diff --git a/co_sim_io/c/co_sim_io_c.cpp b/co_sim_io/c/co_sim_io_c.cpp index 0bdb4606..ae664a81 100644 --- a/co_sim_io/c/co_sim_io_c.cpp +++ b/co_sim_io/c/co_sim_io_c.cpp @@ -273,6 +273,21 @@ CoSimIO_Node CoSimIO_ModelPart_CreateNewNode( return node; } +void CoSimIO_ModelPart_CreateNewNodes( + CoSimIO_ModelPart I_ModelPart, + const int I_NumberOfNodes, + const int* I_Id, + const double* I_X, + const double* I_Y, + const double* I_Z) +{ + CoSimIO::Internals::DataContainerRawMemoryReadOnly ids(I_Id, I_NumberOfNodes); + CoSimIO::Internals::DataContainerRawMemoryReadOnly x(I_X, I_NumberOfNodes); + CoSimIO::Internals::DataContainerRawMemoryReadOnly y(I_Y, I_NumberOfNodes); + CoSimIO::Internals::DataContainerRawMemoryReadOnly z(I_Z, I_NumberOfNodes); + static_cast(I_ModelPart.PtrCppModelPart)->CreateNewNodes(ids, x, y, z); +} + CoSimIO_Node CoSimIO_ModelPart_CreateNewGhostNode( CoSimIO_ModelPart I_ModelPart, const int I_Id, @@ -287,6 +302,23 @@ CoSimIO_Node CoSimIO_ModelPart_CreateNewGhostNode( return node; } +void CoSimIO_ModelPart_CreateNewGhostNodes( + CoSimIO_ModelPart I_ModelPart, + const int I_NumberOfNodes, + const int* I_Id, + const double* I_X, + const double* I_Y, + const double* I_Z, + const int* PartitionIndex) +{ + CoSimIO::Internals::DataContainerRawMemoryReadOnly ids(I_Id, I_NumberOfNodes); + CoSimIO::Internals::DataContainerRawMemoryReadOnly x(I_X, I_NumberOfNodes); + CoSimIO::Internals::DataContainerRawMemoryReadOnly y(I_Y, I_NumberOfNodes); + CoSimIO::Internals::DataContainerRawMemoryReadOnly z(I_Z, I_NumberOfNodes); + CoSimIO::Internals::DataContainerRawMemoryReadOnly p_idx(PartitionIndex, I_NumberOfNodes); + static_cast(I_ModelPart.PtrCppModelPart)->CreateNewGhostNodes(ids, x, y, z, p_idx); +} + CoSimIO_Element CoSimIO_ModelPart_CreateNewElement( CoSimIO_ModelPart I_ModelPart, const int I_Id, @@ -304,6 +336,21 @@ CoSimIO_Element CoSimIO_ModelPart_CreateNewElement( return elem; } +void CoSimIO_ModelPart_CreateNewElements( + CoSimIO_ModelPart I_ModelPart, + const int I_NumberOfElements, + const int* I_Id, + const CoSimIO_ElementType* I_Type, + const int I_NumberOfConnectivities, + const int* I_Connectivities) +{ + CoSimIO::Internals::DataContainerRawMemoryReadOnly ids(I_Id, I_NumberOfElements); + std::vector types(I_NumberOfElements); + for (int i=0; i(I_Type[i]);} + CoSimIO::Internals::DataContainerRawMemoryReadOnly connectivities(I_Connectivities, I_NumberOfConnectivities); + static_cast(I_ModelPart.PtrCppModelPart)->CreateNewElements(ids, types, connectivities); +} + int CoSimIO_Node_Id(CoSimIO_Node I_Node) { diff --git a/co_sim_io/c/co_sim_io_c_model_part.h b/co_sim_io/c/co_sim_io_c_model_part.h index 85e884b4..d4b2d2f7 100644 --- a/co_sim_io/c/co_sim_io_c_model_part.h +++ b/co_sim_io/c/co_sim_io_c_model_part.h @@ -99,6 +99,14 @@ CoSimIO_Node CoSimIO_ModelPart_CreateNewNode( const double I_Y, const double I_Z); +void CoSimIO_ModelPart_CreateNewNodes( + CoSimIO_ModelPart I_ModelPart, + const int I_NumberOfNodes, + const int* I_Id, + const double* I_X, + const double* I_Y, + const double* I_Z); + CoSimIO_Node CoSimIO_ModelPart_CreateNewGhostNode( CoSimIO_ModelPart I_ModelPart, const int I_Id, @@ -107,11 +115,28 @@ CoSimIO_Node CoSimIO_ModelPart_CreateNewGhostNode( const double I_Z, const int PartitionIndex); +void CoSimIO_ModelPart_CreateNewGhostNodes( + CoSimIO_ModelPart I_ModelPart, + const int I_NumberOfNodes, + const int* I_Id, + const double* I_X, + const double* I_Y, + const double* I_Z, + const int* PartitionIndex); + CoSimIO_Element CoSimIO_ModelPart_CreateNewElement( CoSimIO_ModelPart I_ModelPart, const int I_Id, const CoSimIO_ElementType I_Type, const int* I_Connectivities); +void CoSimIO_ModelPart_CreateNewElements( + CoSimIO_ModelPart I_ModelPart, + const int I_NumberOfElements, + const int* I_Id, + const CoSimIO_ElementType* I_Type, + const int I_NumberOfConnectivities, + const int* I_Connectivities); + #endif /* CO_SIM_IO_C_MODEL_PART_INCLUDED */ diff --git a/co_sim_io/includes/model_part.hpp b/co_sim_io/includes/model_part.hpp index 8c379090..557462c6 100644 --- a/co_sim_io/includes/model_part.hpp +++ b/co_sim_io/includes/model_part.hpp @@ -29,7 +29,9 @@ see https://github.com/KratosMultiphysics/Kratos/blob/master/kratos/includes/mod // Project includes #include "define.hpp" +#include "data_container.hpp" #include "serializer.hpp" +#include "includes/utilities.hpp" namespace CoSimIO { @@ -76,6 +78,100 @@ class PointerVector const ContainerType& mPointerVector; }; + +template +class IndexedVector +{ +public: + + using ContainerType = std::vector; + using iterator = typename ContainerType::iterator; + using const_iterator = typename ContainerType::const_iterator; + + IndexedVector() = default; + + iterator begin() {return mData.begin();} + iterator end() {return mData.end();} + + const_iterator begin() const {return mData.begin();} + const_iterator end() const {return mData.end();} + + std::size_t size() const {return mData.size();} + + void reserve(std::size_t NewCapacity) + { + mData.reserve(NewCapacity); + mAccessMap.reserve(NewCapacity); + } + + const ContainerType& data() const {return mData;} + + bool contains(CoSimIO::IdType Id) const {return mAccessMap.count(Id) > 0;} + + iterator find(CoSimIO::IdType Id) + { + const auto it_index = mAccessMap.find(Id); + if (it_index == mAccessMap.end()) { + return mData.end(); + } else { + return mData.begin()+it_index->second; + } + } + + const_iterator find(CoSimIO::IdType Id) const + { + const auto it_index = mAccessMap.find(Id); + if (it_index == mAccessMap.end()) { + return mData.end(); + } else { + return mData.begin()+it_index->second; + } + } + + void clear() + { + mData.clear(); + mAccessMap.clear(); + } + + void shrink_to_fit() + { + mData.shrink_to_fit(); + } + + void push_back(const TDataType& rData, CoSimIO::IdType Id) + { + mData.push_back(rData); + mAccessMap[Id] = mData.size()-1; + } + +private: + ContainerType mData; + std::unordered_map mAccessMap; + + void ComputeAccessMap() + { + mAccessMap.clear(); + mAccessMap.reserve(mData.size()); + for (std::size_t i=0; iId()] = i; + } + } + + friend class Serializer; + + void save(CoSimIO::Internals::Serializer& rSerializer) const + { + rSerializer.save("mData", mData); + } + + void load(CoSimIO::Internals::Serializer& rSerializer) + { + rSerializer.load("mData", mData); + ComputeAccessMap(); + } +}; + } //namespace Internals class CO_SIM_IO_API Node @@ -220,8 +316,8 @@ class CO_SIM_IO_API ModelPart using NodePointerType = CoSimIO::intrusive_ptr; using ElementPointerType = CoSimIO::intrusive_ptr; - using NodesContainerType = std::vector; - using ElementsContainerType = std::vector; + using NodesContainerType = Internals::IndexedVector; + using ElementsContainerType = Internals::IndexedVector; using PartitionModelPartsContainerType = std::unordered_map>; @@ -239,12 +335,22 @@ class CO_SIM_IO_API ModelPart std::size_t NumberOfElements() const { return mElements.size(); } + // node creation interface Node& CreateNewNode( const IdType I_Id, const double I_X, const double I_Y, const double I_Z); + template + void CreateNewNodes( + const TIdContainerType& I_Id, + const TCoordsContainerType& I_X, + const TCoordsContainerType& I_Y, + const TCoordsContainerType& I_Z); + + // ghost node creation interface Node& CreateNewGhostNode( const IdType I_Id, const double I_X, @@ -252,16 +358,35 @@ class CO_SIM_IO_API ModelPart const double I_Z, const int PartitionIndex); + template + void CreateNewGhostNodes( + const TIdContainerType& I_Id, + const TCoordsContainerType& I_X, + const TCoordsContainerType& I_Y, + const TCoordsContainerType& I_Z, + const TPartitionIndexContainerType& PartitionIndex); + + // element creation interface Element& CreateNewElement( const IdType I_Id, const ElementType I_Type, const ConnectivitiesType& I_Connectivities); - const Internals::PointerVector Nodes() const {return Internals::PointerVector(mNodes);} + template + void CreateNewElements( + const TIdContainerType& I_Id, + const TTypeContainerType& I_Type, + const TConnectivitiesContainerType& I_Connectivities); + + const Internals::PointerVector Nodes() const {return Internals::PointerVector(mNodes.data());} const Internals::PointerVector LocalNodes() const {return Internals::PointerVector(GetLocalModelPart().Nodes());} const Internals::PointerVector GhostNodes() const {return Internals::PointerVector(GetGhostModelPart().Nodes());} - const Internals::PointerVector Elements() const {return Internals::PointerVector(mElements);} + const Internals::PointerVector Elements() const {return Internals::PointerVector(mElements.data());} const ModelPart& GetLocalModelPart() const; const ModelPart& GetGhostModelPart() const; @@ -342,6 +467,106 @@ class CO_SIM_IO_API ModelPart void load(CoSimIO::Internals::Serializer& rSerializer); }; + +template +inline void ModelPart::CreateNewNodes( + const TIdContainerType& I_Id, + const TCoordsContainerType& I_X, + const TCoordsContainerType& I_Y, + const TCoordsContainerType& I_Z) +{ + CO_SIM_IO_TRY + + const std::size_t num_new_nodes = I_Id.size(); + + CO_SIM_IO_ERROR_IF(num_new_nodes != I_X.size()) << "Wrong number of X-Coordinates!" << std::endl; + CO_SIM_IO_ERROR_IF(num_new_nodes != I_Y.size()) << "Wrong number of Y-Coordinates!" << std::endl; + CO_SIM_IO_ERROR_IF(num_new_nodes != I_Z.size()) << "Wrong number of Z-Coordinates!" << std::endl; + + mNodes.reserve(mNodes.size()+num_new_nodes); + GetLocalModelPart().mNodes.reserve(GetLocalModelPart().mNodes.size()+num_new_nodes); + + for (std::size_t i=0; i +inline void ModelPart::CreateNewGhostNodes( + const TIdContainerType& I_Id, + const TCoordsContainerType& I_X, + const TCoordsContainerType& I_Y, + const TCoordsContainerType& I_Z, + const TPartitionIndexContainerType& PartitionIndex) +{ + CO_SIM_IO_TRY + + const std::size_t num_new_nodes = I_Id.size(); + + CO_SIM_IO_ERROR_IF(num_new_nodes != I_X.size()) << "Wrong number of X-Coordinates!" << std::endl; + CO_SIM_IO_ERROR_IF(num_new_nodes != I_Y.size()) << "Wrong number of Y-Coordinates!" << std::endl; + CO_SIM_IO_ERROR_IF(num_new_nodes != I_Z.size()) << "Wrong number of Z-Coordinates!" << std::endl; + CO_SIM_IO_ERROR_IF(num_new_nodes != PartitionIndex.size()) << "Wrong number of partition indices!" << std::endl; + + mNodes.reserve(mNodes.size()+num_new_nodes); + GetGhostModelPart().mNodes.reserve(GetGhostModelPart().mNodes.size()+num_new_nodes); + // preparing the sizes in the PartitionModelParts requires to compute how many nodes go to which partition + // => num_nodes_this_rank + // as this might be expensive, it is skipped for now + // GetPartitionModelPart(num_nodes_this_rank).mNodes.reserve(GetPartitionModelPart(num_nodes_this_rank).mNodes.size()+num_new_nodes); + + for (std::size_t i=0; i +inline void ModelPart::CreateNewElements( + const TIdContainerType& I_Id, + const TTypeContainerType& I_Type, + const TConnectivitiesContainerType& I_Connectivities) +{ + CO_SIM_IO_TRY + + const std::size_t num_new_elements = I_Id.size(); + + CO_SIM_IO_ERROR_IF(num_new_elements != I_Type.size()) << "Wrong number of Types!" << std::endl; + + std::size_t exp_num_connectivities = 0; + for (std::size_t i=0; i, + std::vector>) .def("CreateNewGhostNode", &CoSimIO::ModelPart::CreateNewGhostNode, py::return_value_policy::reference_internal) + .def("CreateNewGhostNodes", &CoSimIO::ModelPart::CreateNewGhostNodes, + std::vector, + std::vector>) .def("CreateNewElement", &CoSimIO::ModelPart::CreateNewElement, py::return_value_policy::reference_internal) + .def("CreateNewElements", &CoSimIO::ModelPart::CreateNewElements, + std::vector, + std::vector>) .def("GetNode", [](CoSimIO::ModelPart& I_ModelPart, const CoSimIO::IdType I_Id){ return I_ModelPart.pGetNode(I_Id);}, py::return_value_policy::reference_internal) .def("GetElement", [](CoSimIO::ModelPart& I_ModelPart, const CoSimIO::IdType I_Id){ diff --git a/co_sim_io/sources/exception.cpp b/co_sim_io/sources/exception.cpp index 9d39e7b4..d01ca7cf 100644 --- a/co_sim_io/sources/exception.cpp +++ b/co_sim_io/sources/exception.cpp @@ -88,9 +88,10 @@ void Exception::update_what(){ if (mCallStack.empty()) { buffer << "in Unknown Location"; } else { - buffer << "in " << mCallStack[0] << "\n"; + buffer << "in 1. " << mCallStack[0] << "\n"; + int counter = 2; for (auto i = mCallStack.begin()+1; i != mCallStack.end(); ++i) { - buffer << " " << *i << "\n"; + buffer << " " << counter++ << ". " << *i << "\n"; } } mWhat = buffer.str(); diff --git a/co_sim_io/sources/model_part.cpp b/co_sim_io/sources/model_part.cpp index 94b0459d..9cab9d59 100644 --- a/co_sim_io/sources/model_part.cpp +++ b/co_sim_io/sources/model_part.cpp @@ -15,7 +15,6 @@ // Project includes #include "includes/model_part.hpp" -#include "includes/utilities.hpp" namespace CoSimIO { @@ -138,8 +137,8 @@ Node& ModelPart::CreateNewNode( CoSimIO::intrusive_ptr new_node(CoSimIO::make_intrusive(I_Id, I_X, I_Y, I_Z)); - mNodes.push_back(new_node); - GetLocalModelPart().mNodes.push_back(new_node); + mNodes.push_back(new_node, I_Id); + GetLocalModelPart().mNodes.push_back(new_node, I_Id); return *new_node; } @@ -152,12 +151,13 @@ Node& ModelPart::CreateNewGhostNode( const int PartitionIndex) { CO_SIM_IO_ERROR_IF(HasNode(I_Id)) << "The Node with Id " << I_Id << " exists already!" << std::endl; + CO_SIM_IO_ERROR_IF(PartitionIndex<0) << "PartitionIndex must be >= 0!" << std::endl; CoSimIO::intrusive_ptr new_node(CoSimIO::make_intrusive(I_Id, I_X, I_Y, I_Z)); - mNodes.push_back(new_node); - GetGhostModelPart().mNodes.push_back(new_node); - GetPartitionModelPart(PartitionIndex).mNodes.push_back(new_node); + mNodes.push_back(new_node, I_Id); + GetGhostModelPart().mNodes.push_back(new_node, I_Id); + GetPartitionModelPart(PartitionIndex).mNodes.push_back(new_node, I_Id); return *new_node; } @@ -177,8 +177,8 @@ Element& ModelPart::CreateNewElement( CoSimIO::intrusive_ptr new_element(CoSimIO::make_intrusive(I_Id, I_Type, nodes)); - mElements.push_back(new_element); - GetLocalModelPart().mElements.push_back(new_element); + mElements.push_back(new_element, I_Id); + GetLocalModelPart().mElements.push_back(new_element, I_Id); return *new_element; } @@ -247,40 +247,32 @@ void ModelPart::Clear() ModelPart::NodesContainerType::const_iterator ModelPart::FindNode(const IdType I_Id) const { - return std::find_if( - mNodes.begin(), mNodes.end(), - [I_Id](const NodePointerType& rp_node) { return rp_node->Id() == I_Id;}); + return mNodes.find(I_Id); } ModelPart::NodesContainerType::iterator ModelPart::FindNode(const IdType I_Id) { - return std::find_if( - mNodes.begin(), mNodes.end(), - [I_Id](const NodePointerType& rp_node) { return rp_node->Id() == I_Id;}); + return mNodes.find(I_Id); } ModelPart::ElementsContainerType::const_iterator ModelPart::FindElement(const IdType I_Id) const { - return std::find_if( - mElements.begin(), mElements.end(), - [I_Id](const ElementPointerType& rp_elem) { return rp_elem->Id() == I_Id;}); + return mElements.find(I_Id); } ModelPart::ElementsContainerType::iterator ModelPart::FindElement(const IdType I_Id) { - return std::find_if( - mElements.begin(), mElements.end(), - [I_Id](const ElementPointerType& rp_elem) { return rp_elem->Id() == I_Id;}); + return mElements.find(I_Id); } bool ModelPart::HasNode(const IdType I_Id) const { - return FindNode(I_Id) != mNodes.end(); + return mNodes.contains(I_Id); } bool ModelPart::HasElement(const IdType I_Id) const { - return FindElement(I_Id) != mElements.end(); + return mElements.contains(I_Id); } ModelPart& ModelPart::GetLocalModelPart() diff --git a/docs/model_part/model_part_c.md b/docs/model_part/model_part_c.md index 5e9e8037..fd81c19e 100644 --- a/docs/model_part/model_part_c.md +++ b/docs/model_part/model_part_c.md @@ -50,23 +50,43 @@ const char* name = CoSimIO_ModelPart_Name(model_part); CoSimIO_FreeModelPart(model_part); ``` -Nodes can be created like this: +As single `Node` can be created with `CoSimIO_ModelPart_CreateNewNode`: ```c -// memory of node is managed by model_part! +/* memory of node is managed by model_part! */ CoSimIO_Node node = CoSimIO_ModelPart_CreateNewNode( model_part, - 1, // Id - 0.0, // X-Coordinate - 1.5, // Y-Coordinate - -4.22 // Z-Coordinate + 1, /* Id */ + 0.0, /* X-Coordinate */ + 1.5, /* Y-Coordinate */ + -4.22 /* Z-Coordinate */ +); +``` + +Multiple nodes can be created with `CoSimIO_ModelPart_CreateNewNodes`: +```c +int num_nodes = 10; +int ids[10]; +double x_coords[10]; +double y_coords[10]; +double z_coords[10]; + +/* initialize the vectors somehow ... */ + +CoSimIO_ModelPart_CreateNewNodes( + model_part, + num_nodes, + ids, /* Ids */ + x_coords, /* X-Coordinates */ + y_coords, /* Y-Coordinates */ + z_coords /* Z-Coordinates */ ); ``` Elements can be created after nodes were created. The mesh connectivites are documented [here](../mesh_connectivities.md). ```c -int connectivity[2] = {1,2}; // Ids of the Nodes +int connectivity[2] = {1,2}; /* Ids of the Nodes */ -// memory of element is managed by model_part! +/* memory of element is managed by model_part! */ CoSimIO_Element element = CoSimIO_ModelPart_CreateNewElement( model_part, 2, // Id @@ -74,6 +94,34 @@ CoSimIO_Element element = CoSimIO_ModelPart_CreateNewElement( connectivity // Connectivity information, i.e. Ids of nodes that the element has ); ``` + +Multiple elements can be created with `CoSimIO_ModelPart_CreateNewElements`: +```c +int num_elements = 10; +int ids[10]; +CoSimIO_ElementType types[10]; + +int num_connectivities = ...; /*to be calculated, depends on element types!*/ +int connectivities[...]; +/* +the connectivities vector is contiguous, not a vector of vectors! +Example: +types is [Line2D2 and Triangle3D3] connectivities is [1,2,3,4,5], +the {1,2} are the connectivities for the line +and {3,4,5} are the connectivities for the triangle*/ + +/* initialize the vectors somehow ... */ + +CoSimIO_ModelPart_CreateNewElements( + model_part, + num_elements, /* Number of elements */ + ids, /* Ids */ + types, /* Element types */ + num_connectivities, /* Number of connectivities */ + connectivities /* Connectivities */ +); +``` + Note: Node and Element Ids start with 1 (0 is not accepted). Use the following functions to get the number of nodes and elements: @@ -85,16 +133,16 @@ int number_of_elements = CoSimIO_ModelPart_NumberOfElements(model_part); The nodes and elements can be iterated with: ```c -// iterate nodes +/* iterate nodes */ for (int i=0; i ids(num_nodes); +std::vector x_coords(num_nodes); +std::vector y_coords(num_nodes); +std::vector z_coords(num_nodes); + +// initialize the vectors somehow ... + +model_part.CreateNewNodes( + ids, // Ids + x_coords, // X-Coordinates + y_coords, // Y-Coordinates + z_coords // Z-Coordinates +); +``` + Elements can be created after nodes were created. The mesh connectivites are documented [here](../mesh_connectivities.md). ```c++ std::vector connectivity {1,2}; // Ids of the Nodes @@ -56,6 +74,28 @@ CoSimIO::Element& element = model_part.CreateNewElement( connectivity // Connectivity information, i.e. Ids of nodes that the element has ); ``` + +Multiple elements can be created with `CreateNewElements`: +```c++ +std::size_t num_elements = 10; +std::vector ids(num_elements); +std::vector types(num_elements); +std::vector connectivities; +// the connectivities vector is contiguous, not a vector of vectors! +// Example: +// types is [Line2D2 and Triangle3D3] connectivities is [1,2,3,4,5], +// the {1,2} are the connectivities for the line +// and {3,4,5} are the connectivities for the triangle + +// initialize the vectors somehow ... + +model_part.CreateNewElements( + ids, // Ids + types, // Element types + connectivities // Connectivities +); +``` + Note: Node and Element Ids start with 1 (0 is not accepted). Use the following functions to get the number of nodes and elements: @@ -124,8 +164,30 @@ CoSimIO::Node& ghost_node = model_part.CreateNewGhostNode( 5 // Partition index where the node is local ); ``` + +Multiple ghost nodes can be created with `CreateNewGhostNodes`, similar to the creation of multiple (local) nodes: +```c++ +std::size_t num_nodes = 10; +std::vector ids(num_nodes); +std::vector x_coords(num_nodes); +std::vector y_coords(num_nodes); +std::vector z_coords(num_nodes); +std::vector partition_indices(num_nodes); + +// initialize the vectors somehow ... + +model_part.CreateNewGhostNodes( + ids, // Ids + x_coords, // X-Coordinates + y_coords, // Y-Coordinates + z_coords, // Z-Coordinates + partition_indices // Partition indices where the nodes are local +); +``` + These ghost nodes can also be used for the creation of elements. Note that this node has to be created as local node in its local partition, otherwise deadlocks can occur! +Also the Ids must be unique, again otherwise deadlocks can occur! Use the following functions to get the number of local and ghost nodes: ```c++ diff --git a/docs/model_part/model_part_python.md b/docs/model_part/model_part_python.md index 5894085e..2c400553 100644 --- a/docs/model_part/model_part_python.md +++ b/docs/model_part/model_part_python.md @@ -32,7 +32,7 @@ model_part = CoSimIO.ModelPart("my_model_part") name = model_part.Name() ``` -Nodes can be created like this: +As single `Node` can be created with `CreateNewNode`: ```python node = model_part.CreateNewNode( 1, # Id @@ -42,6 +42,22 @@ node = model_part.CreateNewNode( ) ``` +Multiple nodes can be created with `CreateNewNodes`: +```python +num_nodes = 10 +ids = [...] # len = num_nodes +x_coords = [...] # len = num_nodes +y_coords = [...] # len = num_nodes +z_coords = [...] # len = num_nodes + +model_part.CreateNewNodes( + ids, # Ids + x_coords, # X-Coordinates + y_coords, # Y-Coordinates + z_coords # Z-Coordinates +) +``` + Elements can be created after nodes were created. The mesh connectivites are documented [here](../mesh_connectivities.md). ```python connectivity = [1,2] # Ids of the Nodes @@ -52,6 +68,26 @@ element = model_part.CreateNewElement( connectivity # Connectivity information, i.e. Ids of nodes that the element has ) ``` + +Multiple elements can be created with `CreateNewElements`: +```python +std::size_t num_elements = 10 +ids = [...] # len = num_elements +types = [...] # len = num_elements +connectivities = [...] # len depends on element types +# the connectivities list is contiguous, not a list of list! +# Example: +# types is [Line2D2 and Triangle3D3] connectivities is [1,2,3,4,5], +# the [1,2] are the connectivities for the line +# and [3,4,5] are the connectivities for the triangle + +model_part.CreateNewElements( + ids, # Ids + types, # Element types + connectivities # Connectivities +) +``` + Note: Node and Element Ids start with 1 (0 is not accepted). Use the following functions to get the number of nodes and elements: @@ -102,18 +138,37 @@ ghost_node = model_part.CreateNewGhostNode( 1.5, # Y-Coordinate -4.2, # Z-Coordinate 5 # Partition index where the node is local -); +) ``` + +Multiple ghost nodes can be created with `CreateNewGhostNodes`, similar to the creation of multiple (local) nodes: +```python +num_ghost_nodes = 10 +ids = [...] # len = num_ghost_nodes +x_coords = [...] # len = num_ghost_nodes +y_coords = [...] # len = num_ghost_nodes +z_coords = [...] # len = num_ghost_nodes +partition_indices = [...] # len = num_ghost_nodes + +model_part.CreateNewGhostNodes( + ids, # Ids + x_coords, # X-Coordinates + y_coords, # Y-Coordinates + z_coords, # Z-Coordinates + partition_indices # Partition indices where the nodes are local +``` + These ghost nodes can also be used for the creation of elements. Note that this node has to be created as local node in its local partition, otherwise deadlocks can occur! +Also the Ids must be unique, again otherwise deadlocks can occur! Use the following functions to get the number of local and ghost nodes: ```python -number_of_local_nodes = model_part.NumberOfLocalNodes(); +number_of_local_nodes = model_part.NumberOfLocalNodes() -number_of_ghost_nodes = model_part.NumberOfGhostNodes(); +number_of_ghost_nodes = model_part.NumberOfGhostNodes() -number_of_all_nodes = model_part.NumberOfNodes(); # local + ghost nodes +number_of_all_nodes = model_part.NumberOfNodes() # local + ghost nodes ``` Note that `model_part.Nodes()` contains all the nodes, i.e. local and ghost nodes. diff --git a/tests/co_sim_io/c/model_part/test_model_part_create_multiple.c b/tests/co_sim_io/c/model_part/test_model_part_create_multiple.c new file mode 100644 index 00000000..4306ee19 --- /dev/null +++ b/tests/co_sim_io/c/model_part/test_model_part_create_multiple.c @@ -0,0 +1,104 @@ +/* ______ _____ _ ________ + / ____/___ / ___/(_)___ ___ / _/ __ | + / / / __ \\__ \/ / __ `__ \ / // / / / + / /___/ /_/ /__/ / / / / / / // // /_/ / + \____/\____/____/_/_/ /_/ /_/___/\____/ + Kratos CoSimulationApplication + + License: BSD License, see license.txt + + Main authors: Philipp Bucher (https://github.com/philbucher) +*/ + +/* Project includes */ +#include "c/co_sim_io_c.h" + +#include "../checks.h" + +int main() +{ + /* declaring variables */ + int i; + int j; + int n_nodes; + int conn_counter=0; + #define NUM_LOCAL_NODES 20 + #define NUM_GHOST_NODES 15 + #define NUM_ELEMENTS 12 + int ids[NUM_LOCAL_NODES]; + int part_idx[NUM_LOCAL_NODES]; + double node_x[NUM_LOCAL_NODES]; + double node_y[NUM_LOCAL_NODES]; + double node_z[NUM_LOCAL_NODES]; + int ghost_node_ids[NUM_LOCAL_NODES]; /* allocating more to make handling easier */ + CoSimIO_ElementType types[NUM_ELEMENTS]; + int conn[NUM_ELEMENTS*3]; /*allocating more to be safe*/ + CoSimIO_ModelPart model_part; + CoSimIO_Node node; + CoSimIO_Element elem; + + model_part = CoSimIO_CreateModelPart("my_model_part"); + + COSIMIO_CHECK_INT_EQUAL(CoSimIO_ModelPart_NumberOfNodes(model_part), 0); + COSIMIO_CHECK_INT_EQUAL(CoSimIO_ModelPart_NumberOfLocalNodes(model_part), 0); + COSIMIO_CHECK_INT_EQUAL(CoSimIO_ModelPart_NumberOfGhostNodes(model_part), 0); + COSIMIO_CHECK_INT_EQUAL(CoSimIO_ModelPart_NumberOfElements(model_part), 0); + + for (i=0; i +#include +#include // Project includes #include "co_sim_io_testing.hpp" @@ -693,6 +695,251 @@ TEST_CASE("model_part_pointer_vector") CHECK(PointerVectorChecker(model_part.Elements())); } +template +void AuxCreateNodesTestInitializeFunction( + const std::size_t NumNodes, + TIdContainerType& I_Id, + TCoordsContainerType& I_X, + TCoordsContainerType& I_Y, + TCoordsContainerType& I_Z) +{ + for (std::size_t i=0; i +void AuxCreateNodesTestFunction( + const std::size_t NumNodes, + const TIdContainerType& I_Id, + const TCoordsContainerType& I_X, + const TCoordsContainerType& I_Y, + const TCoordsContainerType& I_Z) +{ + REQUIRE_EQ(I_Id.size(), NumNodes); + REQUIRE_EQ(I_X.size(), NumNodes); + REQUIRE_EQ(I_Y.size(), NumNodes); + REQUIRE_EQ(I_Z.size(), NumNodes); + + ModelPart model_part("for_test"); + + model_part.CreateNewNodes(I_Id, I_X, I_Y, I_Z); + + CHECK_EQ(model_part.NumberOfNodes(), NumNodes); + CHECK_EQ(model_part.NumberOfLocalNodes(), NumNodes); + CHECK_EQ(model_part.NumberOfGhostNodes(), 0); + CHECK_EQ(model_part.NumberOfElements(), 0); + + for (std::size_t i=0; i ids(num_nodes); + std::vector x(num_nodes); + std::vector y(num_nodes); + std::vector z(num_nodes); + + AuxCreateNodesTestInitializeFunction(num_nodes, ids, x, y, z); + AuxCreateNodesTestFunction(num_nodes, ids, x, y, z); +} + +TEST_CASE("model_part_CreateNodes_std::array") +{ + ModelPart model_part("for_test"); + + constexpr std::size_t num_nodes = 234; + + std::array ids; + std::array x; + std::array y; + std::array z; + + AuxCreateNodesTestInitializeFunction(num_nodes, ids, x, y, z); + AuxCreateNodesTestFunction(num_nodes, ids, x, y, z); +} + +TEST_CASE("model_part_CreateNodes_raw_array") +{ + constexpr std::size_t num_nodes = 234; + + CoSimIO::IdType arr_ids[num_nodes]; + double arr_x[num_nodes]; + double arr_y[num_nodes]; + double arr_z[num_nodes]; + + AuxCreateNodesTestInitializeFunction(num_nodes, arr_ids, arr_x, arr_y, arr_z); + + const CoSimIO::Internals::DataContainerRawMemoryReadOnly ids(arr_ids, num_nodes); + const CoSimIO::Internals::DataContainerRawMemoryReadOnly x(arr_x, num_nodes); + const CoSimIO::Internals::DataContainerRawMemoryReadOnly y(arr_y, num_nodes); + const CoSimIO::Internals::DataContainerRawMemoryReadOnly z(arr_z, num_nodes); + + AuxCreateNodesTestFunction(num_nodes, ids, x, y, z); +} + +template +void AuxCreateGhostNodesTestInitializeFunction( + const std::size_t NumNodes, + TIdContainerType& I_Id, + TCoordsContainerType& I_X, + TCoordsContainerType& I_Y, + TCoordsContainerType& I_Z, + TPartitionIndexContainerType& PartitionIndex) +{ + for (std::size_t i=0; i(i); + } +} + +template +void AuxCreateGhostNodesTestFunction( + const std::size_t NumNodes, + const TIdContainerType& I_Id, + const TCoordsContainerType& I_X, + const TCoordsContainerType& I_Y, + const TCoordsContainerType& I_Z, + const TPartitionIndexContainerType& PartitionIndex) +{ + REQUIRE_EQ(I_Id.size(), NumNodes); + REQUIRE_EQ(I_X.size(), NumNodes); + REQUIRE_EQ(I_Y.size(), NumNodes); + REQUIRE_EQ(I_Z.size(), NumNodes); + REQUIRE_EQ(PartitionIndex.size(), NumNodes); + + ModelPart model_part("for_test"); + + model_part.CreateNewGhostNodes(I_Id, I_X, I_Y, I_Z, PartitionIndex); + + CHECK_EQ(model_part.NumberOfNodes(), NumNodes); + CHECK_EQ(model_part.NumberOfLocalNodes(), 0); + CHECK_EQ(model_part.NumberOfGhostNodes(), NumNodes); + CHECK_EQ(model_part.NumberOfElements(), 0); + + for (std::size_t i=0; i ids(num_nodes); + std::vector x(num_nodes); + std::vector y(num_nodes); + std::vector z(num_nodes); + std::vector part_indices(num_nodes); + + AuxCreateGhostNodesTestInitializeFunction(num_nodes, ids, x, y, z, part_indices); + AuxCreateGhostNodesTestFunction(num_nodes, ids, x, y, z, part_indices); +} + +TEST_CASE("model_part_CreateGhostNodes_std::array") +{ + ModelPart model_part("for_test"); + + constexpr std::size_t num_nodes = 234; + + std::array ids; + std::array x; + std::array y; + std::array z; + std::array part_indices; + + AuxCreateGhostNodesTestInitializeFunction(num_nodes, ids, x, y, z, part_indices); + AuxCreateGhostNodesTestFunction(num_nodes, ids, x, y, z, part_indices); +} + +TEST_CASE("model_part_CreateGhostNodes_raw_array") +{ + constexpr std::size_t num_nodes = 234; + + CoSimIO::IdType arr_ids[num_nodes]; + double arr_x[num_nodes]; + double arr_y[num_nodes]; + double arr_z[num_nodes]; + int arr_part_indices[num_nodes]; + + AuxCreateGhostNodesTestInitializeFunction(num_nodes, arr_ids, arr_x, arr_y, arr_z, arr_part_indices); + + const CoSimIO::Internals::DataContainerRawMemoryReadOnly ids(arr_ids, num_nodes); + const CoSimIO::Internals::DataContainerRawMemoryReadOnly x(arr_x, num_nodes); + const CoSimIO::Internals::DataContainerRawMemoryReadOnly y(arr_y, num_nodes); + const CoSimIO::Internals::DataContainerRawMemoryReadOnly z(arr_z, num_nodes); + const CoSimIO::Internals::DataContainerRawMemoryReadOnly part_indices(arr_part_indices, num_nodes); + + AuxCreateGhostNodesTestFunction(num_nodes, ids, x, y, z, part_indices); +} + +TEST_CASE("model_part_CreateElements_std::vector") +{ + constexpr std::size_t num_nodes = 234; + + // first create Nodes + std::vector node_ids(num_nodes); + std::vector x(num_nodes); + std::vector y(num_nodes); + std::vector z(num_nodes); + AuxCreateNodesTestInitializeFunction(num_nodes, node_ids, x, y, z); + + ModelPart model_part("for_test"); + model_part.CreateNewNodes(node_ids, x, y, z); + + constexpr std::size_t num_elements = 123; + std::vector ids(num_elements); + std::vector types(num_elements, CoSimIO::ElementType::Line2D2); + std::vector connectivities; + connectivities.reserve(num_elements*3); + + std::iota(ids.begin(), ids.end(), 1); + std::fill_n(types.begin(), 20, CoSimIO::ElementType::Triangle3D3); // first 20 are triangles + + for (std::size_t i=0; i