12 #include "../config/config.hpp"
14 #ifdef MFEM_USE_CONDUIT
17 #include "../general/text.hpp"
18 #include <conduit_relay.hpp>
19 #include <conduit_blueprint.hpp>
24 using namespace conduit;
38 ConduitDataCollection::ConduitDataCollection(
const std::string& coll_name,
41 relay_protocol(
"hdf5")
50 const std::string& coll_name,
53 relay_protocol(
"hdf5")
56 MPI_Comm_rank(comm, &
myid);
76 MFEM_ABORT(
"Error creating directory: " << dir_name);
85 if (!blueprint::mesh::verify(n_mesh,verify_info))
87 MFEM_ABORT(
"Conduit Mesh Blueprint Verify Failed:\n"
88 << verify_info.to_json());
94 std::string
name = itr->first;
102 n_mesh[
"fields"][name]);
136 int num_domains = n_root[
"number_of_trees"].to_int();
141 MFEM_WARNING(
"num_procs must equal num_domains");
167 const std::string &main_toplogy_name,
180 std::string topo_name = main_toplogy_name;
184 topo_name = n_mesh[
"topologies"].schema().child_name(0);
187 MFEM_ASSERT(n_mesh.has_path(
"topologies/" + topo_name),
188 "Expected topology named \"" + topo_name +
"\" "
189 "(node is missing path \"topologies/" + topo_name +
"\")");
192 std::string coords_name =
193 n_mesh[
"topologies"][topo_name][
"coordset"].as_string();
196 MFEM_ASSERT(n_mesh.has_path(
"coordsets/" + coords_name),
197 "Expected topology named \"" + coords_name +
"\" "
198 "(node is missing path \"coordsets/" + coords_name +
"\")");
200 const Node &n_coordset = n_mesh[
"coordsets"][coords_name];
201 const Node &n_coordset_vals = n_coordset[
"values"];
204 int ndims = n_coordset_vals.number_of_children();
207 int num_verts = n_coordset_vals[0].dtype().number_of_elements();
209 const double *verts_ptr = NULL;
217 n_coordset_vals[0].dtype().is_double() &&
218 blueprint::mcarray::is_interleaved(n_coordset_vals) )
222 verts_ptr = n_coordset_vals[0].value();
229 NodeConstIterator itr = n_coordset_vals.children();
230 while (itr.has_next())
232 const Node &c_vals = itr.next();
233 std::string c_name = itr.name();
235 if ( c_vals.dtype().is_double() )
238 n_tmp[c_name].set_external(c_vals);
244 c_vals.to_double_array(n_tmp[c_name]);
253 n_tmp[
"z"].set(DataType::c_double(num_verts));
259 n_tmp[
"y"].set(DataType::c_double(num_verts));
262 Node &n_conv_coords_vals = n_conv[
"coordsets"][coords_name][
"values"];
263 blueprint::mcarray::to_interleaved(n_tmp,
265 verts_ptr = n_conv_coords_vals[0].value();
270 const Node &n_mesh_topo = n_mesh[
"topologies"][topo_name];
271 std::string mesh_ele_shape = n_mesh_topo[
"elements/shape"].as_string();
276 const Node &n_mesh_conn = n_mesh_topo[
"elements/connectivity"];
278 const int *elem_indices = NULL;
280 if (n_mesh_conn.dtype().is_int() &&
281 n_mesh_conn.is_compact() )
283 elem_indices = n_mesh_topo[
"elements/connectivity"].value();
287 Node &n_mesh_conn_conv=
288 n_conv[
"topologies"][topo_name][
"elements/connectivity"];
289 n_mesh_conn.to_int_array(n_mesh_conn_conv);
290 elem_indices = n_mesh_conn_conv.value();
294 n_mesh_topo[
"elements/connectivity"].dtype().number_of_elements();
295 num_mesh_ele = num_mesh_ele / num_idxs_per_ele;
298 const int *bndry_indices = NULL;
299 int num_bndry_ele = 0;
304 if ( n_mesh_topo.has_child(
"boundary_topology") )
306 std::string bndry_topo_name = n_mesh_topo[
"boundary_topology"].as_string();
315 if (n_mesh[
"topologies"].has_child(bndry_topo_name))
317 const Node &n_bndry_topo = n_mesh[
"topologies"][bndry_topo_name];
318 std::string bndry_ele_shape = n_bndry_topo[
"elements/shape"].as_string();
320 bndry_geo = ShapeNameToGeomType(bndry_ele_shape);
323 const Node &n_bndry_conn = n_bndry_topo[
"elements/connectivity"];
326 if ( n_bndry_conn.dtype().is_int() &&
327 n_bndry_conn.is_compact())
329 bndry_indices = n_bndry_conn.value();
333 Node &n_bndry_conn_conv =
334 n_conv[
"topologies"][bndry_topo_name][
"elements/connectivity"];
335 n_bndry_conn.to_int_array(n_bndry_conn_conv);
336 bndry_indices = (n_bndry_conn_conv).value();
341 n_bndry_topo[
"elements/connectivity"].dtype().number_of_elements();
342 num_bndry_ele = num_bndry_ele / num_idxs_per_bndry_ele;
350 const int *mesh_atts = NULL;
351 const int *bndry_atts = NULL;
360 std::string main_att_name =
"";
362 const Node &n_fields = n_mesh[
"fields"];
363 NodeConstIterator itr = n_fields.children();
365 while ( itr.has_next() && main_att_name ==
"" )
368 std::string fld_name = itr.name();
369 if ( fld_name.find(
"boundary") == std::string::npos &&
370 fld_name.find(
"_attribute") != std::string::npos )
372 main_att_name = fld_name;
376 if ( main_att_name !=
"" )
378 const Node &n_mesh_atts_vals = n_fields[main_att_name][
"values"];
381 if (n_mesh_atts_vals.dtype().is_int() &&
382 n_mesh_atts_vals.is_compact() )
384 mesh_atts = n_mesh_atts_vals.value();
388 Node &n_mesh_atts_vals_conv = n_conv[
"fields"][main_att_name][
"values"];
389 n_mesh_atts_vals.to_int_array(n_mesh_atts_vals_conv);
390 mesh_atts = n_mesh_atts_vals_conv.value();
402 std::string bnd_att_name =
"";
403 itr = n_fields.children();
405 while ( itr.has_next() && bnd_att_name ==
"" )
408 std::string fld_name = itr.name();
409 if ( fld_name.find(
"boundary") != std::string::npos &&
410 fld_name.find(
"_attribute") != std::string::npos )
412 bnd_att_name = fld_name;
416 if ( bnd_att_name !=
"" )
419 const Node &n_bndry_atts_vals =n_fields[bnd_att_name][
"values"];
422 if ( n_bndry_atts_vals.dtype().is_int() &&
423 n_bndry_atts_vals.is_compact())
425 bndry_atts = n_bndry_atts_vals.value();
429 Node &n_bndry_atts_vals_conv = n_conv[
"fields"][bnd_att_name][
"values"];
430 n_bndry_atts_vals.to_int_array(n_bndry_atts_vals_conv);
431 bndry_atts = n_bndry_atts_vals_conv.value();
455 const_cast<double*>(verts_ptr),
458 const_cast<int*>(elem_indices),
461 const_cast<int*>(mesh_atts),
464 const_cast<int*>(bndry_indices),
467 const_cast<int*>(bndry_atts),
473 if (n_mesh_topo.has_child(
"grid_function"))
475 std::string nodes_gf_name = n_mesh_topo[
"grid_function"].as_string();
478 const Node &n_mesh_gf = n_mesh[
"fields"][nodes_gf_name];
487 if (zero_copy && !n_conv.dtype().is_empty())
503 res =
new Mesh(*mesh,
true);
522 const double *vals_ptr = NULL;
528 if (n_field[
"values"].dtype().is_object())
530 vdim = n_field[
"values"].number_of_children();
535 if ( n_field[
"values"][0].dtype().is_double() )
538 if (n_field[
"values"].is_contiguous())
541 vals_ptr = n_field[
"values"].child(0).value();
544 else if (blueprint::mcarray::is_interleaved(n_field[
"values"]))
548 vals_ptr = n_field[
"values"].child(0).value();
554 blueprint::mcarray::to_contiguous(n_field[
"values"],
556 vals_ptr = n_conv[
"values"].child(0).value();
564 NodeConstIterator itr = n_field[
"values"].children();
565 while (itr.has_next())
567 const Node &c_vals = itr.next();
568 std::string c_name = itr.name();
570 if ( c_vals.dtype().is_double() )
573 n_tmp[c_name].set_external(c_vals);
579 c_vals.to_double_array(n_tmp[c_name]);
585 blueprint::mcarray::to_contiguous(n_tmp,
587 vals_ptr = n_conv[
"values"].child(0).value();
592 if (n_field[
"values"].dtype().is_double() &&
593 n_field[
"values"].is_compact())
595 vals_ptr = n_field[
"values"].value();
599 n_field[
"values"].to_double_array(n_conv[
"values"]);
600 vals_ptr = n_conv[
"values"].value();
604 if (zero_copy && !n_conv.dtype().is_empty())
611 std::string fec_name = n_field[
"basis"].as_string();
623 res =
new GridFunction(fes,const_cast<double*>(vals_ptr));
630 Vector vals_vec(const_cast<double*>(vals_ptr),fes->GetVSize());
646 const std::string &coordset_name,
647 const std::string &main_topology_name,
648 const std::string &boundary_topology_name,
649 const std::string &main_adjset_name)
653 MFEM_ASSERT(dim >= 1 && dim <= 3,
"invalid mesh dimension");
663 int num_vertices = mesh->
GetNV();
665 MFEM_ASSERT( ( stride == 3 *
sizeof(
double) ),
666 "Unexpected stride for Vertex");
668 Node &n_mesh_coords = n_mesh[
"coordsets"][coordset_name];
669 n_mesh_coords[
"type"] =
"explicit";
674 n_mesh_coords[
"values/x"].set_external(coords_ptr,
681 n_mesh_coords[
"values/y"].set_external(coords_ptr,
688 n_mesh_coords[
"values/z"].set_external(coords_ptr,
698 Node &n_topo = n_mesh[
"topologies"][main_topology_name];
700 n_topo[
"type"] =
"unstructured";
701 n_topo[
"coordset"] = coordset_name;
705 std::string ele_shape = ElementTypeToShapeName(ele_type);
707 n_topo[
"elements/shape"] = ele_shape;
711 if (gf_mesh_nodes != NULL)
713 n_topo[
"grid_function"] =
"mesh_nodes";
721 int num_ele = mesh->
GetNE();
724 int num_conn_idxs = num_ele * idxs_per_ele;
726 n_topo[
"elements/connectivity"].set(DataType::c_int(num_conn_idxs));
728 int *conn_ptr = n_topo[
"elements/connectivity"].value();
730 for (
int i=0; i < num_ele; i++)
735 memcpy(conn_ptr, ele_verts, idxs_per_ele *
sizeof(
int));
737 conn_ptr += idxs_per_ele;
740 if (gf_mesh_nodes != NULL)
743 n_mesh[
"fields/mesh_nodes"],
751 Node &n_mesh_att = n_mesh[
"fields/element_attribute"];
753 n_mesh_att[
"association"] =
"element";
754 n_mesh_att[
"topology"] = main_topology_name;
755 n_mesh_att[
"values"].set(DataType::c_int(num_ele));
757 int_array att_vals = n_mesh_att[
"values"].value();
758 for (
int i = 0; i < num_ele; i++)
770 n_topo[
"boundary_topology"] = boundary_topology_name;
772 Node &n_bndry_topo = n_mesh[
"topologies"][boundary_topology_name];
774 n_bndry_topo[
"type"] =
"unstructured";
775 n_bndry_topo[
"coordset"] = coordset_name;
777 int num_bndry_ele = mesh->
GetNBE();
784 std::string bndry_ele_shape = ElementTypeToShapeName(bndry_ele_type);
785 n_bndry_topo[
"elements/shape"] = bndry_ele_shape;
790 int num_bndry_conn_idxs = num_bndry_ele * bndry_idxs_per_ele;
792 n_bndry_topo[
"elements/connectivity"].set(DataType::c_int(num_bndry_conn_idxs));
794 int *bndry_conn_ptr = n_bndry_topo[
"elements/connectivity"].value();
796 for (
int i=0; i < num_bndry_ele; i++)
799 const int *bndry_ele_verts = bndry_ele->
GetVertices();
801 memcpy(bndry_conn_ptr, bndry_ele_verts, bndry_idxs_per_ele *
sizeof(
int));
803 bndry_conn_ptr += bndry_idxs_per_ele;
810 Node &n_bndry_mesh_att = n_mesh[
"fields/boundary_attribute"];
812 n_bndry_mesh_att[
"association"] =
"element";
813 n_bndry_mesh_att[
"topology"] = boundary_topology_name;
814 n_bndry_mesh_att[
"values"].set(DataType::c_int(num_bndry_ele));
816 int_array bndry_att_vals = n_bndry_mesh_att[
"values"].value();
817 for (
int i = 0; i < num_bndry_ele; i++)
835 Node &n_adjset = n_mesh[
"adjsets"][main_adjset_name];
837 n_adjset[
"association"] =
"vertex";
838 n_adjset[
"topology"] = main_topology_name;
839 n_adjset[
"groups"].set(DataType::object());
842 const int local_rank = pmesh->
GetMyRank();
843 const int num_groups = pmesh_gtopo.
NGroups();
845 for (
int i = 1; i < num_groups; i++)
848 const int *group_nbrs = pmesh_gtopo.
GetGroup(i);
855 std::string group_name =
"group";
857 for (
int j = 0; j < num_group_nbrs; j++)
862 for (
int j = 0; j < num_group_nbrs; j++)
864 group_name +=
"_" + std::to_string(group_ranks[j]);
872 Node &n_group = n_adjset[
"groups"][group_name];
874 n_group[
"neighbors"].set(group_ranks.
GetData(), group_ranks.
Size());
875 n_group[
"values"].set(DataType::c_int(num_group_verts));
877 int_array group_vals = n_group[
"values"].value();
878 for (
int j = 0; j < num_group_verts; j++)
895 Node &n_domid = n_mesh[
"state/domain_id"];
896 n_domid.set(local_rank);
905 const std::string &main_topology_name)
908 n_field[
"topology"] = main_topology_name;
915 n_field[
"values"].set_external(gf->
GetData(),
928 index_t stride =
sizeof(double) * entry_stride;
930 for (
int d = 0; d < vdim; d++)
932 std::ostringstream oss;
934 std::string comp_name = oss.str();
935 n_field[
"values"][comp_name].set_external(gf->
GetData(),
939 offset +=
sizeof(double) * vdim_stride;
970 const std::string &relay_protocol)
999 std::ostringstream oss;
1017 const std::string &relay_protocol)
1020 std::string root_proto =
"json";
1022 if (relay_protocol ==
"hdf5")
1029 Node &n_bp_idx = n_root[
"blueprint_index"];
1031 blueprint::mesh::generate_index(n_mesh,
1043 std::string gf_name = itr->first;
1046 Node &idx_gf_ncomps = n_bp_idx[
"mesh/fields"][gf_name][
"number_of_components"];
1049 if ( idx_gf_ncomps.to_int() != gf->
VectorDim() )
1056 n_root[
"protocol/version"] =
"0.3.1";
1060 n_root[
"number_of_files"] = num_domains;
1061 n_root[
"number_of_trees"] = num_domains;
1063 n_root[
"tree_pattern"] =
"";
1066 n_root[
"blueprint_index/mesh/state/time"] =
time;
1067 n_root[
"blueprint_index/mesh/state/time_step"] =
time_step;
1068 n_root[
"blueprint_index/mesh/state/cycle"] =
cycle;
1077 const std::string &relay_protocol)
1079 relay::io::save(n_mesh,
MeshFileName(domain_id, relay_protocol));
1089 std::string root_protocol =
"json";
1093 root_protocol =
"hdf5";
1097 relay::io::load(
RootFileName(), root_protocol, root_out);
1104 std::string root_json = root_out.to_json();
1106 int json_str_size = root_json.size() + 1;
1109 int mpi_status = MPI_Bcast((
void*)&json_str_size,
1115 if (mpi_status != MPI_SUCCESS)
1117 MFEM_ABORT(
"Broadcast of root file json string size failed");
1121 mpi_status = MPI_Bcast((
void*)root_json.c_str(),
1127 if (mpi_status != MPI_SUCCESS)
1129 MFEM_ABORT(
"Broadcast of root file json string failed");
1139 int json_str_size = -1;
1140 int mpi_status = MPI_Bcast(&json_str_size,
1146 if (mpi_status != MPI_SUCCESS)
1148 MFEM_ABORT(
"Broadcast of root file json string size failed");
1152 char *json_buff =
new char[json_str_size];
1153 mpi_status = MPI_Bcast(json_buff,
1159 if (mpi_status != MPI_SUCCESS)
1161 MFEM_ABORT(
"Broadcast of root file json string failed");
1165 Generator g(std::string(json_buff),
"json");
1168 delete [] json_buff;
1176 const std::string &relay_protocol)
1182 relay::io::load(
MeshFileName(domain_id, relay_protocol), n_mesh);
1186 if (!blueprint::mesh::verify(n_mesh,verify_info))
1188 MFEM_ABORT(
"Conduit Mesh Blueprint Verify Failed:\n"
1189 << verify_info.to_json());
1196 NodeConstIterator itr = n_mesh[
"fields"].children();
1198 std::string nodes_gf_name =
"";
1200 const Node &n_topo = n_mesh[
"topologies/main"];
1201 if (n_topo.has_child(
"grid_function"))
1203 nodes_gf_name = n_topo[
"grid_function"].as_string();
1206 while (itr.has_next())
1208 const Node &n_field = itr.next();
1209 std::string field_name = itr.name();
1213 if ( field_name != nodes_gf_name &&
1214 field_name.find(
"_attribute") == std::string::npos
1233 ConduitDataCollection::ElementTypeToShapeName(
Element::Type element_type)
1242 switch (element_type)
1259 ConduitDataCollection::ShapeNameToGeomType(
const std::string &shape_name)
1265 if (shape_name ==
"point")
1269 else if (shape_name ==
"line")
1273 else if (shape_name ==
"tri")
1277 else if (shape_name ==
"quad")
1281 else if (shape_name ==
"tet")
1285 else if (shape_name ==
"hex")
1291 MFEM_ABORT(
"Unsupported Element Shape: " << shape_name);
Geometry::Type GetGeometryType() const
Ordering::Type GetOrdering() const
Return the ordering method.
int Size() const
Return the logical size of the array.
int GetNDofs() const
Returns number of degrees of freedom.
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
const double * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Class for grid function - Vector with associated FE space.
void SaveMeshAndFields(int domain_id, const conduit::Node &n_mesh, const std::string &file_protocol)
Saves all meshes and fields for the current cycle.
int GroupNVertices(int group) const
bool appendRankToFileName
Append rank to any output file names.
iterator begin()
Returns a begin iterator to the registered fields.
virtual void GetVertices(Array< int > &v) const =0
Returns element's vertices.
std::string RootFileName()
Returns blueprint root file name for the current cycle.
void DeleteAll()
Delete data owned by the DataCollection including field information.
virtual bool HasBoundaryElements() const
Checks if the mesh has boundary elements.
int GetNBE() const
Returns number of boundary elements.
iterator end()
Returns an end iterator to the registered fields.
int pad_digits_cycle
Number of digits used for the cycle and MPI rank in filenames.
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
int GetGroupSize(int g) const
Get the number of processors in a group.
Element::Type GetElementType(int i) const
Returns the type of element i.
const int * GetGroup(int g) const
Return a pointer to a list of neighbors for a given group. Neighbor 0 is the local processor...
T * GetData()
Returns the data.
int GetNE() const
Returns number of elements.
static void MeshToBlueprintMesh(Mesh *m, conduit::Node &out, const std::string &coordset_name="coords", const std::string &main_topology_name="main", const std::string &boundary_topology_name="boundary", const std::string &main_adjset_name="main_adjset")
Describes a MFEM mesh using the mesh blueprint.
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
bool own_data
Should the collection delete its mesh and fields.
void DeleteFirst(const T &el)
Delete the first entry with value == 'el'.
double * GetData() const
Return a pointer to the beginning of the Vector data.
Geometry::Type GetElementBaseGeometry(int i) const
std::string relay_protocol
virtual void Load(int cycle=0)
Load the collection based blueprint data.
ConduitDataCollection(const std::string &collection_name, Mesh *mesh=NULL)
Constructor. The collection name is used when saving the data.
MPI_Comm m_comm
Associated MPI communicator.
double time
Physical time (for time-dependent simulations)
static Mesh * BlueprintMeshToMesh(const conduit::Node &n_mesh, const std::string &main_toplogy_name="", bool zero_copy=false)
Constructs and MFEM mesh from a Conduit Blueprint Description.
Mesh * mesh
The (common) mesh for the collected fields.
virtual ~ConduitDataCollection()
We will delete the mesh and fields if we own them.
int cycle
Time cycle; for time-dependent simulations cycle >= 0, otherwise = -1.
std::string MeshFileName(int domain_id, const std::string &file_protocol="hdf5")
Returns the mesh file name for a given domain at the current cycle.
std::string to_padded_string(int i, int digits)
Convert an integer to a 0-padded string with the given number of digits.
static const int NumVerts[NumGeom]
Type
Constants for the classes derived from Element.
static int create_directory(const std::string &dir_name, const Mesh *mesh, int myid)
virtual void Save()
Save the collection and a Conduit blueprint root file.
void Register(const std::string &fname, T *field, bool own_data)
Register field field with name fname.
const Element * GetElement(int i) const
void LoadRootFile(conduit::Node &n_root_out)
Loads contents of the root field for the current cycle into n_root_out.
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
int GetVDim() const
Returns vector dimension.
FiniteElementSpace * FESpace()
int SpaceDimension() const
void SaveRootFile(int num_domains, const conduit::Node &n_mesh, const std::string &file_protocol)
Saves root file for the current cycle.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
void LoadMeshAndFields(int domain_id, const std::string &file_protocol)
Loads all meshes and fields of a given domain id for the current cycle.
int GetNeighborRank(int i) const
Return the MPI rank of neighbor 'i'.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
int myid
MPI rank (in parallel)
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name...
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
virtual const char * Name() const
GFieldMap::const_iterator FieldMapConstIterator
void clear()
Clears the map of registered fields without reclaiming memory.
std::string MeshDirectoryName()
Returns the mesh output directory for the current cycle.
std::string prefix_path
A path where the directory with results is saved. If not empty, it has '/' at the end...
int NGroups() const
Return the number of groups.
int GroupVertex(int group, int i) const
const FiniteElementCollection * FEColl() const
void GetNodes(Vector &node_coord) const
std::string name
Name of the collection, used as a directory name when saving.
std::string MeshFilePattern(const std::string &file_protocol="hdf5")
Returns the mesh file pattern for the current cycle.
static void GridFunctionToBlueprintField(GridFunction *gf, conduit::Node &out, const std::string &main_topology_name="main")
Describes a MFEM grid function using the mesh blueprint.
double time_step
Time step i.e. delta_t (for time-dependent simulations)
int num_procs
Number of MPI ranks (in parallel)
static GridFunction * BlueprintFieldToGridFunction(Mesh *mesh, const conduit::Node &n_field, bool zero_copy=false)
Constructs and MFEM Grid Function from a Conduit Blueprint Description.
Class for parallel meshes.
Abstract data type element.
int GetAttribute(int i) const
Return the attribute of element i.
virtual Type GetType() const =0
Returns element's type.
void SetProtocol(const std::string &protocol)
Set the Conduit relay i/o protocol to use.
const Element * GetBdrElement(int i) const