From dd02fc85b9c4ad3438c1adef5377513d916c78d0 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Dec 2024 07:04:39 +0100 Subject: [PATCH 01/33] add additional insert and typecheck to PVS --- kratos/containers/pointer_vector_set.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/kratos/containers/pointer_vector_set.h b/kratos/containers/pointer_vector_set.h index 7eccc0b0fc78..119b128b1f2f 100644 --- a/kratos/containers/pointer_vector_set.h +++ b/kratos/containers/pointer_vector_set.h @@ -667,6 +667,20 @@ class PointerVectorSet final SortedInsert(first, last); } + /** + * @brief Insert elements from another PointerVectorSet range. + * @details This function inserts element pointers from another PointerVectorSet range specified by first and last into the current set. + * Since, PointerVectorSet is assumed to be sorted and unique, the incoming PointerVectorSet is not + * sorted and made unique again. This will not insert any elements in the incoming set, if there exists an element with a key + * which is equal to an element's key in the input range. + * @param first Other PointerVectorSet starting iterator + * @param last Other PointerVectorSet ending iterator + */ + void insert(PointerVectorSet::iterator first, PointerVectorSet::iterator last) + { + SortedInsert(first, last); + } + void insert(const PointerVectorSet& rOther) { insert(rOther.begin(), rOther.end()); @@ -1199,7 +1213,10 @@ class PointerVectorSet final // which is harder to guess, and cryptic. Hence, using the decltype. using iterator_value_type = std::decay_t; - if constexpr(std::is_same_v>) { + if constexpr(std::is_same_v || std::is_same_v) { + // if the TIteratorType is of boost::indirect_iterator type, then we can get the pointer by dereferencing. + return *(Iterator.base()); + } else if constexpr(std::is_same_v>) { // this supports any type of pointers return *Iterator; } else if constexpr(std::is_same_v> && std::is_same_v>>) { From 2bf1e96b59c880b231cb0e99f1d81a48f54dc7b5 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Dec 2024 07:04:54 +0100 Subject: [PATCH 02/33] remove push_backs from ModelPart --- kratos/includes/model_part.h | 288 +++++++++++------------------ kratos/sources/model_part.cpp | 329 +++++++++++----------------------- 2 files changed, 203 insertions(+), 414 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index b1b38b85efb2..890d15182c11 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -39,6 +39,7 @@ #include "includes/master_slave_constraint.h" #include "containers/variable.h" #include "containers/variable_data.h" +#include "utilities/parallel_utilities.h" namespace Kratos { @@ -95,6 +96,13 @@ class KRATOS_API(KRATOS_CORE) ModelPart final Kratos_Ownership_Size }; + ///@} + ///@name Class definitions + ///@{ + + template + struct Container {}; + ///@} ///@name Type Definitions ///@{ @@ -356,47 +364,8 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddNodes(TIteratorType nodes_begin, TIteratorType nodes_end, IndexType ThisIndex = 0) { - KRATOS_TRY - ModelPart::NodesContainerType aux; - ModelPart::NodesContainerType aux_root; //they may not exist in the root - ModelPart* root_model_part = &this->GetRootModelPart(); - - for(TIteratorType it = nodes_begin; it!=nodes_end; it++) - { - auto it_found = root_model_part->Nodes().find(it->Id()); - if(it_found == root_model_part->NodesEnd()) //node does not exist in the top model part - { - aux_root.push_back( *(it.base()) ); //node does not exist - aux.push_back( *(it.base()) ); - } - else //if it does exist verify it is the same node - { - if(&(*it_found) != &(*it))//check if the pointee coincides - KRATOS_ERROR << "attempting to add a new node with Id :" << it_found->Id() << ", unfortunately a (different) node with the same Id already exists" << std::endl; - else - aux.push_back( *(it.base()) ); - } - } - - //now add to the root model part - for(auto it = aux_root.begin(); it!=aux_root.end(); it++) - root_model_part->Nodes().push_back( *(it.base()) ); - root_model_part->Nodes().Unique(); - - //add to all of the leaves - - ModelPart* current_part = this; - while(current_part->IsSubModelPart()) - { - for(auto it = aux.begin(); it!=aux.end(); it++) - current_part->Nodes().push_back( *(it.base()) ); - - current_part->Nodes().Unique(); - - current_part = &(current_part->GetParentModelPart()); - } - - KRATOS_CATCH("") + EntityInserter inserter{this}; + inserter.operator()(nodes_begin, nodes_end); } /** Inserts a node in the current mesh. @@ -694,46 +663,8 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddMasterSlaveConstraints(TIteratorType constraints_begin, TIteratorType constraints_end, IndexType ThisIndex = 0) { - KRATOS_TRY - ModelPart::MasterSlaveConstraintContainerType aux; - ModelPart::MasterSlaveConstraintContainerType aux_root; - ModelPart* root_model_part = &this->GetRootModelPart(); - - for(TIteratorType it = constraints_begin; it!=constraints_end; it++) - { - auto it_found = root_model_part->MasterSlaveConstraints().find(it->Id()); - if(it_found == root_model_part->MasterSlaveConstraintsEnd()) //node does not exist in the top model part - { - aux_root.push_back( *(it.base()) ); - aux.push_back( *(it.base()) ); - } - else //if it does exist verify it is the same node - { - if(&(*it_found) != &(*it))//check if the pointee coincides - KRATOS_ERROR << "attempting to add a new master-slave constraint with Id :" << it_found->Id() << ", unfortunately a (different) master-slave constraint with the same Id already exists" << std::endl; - else - aux.push_back( *(it.base()) ); - } - } - - for(auto it = aux_root.begin(); it!=aux_root.end(); it++) - root_model_part->MasterSlaveConstraints().push_back( *(it.base()) ); - root_model_part->MasterSlaveConstraints().Unique(); - - //add to all of the leaves - - ModelPart* current_part = this; - while(current_part->IsSubModelPart()) - { - for(auto it = aux.begin(); it!=aux.end(); it++) - current_part->MasterSlaveConstraints().push_back( *(it.base()) ); - - current_part->MasterSlaveConstraints().Unique(); - - current_part = &(current_part->GetParentModelPart()); - } - - KRATOS_CATCH("") + EntityInserter inserter{this}; + inserter.operator()(constraints_begin, constraints_end); } /** @@ -1042,46 +973,8 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddElements(TIteratorType elements_begin, TIteratorType elements_end, IndexType ThisIndex = 0) { - KRATOS_TRY - ModelPart::ElementsContainerType aux; - ModelPart::ElementsContainerType aux_root; - ModelPart* root_model_part = &this->GetRootModelPart(); - - for(TIteratorType it = elements_begin; it!=elements_end; it++) - { - auto it_found = root_model_part->Elements().find(it->Id()); - if(it_found == root_model_part->ElementsEnd()) //node does not exist in the top model part - { - aux_root.push_back( *(it.base()) ); - aux.push_back( *(it.base()) ); - } - else //if it does exist verify it is the same node - { - if(&(*it_found) != &(*it))//check if the pointee coincides - KRATOS_ERROR << "attempting to add a new element with Id :" << it_found->Id() << ", unfortunately a (different) element with the same Id already exists" << std::endl; - else - aux.push_back( *(it.base()) ); - } - } - - for(auto it = aux_root.begin(); it!=aux_root.end(); it++) - root_model_part->Elements().push_back( *(it.base()) ); - root_model_part->Elements().Unique(); - - //add to all of the leaves - - ModelPart* current_part = this; - while(current_part->IsSubModelPart()) - { - for(auto it = aux.begin(); it!=aux.end(); it++) - current_part->Elements().push_back( *(it.base()) ); - - current_part->Elements().Unique(); - - current_part = &(current_part->GetParentModelPart()); - } - - KRATOS_CATCH("") + EntityInserter inserter{this}; + inserter.operator()(elements_begin, elements_end); } /// Creates new element with a node ids list. @@ -1228,52 +1121,13 @@ class KRATOS_API(KRATOS_CORE) ModelPart final */ void AddConditions(std::vector const& ConditionIds, IndexType ThisIndex = 0); - /** Inserts a list of pointers to nodes + /** Inserts a list of pointers to conditions */ template void AddConditions(TIteratorType conditions_begin, TIteratorType conditions_end, IndexType ThisIndex = 0) { - KRATOS_TRY - ModelPart::ConditionsContainerType aux; - ModelPart::ConditionsContainerType aux_root; - ModelPart* root_model_part = &this->GetRootModelPart(); - - for(TIteratorType it = conditions_begin; it!=conditions_end; it++) - { - auto it_found = root_model_part->Conditions().find(it->Id()); - if(it_found == root_model_part->ConditionsEnd()) //node does not exist in the top model part - { - aux.push_back( *(it.base()) ); - aux_root.push_back( *(it.base()) ); - } - else //if it does exist verify it is the same node - { - if(&(*it_found) != &(*it))//check if the pointee coincides - KRATOS_ERROR << "attempting to add a new Condition with Id :" << it_found->Id() << ", unfortunately a (different) Condition with the same Id already exists" << std::endl; - else - aux.push_back( *(it.base()) ); - } - } - - //now add to the root model part - for(auto it = aux_root.begin(); it!=aux_root.end(); it++) - root_model_part->Conditions().push_back( *(it.base()) ); - root_model_part->Conditions().Unique(); - - //add to all of the leaves - - ModelPart* current_part = this; - while(current_part->IsSubModelPart()) - { - for(auto it = aux.begin(); it!=aux.end(); it++) - current_part->Conditions().push_back( *(it.base()) ); - - current_part->Conditions().Unique(); - - current_part = &(current_part->GetParentModelPart()); - } - - KRATOS_CATCH("") + EntityInserter inserter{this}; + inserter.operator()(conditions_begin, conditions_end); } /// Creates new condition with a node ids list. @@ -1525,40 +1379,31 @@ class KRATOS_API(KRATOS_CORE) ModelPart final void AddGeometries(TIteratorType GeometryBegin, TIteratorType GeometriesEnd, IndexType ThisIndex = 0) { KRATOS_TRY - std::vector aux, aux_root; + ModelPart* p_root_model_part = &this->GetRootModelPart(); - for(TIteratorType it = GeometryBegin; it!=GeometriesEnd; it++) { - auto it_found = p_root_model_part->Geometries().find(it->Id()); - if(it_found == p_root_model_part->GeometriesEnd()) { // Geometry does not exist in the top model part - aux_root.push_back(*(it.base())); - aux.push_back(*(it.base())); - } else { // If it does exist verify it is the same geometry - if (GeometryType::HasSameGeometryType(*it, *it_found)) { // Check the geometry type and connectivities - for (IndexType i_pt = 0; i_pt < it->PointsNumber(); ++i_pt) { - KRATOS_ERROR_IF((*it)[i_pt].Id() != (*it_found)[i_pt].Id()) << "Attempting to add a new geometry with Id: " << it->Id() << ". A same type geometry with same Id but different connectivities already exists." << std::endl; + block_for_each(GeometryBegin, GeometriesEnd, [p_root_model_part](const auto& prGeometry) { + const auto& r_geometry = ReferenceGetter::Execute(prGeometry); + const auto& r_geometries = p_root_model_part->Geometries(); + auto it_found = r_geometries.find(r_geometry.Id()); + if (it_found != p_root_model_part->GeometriesEnd()) { + if (GeometryType::HasSameGeometryType(r_geometry, *it_found)) { // Check the geometry type and connectivities + for (IndexType i_pt = 0; i_pt < r_geometry.PointsNumber(); ++i_pt) { + KRATOS_ERROR_IF((r_geometry)[i_pt].Id() != (*it_found)[i_pt].Id()) << "Attempting to add a new geometry with Id: " << r_geometry.Id() << ". A same type geometry with same Id but different connectivities already exists." << std::endl; } - aux.push_back(*(it_found.base())); // If the Id, type and connectivities are the same add the existing geometry - } else if(&(*it_found) != &(*it)) { // Check if the pointee coincides + } else if(&(*it_found) != &r_geometry) { // Check if the pointee coincides KRATOS_ERROR << "Attempting to add a new geometry with Id: " << it_found->Id() << ". A different geometry with the same Id already exists." << std::endl; - } else { - aux.push_back(*(it.base())); } } - } + }); // Add to root model part - for(auto& p_geom : aux_root) { - p_root_model_part->AddGeometry(p_geom); - } + p_root_model_part->Geometries().insert(GeometryBegin, GeometriesEnd); // Add to all of the leaves ModelPart* p_current_part = this; while(p_current_part->IsSubModelPart()) { - for(auto& p_geom : aux) { - p_current_part->AddGeometry(p_geom); - } - + p_current_part->Geometries().insert(GeometryBegin, GeometriesEnd); p_current_part = &(p_current_part->GetParentModelPart()); } @@ -1988,6 +1833,60 @@ class KRATOS_API(KRATOS_CORE) ModelPart final ///@name Private Operations ///@{ + template + struct ReferenceGetter + { + template + inline static const TReturnValueType& Execute(const TInputValueType& rInputValue) { + if constexpr(std::is_same_v>) { + return rInputValue; + } else if constexpr(std::is_same_v>>) { + return *rInputValue; + } else if constexpr(std::is_same_v>>) { + return **rInputValue; + } else { + static_assert(!std::is_same_v, "Unsupported value type."); + return TReturnValueType{}; + } + } + }; + + template + struct EntityInserter + { + ModelPart* mpModelPart; + + template + void operator()(TIterator begin, TIterator end) { + KRATOS_TRY + + ModelPart* p_root_model_part = &mpModelPart->GetRootModelPart(); + + block_for_each(begin, end, [p_root_model_part](const auto& prEntity) { + const auto& r_entity = ReferenceGetter::Execute(prEntity); + const auto& r_entities = Container::GetContainer(p_root_model_part->GetMesh()); // TODO: This is only required to only trigger a find, not a sort. Once the find is fixed, then we can simplify this. + auto it_found = r_entities.find(r_entity.Id()); + KRATOS_ERROR_IF_NOT(&r_entity == &*it_found) + << "attempting to add a new " << Container::GetEntityName() << " with Id :" + << r_entity.Id() << ", unfortunately a (different) " << Container::GetEntityName() + << " with the same Id already exists" + << std::endl; + }); + + //now add to the root model part + Container::GetContainer(p_root_model_part->GetMesh()).insert(begin, end); + + //add to all of the parents + ModelPart* p_current_part = mpModelPart; + while(p_current_part->IsSubModelPart()) { + Container::GetContainer(p_current_part->GetMesh()).insert(begin, end); + p_current_part = &(p_current_part->GetParentModelPart()); + } + + KRATOS_CATCH("") + } + }; + /** * @brief This method trims a string in the different components to access recursively to any subproperty * @param rStringName The given name to be trimmed @@ -2068,6 +1967,25 @@ class KRATOS_API(KRATOS_CORE) ModelPart final ///@name Type Definitions ///@{ +template <> struct ModelPart::Container { + static std::string GetEntityName() { return "node"; } + static NodesContainerType& GetContainer(ModelPart::MeshType& rMesh) { return rMesh.Nodes(); } +}; + +template <> struct ModelPart::Container { + static std::string GetEntityName() { return "condition"; } + static ConditionsContainerType& GetContainer(ModelPart::MeshType& rMesh) { return rMesh.Conditions(); } +}; + +template <> struct ModelPart::Container { + static std::string GetEntityName() { return "element"; } + static ElementsContainerType& GetContainer(ModelPart::MeshType& rMesh) { return rMesh.Elements(); } +}; + +template <> struct ModelPart::Container { + static std::string GetEntityName() { return "master-slave-constraint"; } + static MasterSlaveConstraintContainerType& GetContainer(ModelPart::MeshType& rMesh) { return rMesh.MasterSlaveConstraints(); } +}; ///@} ///@name Input and output diff --git a/kratos/sources/model_part.cpp b/kratos/sources/model_part.cpp index db3f4db5e0bc..215c3f769c35 100644 --- a/kratos/sources/model_part.cpp +++ b/kratos/sources/model_part.cpp @@ -28,6 +28,78 @@ namespace Kratos KRATOS_CREATE_LOCAL_FLAG(ModelPart, ALL_ENTITIES, 0); KRATOS_CREATE_LOCAL_FLAG(ModelPart, OVERWRITE_ENTITIES, 1); +namespace ModelPartHelperUtilities +{ + +template +void AddEntitiesFromIds( + ModelPart* pModelPart, + const std::vector& rEntityIds) +{ + KRATOS_TRY + + if(pModelPart->IsSubModelPart()) { //does nothing if we are on the top model part + //obtain from the root model part the corresponding list of nodes + ModelPart* root_model_part = &pModelPart->GetRootModelPart(); + + std::vector aux; + aux.reserve(rEntityIds.size()); + + const auto& r_container = ModelPart::Container::GetContainer(root_model_part->GetMesh()); + + for(const auto entity_id : rEntityIds) { + auto it = r_container.find(entity_id); + if(it != r_container.end()) { + aux.push_back(*(it.base())); + } else { + KRATOS_ERROR << "while adding " << ModelPart::Container::GetEntityName() << "s to submodelpart " + << pModelPart->FullName() << ", the " + << ModelPart::Container::GetEntityName() + << " with Id " << entity_id << " does not exist in the root model part"; + } + } + + ModelPart* current_part = pModelPart; + while(current_part->IsSubModelPart()) { + ModelPart::Container::GetContainer(current_part->GetMesh()).insert(aux.begin(), aux.end()); + current_part = &(current_part->GetParentModelPart()); + } + } + + KRATOS_CATCH(""); +} + +template +void RemoveEntities( + ModelPart::MeshType& rMesh, + const Flags& rIdentifierFlag) +{ + KRATOS_TRY + + auto& r_container = ModelPart::Container::GetContainer(rMesh); + + //count the nodes to be erase + const auto erase_count = block_for_each>(r_container, [&rIdentifierFlag](const auto& rEntity) -> unsigned int { + return rEntity.Is(rIdentifierFlag); + }); + + TContainerType temp_entities; + temp_entities.reserve(r_container.size() - erase_count); + temp_entities.swap(r_container); + + for(auto i_entity = temp_entities.begin() ; i_entity != temp_entities.end() ; ++i_entity) { + if (i_entity->IsNot(rIdentifierFlag)) { + // we can safely insert them at the end with the correct hint here since, the original r_mesh + // is sorted and unique. + r_container.insert(r_container.end(), std::move(*(i_entity.base()))); + } + } + + KRATOS_CATCH(""); +} + +} // namespace ModelPartHelperUtilities + /// Default constructor. ModelPart::ModelPart(VariablesList::Pointer pVariablesList, Model& rOwnerModel) : ModelPart("Default", pVariablesList, rOwnerModel) { } @@ -232,37 +304,9 @@ void ModelPart::AddNode(ModelPart::NodeType::Pointer pNewNode, ModelPart::IndexT /** Inserts a list of nodes in a submodelpart provided their Id. Does nothing if applied to the top model part */ -void ModelPart::AddNodes(std::vector const& NodeIds, IndexType ThisIndex) +void ModelPart::AddNodes(std::vector const& rNodeIds, IndexType ThisIndex) { - KRATOS_TRY - if(IsSubModelPart()) //does nothing if we are on the top model part - { - //obtain from the root model part the corresponding list of nodes - ModelPart* root_model_part = &this->GetRootModelPart(); - ModelPart::NodesContainerType aux; - aux.reserve(NodeIds.size()); - for(unsigned int i=0; iNodes().find(NodeIds[i]); - if(it!=root_model_part->NodesEnd()) - aux.push_back(*(it.base())); - else - KRATOS_ERROR << "while adding nodes to submodelpart, the node with Id " << NodeIds[i] << " does not exist in the root model part"; - } - - ModelPart* current_part = this; - while(current_part->IsSubModelPart()) - { - for(auto it = aux.begin(); it!=aux.end(); it++) - current_part->Nodes().push_back( *(it.base()) ); - - current_part->Nodes().Unique(); - - current_part = &(current_part->GetParentModelPart()); - } - } - - KRATOS_CATCH(""); + ModelPartHelperUtilities::AddEntitiesFromIds(this, rNodeIds); } /** Inserts a node in the mesh with ThisIndex. @@ -444,34 +488,10 @@ void ModelPart::RemoveNodeFromAllLevels(ModelPart::NodeType::Pointer pThisNode, void ModelPart::RemoveNodes(Flags IdentifierFlag) { - // Lambda to remove nodes from a mesh - auto remove_nodes_from_mesh = [&](ModelPart::MeshType& r_mesh) { - //count the nodes to be erase - const unsigned int nnodes = r_mesh.Nodes().size(); - unsigned int erase_count = 0; - #pragma omp parallel for reduction(+:erase_count) - for(int i=0; i(nnodes); ++i) { - ModelPart::NodesContainerType::iterator i_node = r_mesh.NodesBegin() + i; - - if( i_node->IsNot(IdentifierFlag) ) - erase_count++; - } - - ModelPart::NodesContainerType temp_nodes_container; - temp_nodes_container.reserve(r_mesh.Nodes().size() - erase_count); - - temp_nodes_container.swap(r_mesh.Nodes()); - - for(ModelPart::NodesContainerType::iterator i_node = temp_nodes_container.begin() ; i_node != temp_nodes_container.end() ; ++i_node) { - if( i_node->IsNot(IdentifierFlag) ) - (r_mesh.Nodes()).push_back(std::move(*(i_node.base()))); - } - }; - // This method is optimized to free the memory // Loop over all the local meshes (Is this still necessary with Submodelparts?) for(auto& r_mesh: this->GetMeshes()) { - remove_nodes_from_mesh(r_mesh); + ModelPartHelperUtilities::RemoveEntities(r_mesh, IdentifierFlag); } if (IsDistributed()) { @@ -479,19 +499,19 @@ void ModelPart::RemoveNodes(Flags IdentifierFlag) this->GetCommunicator().SynchronizeOrNodalFlags(IdentifierFlag); // Remove the nodes from the mpi-interfaces in case there is any - remove_nodes_from_mesh(this->GetCommunicator().LocalMesh()); + ModelPartHelperUtilities::RemoveEntities(this->GetCommunicator().LocalMesh(), IdentifierFlag); for(auto& r_mesh: this->GetCommunicator().LocalMeshes()) { - remove_nodes_from_mesh(r_mesh); + ModelPartHelperUtilities::RemoveEntities(r_mesh, IdentifierFlag); } - remove_nodes_from_mesh(this->GetCommunicator().GhostMesh()); + ModelPartHelperUtilities::RemoveEntities(this->GetCommunicator().GhostMesh(), IdentifierFlag); for(auto& r_mesh: this->GetCommunicator().GhostMeshes()) { - remove_nodes_from_mesh(r_mesh); + ModelPartHelperUtilities::RemoveEntities(r_mesh, IdentifierFlag); } - remove_nodes_from_mesh(this->GetCommunicator().InterfaceMesh()); + ModelPartHelperUtilities::RemoveEntities(this->GetCommunicator().InterfaceMesh(), IdentifierFlag); for(auto& r_mesh: this->GetCommunicator().InterfaceMeshes()) { - remove_nodes_from_mesh(r_mesh); + ModelPartHelperUtilities::RemoveEntities(r_mesh, IdentifierFlag); } } @@ -940,34 +960,7 @@ void ModelPart::AddElement(ModelPart::ElementType::Pointer pNewElement, ModelPar */ void ModelPart::AddElements(std::vector const& ElementIds, IndexType ThisIndex) { - KRATOS_TRY - if(IsSubModelPart()) //does nothing if we are on the top model part - { - //obtain from the root model part the corresponding list of nodes - ModelPart* root_model_part = &this->GetRootModelPart(); - ModelPart::ElementsContainerType aux; - aux.reserve(ElementIds.size()); - for(unsigned int i=0; iElements().find(ElementIds[i]); - if(it!=root_model_part->ElementsEnd()) - aux.push_back(*(it.base())); - else - KRATOS_ERROR << "the element with Id " << ElementIds[i] << " does not exist in the root model part"; - } - - ModelPart* current_part = this; - while(current_part->IsSubModelPart()) - { - for(auto it = aux.begin(); it!=aux.end(); it++) - current_part->Elements().push_back( *(it.base()) ); - - current_part->Elements().Unique(); - - current_part = &(current_part->GetParentModelPart()); - } - } - KRATOS_CATCH(""); + ModelPartHelperUtilities::AddEntitiesFromIds(this, ElementIds); } /** Inserts an element in the mesh with ThisIndex. @@ -1128,36 +1121,14 @@ void ModelPart::RemoveElements(Flags IdentifierFlag) { // This method is optimized to free the memory //loop over all the meshes - auto& meshes = this->GetMeshes(); - for(ModelPart::MeshesContainerType::iterator i_mesh = meshes.begin() ; i_mesh != meshes.end() ; i_mesh++) - { - //count the elements to be erase - const unsigned int nelements = i_mesh->Elements().size(); - unsigned int erase_count = 0; - #pragma omp parallel for reduction(+:erase_count) - for(int i=0; i(nelements); ++i) - { - auto i_elem = i_mesh->ElementsBegin() + i; - - if( i_elem->IsNot(IdentifierFlag) ) - erase_count++; - } - - ModelPart::ElementsContainerType temp_elements_container; - temp_elements_container.reserve(i_mesh->Elements().size() - erase_count); - - temp_elements_container.swap(i_mesh->Elements()); - - for(ModelPart::ElementsContainerType::iterator i_elem = temp_elements_container.begin() ; i_elem != temp_elements_container.end() ; i_elem++) - { - if( i_elem->IsNot(IdentifierFlag) ) - (i_mesh->Elements()).push_back(std::move(*(i_elem.base()))); - } + for(auto& r_mesh : this->GetMeshes()) { + ModelPartHelperUtilities::RemoveEntities(r_mesh, IdentifierFlag); } //now recursively remove the elements in the submodelparts - for (SubModelPartIterator i_sub_model_part = SubModelPartsBegin(); i_sub_model_part != SubModelPartsEnd(); i_sub_model_part++) - i_sub_model_part->RemoveElements(IdentifierFlag); + for (auto& r_sub_model_part : this->SubModelParts()) { + r_sub_model_part.RemoveElements(IdentifierFlag); + } } void ModelPart::RemoveElementsFromAllLevels(Flags IdentifierFlag) @@ -1199,34 +1170,7 @@ void ModelPart::AddMasterSlaveConstraint(ModelPart::MasterSlaveConstraintType::P */ void ModelPart::AddMasterSlaveConstraints(std::vector const& MasterSlaveConstraintIds, IndexType ThisIndex) { - KRATOS_TRY - if(IsSubModelPart()) //does nothing if we are on the top model part - { - //obtain from the root model part the corresponding list of constraints - ModelPart* root_model_part = &this->GetRootModelPart(); - ModelPart::MasterSlaveConstraintContainerType aux; - aux.reserve(MasterSlaveConstraintIds.size()); - for(unsigned int i=0; iMasterSlaveConstraints().find(MasterSlaveConstraintIds[i]); - if(it!=root_model_part->MasterSlaveConstraintsEnd()) - aux.push_back(*(it.base())); - else - KRATOS_ERROR << "the master-slave constraint with Id " << MasterSlaveConstraintIds[i] << " does not exist in the root model part"; - } - - ModelPart* current_part = this; - while(current_part->IsSubModelPart()) - { - for(auto it = aux.begin(); it!=aux.end(); it++) - current_part->MasterSlaveConstraints().push_back( *(it.base()) ); - - current_part->MasterSlaveConstraints().Unique(); - - current_part = &(current_part->GetParentModelPart()); - } - } - KRATOS_CATCH(""); + ModelPartHelperUtilities::AddEntitiesFromIds(this, MasterSlaveConstraintIds); } /// @brief Construct a new @ref MasterSlaveConstraint and insert it into the specified @ref Mesh. @@ -1394,33 +1338,14 @@ void ModelPart::RemoveMasterSlaveConstraintFromAllLevels(ModelPart::MasterSlaveC void ModelPart::RemoveMasterSlaveConstraints(Flags IdentifierFlag) { // This method is optimized to free the memory loop over all the meshes - auto& meshes = this->GetMeshes(); - for(auto it_mesh = meshes.begin() ; it_mesh != meshes.end() ; it_mesh++) { - // Count the constraints to be erase - const SizeType nconstraints = it_mesh->MasterSlaveConstraints().size(); - SizeType erase_count = 0; - #pragma omp parallel for reduction(+:erase_count) - for(int i=0; i(nconstraints); ++i) { - auto it_const = it_mesh->MasterSlaveConstraintsBegin() + i; - - if( it_const->IsNot(IdentifierFlag) ) - erase_count++; - } - - ModelPart::MasterSlaveConstraintContainerType temp_constraints_container; - temp_constraints_container.reserve(it_mesh->MasterSlaveConstraints().size() - erase_count); - - temp_constraints_container.swap(it_mesh->MasterSlaveConstraints()); - - for(auto it_const = temp_constraints_container.begin() ; it_const != temp_constraints_container.end(); it_const++) { - if( it_const->IsNot(IdentifierFlag) ) - (it_mesh->MasterSlaveConstraints()).push_back(std::move(*(it_const.base()))); - } + for(auto& r_mesh : this->GetMeshes()) { + ModelPartHelperUtilities::RemoveEntities(r_mesh, IdentifierFlag); } // Now recursively remove the constraints in the submodelparts - for (SubModelPartIterator i_sub_model_part = SubModelPartsBegin(); i_sub_model_part != SubModelPartsEnd(); i_sub_model_part++) - i_sub_model_part->RemoveMasterSlaveConstraints(IdentifierFlag); + for (auto& r_sub_model_part : this->SubModelParts()) { + r_sub_model_part.RemoveMasterSlaveConstraints(IdentifierFlag); + } } /***********************************************************************************/ @@ -1477,34 +1402,7 @@ void ModelPart::AddCondition(ModelPart::ConditionType::Pointer pNewCondition, Mo */ void ModelPart::AddConditions(std::vector const& ConditionIds, IndexType ThisIndex) { - KRATOS_TRY - if(IsSubModelPart()) //does nothing if we are on the top model part - { - //obtain from the root model part the corresponding list of nodes - ModelPart* root_model_part = &this->GetRootModelPart(); - ModelPart::ConditionsContainerType aux; - aux.reserve(ConditionIds.size()); - for(unsigned int i=0; iConditions().find(ConditionIds[i]); - if(it!=root_model_part->ConditionsEnd()) - aux.push_back(*(it.base())); - else - KRATOS_ERROR << "the condition with Id " << ConditionIds[i] << " does not exist in the root model part"; - } - - ModelPart* current_part = this; - while(current_part->IsSubModelPart()) - { - for(auto it = aux.begin(); it!=aux.end(); it++) - current_part->Conditions().push_back( *(it.base()) ); - - current_part->Conditions().Unique(); - - current_part = &(current_part->GetParentModelPart()); - } - } - KRATOS_CATCH(""); + ModelPartHelperUtilities::AddEntitiesFromIds(this, ConditionIds); } /** Inserts a condition in the mesh with ThisIndex. @@ -1663,36 +1561,14 @@ void ModelPart::RemoveConditions(Flags IdentifierFlag) { // This method is optimized to free the memory //loop over all the meshes - auto& meshes = this->GetMeshes(); - for(ModelPart::MeshesContainerType::iterator i_mesh = meshes.begin() ; i_mesh != meshes.end() ; i_mesh++) - { - //count the conditions to be erase - const unsigned int nconditions = i_mesh->Conditions().size(); - unsigned int erase_count = 0; - #pragma omp parallel for reduction(+:erase_count) - for(int i=0; i(nconditions); ++i) - { - auto i_cond = i_mesh->ConditionsBegin() + i; - - if( i_cond->IsNot(IdentifierFlag) ) - erase_count++; - } - - ModelPart::ConditionsContainerType temp_conditions_container; - temp_conditions_container.reserve(i_mesh->Conditions().size() - erase_count); - - temp_conditions_container.swap(i_mesh->Conditions()); - - for(ModelPart::ConditionsContainerType::iterator i_cond = temp_conditions_container.begin() ; i_cond != temp_conditions_container.end() ; i_cond++) - { - if( i_cond->IsNot(IdentifierFlag) ) - (i_mesh->Conditions()).push_back(std::move(*(i_cond.base()))); - } + for(auto& r_mesh : this->GetMeshes()) { + ModelPartHelperUtilities::RemoveEntities(r_mesh, IdentifierFlag); } //now recursively remove the conditions in the submodelparts - for (SubModelPartIterator i_sub_model_part = SubModelPartsBegin(); i_sub_model_part != SubModelPartsEnd(); i_sub_model_part++) - i_sub_model_part->RemoveConditions(IdentifierFlag); + for (auto& r_sub_model_part : this->SubModelParts()) { + r_sub_model_part.RemoveConditions(IdentifierFlag); + } } void ModelPart::RemoveConditionsFromAllLevels(Flags IdentifierFlag) @@ -2013,7 +1889,6 @@ void ModelPart::AddGeometry( */ void ModelPart::AddGeometries(std::vector const& GeometriesIds) { - KRATOS_TRY if(IsSubModelPart()) { // Does nothing if we are on the top model part // Obtain from the root model part the corresponding list of geometries ModelPart* p_root_model_part = &this->GetRootModelPart(); @@ -2030,14 +1905,10 @@ void ModelPart::AddGeometries(std::vector const& GeometriesIds) ModelPart* p_current_part = this; while(p_current_part->IsSubModelPart()) { - for(auto& p_geom : aux) { - p_current_part->AddGeometry(p_geom); - } - + p_current_part->Geometries().insert(aux.begin(), aux.end()); p_current_part = &(p_current_part->GetParentModelPart()); } } - KRATOS_CATCH(""); } /// Removes a geometry by id. From 2c5d23f6e2563154e8b8357d47bde1f490863152 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Dec 2024 07:16:02 +0100 Subject: [PATCH 03/33] include reduction_utils --- kratos/sources/model_part.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kratos/sources/model_part.cpp b/kratos/sources/model_part.cpp index 215c3f769c35..4413c0dc0d66 100644 --- a/kratos/sources/model_part.cpp +++ b/kratos/sources/model_part.cpp @@ -20,7 +20,7 @@ #include "includes/define.h" #include "includes/model_part.h" #include "includes/exception.h" -#include "utilities/parallel_utilities.h" +#include "utilities/reduction_utilities.h" namespace Kratos { From d5521ba00ef721efcc2324257a229821fe06c435 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Dec 2024 07:25:36 +0100 Subject: [PATCH 04/33] minor --- kratos/includes/model_part.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index 890d15182c11..ad21dcc25ae8 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -1862,14 +1862,16 @@ class KRATOS_API(KRATOS_CORE) ModelPart final ModelPart* p_root_model_part = &mpModelPart->GetRootModelPart(); - block_for_each(begin, end, [p_root_model_part](const auto& prEntity) { + block_for_each(begin, end, [&](const auto& prEntity) { const auto& r_entity = ReferenceGetter::Execute(prEntity); const auto& r_entities = Container::GetContainer(p_root_model_part->GetMesh()); // TODO: This is only required to only trigger a find, not a sort. Once the find is fixed, then we can simplify this. auto it_found = r_entities.find(r_entity.Id()); KRATOS_ERROR_IF_NOT(&r_entity == &*it_found) << "attempting to add a new " << Container::GetEntityName() << " with Id :" - << r_entity.Id() << ", unfortunately a (different) " << Container::GetEntityName() - << " with the same Id already exists" + << r_entity.Id() << " to root model part " << p_root_model_part->FullName() + << ", unfortunately a (different) " << Container::GetEntityName() + << " with the same Id already exists. [ Occurred while adding " << Container::GetEntityName() + << " to " << mpModelPart->FullName() << " ]." << std::endl; }); From 2f72e0c3f6e97a1852894456ea0e9a3435da2291 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 5 Dec 2024 07:30:36 +0100 Subject: [PATCH 05/33] func name change --- kratos/includes/model_part.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index ad21dcc25ae8..9ca170552632 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -1383,7 +1383,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final ModelPart* p_root_model_part = &this->GetRootModelPart(); block_for_each(GeometryBegin, GeometriesEnd, [p_root_model_part](const auto& prGeometry) { - const auto& r_geometry = ReferenceGetter::Execute(prGeometry); + const auto& r_geometry = ReferenceGetter::Get(prGeometry); const auto& r_geometries = p_root_model_part->Geometries(); auto it_found = r_geometries.find(r_geometry.Id()); if (it_found != p_root_model_part->GeometriesEnd()) { @@ -1837,7 +1837,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final struct ReferenceGetter { template - inline static const TReturnValueType& Execute(const TInputValueType& rInputValue) { + inline static const TReturnValueType& Get(const TInputValueType& rInputValue) { if constexpr(std::is_same_v>) { return rInputValue; } else if constexpr(std::is_same_v>>) { @@ -1863,7 +1863,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final ModelPart* p_root_model_part = &mpModelPart->GetRootModelPart(); block_for_each(begin, end, [&](const auto& prEntity) { - const auto& r_entity = ReferenceGetter::Execute(prEntity); + const auto& r_entity = ReferenceGetter::Get(prEntity); const auto& r_entities = Container::GetContainer(p_root_model_part->GetMesh()); // TODO: This is only required to only trigger a find, not a sort. Once the find is fixed, then we can simplify this. auto it_found = r_entities.find(r_entity.Id()); KRATOS_ERROR_IF_NOT(&r_entity == &*it_found) From 1e98ea3ce713a545832183d835558f541a38b072 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Dec 2024 12:49:56 +0100 Subject: [PATCH 06/33] fix embedded_skin_utility for Id Change --- kratos/utilities/embedded_skin_utility.cpp | 16 ++++++++-------- kratos/utilities/embedded_skin_utility.h | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/kratos/utilities/embedded_skin_utility.cpp b/kratos/utilities/embedded_skin_utility.cpp index afcc23242c29..bde315fcda2a 100644 --- a/kratos/utilities/embedded_skin_utility.cpp +++ b/kratos/utilities/embedded_skin_utility.cpp @@ -39,8 +39,8 @@ namespace Kratos // Auxiliar vectors to store pointers to the new entities // These vectors will be use when renumbering the entities ids. - ModelPart::NodesContainerType new_nodes_vect; - ModelPart::ConditionsContainerType new_conds_vect; + std::vector new_nodes_vect; + std::vector new_conds_vect; // Set the new condition properties Properties::Pointer p_cond_prop = this->SetSkinEntitiesProperties(); @@ -121,8 +121,8 @@ namespace Kratos unsigned int &rTempNodeId, unsigned int &rTempCondId, Properties::Pointer pCondProp, - ModelPart::NodesContainerType &rNewNodesVect, - ModelPart::ConditionsContainerType &rNewCondsVect) + std::vector &rNewNodesVect, + std::vector &rNewCondsVect) { // Set the split utility and compute the splitting pattern const auto &r_geom = pElement->GetGeometry(); @@ -178,8 +178,8 @@ namespace Kratos template void EmbeddedSkinUtility::RenumberAndAddSkinEntities( - const ModelPart::NodesContainerType &rNewNodesVect, - const ModelPart::ConditionsContainerType &rNewCondsVect) + const std::vector &rNewNodesVect, + const std::vector &rNewCondsVect) { // Once all the entities have been created, renumber the ids. // Created entities local number partial reduction @@ -207,13 +207,13 @@ namespace Kratos for (int i_node = 0; i_node < static_cast(rNewNodesVect.size()); ++i_node){ auto it_node = new_nodes_begin + i_node; const unsigned int new_id = new_node_id + i_node; - it_node->SetId(new_id); + (*it_node)->SetId(new_id); } for (int i_cond = 0; i_cond < static_cast(rNewCondsVect.size()); ++i_cond){ auto it_cond = new_conds_begin + i_cond; const unsigned int new_id = new_cond_id + i_cond; - it_cond->SetId(new_id); + (*it_cond)->SetId(new_id); } // Add the created conditions to the skin model part diff --git a/kratos/utilities/embedded_skin_utility.h b/kratos/utilities/embedded_skin_utility.h index 77ac8eba307f..dd3b09966392 100644 --- a/kratos/utilities/embedded_skin_utility.h +++ b/kratos/utilities/embedded_skin_utility.h @@ -241,8 +241,8 @@ class KRATOS_API(KRATOS_CORE) EmbeddedSkinUtility unsigned int &rTempNodeId, unsigned int &rTempCondId, Properties::Pointer pCondProp, - ModelPart::NodesContainerType &rNewNodesVect, - ModelPart::ConditionsContainerType &rNewCondsVect); + std::vector &rNewNodesVect, + std::vector &rNewCondsVect); /** * @brief Checks if an element is split @@ -329,8 +329,8 @@ class KRATOS_API(KRATOS_CORE) EmbeddedSkinUtility * @param rNewCondsVect vector that stores the new skin conditions */ void RenumberAndAddSkinEntities( - const ModelPart::NodesContainerType &rNewNodesVect, - const ModelPart::ConditionsContainerType &rNewCondsVect); + const std::vector &rNewNodesVect, + const std::vector &rNewCondsVect); /** * @brief Set the Distances Vector object From 9c05b3153ea69089b27a0b0c86e498b41a99a7c2 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Dec 2024 12:50:26 +0100 Subject: [PATCH 07/33] allow insertion from const vectors --- kratos/containers/pointer_vector_set.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/kratos/containers/pointer_vector_set.h b/kratos/containers/pointer_vector_set.h index 119b128b1f2f..9732c0bc7bcc 100644 --- a/kratos/containers/pointer_vector_set.h +++ b/kratos/containers/pointer_vector_set.h @@ -20,6 +20,7 @@ #include #include #include +#include // External includes #include @@ -647,10 +648,23 @@ class PointerVectorSet final template void insert(InputIterator first, InputIterator last) { - // first sorts the input iterators and make the input unique. - std::sort(first, last, CompareKey()); - auto new_last = std::unique(first, last, EqualKeyTo()); - SortedInsert(first, new_last); + if constexpr(std::is_assignable_v()), decltype(*std::declval())>) { + // first sorts the input iterators and make the input unique if the iterators are assignable + std::sort(first, last, CompareKey()); + auto new_last = std::unique(first, last, EqualKeyTo()); + SortedInsert(first, new_last); + } else { + // the iterators are not assignable, hence they may be coming from a const vector, So, we need to make a copy + // to do the sort and unique. + std::vector temp; + temp.reserve(std::distance(first, last)); + for (auto it = first; it != last; ++it) { + temp.push_back(GetPointer(it)); + } + std::sort(temp.begin(), temp.end(), CompareKey()); + auto new_last = std::unique(temp.begin(), temp.end(), EqualKeyTo()); + SortedInsert(temp.begin(), new_last); + } } /** From abbce1564734a728bd52c445d8b05dc571dcf665 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Dec 2024 12:50:42 +0100 Subject: [PATCH 08/33] allow insertion from parent entity ranges --- kratos/includes/model_part.h | 97 ++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 15 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index 9ca170552632..0e94e9420482 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -1397,14 +1397,45 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } }); - // Add to root model part - p_root_model_part->Geometries().insert(GeometryBegin, GeometriesEnd); - - // Add to all of the leaves ModelPart* p_current_part = this; - while(p_current_part->IsSubModelPart()) { - p_current_part->Geometries().insert(GeometryBegin, GeometriesEnd); - p_current_part = &(p_current_part->GetParentModelPart()); + if constexpr(std::is_same_v>) { + // if the given iterators are of PointerVectorSet::iterator, then they may be trying to add + // new entities using a parent PointerVectorSet iterators. + do { + // check if the given [GeometryBegin, end) range is a subset of the given PointerVectorSet. + auto& current_pvs = p_current_part->Geometries(); + + auto current_pvs_begin_iterator = current_pvs.find(*GeometryBegin->Id()); + // now we check whether the current_pvs_begin_iterator's pointing (the pointer, not the iterator) memory location + // is same as the memory location of the pointer pointed by the GeometryBegin + if (current_pvs_begin_iterator != current_pvs.end() && ¤t_pvs_begin_iterator->base() == &GeometryBegin->base()) { + // memory location pointing to GeometryBegin is in the current_pvs. then check the same for the end. + auto current_pvs_end_iterator = current_pvs.find(*(GeometryBegin - 1) ->Id()); + + // now we check whether the current_pvs_end_iterator's pointing (the pointer, not the iterator) memory location + // is same as the memory location of the pointer pointed by the end + if (current_pvs_end_iterator != current_pvs.end() && ¤t_pvs_end_iterator->base() == &GeometriesEnd->base()) { + // now we can safely assume that the given [GeometryBegin, GeometriesEnd) range is a subset of the current_pvs. + // hence we don't have to add anything here. + // and we don't have to add it to the parents of the PVS, because they should be already there. + break; + } else { + // now we can safely assume that the given [GeometryBegin, GeometriesEnd) range is not a subset of the current_pvs. + // hence we have to add the given range + current_pvs.insert(GeometryBegin, GeometriesEnd); + } + } else { + // now we can safely assume that the given [GeometryBegin, GeometriesEnd) range is not a subset of the current_pvs. + // hence we have to add the given range + current_pvs.insert(GeometryBegin, GeometriesEnd); + } + p_current_part = &(p_current_part->GetParentModelPart()); + } while (p_current_part->IsSubModelPart()); + } else { + do { + p_current_part->Geometries().insert(GeometryBegin, GeometriesEnd); + p_current_part = &(p_current_part->GetParentModelPart()); + } while (p_current_part->IsSubModelPart()); } KRATOS_CATCH("") @@ -1860,13 +1891,18 @@ class KRATOS_API(KRATOS_CORE) ModelPart final void operator()(TIterator begin, TIterator end) { KRATOS_TRY + // do nothing if the begin and end are the same + if (std::distance(begin, end) == 0) { + return; + } + ModelPart* p_root_model_part = &mpModelPart->GetRootModelPart(); block_for_each(begin, end, [&](const auto& prEntity) { const auto& r_entity = ReferenceGetter::Get(prEntity); const auto& r_entities = Container::GetContainer(p_root_model_part->GetMesh()); // TODO: This is only required to only trigger a find, not a sort. Once the find is fixed, then we can simplify this. auto it_found = r_entities.find(r_entity.Id()); - KRATOS_ERROR_IF_NOT(&r_entity == &*it_found) + KRATOS_ERROR_IF(it_found != r_entities.end() && &r_entity != &*it_found) << "attempting to add a new " << Container::GetEntityName() << " with Id :" << r_entity.Id() << " to root model part " << p_root_model_part->FullName() << ", unfortunately a (different) " << Container::GetEntityName() @@ -1875,15 +1911,46 @@ class KRATOS_API(KRATOS_CORE) ModelPart final << std::endl; }); - //now add to the root model part - Container::GetContainer(p_root_model_part->GetMesh()).insert(begin, end); - - //add to all of the parents ModelPart* p_current_part = mpModelPart; - while(p_current_part->IsSubModelPart()) { - Container::GetContainer(p_current_part->GetMesh()).insert(begin, end); + do { + auto& current_pvs = Container::GetContainer(p_current_part->GetMesh()); + + if constexpr(std::is_same_v>) { + // if the given iterators are of PointerVectorSet::iterator, then they may be trying to add + // new entities using a parent PointerVectorSet iterators. + + // check if the given [begin, end) range is a subset of the given PointerVectorSet. + auto current_pvs_begin_iterator = current_pvs.find(*begin->Id()); + // now we check whether the current_pvs_begin_iterator's pointing (the pointer, not the iterator) memory location + // is same as the memory location of the pointer pointed by the begin + if (current_pvs_begin_iterator != current_pvs.end() && ¤t_pvs_begin_iterator->base() == &begin->base()) { + // memory location pointing to begin is in the current_pvs. then check the same for the end. + auto current_pvs_end_iterator = current_pvs.find(*(end - 1)->Id()); + + // now we check whether the current_pvs_end_iterator's pointing (the pointer, not the iterator) memory location + // is same as the memory location of the pointer pointed by the end + if (current_pvs_end_iterator != current_pvs.end() && ¤t_pvs_end_iterator->base() == &end->base()) { + // now we can safely assume that the given [begin, end) range is a subset of the current_pvs. + // hence we don't have to add anything here. + // and we don't have to add it to the parents of the PVS, because they should be already there. + break; + } else { + // now we can safely assume that the given [begin, end) range is not a subset of the current_pvs. + // hence we have to add the given range + current_pvs.insert(begin, end); + } + } else { + // now we can safely assume that the given [begin, end) range is not a subset of the current_pvs. + // hence we have to add the given range + current_pvs.insert(begin, end); + } + } else { + current_pvs.insert(begin, end); + } + + // now get the parent. p_current_part = &(p_current_part->GetParentModelPart()); - } + } while (p_current_part->IsSubModelPart()); KRATOS_CATCH("") } From 71ae35fdf390c56073ff5e5d1635cdc5a5d19567 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Dec 2024 15:03:47 +0100 Subject: [PATCH 09/33] fix for iterator invalidation --- kratos/includes/model_part.h | 229 +++++++++++------- ...reate_entities_from_geometries_modeler.cpp | 2 +- .../utilities/test_model_part_utilities.cpp | 8 +- 3 files changed, 141 insertions(+), 98 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index 0e94e9420482..b5e36972b7d3 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -364,8 +364,12 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddNodes(TIteratorType nodes_begin, TIteratorType nodes_end, IndexType ThisIndex = 0) { - EntityInserter inserter{this}; - inserter.operator()(nodes_begin, nodes_end); + EntityRangeChecker checker{this}; + checker.operator()(nodes_begin, nodes_end); + + InsertEntityRange([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Nodes()); + }, nodes_begin, nodes_end); } /** Inserts a node in the current mesh. @@ -663,8 +667,12 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddMasterSlaveConstraints(TIteratorType constraints_begin, TIteratorType constraints_end, IndexType ThisIndex = 0) { - EntityInserter inserter{this}; - inserter.operator()(constraints_begin, constraints_end); + EntityRangeChecker checker{this}; + checker.operator()(constraints_begin, constraints_end); + + InsertEntityRange([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().MasterSlaveConstraints()); + }, constraints_begin, constraints_end); } /** @@ -973,8 +981,12 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddElements(TIteratorType elements_begin, TIteratorType elements_end, IndexType ThisIndex = 0) { - EntityInserter inserter{this}; - inserter.operator()(elements_begin, elements_end); + EntityRangeChecker checker{this}; + checker.operator()(elements_begin, elements_end); + + InsertEntityRange([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Elements()); + }, elements_begin, elements_end); } /// Creates new element with a node ids list. @@ -1126,8 +1138,12 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddConditions(TIteratorType conditions_begin, TIteratorType conditions_end, IndexType ThisIndex = 0) { - EntityInserter inserter{this}; - inserter.operator()(conditions_begin, conditions_end); + EntityRangeChecker checker{this}; + checker.operator()(conditions_begin, conditions_end); + + InsertEntityRange([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Conditions()); + }, conditions_begin, conditions_end); } /// Creates new condition with a node ids list. @@ -1397,46 +1413,9 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } }); - ModelPart* p_current_part = this; - if constexpr(std::is_same_v>) { - // if the given iterators are of PointerVectorSet::iterator, then they may be trying to add - // new entities using a parent PointerVectorSet iterators. - do { - // check if the given [GeometryBegin, end) range is a subset of the given PointerVectorSet. - auto& current_pvs = p_current_part->Geometries(); - - auto current_pvs_begin_iterator = current_pvs.find(*GeometryBegin->Id()); - // now we check whether the current_pvs_begin_iterator's pointing (the pointer, not the iterator) memory location - // is same as the memory location of the pointer pointed by the GeometryBegin - if (current_pvs_begin_iterator != current_pvs.end() && ¤t_pvs_begin_iterator->base() == &GeometryBegin->base()) { - // memory location pointing to GeometryBegin is in the current_pvs. then check the same for the end. - auto current_pvs_end_iterator = current_pvs.find(*(GeometryBegin - 1) ->Id()); - - // now we check whether the current_pvs_end_iterator's pointing (the pointer, not the iterator) memory location - // is same as the memory location of the pointer pointed by the end - if (current_pvs_end_iterator != current_pvs.end() && ¤t_pvs_end_iterator->base() == &GeometriesEnd->base()) { - // now we can safely assume that the given [GeometryBegin, GeometriesEnd) range is a subset of the current_pvs. - // hence we don't have to add anything here. - // and we don't have to add it to the parents of the PVS, because they should be already there. - break; - } else { - // now we can safely assume that the given [GeometryBegin, GeometriesEnd) range is not a subset of the current_pvs. - // hence we have to add the given range - current_pvs.insert(GeometryBegin, GeometriesEnd); - } - } else { - // now we can safely assume that the given [GeometryBegin, GeometriesEnd) range is not a subset of the current_pvs. - // hence we have to add the given range - current_pvs.insert(GeometryBegin, GeometriesEnd); - } - p_current_part = &(p_current_part->GetParentModelPart()); - } while (p_current_part->IsSubModelPart()); - } else { - do { - p_current_part->Geometries().insert(GeometryBegin, GeometriesEnd); - p_current_part = &(p_current_part->GetParentModelPart()); - } while (p_current_part->IsSubModelPart()); - } + InsertEntityRange([](ModelPart* pModelPart) { + return &(pModelPart->Geometries()); + }, GeometryBegin, GeometriesEnd); KRATOS_CATCH("") } @@ -1883,19 +1862,14 @@ class KRATOS_API(KRATOS_CORE) ModelPart final }; template - struct EntityInserter - { + struct EntityRangeChecker{ + ModelPart* mpModelPart; template void operator()(TIterator begin, TIterator end) { KRATOS_TRY - // do nothing if the begin and end are the same - if (std::distance(begin, end) == 0) { - return; - } - ModelPart* p_root_model_part = &mpModelPart->GetRootModelPart(); block_for_each(begin, end, [&](const auto& prEntity) { @@ -1910,51 +1884,120 @@ class KRATOS_API(KRATOS_CORE) ModelPart final << " to " << mpModelPart->FullName() << " ]." << std::endl; }); + KRATOS_CATCH(""); + } + }; - ModelPart* p_current_part = mpModelPart; - do { - auto& current_pvs = Container::GetContainer(p_current_part->GetMesh()); - - if constexpr(std::is_same_v>) { - // if the given iterators are of PointerVectorSet::iterator, then they may be trying to add - // new entities using a parent PointerVectorSet iterators. - - // check if the given [begin, end) range is a subset of the given PointerVectorSet. - auto current_pvs_begin_iterator = current_pvs.find(*begin->Id()); - // now we check whether the current_pvs_begin_iterator's pointing (the pointer, not the iterator) memory location - // is same as the memory location of the pointer pointed by the begin - if (current_pvs_begin_iterator != current_pvs.end() && ¤t_pvs_begin_iterator->base() == &begin->base()) { - // memory location pointing to begin is in the current_pvs. then check the same for the end. - auto current_pvs_end_iterator = current_pvs.find(*(end - 1)->Id()); - - // now we check whether the current_pvs_end_iterator's pointing (the pointer, not the iterator) memory location - // is same as the memory location of the pointer pointed by the end - if (current_pvs_end_iterator != current_pvs.end() && ¤t_pvs_end_iterator->base() == &end->base()) { - // now we can safely assume that the given [begin, end) range is a subset of the current_pvs. - // hence we don't have to add anything here. - // and we don't have to add it to the parents of the PVS, because they should be already there. - break; - } else { - // now we can safely assume that the given [begin, end) range is not a subset of the current_pvs. - // hence we have to add the given range - current_pvs.insert(begin, end); - } - } else { - // now we can safely assume that the given [begin, end) range is not a subset of the current_pvs. - // hence we have to add the given range - current_pvs.insert(begin, end); - } + /** + * @brief + * @details Assume the following model part structure: + * MainModelPart + * -- SubModelPart1 + * -- SubSubModelPart1 + * -- SubSubModelPart2 + * + * now we try to add nodes in the following order which are stored in std::vector aux + * 1. MainModelPart.insert(aux.begin(), aux.end()); + * 2. SubModelPart2.insert(MainModelPart.begin(), MainModelPart.end()) + * + * In the second step, it will try to add the root model part nodes to the SubModelPart2. In this case, + * We need to be careful when inserting because: + * 1. Every range insertion will invalidate the iterators of the respective PointerVectorSet because + * at the end of the range insertion, we do a swap between the underlying container of PointerVectorSet. + * 2. We need valid iterators to insert for all the parent model parts. + * + * Therefore, in this method, if the iterator type is of the same PointerVectorSet::iterator (means, the iterator originated from + * a PointerVectorSet of the same type), then we check the raw memory pointed by the iterators [begin, end) (PointerVectorSet::pointer type object memory location, + * not the PointerVectorSet::value_type memory location) are a subset of the same memory range pointed by PointerVectorSet::begin and PointerVectorSet::end. + * - If they are a subset, we don't do anything, and we will avoid recursively filling parents as well because, at this point parents should be already filled. + * - If they are not a subset, then we insert them. That means, the range given for insertion did not originate from the current ModelPart, hence it will not + * invalidate the range [begin, end). + * If the iterator type not of the same PointerVectorSet::iterator, then we insert them in normal manner. + * @tparam TContainerGetter + * @tparam TIterator + * @param pModelPart + * @param rContainerGetter + * @param begin + * @param end + * @return true + * @return false + */ + template + static bool InsertEntityRange( + ModelPart* pModelPart, + TContainerGetter&& rContainerGetter, + TIterator begin, + TIterator end) + { + KRATOS_TRY + + auto& current_pvs = *rContainerGetter(pModelPart); + + if constexpr(std::is_same_v>) { + // do nothing if the given range is empty. + if (std::distance(begin, end) == 0) { + return false; + } + + // if the given iterators are of PointerVectorSet::iterator, then they may be trying to add + // new entities using a parent PointerVectorSet iterators. + + // check if the given [begin, end) range is a subset of the given PointerVectorSet. + auto current_pvs_begin_iterator = current_pvs.find(*begin->Id()); + // now we check whether the current_pvs_begin_iterator's pointing (the pointer, not the iterator) memory location + // is same as the memory location of the pointer pointed by the begin + if (current_pvs_begin_iterator != current_pvs.end() && ¤t_pvs_begin_iterator->base() == &begin->base()) { + // memory location pointing to begin is in the current_pvs. then check the same for the end. + auto current_pvs_end_iterator = current_pvs.find(*(end - 1)->Id()); + + // now we check whether the current_pvs_end_iterator's pointing (the pointer, not the iterator) memory location + // is same as the memory location of the pointer pointed by the end + if (current_pvs_end_iterator != current_pvs.end() && ¤t_pvs_end_iterator->base() == &end->base()) { + // now we can safely assume that the given [begin, end) range is a subset of the current_pvs. + // hence we don't have to add anything here. + // and we don't have to add it to the parents of the PVS, because they should be already there. + return false; } else { + // now we can safely assume that the given [begin, end) range is not a subset of the current_pvs. + // hence we have to add the given range current_pvs.insert(begin, end); } + } else { + // now we can safely assume that the given [begin, end) range is not a subset of the current_pvs. + // hence we have to add the given range + current_pvs.insert(begin, end); + } + } else { + current_pvs.insert(begin, end); + } + + return true; - // now get the parent. - p_current_part = &(p_current_part->GetParentModelPart()); - } while (p_current_part->IsSubModelPart()); + KRATOS_CATCH(""); + } - KRATOS_CATCH("") + template + void InsertEntityRange( + TContainerGetter&& rContainerGetter, + TIterator begin, + TIterator end) + { + KRATOS_TRY + + ModelPart* p_current_part = this; + bool has_range_added = true; + while (p_current_part->IsSubModelPart() && has_range_added) { + has_range_added = InsertEntityRange(p_current_part, rContainerGetter, begin, end); + p_current_part = &(p_current_part->GetParentModelPart()); } - }; + + // now finally add to the root model part + if (has_range_added) { + InsertEntityRange(&(p_current_part->GetRootModelPart()), rContainerGetter, begin, end); + } + + KRATOS_CATCH("") + } /** * @brief This method trims a string in the different components to access recursively to any subproperty diff --git a/kratos/modeler/create_entities_from_geometries_modeler.cpp b/kratos/modeler/create_entities_from_geometries_modeler.cpp index 4326f6dd1434..bd0922128d67 100644 --- a/kratos/modeler/create_entities_from_geometries_modeler.cpp +++ b/kratos/modeler/create_entities_from_geometries_modeler.cpp @@ -36,7 +36,7 @@ void CreateEntitiesFromGeometries( ModelPart& rModelPart) { // Create the entities container and allocate space - TEntitiesContainerType entities_to_add; + std::vector entities_to_add; entities_to_add.reserve(rModelPart.NumberOfGeometries()); // Get current max element id diff --git a/kratos/tests/cpp_tests/utilities/test_model_part_utilities.cpp b/kratos/tests/cpp_tests/utilities/test_model_part_utilities.cpp index 90defa906952..ff9a11eb6b90 100644 --- a/kratos/tests/cpp_tests/utilities/test_model_part_utilities.cpp +++ b/kratos/tests/cpp_tests/utilities/test_model_part_utilities.cpp @@ -31,12 +31,12 @@ namespace Kratos::Testing { for(std::size_t id=1; id<25; id++) { auto p_node = r_model_part.CreateNewNode(id, 0.00,0.00,0.00); if (id%2!=0) { - aux.push_back(p_node); + aux.insert(aux.end(), p_node); } if (id<15) { - aux2.push_back(p_node); + aux2.insert(aux2.end(), p_node); } - aux3.push_back(p_node); + aux3.insert(aux3.end(), p_node); } // We check the first one r_ssmp.AddNodes(aux.begin(), aux.end()); @@ -63,7 +63,7 @@ namespace Kratos::Testing { // Here we can go a bit further. No need to be Unique for(auto it=aux.begin();it!=aux.end(); it++){ - aux3.push_back(*(it.base())); + aux3.insert(aux3.end(), *(it.base())); } r_ssmp.AddNodes(aux3.begin(), aux3.end()); KRATOS_EXPECT_EQ(r_ssmp.NumberOfNodes(), 24); From 6d34602af6e8317fe00e62b9975b7a88cfbd2e50 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Dec 2024 15:15:39 +0100 Subject: [PATCH 10/33] add comments --- kratos/includes/model_part.h | 42 ++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index b5e36972b7d3..0ca57d1c53d1 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -1843,6 +1843,16 @@ class KRATOS_API(KRATOS_CORE) ModelPart final ///@name Private Operations ///@{ + /** + * @brief Provides a mechanism to get the reference from given input with some types. + * @details The range addition methods in the model parts are used with following types: + * - std::vector::iterator -> dereference will give the Entity::Pointer + * - PointerVectorSet::iterator -> dereference will give the Entity + * - PointerVectorSet::ptr_iterator -> dereference will give the Entity::Pointer. + * This functor generalizes and gives the reference from a given entity. + * + * @tparam TReturnValueType + */ template struct ReferenceGetter { @@ -1861,6 +1871,11 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } }; + /** + * @brief Generalized checker to check whether if an item being inserted is already there, if so whether the item is the same. + * + * @tparam TContainerType + */ template struct EntityRangeChecker{ @@ -1889,7 +1904,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final }; /** - * @brief + * @brief Insert a given range of entities to a model part container if the given range is not a subset. * @details Assume the following model part structure: * MainModelPart * -- SubModelPart1 @@ -1913,14 +1928,14 @@ class KRATOS_API(KRATOS_CORE) ModelPart final * - If they are not a subset, then we insert them. That means, the range given for insertion did not originate from the current ModelPart, hence it will not * invalidate the range [begin, end). * If the iterator type not of the same PointerVectorSet::iterator, then we insert them in normal manner. - * @tparam TContainerGetter - * @tparam TIterator - * @param pModelPart - * @param rContainerGetter - * @param begin - * @param end - * @return true - * @return false + * @tparam TContainerGetter Lambda function type to get the PointerVectorSet from a ModelPart* + * @tparam TIterator Type of the iterator + * @param pModelPart Model part to get the container from + * @param rContainerGetter Lambda function type to get the PointerVectorSet from a ModelPart* [](ModelPart*) -> PointerVectorSet* + * @param begin Begining of the range + * @param end End of the range + * @return true If the given range is not a subset of the current PointerVectorSet given by rContainerGetter(pModelPart) + * @return false If the given range is a subset of the current PointerVectorSet given by rContainerGetter(pModelPart) */ template static bool InsertEntityRange( @@ -1976,6 +1991,15 @@ class KRATOS_API(KRATOS_CORE) ModelPart final KRATOS_CATCH(""); } + /** + * @brief Generalized method to add entities to the current model part and all the parent model parts. + * + * @tparam TContainerGetter + * @tparam TIterator + * @param rContainerGetter + * @param begin + * @param end + */ template void InsertEntityRange( TContainerGetter&& rContainerGetter, From f1c4a6f7e66e356d14f20b1bf567e47ad3096ef1 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Tue, 10 Dec 2024 15:45:08 +0100 Subject: [PATCH 11/33] minor signature modification --- kratos/includes/model_part.h | 48 +++++++++++++++++------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index 0ca57d1c53d1..90b50ad61aaf 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -1928,26 +1928,22 @@ class KRATOS_API(KRATOS_CORE) ModelPart final * - If they are not a subset, then we insert them. That means, the range given for insertion did not originate from the current ModelPart, hence it will not * invalidate the range [begin, end). * If the iterator type not of the same PointerVectorSet::iterator, then we insert them in normal manner. - * @tparam TContainerGetter Lambda function type to get the PointerVectorSet from a ModelPart* - * @tparam TIterator Type of the iterator - * @param pModelPart Model part to get the container from - * @param rContainerGetter Lambda function type to get the PointerVectorSet from a ModelPart* [](ModelPart*) -> PointerVectorSet* - * @param begin Begining of the range - * @param end End of the range - * @return true If the given range is not a subset of the current PointerVectorSet given by rContainerGetter(pModelPart) - * @return false If the given range is a subset of the current PointerVectorSet given by rContainerGetter(pModelPart) + * @tparam TPointerVectorSetContainer Type of the PointerVectorSet container + * @tparam TIterator Type of the iterator + * @param rContainer PointerVectorSet container to insert the given range. + * @param begin Begining of the range + * @param end End of the range + * @return true If the given range is not a subset of the current PointerVectorSet given by rContainerGetter(pModelPart) + * @return false If the given range is a subset of the current PointerVectorSet given by rContainerGetter(pModelPart) */ - template + template static bool InsertEntityRange( - ModelPart* pModelPart, - TContainerGetter&& rContainerGetter, + TPointerVectorSetContainer& rContainer, TIterator begin, TIterator end) { KRATOS_TRY - auto& current_pvs = *rContainerGetter(pModelPart); - if constexpr(std::is_same_v>) { // do nothing if the given range is empty. if (std::distance(begin, end) == 0) { @@ -1958,32 +1954,32 @@ class KRATOS_API(KRATOS_CORE) ModelPart final // new entities using a parent PointerVectorSet iterators. // check if the given [begin, end) range is a subset of the given PointerVectorSet. - auto current_pvs_begin_iterator = current_pvs.find(*begin->Id()); + auto current_pvs_begin_iterator = rContainer.find(*begin->Id()); // now we check whether the current_pvs_begin_iterator's pointing (the pointer, not the iterator) memory location // is same as the memory location of the pointer pointed by the begin - if (current_pvs_begin_iterator != current_pvs.end() && ¤t_pvs_begin_iterator->base() == &begin->base()) { - // memory location pointing to begin is in the current_pvs. then check the same for the end. - auto current_pvs_end_iterator = current_pvs.find(*(end - 1)->Id()); + if (current_pvs_begin_iterator != rContainer.end() && ¤t_pvs_begin_iterator->base() == &begin->base()) { + // memory location pointing to begin is in the rContainer. then check the same for the end. + auto current_pvs_end_iterator = rContainer.find(*(end - 1)->Id()); // now we check whether the current_pvs_end_iterator's pointing (the pointer, not the iterator) memory location // is same as the memory location of the pointer pointed by the end - if (current_pvs_end_iterator != current_pvs.end() && ¤t_pvs_end_iterator->base() == &end->base()) { - // now we can safely assume that the given [begin, end) range is a subset of the current_pvs. + if (current_pvs_end_iterator != rContainer.end() && ¤t_pvs_end_iterator->base() == &end->base()) { + // now we can safely assume that the given [begin, end) range is a subset of the rContainer. // hence we don't have to add anything here. // and we don't have to add it to the parents of the PVS, because they should be already there. return false; } else { - // now we can safely assume that the given [begin, end) range is not a subset of the current_pvs. + // now we can safely assume that the given [begin, end) range is not a subset of the rContainer. // hence we have to add the given range - current_pvs.insert(begin, end); + rContainer.insert(begin, end); } } else { - // now we can safely assume that the given [begin, end) range is not a subset of the current_pvs. + // now we can safely assume that the given [begin, end) range is not a subset of the rContainer. // hence we have to add the given range - current_pvs.insert(begin, end); + rContainer.insert(begin, end); } } else { - current_pvs.insert(begin, end); + rContainer.insert(begin, end); } return true; @@ -2011,13 +2007,13 @@ class KRATOS_API(KRATOS_CORE) ModelPart final ModelPart* p_current_part = this; bool has_range_added = true; while (p_current_part->IsSubModelPart() && has_range_added) { - has_range_added = InsertEntityRange(p_current_part, rContainerGetter, begin, end); + has_range_added = InsertEntityRange(*rContainerGetter(p_current_part), begin, end); p_current_part = &(p_current_part->GetParentModelPart()); } // now finally add to the root model part if (has_range_added) { - InsertEntityRange(&(p_current_part->GetRootModelPart()), rContainerGetter, begin, end); + InsertEntityRange(*rContainerGetter(&(p_current_part->GetRootModelPart())), begin, end); } KRATOS_CATCH("") From 35c187475aa10ef6395a3be4bfbc6c0fe2af5c12 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Dec 2024 04:49:12 +0100 Subject: [PATCH 12/33] fix assign_ms_const_to_neigh_utils --- .../assign_master_slave_constraints_to_neighbours_utility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.cpp b/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.cpp index 4bba4689fdd9..9b3169bfa7e5 100644 --- a/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.cpp +++ b/kratos/utilities/assign_master_slave_constraints_to_neighbours_utility.cpp @@ -222,7 +222,7 @@ void AssignMasterSlaveConstraintsToNeighboursUtility::AssignMasterSlaveConstrain }); // Create a temporary container to store the master-slave constraints - ConstraintContainerType temp_constraints; + std::vector temp_constraints; ModelPart::MasterSlaveConstraintType::Pointer p_constraint; // Dequeue the constraints from the concurrent queue and add them to the temporary container From 13e87e7e09246cef26bee1d8f62c7066f3884e40 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Dec 2024 05:03:37 +0100 Subject: [PATCH 13/33] fix error msg tests --- kratos/tests/test_model_part.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kratos/tests/test_model_part.py b/kratos/tests/test_model_part.py index f1ea24395519..e418d644d8eb 100644 --- a/kratos/tests/test_model_part.py +++ b/kratos/tests/test_model_part.py @@ -734,7 +734,7 @@ def test_add_node(self): ### here we test adding a list of nodes at once #now add node 4 and 5 to the model_part1 by Id - here it fails since we did not yet add node 4 - with self.assertRaisesRegex(RuntimeError, "Error: while adding nodes to submodelpart, the node with Id 4 does not exist in the root model part"): + with self.assertRaisesRegex(RuntimeError, "Error: while adding nodes to submodelpart Main.sub1, the node with Id 4 does not exist in the root model part"): sub1.AddNodes([4,5]) model_part1.AddNode( n4, 0 ) @@ -783,7 +783,7 @@ def test_add_condition(self): ### here we test adding a list of conditions at once #now add node 4 and 5 to the model_part1 by Id - here it fails since we did not yet add node 4 - with self.assertRaisesRegex(RuntimeError, "Error: the condition with Id 4 does not exist in the root model part"): + with self.assertRaisesRegex(RuntimeError, "Error: while adding conditions to submodelpart Main.sub1, the condition with Id 4 does not exist in the root model part"): sub1.AddConditions([4,5]) model_part1.AddCondition( c4, 0 ) @@ -831,7 +831,7 @@ def test_add_element(self): ### here we test adding a list of elements at once #now add node 4 and 5 to the model_part1 by Id - here it fails since we did not yet add node 4 - with self.assertRaisesRegex(RuntimeError, "Error: the element with Id 4 does not exist in the root model part"): + with self.assertRaisesRegex(RuntimeError, "Error: while adding elements to submodelpart Main.sub1, the element with Id 4 does not exist in the root model part"): sub1.AddElements([4,5]) model_part1.AddElement( e4, 0 ) From a50fd2baf6a77bf6ea677a8bfb87b0a7e318e489 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Dec 2024 05:19:32 +0100 Subject: [PATCH 14/33] fix hdf5 --- .../custom_io/hdf5_connectivities_data.cpp | 10 ++++++++-- .../HDF5Application/custom_io/hdf5_points_data.cpp | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/applications/HDF5Application/custom_io/hdf5_connectivities_data.cpp b/applications/HDF5Application/custom_io/hdf5_connectivities_data.cpp index 343369247550..b6a621a7a515 100644 --- a/applications/HDF5Application/custom_io/hdf5_connectivities_data.cpp +++ b/applications/HDF5Application/custom_io/hdf5_connectivities_data.cpp @@ -90,7 +90,10 @@ void ConnectivitiesData::CreateEntities(NodesContainerType& rNodes, } ElementType::Pointer p_elem = r_elem.Create(mIds[i], nodes, rProperties(mPropertiesIds[i])); - rElements.push_back(p_elem); + // here we can safely use the insert with the rElements.end() as the hint + // because, when reading, we can assume that it was written in the + // sorted order within HDF5. + rElements.insert(rElements.end(), p_elem); } KRATOS_CATCH(""); } @@ -119,7 +122,10 @@ void ConnectivitiesData::CreateEntities(NodesContainerType& rNodes, } Condition::Pointer p_cond = r_cond.Create(mIds[i], nodes, rProperties(mPropertiesIds[i])); - rConditions.push_back(p_cond); + // here we can safely use the insert with the rConditions.end() as the hint + // because, when reading, we can assume that it was written in the + // sorted order within HDF5. + rConditions.insert(rConditions.end(), p_cond); } KRATOS_CATCH(""); } diff --git a/applications/HDF5Application/custom_io/hdf5_points_data.cpp b/applications/HDF5Application/custom_io/hdf5_points_data.cpp index 8e7c4fa5d5ff..354a0006bb55 100644 --- a/applications/HDF5Application/custom_io/hdf5_points_data.cpp +++ b/applications/HDF5Application/custom_io/hdf5_points_data.cpp @@ -36,7 +36,10 @@ void PointsData::CreateNodes(NodesContainerType& rNodes) const array_1d& r_coord = mCoords[i]; NodeType::Pointer p_node = Kratos::make_intrusive( mIds[i], r_coord[0], r_coord[1], r_coord[2]); - rNodes.push_back(p_node); + // here we can safely use the insert with the rNodes.end() as the hint + // because, when reading, we can assume that it was written in the + // sorted order within HDF5. + rNodes.insert(rNodes.end(), p_node); } KRATOS_CATCH(""); } From 8a4275983cccc3db092194ccad86d0b2edcc851b Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Dec 2024 10:57:52 +0100 Subject: [PATCH 15/33] generalize addition from ids --- kratos/includes/model_part.h | 5 +++ kratos/sources/model_part.cpp | 85 ++++++++++++++++++----------------- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index 90b50ad61aaf..0badf8ed48e7 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -2019,6 +2019,11 @@ class KRATOS_API(KRATOS_CORE) ModelPart final KRATOS_CATCH("") } + template + static void AddEntitiesFromIds( + ModelPart* pModelPart, + const std::vector& rEntityIds); + /** * @brief This method trims a string in the different components to access recursively to any subproperty * @param rStringName The given name to be trimmed diff --git a/kratos/sources/model_part.cpp b/kratos/sources/model_part.cpp index 4413c0dc0d66..2902585475ea 100644 --- a/kratos/sources/model_part.cpp +++ b/kratos/sources/model_part.cpp @@ -31,44 +31,6 @@ KRATOS_CREATE_LOCAL_FLAG(ModelPart, OVERWRITE_ENTITIES, 1); namespace ModelPartHelperUtilities { -template -void AddEntitiesFromIds( - ModelPart* pModelPart, - const std::vector& rEntityIds) -{ - KRATOS_TRY - - if(pModelPart->IsSubModelPart()) { //does nothing if we are on the top model part - //obtain from the root model part the corresponding list of nodes - ModelPart* root_model_part = &pModelPart->GetRootModelPart(); - - std::vector aux; - aux.reserve(rEntityIds.size()); - - const auto& r_container = ModelPart::Container::GetContainer(root_model_part->GetMesh()); - - for(const auto entity_id : rEntityIds) { - auto it = r_container.find(entity_id); - if(it != r_container.end()) { - aux.push_back(*(it.base())); - } else { - KRATOS_ERROR << "while adding " << ModelPart::Container::GetEntityName() << "s to submodelpart " - << pModelPart->FullName() << ", the " - << ModelPart::Container::GetEntityName() - << " with Id " << entity_id << " does not exist in the root model part"; - } - } - - ModelPart* current_part = pModelPart; - while(current_part->IsSubModelPart()) { - ModelPart::Container::GetContainer(current_part->GetMesh()).insert(aux.begin(), aux.end()); - current_part = &(current_part->GetParentModelPart()); - } - } - - KRATOS_CATCH(""); -} - template void RemoveEntities( ModelPart::MeshType& rMesh, @@ -302,11 +264,50 @@ void ModelPart::AddNode(ModelPart::NodeType::Pointer pNewNode, ModelPart::IndexT } } +template +void ModelPart::AddEntitiesFromIds( + ModelPart* pModelPart, + const std::vector& rEntityIds) +{ + KRATOS_TRY + + if(pModelPart->IsSubModelPart()) { //does nothing if we are on the top model part + //obtain from the root model part the corresponding list of nodes + ModelPart* root_model_part = &pModelPart->GetRootModelPart(); + + std::vector aux; + aux.resize(rEntityIds.size()); + + const auto& r_container = ModelPart::Container::GetContainer(root_model_part->GetMesh()); + + IndexPartition(rEntityIds.size()).for_each([&r_container, &rEntityIds, &aux, pModelPart](const auto Index) { + auto it = r_container.find(rEntityIds[Index]); + + KRATOS_ERROR_IF(it == r_container.end()) + << "while adding " << ModelPart::Container::GetEntityName() << "s to submodelpart " + << pModelPart->FullName() << ", the " + << ModelPart::Container::GetEntityName() + << " with Id " << rEntityIds[Index] << " does not exist in the root model part"; + + aux[Index] = *(it.base()); + }); + + ModelPart* current_part = pModelPart; + while( + current_part->IsSubModelPart() && + InsertEntityRange(ModelPart::Container::GetContainer(current_part->GetMesh()), aux.begin(), aux.end())) { + current_part = &(current_part->GetParentModelPart()); + } + } + + KRATOS_CATCH(""); +} + /** Inserts a list of nodes in a submodelpart provided their Id. Does nothing if applied to the top model part */ void ModelPart::AddNodes(std::vector const& rNodeIds, IndexType ThisIndex) { - ModelPartHelperUtilities::AddEntitiesFromIds(this, rNodeIds); + AddEntitiesFromIds(this, rNodeIds); } /** Inserts a node in the mesh with ThisIndex. @@ -960,7 +961,7 @@ void ModelPart::AddElement(ModelPart::ElementType::Pointer pNewElement, ModelPar */ void ModelPart::AddElements(std::vector const& ElementIds, IndexType ThisIndex) { - ModelPartHelperUtilities::AddEntitiesFromIds(this, ElementIds); + AddEntitiesFromIds(this, ElementIds); } /** Inserts an element in the mesh with ThisIndex. @@ -1170,7 +1171,7 @@ void ModelPart::AddMasterSlaveConstraint(ModelPart::MasterSlaveConstraintType::P */ void ModelPart::AddMasterSlaveConstraints(std::vector const& MasterSlaveConstraintIds, IndexType ThisIndex) { - ModelPartHelperUtilities::AddEntitiesFromIds(this, MasterSlaveConstraintIds); + AddEntitiesFromIds(this, MasterSlaveConstraintIds); } /// @brief Construct a new @ref MasterSlaveConstraint and insert it into the specified @ref Mesh. @@ -1402,7 +1403,7 @@ void ModelPart::AddCondition(ModelPart::ConditionType::Pointer pNewCondition, Mo */ void ModelPart::AddConditions(std::vector const& ConditionIds, IndexType ThisIndex) { - ModelPartHelperUtilities::AddEntitiesFromIds(this, ConditionIds); + AddEntitiesFromIds(this, ConditionIds); } /** Inserts a condition in the mesh with ThisIndex. From 93293e0d3e8eeec3d73779fc4813b9bedeee2000 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Dec 2024 11:49:14 +0100 Subject: [PATCH 16/33] simplify --- kratos/sources/model_part.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kratos/sources/model_part.cpp b/kratos/sources/model_part.cpp index 2902585475ea..bfaf73174d35 100644 --- a/kratos/sources/model_part.cpp +++ b/kratos/sources/model_part.cpp @@ -293,9 +293,8 @@ void ModelPart::AddEntitiesFromIds( }); ModelPart* current_part = pModelPart; - while( - current_part->IsSubModelPart() && - InsertEntityRange(ModelPart::Container::GetContainer(current_part->GetMesh()), aux.begin(), aux.end())) { + while(current_part->IsSubModelPart()) { + ModelPart::Container::GetContainer(current_part->GetMesh()).insert(aux.begin(), aux.end()); current_part = &(current_part->GetParentModelPart()); } } From 6adabf4fe3a9a05e71ccb665b9cce2e031c20415 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 11 Dec 2024 15:13:14 +0100 Subject: [PATCH 17/33] fix ranged id addition --- kratos/includes/model_part.h | 159 +++++++++++++++------------------- kratos/sources/model_part.cpp | 121 +++++++++++++------------- 2 files changed, 129 insertions(+), 151 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index 0badf8ed48e7..c6b90f7e4bfd 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -1903,92 +1903,53 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } }; - /** - * @brief Insert a given range of entities to a model part container if the given range is not a subset. - * @details Assume the following model part structure: - * MainModelPart - * -- SubModelPart1 - * -- SubSubModelPart1 - * -- SubSubModelPart2 - * - * now we try to add nodes in the following order which are stored in std::vector aux - * 1. MainModelPart.insert(aux.begin(), aux.end()); - * 2. SubModelPart2.insert(MainModelPart.begin(), MainModelPart.end()) - * - * In the second step, it will try to add the root model part nodes to the SubModelPart2. In this case, - * We need to be careful when inserting because: - * 1. Every range insertion will invalidate the iterators of the respective PointerVectorSet because - * at the end of the range insertion, we do a swap between the underlying container of PointerVectorSet. - * 2. We need valid iterators to insert for all the parent model parts. - * - * Therefore, in this method, if the iterator type is of the same PointerVectorSet::iterator (means, the iterator originated from - * a PointerVectorSet of the same type), then we check the raw memory pointed by the iterators [begin, end) (PointerVectorSet::pointer type object memory location, - * not the PointerVectorSet::value_type memory location) are a subset of the same memory range pointed by PointerVectorSet::begin and PointerVectorSet::end. - * - If they are a subset, we don't do anything, and we will avoid recursively filling parents as well because, at this point parents should be already filled. - * - If they are not a subset, then we insert them. That means, the range given for insertion did not originate from the current ModelPart, hence it will not - * invalidate the range [begin, end). - * If the iterator type not of the same PointerVectorSet::iterator, then we insert them in normal manner. - * @tparam TPointerVectorSetContainer Type of the PointerVectorSet container - * @tparam TIterator Type of the iterator - * @param rContainer PointerVectorSet container to insert the given range. - * @param begin Begining of the range - * @param end End of the range - * @return true If the given range is not a subset of the current PointerVectorSet given by rContainerGetter(pModelPart) - * @return false If the given range is a subset of the current PointerVectorSet given by rContainerGetter(pModelPart) - */ - template - static bool InsertEntityRange( - TPointerVectorSetContainer& rContainer, + template + static bool IsSubSet( + const TContainerType& rContainer, TIterator begin, TIterator end) { - KRATOS_TRY - - if constexpr(std::is_same_v>) { - // do nothing if the given range is empty. - if (std::distance(begin, end) == 0) { - return false; - } - - // if the given iterators are of PointerVectorSet::iterator, then they may be trying to add - // new entities using a parent PointerVectorSet iterators. - - // check if the given [begin, end) range is a subset of the given PointerVectorSet. - auto current_pvs_begin_iterator = rContainer.find(*begin->Id()); - // now we check whether the current_pvs_begin_iterator's pointing (the pointer, not the iterator) memory location - // is same as the memory location of the pointer pointed by the begin - if (current_pvs_begin_iterator != rContainer.end() && ¤t_pvs_begin_iterator->base() == &begin->base()) { - // memory location pointing to begin is in the rContainer. then check the same for the end. - auto current_pvs_end_iterator = rContainer.find(*(end - 1)->Id()); - - // now we check whether the current_pvs_end_iterator's pointing (the pointer, not the iterator) memory location - // is same as the memory location of the pointer pointed by the end - if (current_pvs_end_iterator != rContainer.end() && ¤t_pvs_end_iterator->base() == &end->base()) { - // now we can safely assume that the given [begin, end) range is a subset of the rContainer. - // hence we don't have to add anything here. - // and we don't have to add it to the parents of the PVS, because they should be already there. - return false; - } else { - // now we can safely assume that the given [begin, end) range is not a subset of the rContainer. - // hence we have to add the given range - rContainer.insert(begin, end); - } - } else { - // now we can safely assume that the given [begin, end) range is not a subset of the rContainer. - // hence we have to add the given range - rContainer.insert(begin, end); - } - } else { - rContainer.insert(begin, end); + // do nothing if the given range is empty. + if (std::distance(begin, end) == 0) { + return true; } - return true; + // check if the given [begin, end) range is a subset of the given PointerVectorSet. + auto current_pvs_begin_it = rContainer.find(*begin->Id()); + if (current_pvs_begin_it != rContainer.end() && ¤t_pvs_begin_it->base() == &begin->base()) { + // memory location pointing to begin is in the rContainer. then check the same for the end. + auto current_pvs_end_it = rContainer.find(*(end - 1)->Id()); + return current_pvs_end_it != rContainer.end() && ¤t_pvs_end_it->base() == &end->base(); + } - KRATOS_CATCH(""); + return false; } /** * @brief Generalized method to add entities to the current model part and all the parent model parts. + * @details Following cases are considered + * 1. TIterator not being the type of the PointerVectorSet::iterator + * 2. TIterator being the type of PointerVectorSet::iterator + * a. [begin, end) defines a subrange in the considered PointerVectorSet. + * b. [begin, end) does not define a subrange in the considered PointerVectorSet. + * + * - In the case 1: + * - We have to make sure that the range [begin, end) is not always sorted and made unique when inserted to + * current model part and the parent model part. This requires constructing an auxiliary TContainerType container + * to add the items in the range. + * -- This will keep on increasing the capacity of the current PVS as well as all the + * parent PVS containers. + * + * - In the case 2a: + * - If it defines a subrange, we don't have to do anything. We can simply skip the insertion on the current PVS as + * well as in all the parents because they must already have the subrange. + * -- This will keep the same capacity of the PVS. + * + * - In the case 2b: + * - If does not define a subrange and it is of type PVS, hence they are sorted and made unique. So we don't need + * an auxiliary here as well. + * -- This will keep on increasing the capacity of the current PVS as well as all the + * parent PVS containers. * * @tparam TContainerGetter * @tparam TIterator @@ -2004,26 +1965,40 @@ class KRATOS_API(KRATOS_CORE) ModelPart final { KRATOS_TRY + ModelPart* p_current_part = this; - bool has_range_added = true; - while (p_current_part->IsSubModelPart() && has_range_added) { - has_range_added = InsertEntityRange(*rContainerGetter(p_current_part), begin, end); - p_current_part = &(p_current_part->GetParentModelPart()); - } - // now finally add to the root model part - if (has_range_added) { - InsertEntityRange(*rContainerGetter(&(p_current_part->GetRootModelPart())), begin, end); + if constexpr(!std::is_same_v>) { + // this represents the case 1. + using container_type = std::remove_pointer_t()(std::declval()))>; + container_type aux; + aux.insert(begin, end); + + // we add to all the parents and the current model part + while (p_current_part->IsSubModelPart()) { + rContainerGetter(p_current_part)->insert(aux.begin(), aux.end()); + p_current_part = &(p_current_part->GetParentModelPart()); + } + + // now we add to the root model part + rContainerGetter(p_current_part)->insert(aux.begin(), aux.end()); + } else { + // this represents the case 2. + // now the iterators belong to PVS::iterator, hence no sorting or making them to unique will occur. + while (p_current_part->IsSubModelPart() && !IsSubSet(*rContainerGetter(p_current_part), begin, end)) { + rContainerGetter(p_current_part)->insert(begin, end); + p_current_part = &(p_current_part->GetParentModelPart()); + } + + // now we do the same for the root model part + if (!IsSubSet(*rContainerGetter(p_current_part), begin, end)) { + rContainerGetter(p_current_part)->insert(begin, end); + } } KRATOS_CATCH("") } - template - static void AddEntitiesFromIds( - ModelPart* pModelPart, - const std::vector& rEntityIds); - /** * @brief This method trims a string in the different components to access recursively to any subproperty * @param rStringName The given name to be trimmed @@ -2124,6 +2099,12 @@ template <> struct ModelPart::Container struct ModelPart::Container { + static std::string GetEntityName() { return "geometry"; } + // TODO: Can be used once we move the geometries container to meshes. + // static GeometriesMapType& GetContainer(ModelPart::MeshType& rMesh) { return rMesh.Geometries(); } +}; + ///@} ///@name Input and output ///@{ diff --git a/kratos/sources/model_part.cpp b/kratos/sources/model_part.cpp index bfaf73174d35..537f2d87f98a 100644 --- a/kratos/sources/model_part.cpp +++ b/kratos/sources/model_part.cpp @@ -13,6 +13,7 @@ // System includes #include +#include // External includes @@ -31,6 +32,59 @@ KRATOS_CREATE_LOCAL_FLAG(ModelPart, OVERWRITE_ENTITIES, 1); namespace ModelPartHelperUtilities { +template +void AddEntitiesFromIds( + TContainerGetter&& rContainerGetter, + ModelPart* pModelPart, + const std::vector& rEntityIds) +{ + KRATOS_TRY + + using container_type = std::remove_pointer_t()(std::declval()))>; + + if(pModelPart->IsSubModelPart()) { //does nothing if we are on the top model part + //obtain from the root model part the corresponding list of nodes + ModelPart* root_model_part = &pModelPart->GetRootModelPart(); + + // we first sort and unique the given entity ids. + std::vector unique_sorted_ids; + unique_sorted_ids.resize(rEntityIds.size()); + IndexPartition(rEntityIds.size()).for_each([&unique_sorted_ids, &rEntityIds](const auto Index) { + unique_sorted_ids[Index] = rEntityIds[Index]; + }); + std::sort(unique_sorted_ids.begin(), unique_sorted_ids.end()); + auto new_last = std::unique(unique_sorted_ids.begin(), unique_sorted_ids.end()); + + const auto& r_container = *rContainerGetter(root_model_part); + + // aux is created to avoid doing sort and unique for all the parent model parts and current model part + // when insertion is done. + container_type aux; + aux.reserve(std::distance(unique_sorted_ids.begin(), new_last)); + for (auto it_id = unique_sorted_ids.begin(); it_id != new_last; ++it_id) { + auto it = r_container.find(*it_id); + + KRATOS_ERROR_IF(it == r_container.end()) + << "while adding " << ModelPart::Container::GetEntityName() << "s to submodelpart " + << pModelPart->FullName() << ", the " + << ModelPart::Container::GetEntityName() + << " with Id " << *it_id << " does not exist in the root model part"; + + // here the hint is valid, hence this will be a simple push_back within the PVS. + aux.insert(aux.end(), *(it.base())); + } + + ModelPart* current_part = pModelPart; + while(current_part->IsSubModelPart()) { + // this will directly call the PVS::insert overloaded for the PVS::iterator type. + rContainerGetter(current_part)->insert(aux.begin(), aux.end()); + current_part = &(current_part->GetParentModelPart()); + } + } + + KRATOS_CATCH(""); +} + template void RemoveEntities( ModelPart::MeshType& rMesh, @@ -264,49 +318,11 @@ void ModelPart::AddNode(ModelPart::NodeType::Pointer pNewNode, ModelPart::IndexT } } -template -void ModelPart::AddEntitiesFromIds( - ModelPart* pModelPart, - const std::vector& rEntityIds) -{ - KRATOS_TRY - - if(pModelPart->IsSubModelPart()) { //does nothing if we are on the top model part - //obtain from the root model part the corresponding list of nodes - ModelPart* root_model_part = &pModelPart->GetRootModelPart(); - - std::vector aux; - aux.resize(rEntityIds.size()); - - const auto& r_container = ModelPart::Container::GetContainer(root_model_part->GetMesh()); - - IndexPartition(rEntityIds.size()).for_each([&r_container, &rEntityIds, &aux, pModelPart](const auto Index) { - auto it = r_container.find(rEntityIds[Index]); - - KRATOS_ERROR_IF(it == r_container.end()) - << "while adding " << ModelPart::Container::GetEntityName() << "s to submodelpart " - << pModelPart->FullName() << ", the " - << ModelPart::Container::GetEntityName() - << " with Id " << rEntityIds[Index] << " does not exist in the root model part"; - - aux[Index] = *(it.base()); - }); - - ModelPart* current_part = pModelPart; - while(current_part->IsSubModelPart()) { - ModelPart::Container::GetContainer(current_part->GetMesh()).insert(aux.begin(), aux.end()); - current_part = &(current_part->GetParentModelPart()); - } - } - - KRATOS_CATCH(""); -} - /** Inserts a list of nodes in a submodelpart provided their Id. Does nothing if applied to the top model part */ void ModelPart::AddNodes(std::vector const& rNodeIds, IndexType ThisIndex) { - AddEntitiesFromIds(this, rNodeIds); + ModelPartHelperUtilities::AddEntitiesFromIds([](ModelPart* pModelPart) { return &pModelPart->Nodes(); }, this, rNodeIds); } /** Inserts a node in the mesh with ThisIndex. @@ -960,7 +976,7 @@ void ModelPart::AddElement(ModelPart::ElementType::Pointer pNewElement, ModelPar */ void ModelPart::AddElements(std::vector const& ElementIds, IndexType ThisIndex) { - AddEntitiesFromIds(this, ElementIds); + ModelPartHelperUtilities::AddEntitiesFromIds([](ModelPart* pModelPart) { return &pModelPart->Elements(); }, this, ElementIds); } /** Inserts an element in the mesh with ThisIndex. @@ -1170,7 +1186,7 @@ void ModelPart::AddMasterSlaveConstraint(ModelPart::MasterSlaveConstraintType::P */ void ModelPart::AddMasterSlaveConstraints(std::vector const& MasterSlaveConstraintIds, IndexType ThisIndex) { - AddEntitiesFromIds(this, MasterSlaveConstraintIds); + ModelPartHelperUtilities::AddEntitiesFromIds([](ModelPart* pModelPart) { return &pModelPart->MasterSlaveConstraints(); }, this, MasterSlaveConstraintIds); } /// @brief Construct a new @ref MasterSlaveConstraint and insert it into the specified @ref Mesh. @@ -1402,7 +1418,7 @@ void ModelPart::AddCondition(ModelPart::ConditionType::Pointer pNewCondition, Mo */ void ModelPart::AddConditions(std::vector const& ConditionIds, IndexType ThisIndex) { - AddEntitiesFromIds(this, ConditionIds); + ModelPartHelperUtilities::AddEntitiesFromIds([](ModelPart* pModelPart) { return &pModelPart->Conditions(); }, this, ConditionIds); } /** Inserts a condition in the mesh with ThisIndex. @@ -1889,26 +1905,7 @@ void ModelPart::AddGeometry( */ void ModelPart::AddGeometries(std::vector const& GeometriesIds) { - if(IsSubModelPart()) { // Does nothing if we are on the top model part - // Obtain from the root model part the corresponding list of geometries - ModelPart* p_root_model_part = &this->GetRootModelPart(); - std::vector aux; - aux.reserve(GeometriesIds.size()); - for(auto& r_id : GeometriesIds) { - auto it_found = p_root_model_part->Geometries().find(r_id); - if(it_found != p_root_model_part->GeometriesEnd()) { - aux.push_back(*(it_found.base())); - } else { - KRATOS_ERROR << "The geometry with Id " << r_id << " does not exist in the root model part" << std::endl; - } - } - - ModelPart* p_current_part = this; - while(p_current_part->IsSubModelPart()) { - p_current_part->Geometries().insert(aux.begin(), aux.end()); - p_current_part = &(p_current_part->GetParentModelPart()); - } - } + ModelPartHelperUtilities::AddEntitiesFromIds([](ModelPart* pModelPart) { return &pModelPart->Geometries(); }, this, GeometriesIds); } /// Removes a geometry by id. From d7d47347d4d7f84d82e73ad7a4d0a9db758bb7ee Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 16 Dec 2024 09:27:39 +0100 Subject: [PATCH 18/33] fix parmmg --- .../custom_utilities/parmmg/pmmg_utilities.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/applications/MeshingApplication/custom_utilities/parmmg/pmmg_utilities.cpp b/applications/MeshingApplication/custom_utilities/parmmg/pmmg_utilities.cpp index 0a4022e0f9c1..b431c8e04dc7 100644 --- a/applications/MeshingApplication/custom_utilities/parmmg/pmmg_utilities.cpp +++ b/applications/MeshingApplication/custom_utilities/parmmg/pmmg_utilities.cpp @@ -1184,9 +1184,9 @@ void ParMmgUtilities::WriteMeshDataToModelPart( std::unordered_map color_nodes, first_color_cond, second_color_cond, first_color_elem, second_color_elem; // The tempotal store of - ConditionsArrayType created_conditions_vector; - ElementsArrayType created_elements_vector; - NodesArrayType created_nodes_vector; + std::vector created_conditions_vector; + std::vector created_elements_vector; + std::vector created_nodes_vector; // Auxiliar values int ref, is_required; From d718a9ae7ec78854dc4b2c016d85a22428d8e457 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 16 Dec 2024 14:47:06 +0100 Subject: [PATCH 19/33] add benchmarks for modelpart --- kratos/benchmarks/model_part_benchmark.cpp | 271 +++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 kratos/benchmarks/model_part_benchmark.cpp diff --git a/kratos/benchmarks/model_part_benchmark.cpp b/kratos/benchmarks/model_part_benchmark.cpp new file mode 100644 index 000000000000..4f7ca7f0e4f6 --- /dev/null +++ b/kratos/benchmarks/model_part_benchmark.cpp @@ -0,0 +1,271 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main authors: Suneth Warnakulasuriya +// + +// System includes +#include + +// External includes +#include + +// Project includes +#include "containers/model.h" +#include "containers/pointer_vector_set.h" +#include "includes/indexed_object.h" +#include "includes/key_hash.h" +#include "includes/model_part.h" +#include "includes/smart_pointers.h" +#include "utilities/assign_unique_model_part_collection_tag_utility.h" + +namespace Kratos { + +static void BM_ModelPartCreateNewNode(benchmark::State& state) { + for (auto _ : state) { + const IndexType input_size = state.range(0); + + state.PauseTiming(); + + auto model = Model(); + auto& r_model_part = model.CreateModelPart("test"); + + state.ResumeTiming(); + + for (IndexType i = 0; i < input_size; ++i) { + r_model_part.CreateNewNode(i + 1, 0.0, 0.0, 0.0); + } + } +} + + +static void BM_ModelPartAddNodesToRootFromRange1(benchmark::State& state) { + for (auto _ : state) { + const IndexType input_size = state.range(0); + const bool fill_existing = state.range(1) == 1; + + state.PauseTiming(); + + auto model = Model(); + auto& r_model_part = model.CreateModelPart("test"); + + std::vector nodes_to_be_added, existing_nodes; + if (!fill_existing) { + nodes_to_be_added.reserve(input_size); + } else { + nodes_to_be_added.reserve(input_size / 2 + 1); + existing_nodes.reserve(input_size / 2 + 1); + } + + // doing it in reverse to make sure a proper sort is done always + for (IndexType i = input_size; i > 0; --i) { + auto p_node = Kratos::make_intrusive(i, 0.0, 0.0, 0.0); + if (!fill_existing || i % 2 == 0) { + nodes_to_be_added.push_back(p_node); + } else { + existing_nodes.push_back(p_node); + } + } + r_model_part.AddNodes(existing_nodes.begin(), existing_nodes.end()); + state.ResumeTiming(); + + // benchmarking to add nodes for already existing model part with nodes + r_model_part.AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); + } +} + +static void BM_ModelPartAddNodesToRootFromRange2(benchmark::State& state) { + for (auto _ : state) { + const IndexType input_size = state.range(0); + const bool fill_existing = state.range(1) == 1; + + state.PauseTiming(); + + auto model = Model(); + auto& r_model_part = model.CreateModelPart("test"); + + PointerVectorSet nodes_to_be_added, existing_nodes; + if (!fill_existing) { + nodes_to_be_added.reserve(input_size); + } else { + nodes_to_be_added.reserve(input_size / 2 + 1); + existing_nodes.reserve(input_size / 2 + 1); + } + + // doing it in reverse to make sure a proper sort is done always + for (IndexType i = 0; i < input_size; ++i) { + auto p_node = Kratos::make_intrusive(i + 1, 0.0, 0.0, 0.0); + if (!fill_existing || i % 2 == 0) { + nodes_to_be_added.insert(nodes_to_be_added.end(), p_node); + } else { + existing_nodes.insert(existing_nodes.end(), p_node); + } + } + r_model_part.AddNodes(existing_nodes.begin(), existing_nodes.end()); + state.ResumeTiming(); + + // benchmarking to add nodes for already existing model part with nodes + r_model_part.AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); + } +} + +static void BM_ModelPartAddNodesToSubSubFromRange1(benchmark::State& state) { + for (auto _ : state) { + const IndexType input_size = state.range(0); + const bool fill_existing = state.range(1) == 1; + + state.PauseTiming(); + + auto model = Model(); + auto& r_sub_sub_model_part = model.CreateModelPart("test").CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); + + std::vector nodes_to_be_added, existing_nodes; + if (!fill_existing) { + nodes_to_be_added.reserve(input_size); + } else { + nodes_to_be_added.reserve(input_size / 2 + 1); + existing_nodes.reserve(input_size / 2 + 1); + } + + // doing it in reverse to make sure a proper sort is done always + for (IndexType i = 0; i < input_size; ++i) { + auto p_node = Kratos::make_intrusive(i + 1, 0.0, 0.0, 0.0); + if (!fill_existing || i % 2 == 0) { + nodes_to_be_added.insert(nodes_to_be_added.end(), p_node); + } else { + existing_nodes.insert(existing_nodes.end(), p_node); + } + } + r_sub_sub_model_part.AddNodes(existing_nodes.begin(), existing_nodes.end()); + state.ResumeTiming(); + + r_sub_sub_model_part.AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); + } +} + +static void BM_ModelPartAddNodesToSubSubFromRange2(benchmark::State& state) { + for (auto _ : state) { + const IndexType input_size = state.range(0); + const bool fill_existing = state.range(1) == 1; + + state.PauseTiming(); + + auto model = Model(); + auto& r_sub_sub_model_part = model.CreateModelPart("test").CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); + + std::vector nodes_to_be_added, existing_nodes; + if (!fill_existing) { + nodes_to_be_added.reserve(input_size); + } else { + nodes_to_be_added.reserve(input_size / 2 + 1); + existing_nodes.reserve(input_size / 2 + 1); + } + + // doing it in reverse to make sure a proper sort is done always + for (IndexType i = 0; i < input_size; ++i) { + auto p_node = Kratos::make_intrusive(i + 1, 0.0, 0.0, 0.0); + if (!fill_existing || i % 2 == 0) { + nodes_to_be_added.insert(nodes_to_be_added.end(), p_node); + } else { + existing_nodes.insert(existing_nodes.end(), p_node); + } + } + r_sub_sub_model_part.GetRootModelPart().AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); + r_sub_sub_model_part.GetRootModelPart().AddNodes(existing_nodes.begin(), existing_nodes.end()); + state.ResumeTiming(); + + r_sub_sub_model_part.AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); + } +} + +static void BM_ModelPartAddNodesToSubSubFromRange3(benchmark::State& state) { + for (auto _ : state) { + const IndexType input_size = state.range(0); + const bool fill_existing = state.range(1) == 1; + + state.PauseTiming(); + + auto model = Model(); + auto& r_sub_sub_model_part = model.CreateModelPart("test").CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); + + std::vector nodes_to_be_added, existing_nodes; + if (!fill_existing) { + nodes_to_be_added.reserve(input_size); + } else { + nodes_to_be_added.reserve(input_size / 2 + 1); + existing_nodes.reserve(input_size / 2 + 1); + } + + // doing it in reverse to make sure a proper sort is done always + for (IndexType i = 0; i < input_size; ++i) { + auto p_node = Kratos::make_intrusive(i + 1, 0.0, 0.0, 0.0); + if (!fill_existing || i % 2 == 0) { + nodes_to_be_added.insert(nodes_to_be_added.end(), p_node); + } else { + existing_nodes.insert(existing_nodes.end(), p_node); + } + } + r_sub_sub_model_part.GetRootModelPart().AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); + r_sub_sub_model_part.GetRootModelPart().AddNodes(existing_nodes.begin(), existing_nodes.end()); + state.ResumeTiming(); + + r_sub_sub_model_part.AddNodes(r_sub_sub_model_part.GetRootModelPart().NodesBegin(), r_sub_sub_model_part.GetRootModelPart().NodesEnd()); + } +} + +static void BM_ModelPartAddNodesToSubSubFromId1(benchmark::State& state) { + for (auto _ : state) { + const IndexType input_size = state.range(0); + const bool fill_existing = state.range(1) == 1; + + state.PauseTiming(); + + auto model = Model(); + auto& r_root_model_part = model.CreateModelPart("test"); + auto& r_sub_sub_model_part = r_root_model_part.CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); + + std::vector nodes; + std::vector node_ids_to_add, existing_node_ids; + if (!fill_existing) { + node_ids_to_add.reserve(input_size); + } else { + node_ids_to_add.reserve(input_size / 2 + 1); + existing_node_ids.reserve(input_size / 2 + 1); + } + + // doing it in reverse to make sure a proper sort is done always + for (IndexType i = input_size; i > 0; --i) { + nodes.push_back(Kratos::make_intrusive(i, 0.0, 0.0, 0.0)); + if (!fill_existing || i % 2 == 0) { + node_ids_to_add.push_back(i); + } else { + existing_node_ids.push_back(i); + } + } + r_root_model_part.AddNodes(nodes.begin(), nodes.end()); + r_sub_sub_model_part.AddNodes(existing_node_ids); + state.ResumeTiming(); + + r_sub_sub_model_part.AddNodes(node_ids_to_add); + } +} + + +// Register the function as a benchmark +BENCHMARK(BM_ModelPartCreateNewNode) -> RangeMultiplier(10) -> Range(1e2, 1e+6); +BENCHMARK(BM_ModelPartAddNodesToRootFromRange1) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); +BENCHMARK(BM_ModelPartAddNodesToRootFromRange2) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); +BENCHMARK(BM_ModelPartAddNodesToSubSubFromRange1) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); +BENCHMARK(BM_ModelPartAddNodesToSubSubFromRange2) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); +BENCHMARK(BM_ModelPartAddNodesToSubSubFromRange3) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); +BENCHMARK(BM_ModelPartAddNodesToSubSubFromId1) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); + +} // namespace Kratos + +BENCHMARK_MAIN(); \ No newline at end of file From 4430f5e7fd8b2cf025b5331e70aafab3db25d8e0 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Mon, 16 Dec 2024 16:46:06 +0100 Subject: [PATCH 20/33] minor for comparison --- kratos/benchmarks/model_part_benchmark.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kratos/benchmarks/model_part_benchmark.cpp b/kratos/benchmarks/model_part_benchmark.cpp index 4f7ca7f0e4f6..7e5531aa0ebc 100644 --- a/kratos/benchmarks/model_part_benchmark.cpp +++ b/kratos/benchmarks/model_part_benchmark.cpp @@ -230,7 +230,7 @@ static void BM_ModelPartAddNodesToSubSubFromId1(benchmark::State& state) { auto& r_root_model_part = model.CreateModelPart("test"); auto& r_sub_sub_model_part = r_root_model_part.CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); - std::vector nodes; + PointerVectorSet nodes; std::vector node_ids_to_add, existing_node_ids; if (!fill_existing) { node_ids_to_add.reserve(input_size); @@ -239,9 +239,12 @@ static void BM_ModelPartAddNodesToSubSubFromId1(benchmark::State& state) { existing_node_ids.reserve(input_size / 2 + 1); } + for (IndexType i = 0; i < input_size; ++i) { + nodes.insert(nodes.end(), Kratos::make_intrusive(i + 1, 0.0, 0.0, 0.0)); + } + // doing it in reverse to make sure a proper sort is done always for (IndexType i = input_size; i > 0; --i) { - nodes.push_back(Kratos::make_intrusive(i, 0.0, 0.0, 0.0)); if (!fill_existing || i % 2 == 0) { node_ids_to_add.push_back(i); } else { From d7e05de55a017b9eb57b894c6bb006e647b35576 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 18 Dec 2024 10:24:08 +0100 Subject: [PATCH 21/33] add type_traits --- kratos/utilities/type_traits.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 kratos/utilities/type_traits.h diff --git a/kratos/utilities/type_traits.h b/kratos/utilities/type_traits.h new file mode 100644 index 000000000000..539dc2b2b3e5 --- /dev/null +++ b/kratos/utilities/type_traits.h @@ -0,0 +1,33 @@ +// | / | +// ' / __| _` | __| _ \ __| +// . \ | ( | | ( |\__ ` +// _|\_\_| \__,_|\__|\___/ ____/ +// Multi-Physics +// +// License: BSD License +// Kratos default license: kratos/license.txt +// +// Main author: Suneth Warnakulasuriya +// + +#pragma once + +#include + +namespace Kratos { + +template +using BaseType = typename std::remove_cv_t>; + +// Primary template that will be used for the fallback +template +struct HasValueType : std::false_type {}; + +// Specialization for types that have a `value_type` member +template +struct HasValueType> : std::true_type {}; + +template +using IsRValueContainer = std::conjunction, HasValueType>; + +} // namespace Kratos \ No newline at end of file From fedc6b380848c07cc645dfd96a3335802c42c692 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 18 Dec 2024 10:24:23 +0100 Subject: [PATCH 22/33] allow rvalue containers in pvs insert --- kratos/containers/pointer_vector_set.h | 53 ++++++++++++++++++-------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/kratos/containers/pointer_vector_set.h b/kratos/containers/pointer_vector_set.h index 9732c0bc7bcc..dec97688d855 100644 --- a/kratos/containers/pointer_vector_set.h +++ b/kratos/containers/pointer_vector_set.h @@ -29,6 +29,7 @@ #include "includes/define.h" #include "includes/serializer.h" #include "containers/key_generator.h" +#include "utilities/type_traits.h" namespace Kratos { @@ -648,23 +649,45 @@ class PointerVectorSet final template void insert(InputIterator first, InputIterator last) { - if constexpr(std::is_assignable_v()), decltype(*std::declval())>) { - // first sorts the input iterators and make the input unique if the iterators are assignable - std::sort(first, last, CompareKey()); - auto new_last = std::unique(first, last, EqualKeyTo()); - SortedInsert(first, new_last); + // We copy always the input range to a temp not to have the input range mutated. + std::vector temp; + temp.reserve(std::distance(first, last)); + for (auto it = first; it != last; ++it) { + temp.push_back(GetPointer(it)); + } + std::sort(temp.begin(), temp.end(), CompareKey()); + auto new_last = std::unique(temp.begin(), temp.end(), EqualKeyTo()); + SortedInsert(temp.begin(), new_last); + + // KRATOS_ERROR << "HELLO THERE"; + } + + + /** + * @brief Inserts elements from a r_value container. + * @details This method is used to insert all values from an r valued container. + * This mutates the r valued input container to be sorted and unique if it is not the type of PointerVectorSet. + * If it is the type of the PointerVectorSet, then it doesn't mutate the input container. + * + * @warning The move assumes the ownership of the container, hence the the rContainer may be mutated. if the TContainer is of type std::shared_ptr or intrusive_ptr + * then, there will always be a null pointer at the end past position of the unique sorted list since the std::unique uses the move assignment operator + * within its algorithm. Therefore, the new_last created here will have the correct pointer to the object, and the rContainer will have a nullptr in the + * corresponding place. Therefore, if this method is called once, and if it used with a container type which is not PointerVectorSet, please do not use + * the input rContainer anymore. It will segfault unless the PointerVectorSet is created with raw pointers. [This is because since c++11 std::unique uses the move assignment operator] + * @tparam TContainer + * @param rContainer + */ + template::value, bool> = true> + void insert(TContainer&& rContainer) + { + if constexpr(!std::is_same_v, PointerVectorSet>) { + std::sort(rContainer.begin(), rContainer.end(), CompareKey()); + auto new_last = std::unique(rContainer.begin(), rContainer.end(), EqualKeyTo()); + SortedInsert(rContainer.begin(), new_last); } else { - // the iterators are not assignable, hence they may be coming from a const vector, So, we need to make a copy - // to do the sort and unique. - std::vector temp; - temp.reserve(std::distance(first, last)); - for (auto it = first; it != last; ++it) { - temp.push_back(GetPointer(it)); - } - std::sort(temp.begin(), temp.end(), CompareKey()); - auto new_last = std::unique(temp.begin(), temp.end(), EqualKeyTo()); - SortedInsert(temp.begin(), new_last); + SortedInsert(rContainer.begin(), rContainer.end()); } + } /** From d6422955d913bf5213681006ea0f4a94d17882fc Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 18 Dec 2024 10:24:49 +0100 Subject: [PATCH 23/33] allow rvalue containers in model part --- kratos/includes/model_part.h | 126 ++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 15 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index c6b90f7e4bfd..e22cd4fd794e 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -40,6 +40,7 @@ #include "containers/variable.h" #include "containers/variable_data.h" #include "utilities/parallel_utilities.h" +#include "utilities/type_traits.h" namespace Kratos { @@ -364,14 +365,23 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddNodes(TIteratorType nodes_begin, TIteratorType nodes_end, IndexType ThisIndex = 0) { - EntityRangeChecker checker{this}; - checker.operator()(nodes_begin, nodes_end); + EntityRangeChecker()(this, nodes_begin, nodes_end); InsertEntityRange([](ModelPart* pModelPart) { return &(pModelPart->GetMesh().Nodes()); }, nodes_begin, nodes_end); } + template::value, bool> = true> + void AddNodes(TContainer&& rInputContainer) + { + EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); + + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Nodes()); + }, std::move(rInputContainer)); + } + /** Inserts a node in the current mesh. */ NodeType::Pointer CreateNewNode(int Id, double x, double y, double z, VariablesList::Pointer pNewVariablesList, IndexType ThisIndex = 0); @@ -667,14 +677,23 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddMasterSlaveConstraints(TIteratorType constraints_begin, TIteratorType constraints_end, IndexType ThisIndex = 0) { - EntityRangeChecker checker{this}; - checker.operator()(constraints_begin, constraints_end); + EntityRangeChecker()(this, constraints_begin, constraints_end); InsertEntityRange([](ModelPart* pModelPart) { return &(pModelPart->GetMesh().MasterSlaveConstraints()); }, constraints_begin, constraints_end); } + template::value, bool> = true> + void AddMasterSlaveConstraints(TContainer&& rInputContainer) + { + EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); + + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().MasterSlaveConstraints()); + }, std::move(rInputContainer)); + } + /** * @brief Creates a new master-slave constraint in the current modelpart. * @todo Replace these 3 functions by one that perfectly forwards arguments, then just define these 3 interfaces on the pybind side @@ -981,14 +1000,23 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddElements(TIteratorType elements_begin, TIteratorType elements_end, IndexType ThisIndex = 0) { - EntityRangeChecker checker{this}; - checker.operator()(elements_begin, elements_end); + EntityRangeChecker()(this, elements_begin, elements_end); InsertEntityRange([](ModelPart* pModelPart) { return &(pModelPart->GetMesh().Elements()); }, elements_begin, elements_end); } + template::value, bool> = true> + void AddElements(TContainer&& rInputContainer) + { + EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); + + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Elements()); + }, std::move(rInputContainer)); + } + /// Creates new element with a node ids list. ElementType::Pointer CreateNewElement(std::string ElementName, IndexType Id, std::vector ElementNodeIds, @@ -1138,14 +1166,23 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template void AddConditions(TIteratorType conditions_begin, TIteratorType conditions_end, IndexType ThisIndex = 0) { - EntityRangeChecker checker{this}; - checker.operator()(conditions_begin, conditions_end); + EntityRangeChecker()(this, conditions_begin, conditions_end); InsertEntityRange([](ModelPart* pModelPart) { return &(pModelPart->GetMesh().Conditions()); }, conditions_begin, conditions_end); } + template::value, bool> = true> + void AddConditions(TContainer&& rInputContainer) + { + EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); + + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Conditions()); + }, std::move(rInputContainer)); + } + /// Creates new condition with a node ids list. ConditionType::Pointer CreateNewCondition(std::string ConditionName, IndexType Id, std::vector ConditionNodeIds, @@ -1420,6 +1457,37 @@ class KRATOS_API(KRATOS_CORE) ModelPart final KRATOS_CATCH("") } + + /// Inserts a list of geometries to a submodelpart provided their iterators + template::value, bool> = true> + void AddGeometries(TContainer&& rInputContainer) + { + KRATOS_TRY + + ModelPart* p_root_model_part = &this->GetRootModelPart(); + + block_for_each(rInputContainer.begin(), rInputContainer.end(), [p_root_model_part](const auto& prGeometry) { + const auto& r_geometry = ReferenceGetter::Get(prGeometry); + const auto& r_geometries = p_root_model_part->Geometries(); + auto it_found = r_geometries.find(r_geometry.Id()); + if (it_found != p_root_model_part->GeometriesEnd()) { + if (GeometryType::HasSameGeometryType(r_geometry, *it_found)) { // Check the geometry type and connectivities + for (IndexType i_pt = 0; i_pt < r_geometry.PointsNumber(); ++i_pt) { + KRATOS_ERROR_IF((r_geometry)[i_pt].Id() != (*it_found)[i_pt].Id()) << "Attempting to add a new geometry with Id: " << r_geometry.Id() << ". A same type geometry with same Id but different connectivities already exists." << std::endl; + } + } else if(&(*it_found) != &r_geometry) { // Check if the pointee coincides + KRATOS_ERROR << "Attempting to add a new geometry with Id: " << it_found->Id() << ". A different geometry with the same Id already exists." << std::endl; + } + } + }); + + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->Geometries()); + }, std::move(rInputContainer)); + + KRATOS_CATCH("") + } + /// Returns the Geometry::Pointer corresponding to the Id typename GeometryType::Pointer pGetGeometry(IndexType GeometryId) { return mGeometries.pGetGeometry(GeometryId); @@ -1878,14 +1946,11 @@ class KRATOS_API(KRATOS_CORE) ModelPart final */ template struct EntityRangeChecker{ - - ModelPart* mpModelPart; - template - void operator()(TIterator begin, TIterator end) { + void operator()(ModelPart* pModelPart, TIterator begin, TIterator end) { KRATOS_TRY - ModelPart* p_root_model_part = &mpModelPart->GetRootModelPart(); + ModelPart* p_root_model_part = &pModelPart->GetRootModelPart(); block_for_each(begin, end, [&](const auto& prEntity) { const auto& r_entity = ReferenceGetter::Get(prEntity); @@ -1896,7 +1961,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final << r_entity.Id() << " to root model part " << p_root_model_part->FullName() << ", unfortunately a (different) " << Container::GetEntityName() << " with the same Id already exists. [ Occurred while adding " << Container::GetEntityName() - << " to " << mpModelPart->FullName() << " ]." + << " to " << pModelPart->FullName() << " ]." << std::endl; }); KRATOS_CATCH(""); @@ -1959,7 +2024,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final */ template void InsertEntityRange( - TContainerGetter&& rContainerGetter, + const TContainerGetter& rContainerGetter, TIterator begin, TIterator end) { @@ -1999,6 +2064,37 @@ class KRATOS_API(KRATOS_CORE) ModelPart final KRATOS_CATCH("") } + template::value, bool> = true> + void InsertEntityRValuedContainer( + const TContainerGetter& rContainerGetter, + TInputContainer&& rInputContainer) + { + KRATOS_TRY + + using container_type = std::remove_pointer_t()(std::declval()))>; + + ModelPart* p_current_part = this; + + if constexpr(!std::is_same_v, container_type>) { + // this represents the case 1. + container_type aux; + aux.insert(std::move(rInputContainer)); + + // we add to all the parents and the current model part + while (p_current_part->IsSubModelPart()) { + rContainerGetter(p_current_part)->insert(aux.begin(), aux.end()); + p_current_part = &(p_current_part->GetParentModelPart()); + } + + // now we add to the root model part + rContainerGetter(p_current_part)->insert(aux.begin(), aux.end()); + } else { + InsertEntityRange(rContainerGetter, rInputContainer.begin(), rInputContainer.end()); + } + + KRATOS_CATCH("") + } + /** * @brief This method trims a string in the different components to access recursively to any subproperty * @param rStringName The given name to be trimmed From ee29e90ebc3151c698bdd7789117826a986828df Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 18 Dec 2024 10:25:03 +0100 Subject: [PATCH 24/33] tests for rvalue containers in PVS --- .../containers/test_pointer_vector_set.cpp | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp b/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp index 74ce8ffc56eb..04151c959679 100644 --- a/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp +++ b/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp @@ -150,6 +150,18 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert4, KratosCoreFastSuite) tmp.push_back(p_element_3_copy); test_container.insert(tmp.begin(), tmp.end()); + // check whether the original tmp is not touched. + auto temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_6); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3_copy); + KRATOS_EXPECT_EQ(test_container.size(), 6); auto itr = test_container.begin(); @@ -181,6 +193,13 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert5, KratosCoreFastSuite) tmp.push_back(p_element_8); test_container.insert(tmp.begin(), tmp.end()); + // check whether the original tmp is not touched. + auto temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_8); + KRATOS_EXPECT_EQ(test_container.size(), 4); auto itr = test_container.begin(); for (; itr != test_container.end() - 1; ++itr) { @@ -198,6 +217,16 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert5, KratosCoreFastSuite) tmp.push_back(p_element_6); test_container.insert(tmp.begin(), tmp.end()); + // check whether the original tmp is not touched. + temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3_ptr_copy); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_7); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_6); + KRATOS_EXPECT_EQ(test_container.size(), 8); itr = test_container.begin(); for (; itr != test_container.end() - 1; ++itr) { @@ -225,6 +254,13 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert6, KratosCoreFastSuite) tmp.push_back(p_element_8); test_container.insert(tmp.begin(), tmp.end()); + // check whether the original tmp is not touched. + auto temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_8); + KRATOS_EXPECT_EQ(test_container.size(), 4); auto itr = test_container.begin(); KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); @@ -243,6 +279,16 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert6, KratosCoreFastSuite) tmp.push_back(p_element_6); test_container.insert(tmp.begin(), tmp.end()); + // check whether the original tmp is not touched. + temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3_copy); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_7); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_6); + KRATOS_EXPECT_EQ(test_container.size(), 8); itr = test_container.begin(); KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); @@ -275,6 +321,14 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert7, KratosCoreFastSuite) tmp.push_back(p_element_8); test_container_1.insert(tmp.begin(), tmp.end()); + + // check whether the original tmp is not touched. + auto temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_2); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_8); + KRATOS_EXPECT_EQ(test_container_1.size(), 4); auto itr = test_container_1.begin(); KRATOS_EXPECT_EQ(&*(itr++), &*p_element_1); @@ -301,6 +355,16 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert7, KratosCoreFastSuite) tmp.push_back(p_element_6); test_container_3.insert(tmp.begin(), tmp.end()); + // check whether the original tmp is not touched. + temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3_copy); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_7); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_6); + test_container_2.insert(test_container_3); KRATOS_EXPECT_EQ(test_container_2.size(), 8); itr = test_container_2.begin(); @@ -331,6 +395,13 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert8, KratosCoreFastSuite) tmp.push_back(elements[28]); test_container_1.insert(tmp.begin(), tmp.end()); + // check whether the original tmp is not touched. + auto temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[2]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[1]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[25]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[28]); + KRATOS_EXPECT_EQ(test_container_1.size(), 4); auto itr = test_container_1.begin(); KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); @@ -357,6 +428,16 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert8, KratosCoreFastSuite) tmp.push_back(elements[6]); test_container_3.insert(tmp.begin(), tmp.end()); + temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[3]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[4]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[5]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[3]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4_copy); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_10_copy); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[7]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[6]); + test_container_2.insert(test_container_3); KRATOS_EXPECT_EQ(test_container_2.size(), 10); itr = test_container_2.begin(); @@ -377,6 +458,11 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert8, KratosCoreFastSuite) tmp.push_back(elements[48]); test_container_2.insert(tmp.begin(), tmp.end()); + temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[39]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[29]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[48]); + KRATOS_EXPECT_EQ(test_container_2.size(), 13); itr = test_container_2.begin(); KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); @@ -399,6 +485,11 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert8, KratosCoreFastSuite) tmp.push_back(elements[45]); test_container_2.insert(tmp.begin(), tmp.end()); + temp_itr = tmp.begin(); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[28]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[31]); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*elements[45]); + KRATOS_EXPECT_EQ(test_container_2.size(), 15); itr = test_container_2.begin(); KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); @@ -443,6 +534,51 @@ KRATOS_TEST_CASE_IN_SUITE(TestPointerVectorSetInsert9, KratosCoreFastSuite) KRATOS_EXPECT_EQ(&*(itr++), &*elements[28]); } +KRATOS_TEST_CASE_IN_SUITE(TestPointerVectorSetInsert10, KratosCoreFastSuite) +{ + PointerVectorSet, std::equal_to, std::shared_ptr> test_container; + + std::vector> elements; + for (IndexType i = 0; i < 50; ++i) { + elements.push_back(Kratos::make_shared(i + 1)); + } + + std::vector> tmp; + tmp.push_back(elements[5]); + tmp.push_back(elements[28]); + tmp.push_back(elements[2]); + tmp.push_back(elements[5]); + tmp.push_back(elements[28]); + tmp.push_back(elements[1]); + tmp.push_back(elements[25]); + + // following will change the original tmp + test_container.insert(std::move(tmp)); + + // now we check for the order + auto itr_temp = tmp.begin(); + KRATOS_EXPECT_EQ(tmp.size(), 7); + KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 2); + KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 3); + KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 6); + KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 26); + KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 29); + + // we cannot check for the following because it will always pointing to the nullptr + // KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 6); + // but this we can check for the following + KRATOS_EXPECT_EQ((*(itr_temp++)), nullptr); + KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 29); + + KRATOS_EXPECT_EQ(test_container.size(), 5); + auto itr = test_container.begin(); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[2]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[5]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[25]); + KRATOS_EXPECT_EQ(&*(itr++), &*elements[28]); +} + KRATOS_TEST_CASE_IN_SUITE(TestPointerVectorSet, KratosCoreFastSuite) { // create model and model part From 71e30740e2dfd43601babfd1e3903270bf053ec8 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 18 Dec 2024 10:49:11 +0100 Subject: [PATCH 25/33] more performance improvements --- kratos/sources/model_part.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/kratos/sources/model_part.cpp b/kratos/sources/model_part.cpp index 537f2d87f98a..9ea3d91daf51 100644 --- a/kratos/sources/model_part.cpp +++ b/kratos/sources/model_part.cpp @@ -45,34 +45,32 @@ void AddEntitiesFromIds( if(pModelPart->IsSubModelPart()) { //does nothing if we are on the top model part //obtain from the root model part the corresponding list of nodes ModelPart* root_model_part = &pModelPart->GetRootModelPart(); + const auto& r_container = *rContainerGetter(root_model_part); // we first sort and unique the given entity ids. - std::vector unique_sorted_ids; - unique_sorted_ids.resize(rEntityIds.size()); - IndexPartition(rEntityIds.size()).for_each([&unique_sorted_ids, &rEntityIds](const auto Index) { - unique_sorted_ids[Index] = rEntityIds[Index]; - }); - std::sort(unique_sorted_ids.begin(), unique_sorted_ids.end()); - auto new_last = std::unique(unique_sorted_ids.begin(), unique_sorted_ids.end()); + std::vector entities; + entities.resize(rEntityIds.size()); - const auto& r_container = *rContainerGetter(root_model_part); + // we are doing this in parallel because the most complex one is the finding of the entity for given id. + IndexPartition(rEntityIds.size()).for_each([pModelPart, &r_container, &entities, &rEntityIds](const auto Index) { + const auto entity_id = rEntityIds[Index]; - // aux is created to avoid doing sort and unique for all the parent model parts and current model part - // when insertion is done. - container_type aux; - aux.reserve(std::distance(unique_sorted_ids.begin(), new_last)); - for (auto it_id = unique_sorted_ids.begin(); it_id != new_last; ++it_id) { - auto it = r_container.find(*it_id); + auto it = r_container.find(entity_id); KRATOS_ERROR_IF(it == r_container.end()) << "while adding " << ModelPart::Container::GetEntityName() << "s to submodelpart " << pModelPart->FullName() << ", the " << ModelPart::Container::GetEntityName() - << " with Id " << *it_id << " does not exist in the root model part"; + << " with Id " << entity_id << " does not exist in the root model part"; - // here the hint is valid, hence this will be a simple push_back within the PVS. - aux.insert(aux.end(), *(it.base())); - } + entities[Index] = *(it.base()); + }); + + // aux is created to avoid doing sort and unique for all the parent model parts and current model part + // when insertion is done. since we dont use the entities anymore we can use the move operator here. + // since aux is an empty container. it will call push_back in the insert. + container_type aux; + aux.insert(std::move(entities)); ModelPart* current_part = pModelPart; while(current_part->IsSubModelPart()) { From 102415604b5c82cd01a9b14d3fe3d7ac17c98035 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 18 Dec 2024 10:49:17 +0100 Subject: [PATCH 26/33] fix tests --- kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp b/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp index 04151c959679..e297fbbc246c 100644 --- a/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp +++ b/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp @@ -222,6 +222,7 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert5, KratosCoreFastSuite) KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3_ptr_copy); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_7); @@ -284,6 +285,7 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert6, KratosCoreFastSuite) KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3_copy); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_7); @@ -360,6 +362,7 @@ KRATOS_TEST_CASE_IN_SUITE(PointerVectorSetInsert7, KratosCoreFastSuite) KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_4); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_5); + KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_3_copy); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_1); KRATOS_EXPECT_EQ(&**(temp_itr++), &*p_element_7); From a9e8219943f62cef8884581b1380fbcf72508e54 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 18 Dec 2024 10:52:17 +0100 Subject: [PATCH 27/33] minor --- kratos/utilities/type_traits.h | 1 + 1 file changed, 1 insertion(+) diff --git a/kratos/utilities/type_traits.h b/kratos/utilities/type_traits.h index 539dc2b2b3e5..d4485a966cf7 100644 --- a/kratos/utilities/type_traits.h +++ b/kratos/utilities/type_traits.h @@ -16,6 +16,7 @@ namespace Kratos { +// TODO: Remove the following when we move to C++20 or higher template using BaseType = typename std::remove_cv_t>; From abfdcab962ccaafc8cc2cbce75aab35673390ae7 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Wed, 18 Dec 2024 12:04:42 +0100 Subject: [PATCH 28/33] bug fix --- kratos/includes/model_part.h | 110 ++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 33 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index e22cd4fd794e..b7363d42021f 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -18,11 +18,13 @@ #include #include #include +#include // External includes // Project includes #include "includes/define.h" +#include "includes/key_hash.h" #include "includes/serializer.h" #include "includes/process_info.h" #include "containers/data_value_container.h" @@ -375,11 +377,19 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template::value, bool> = true> void AddNodes(TContainer&& rInputContainer) { - EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); + // This check is required in cases where std::vector is passed as an r value, then it will + // not call the correct addition with the input args of const std::vector&, it will get in to this method. + // this check will redirect it to the std::vector method with the rContainer. + if constexpr(!std::is_same_v, std::vector>) { + EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { - return &(pModelPart->GetMesh().Nodes()); - }, std::move(rInputContainer)); + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Nodes()); + }, std::move(rInputContainer)); + } else { + // call the vector of int insertion. + AddNodes(rInputContainer); + } } /** Inserts a node in the current mesh. @@ -687,11 +697,19 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template::value, bool> = true> void AddMasterSlaveConstraints(TContainer&& rInputContainer) { - EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); + // This check is required in cases where std::vector is passed as an r value, then it will + // not call the correct addition with the input args of const std::vector&, it will get in to this method. + // this check will redirect it to the std::vector method with the rContainer. + if constexpr(!std::is_same_v, std::vector>) { + EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { - return &(pModelPart->GetMesh().MasterSlaveConstraints()); - }, std::move(rInputContainer)); + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().MasterSlaveConstraints()); + }, std::move(rInputContainer)); + } else { + // call the vector of int insertion. + AddMasterSlaveConstraints(rInputContainer); + } } /** @@ -1010,11 +1028,19 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template::value, bool> = true> void AddElements(TContainer&& rInputContainer) { - EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); + // This check is required in cases where std::vector is passed as an r value, then it will + // not call the correct addition with the input args of const std::vector&, it will get in to this method. + // this check will redirect it to the std::vector method with the rContainer. + if constexpr(!std::is_same_v, std::vector>) { + EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { - return &(pModelPart->GetMesh().Elements()); - }, std::move(rInputContainer)); + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Elements()); + }, std::move(rInputContainer)); + } else { + // call the vector of int insertion. + AddElements(rInputContainer); + } } /// Creates new element with a node ids list. @@ -1176,11 +1202,19 @@ class KRATOS_API(KRATOS_CORE) ModelPart final template::value, bool> = true> void AddConditions(TContainer&& rInputContainer) { - EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); + // This check is required in cases where std::vector is passed as an r value, then it will + // not call the correct addition with the input args of const std::vector&, it will get in to this method. + // this check will redirect it to the std::vector method with the rContainer. + if constexpr(!std::is_same_v, std::vector>) { + EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { - return &(pModelPart->GetMesh().Conditions()); - }, std::move(rInputContainer)); + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->GetMesh().Conditions()); + }, std::move(rInputContainer)); + } else { + // call the vector of int insertion. + AddConditions(rInputContainer); + } } /// Creates new condition with a node ids list. @@ -1464,26 +1498,36 @@ class KRATOS_API(KRATOS_CORE) ModelPart final { KRATOS_TRY - ModelPart* p_root_model_part = &this->GetRootModelPart(); - - block_for_each(rInputContainer.begin(), rInputContainer.end(), [p_root_model_part](const auto& prGeometry) { - const auto& r_geometry = ReferenceGetter::Get(prGeometry); - const auto& r_geometries = p_root_model_part->Geometries(); - auto it_found = r_geometries.find(r_geometry.Id()); - if (it_found != p_root_model_part->GeometriesEnd()) { - if (GeometryType::HasSameGeometryType(r_geometry, *it_found)) { // Check the geometry type and connectivities - for (IndexType i_pt = 0; i_pt < r_geometry.PointsNumber(); ++i_pt) { - KRATOS_ERROR_IF((r_geometry)[i_pt].Id() != (*it_found)[i_pt].Id()) << "Attempting to add a new geometry with Id: " << r_geometry.Id() << ". A same type geometry with same Id but different connectivities already exists." << std::endl; + // This check is required in cases where std::vector is passed as an r value, then it will + // not call the correct addition with the input args of const std::vector&, it will get in to this method. + // this check will redirect it to the std::vector method with the rContainer. + if constexpr(!std::is_same_v, std::vector>) { + ModelPart* p_root_model_part = &this->GetRootModelPart(); + + block_for_each(rInputContainer.begin(), rInputContainer.end(), [p_root_model_part](const auto& prGeometry) { + const auto& r_geometry = ReferenceGetter::Get(prGeometry); + const auto& r_geometries = p_root_model_part->Geometries(); + auto it_found = r_geometries.find(r_geometry.Id()); + if (it_found != p_root_model_part->GeometriesEnd()) { + if (GeometryType::HasSameGeometryType(r_geometry, *it_found)) { // Check the geometry type and connectivities + for (IndexType i_pt = 0; i_pt < r_geometry.PointsNumber(); ++i_pt) { + KRATOS_ERROR_IF((r_geometry)[i_pt].Id() != (*it_found)[i_pt].Id()) << "Attempting to add a new geometry with Id: " << r_geometry.Id() << ". A same type geometry with same Id but different connectivities already exists." << std::endl; + } + } else if(&(*it_found) != &r_geometry) { // Check if the pointee coincides + KRATOS_ERROR << "Attempting to add a new geometry with Id: " << it_found->Id() << ". A different geometry with the same Id already exists." << std::endl; } - } else if(&(*it_found) != &r_geometry) { // Check if the pointee coincides - KRATOS_ERROR << "Attempting to add a new geometry with Id: " << it_found->Id() << ". A different geometry with the same Id already exists." << std::endl; } - } - }); + }); + + InsertEntityRValuedContainer([](ModelPart* pModelPart) { + return &(pModelPart->Geometries()); + }, std::move(rInputContainer)); + } else { + // call the vector of int insertion. + AddGeometries(rInputContainer); + } + - InsertEntityRValuedContainer([](ModelPart* pModelPart) { - return &(pModelPart->Geometries()); - }, std::move(rInputContainer)); KRATOS_CATCH("") } From a00437f37dcfa204cce3996c0cbf2a9a17612919 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Thu, 2 Jan 2025 11:43:52 +0100 Subject: [PATCH 29/33] fix sub range addition --- kratos/includes/model_part.h | 39 ++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/kratos/includes/model_part.h b/kratos/includes/model_part.h index b7363d42021f..3c6b92e18f6e 100644 --- a/kratos/includes/model_part.h +++ b/kratos/includes/model_part.h @@ -103,6 +103,8 @@ class KRATOS_API(KRATOS_CORE) ModelPart final ///@name Class definitions ///@{ + /// @brief Templated class to get corresponding container and its information from a mesh. + /// @tparam TContainerType The type of the container to be retrieved. template struct Container {}; @@ -383,7 +385,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final if constexpr(!std::is_same_v, std::vector>) { EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { + InsertEntities([](ModelPart* pModelPart) { return &(pModelPart->GetMesh().Nodes()); }, std::move(rInputContainer)); } else { @@ -703,7 +705,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final if constexpr(!std::is_same_v, std::vector>) { EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { + InsertEntities([](ModelPart* pModelPart) { return &(pModelPart->GetMesh().MasterSlaveConstraints()); }, std::move(rInputContainer)); } else { @@ -1034,7 +1036,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final if constexpr(!std::is_same_v, std::vector>) { EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { + InsertEntities([](ModelPart* pModelPart) { return &(pModelPart->GetMesh().Elements()); }, std::move(rInputContainer)); } else { @@ -1208,7 +1210,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final if constexpr(!std::is_same_v, std::vector>) { EntityRangeChecker()(this, rInputContainer.begin(), rInputContainer.end()); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { + InsertEntities([](ModelPart* pModelPart) { return &(pModelPart->GetMesh().Conditions()); }, std::move(rInputContainer)); } else { @@ -1519,7 +1521,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } }); - InsertEntityRValuedContainer([](ModelPart* pModelPart) { + InsertEntities([](ModelPart* pModelPart) { return &(pModelPart->Geometries()); }, std::move(rInputContainer)); } else { @@ -2012,11 +2014,11 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } }; - template + template static bool IsSubSet( const TContainerType& rContainer, - TIterator begin, - TIterator end) + typename TContainerType::iterator begin, + typename TContainerType::iterator end) { // do nothing if the given range is empty. if (std::distance(begin, end) == 0) { @@ -2024,11 +2026,11 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } // check if the given [begin, end) range is a subset of the given PointerVectorSet. - auto current_pvs_begin_it = rContainer.find(*begin->Id()); - if (current_pvs_begin_it != rContainer.end() && ¤t_pvs_begin_it->base() == &begin->base()) { + auto current_pvs_begin_it = rContainer.find(begin->Id()); + if (current_pvs_begin_it != rContainer.end() && &*(current_pvs_begin_it.base()) == &*(begin.base())) { // memory location pointing to begin is in the rContainer. then check the same for the end. - auto current_pvs_end_it = rContainer.find(*(end - 1)->Id()); - return current_pvs_end_it != rContainer.end() && ¤t_pvs_end_it->base() == &end->base(); + auto current_pvs_end_it = rContainer.find((end - 1)->Id()); + return current_pvs_end_it != rContainer.end() && &*(current_pvs_end_it.base()) == &*((end - 1).base()); } return false; @@ -2074,12 +2076,13 @@ class KRATOS_API(KRATOS_CORE) ModelPart final { KRATOS_TRY + using container_type = std::remove_pointer_t()(std::declval()))>; ModelPart* p_current_part = this; - if constexpr(!std::is_same_v>) { + if constexpr(!std::is_same_v> && + !std::is_same_v>) { // this represents the case 1. - using container_type = std::remove_pointer_t()(std::declval()))>; container_type aux; aux.insert(begin, end); @@ -2094,13 +2097,15 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } else { // this represents the case 2. // now the iterators belong to PVS::iterator, hence no sorting or making them to unique will occur. - while (p_current_part->IsSubModelPart() && !IsSubSet(*rContainerGetter(p_current_part), begin, end)) { + bool is_sub_set = IsSubSet(*rContainerGetter(p_current_part), begin, end); + while (p_current_part->IsSubModelPart() && !is_sub_set) { rContainerGetter(p_current_part)->insert(begin, end); p_current_part = &(p_current_part->GetParentModelPart()); + is_sub_set = IsSubSet(*rContainerGetter(p_current_part), begin, end); } // now we do the same for the root model part - if (!IsSubSet(*rContainerGetter(p_current_part), begin, end)) { + if (!is_sub_set) { rContainerGetter(p_current_part)->insert(begin, end); } } @@ -2109,7 +2114,7 @@ class KRATOS_API(KRATOS_CORE) ModelPart final } template::value, bool> = true> - void InsertEntityRValuedContainer( + void InsertEntities( const TContainerGetter& rContainerGetter, TInputContainer&& rInputContainer) { From 36fd86408b383fd16bf514e921b1c3d4e28f3243 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Thu, 2 Jan 2025 11:44:04 +0100 Subject: [PATCH 30/33] add a test to subrange addition --- .../cpp_tests/sources/test_model_part.cpp | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/kratos/tests/cpp_tests/sources/test_model_part.cpp b/kratos/tests/cpp_tests/sources/test_model_part.cpp index bff6ee5bc618..dc9a69d178e3 100644 --- a/kratos/tests/cpp_tests/sources/test_model_part.cpp +++ b/kratos/tests/cpp_tests/sources/test_model_part.cpp @@ -12,6 +12,9 @@ // Vicente Mataix Ferrandiz // +// System includes +#include + // Project includes #include "containers/model.h" #include "testing/testing.h" @@ -580,4 +583,74 @@ namespace Kratos::Testing { model_part.RemoveSubModelPart("Inlet1.sub_inlet.sub_sub_inlet.test"), "Error: There is no sub model part with name \"sub_sub_inlet\" in model part \"Main.Inlet1.sub_inlet\""); } + + KRATOS_TEST_CASE_IN_SUITE(ModelPartSubRangeAddition, KratosCoreFastSuite) + { + Model model; + auto& r_model_part = model.CreateModelPart("test"); + Properties::Pointer p_elem_prop = r_model_part.CreateNewProperties(0); + + for (IndexType i = 0; i < 16; ++i) { + r_model_part.CreateNewNode(i + 1, 0.0, 0.0, 0.0); + } + + KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); + KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); + + auto& r_sub_model_part_1 = r_model_part.CreateSubModelPart("sub1"); + // following should not do anything hence the capacity should not be changed. + r_sub_model_part_1.AddNodes(r_model_part.Nodes().begin(), r_model_part.Nodes().end()); + KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); + KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().size(), 16); + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), 16); + + auto& r_sub_model_part_2 = r_sub_model_part_1.CreateSubModelPart("sub2"); + // following should not do anything hence the capacity should not be changed. + r_sub_model_part_2.AddNodes(r_model_part.Nodes().begin() + 8, r_model_part.Nodes().end()); + KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); + KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().size(), 16); + // the capacity of the r_sub_model_part_1 has increased because, the r_sub_model_part_2 + // used the iterators of the r_model_part. Then r_sub_model_part_1 is not a subset of r_model_part + // because even though they are pointing to the same memory locations, the intrusive_ptrs memory locations + // are not a subset. + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), 24); + KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().size(), 8); + KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().capacity(), 8); + + // now we add using a sub range to sub2 + auto& r_sub_model_part_3 = r_sub_model_part_1.CreateSubModelPart("sub3"); + // following should not do anything hence the capacity should not be changed. + r_sub_model_part_3.AddNodes(r_model_part.Nodes().begin() + 4, r_model_part.Nodes().end()); + KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); + KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().size(), 16); + + // again here the capacity changes because not r_sub_model_part_1 contains intrusive_ptrs + // which are not a sub set of the r_model_part + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), 28); + KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().size(), 8); + KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().capacity(), 8); + KRATOS_EXPECT_EQ(r_sub_model_part_3.Nodes().size(), 12); + KRATOS_EXPECT_EQ(r_sub_model_part_3.Nodes().capacity(), 12); + + auto& r_sub_model_part_4 = r_sub_model_part_3.CreateSubModelPart("sub4"); + r_sub_model_part_4.AddNodes(r_sub_model_part_3.Nodes().begin() + 4, r_sub_model_part_3.Nodes().end() - 1); + + // now there shouldn't be any change in the size or the capacity, because + // now we added r_sub_model_part_3 items to the r_sub_model_part_4. Then it will add them to the + // r_sub_model_part_4, and when it checks IsSubSet for added nodes with r_sub_model_part_3, then it will + // be a subset, hence all the parent model part additions are ignored. + KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); + KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().size(), 16); + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), 28); + KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().size(), 8); + KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().capacity(), 8); + KRATOS_EXPECT_EQ(r_sub_model_part_3.Nodes().size(), 12); + KRATOS_EXPECT_EQ(r_sub_model_part_3.Nodes().capacity(), 12); + KRATOS_EXPECT_EQ(r_sub_model_part_4.Nodes().size(), 7); + KRATOS_EXPECT_EQ(r_sub_model_part_4.Nodes().capacity(), 7); + } } // namespace Kratos::Testing. From 88a5f51abd667b6772042cf693520466df073203 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya <7856520+sunethwarna@users.noreply.github.com> Date: Thu, 2 Jan 2025 11:53:54 +0100 Subject: [PATCH 31/33] fix test --- .../cpp_tests/containers/test_pointer_vector_set.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp b/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp index e297fbbc246c..76f9c91f7c82 100644 --- a/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp +++ b/kratos/tests/cpp_tests/containers/test_pointer_vector_set.cpp @@ -558,7 +558,8 @@ KRATOS_TEST_CASE_IN_SUITE(TestPointerVectorSetInsert10, KratosCoreFastSuite) // following will change the original tmp test_container.insert(std::move(tmp)); - // now we check for the order + // now we check for the order since above should be changing the temp + // since it was moved. auto itr_temp = tmp.begin(); KRATOS_EXPECT_EQ(tmp.size(), 7); KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 2); @@ -567,12 +568,6 @@ KRATOS_TEST_CASE_IN_SUITE(TestPointerVectorSetInsert10, KratosCoreFastSuite) KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 26); KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 29); - // we cannot check for the following because it will always pointing to the nullptr - // KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 6); - // but this we can check for the following - KRATOS_EXPECT_EQ((*(itr_temp++)), nullptr); - KRATOS_EXPECT_EQ((**(itr_temp++)).Id(), 29); - KRATOS_EXPECT_EQ(test_container.size(), 5); auto itr = test_container.begin(); KRATOS_EXPECT_EQ(&*(itr++), &*elements[1]); From 22ff3e16e059bfa6703f27a438491204046de27c Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 2 Jan 2025 15:43:07 +0100 Subject: [PATCH 32/33] expose shrink_to_fit --- kratos/containers/pointer_vector_set.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kratos/containers/pointer_vector_set.h b/kratos/containers/pointer_vector_set.h index dec97688d855..c3962b970766 100644 --- a/kratos/containers/pointer_vector_set.h +++ b/kratos/containers/pointer_vector_set.h @@ -860,6 +860,11 @@ class PointerVectorSet final return mData.capacity(); } + void shrink_to_fit() + { + mData.shrink_to_fit(); + } + /** * @brief Sort the elements in the set. * @details This function sorts the elements in the set using the CompareKey comparison function. After sorting, From 99aca1d966ceff0ae83752ca3d09836be3872102 Mon Sep 17 00:00:00 2001 From: Suneth Warnakulasuriya Date: Thu, 2 Jan 2025 15:43:13 +0100 Subject: [PATCH 33/33] change test --- .../cpp_tests/sources/test_model_part.cpp | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/kratos/tests/cpp_tests/sources/test_model_part.cpp b/kratos/tests/cpp_tests/sources/test_model_part.cpp index dc9a69d178e3..36f69b996300 100644 --- a/kratos/tests/cpp_tests/sources/test_model_part.cpp +++ b/kratos/tests/cpp_tests/sources/test_model_part.cpp @@ -595,44 +595,48 @@ namespace Kratos::Testing { } KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); + r_model_part.Nodes().shrink_to_fit(); KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); auto& r_sub_model_part_1 = r_model_part.CreateSubModelPart("sub1"); - // following should not do anything hence the capacity should not be changed. + r_sub_model_part_1.AddNodes(r_model_part.Nodes().begin(), r_model_part.Nodes().end()); - KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); + // above should not do anything to the r_model_part, hence capacity should be the same. KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().size(), 16); + r_sub_model_part_1.Nodes().shrink_to_fit(); KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), 16); auto& r_sub_model_part_2 = r_sub_model_part_1.CreateSubModelPart("sub2"); - // following should not do anything hence the capacity should not be changed. r_sub_model_part_2.AddNodes(r_model_part.Nodes().begin() + 8, r_model_part.Nodes().end()); + // above should not do anything to the r_model_part, hence capacity should be the same. KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().size(), 16); - // the capacity of the r_sub_model_part_1 has increased because, the r_sub_model_part_2 + // the capacity of the r_sub_model_part_1 may be changed because, the r_sub_model_part_2 // used the iterators of the r_model_part. Then r_sub_model_part_1 is not a subset of r_model_part // because even though they are pointing to the same memory locations, the intrusive_ptrs memory locations - // are not a subset. - KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), 24); + // are not a subset. Therefore not checking for the capacity. KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().size(), 8); + r_sub_model_part_2.Nodes().shrink_to_fit(); KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().capacity(), 8); // now we add using a sub range to sub2 auto& r_sub_model_part_3 = r_sub_model_part_1.CreateSubModelPart("sub3"); - // following should not do anything hence the capacity should not be changed. r_sub_model_part_3.AddNodes(r_model_part.Nodes().begin() + 4, r_model_part.Nodes().end()); + // above should not do anything to the r_model_part, hence capacity should be the same. KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().size(), 16); // again here the capacity changes because not r_sub_model_part_1 contains intrusive_ptrs // which are not a sub set of the r_model_part - KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), 28); + auto r_sub_model_part_1_capacity = r_sub_model_part_1.Nodes().capacity(); KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().size(), 8); KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().capacity(), 8); KRATOS_EXPECT_EQ(r_sub_model_part_3.Nodes().size(), 12); + r_sub_model_part_3.Nodes().shrink_to_fit(); KRATOS_EXPECT_EQ(r_sub_model_part_3.Nodes().capacity(), 12); auto& r_sub_model_part_4 = r_sub_model_part_3.CreateSubModelPart("sub4"); @@ -645,12 +649,13 @@ namespace Kratos::Testing { KRATOS_EXPECT_EQ(r_model_part.Nodes().size(), 16); KRATOS_EXPECT_EQ(r_model_part.Nodes().capacity(), 16); KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().size(), 16); - KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), 28); + KRATOS_EXPECT_EQ(r_sub_model_part_1.Nodes().capacity(), r_sub_model_part_1_capacity); KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().size(), 8); KRATOS_EXPECT_EQ(r_sub_model_part_2.Nodes().capacity(), 8); KRATOS_EXPECT_EQ(r_sub_model_part_3.Nodes().size(), 12); KRATOS_EXPECT_EQ(r_sub_model_part_3.Nodes().capacity(), 12); KRATOS_EXPECT_EQ(r_sub_model_part_4.Nodes().size(), 7); + r_sub_model_part_4.Nodes().shrink_to_fit(); KRATOS_EXPECT_EQ(r_sub_model_part_4.Nodes().capacity(), 7); } } // namespace Kratos::Testing.