From 3ac151d4e73dfb603c71eea9bdd9f0541f1a7e3c Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 14:44:14 +0200 Subject: [PATCH 01/15] [arcane,core+mesh] Prepare Item info structures for parallel in polyhedral mesh. --- arcane/src/arcane/core/ItemAllocationInfo.h | 56 +++++++++++++++++++-- arcane/src/arcane/mesh/ItemData.cc | 18 ++++++- arcane/src/arcane/mesh/ItemData.h | 21 +++++--- 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/arcane/src/arcane/core/ItemAllocationInfo.h b/arcane/src/arcane/core/ItemAllocationInfo.h index 072c59565e..1731b14266 100644 --- a/arcane/src/arcane/core/ItemAllocationInfo.h +++ b/arcane/src/arcane/core/ItemAllocationInfo.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ItemAllocationInfo (C) 2000-2023 */ +/* ItemAllocationInfo (C) 2000-2025 */ /* */ /* AllocationInfo for mesh using eItemAllocationInfo mode */ /*---------------------------------------------------------------------------*/ @@ -37,6 +37,16 @@ class ItemAllocationInfo String connectivity_name; Int32ConstSmallSpan nb_connected_items_per_item; Int64ConstSmallSpan connected_items_uids; + // If ItemAllocation has to own the data use the followings. + // In this case, Store a view in the corresponding spans using method updateViewsFromInternalData(). + Int32UniqueArray _nb_connected_items_per_item_data; + Int64UniqueArray _connected_items_uids_data; + + void updateViewsFromInternalData() + { + nb_connected_items_per_item = _nb_connected_items_per_item_data.constSmallSpan(); + connected_items_uids = _connected_items_uids_data.constSmallSpan(); + } }; struct FamilyInfo @@ -44,11 +54,51 @@ class ItemAllocationInfo String name; eItemKind item_kind; Int64ConstSmallSpan item_uids; - UniqueArray connected_family_info; + UniqueArray connected_family_infos; Real3ConstSmallSpan item_coordinates; // if needed String item_coordinates_variable_name; // if needed + Int32UniqueArray item_owners; // if needed + // If ItemAllocation has to own the data use the followings. + // In this case, Store a view in the corresponding spans using method updateViewsFromInternalData(). + Int64UniqueArray _item_uids_data; + Real3UniqueArray _item_coordinates_data; + + void updateViewsFromInternalData() + { + item_uids = _item_uids_data.constSmallSpan(); + item_coordinates = _item_coordinates_data.constSmallSpan(); + for (auto& connected_family_info : connected_family_infos) { + connected_family_info.updateViewsFromInternalData(); + } + } + + void clear() + { + name = String{}; + item_kind = IK_Unknown; + item_uids = Int64ConstSmallSpan{}; + connected_family_infos.clear(); + item_coordinates = Real3ConstSmallSpan{}; + item_coordinates_variable_name = String{}; + _item_uids_data.clear(); + _item_coordinates_data.clear(); + item_owners.clear(); + } }; UniqueArray family_infos; + + // To use if ItemAllocationInfo has to own the data. The views will point to the stored data + void updateViewsFromInternalData() + { + for (auto& family_info : family_infos) { + family_info.updateViewsFromInternalData(); + } + } + + void clear() + { + family_infos.clear(); + } }; } // End namespace Arcane diff --git a/arcane/src/arcane/mesh/ItemData.cc b/arcane/src/arcane/mesh/ItemData.cc index 9f88c31101..15f7a49896 100644 --- a/arcane/src/arcane/mesh/ItemData.cc +++ b/arcane/src/arcane/mesh/ItemData.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ItemData.cc (C) 2000-2024 */ +/* ItemData.cc (C) 2000-2025 */ /* */ /* Class gathering item data : ids and connectivities */ /*---------------------------------------------------------------------------*/ @@ -112,6 +112,20 @@ _deserialize(ISerializer* buffer, IMesh* mesh) /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +void ItemData:: +clear() +{ + m_nb_items = 0; + m_item_infos.clear(); + _internal_item_lids.clear(); + m_item_lids = Int32ArrayView(); + m_item_owners.clear(); + m_item_family = nullptr; + m_item_family_modifier = nullptr; + m_subdomain_id = -1; +} + + } // End namespace Arcane::mesh /*---------------------------------------------------------------------------*/ diff --git a/arcane/src/arcane/mesh/ItemData.h b/arcane/src/arcane/mesh/ItemData.h index efd54994b6..39fce19ce7 100644 --- a/arcane/src/arcane/mesh/ItemData.h +++ b/arcane/src/arcane/mesh/ItemData.h @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2022 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ItemData.h (C) 2000-2018 */ +/* ItemData.h (C) 2000-2025 */ /* */ /* Class gathering item data : ids and connectivities */ /*---------------------------------------------------------------------------*/ @@ -77,7 +77,10 @@ class ARCANE_MESH_EXPORT ItemData , m_item_lids(item_lids) , m_item_family(item_family) , m_item_family_modifier(item_family_modifier) - , m_subdomain_id(subdomain_id){} + , m_subdomain_id(subdomain_id) + { + _ownerDefaultInit(); + } /*! Ici on ne fournit pas les item_lids qui sont donc créés en internes. * @@ -90,7 +93,10 @@ class ARCANE_MESH_EXPORT ItemData , m_item_lids(_internal_item_lids) , m_item_family(item_family) , m_item_family_modifier(item_family_modifier) - , m_subdomain_id(subdomain_id){} + , m_subdomain_id(subdomain_id) + { + _ownerDefaultInit(); + } /** Destructeur de la classe */ virtual ~ItemData() {} @@ -101,7 +107,8 @@ class ARCANE_MESH_EXPORT ItemData Int64Array& itemInfos() {return m_item_infos;} // Need to return Array& since size is not always known at construction Int64ConstArrayView itemInfos() const {return m_item_infos;} Int32ArrayView itemLids() {return m_item_lids;} - Int32ArrayView itemOwners() { if (m_item_owners.empty()) _ownerDefaultInit(); return m_item_owners;} + Int32ArrayView itemOwners() { return m_item_owners;} + Int32ConstArrayView itemOwners() const { return m_item_owners;} IItemFamily* itemFamily() {return m_item_family;} IItemFamily const* itemFamily() const {return m_item_family;} IItemFamilyModifier* itemFamilyModifier() {return m_item_family_modifier;} @@ -110,9 +117,9 @@ class ARCANE_MESH_EXPORT ItemData void serialize(ISerializer* buffer); // Fill the buffer from the data void deserialize(ISerializer* buffer, IMesh* mesh); // Fill the buffer from the data : using an internal lids array void deserialize(ISerializer* buffer, IMesh* mesh, Int32Array& item_lids); // Fill the data from the buffer using external lids array. item_lids must live as long as ItemData does... + void clear(); // Clear all internal data - -private: + private: void _deserialize(ISerializer* buffer, IMesh* mesh); void _ownerDefaultInit() { m_item_owners.resize(m_nb_items); m_item_owners.fill(m_subdomain_id);} From 4dbd19b7ce1caa7bee7392d5d8dde4eefec82d5d Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 14:47:02 +0200 Subject: [PATCH 02/15] [arcane,std] Handle Item info structures modification in vtk polyhedral mesh reader. --- .../arcane/std/VtkPolyhedralMeshIOService.cc | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc b/arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc index 69bbc03068..ccb96abef5 100644 --- a/arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc +++ b/arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc @@ -346,7 +346,7 @@ _fillItemAllocationInfo(ItemAllocationInfo& item_allocation_info, VtkReader& vtk auto nb_connected_family = 3; item_allocation_info.family_infos.resize(nb_item_family); for (auto& family_info : item_allocation_info.family_infos) { - family_info.connected_family_info.resize(nb_connected_family); + family_info.connected_family_infos.resize(nb_connected_family); } // Create regular item families and connectivities auto& cell_family_info = item_allocation_info.family_infos[0]; @@ -367,21 +367,21 @@ _fillItemAllocationInfo(ItemAllocationInfo& item_allocation_info, VtkReader& vtk edge_family_info.item_uids = vtk_reader.edgeUids(); // Cell to nodes connectivity auto cell_connected_family_index = 0; - auto& cell_connected_node_family_info = cell_family_info.connected_family_info[cell_connected_family_index++]; + auto& cell_connected_node_family_info = cell_family_info.connected_family_infos[cell_connected_family_index++]; cell_connected_node_family_info.name = node_family_info.name; cell_connected_node_family_info.item_kind = node_family_info.item_kind; cell_connected_node_family_info.connectivity_name = "CellToNodes"; cell_connected_node_family_info.nb_connected_items_per_item = vtk_reader.cellNbNodes(); cell_connected_node_family_info.connected_items_uids = vtk_reader.cellNodes(); // Cell to faces connectivity - auto& cell_connected_face_family_info = cell_family_info.connected_family_info[cell_connected_family_index++]; + auto& cell_connected_face_family_info = cell_family_info.connected_family_infos[cell_connected_family_index++]; cell_connected_face_family_info.name = face_family_info.name; cell_connected_face_family_info.item_kind = face_family_info.item_kind; cell_connected_face_family_info.connectivity_name = "CellToFaces"; cell_connected_face_family_info.nb_connected_items_per_item = vtk_reader.cellNbFaces(); cell_connected_face_family_info.connected_items_uids = vtk_reader.cellFaces(); // Cell to edges connectivity - auto& cell_connected_edge_family_info = cell_family_info.connected_family_info[cell_connected_family_index++]; + auto& cell_connected_edge_family_info = cell_family_info.connected_family_infos[cell_connected_family_index++]; cell_connected_edge_family_info.name = edge_family_info.name; cell_connected_edge_family_info.item_kind = edge_family_info.item_kind; cell_connected_edge_family_info.connectivity_name = "CellToEdges"; @@ -389,21 +389,21 @@ _fillItemAllocationInfo(ItemAllocationInfo& item_allocation_info, VtkReader& vtk cell_connected_edge_family_info.connected_items_uids = vtk_reader.cellEdges(); // Face to cells connectivity auto face_connected_family_index = 0; - auto& face_connected_cell_family_info = face_family_info.connected_family_info[face_connected_family_index++]; + auto& face_connected_cell_family_info = face_family_info.connected_family_infos[face_connected_family_index++]; face_connected_cell_family_info.name = cell_family_info.name; face_connected_cell_family_info.item_kind = cell_family_info.item_kind; face_connected_cell_family_info.connectivity_name = "FaceToCells"; face_connected_cell_family_info.nb_connected_items_per_item = vtk_reader.faceNbCells(); face_connected_cell_family_info.connected_items_uids = vtk_reader.faceCells(); // Face to nodes connectivity - auto& face_connected_node_family_info = face_family_info.connected_family_info[face_connected_family_index++]; + auto& face_connected_node_family_info = face_family_info.connected_family_infos[face_connected_family_index++]; face_connected_node_family_info.name = node_family_info.name; face_connected_node_family_info.item_kind = node_family_info.item_kind; face_connected_node_family_info.connectivity_name = "FaceToNodes"; face_connected_node_family_info.nb_connected_items_per_item = vtk_reader.faceNbNodes(); face_connected_node_family_info.connected_items_uids = vtk_reader.faceNodes(); // Face to edges connectivity - auto& face_connected_edge_family_info = face_family_info.connected_family_info[face_connected_family_index]; + auto& face_connected_edge_family_info = face_family_info.connected_family_infos[face_connected_family_index]; face_connected_edge_family_info.name = edge_family_info.name; face_connected_edge_family_info.item_kind = edge_family_info.item_kind; face_connected_edge_family_info.connectivity_name = "FaceToEdges"; @@ -411,21 +411,21 @@ _fillItemAllocationInfo(ItemAllocationInfo& item_allocation_info, VtkReader& vtk face_connected_edge_family_info.connected_items_uids = vtk_reader.faceEdges(); // Edge to cells connectivity auto edge_connected_family_index = 0; - auto& edge_connected_cell_family_info = edge_family_info.connected_family_info[edge_connected_family_index++]; + auto& edge_connected_cell_family_info = edge_family_info.connected_family_infos[edge_connected_family_index++]; edge_connected_cell_family_info.name = cell_family_info.name; edge_connected_cell_family_info.item_kind = cell_family_info.item_kind; edge_connected_cell_family_info.connectivity_name = "EdgeToCells"; edge_connected_cell_family_info.nb_connected_items_per_item = vtk_reader.edgeNbCells(); edge_connected_cell_family_info.connected_items_uids = vtk_reader.edgeCells(); // Edge to faces connectivity - auto& edge_connected_face_family_info = edge_family_info.connected_family_info[edge_connected_family_index++]; + auto& edge_connected_face_family_info = edge_family_info.connected_family_infos[edge_connected_family_index++]; edge_connected_face_family_info.name = face_family_info.name; edge_connected_face_family_info.item_kind = face_family_info.item_kind; edge_connected_face_family_info.connectivity_name = "EdgeToFaces"; edge_connected_face_family_info.nb_connected_items_per_item = vtk_reader.edgeNbFaces(); edge_connected_face_family_info.connected_items_uids = vtk_reader.edgeFaces(); // Edge to nodes connectivity - auto& edge_connected_node_family_info = edge_family_info.connected_family_info[edge_connected_family_index++]; + auto& edge_connected_node_family_info = edge_family_info.connected_family_infos[edge_connected_family_index++]; edge_connected_node_family_info.name = node_family_info.name; edge_connected_node_family_info.item_kind = node_family_info.item_kind; edge_connected_node_family_info.connectivity_name = "EdgeToNodes"; @@ -433,21 +433,21 @@ _fillItemAllocationInfo(ItemAllocationInfo& item_allocation_info, VtkReader& vtk edge_connected_node_family_info.connected_items_uids = vtk_reader.edgeNodes(); // Node to cells connectivity auto node_connected_family_index = 0; - auto& node_connected_cell_family_info = node_family_info.connected_family_info[node_connected_family_index++]; + auto& node_connected_cell_family_info = node_family_info.connected_family_infos[node_connected_family_index++]; node_connected_cell_family_info.name = cell_family_info.name; node_connected_cell_family_info.item_kind = cell_family_info.item_kind; node_connected_cell_family_info.connectivity_name = "NodeToCells"; node_connected_cell_family_info.nb_connected_items_per_item = vtk_reader.nodeNbCells(); node_connected_cell_family_info.connected_items_uids = vtk_reader.nodeCells(); // Node to faces connectivity - auto& node_connected_face_family_info = node_family_info.connected_family_info[node_connected_family_index++]; + auto& node_connected_face_family_info = node_family_info.connected_family_infos[node_connected_family_index++]; node_connected_face_family_info.name = face_family_info.name; node_connected_face_family_info.item_kind = face_family_info.item_kind; node_connected_face_family_info.connectivity_name = "NodeToFaces"; node_connected_face_family_info.nb_connected_items_per_item = vtk_reader.nodeNbFaces(); node_connected_face_family_info.connected_items_uids = vtk_reader.nodeFaces(); // Node to edges connectivity - auto& node_connected_edge_family_info = node_family_info.connected_family_info[node_connected_family_index++]; + auto& node_connected_edge_family_info = node_family_info.connected_family_infos[node_connected_family_index++]; node_connected_edge_family_info.name = edge_family_info.name; node_connected_edge_family_info.item_kind = edge_family_info.item_kind; node_connected_edge_family_info.connectivity_name = "NodeToEdges"; From c9cbfabe3d248a3e8514fbf16fde80734de1ca86 Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 14:49:46 +0200 Subject: [PATCH 03/15] [arcane,std] Fix created face group name for parallel in vtk polyhedral mesh reader. --- arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc b/arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc index ccb96abef5..d5a1cd2cac 100644 --- a/arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc +++ b/arcane/src/arcane/std/VtkPolyhedralMeshIOService.cc @@ -536,7 +536,7 @@ _readVariablesAndGroups(IPrimaryMesh* mesh, VtkReader& reader) auto* face_array = face_data->GetArray(array_index); if (String name = face_array->GetName(); name.substring(0, 6) == "GROUP_") { _createGroup(face_array, name.substring(6), mesh, mesh->faceFamily(), vtk_to_Arcane_lids); - created_infos_str() << ""; + created_infos_str() << ""; } else { auto var_info = _createVariable(face_array, name, mesh, mesh->faceFamily(), arcane_to_vtk_lids); From 77a678695c810e48d8171a2517a500ef24a578c1 Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 15:05:57 +0200 Subject: [PATCH 04/15] [arcane,core] Add and update internal interfaces for parallel in polyhedral mesh. --- .../IItemFamilySerializerMngInternal.h | 56 +++++++++++++++++++ .../src/arcane/core/internal/IMeshInternal.h | 13 +++++ .../core/internal/IPolyhedralMeshModifier.h | 1 + 3 files changed, 70 insertions(+) create mode 100644 arcane/src/arcane/core/internal/IItemFamilySerializerMngInternal.h diff --git a/arcane/src/arcane/core/internal/IItemFamilySerializerMngInternal.h b/arcane/src/arcane/core/internal/IItemFamilySerializerMngInternal.h new file mode 100644 index 0000000000..acd6a4576d --- /dev/null +++ b/arcane/src/arcane/core/internal/IItemFamilySerializerMngInternal.h @@ -0,0 +1,56 @@ +// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- +//----------------------------------------------------------------------------- +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: Apache-2.0 +//----------------------------------------------------------------------------- +/*---------------------------------------------------------------------------*/ +/* IItemFamilySerializerMngInternal.h (C) 2000-2025 */ +/* */ +/* Gestionnaire des outils de sérialisation/désérialisation d'une famille. */ +/*---------------------------------------------------------------------------*/ +#ifndef ARCANE_CORE_IITEMFAMILYSERIALIZERMNGINTERNAL_H +#define ARCANE_CORE_IITEMFAMILYSERIALIZERMNGINTERNAL_H +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +namespace Arcane +{ +class IItemFamily; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/*! + * \brief Gère la sérialisation/désérialisation des entités d'une famille. + */ +class ARCANE_CORE_EXPORT IItemFamilySerializerMngInternal +{ + public: + + virtual ~IItemFamilySerializerMngInternal() = default; + + public: + + /*! + * \brief Finalise les allocations réalisées par les serializers enregistrés dans le gestionnaire. + * + * Utilisé pour le maillage polyédrique où les allocations ne sont réalisées qu'après avoir + * effectué toutes les sérialisations pour toutes les familles + */ + virtual void finalizeItemAllocation() = 0; +}; + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +} // namespace Arcane + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +#endif + diff --git a/arcane/src/arcane/core/internal/IMeshInternal.h b/arcane/src/arcane/core/internal/IMeshInternal.h index 404e81f6f7..e82fba3b20 100644 --- a/arcane/src/arcane/core/internal/IMeshInternal.h +++ b/arcane/src/arcane/core/internal/IMeshInternal.h @@ -24,6 +24,7 @@ namespace Arcane class IItemConnectivityMng; class IPolyhedralMeshModifier; +class IItemFamilySerializerMngInternal; /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -62,6 +63,18 @@ class ARCANE_CORE_EXPORT IMeshInternal * Cette méthode retourne nullptr si l'implémentation du maillage n'est pas PolyhedralMesh */ virtual IPolyhedralMeshModifier* polyhedralMeshModifier() const noexcept = 0; + + /*! + * \brief Renvoie le gestionnaire des outils de sérialisation des familles. + * + * Ce gestionnaire est utilisé pour le maillage polyédrique, afin de lancer une + * phase de finalisation de l'ajout des items après l'appel aux méthodes de désérialisation, + * car ces méthodes sont asynchrones et il faut déclencher la phase de finalisation. + * + * @return Cette méthode retourne nullptr si le gestionnaire n'existe pas. + */ + virtual IItemFamilySerializerMngInternal* familySerializerMng() const noexcept {return nullptr;} + }; diff --git a/arcane/src/arcane/core/internal/IPolyhedralMeshModifier.h b/arcane/src/arcane/core/internal/IPolyhedralMeshModifier.h index 72c68335c6..77169e6ff0 100644 --- a/arcane/src/arcane/core/internal/IPolyhedralMeshModifier.h +++ b/arcane/src/arcane/core/internal/IPolyhedralMeshModifier.h @@ -37,6 +37,7 @@ class ARCANE_CORE_EXPORT IPolyhedralMeshModifier virtual ~IPolyhedralMeshModifier() = default; virtual void addItems(Int64ConstArrayView unique_ids, Int32ArrayView local_ids, eItemKind ik, const String& family_name) = 0; + virtual void addItems(Int64ConstArrayView unique_ids, Int32ArrayView local_ids, Int32ConstArrayView owners, eItemKind ik, const String& family_name) = 0; virtual void removeItems(Int32ConstArrayView local_ids, eItemKind ik, const String& family_name) = 0; }; From ef8ccc8ebb35a60ed5daa7e14f4f1244c5e1be96 Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 18:43:36 +0200 Subject: [PATCH 05/15] [arcane,mesh] Add exchange items for polyhedral mesh. --- arcane/src/arcane/mesh/PolyhedralMesh.cc | 1198 +++++++++++++++++----- arcane/src/arcane/mesh/PolyhedralMesh.h | 37 +- 2 files changed, 965 insertions(+), 270 deletions(-) diff --git a/arcane/src/arcane/mesh/PolyhedralMesh.cc b/arcane/src/arcane/mesh/PolyhedralMesh.cc index 25e302a009..a176a3f424 100644 --- a/arcane/src/arcane/mesh/PolyhedralMesh.cc +++ b/arcane/src/arcane/mesh/PolyhedralMesh.cc @@ -1,6 +1,6 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2025CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- @@ -11,6 +11,8 @@ /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +#include + #include "arcane/mesh/PolyhedralMesh.h" #include "ItemFamilyNetwork.h" @@ -24,6 +26,7 @@ #include "arcane/core/MeshBuildInfo.h" #include "arcane/core/ServiceFactory.h" #include "arcane/core/AbstractService.h" +#include "arcane/core/CommonVariables.h" #include "arcane/core/IMeshFactory.h" #include "arcane/core/ItemInternal.h" #include "arcane/core/IDoFFamily.h" @@ -32,6 +35,8 @@ #include "arcane/core/IMeshExchanger.h" #include "arcane/core/IGhostLayerMng.h" #include "arcane/core/MeshVisitor.h" +#include "arcane/core/internal/IItemFamilyInternal.h" +#include "arcane/core/internal/IItemFamilySerializerMngInternal.h" #include "arcane/core/internal/IVariableMngInternal.h" #include "arcane/core/internal/IPolyhedralMeshModifier.h" #include "arcane/core/internal/IMeshModifierInternal.h" @@ -59,10 +64,12 @@ #include "neo/Mesh.h" #include "ItemConnectivityMng.h" +#include "arcane/core/ItemPrinter.h" + #endif // #define ARCANE_DEBUG_POLYHEDRAL_MESH - #define ARCANE_DEBUG_LOAD_BALANCING +#define ARCANE_DEBUG_LOAD_BALANCING #ifdef ARCANE_DEBUG_LOAD_BALANCING static bool arcane_debug_load_balancing = true; @@ -82,6 +89,11 @@ _errorEmptyMesh() const /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +#ifdef ARCANE_HAS_POLYHEDRAL_MESH_TOOLS + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + namespace Arcane { @@ -90,186 +102,409 @@ namespace Arcane namespace mesh { + namespace PolyhedralTools + { + class ItemLocalIds + { + Neo::FutureItemRange m_future_items; + std::shared_ptr m_mesh_state = nullptr; + + public: + + void fillArrayView(Int32ArrayView local_ids, Neo::EndOfMeshUpdate mesh_state) + { + auto lids = m_future_items.get(mesh_state); + if (local_ids.size() != lids.size()) + ARCANE_FATAL("Cannot fill local_ids view, its size {0} != {1} (added item size)", local_ids.size(), m_future_items.size()); + std::copy(lids.begin(), lids.end(), local_ids.begin()); + } + + void fillArrayView(Int32ArrayView local_ids) + { + ARCANE_CHECK_POINTER2(m_mesh_state.get(), "PolyhedralTools::ItemLocalIds must have a valid end of mesh state"); + fillArrayView(local_ids, *m_mesh_state); + } + + Integer size() const noexcept { return m_future_items.size(); } + bool isFilled() const noexcept { return m_mesh_state.get() != nullptr; }; + void checkIsFilled(String error_message) const noexcept + { + if (!isFilled()) + ARCANE_FATAL("Item local ids are not filled." + error_message); + } + friend class mesh::PolyhedralMeshImpl; + friend class mesh::PolyhedralMesh; + }; + } // namespace PolyhedralTools /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ - class PolyhedralFamilyPolicyMng - : public ItemFamilyPolicyMng + class PolyhedralFamilySerializer; + class PolyhedralFamilySerializerMng : public IItemFamilySerializerMngInternal { - public: - PolyhedralFamilyPolicyMng(ItemFamily* family) - : ItemFamilyPolicyMng(family) - , m_family(family){} - public: - IItemFamilySerializer* createSerializer(bool use_flags) override + PolyhedralMesh* m_mesh = nullptr; + Integer m_nb_serializers = 0; + UniqueArray m_serializers; + + public: + + PolyhedralFamilySerializerMng(PolyhedralMesh* mesh) + : m_mesh(mesh) + { + ARCANE_CHECK_POINTER2(mesh, "Must give a non null PolyhedralMesh pointer."); + } + + void addSerializer(PolyhedralFamilySerializer* serializer) { - return new ItemFamilySerializer(m_family, nullptr, nullptr); // todo handle mesh incremental builder interface and IItemFamilyModifier + m_serializers.push_back(serializer); + ++m_nb_serializers; } - private: - ItemFamily* m_family; + + void finalizeItemAllocation() override; }; /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ - class PolyhedralFamily - : public ItemFamily - , public IDoFFamily + class PolyhedralFamilySerializer : public IItemFamilySerializer { - ItemSharedInfoWithType* m_shared_info = nullptr; - Int32UniqueArray m_empty_connectivity{ 0 }; - Int32UniqueArray m_empty_connectivity_indexes; - Int32UniqueArray m_empty_connectivity_nb_item; + private: - public: - - inline static const String m_arcane_item_lids_property_name{ "Arcane_Item_Lids" }; // inline used to initialize within the declaration - inline static const String m_arcane_remove_item_property_name{ "Arcane_Remove_Items" }; // inline used to initialize within the declaration + PolyhedralMesh* m_mesh = nullptr; + IItemFamily* m_family = nullptr; + PolyhedralFamilySerializerMng* m_mng = nullptr; + ItemData m_item_data; + UniqueArray m_deserialized_lids_array; + UniqueArray> m_future_item_lids_array; + ItemAllocationInfo::FamilyInfo m_family_info; public: - PolyhedralFamily(IMesh* mesh, eItemKind ik, String name) - : ItemFamily(mesh, ik, name) + explicit PolyhedralFamilySerializer(PolyhedralMesh* mesh, IItemFamily* family, PolyhedralFamilySerializerMng* mng) + : m_mesh(mesh) + , m_family(family) + , m_mng(mng) {} + PolyhedralFamilySerializer(const PolyhedralFamilySerializer&) = delete; + PolyhedralFamilySerializer& operator=(const PolyhedralFamilySerializer&) = delete; + + ArrayView> itemLidsArray() { return m_future_item_lids_array.view(); } + public: - void preAllocate(Integer nb_item) - { - Integer nb_hash = itemsMap().nbBucket(); - Integer wanted_size = 2 * (nb_item + nbItem()); - if (nb_hash < wanted_size) - itemsMap().resize(wanted_size, true); - m_empty_connectivity_indexes.resize(nb_item + nbItem(), 0); - m_empty_connectivity_nb_item.resize(nb_item + nbItem(), 0); - _updateEmptyConnectivity(); - } + void serializeItems(ISerializer* buf, Int32ConstArrayView items_local_ids) override; + void deserializeItems(ISerializer* buf, Int32Array* items_local_ids) override; - ItemInternal* _allocItem(const Int64 uid) + void clear() { - bool need_alloc; // given by alloc - ItemInternal* item_internal = ItemFamily::_allocOne(uid, need_alloc); - if (!need_alloc) - item_internal->setUniqueId(uid); - else { - _allocateInfos(item_internal, uid, m_shared_info); - } - item_internal->setOwner(m_sub_domain_id, m_sub_domain_id); - return item_internal; + m_item_data.clear(); + m_deserialized_lids_array.clear(); + m_future_item_lids_array.clear(); + m_family_info.clear(); } - void addItems(Int64ConstSmallSpan uids, Int32ArrayView items) + void fillDeserializedLocalIds() { - if (uids.empty()) - return; - ARCANE_ASSERT((uids.size() == items.size()), ("one must have items.size==uids.size()")); - m_mesh->traceMng()->debug(Arccore::Trace::Highest) << " PolyhedralFamily::addItems "; - preAllocate(uids.size()); - auto index{ 0 }; - for (auto uid : uids) { - ItemInternal* ii = _allocItem(uid); - items[index++] = ii->localId(); + auto index = 0; + for (auto item_lids_array : m_deserialized_lids_array) { + auto& future_item_lids = m_future_item_lids_array[index]; + future_item_lids->checkIsFilled("Cannot fill deserialized local ids, future item local ids are not filled."); + item_lids_array->resize(future_item_lids->size()); + future_item_lids->fillArrayView(item_lids_array->view()); + ++index; } - m_need_prepare_dump = true; - _updateItemInternalList(); + clear(); } - void removeItems(Int32ConstArrayView local_ids) + IItemFamilySerializerMngInternal* mng() { - _removeMany(local_ids); + return m_mng; } - void _updateItemInternalList() + // no need to distinguish between dependency or relation in Neo graph + void serializeItemRelations(ISerializer*, Int32ConstArrayView) override {} + void deserializeItemRelations(ISerializer*, Int32Array*) override {} + + private: + + void _fillItemData(Int32ConstArrayView items_local_ids); + void _fillItemFamilyInfo(const ItemData& item_data, + StringConstArrayView connected_family_names, + StringConstArrayView connectivity_names) { - switch (itemKind()) { - case IK_Cell: - m_item_internal_list->cells = _itemsInternal(); - break; - case IK_Face: - m_item_internal_list->faces = _itemsInternal(); - break; - case IK_Edge: - m_item_internal_list->edges = _itemsInternal(); - break; - case IK_Node: - m_item_internal_list->nodes = _itemsInternal(); - break; - case IK_DoF: - case IK_Particle: - case IK_Unknown: - break; + // clear data + m_family_info.clear(); + // Check info in ItemData + if (m_family != item_data.itemFamily()) + ARCANE_FATAL("PolyhedralFamilySerializer: Family mismatch. Synchronized family is {0} and serialized family is {1}", + m_family->name(), item_data.itemFamily()->name()); + m_family_info.name = item_data.itemFamily()->name(); + m_family_info.item_kind = item_data.itemFamily()->itemKind(); + auto& connected_family_infos = m_family_info.connected_family_infos; + auto nb_connected_family = item_data.itemInfos()[0]; + connected_family_infos.resize(nb_connected_family); + auto& item_uids = m_family_info._item_uids_data; + item_uids.reserve(item_data.nbItems()); + auto item_infos = item_data.itemInfos(); + for (auto connected_family_info : connected_family_infos) { + connected_family_info._connected_items_uids_data.reserve(4 * item_uids.size()); + connected_family_info._nb_connected_items_per_item_data.reserve(item_uids.size()); + } + for (auto index = 1; index < item_infos.size();) { + item_uids.push_back(item_infos[index + 1]); // first index is item type, not used in polyhedral + index += 2; + for (auto connected_family_index = 0; connected_family_index < nb_connected_family; ++connected_family_index) { + eItemKind family_kind = static_cast(item_infos[index]); + auto* connected_family = m_mesh->findItemFamily(family_kind, connected_family_names[connected_family_index], false, false); + ARCANE_CHECK_POINTER(connected_family); + auto& current_connected_family_infos = connected_family_infos[connected_family_index]; + current_connected_family_infos.item_kind = family_kind; + current_connected_family_infos.name = connected_family->name(); + current_connected_family_infos.connectivity_name = connectivity_names[connected_family_index]; + ++index; + auto nb_connected_items = static_cast(item_infos[index]); + ++index; + current_connected_family_infos._nb_connected_items_per_item_data.push_back(nb_connected_items); + auto real_nb_connected_items = nb_connected_items; + if (m_family->itemKind() == IK_Face && connected_family->itemKind() == IK_Cell) + real_nb_connected_items = 2; // 2 cells are stored, even if one is null (boundary) + current_connected_family_infos._connected_items_uids_data.addRange(item_infos.subView(index, real_nb_connected_items)); + index += real_nb_connected_items; + } } + // Update FamilyInfo views + m_family_info.updateViewsFromInternalData(); + // get owners + m_family_info.item_owners = item_data.itemOwners(); } - void _updateEmptyConnectivity() + IItemFamily* family() const override { - auto item_internal_connectivity_list = itemInternalConnectivityList(); - for (auto item_kind = 0; item_kind < ItemInternalConnectivityList::MAX_ITEM_KIND; ++item_kind) { - item_internal_connectivity_list->_setConnectivityList(item_kind, m_empty_connectivity); - item_internal_connectivity_list->_setConnectivityIndex(item_kind, m_empty_connectivity_indexes); - item_internal_connectivity_list->_setConnectivityNbItem(item_kind, m_empty_connectivity_nb_item); - } + return m_family; } + }; - // IItemFamily - IDoFFamily* toDoFFamily() override { - return this; - } - // todo bloquer toutes les methodes d'allocation de IItemFamily + /*---------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------*/ - void build() override { - ItemFamily::build(); - m_sub_domain_id = subDomain()->subDomainId(); - ItemTypeMng* itm = m_mesh->itemTypeMng(); - ItemTypeInfo* dof_type_info = itm->typeFromId(IT_NullType); - m_shared_info = _findSharedInfo(dof_type_info); - _updateEmptyConnectivity(); - ItemFamily::setPolicyMng(new PolyhedralFamilyPolicyMng{this}); + void PolyhedralFamilySerializerMng:: + finalizeItemAllocation() + { + UniqueArray> future_item_lids; + for (auto family_serializer : m_serializers) { + for (auto& item_lids : family_serializer->itemLidsArray()) { + future_item_lids.push_back(item_lids); + } + } + m_mesh->applyScheduledAllocateItems(future_item_lids); + for (auto family_serializer : m_serializers) { + family_serializer->fillDeserializedLocalIds(); + } + m_serializers.clear(); + } - } + /*---------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------*/ - // IDoFFamily - String name() const override { return ItemFamily::name(); } - String fullName() const override { return ItemFamily::fullName(); } - Integer nbItem() const override { return ItemFamily::nbItem(); } - ItemGroup allItems() const override { return ItemFamily::allItems(); } - void endUpdate() override { info() << "END UPDATE "<< m_name ; return ItemFamily::endUpdate(); } - IItemFamily* itemFamily() override { return this; } + class PolyhedralFamilyPolicyMng + : public ItemFamilyPolicyMng + { + public: + PolyhedralFamilyPolicyMng(PolyhedralMesh* mesh, ItemFamily* family) + : ItemFamilyPolicyMng(family) + , m_mesh(mesh) + , m_family(family) + {} - DoFVectorView addDoFs(Int64ConstArrayView dof_uids, Int32ArrayView dof_lids){ - auto* polyhedral_mesh_modifier = m_mesh->_internalApi()->polyhedralMeshModifier(); - ARCANE_CHECK_POINTER(polyhedral_mesh_modifier); - polyhedral_mesh_modifier->addItems(dof_uids, dof_lids, ItemFamily::itemKind(), name()); - return ItemFamily::view(dof_lids); - } + public: - DoFVectorView addGhostDoFs(Int64ConstArrayView dof_uids, Int32ArrayView dof_lids, - Int32ConstArrayView owners) + IItemFamilySerializer* createSerializer(bool) override { - ARCANE_NOT_YET_IMPLEMENTED(""); - ARCANE_UNUSED(dof_uids); - ARCANE_UNUSED(owners); - return ItemFamily::view(dof_lids); + return new PolyhedralFamilySerializer(m_mesh, m_family, m_mesh->polyhedralFamilySerializerMng()); } - void removeDoFs(Int32ConstArrayView items_local_id){ - auto* mesh_modifier = m_mesh->_internalApi()->polyhedralMeshModifier(); - mesh_modifier->removeItems(items_local_id, ItemFamily::itemKind(), m_name); - } - }; + private: + + PolyhedralMesh* m_mesh = nullptr; + ItemFamily* m_family = nullptr; +}; -} // namespace mesh /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -} // namespace Arcane +class PolyhedralFamily +: public ItemFamily +, public IDoFFamily +{ + ItemSharedInfoWithType* m_shared_info = nullptr; + Int32UniqueArray m_empty_connectivity{ 0 }; + Int32UniqueArray m_empty_connectivity_indexes; + Int32UniqueArray m_empty_connectivity_nb_item; + PolyhedralMesh* m_mesh = nullptr; + + public: + + inline static const String m_arcane_item_lids_property_name{ "Arcane_Item_Lids" }; // inline used to initialize within the declaration + inline static const String m_arcane_remove_item_property_name{ "Arcane_Remove_Items" }; // inline used to initialize within the declaration + + public: + + PolyhedralFamily(PolyhedralMesh* mesh, eItemKind ik, String name) + : ItemFamily(mesh, ik, name) + , m_mesh(mesh) + {} + + public: + + void preAllocate(Integer nb_item) + { + Integer nb_hash = itemsMap().nbBucket(); + Integer wanted_size = 2 * (nb_item + nbItem()); + if (nb_hash < wanted_size) + itemsMap().resize(wanted_size, true); + m_empty_connectivity_indexes.resize(nb_item + nbItem(), 0); + m_empty_connectivity_nb_item.resize(nb_item + nbItem(), 0); + _updateEmptyConnectivity(); + } + + ItemInternal* _allocItem(const Int64 uid, const Int32 owner) + { + bool need_alloc; // given by alloc + ItemInternal* item_internal = ItemFamily::_findOrAllocOne(uid, need_alloc); + if (!need_alloc) + item_internal->setUniqueId(uid); + else { + _allocateInfos(item_internal, uid, m_shared_info); + } + item_internal->setOwner(owner, m_sub_domain_id); + return item_internal; + } + void addItems(Int64ConstSmallSpan uids, Int32ArrayView items) + { + Int32UniqueArray owners(uids.size(), m_sub_domain_id); + addItems(uids, items, owners); + } + + void addItems(Int64ConstSmallSpan uids, Int32ArrayView items, Int32ConstArrayView owners) + { + if (uids.empty()) + return; + ARCANE_ASSERT((uids.size() == items.size()), ("one must have items.size==uids.size()")); + preAllocate(uids.size()); + auto index{ 0 }; + for (auto uid : uids) { + ItemInternal* ii = _allocItem(uid,owners[index]); + items[index] = ii->localId(); + ++index; + } + m_need_prepare_dump = true; + _updateItemInternalList(); + } + + void removeItems(Int32ConstArrayView local_ids) + { + _removeMany(local_ids); + } + + void _updateItemInternalList() + { + switch (itemKind()) { + case IK_Cell: + m_item_internal_list->cells = _itemsInternal(); + break; + case IK_Face: + m_item_internal_list->faces = _itemsInternal(); + break; + case IK_Edge: + m_item_internal_list->edges = _itemsInternal(); + break; + case IK_Node: + m_item_internal_list->nodes = _itemsInternal(); + break; + case IK_DoF: + case IK_Particle: + case IK_Unknown: + break; + } + } + + void _updateEmptyConnectivity() + { + auto item_internal_connectivity_list = itemInternalConnectivityList(); + for (auto item_kind = 0; item_kind < ItemInternalConnectivityList::MAX_ITEM_KIND; ++item_kind) { + item_internal_connectivity_list->_setConnectivityList(item_kind, m_empty_connectivity); + item_internal_connectivity_list->_setConnectivityIndex(item_kind, m_empty_connectivity_indexes); + item_internal_connectivity_list->_setConnectivityNbItem(item_kind, m_empty_connectivity_nb_item); + } + } + + // IItemFamily + IDoFFamily* toDoFFamily() override + { + return this; + } + // todo bloquer toutes les methodes d'allocation de IItemFamily + + void build() override + { + ItemFamily::build(); + m_sub_domain_id = subDomain()->subDomainId(); + ItemTypeMng* itm = m_mesh->itemTypeMng(); + ItemTypeInfo* dof_type_info = itm->typeFromId(IT_NullType); + m_shared_info = _findSharedInfo(dof_type_info); + _updateEmptyConnectivity(); + ItemFamily::setPolicyMng(new PolyhedralFamilyPolicyMng{ m_mesh, this }); + } + + void addGhostItems(Int64ConstArrayView unique_ids, Int32ArrayView items,Int32ConstArrayView owners) override + { + auto* polyhedral_mesh_modifier = m_mesh->_internalApi()->polyhedralMeshModifier(); + ARCANE_CHECK_POINTER(polyhedral_mesh_modifier); + polyhedral_mesh_modifier->addItems(unique_ids, items, owners, ItemFamily::itemKind(), name()); + } + + // IDoFFamily + String name() const override { return ItemFamily::name(); } + String fullName() const override { return ItemFamily::fullName(); } + Integer nbItem() const override { return ItemFamily::nbItem(); } + ItemGroup allItems() const override { return ItemFamily::allItems(); } + void endUpdate() override + { + return ItemFamily::endUpdate(); + } + IItemFamily* itemFamily() override { return this; } + + DoFVectorView addDoFs(Int64ConstArrayView dof_uids, Int32ArrayView dof_lids) override + { + auto* polyhedral_mesh_modifier = m_mesh->_internalApi()->polyhedralMeshModifier(); + ARCANE_CHECK_POINTER(polyhedral_mesh_modifier); + polyhedral_mesh_modifier->addItems(dof_uids, dof_lids, ItemFamily::itemKind(), name()); + return ItemFamily::view(dof_lids); + } + + DoFVectorView addGhostDoFs(Int64ConstArrayView dof_uids, Int32ArrayView dof_lids, + Int32ConstArrayView owners) override + { + addGhostItems(dof_uids, dof_lids, owners); + return ItemFamily::view(dof_lids); + } + + void removeDoFs(Int32ConstArrayView items_local_id) override + { + auto* mesh_modifier = m_mesh->_internalApi()->polyhedralMeshModifier(); + mesh_modifier->removeItems(items_local_id, ItemFamily::itemKind(), m_name); + } +}; + +} // namespace mesh /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ -#ifdef ARCANE_HAS_POLYHEDRAL_MESH_TOOLS +} // namespace Arcane /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -297,6 +532,8 @@ namespace mesh static const Neo::ItemKind item_kind = Neo::ItemKind::IK_None; }; + public: + static Neo::ItemKind itemKindArcaneToNeo(eItemKind ik) { switch (ik) { @@ -317,25 +554,30 @@ namespace mesh return Neo::ItemKind::IK_Node; } - public: - - class ItemLocalIds + static eItemKind itemKindNeoToArcane(Neo::ItemKind ik) { - Neo::FutureItemRange m_future_items; - - public: - void fillArrayView(Int32ArrayView local_ids, Neo::EndOfMeshUpdate mesh_state) - { - auto lids = m_future_items.get(mesh_state); - std::copy(lids.begin(),lids.end(),local_ids.begin()); + switch (ik) { + case Neo::ItemKind::IK_Cell: + return IK_Cell; + case Neo::ItemKind::IK_Face: + return IK_Face; + case Neo::ItemKind::IK_Edge: + return IK_Edge; + case Neo::ItemKind::IK_Node: + return IK_Node; + case Neo::ItemKind::IK_Dof: + return IK_DoF; + case Neo::ItemKind::IK_None: + return IK_Unknown; } - friend class PolyhedralMeshImpl; - }; + return IK_Node; + } public: explicit PolyhedralMeshImpl(ISubDomain* subDomain) : m_subdomain(subDomain) + , m_mesh(String::format(subDomain->defaultMeshHandle().meshName(),"Polyhedral").localstr(),subDomain->parallelMng()->commRank()) {} public: @@ -350,6 +592,13 @@ namespace mesh Integer nbCell() const { return m_mesh.nbCells(); } Integer nbItem(eItemKind ik) const { return m_mesh.nbItems(itemKindArcaneToNeo(ik)); } + SmallSpan connectivities(IItemFamily* source_family) + { + auto& neo_source_family = m_mesh.findFamily(itemKindArcaneToNeo(source_family->itemKind()), source_family->name().localstr()); + auto connectivities = m_mesh.getConnectivities(neo_source_family); + return { connectivities.begin(), connectivities.size() }; + } + static void _setFaceInfos(Int32 mod_flags, Face& face) { Int32 face_flags = face.itemBase().flags(); @@ -369,7 +618,17 @@ namespace mesh void scheduleAddItems(PolyhedralFamily* arcane_item_family, Int64ConstSmallSpan uids, - ItemLocalIds& item_local_ids) + PolyhedralTools::ItemLocalIds& item_local_ids) + { + scheduleAddItems(arcane_item_family, uids, Int32ConstSmallSpan{}, item_local_ids); + } + + /*---------------------------------------------------------------------------*/ + + void scheduleAddItems(PolyhedralFamily* arcane_item_family, + Int64ConstSmallSpan uids, + Int32ConstSmallSpan owners, + PolyhedralTools::ItemLocalIds& item_local_ids) { auto& added_items = item_local_ids.m_future_items; auto& item_family = m_mesh.findFamily(itemKindArcaneToNeo(arcane_item_family->itemKind()), @@ -378,16 +637,25 @@ namespace mesh // add arcane items auto& mesh_graph = m_mesh.internalMeshGraph(); item_family.addMeshScalarProperty(PolyhedralFamily::m_arcane_item_lids_property_name.localstr()); + // copy uids and owners to send them to Neo + UniqueArray uids_copy(uids); + UniqueArray owners_copy(owners); mesh_graph.addAlgorithm(Neo::MeshKernel::InProperty{ item_family, item_family.lidPropName() }, Neo::MeshKernel::OutProperty{ item_family, PolyhedralFamily::m_arcane_item_lids_property_name.localstr() }, - [arcane_item_family, uids,added_items](Neo::ItemLidsProperty const& lids_property, - Neo::MeshScalarPropertyT&) { - Int32UniqueArray arcane_items(uids.size()); - arcane_item_family->addItems(uids, arcane_items); - arcane_item_family->traceMng()->debug(Trace::Highest) << arcane_items; - // debug check lid matching. maybe to remove if too coostly - auto neo_lids = lids_property.values(); - if (!std::equal(neo_lids.begin(), neo_lids.end(), arcane_items.begin())) + [arcane_item_family, uids_local=std::move(uids_copy), &added_items, owners_local=std::move(owners_copy)] + (Neo::ItemLidsProperty const& lids_property, + Neo::MeshScalarPropertyT&) { + auto new_items_lids{added_items.new_items.localIds()}; + Int32ConstSpan neo_items{ new_items_lids.data(), static_cast(new_items_lids.size()) }; + UniqueArray arcane_items(added_items.new_items.size()); + if (owners_local.empty()) + arcane_item_family->addItems(uids_local, arcane_items); + else + arcane_item_family->addItems(uids_local, arcane_items, Int32ConstArrayView{ owners_local.size(), owners_local.data() }); + // debug check lid matching. + if (!arcane_items.size() == added_items.new_items.size()) + arcane_item_family->traceMng()->fatal() << "Inconsistent item lids generation between Arcane and Neo, nb items Neo " + << added_items.new_items.size() << " nb items Arcane " << arcane_items.size(); if (!std::equal(added_items.new_items.begin(), added_items.new_items.end(), arcane_items.begin())) arcane_item_family->traceMng()->fatal() << "Inconsistent item lids generation between Arcane and Neo."; }); @@ -400,16 +668,15 @@ namespace mesh { auto& item_family = m_mesh.findFamily(itemKindArcaneToNeo(arcane_item_family->itemKind()), arcane_item_family->name().localstr()); - Neo::ItemRange removed_items{Neo::ItemLocalIds{{local_ids.begin(),local_ids.end()},0,0}}; + Neo::ItemRange removed_items{ Neo::ItemLocalIds{ { local_ids.begin(), local_ids.end() }, 0, 0 } }; m_mesh.scheduleRemoveItems(item_family, removed_items); // Remove Arcane items auto& mesh_graph = m_mesh.internalMeshGraph(); item_family.addMeshScalarProperty(PolyhedralFamily::m_arcane_remove_item_property_name.localstr()); mesh_graph.addAlgorithm(Neo::MeshKernel::InProperty{ item_family, m_mesh._removeItemPropertyName(item_family) }, Neo::MeshKernel::OutProperty{ item_family, PolyhedralFamily::m_arcane_remove_item_property_name.localstr() }, - [arcane_item_family,local_ids](Neo::MeshScalarPropertyT const&, - Neo::MeshScalarPropertyT&) { - // plutôt utiliser remove property ? + [arcane_item_family, local_ids](Neo::MeshScalarPropertyT const&, + Neo::MeshScalarPropertyT&) { arcane_item_family->removeItems(local_ids); }); } @@ -417,7 +684,7 @@ namespace mesh /*---------------------------------------------------------------------------*/ void scheduleAddConnectivity(PolyhedralFamily* arcane_source_item_family, - ItemLocalIds& source_items, + PolyhedralTools::ItemLocalIds& source_items, Integer nb_connected_items_per_item, PolyhedralFamily* arcane_target_item_family, Int64ConstArrayView target_items_uids, @@ -435,7 +702,7 @@ namespace mesh /*---------------------------------------------------------------------------*/ void scheduleAddConnectivity(PolyhedralFamily* arcane_source_item_family, - ItemLocalIds& source_items, + PolyhedralTools::ItemLocalIds& source_items, Int32ConstSmallSpan nb_connected_items_per_item, PolyhedralFamily* arcane_target_item_family, Int64ConstSmallSpan target_items_uids, @@ -449,22 +716,63 @@ namespace mesh connectivity_name); } + /*---------------------------------------------------------------------------*/ + /*---------------------------------------------------------------------------*/ + + void scheduleUpdateConnectivity(PolyhedralFamily* arcane_source_item_family, + PolyhedralTools::ItemLocalIds& source_items, + Integer nb_connected_items_per_item, + PolyhedralFamily* arcane_target_item_family, + Int64ConstArrayView target_items_uids, + String const& name) + { + // add connectivity in Neo + _scheduleAddConnectivity(arcane_source_item_family, + source_items, + nb_connected_items_per_item, + arcane_target_item_family, + target_items_uids, + name, + Neo::Mesh::ConnectivityOperation::Modify); + } + + /*---------------------------------------------------------------------------*/ + + void scheduleUpdateConnectivity(PolyhedralFamily* arcane_source_item_family, + PolyhedralTools::ItemLocalIds& source_items, + Int32ConstSmallSpan nb_connected_items_per_item, + PolyhedralFamily* arcane_target_item_family, + Int64ConstSmallSpan target_items_uids, + String const& connectivity_name) + { + _scheduleAddConnectivity(arcane_source_item_family, + source_items, + std::vector{ nb_connected_items_per_item.begin(), nb_connected_items_per_item.end() }, + arcane_target_item_family, + target_items_uids, + connectivity_name, + Neo::Mesh::ConnectivityOperation::Modify); + } + /*---------------------------------------------------------------------------*/ // template to handle nb_items_per_item type (an int or an array) template void _scheduleAddConnectivity(PolyhedralFamily* arcane_source_item_family, - ItemLocalIds& source_items, + PolyhedralTools::ItemLocalIds& source_items, ConnectivitySizeType&& nb_connected_items_per_item, PolyhedralFamily* arcane_target_item_family, Int64ConstSmallSpan target_item_uids, - String const& connectivity_name) + String const& connectivity_name, + Neo::Mesh::ConnectivityOperation operation = Neo::Mesh::ConnectivityOperation::Add) { // add connectivity in Neo auto& source_family = m_mesh.findFamily(itemKindArcaneToNeo(arcane_source_item_family->itemKind()), arcane_source_item_family->name().localstr()); auto& target_family = m_mesh.findFamily(itemKindArcaneToNeo(arcane_target_item_family->itemKind()), arcane_target_item_family->name().localstr()); + // Copy data to send them to Neo + UniqueArray target_item_uids_copy(target_item_uids); // Remove connectivities with a null item std::vector target_item_uids_filtered; target_item_uids_filtered.reserve(target_item_uids.size()); @@ -476,25 +784,28 @@ namespace mesh m_mesh.scheduleAddConnectivity(source_family, source_items.m_future_items, target_family, std::forward(nb_connected_items_per_item), std::move(target_item_uids_filtered), - connectivity_name.localstr()); + connectivity_name.localstr(), + operation); // Register Neo connectivities in Arcane auto& mesh_graph = m_mesh.internalMeshGraph(); std::string connectivity_add_output_property_name = std::string{ "EndOf" } + connectivity_name.localstr() + "Add"; source_family.addScalarProperty(connectivity_add_output_property_name); + // todo is operation == Modify, the update algo should not be needed. To check mesh_graph.addAlgorithm(Neo::MeshKernel::InProperty{ source_family, connectivity_name.localstr() }, Neo::MeshKernel::OutProperty{ source_family, connectivity_add_output_property_name }, - [arcane_source_item_family, arcane_target_item_family, &source_family, &target_family, this, connectivity_name](Neo::Mesh::ConnectivityPropertyType const&, - Neo::ScalarPropertyT&) { + [arcane_source_item_family, arcane_target_item_family, &source_family, &target_family, this] + (Neo::Mesh::ConnectivityPropertyType const& neo_connectivity, + Neo::ScalarPropertyT&) { auto item_internal_connectivity_list = arcane_source_item_family->itemInternalConnectivityList(); // todo check if families are default families - auto connectivity = m_mesh.getConnectivity(source_family, target_family, connectivity_name.localstr()); + auto connectivity = m_mesh.getConnectivity(source_family, target_family, neo_connectivity.name()); // to access connectivity data (for initializing Arcane connectivities) create a proxy on Neo connectivity - auto& connectivity_values = source_family.getConcreteProperty(connectivity_name.localstr()); - Neo::MeshArrayPropertyProxyT connectivity_proxy{connectivity_values}; + auto& connectivity_values = source_family.getConcreteProperty(neo_connectivity.name()); + Neo::MeshArrayPropertyProxyT connectivity_proxy{ connectivity_values }; auto nb_item_data = connectivity_proxy.arrayPropertyOffsets(); auto nb_item_size = connectivity_proxy.arrayPropertyOffsetsSize(); // todo check MeshArrayProperty::size item_internal_connectivity_list->_setConnectivityNbItem(arcane_target_item_family->itemKind(), - Int32ArrayView{ Integer(nb_item_size), nb_item_data }); + Int32ArrayView{ Integer(nb_item_size), nb_item_data }); auto max_nb_connected_items = connectivity.maxNbConnectedItems(); item_internal_connectivity_list->_setMaxNbConnectedItem(arcane_target_item_family->itemKind(), max_nb_connected_items); auto connectivity_values_data = connectivity_proxy.arrayPropertyData(); @@ -511,34 +822,53 @@ namespace mesh std::string flag_definition_output_property_name{ "EndOfFlagDefinition" }; source_family.addScalarProperty(flag_definition_output_property_name); mesh_graph.addAlgorithm(Neo::MeshKernel::InProperty{ source_family, connectivity_add_output_property_name }, Neo::MeshKernel::OutProperty{ source_family, flag_definition_output_property_name }, - [arcane_source_item_family, this, target_item_uids, &source_items](Neo::ScalarPropertyT const&, Neo::ScalarPropertyT const&) { + [arcane_source_item_family, this, target_item_uids_local=std::move(target_item_uids_copy), &source_items](Neo::ScalarPropertyT const&, Neo::ScalarPropertyT const&) { auto current_face_index = 0; auto arcane_faces = arcane_source_item_family->itemInfoListView(); for (auto face_lid : source_items.m_future_items.new_items) { Face current_face = arcane_faces[face_lid].toFace(); - if (target_item_uids[2 * current_face_index + 1] == NULL_ITEM_LOCAL_ID) { - // if (current_face.frontCell().null()) { - // Reste uniquement la back_cell ou aucune maille. - Int32 mod_flags = (target_item_uids[2 * current_face_index] != NULL_ITEM_LOCAL_ID) ? (ItemFlags::II_Boundary | ItemFlags::II_HasBackCell | ItemFlags::II_BackCellIsFirst) : 0; + if (target_item_uids_local[2 * current_face_index + 1] == NULL_ITEM_LOCAL_ID) { + // Only back cell or none + Int32 mod_flags = (target_item_uids_local[2 * current_face_index] != NULL_ITEM_LOCAL_ID) ? (ItemFlags::II_Boundary | ItemFlags::II_HasBackCell | ItemFlags::II_BackCellIsFirst) : 0; _setFaceInfos(mod_flags, current_face); } - else if (target_item_uids[2 * current_face_index] == NULL_ITEM_LOCAL_ID) { - // Reste uniquement la front cell + else if (target_item_uids_local[2 * current_face_index] == NULL_ITEM_LOCAL_ID) { + // Only front cell or none _setFaceInfos(ItemFlags::II_Boundary | ItemFlags::II_HasFrontCell | ItemFlags::II_FrontCellIsFirst, current_face); } else { - // Il y a deux mailles connectées. + // Both back and front cells _setFaceInfos(ItemFlags::II_HasFrontCell | ItemFlags::II_HasBackCell | ItemFlags::II_BackCellIsFirst, current_face); } ++current_face_index; } }); } + // Add an algorithm to remove items isolated after a connectivity update. Add it only once, when connectivity is added + if (operation == Neo::Mesh::ConnectivityOperation::Modify) return; + auto isolated_item_property_name = m_mesh._isolatedItemLidsPropertyName(source_family,target_family); + auto end_of_isolated_removal_property_name = std::string{ "EndOf" } + isolated_item_property_name; + source_family.addScalarProperty(end_of_isolated_removal_property_name); + mesh_graph.addAlgorithm(Neo::MeshKernel::InProperty{ source_family, isolated_item_property_name }, + Neo::MeshKernel::OutProperty{source_family, end_of_isolated_removal_property_name}, + [arcane_source_item_family](Neo::MeshScalarPropertyT const& isolated_items_lids_property, + Neo::ScalarPropertyT& end_of_isolated_removal_property) { + end_of_isolated_removal_property.set(1); + // remove Arcane items + Int32UniqueArray isolated_item_lids; + isolated_item_lids.reserve(isolated_items_lids_property.size()); + ENUMERATE_(Item,iitem,arcane_source_item_family->allItems()) { + if (isolated_items_lids_property[iitem->localId()] == 1) { + isolated_item_lids.push_back(iitem->localId()); + } + } + arcane_source_item_family->removeItems(isolated_item_lids); + }, Neo::MeshKernel::AlgorithmPropertyGraph::AlgorithmPersistence::KeepAfterExecution); } /*---------------------------------------------------------------------------*/ - void scheduleSetItemCoordinates(PolyhedralFamily* item_family, ItemLocalIds& local_ids, Real3ConstSmallSpan item_coords, VariableItemReal3& arcane_coords) + void scheduleSetItemCoordinates(PolyhedralFamily* item_family, PolyhedralTools::ItemLocalIds& local_ids, Real3ConstSmallSpan item_coords, VariableItemReal3& arcane_coords) { auto& _item_family = m_mesh.findFamily(itemKindArcaneToNeo(item_family->itemKind()), item_family->name().localstr()); std::vector _node_coords(item_coords.size()); @@ -561,9 +891,6 @@ namespace mesh arcane_coords[ItemLocalId{ item }] = { item_coords_property[item].x, item_coords_property[item].y, item_coords_property[item].z }; - // std::cout << "x y z : " << item_coords_property[item].x << " " - // << item_coords_property[item].y << " " - // << item_coords_property[item].z; } }); } @@ -574,7 +901,6 @@ namespace mesh { return m_mesh.applyScheduledOperations(); } - }; template <> class PolyhedralMeshImpl::ItemKindTraits @@ -598,6 +924,119 @@ namespace mesh static const Neo::ItemKind item_kind = Neo::ItemKind::IK_Dof; }; + /*---------------------------------------------------------------------------*/ + + void PolyhedralFamilySerializer::serializeItems(ISerializer* buf, Int32ConstArrayView items_local_ids) + { + ARCANE_CHECK_POINTER(m_family); + ARCANE_CHECK_POINTER(m_mng); + + switch (buf->mode()) { + case ISerializer::ModeReserve: { + _fillItemData(items_local_ids); + m_item_data.serialize(buf); + auto connectivities = m_mesh->_impl()->connectivities(m_family); + for (auto out_connectivity : connectivities) { + buf->reserve(out_connectivity.target_family.name()); + buf->reserve(out_connectivity.name); + } + break; + } + case ISerializer::ModePut: { + m_item_data.serialize(buf); + auto connectivities = m_mesh->_impl()->connectivities(m_family); + for (auto out_connectivity : connectivities) { + buf->put(out_connectivity.target_family.name()); + buf->put(out_connectivity.name); + } + clear(); + break; + } + case ISerializer::ModeGet: { + deserializeItems(buf, nullptr); + break; + } + } + } + + /*---------------------------------------------------------------------------*/ + + void PolyhedralFamilySerializer::deserializeItems(ISerializer* buf, Int32Array* items_local_ids) + { + ARCANE_ASSERT((buf->mode() == ISerializer::ModeGet), + ("Impossible to deserialize a buffer not in ModeGet. In ItemData::deserialize.Exiting")) + ARCANE_CHECK_POINTER(m_mesh); + ARCANE_CHECK_POINTER(m_family); + ARCANE_CHECK_POINTER(m_mng); + ItemData item_data; + if (items_local_ids) + item_data.deserialize(buf, m_mesh, *items_local_ids); + else + item_data.deserialize(buf, m_mesh); + auto connectivities = m_mesh->_impl()->connectivities(m_family); + auto nb_connectivities = connectivities.size(); + StringUniqueArray connected_family_names(nb_connectivities); + StringUniqueArray connectivity_names(nb_connectivities); + auto index = 0; + for (auto out_connectivity : connectivities) { + buf->get(connected_family_names[index]); + buf->get(connectivity_names[index]); + ++index; + } + _fillItemFamilyInfo(item_data, connected_family_names, connectivity_names); + + if (items_local_ids) { + m_deserialized_lids_array.push_back(items_local_ids); + // and that's all, they will be filled in finalizeItemAllocation + } + m_future_item_lids_array.push_back(std::make_shared()); + m_mesh->scheduleAllocateItems(m_family_info, *m_future_item_lids_array.back().get()); + + // Add serializer in mng. Update is triggered when finalizeItemAllocation is called + m_mng->addSerializer(this); + } + + /*---------------------------------------------------------------------------*/ + void PolyhedralFamilySerializer::_fillItemData(Int32ConstArrayView items_local_ids) + { + m_item_data = ItemData{ items_local_ids.size(), 0, m_family, nullptr, m_family->parallelMng()->commRank() }; + Int64Array& item_infos = m_item_data.itemInfos(); + Int32ArrayView item_owners = m_item_data.itemOwners(); + // Reserve size + const Integer nb_item = items_local_ids.size(); + item_infos.reserve(1 + nb_item * 32); // Size evaluation for hexa cell (the more data to store) : 1_family_info + nb_item *(2_info_per_family + 6 (faces) + 12 (edges) + 8 (vertices) connected elements) = 1 + nb_item *(6 + 6 + 12 +8) + // Fill item data (cf ItemData.h) + PolyhedralMeshImpl* mesh_impl = m_mesh->_impl(); + auto connectivities = mesh_impl->connectivities(m_family); + item_infos.add(connectivities.size()); + bool is_face_family = m_family->itemKind() == IK_Face; + ENUMERATE_ITEM (item, m_family->view(items_local_ids)) { + item_infos.add(42); // Item type, not used for polyhedral mesh + item_infos.add(item->uniqueId().asInt64()); + item_owners[item.index()] = item->owner(); + for (auto out_connectivity : connectivities) { + auto target_family = m_mesh->findItemFamily(PolyhedralMeshImpl::itemKindNeoToArcane(out_connectivity.target_family.itemKind()), + out_connectivity.target_family.name(), false, false); + // auto arcane_connected_items = target_family->view(); + auto arcane_connected_items = target_family->itemInfoListView(); + bool is_face_cell_connection = is_face_family && target_family->itemKind() == IK_Cell; + item_infos.add(PolyhedralMeshImpl::itemKindNeoToArcane(out_connectivity.target_family.itemKind())); + auto connected_items = out_connectivity[item.localId()]; + auto nb_connected_items = connected_items.size(); + item_infos.add(nb_connected_items); + if (is_face_cell_connection && item->itemBase().isBoundary() && item->itemBase().backCell().isNull()) { + item_infos.add(NULL_ITEM_UNIQUE_ID); + } + for (auto connected_item_lid : connected_items) { + item_infos.add(arcane_connected_items[connected_item_lid].uniqueId().asInt64()); + } + if (is_face_cell_connection && item->itemBase().isBoundary() && !item->itemBase().backCell().isNull()) { + item_infos.add(NULL_ITEM_UNIQUE_ID); + } + } + } + } + } // End namespace mesh /*---------------------------------------------------------------------------*/ @@ -614,7 +1053,12 @@ class mesh::PolyhedralMesh::PolyhedralMeshModifier void addItems(Int64ConstArrayView unique_ids, Int32ArrayView local_ids, eItemKind ik, const String& family_name) override { - m_mesh->addItems(unique_ids,local_ids,ik,family_name); + m_mesh->addItems(unique_ids, local_ids, ik, family_name); + } + + void addItems(Int64ConstArrayView unique_ids, Int32ArrayView local_ids, Int32ConstArrayView owners, eItemKind ik, const String& family_name) override + { + m_mesh->addItems(unique_ids, local_ids, owners, ik, family_name); } void removeItems(Int32ConstArrayView local_ids, eItemKind ik, const String& family_name) override @@ -623,6 +1067,7 @@ class mesh::PolyhedralMesh::PolyhedralMeshModifier } private: + PolyhedralMesh* m_mesh; }; @@ -647,7 +1092,7 @@ class mesh::PolyhedralMesh::InternalApi { if (v.meshStructure() != eMeshStructure::Polyhedral && v.meshAMRKind() != eMeshAMRKind::None) { ARCANE_FATAL("Incompatible mesh structure ({0}) and amr kind ({1}) for Polyhedral mesh {2}. Must be (Polyhedral,None). ", - v.meshStructure(),v.meshAMRKind(), m_mesh->name()); + v.meshStructure(), v.meshAMRKind(), m_mesh->name()); } m_mesh->m_mesh_kind = v; } @@ -664,7 +1109,7 @@ class mesh::PolyhedralMesh::InternalApi void removeNeedRemoveMarkedItems() override { - m_mesh->traceMng()->warning() << "PolyhedralMesh::removeNeedRemoveMarkedItems() not yet implemented in PolyhedralMesh"; + m_mesh->removeNeedRemoveMarkedItems(); } NodeLocalId addNode([[maybe_unused]] ItemUniqueId unique_id) override { @@ -683,6 +1128,11 @@ class mesh::PolyhedralMesh::InternalApi ARCANE_THROW(NotImplementedException, ""); } + IItemFamilySerializerMngInternal* familySerializerMng() const noexcept override + { + return m_mesh->polyhedralFamilySerializerMng(); + } + private: PolyhedralMesh* m_mesh = nullptr; @@ -697,37 +1147,56 @@ class mesh::PolyhedralMesh::NoCompactionMeshCompacter : public IMeshCompacter { public: + explicit NoCompactionMeshCompacter(PolyhedralMesh* mesh) : m_mesh(mesh) - , m_trace_mng(mesh->traceMng()){} + , m_trace_mng(mesh->traceMng()) + {} - void doAllActions() override {_info();}; + void doAllActions() override { _info(); }; - void beginCompact() override {_info();}; - void compactVariablesAndGroups() override {_info();}; - void updateInternalReferences() override {_info();}; - void endCompact() override {_info();}; - void finalizeCompact() override {_info();}; + void beginCompact() override { _info(); }; + void compactVariablesAndGroups() override { _info(); }; + void updateInternalReferences() override { _info(); }; + void endCompact() override { _info(); }; + void finalizeCompact() override { _info(); }; - IMesh* mesh() const override {return m_mesh;}; + IMesh* mesh() const override { return m_mesh; }; - const ItemFamilyCompactInfos* findCompactInfos(IItemFamily* family) const override {_info(); return nullptr;} + const ItemFamilyCompactInfos* findCompactInfos(IItemFamily*) const override + { + _info(); + return nullptr; + } - ePhase phase() const override {_info(); return ePhase::Ended;} + ePhase phase() const override + { + _info(); + return ePhase::Ended; + } - void setSorted(bool v) override {_info();}; + void setSorted(bool) override { _info(); }; - bool isSorted() const override {_info();return false;}; + bool isSorted() const override + { + _info(); + return false; + }; - ItemFamilyCollection families() const override {_info();return ItemFamilyCollection {};}; + ItemFamilyCollection families() const override + { + _info(); + return ItemFamilyCollection{}; + }; - void _setCompactVariablesAndGroups(bool v) override {_info();}; + void _setCompactVariablesAndGroups(bool) override { _info(); }; private: + PolyhedralMesh* m_mesh = nullptr; ITraceMng* m_trace_mng = nullptr; - void _info() const {m_trace_mng->info() << A_FUNCINFO << "No compacting in PolyhedralMesh";} + void _info() const { m_trace_mng->info() << A_FUNCINFO << "No compacting in PolyhedralMesh"; } }; /*---------------------------------------------------------------------------*/ @@ -737,13 +1206,14 @@ class mesh::PolyhedralMesh::NoCompactionMeshCompactMng : public IMeshCompactMng { public: + explicit NoCompactionMeshCompactMng(PolyhedralMesh* mesh) : m_mesh(mesh) , m_trace_mng(mesh->traceMng()) - , m_mesh_compacter{std::make_unique(m_mesh)} + , m_mesh_compacter{ std::make_unique(m_mesh) } {} - IMesh* mesh() const override {return m_mesh;} + IMesh* mesh() const override { return m_mesh; } IMeshCompacter* beginCompact() override { _info(); @@ -757,7 +1227,7 @@ class mesh::PolyhedralMesh::NoCompactionMeshCompactMng return m_mesh_compacter.get(); }; - void endCompact() override {_info();}; + void endCompact() override { _info(); }; IMeshCompacter* compacter() override { @@ -765,13 +1235,13 @@ class mesh::PolyhedralMesh::NoCompactionMeshCompactMng return m_mesh_compacter.get(); }; - private: + PolyhedralMesh* m_mesh = nullptr; ITraceMng* m_trace_mng = nullptr; std::unique_ptr m_mesh_compacter = nullptr; - void _info() const {m_trace_mng->info() << A_FUNCINFO << "No compacting in PolyhedralMesh";} + void _info() const { m_trace_mng->info() << A_FUNCINFO << "No compacting in PolyhedralMesh"; } }; /*---------------------------------------------------------------------------*/ @@ -803,7 +1273,6 @@ handle() const /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ - mesh::PolyhedralMesh:: PolyhedralMesh(ISubDomain* subdomain, const MeshBuildInfo& mbi) : EmptyMesh{ subdomain->traceMng() } @@ -816,15 +1285,16 @@ PolyhedralMesh(ISubDomain* subdomain, const MeshBuildInfo& mbi) , m_mesh_part_info{ makeMeshPartInfoFromParallelMng(m_parallel_mng) } , m_item_type_mng(ItemTypeMng::_singleton()) , m_mesh_kind(mbi.meshKind()) +, m_polyhedral_family_serializer_mng{ std::make_unique(this) } , m_initial_allocator(*this) , m_variable_mng{ subdomain->variableMng() } , m_mesh_checker{ this } -, m_internal_api{std::make_unique(this)} -, m_compact_mng{std::make_unique(this)} -, m_mesh_utilities{std::make_unique(this)} -, m_mesh_exchange_mng{std::make_unique(this)} -, m_item_family_network{std::make_unique(m_trace_mng)} -, m_ghost_layer_mng{std::make_unique(m_trace_mng)} +, m_internal_api{ std::make_unique(this) } +, m_compact_mng{ std::make_unique(this) } +, m_mesh_utilities{ std::make_unique(this) } +, m_mesh_exchange_mng{ std::make_unique(this) } +, m_item_family_network{ std::make_unique(m_trace_mng) } +, m_ghost_layer_mng{ std::make_unique(m_trace_mng) } { m_mesh_handle._setMesh(this); m_mesh_item_internal_list.mesh = this; @@ -836,26 +1306,42 @@ PolyhedralMesh(ISubDomain* subdomain, const MeshBuildInfo& mbi) void Arcane::mesh::PolyhedralMesh:: allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info) +{ + _allocateItems(item_allocation_info, ArrayView{}); +} + +/*---------------------------------------------------------------------------*/ + +void Arcane::mesh::PolyhedralMesh:: +allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info, ArrayView family_lids) +{ + _allocateItems(item_allocation_info, family_lids); +} + +/*---------------------------------------------------------------------------*/ + +void Arcane::mesh::PolyhedralMesh:: +_allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info, ArrayView family_lids) { // Second step read a vtk polyhedral mesh - m_subdomain->traceMng()->info() << "--PolyhedralMesh : allocate items --"; - UniqueArray item_local_ids(item_allocation_info.family_infos.size()); + m_subdomain->traceMng()->info() << "--PolyhedralMesh: allocate items --"; + UniqueArray item_local_ids(item_allocation_info.family_infos.size()); auto family_index = 0; // Prepare item creation for (auto& family_info : item_allocation_info.family_infos) { bool create_if_needed = true; - auto* item_family = _findItemFamily(family_info.item_kind, family_info.name,create_if_needed); - m_trace_mng->debug() << " Create items " << family_info.name; - m_mesh->scheduleAddItems(item_family, family_info.item_uids, item_local_ids[family_index++]); + auto* item_family = _findItemFamily(family_info.item_kind, family_info.name, create_if_needed); + m_trace_mng->debug(Trace::High) << "- Create items " << family_info.name; + m_mesh->scheduleAddItems(item_family, family_info.item_uids, family_info.item_owners.constSmallSpan(), item_local_ids[family_index++]); } // Prepare connectivity creation family_index = 0; for (auto& family_info : item_allocation_info.family_infos) { auto* item_family = _findItemFamily(family_info.item_kind, family_info.name); - m_trace_mng->debug(Trace::High) << "Current family " << family_info.name; - for (auto& current_connected_family_info : family_info.connected_family_info) { + m_trace_mng->debug(Trace::High) << "- Current family " << family_info.name; + for (auto& current_connected_family_info : family_info.connected_family_infos) { auto connected_family = _findItemFamily(current_connected_family_info.item_kind, current_connected_family_info.name); - m_trace_mng->debug(Trace::High) << " Create connectivity " << current_connected_family_info.connectivity_name; + m_trace_mng->debug(Trace::High) << "- Create connectivity " << current_connected_family_info.connectivity_name; // check if connected family exists if (!connected_family) { ARCANE_WARNING((String::format("Cannot find family {0} with kind {1} " @@ -883,9 +1369,11 @@ allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info) continue; } auto* item_family = _findItemFamily(family_info.item_kind, family_info.name); - if (item_family == itemFamily(IK_Node)) { // mesh node coords - m_arcane_node_coords = std::make_unique(VariableBuildInfo(this, family_info.item_coordinates_variable_name)); - m_arcane_node_coords->setUsed(true); + if (item_family == itemFamily(IK_Node)) { // create mesh node coords if doesn't exist + if (!m_arcane_node_coords.get()) { + m_arcane_node_coords = std::make_unique(VariableBuildInfo(this, family_info.item_coordinates_variable_name)); + m_arcane_node_coords->setUsed(true); + } } else { auto arcane_item_coords_var_ptr = std::make_unique(VariableBuildInfo(this, family_info.item_coordinates_variable_name), @@ -914,12 +1402,172 @@ allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info) else m_mesh->scheduleSetItemCoordinates(item_family, item_local_ids[family_index], family_info.item_coordinates, *m_arcane_item_coords[index++].get()); } - m_mesh->applyScheduledOperations(); + auto mesh_state = m_mesh->applyScheduledOperations(); + m_is_allocated = true; + // indicates mesh contains general Cells + itemTypeMng()->setMeshWithGeneralCells(this); + + if (!family_lids.empty()) { + auto index = 0; + ARCANE_CHECK(family_lids.size() == item_local_ids.size()); + for (auto& lid_array : item_local_ids) { + family_lids[index].resize(lid_array.size()); + lid_array.fillArrayView(family_lids[index].view(), mesh_state); + ++index; + } + } +} + +/*---------------------------------------------------------------------------*/ + +void Arcane::mesh::PolyhedralMesh:: +scheduleAllocateItems(const Arcane::ItemAllocationInfo::FamilyInfo& family_info, mesh::PolyhedralTools::ItemLocalIds& item_local_ids) +{ + // Second step read a vtk polyhedral mesh + m_subdomain->traceMng()->info() << "--PolyhedralMesh: schedule allocate items --"; + // Prepare item creation + bool create_if_needed = true; + auto* item_family = _findItemFamily(family_info.item_kind, family_info.name, create_if_needed); + m_trace_mng->debug(Trace::High) << "- Current family " << family_info.name; + m_trace_mng->debug(Trace::High) << "- Create items "; + m_mesh->scheduleAddItems(item_family, family_info.item_uids, family_info.item_owners.constSmallSpan(), item_local_ids); + // Prepare connectivity creation + for (auto& current_connected_family_info : family_info.connected_family_infos) { + auto connected_family = _findItemFamily(current_connected_family_info.item_kind, current_connected_family_info.name); + m_trace_mng->debug(Trace::High) << "- Create connectivity " << current_connected_family_info.connectivity_name; + // check if connected family exists + if (!connected_family) { + ARCANE_WARNING((String::format("Cannot find family {0} with kind {1} " + "The connectivity between {1} and this family is skipped", + current_connected_family_info.name, + current_connected_family_info.item_kind, + item_family->name()) + .localstr())); + continue; + } + m_mesh->scheduleUpdateConnectivity(item_family, + item_local_ids, + current_connected_family_info.nb_connected_items_per_item, + connected_family, + current_connected_family_info.connected_items_uids, + current_connected_family_info.connectivity_name); + } +} + +/*---------------------------------------------------------------------------*/ + +void Arcane::mesh::PolyhedralMesh:: +applyScheduledAllocateItems(UniqueArray> item_lids) +{ + // Create items and connectivities + auto mesh_state = m_mesh->applyScheduledOperations(); + // Fill item_lids (they are already filled in applyScheduledOperations: unlock them setting the mesh_state) + for (auto item_local_ids : item_lids) { + item_local_ids->m_mesh_state = std::make_shared(mesh_state); + } + + // Call Arcane ItemFamily endUpdate and mesh end update + for (auto& family : m_arcane_families) { + family->endUpdate(); + } + endUpdate(); m_is_allocated = true; // indicates mesh contains general Cells itemTypeMng()->setMeshWithGeneralCells(this); } +/*---------------------------------------------------------------------------*/ + +void mesh::PolyhedralMesh::removeNeedRemoveMarkedItems() +{ + // Loop through all item families in the mesh: must include DoF and Particles + for (auto family_index = 0 ; family_index < m_arcane_families.size(); ++family_index) { + // Get the list of local IDs for items to remove + auto* family = m_arcane_families[family_index].get(); + Int32UniqueArray items_to_remove; + items_to_remove.reserve(family->nbItem()); + auto& items_map = family->itemsMap(); + if (items_map.count() == 0) continue; + items_map.eachItem([&](ItemBase item) { + // Schedule removal of items marked for removal + auto f = item.flags(); + if (f & ItemFlags::II_NeedRemove) { + f &= ~ItemFlags::II_NeedRemove & ItemFlags::II_Suppressed; + item.toMutable().setFlags(f); + items_to_remove.add(item.localId()); + } + }); + if (!items_to_remove.empty()) { + removeItems(items_to_remove,family); + } + } +} + +/*---------------------------------------------------------------------------*/ + +Arcane::mesh::PolyhedralFamilySerializerMng* mesh::PolyhedralMesh:: +polyhedralFamilySerializerMng() +{ + return m_polyhedral_family_serializer_mng.get(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void Arcane::mesh::PolyhedralMesh:: +_endUpdateFamilies() +{ + for (auto& family : m_arcane_families) { + family->endUpdate(); + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void Arcane::mesh::PolyhedralMesh:: +_computeFamilySynchronizeInfos() +{ + m_subdomain->traceMng()->info() << "Computing family synchronization information for " << name(); + for( auto& family : m_arcane_families ){ + family->computeSynchronizeInfos(); + } + + // Write topology for cell synchronization + if (!platform::getEnvironmentVariable("ARCANE_DUMP_VARIABLE_SYNCHRONIZER_TOPOLOGY").null()){ + auto* var_syncer = cellFamily()->allItemsSynchronizer(); + Int32 iteration = m_subdomain->commonVariables().globalIteration(); + String file_name = String::format("{0}_sync_topology_iter{1}.json",name(),iteration); + mesh_utils::dumpSynchronizerTopologyJSON(var_syncer,file_name); + } +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void Arcane::mesh::PolyhedralMesh:: +_notifyEndUpdateForFamilies() +{ + for( auto& family : m_arcane_families ) + family->_internalApi()->notifyEndUpdateFromMesh(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void Arcane::mesh::PolyhedralMesh:: +_computeGroupSynchronizeInfos() +{ + auto action = [](ItemGroup& group) { + if (group.hasSynchronizer()) + group.synchronizer()->compute(); + }; + + m_trace_mng->info() << "Computing group synchronization information for " << name(); + meshvisitor::visitGroups(this, action); + +} + /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -1130,13 +1778,14 @@ _createUnitMesh() auto node_family = m_default_arcane_families[IK_Node]; Int64UniqueArray cell_uids{ 0 }, node_uids{ 0, 1, 2, 3, 4, 5 }; // todo add a cell_lids struct (containing future) - PolyhedralMeshImpl::ItemLocalIds cell_lids, node_lids; + PolyhedralTools::ItemLocalIds cell_lids, node_lids; m_mesh->scheduleAddItems(cell_family, cell_uids.constView(), cell_lids); m_mesh->scheduleAddItems(node_family, node_uids.constView(), node_lids); int nb_node = 6; + Int64UniqueArray node_cells_uids{ 0, 0, 0, 0, 0, 0 }; m_mesh->scheduleAddConnectivity(cell_family, cell_lids, nb_node, node_family, node_uids, String{ "CellToNodes" }); m_mesh->scheduleAddConnectivity(node_family, node_lids, 1, cell_family, - Int64UniqueArray{ 0, 0, 0, 0, 0, 0 }, String{ "NodeToCells" }); + node_cells_uids, String{ "NodeToCells" }); m_mesh->applyScheduledOperations(); cell_family->endUpdate(); node_family->endUpdate(); @@ -1159,21 +1808,6 @@ endUpdate() m_default_arcane_families[ik] = m_empty_arcane_families[ik].get(); } } - // Wip add a first version of a family network. Should be done automatically in addConectivity - m_item_family_network->addDependency(itemFamily(IK_Cell), itemFamily(IK_Node), nullptr); - m_item_family_network->addDependency(itemFamily(IK_Cell), itemFamily(IK_Face), nullptr); - m_item_family_network->addDependency(itemFamily(IK_Cell), itemFamily(IK_Edge), nullptr); - m_item_family_network->addDependency(itemFamily(IK_Face), itemFamily(IK_Node),nullptr); - m_item_family_network->addDependency(itemFamily(IK_Edge), itemFamily(IK_Node),nullptr); - m_item_family_network->addRelation(itemFamily(IK_Face), itemFamily(IK_Edge),nullptr); - m_item_family_network->addRelation(itemFamily(IK_Face), itemFamily(IK_Face),nullptr); - m_item_family_network->addRelation(itemFamily(IK_Face), itemFamily(IK_Cell),nullptr); - m_item_family_network->addRelation(itemFamily(IK_Edge), itemFamily(IK_Cell),nullptr); - m_item_family_network->addRelation(itemFamily(IK_Node), itemFamily(IK_Cell),nullptr); - m_item_family_network->addRelation(itemFamily(IK_Node), itemFamily(IK_Face),nullptr); - m_item_family_network->addRelation(itemFamily(IK_Node), itemFamily(IK_Edge),nullptr); - m_item_family_network->addRelation(itemFamily(IK_Edge), itemFamily(IK_Face),nullptr); - } /*---------------------------------------------------------------------------*/ @@ -1389,11 +2023,26 @@ _compactMng() void mesh::PolyhedralMesh:: addItems(Int64ConstArrayView unique_ids, Int32ArrayView local_ids, eItemKind ik, const String& family_name) { + ARCANE_ASSERT((unique_ids.size() == local_ids.size()),("local and unique ids arrays must have same size")) + auto* item_family = _findItemFamily(ik, family_name, false); + PolyhedralTools::ItemLocalIds item_local_ids; + m_mesh->scheduleAddItems(item_family, unique_ids, item_local_ids); + auto mesh_state = m_mesh->applyScheduledOperations(); + item_local_ids.fillArrayView(local_ids, mesh_state); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + +void mesh::PolyhedralMesh:: +addItems(Int64ConstArrayView unique_ids, Int32ArrayView local_ids, Int32ConstArrayView owners, eItemKind ik, const String& family_name) +{ + ARCANE_ASSERT((unique_ids.size() == local_ids.size() && (unique_ids.size()== owners.size())),("local/unique ids and owners arrays must have same size")) auto* item_family = _findItemFamily(ik, family_name, false); - PolyhedralMeshImpl::ItemLocalIds item_local_ids; - m_mesh->scheduleAddItems(item_family,unique_ids,item_local_ids); + PolyhedralTools::ItemLocalIds item_local_ids; + m_mesh->scheduleAddItems(item_family, unique_ids, owners,item_local_ids); auto mesh_state = m_mesh->applyScheduledOperations(); - item_local_ids.fillArrayView(local_ids,mesh_state); + item_local_ids.fillArrayView(local_ids, mesh_state); } /*---------------------------------------------------------------------------*/ @@ -1403,13 +2052,29 @@ void mesh::PolyhedralMesh:: removeItems(Int32ConstArrayView local_ids, eItemKind ik, const String& family_name) { auto* item_family = _findItemFamily(ik, family_name, false); - m_mesh->scheduleRemoveItems(item_family,local_ids); + if (!item_family) { + ARCANE_FATAL("ItemFamily with name {0} and kind {1} does not exist in the mesh.", family_name,ik); + } + m_mesh->scheduleRemoveItems(item_family, local_ids); m_mesh->applyScheduledOperations(); } /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +void mesh::PolyhedralMesh:: +removeItems(Int32ConstArrayView local_ids, IItemFamily* family) +{ + if (local_ids.empty()) return; + if (!family) { + ARCANE_FATAL("Invalid IItemFamily passed to removeItems."); + } + removeItems(local_ids, family->itemKind(), family->name()); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ + void mesh::PolyhedralMesh:: addNodes(Int64ConstArrayView nodes_uid, Int32ArrayView nodes_lid) { @@ -1423,20 +2088,19 @@ void mesh::PolyhedralMesh:: exchangeItems() { m_trace_mng->info() << "PolyhedralMesh::_exchangeItems() do_compact?=" << "false" - << " nb_exchange=" << 0 << " version=" << 0; + << " nb_exchange=" << 0 << " version=" << 0; _exchangeItems(); String check_exchange = platform::getEnvironmentVariable("ARCANE_CHECK_EXCHANGE"); - if (!check_exchange.null()){ + if (!check_exchange.null()) { m_mesh_checker.checkGhostCells(); m_trace_mng->pwarning() << "CHECKING SYNCHRONISATION !"; m_mesh_checker.checkVariablesSynchronization(); m_mesh_checker.checkItemGroupsSynchronization(); } - if (checkLevel()>=2) + if (checkLevel() >= 2) m_mesh_checker.checkValidMesh(); - else if (checkLevel()>=1) + else if (checkLevel() >= 1) m_mesh_checker.checkValidConnectivity(); - } /*---------------------------------------------------------------------------*/ @@ -1447,13 +2111,12 @@ _exchangeItems() { // todo handle submeshes, cf. DynamicMesh - Trace::Setter mci(traceMng(),_className()); + Trace::Setter mci(traceMng(), _className()); if (!m_is_dynamic) ARCANE_FATAL("property isDynamic() has to be 'true'"); - if (arcane_debug_load_balancing){ - // TODO: faire cela dans le MeshExchanger et par famille. + if (arcane_debug_load_balancing) { for (auto& family : m_arcane_families) { family->itemsNewOwner().checkIfSync(); } @@ -1462,7 +2125,7 @@ _exchangeItems() IMeshExchanger* iexchanger = m_mesh_exchange_mng->beginExchange(); // If no entity to exchange return - if (iexchanger->computeExchangeInfos()){ + if (iexchanger->computeExchangeInfos()) { m_trace_mng->pwarning() << "No load balance is performed"; m_mesh_exchange_mng->endExchange(); return; @@ -1477,40 +2140,35 @@ _exchangeItems() // Update groups : remove gone entities // invalidate computed groups { - auto action = [](ItemGroup& group) - { + auto action = [](ItemGroup& group) { if (group.internal()->hasComputeFunctor() || group.isLocalToSubDomain()) group.invalidate(); else group.internal()->removeSuppressedItems(); }; - // todo update submeshes meshvisitor::visitGroups(this, action); } iexchanger->allocateReceivedItems(); - // todo update families (endUpdate and compute SynchronizeInfo cf. DynamicMesh::_internalEndUpdateInit(true);) + // Equivalent of DynamicMesh::_internalEndUpdateInit + _endUpdateFamilies(); + _computeFamilySynchronizeInfos(); // Update groups iexchanger->updateItemGroups(); - auto action = [](ItemGroup& group) - { - if (group.hasSynchronizer()) - group.synchronizer()->compute(); - }; - - m_trace_mng->info() << "Computing group synchronization information for " << name(); - meshvisitor::visitGroups(this,action); + _computeGroupSynchronizeInfos(); iexchanger->updateVariables(); - // todo DynamicMesh::_internalEndUpdateFinal(bool) + // Equivalent DynamicMesh::_internalEndUpdateFinal(bool) + // check mesh is conform with reference (complete sequential connectivity on a file) + m_mesh_checker.checkMeshFromReferenceFile(); + _notifyEndUpdateForFamilies(); iexchanger->finalizeExchange(); - // TODO: garantir cet appel en cas d'exception. m_mesh_exchange_mng->endExchange(); // // todo handle extra ghost @@ -1518,7 +2176,6 @@ _exchangeItems() // this->endUpdate(true,false); // else this->endUpdate(); - } /*---------------------------------------------------------------------------*/ @@ -1531,13 +2188,13 @@ prepareForDump() auto want_dump = false; auto need_compact = false; m_trace_mng->info(4) << "DynamicMesh::prepareForDump() name=" << name() - << " need_compact?=" << need_compact - << " want_dump?=" << want_dump - << " timestamp=" << 0; + << " need_compact?=" << need_compact + << " want_dump?=" << want_dump + << " timestamp=" << 0; { eMeshEventType t = eMeshEventType::BeginPrepareDump; - m_mesh_events.eventObservable(t).notify(MeshEventArgs(this,t)); + m_mesh_events.eventObservable(t).notify(MeshEventArgs(this, t)); } // todo use Properties @@ -1549,7 +2206,7 @@ prepareForDump() { eMeshEventType t = eMeshEventType::EndPrepareDump; - m_mesh_events.eventObservable(t).notify(MeshEventArgs(this,t)); + m_mesh_events.eventObservable(t).notify(MeshEventArgs(this, t)); } } @@ -1683,6 +2340,13 @@ _modifierInternalApi() /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ +mesh::PolyhedralMeshImpl* mesh::PolyhedralMesh::_impl() +{ + return m_mesh.get(); +} + +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ } // End namespace Arcane diff --git a/arcane/src/arcane/mesh/PolyhedralMesh.h b/arcane/src/arcane/mesh/PolyhedralMesh.h index 75b6607419..1b1be42e00 100644 --- a/arcane/src/arcane/mesh/PolyhedralMesh.h +++ b/arcane/src/arcane/mesh/PolyhedralMesh.h @@ -64,6 +64,12 @@ namespace Arcane::mesh class PolyhedralMeshImpl; class PolyhedralFamily; +class PolyhedralFamilySerializer; +class PolyhedralFamilySerializerMng; +namespace PolyhedralTools +{ + class ItemLocalIds; +} /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -74,6 +80,7 @@ class PolyhedralMesh { friend class PolyhedralFamily; + friend class PolyhedralFamilySerializer; private: @@ -90,11 +97,18 @@ class PolyhedralMesh ItemTypeMng* m_item_type_mng = nullptr; MeshKind m_mesh_kind; MeshEventsImpl m_mesh_events; + std::unique_ptr m_polyhedral_family_serializer_mng; public: // IPolyhedralMeshInitialAllocator interface void allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info) override; + // Get items local ids after creation. Argument family_ids will be resized in the method + void allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info, ArrayView family_lids); + void scheduleAllocateItems(const Arcane::ItemAllocationInfo::FamilyInfo& family_info, PolyhedralTools::ItemLocalIds& future_item_local_ids); + void applyScheduledAllocateItems(UniqueArray> item_lids); + void removeNeedRemoveMarkedItems(); + PolyhedralFamilySerializerMng* polyhedralFamilySerializerMng(); public: @@ -158,6 +172,8 @@ class PolyhedralMesh // IPrimaryMeshBase interface IMeshInitialAllocator* initialAllocator() override { return &m_initial_allocator; } + void _allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info, ArrayView family_lids); + // IMeshBase interface public: @@ -280,7 +296,7 @@ class PolyhedralMesh ARCANE_NOT_YET_IMPLEMENTED("Parallel for polyhedral mesh is WIP"); } } - void endUpdate(bool update_ghost_layer, bool remove_old_ghost) override + void endUpdate(bool, bool) override { // not yet implemented : must exit in parallel if (m_subdomain->parallelMng()->isParallel()) { @@ -315,21 +331,35 @@ class PolyhedralMesh void prepareForDump() override; - bool useMeshItemFamilyDependencies() const override {return true;} + bool useMeshItemFamilyDependencies() const override {return false;} IMeshModifierInternal* _modifierInternalApi() override; + IItemFamilyModifier* findItemFamilyModifier(eItemKind, const String&) override {return nullptr;} + + void connectivities(IItemFamily* source_family); + private: void addItems(Int64ConstArrayView unique_ids, Int32ArrayView local_ids, eItemKind ik, const String& family_name); + void addItems(Int64ConstArrayView unique_ids, Int32ArrayView local_ids, Int32ConstArrayView owners, eItemKind ik, const String& family_name); void removeItems(Int32ConstArrayView local_ids, eItemKind ik, const String& family_name); + void removeItems(Int32ConstArrayView local_ids, IItemFamily* family); PolyhedralFamily* _createItemFamily(eItemKind ik, const String& name); PolyhedralFamily* _itemFamily(eItemKind ik); PolyhedralFamily* _findItemFamily(eItemKind ik, const String& name, bool create_if_needed = false); const char* _className() const { return "PolyhedralMesh"; } - void _exchangeItems(); + void _exchangeItems(); + + void _endUpdateFamilies(); + + void _computeFamilySynchronizeInfos(); + + void _notifyEndUpdateForFamilies(); + + void _computeGroupSynchronizeInfos(); #endif // ARCANE_HAS_POLYHEDRAL_MESH_TOOLS @@ -339,6 +369,7 @@ class PolyhedralMesh void _createUnitMesh(); void _updateMeshInternalList(eItemKind kind); + PolyhedralMeshImpl* _impl(); }; /*---------------------------------------------------------------------------*/ From 4c66b332c4dc8b651e20435ab44bf5e9a6131c5b Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 18:47:39 +0200 Subject: [PATCH 06/15] [arcane,mesh] Finalize exchanged item allocation for polyhedral mesh. --- arcane/src/arcane/mesh/MeshExchanger.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arcane/src/arcane/mesh/MeshExchanger.cc b/arcane/src/arcane/mesh/MeshExchanger.cc index f20ffa2364..4bd6b388d6 100644 --- a/arcane/src/arcane/mesh/MeshExchanger.cc +++ b/arcane/src/arcane/mesh/MeshExchanger.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* MeshExchanger.cc (C) 2000-2024 */ +/* MeshExchanger.cc (C) 2000-2025 */ /* */ /* Gestion d'un échange de maillage entre sous-domaines. */ /*---------------------------------------------------------------------------*/ @@ -26,6 +26,8 @@ #include "arcane/mesh/DynamicMesh.h" #include "arcane/mesh/MeshExchange.h" #include "arcane/core/internal/IMeshModifierInternal.h" +#include "arcane/core/internal/IItemFamilySerializerMngInternal.h" +#include "arcane/core/internal/IMeshInternal.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ @@ -351,6 +353,10 @@ allocateReceivedItems() for( IItemFamilyExchanger* e : m_family_exchangers ){ e->readAndAllocItems(); // Attention, ne procède plus sur les différents sous-maillages } + // If needed, finalize item allocations (for polyhedral meshes) + auto* family_serializer_mng = m_mesh->_internalApi()->familySerializerMng(); + if (family_serializer_mng) family_serializer_mng->finalizeItemAllocation(); + // Build item relations (only dependencies are build in readAndAllocItems) // only for families registered in the graph if (m_mesh->itemFamilyNetwork() && m_mesh->itemFamilyNetwork()->isActivated()) From 74b0ffded54af80341860d3ba3663a4cb0797723 Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 18:49:14 +0200 Subject: [PATCH 07/15] [arcane,mesh] Fix problem in group synchronization test. Own groups cannot be tested. --- arcane/src/arcane/mesh/ItemGroupsSynchronize.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arcane/src/arcane/mesh/ItemGroupsSynchronize.cc b/arcane/src/arcane/mesh/ItemGroupsSynchronize.cc index 12e78a50fd..6de75cbf86 100644 --- a/arcane/src/arcane/mesh/ItemGroupsSynchronize.cc +++ b/arcane/src/arcane/mesh/ItemGroupsSynchronize.cc @@ -181,6 +181,7 @@ checkSynchronize() // TODO: vérifier que tous les sous-domaines ont les mêmes groupes. Integer nb_diff = 0; for( const ItemGroup& group : m_item_family->groups() ){ + if (group.isOwn()) continue; m_var.fill(0); ENUMERATE_ITEM(i_item,group){ m_var[*i_item] = 1; @@ -188,7 +189,7 @@ checkSynchronize() Integer diff = m_var.checkIfSync(10); if (diff!=0){ error() << "Group is not in sync (name=" << group.name() - << ", nb_diff=" << nb_diff << ")"; + << ", nb_diff=" << diff << ")"; } nb_diff += diff; } From bd9f645574466340fa31ae7a4dee93eaca8089c1 Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 18:52:15 +0200 Subject: [PATCH 08/15] [arcane,tests] Add some checks and prints in ExchangeItemsUnitTest. --- .../src/arcane/tests/ExchangeItemsUnitTest.cc | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/arcane/src/arcane/tests/ExchangeItemsUnitTest.cc b/arcane/src/arcane/tests/ExchangeItemsUnitTest.cc index bb04998ab5..6bc3851daf 100644 --- a/arcane/src/arcane/tests/ExchangeItemsUnitTest.cc +++ b/arcane/src/arcane/tests/ExchangeItemsUnitTest.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* ExchangeItemsUnitTest.cc (C) 2000-2023 */ +/* ExchangeItemsUnitTest.cc (C) 2000-2025 */ /* */ /* Service du test de l'échange d'items. */ /*---------------------------------------------------------------------------*/ @@ -21,6 +21,8 @@ #include "arcane/IPrimaryMesh.h" #include "arcane/IMeshUtilities.h" #include "arcane/IVariableSynchronizer.h" +#include "arcane/utils/ValueChecker.h" +#include "arccore/trace/ITraceMng.h" enum TestOperation { @@ -120,6 +122,20 @@ _partitionCells() mesh()->modifier()->setDynamic(true); mesh()->toPrimaryMesh()->exchangeItems();// update ghost is done. + Int32UniqueArray owners, ref_owners; + owners.reserve(mesh()->cellFamily()->nbItem()); + ref_owners.reserve(mesh()->cellFamily()->nbItem()); + ENUMERATE_CELL(icell, allCells()) { + info() << "Cell uid " << icell->uniqueId() << " has owner " << icell->owner(); + owners.push_back(icell->owner()); + ref_owners.push_back(0); + } + + ValueChecker vc{ A_FUNCINFO }; + vc.areEqualArray(owners, ref_owners, "Owners must be 0."); + + + // une fois tout sur un proc on redispatche pour mimer un partitionement initial ENUMERATE_CELL(icell, allCells()) { cell_new_owners[icell] = (icell.index()*subDomain()->parallelMng()->commSize())/mesh()->cellFamily()->nbItem(); @@ -148,11 +164,15 @@ _exchangeCellOwner() ENUMERATE_CELL(icell, allCells()) { cell_new_owners[icell] = comm_size-(icell->owner()+1); // exchange owner info() << "Cell uid " << icell->uniqueId() << " has owner " << icell->owner(); + info() << "Cell uid " << icell->uniqueId() << " will move to " << cell_new_owners[icell]; } mesh()->utilities()->changeOwnersFromCells(); mesh()->modifier()->setDynamic(true); mesh()->toPrimaryMesh()->exchangeItems();// update ghost is done. + ENUMERATE_CELL(icell, allCells()) { + info() << "Cell uid " << icell->uniqueId() << " has owner " << icell->owner(); + } _computeGhostPPVariable(); } From 44824e21b9f3368dfa699e1820d4bd969bfbb37a Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 18:53:59 +0200 Subject: [PATCH 09/15] [arcane,tests] Add exchange unit tests for polyhedral mesh. --- arcane/src/arcane/tests/CMakeLists.txt | 2 + .../tests/testExchangeItem-polyhedral-1.arc | 49 +++++++++++++++++++ .../tests/testExchangeItem-polyhedral-2.arc | 49 +++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 arcane/tests/testExchangeItem-polyhedral-1.arc create mode 100644 arcane/tests/testExchangeItem-polyhedral-2.arc diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index b3a8425a3b..a51b996014 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -734,6 +734,8 @@ if(${VTK_PACKAGE_PREFIX}IOXML_FOUND) arcane_add_test_sequential(polyhedral_vtk3 testMeshPolyhedral-3.arc) arcane_add_test_sequential(polyhedral_vtk4 testMeshPolyhedral-4.arc) arcane_add_test_sequential(polyhedral_with_dofs testMeshPolyhedralWithDoFs.arc) + arcane_add_test_parallel(polyhedral_exchange_item1 testExchangeItem-polyhedral-1.arc 3) + arcane_add_test_parallel(polyhedral_exchange_item2 testExchangeItem-polyhedral-2.arc 3) endif() endif() if(MEDFile_FOUND) diff --git a/arcane/tests/testExchangeItem-polyhedral-1.arc b/arcane/tests/testExchangeItem-polyhedral-1.arc new file mode 100644 index 0000000000..122cbe2f3c --- /dev/null +++ b/arcane/tests/testExchangeItem-polyhedral-1.arc @@ -0,0 +1,49 @@ + + + + Test Arcane 1 + Test Arcane 1 + UnitTest + + + + + + + + faultx1_2x1x1.vtk + + true + false + + + + + + + repartition-cells + + + + + 1 + + true + true + + CellFamilyNewOwnerName + ExchangeItemsTest_CellUids + GhostPP + NodeGhostPP + FaceGhostPP + AllCells + + + + + false + + + + + diff --git a/arcane/tests/testExchangeItem-polyhedral-2.arc b/arcane/tests/testExchangeItem-polyhedral-2.arc new file mode 100644 index 0000000000..3a8c389098 --- /dev/null +++ b/arcane/tests/testExchangeItem-polyhedral-2.arc @@ -0,0 +1,49 @@ + + + + Test Arcane 1 + Test Arcane 1 + UnitTest + + + + + + + + faultx1_2x1x1.vtk + + true + false + + + + + + + exchange-cell-owners + + + + + 1 + + true + true + + CellFamilyNewOwnerName + ExchangeItemsTest_CellUids + GhostPP + NodeGhostPP + FaceGhostPP + AllCells + + + + + false + + + + + From e4028a6f69e7cc21ff0e948d6c27c4d5ac5d2c64 Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 18:55:43 +0200 Subject: [PATCH 10/15] [arcane,tests] Adapt tests with polyhedral mesh for parallel. --- .../arcane/tests/MeshPolyhedralTestModule.cc | 41 ++++- arcane/src/arcane/tests/dof/DoFTester.cc | 163 ++++++++++-------- 2 files changed, 124 insertions(+), 80 deletions(-) diff --git a/arcane/src/arcane/tests/MeshPolyhedralTestModule.cc b/arcane/src/arcane/tests/MeshPolyhedralTestModule.cc index af2aebf2c1..88a7c0e46a 100644 --- a/arcane/src/arcane/tests/MeshPolyhedralTestModule.cc +++ b/arcane/src/arcane/tests/MeshPolyhedralTestModule.cc @@ -173,6 +173,14 @@ _testEnumerationAndConnectivities(IMesh* mesh) for (Edge edge : iface->edges()) { debug(Trace::High) << "face edge lid " << edge.localId() << " uid " << edge.uniqueId().asInt64(); } + // check boundaryCell + if (iface->cells().size() == 1 && !iface->isSubDomainBoundary()) {ARCANE_FATAL("A face with one cell is boundary.");} + if (iface->isSubDomainBoundary()) { + debug(Trace::High) << "face boundary cell lid " << iface->boundaryCell().localId(); + debug(Trace::High) << "face boundary cell uid " << iface->boundaryCell().uniqueId().asInt64(); + if (iface->boundaryCell().localId() == NULL_ITEM_LOCAL_ID) {ARCANE_FATAL("A boundary face's boundary cell is null.");} + if (iface->cells().size() > 1) {ARCANE_FATAL("A boundary face has only one cell.");} + } } // Check face flags _checkFlags(mesh); @@ -384,12 +392,19 @@ _testGroups(IMesh* mesh) if (group.null()) ARCANE_FATAL("Could not find group {0}", group_infos->getName()); ValueChecker vc{ A_FUNCINFO }; - vc.areEqual(group.size(), group_infos->getSize(), "check group size"); + auto group_size = 0; + if (parallelMng()->isParallel()) { + group_size = parallelMng()->reduce(Parallel::ReduceSum, group.own().size()); + } + else { + group_size = group.size(); + } + vc.areEqual(group_size, group_infos->getSize(), "check group size"); } ValueChecker vc{ A_FUNCINFO }; auto nb_internal_group = 19; if (subDomain()->parallelMng()->isParallel()) { - nb_internal_group = 23; + nb_internal_group = 27; } auto nb_group = nb_internal_group + options()->nbMeshGroup; vc.areEqual(nb_group, mesh->groups().count(), "check number of groups in the mesh"); @@ -413,11 +428,21 @@ _testDimensions(IMesh* mesh) auto mesh_size = options()->meshSize(); if (mesh_size.empty()) return; + auto nb_cell = mesh->nbCell(); + auto nb_face = mesh->nbFace(); + auto nb_edge = mesh->nbEdge(); + auto nb_node = mesh->nbNode(); + if (parallelMng()->isParallel()) { + nb_cell = parallelMng()->reduce(Parallel::ReduceSum, mesh->ownCells().size()); + nb_face = parallelMng()->reduce(Parallel::ReduceSum, mesh->ownFaces().size()); + nb_edge = parallelMng()->reduce(Parallel::ReduceSum, mesh->ownEdges().size()); + nb_node = parallelMng()->reduce(Parallel::ReduceSum, mesh->ownNodes().size()); + } ValueChecker vc(A_FUNCINFO); - vc.areEqual(mesh->nbCell(), mesh_size[0]->getNbCells(), "check number of cells"); - vc.areEqual(mesh->nbFace(), mesh_size[0]->getNbFaces(), "check number of faces"); - vc.areEqual(mesh->nbEdge(), mesh_size[0]->getNbEdges(), "check number of edges"); - vc.areEqual(mesh->nbNode(), mesh_size[0]->getNbNodes(), "check number of nodes"); + vc.areEqual(nb_cell, mesh_size[0]->getNbCells(), "check number of cells"); + vc.areEqual(nb_face, mesh_size[0]->getNbFaces(), "check number of faces"); + vc.areEqual(nb_edge, mesh_size[0]->getNbEdges(), "check number of edges"); + vc.areEqual(nb_node, mesh_size[0]->getNbNodes(), "check number of nodes"); } /*---------------------------------------------------------------------------*/ @@ -528,7 +553,7 @@ _checkVariableWithRefValue(VariableRefType variable, Arcane::ItemGroup item_grou debug(Trace::High) << variable.name() << " at item " << iitem.localId() << " " << variable[iitem]; variable_sum += variable[iitem]; } - if (variable_sum != ref_sum) { + if (variable_sum != ref_sum && !parallelMng()->isParallel()) { fatal() << "Error on variable " << variable.name(); } } @@ -550,8 +575,6 @@ _checkArrayVariable(VariableArrayRefType variable_ref, ItemGroup item_group) debug(Trace::High) << variable_ref.name() << " at item " << iitem.localId() << variable_ref[iitem]; } ValueChecker vc{ A_FUNCINFO }; - if (array_size == 0) - ARCANE_FATAL("Array variable {0} array size is zero"); std::vector ref_sum(array_size); std::iota(ref_sum.begin(), ref_sum.end(), 1.); vc.areEqual(variable_sum, item_group.size() * std::accumulate(ref_sum.begin(), ref_sum.end(), 0.), "check array variable values"); diff --git a/arcane/src/arcane/tests/dof/DoFTester.cc b/arcane/src/arcane/tests/dof/DoFTester.cc index 2cc7c4f47c..b0f86ed8ee 100644 --- a/arcane/src/arcane/tests/dof/DoFTester.cc +++ b/arcane/src/arcane/tests/dof/DoFTester.cc @@ -1,11 +1,11 @@ // -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*- //----------------------------------------------------------------------------- -// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) +// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com) // See the top-level COPYRIGHT file for details. // SPDX-License-Identifier: Apache-2.0 //----------------------------------------------------------------------------- /*---------------------------------------------------------------------------*/ -/* DoFTester.cc (C) 2000-2024 */ +/* DoFTester.cc (C) 2000-2025 */ /* */ /* Comment on file content */ /*---------------------------------------------------------------------------*/ @@ -40,6 +40,7 @@ #include "arcane/mesh/NodeFamily.h" #include "arcane/core/IParallelMng.h" #include "arcane/core/IMeshModifier.h" +#include "arcane/core/MeshKind.h" #include "arcane/core/VariableCollection.h" #include "arcane/core/internal/IPolyhedralMeshModifier.h" @@ -142,6 +143,7 @@ class DoFTester String m_dofs_on_node_family_name; // Several dofs per node String m_dofs_multi_on_face_family_name; // Several dofs per face (non constant size) String m_dofs_multi_on_node_family_name; // Several dofs per node (non constant size) + bool m_do_compact = true; }; @@ -153,6 +155,7 @@ executeTest() { info() << "================ WELCOME TO DOF TESTER ====================="; + if (mesh()->meshKind().meshStructure() == eMeshStructure::Polyhedral) m_do_compact = false; addDoF(5,0); removeDoF(); doFGroups(); @@ -335,6 +338,7 @@ _node2DoFConnectivity() Int64UniqueArray uids; // Create dof on own node only. Ghost handled in the following by GhostDoFManager ENUMERATE_NODE(inode,ownNodes()) { + info() << "Add dof on node " << inode.localId() << "," << inode->uniqueId().asInt64() << " owner " << inode->owner(); uids.add(mesh::DoFUids::uid(inode->uniqueId().asInt64())); } Int32UniqueArray lids(uids.size()); @@ -360,6 +364,8 @@ _node2DoFConnectivity() ENUMERATE_NODE(inode,allNodes()) { const DoF& connected_dof = node2dof(inode); dof_uid = connected_dof.uniqueId().asInt64(); + info() << "Node " << inode.localId() << "," << inode->uniqueId().asInt64() << " owner " << inode->owner(); + info() << "is connected to dof " << connected_dof.localId() << "," << connected_dof.uniqueId() << " owner " << connected_dof.owner(); // Check Ghost policy node and dof have same owner if (connected_dof.owner() != inode->owner()) fatal() << "Error in node to dof connectivity ghost policy"; info() << String::format("dof uid {0} owned by {1} connected to node uid {2} owned by {3} ", @@ -379,13 +385,16 @@ _node2DoFConnectivity() } } // Outside an enumerate, for a one-shot use - NodeInfoListView nodes_view(mesh()->nodeFamily()); - Node my_node(nodes_view[0]); - ConnectivityItemVector dof_vec2 = node2dof._connectedItems(my_node); - ENUMERATE_DOF(idof,dof_vec2){ - dof_uid = idof->uniqueId().asInt64(); - info() << String::format("dof uid {0} owned by {1} connected to node uid {2} owned by {3} ", - dof_uid, idof->owner(), my_node.uniqueId().asInt64(), my_node.owner()); + if (mesh()->nodeFamily()->nbItem() > 0) { + NodeInfoListView nodes_view(mesh()->nodeFamily()); + Node my_node(nodes_view[0]); + ConnectivityItemVector dof_vec2 = node2dof._connectedItems(my_node); + ENUMERATE_DOF(idof,dof_vec2){ + info() << "dof lid " << idof->localId() ; + dof_uid = idof->uniqueId().asInt64(); + info() << String::format("dof uid {0} owned by {1} connected to node uid {2} owned by {3} ", + dof_uid, idof->owner(), my_node.uniqueId().asInt64(), my_node.owner()); + } } // clean @@ -467,13 +476,15 @@ _cell2DoFsConnectivity() } } // For one-shot use - CellInfoListView cells_view(mesh()->cellFamily()); - Cell my_cell(cells_view[0]); - ConnectivityItemVector dof_vec2 = cell2dofs(my_cell); - ENUMERATE_DOF(idof,dof_vec2){ - dof_uid = idof->uniqueId().asInt64(); - info() << String::format("dof uid {0} owned by {1} connected to cell uid {2} owned by {3} ", - dof_uid, idof->owner(), my_cell.uniqueId().asInt64(), my_cell.owner()); + if (mesh()->cellFamily()->nbItem() > 0) { + CellInfoListView cells_view(mesh()->cellFamily()); + Cell my_cell(cells_view[0]); + ConnectivityItemVector dof_vec2 = cell2dofs(my_cell); + ENUMERATE_DOF(idof,dof_vec2){ + dof_uid = idof->uniqueId().asInt64(); + info() << String::format("dof uid {0} owned by {1} connected to cell uid {2} owned by {3} ", + dof_uid, idof->owner(), my_cell.uniqueId().asInt64(), my_cell.owner()); + } } // Test constructor by item_property @@ -549,14 +560,16 @@ _Face2DoFsMultiConnectivity() } } // For one-shot use - FaceInfoListView faces_view(mesh()->faceFamily()); - Face my_face(faces_view[0]); - ConnectivityItemVector dof_vec2 = face2dofs(my_face); - ENUMERATE_DOF(idof,dof_vec2){ - dof_uid = idof->uniqueId().asInt64(); - info() << String::format("dof uid {0} owned by {1} connected to face uid {2} owned by {3} ", - dof_uid, idof->owner(), my_face.uniqueId().asInt64(), my_face.owner()); - } + if (mesh()->faceFamily()->nbItem() > 0) { + FaceInfoListView faces_view(mesh()->faceFamily()); + Face my_face(faces_view[0]); + ConnectivityItemVector dof_vec2 = face2dofs(my_face); + ENUMERATE_DOF(idof,dof_vec2){ + dof_uid = idof->uniqueId().asInt64(); + info() << String::format("dof uid {0} owned by {1} connected to face uid {2} owned by {3} ", + dof_uid, idof->owner(), my_face.uniqueId().asInt64(), my_face.owner()); + } + } // Test constructor by item_property FaceToDoFsMultiConnectivity face2dofs_2(mesh()->faceFamily(),dofs_multi_on_face_family->itemFamily(),face2dofs.itemProperty(),"FaceToDoFsMulti2"); @@ -673,26 +686,31 @@ _node2DoFConnectivityRegistered() _checkConnectivityUpdateAfterRemove(node2dof, removed_node_lids, removed_node_uids); // Compact Source family - debug() << "NODES " << node_family->view().localIds(); - node_family->compactItems(true); - debug() << "NODES " << node_family->view().localIds(); - // update lids - for (Arcane::Integer rank = 0; rank < nb_subdomain; ++rank) { - node_family->itemsUniqueIdToLocalId(remaining_node_lids[rank], remaining_node_uids[rank], true); + if (m_do_compact) { + debug() << "NODES " << node_family->view().localIds(); + node_family->compactItems(true); + debug() << "NODES " << node_family->view().localIds(); + // update lids + for (Arcane::Integer rank = 0; rank < nb_subdomain; ++rank) { + node_family->itemsUniqueIdToLocalId(remaining_node_lids[rank], remaining_node_uids[rank], true); + } } // Compact Target family - debug() << "DOFS " << dof_on_node_family->itemFamily()->view().localIds(); - debug() << "DOF family size " << dof_on_node_family->nbItem(); - dof_on_node_family->itemFamily()->compactItems(true); - debug() << "DOF family size " << dof_on_node_family->nbItem(); - debug() << "DOFS " << dof_on_node_family->itemFamily()->view().localIds(); - - _checkConnectivityUpdateAfterCompact(node2dof, remaining_node_lids, remaining_node_uids, node2dof.itemProperty().size()); + if (m_do_compact) { + debug() << "DOFS " << dof_on_node_family->itemFamily()->view().localIds(); + debug() << "DOF family size " << dof_on_node_family->nbItem(); + dof_on_node_family->itemFamily()->compactItems(true); + debug() << "DOF family size " << dof_on_node_family->nbItem(); + debug() << "DOFS " << dof_on_node_family->itemFamily()->view().localIds(); + + _checkConnectivityUpdateAfterCompact(node2dof, remaining_node_lids, remaining_node_uids, node2dof.itemProperty().size()); + } // Remove a second node // update node lids new_nodes_lids = remaining_node_lids; + info() << "New node lids " << new_nodes_lids[0]; nb_remaining_nodes = new_nodes_lids.dim2Size() - (nb_removed_nodes + 1); remaining_node_lids.resize(nb_subdomain, nb_remaining_nodes); remaining_node_uids.resize(nb_subdomain, nb_remaining_nodes); @@ -709,7 +727,8 @@ _node2DoFConnectivityRegistered() node_family->endUpdate(); // Connectivity and ghosts are updated (since own and ghost dof are removed) node_family->computeSynchronizeInfos(); // Not needed by connectivity but needed to have NodeFamily synchronization info up to date - node_family->compactItems(true); + if (m_do_compact) + node_family->compactItems(true); dofMng().connectivityMng()->unregisterConnectivity(&node2dof); } @@ -852,20 +871,22 @@ _node2DoFsConnectivityRegistered() _checkConnectivityUpdateAfterRemove(node2dofs, removed_nodes_lids, removed_nodes_uids, false); // Compact Source family - node_family->compactItems(true); - debug() << "NODES " << Int32UniqueArray(node_family->view().localIds()); - // update lids - for (Arcane::Integer rank = 0; rank < nb_subdomain; ++rank) { + if (m_do_compact) { + node_family->compactItems(true); + debug() << "NODES " << Int32UniqueArray(node_family->view().localIds()); + // update lids + for (Arcane::Integer rank = 0; rank < nb_subdomain; ++rank) { node_family->itemsUniqueIdToLocalId(remaining_nodes_lids[rank], remaining_nodes_uids[rank], true); - } + } // Compact Target family - debug() << "DOFS " << dofs_on_node_family->itemFamily()->view().localIds(); - debug() << "DOF family size " << dofs_on_node_family->nbItem(); - dofs_on_node_family->itemFamily()->compactItems(true); - debug() << "DOF family size " << dofs_on_node_family->nbItem(); - debug() << "DOFS " << dofs_on_node_family->itemFamily()->view().localIds(); - _checkConnectivityUpdateAfterCompact(node2dofs, remaining_nodes_lids, remaining_nodes_uids, node2dofs.itemProperty().dim1Size(), false); + debug() << "DOFS " << dofs_on_node_family->itemFamily()->view().localIds(); + debug() << "DOF family size " << dofs_on_node_family->nbItem(); + dofs_on_node_family->itemFamily()->compactItems(true); + debug() << "DOF family size " << dofs_on_node_family->nbItem(); + debug() << "DOFS " << dofs_on_node_family->itemFamily()->view().localIds(); + _checkConnectivityUpdateAfterCompact(node2dofs, remaining_nodes_lids, remaining_nodes_uids, node2dofs.itemProperty().dim1Size(), false); + } // Check if compaction works when add&remove _addNodes(new_nodes_lids, new_nodes_uids); @@ -875,7 +896,7 @@ _node2DoFsConnectivityRegistered() node_family->endUpdate(); // Connectivity and ghosts are updated (since own and ghost dof are removed) node_family->computeSynchronizeInfos(); // Not needed by connectivity but needed to have NodeFamily synchronization info up to date - node_family->compactItems(true); + if (m_do_compact) node_family->compactItems(true); dofMng().connectivityMng()->unregisterConnectivity(&node2dofs); } @@ -1035,22 +1056,24 @@ _node2DoFsMultiConnectivityRegistered() _checkConnectivityUpdateAfterRemove(node2dofs, removed_nodes_lids, removed_nodes_uids, false); // Compact Source family - node_family->compactItems(true); - debug() << "NODES " << node_family->view().localIds(); - // update lids - for (Arcane::Integer rank = 0; rank < nb_subdomain; ++rank) + if (m_do_compact) { + node_family->compactItems(true); + debug() << "NODES " << node_family->view().localIds(); + // update lids + for (Arcane::Integer rank = 0; rank < nb_subdomain; ++rank) { node_family->itemsUniqueIdToLocalId(remaining_nodes_lids[rank],remaining_nodes_uids[rank],true); } - // Compact Target family - debug() << "DOFS " << dofs_multi_on_node_family->itemFamily()->view().localIds(); - debug() << "DOF family size " << dofs_multi_on_node_family->nbItem(); - dofs_multi_on_node_family->itemFamily()->compactItems(true); - debug() << "DOF family size " << dofs_multi_on_node_family->nbItem(); - debug() << "DOFS " << dofs_multi_on_node_family->itemFamily()->view().localIds(); + // Compact Target family + debug() << "DOFS " << dofs_multi_on_node_family->itemFamily()->view().localIds(); + debug() << "DOF family size " << dofs_multi_on_node_family->nbItem(); + dofs_multi_on_node_family->itemFamily()->compactItems(true); + debug() << "DOF family size " << dofs_multi_on_node_family->nbItem(); + debug() << "DOFS " << dofs_multi_on_node_family->itemFamily()->view().localIds(); - _checkConnectivityUpdateAfterCompact(node2dofs, remaining_nodes_lids, remaining_nodes_uids, node2dofs.itemProperty().dim1Size(), false); + _checkConnectivityUpdateAfterCompact(node2dofs, remaining_nodes_lids, remaining_nodes_uids, node2dofs.itemProperty().dim1Size(), false); + } // Check if compaction works when add&remove _addNodes(new_nodes_lids, new_nodes_uids); @@ -1060,7 +1083,7 @@ _node2DoFsMultiConnectivityRegistered() node_family->endUpdate(); // Connectivity and ghosts are updated (since own and ghost dof are removed) node_family->computeSynchronizeInfos(); // Not needed by connectivity but needed to have NodeFamily synchronization info up to date - node_family->compactItems(true); + if (m_do_compact) node_family->compactItems(true); dofMng().connectivityMng()->unregisterConnectivity(&node2dofs); } @@ -1183,10 +1206,6 @@ DoFTester:: _checkConnectivityUpdateAfterCompact(IItemConnectivity& node2dof, Int32Array2View remaining_nodes_lids, Int64ConstArray2View remaining_nodes_uids, Integer item_property_size, bool is_scalar_connectivity) { - // Compacting not done for now with polyhedral mesh: an option can deactivate its check - bool do_check_compacting = options()->doCheckCompacting(); - if (do_check_compacting) - info() << "--Do check Compacting"; // Check target family compaction : remaining nodes must be associated to at least one dof ItemInternal internal; // for test Integer nb_subdomain = subDomain()->parallelMng()->commSize(); @@ -1202,7 +1221,7 @@ _checkConnectivityUpdateAfterCompact(IItemConnectivity& node2dof, Int32Array2Vie Int32 connected_dof_lids = concrete_node2dof.itemProperty()[remaining_node]; info() << "== Connectivity value for node (uid) " << remaining_nodes_uids[rank][i] << " (lid= " << remaining_nodes_lids[rank][i] << ")" << " = " << connected_dof_lids << " with nb item = " << dof_family->nbItem(); - if (connected_dof_lids == NULL_ITEM_LOCAL_ID || connected_dof_lids+1 > dof_family->nbItem() && do_check_compacting) + if (connected_dof_lids == NULL_ITEM_LOCAL_ID || connected_dof_lids+1 > dof_family->nbItem()) fatal() << "Error in check connectivity after compact"; } else{ @@ -1211,14 +1230,14 @@ _checkConnectivityUpdateAfterCompact(IItemConnectivity& node2dof, Int32Array2Vie info() << "== Connectivity value for node (uid) " << remaining_nodes_uids[rank][i] << " (lid= " << remaining_nodes_lids[rank][i] << ")" << " = " << dofs_ids << " with nb item = " << dof_family->nbItem(); for (Integer j = 0 ; j < dofs.size(); ++ j) - if (dofs_ids[j] == NULL_ITEM_LOCAL_ID || dofs_ids[j]+1 > dof_family->nbItem() && do_check_compacting) + if (dofs_ids[j] == NULL_ITEM_LOCAL_ID || dofs_ids[j]+1 > dof_family->nbItem()) fatal() << "Error in check connectivity after compact"; } } } _printNodeToDoFConnectivity(node2dof, is_scalar_connectivity,true); // Check source family compaction : itemProperty must have family size - if (item_property_size != node2dof.sourceFamily()->nbItem() && do_check_compacting) fatal() << "Error : connectivity is not correctly impacted by change in source family"; + if (item_property_size != node2dof.sourceFamily()->nbItem()) fatal() << "Error : connectivity is not correctly impacted by change in source family"; } /*---------------------------------------------------------------------------*/ @@ -1242,15 +1261,17 @@ _removeNodes(Int32ConstArray2View new_nodes_lids, for (Integer rank = 0; rank < nb_subdomain; ++rank) { removed_node_lids[rank].copy(new_nodes_lids[rank].subConstView(0,nb_removed_nodes)); + info() << "== Remove nodes " << removed_node_lids[rank] << " on rank " << rank; removed_nodes[rank] = node_family->view(removed_node_lids[rank]); remaining_node_lids[rank].copy(new_nodes_lids[rank].subConstView(nb_removed_nodes,nb_remaining_nodes)); + info() << "== Remaining nodes " << remaining_node_lids[rank] << " on rank " << rank; remaining_nodes[rank] = node_family->view(remaining_node_lids[rank]); Int32 i = 0; mesh::NodeFamily* node_family_internal = dynamic_cast(node_family); if (node_family_internal) { ENUMERATE_NODE (inode, removed_nodes[rank]) { removed_node_uids[rank][i++] = inode->uniqueId().asInt64(); - info() << "== Remove item " << inode->localId() << " on rank " << mesh()->parallelMng()->commRank() << " with owner " << rank; + info() << "== Remove node " << inode->localId() << " on rank " << mesh()->parallelMng()->commRank() << " with owner " << rank; node_family_internal->removeNodeIfNotConnected(*inode); } } @@ -1261,7 +1282,7 @@ _removeNodes(Int32ConstArray2View new_nodes_lids, ENUMERATE_NODE(inode,removed_nodes[rank]) { removed_node_uids[rank][i++] = inode->uniqueId().asInt64(); - info() << "== Remove item " << inode->localId() << " on rank " << mesh()->parallelMng()->commRank() << " with owner " << rank; + info() << "== Remove node " << inode->localId() << " on rank " << mesh()->parallelMng()->commRank() << " with owner " << rank; } polyhedral_modifier->removeItems(removed_node_lids[rank], IK_Node, node_family->name()); } From 6a931933cb53f8a5e1580a610030504e5a20cbda Mon Sep 17 00:00:00 2001 From: sdcm Date: Fri, 10 Oct 2025 19:06:02 +0200 Subject: [PATCH 11/15] [arcane,tests] Add a parallel version of polyhedral mesh tests. --- arcane/src/arcane/tests/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arcane/src/arcane/tests/CMakeLists.txt b/arcane/src/arcane/tests/CMakeLists.txt index a51b996014..645d62009e 100644 --- a/arcane/src/arcane/tests/CMakeLists.txt +++ b/arcane/src/arcane/tests/CMakeLists.txt @@ -729,11 +729,11 @@ endif() if(${VTK_PACKAGE_PREFIX}IOXML_FOUND) ARCANE_ADD_TEST_SEQUENTIAL(vtk_vtu testMesh-format_vtu.arc) if (${VTK_PACKAGE_PREFIX}IOLegacy_FOUND AND Neo_FOUND) - arcane_add_test_sequential(polyhedral_vtk1 testMeshPolyhedral-1.arc) - arcane_add_test_sequential(polyhedral_vtk2 testMeshPolyhedral-2.arc) - arcane_add_test_sequential(polyhedral_vtk3 testMeshPolyhedral-3.arc) - arcane_add_test_sequential(polyhedral_vtk4 testMeshPolyhedral-4.arc) - arcane_add_test_sequential(polyhedral_with_dofs testMeshPolyhedralWithDoFs.arc) + arcane_add_test(polyhedral_vtk1 testMeshPolyhedral-1.arc) + arcane_add_test(polyhedral_vtk2 testMeshPolyhedral-2.arc) + arcane_add_test(polyhedral_vtk3 testMeshPolyhedral-3.arc) + arcane_add_test(polyhedral_vtk4 testMeshPolyhedral-4.arc) + arcane_add_test(polyhedral_with_dofs testMeshPolyhedralWithDoFs.arc) arcane_add_test_parallel(polyhedral_exchange_item1 testExchangeItem-polyhedral-1.arc 3) arcane_add_test_parallel(polyhedral_exchange_item2 testExchangeItem-polyhedral-2.arc 3) endif() From 867620cf84d275c936f82449728db43d3c358fc2 Mon Sep 17 00:00:00 2001 From: sdcm Date: Mon, 13 Oct 2025 19:38:21 +0200 Subject: [PATCH 12/15] [arcane,core] Include new internal interface IItemFamilySerializerMngInternal into InterfaceImpl.cc for Windows exports. --- arcane/src/arcane/core/InterfaceImpl.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/arcane/src/arcane/core/InterfaceImpl.cc b/arcane/src/arcane/core/InterfaceImpl.cc index 2090e247f0..94602f8691 100644 --- a/arcane/src/arcane/core/InterfaceImpl.cc +++ b/arcane/src/arcane/core/InterfaceImpl.cc @@ -147,6 +147,7 @@ #include "arcane/core/internal/IVariableSynchronizerMngInternal.h" #include "arcane/core/internal/IIncrementalItemConnectivityInternal.h" #include "arcane/core/internal/IPolyhedralMeshModifier.h" +#include "arcane/core/internal/IItemFamilySerializerMngInternal.h" /*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/ From 3b1d9754eed8bca7c27cfe1aa2e528593e9ac4a4 Mon Sep 17 00:00:00 2001 From: sdcm Date: Mon, 13 Oct 2025 19:43:32 +0200 Subject: [PATCH 13/15] [arcane,core] Add new internal interface IItemFamilySerializerMngInternal into arcane_core internal source list. --- arcane/src/arcane/core/srcs.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/arcane/src/arcane/core/srcs.cmake b/arcane/src/arcane/core/srcs.cmake index 2d924d8664..8a8776c3e3 100644 --- a/arcane/src/arcane/core/srcs.cmake +++ b/arcane/src/arcane/core/srcs.cmake @@ -88,6 +88,7 @@ set(ARCANE_INTERNAL_SOURCES internal/VtkCellTypes.h internal/ParallelMngInternal.h internal/ParallelMngInternal.cc + internal/IItemFamilySerializerMngInternal.h ) set(ARCANE_ORIGINAL_SOURCES From 367034b0d4130b0cf55e9f0d920c34f5e688110f Mon Sep 17 00:00:00 2001 From: sdcm Date: Mon, 13 Oct 2025 19:44:24 +0200 Subject: [PATCH 14/15] [arcane,mesh] Add a missing explicit. --- arcane/src/arcane/mesh/PolyhedralMesh.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcane/src/arcane/mesh/PolyhedralMesh.cc b/arcane/src/arcane/mesh/PolyhedralMesh.cc index a176a3f424..b7cd945b0d 100644 --- a/arcane/src/arcane/mesh/PolyhedralMesh.cc +++ b/arcane/src/arcane/mesh/PolyhedralMesh.cc @@ -149,7 +149,7 @@ namespace mesh public: - PolyhedralFamilySerializerMng(PolyhedralMesh* mesh) + explicit PolyhedralFamilySerializerMng(PolyhedralMesh* mesh) : m_mesh(mesh) { ARCANE_CHECK_POINTER2(mesh, "Must give a non null PolyhedralMesh pointer."); From c54084ee47d2c5c76982fb84d6c6623e48cbf1de Mon Sep 17 00:00:00 2001 From: sdcm Date: Tue, 14 Oct 2025 09:21:51 +0200 Subject: [PATCH 15/15] [arcane,mesh] Fix a check that should have been an assertion. --- arcane/src/arcane/mesh/PolyhedralMesh.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcane/src/arcane/mesh/PolyhedralMesh.cc b/arcane/src/arcane/mesh/PolyhedralMesh.cc index b7cd945b0d..4066bc8020 100644 --- a/arcane/src/arcane/mesh/PolyhedralMesh.cc +++ b/arcane/src/arcane/mesh/PolyhedralMesh.cc @@ -1409,7 +1409,7 @@ _allocateItems(const Arcane::ItemAllocationInfo& item_allocation_info, ArrayView if (!family_lids.empty()) { auto index = 0; - ARCANE_CHECK(family_lids.size() == item_local_ids.size()); + ARCANE_ASSERT((family_lids.size() == item_local_ids.size()),("Incoherence in item number")); for (auto& lid_array : item_local_ids) { family_lids[index].resize(lid_array.size()); lid_array.fillArrayView(family_lids[index].view(), mesh_state);