1260 lines
40 KiB
C++
1260 lines
40 KiB
C++
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
|
|
#include "../config/config.hpp"
|
|
|
|
#ifdef MFEM_USE_SIDRE
|
|
|
|
#include "fem.hpp"
|
|
|
|
#include <axom/sidre.hpp>
|
|
|
|
#include <string>
|
|
#include <iomanip> // for setw, setfill
|
|
#include <cstdio> // for snprintf()
|
|
|
|
namespace sidre = axom::sidre;
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
// Constructor that will automatically create the sidre data store and necessary
|
|
// data groups for domain and global data.
|
|
SidreDataCollection::SidreDataCollection(const std::string& collection_name,
|
|
Mesh * the_mesh, bool own_mesh_data)
|
|
: mfem::DataCollection(collection_name, the_mesh),
|
|
m_owns_datastore(true),
|
|
m_owns_mesh_data(own_mesh_data),
|
|
m_meshNodesGFName("mesh_nodes")
|
|
{
|
|
m_datastore_ptr = new sidre::DataStore();
|
|
|
|
sidre::Group * global_grp =
|
|
m_datastore_ptr->getRoot()->createGroup(collection_name + "_global");
|
|
sidre::Group * domain_grp =
|
|
m_datastore_ptr->getRoot()->createGroup(collection_name);
|
|
|
|
m_bp_grp = domain_grp->createGroup("blueprint");
|
|
// Currently only rank 0 adds anything to bp_index.
|
|
m_bp_index_grp = global_grp->createGroup("blueprint_index/" + name);
|
|
|
|
m_named_bufs_grp = domain_grp->createGroup("named_buffers");
|
|
|
|
if (the_mesh)
|
|
{
|
|
SetMesh(the_mesh);
|
|
}
|
|
#ifdef MFEM_USE_MPI
|
|
else
|
|
{
|
|
m_comm = MPI_COMM_NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Second constructor that allows external code to specify data groups to place
|
|
// domain and global data in.
|
|
|
|
// TODO - Conduit will have the capability to generate a blueprint index group
|
|
// in the future. When this is available, all the blueprint index code can be
|
|
// removed from the data collection class.
|
|
SidreDataCollection::SidreDataCollection(const std::string& collection_name,
|
|
axom::sidre::Group* bp_index_grp,
|
|
axom::sidre::Group* domain_grp,
|
|
bool own_mesh_data)
|
|
: mfem::DataCollection(collection_name),
|
|
m_owns_datastore(false),
|
|
m_owns_mesh_data(own_mesh_data),
|
|
m_meshNodesGFName("mesh_nodes"),
|
|
m_datastore_ptr(NULL),
|
|
m_bp_index_grp(bp_index_grp)
|
|
{
|
|
m_bp_grp = domain_grp->createGroup("blueprint");
|
|
|
|
m_named_bufs_grp = domain_grp->createGroup("named_buffers");
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
m_comm = MPI_COMM_NULL;
|
|
#endif
|
|
}
|
|
|
|
SidreDataCollection::~SidreDataCollection()
|
|
{
|
|
attr_map.DeleteData(true);
|
|
if (m_owns_datastore)
|
|
{
|
|
delete m_datastore_ptr;
|
|
}
|
|
}
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
void SidreDataCollection::SetComm(MPI_Comm comm)
|
|
{
|
|
m_comm = comm;
|
|
serial = false;
|
|
appendRankToFileName = true;
|
|
MPI_Comm_rank(m_comm, &myid);
|
|
MPI_Comm_size(m_comm, &num_procs);
|
|
}
|
|
#endif
|
|
|
|
// protected method
|
|
sidre::Group *SidreDataCollection::named_buffers_grp() const
|
|
{
|
|
MFEM_ASSERT(m_named_bufs_grp != NULL,
|
|
"No group 'named_buffers' in data collection. Verify that"
|
|
" SetMesh was called to set the mesh in the data collection.");
|
|
return m_named_bufs_grp;
|
|
}
|
|
|
|
// protected method
|
|
axom::sidre::View *
|
|
SidreDataCollection::alloc_view(axom::sidre::Group *grp,
|
|
const std::string &view_name)
|
|
{
|
|
MFEM_ASSERT(grp, "Group pointer is NULL");
|
|
sidre::View *v = NULL;
|
|
|
|
if (! grp->hasView(view_name) )
|
|
{
|
|
v = grp->createView(view_name);
|
|
MFEM_ASSERT(v, "error allocating View " << view_name
|
|
<< " in group " << grp->getPathName());
|
|
}
|
|
else
|
|
{
|
|
v = grp->getView(view_name);
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
// protected method
|
|
axom::sidre::View *
|
|
SidreDataCollection::alloc_view(axom::sidre::Group *grp,
|
|
const std::string &view_name,
|
|
const axom::sidre::DataType &dtype)
|
|
{
|
|
MFEM_ASSERT(grp, "Group pointer is NULL");
|
|
sidre::View *v = NULL;
|
|
|
|
if (! grp->hasView(view_name))
|
|
{
|
|
v = grp->createView(view_name, dtype);
|
|
MFEM_ASSERT(v, "error allocating View " << view_name
|
|
<< " in group " << grp->getPathName());
|
|
}
|
|
else
|
|
{
|
|
v = grp->getView(view_name);
|
|
MFEM_ASSERT(v->getSchema().dtype().equals(dtype), "");
|
|
}
|
|
return v;
|
|
}
|
|
|
|
// protected method
|
|
axom::sidre::Group *
|
|
SidreDataCollection::alloc_group(axom::sidre::Group *grp,
|
|
const std::string &group_name)
|
|
{
|
|
MFEM_ASSERT(grp, "Group pointer is NULL");
|
|
sidre::Group *g = NULL;
|
|
|
|
if (! grp->hasGroup(group_name) )
|
|
{
|
|
g = grp->createGroup(group_name);
|
|
MFEM_ASSERT(g, "error allocating Group " << group_name
|
|
<< " in group " << grp->getPathName());
|
|
}
|
|
else
|
|
{
|
|
g = grp->getGroup(group_name);
|
|
}
|
|
return g;
|
|
}
|
|
|
|
// protected method
|
|
std::string
|
|
SidreDataCollection::get_file_path(const std::string &filename) const
|
|
{
|
|
std::stringstream fNameSstr;
|
|
|
|
// Note: If non-empty, prefix_path has a separator ('/') at the end
|
|
fNameSstr << prefix_path << filename;
|
|
|
|
if (GetCycle() >= 0)
|
|
{
|
|
fNameSstr << "_" << std::setfill('0') << std::setw(pad_digits_cycle)
|
|
<< GetCycle();
|
|
}
|
|
|
|
return fNameSstr.str();
|
|
}
|
|
|
|
axom::sidre::View *
|
|
SidreDataCollection::AllocNamedBuffer(const std::string& buffer_name,
|
|
axom::sidre::IndexType sz,
|
|
axom::sidre::TypeID type)
|
|
{
|
|
sz = std::max(sz, sidre::IndexType(0));
|
|
sidre::Group *f = named_buffers_grp();
|
|
sidre::View *v = NULL;
|
|
|
|
if (! f->hasView(buffer_name) )
|
|
{
|
|
// create a buffer view
|
|
v = f->createViewAndAllocate(buffer_name, type, sz);
|
|
}
|
|
else
|
|
{
|
|
v = f->getView(buffer_name);
|
|
MFEM_ASSERT(v->getTypeID() == type, "type does not match existing type");
|
|
|
|
// Here v is the view holding the buffer in the named_buffers group, so
|
|
// its size is the full size of the buffer.
|
|
|
|
// check if we need to resize.
|
|
if (!v->isApplied() || v->getNumElements() < sz)
|
|
{
|
|
// resize, even if the buffer has more than 1 View.
|
|
// v->reallocate(sz); // this will not work for more than 1 view.
|
|
sidre::DataType dtype(v->getSchema().dtype());
|
|
dtype.set_number_of_elements(sz);
|
|
f->destroyViewAndData(buffer_name);
|
|
v = f->createViewAndAllocate(buffer_name, dtype);
|
|
}
|
|
}
|
|
MFEM_ASSERT(v && v->isApplied(), "allocation failed");
|
|
return v;
|
|
}
|
|
|
|
// private method
|
|
void SidreDataCollection::createMeshBlueprintStubs(bool hasBP)
|
|
{
|
|
if (!hasBP)
|
|
{
|
|
m_bp_grp->createGroup("state");
|
|
m_bp_grp->createGroup("coordsets");
|
|
m_bp_grp->createGroup("topologies");
|
|
m_bp_grp->createGroup("fields");
|
|
}
|
|
|
|
// If rank is 0, set up blueprint index state group.
|
|
if (myid == 0)
|
|
{
|
|
m_bp_index_grp->createGroup("state");
|
|
m_bp_index_grp->createGroup("coordsets");
|
|
m_bp_index_grp->createGroup("topologies");
|
|
m_bp_index_grp->createGroup("fields");
|
|
}
|
|
}
|
|
|
|
// private method
|
|
void SidreDataCollection::createMeshBlueprintState(bool hasBP)
|
|
{
|
|
if (!hasBP)
|
|
{
|
|
// Set up blueprint state group.
|
|
m_bp_grp->createViewScalar("state/cycle", 0);
|
|
m_bp_grp->createViewScalar("state/time", 0.);
|
|
m_bp_grp->createViewScalar("state/domain", myid);
|
|
m_bp_grp->createViewScalar("state/time_step", 0.);
|
|
}
|
|
|
|
// If rank is 0, set up blueprint index state group.
|
|
if (myid == 0)
|
|
{
|
|
m_bp_index_grp->createViewScalar("state/cycle", 0);
|
|
m_bp_index_grp->createViewScalar("state/time", 0.);
|
|
m_bp_index_grp->createViewScalar("state/number_of_domains", num_procs);
|
|
}
|
|
}
|
|
|
|
// private method
|
|
void SidreDataCollection::createMeshBlueprintCoordset(bool hasBP)
|
|
{
|
|
int dim = mesh->SpaceDimension();
|
|
MFEM_ASSERT(dim >= 1 && dim <= 3, "invalid mesh dimension");
|
|
|
|
// Assuming mfem::Vertex has the layout of a double array.
|
|
const int NUM_COORDS = sizeof(mfem::Vertex) / sizeof(double);
|
|
|
|
const int num_vertices = mesh->GetNV();
|
|
const int coordset_len = NUM_COORDS * num_vertices;
|
|
|
|
// Add blueprint if not present
|
|
if ( !hasBP )
|
|
{
|
|
m_bp_grp->createViewString("coordsets/coords/type", "explicit");
|
|
|
|
sidre::DataType dtype =
|
|
sidre::DataType::c_double(num_vertices);
|
|
const size_t stride = dtype.stride();
|
|
dtype.set_stride(stride*NUM_COORDS);
|
|
|
|
// Set up views for x, y, z values
|
|
sidre::View *vx, *vy = NULL, *vz = NULL;
|
|
vx = m_bp_grp->createView("coordsets/coords/values/x", dtype);
|
|
|
|
if (dim >= 2)
|
|
{
|
|
dtype.set_offset(dtype.offset() + stride);
|
|
vy = m_bp_grp->createView("coordsets/coords/values/y", dtype);
|
|
}
|
|
if (dim >= 3)
|
|
{
|
|
dtype.set_offset(dtype.offset() + stride);
|
|
vz = m_bp_grp->createView("coordsets/coords/values/z", dtype);
|
|
}
|
|
|
|
if (m_owns_mesh_data)
|
|
{
|
|
// Allocate buffer for coord values.
|
|
sidre::Buffer* coordbuf =
|
|
AllocNamedBuffer("vertex_coords", coordset_len)->getBuffer();
|
|
|
|
vx->attachBuffer(coordbuf);
|
|
if (dim >= 2) { vy->attachBuffer(coordbuf); }
|
|
if (dim >= 3) { vz->attachBuffer(coordbuf); }
|
|
}
|
|
else
|
|
{
|
|
double *coordbuf = mesh->GetVertex(0);
|
|
|
|
vx->setExternalDataPtr(coordbuf);
|
|
if (dim >= 2) { vy->setExternalDataPtr(coordbuf); }
|
|
if (dim >= 3) { vz->setExternalDataPtr(coordbuf); }
|
|
}
|
|
|
|
}
|
|
|
|
// If rank 0, set up blueprint index for coordinate set.
|
|
if (myid == 0)
|
|
{
|
|
m_bp_index_grp->createViewString(
|
|
"coordsets/coords/path", m_bp_grp->getPathName() + "/coordsets/coords");
|
|
|
|
m_bp_index_grp->getGroup("coordsets/coords")->copyView(
|
|
m_bp_grp->getView("coordsets/coords/type") );
|
|
|
|
m_bp_index_grp->createViewString(
|
|
"coordsets/coords/coord_system/type", "cartesian");
|
|
|
|
// These are empty views, their existence in the group tree is used to
|
|
// define the number of dims
|
|
m_bp_index_grp->createView("coordsets/coords/coord_system/axes/x");
|
|
|
|
if (dim >= 2)
|
|
{
|
|
m_bp_index_grp->createView("coordsets/coords/coord_system/axes/y");
|
|
}
|
|
|
|
if (dim == 3)
|
|
{
|
|
m_bp_index_grp->createView("coordsets/coords/coord_system/axes/z");
|
|
}
|
|
}
|
|
|
|
if (m_owns_mesh_data)
|
|
{
|
|
double *coord_values = GetNamedBuffer("vertex_coords")->getData();
|
|
// Change ownership of the mesh vertex data to sidre
|
|
mesh->ChangeVertexDataOwnership(coord_values, coordset_len, hasBP);
|
|
}
|
|
}
|
|
|
|
// private method
|
|
void SidreDataCollection::
|
|
createMeshBlueprintTopologies(bool hasBP, const std::string& mesh_name)
|
|
{
|
|
const bool isBdry = (mesh_name == "boundary");
|
|
|
|
const int num_elements = !isBdry
|
|
? mesh->GetNE()
|
|
: mesh->GetNBE();
|
|
|
|
const std::string mesh_topo_str = "topologies/" + mesh_name;
|
|
const std::string mesh_attr_str = mesh_name + "_material_attribute";
|
|
|
|
int element_size = 0;
|
|
int num_indices = 0;
|
|
int geom = 0;
|
|
std::string eltTypeStr = "point";
|
|
|
|
if (num_elements > 0)
|
|
{
|
|
mfem::Element *elem = !isBdry
|
|
? mesh->GetElement(0)
|
|
: mesh->GetBdrElement(0);
|
|
element_size = elem->GetNVertices();
|
|
|
|
num_indices = num_elements * element_size;
|
|
|
|
// Find the element shape
|
|
// Note: Assumes homogeneous elements, so only check the first element
|
|
geom = elem->GetGeometryType();
|
|
eltTypeStr = getElementName(elem->GetType());
|
|
}
|
|
|
|
// Create the blueprint "topology" group, if not present
|
|
if ( !hasBP )
|
|
{
|
|
sidre::Group* topology_grp = m_bp_grp->createGroup(mesh_topo_str);
|
|
|
|
topology_grp->createViewString("type", "unstructured");
|
|
topology_grp->createViewString("elements/shape", eltTypeStr);
|
|
topology_grp->createViewAndAllocate(
|
|
"elements/connectivity", sidre::INT_ID, num_indices);
|
|
topology_grp->createViewString("coordset", "coords");
|
|
|
|
// If the mesh has nodes, set the name of the GridFunction holding the
|
|
// mesh nodes in the blueprint group.
|
|
if (!isBdry && mesh->GetNodes() != NULL)
|
|
{
|
|
topology_grp->createViewString("grid_function",m_meshNodesGFName);
|
|
}
|
|
}
|
|
|
|
// Add the mesh's attributes as an attribute field
|
|
RegisterAttributeField(mesh_attr_str, isBdry);
|
|
|
|
// Change ownership or copy the element arrays into Sidre
|
|
if (num_elements > 0)
|
|
{
|
|
sidre::View* conn_view =
|
|
m_bp_grp->getGroup(mesh_topo_str)->getView("elements/connectivity");
|
|
|
|
// The SidreDataCollection always owns these arrays:
|
|
Array<int> conn_array(conn_view->getData<int*>(), num_indices);
|
|
Array<int>* attr_array = attr_map.Get(mesh_attr_str);
|
|
if (!isBdry)
|
|
{
|
|
mesh->GetElementData(geom, conn_array, *attr_array);
|
|
}
|
|
else
|
|
{
|
|
mesh->GetBdrElementData(geom, conn_array, *attr_array);
|
|
}
|
|
MFEM_ASSERT(!conn_array.OwnsData(), "");
|
|
MFEM_ASSERT(!attr_array->OwnsData(), "");
|
|
}
|
|
|
|
// If rank 0, set up blueprint index for topologies group
|
|
if (myid == 0)
|
|
{
|
|
const std::string m_bp_grp_path = m_bp_grp->getPathName();
|
|
|
|
if (isBdry)
|
|
{
|
|
// "Shallow" copy the m_bp_grp view into the m_bp_index_grp sub-group.
|
|
// Note that the "topologies/mesh" sub-group has to exist, i.e. this
|
|
// method should be called first with mesh_name = "mesh".
|
|
m_bp_index_grp->getGroup("topologies/mesh")
|
|
->copyView( m_bp_grp->getView("topologies/mesh/boundary_topology") );
|
|
}
|
|
|
|
sidre::Group *bp_index_topo_grp =
|
|
m_bp_index_grp->createGroup(mesh_topo_str);
|
|
sidre::Group *topology_grp = m_bp_grp->getGroup(mesh_topo_str);
|
|
|
|
bp_index_topo_grp->createViewString(
|
|
"path", m_bp_grp_path + "/" + mesh_topo_str);
|
|
bp_index_topo_grp->copyView( topology_grp->getView("type") );
|
|
bp_index_topo_grp->copyView( topology_grp->getView("coordset") );
|
|
|
|
// If the mesh has nodes, set the name of the GridFunction holding the
|
|
// mesh nodes in the blueprint_index group.
|
|
if (!isBdry && mesh->GetNodes() != NULL)
|
|
{
|
|
bp_index_topo_grp->copyView(topology_grp->getView("grid_function"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// private method
|
|
#ifdef MFEM_USE_MPI
|
|
void SidreDataCollection::createMeshBlueprintAdjacencies(bool hasBP)
|
|
{
|
|
ParMesh *pmesh = dynamic_cast<ParMesh*>(mesh);
|
|
|
|
const int GRP_SZ = 25;
|
|
char group_str[GRP_SZ];
|
|
|
|
// TODO(JRC): Separate this out into group hierarchy setup and data allocation
|
|
// stages like all of the other "createMeshBlueprint*" functions.
|
|
MFEM_VERIFY(hasBP == false, "The case hasBP == true is not supported yet!");
|
|
|
|
sidre::Group* adjset_grp = NULL;
|
|
if (pmesh->GetNGroups() > 1)
|
|
{
|
|
adjset_grp = m_bp_grp->createGroup("adjsets/mesh");
|
|
adjset_grp->createViewString("association", "vertex");
|
|
adjset_grp->createViewString("topology", "mesh");
|
|
|
|
if (myid == 0) { m_bp_index_grp->createGroup("adjsets"); }
|
|
}
|
|
|
|
for (int gi = 1; gi < pmesh->GetNGroups(); ++gi)
|
|
{
|
|
int num_gneighbors = pmesh->gtopo.GetGroupSize(gi);
|
|
int num_gvertices = pmesh->GroupNVertices(gi);
|
|
|
|
// Skip creation of empty groups
|
|
if (num_gneighbors > 1 && num_gvertices > 0)
|
|
{
|
|
std::snprintf(group_str, GRP_SZ, "groups/g%d_%d",
|
|
pmesh->gtopo.GetGroupMasterRank(gi),
|
|
pmesh->gtopo.GetGroupMasterGroup(gi));
|
|
sidre::Group* group_grp = adjset_grp->createGroup(group_str);
|
|
|
|
sidre::View* gneighbors_view =
|
|
group_grp->createViewAndAllocate(
|
|
"neighbors", sidre::INT_ID, num_gneighbors - 1);
|
|
int* gneighbors_data = gneighbors_view->getData<int*>();
|
|
|
|
// skip local domain when adding Blueprint neighbors
|
|
const int* gneighbors = pmesh->gtopo.GetGroup(gi);
|
|
for (int ni = 0, noff = 0; ni < num_gneighbors; ++ni)
|
|
{
|
|
if ( gneighbors[ni] == 0 )
|
|
{
|
|
noff++;
|
|
}
|
|
else
|
|
{
|
|
gneighbors_data[ni - noff] =
|
|
pmesh->gtopo.GetNeighborRank(gneighbors[ni]);
|
|
}
|
|
}
|
|
|
|
sidre::View* gvertices_view =
|
|
group_grp->createViewAndAllocate(
|
|
"values", sidre::INT_ID, num_gvertices);
|
|
int* gvertices_data = gvertices_view->getData<int*>();
|
|
|
|
for (int vi = 0; vi < num_gvertices; ++vi)
|
|
{
|
|
gvertices_data[vi] = pmesh->GroupVertex(gi, vi);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// private method
|
|
void SidreDataCollection::verifyMeshBlueprint()
|
|
{
|
|
// Conduit will have a verify mesh blueprint capability in the future.
|
|
// Add call to that when it's available to check actual contents in sidre.
|
|
}
|
|
|
|
|
|
bool SidreDataCollection::HasBoundaryMesh() const
|
|
{
|
|
// check if this rank has any boundary elements
|
|
int hasBndElts = mesh->GetNBE() > 0 ? 1 : 0;
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
// check if any rank has boundary elements
|
|
ParMesh *pmesh = dynamic_cast<ParMesh*>(mesh);
|
|
if (pmesh)
|
|
{
|
|
int hasBndElts_g;
|
|
MPI_Allreduce(&hasBndElts, &hasBndElts_g, 1,
|
|
MPI_INT, MPI_MAX,pmesh->GetComm());
|
|
|
|
hasBndElts = hasBndElts_g;
|
|
}
|
|
#endif
|
|
|
|
return hasBndElts > 0? true : false;
|
|
}
|
|
|
|
void SidreDataCollection::SetMesh(Mesh *new_mesh)
|
|
{
|
|
DataCollection::SetMesh(new_mesh);
|
|
|
|
// hasBP is used to indicate if the data currently in the blueprint should be
|
|
// used to replace the data in the mesh.
|
|
bool hasBP = m_bp_grp->getNumViews() > 0 || m_bp_grp->getNumGroups() > 0;
|
|
bool has_bnd_elts = HasBoundaryMesh();
|
|
|
|
createMeshBlueprintStubs(hasBP);
|
|
createMeshBlueprintState(hasBP);
|
|
createMeshBlueprintCoordset(hasBP);
|
|
|
|
GridFunction *nodes = new_mesh->GetNodes();
|
|
|
|
// register the "mesh" topology in the blueprint.
|
|
createMeshBlueprintTopologies(hasBP, "mesh");
|
|
|
|
if (has_bnd_elts)
|
|
{
|
|
// Set the "boundary_topology" of "mesh" to "boundary".
|
|
m_bp_grp->createViewString("topologies/mesh/boundary_topology", "boundary");
|
|
|
|
// register the "boundary" topology in the blueprint.
|
|
createMeshBlueprintTopologies(hasBP, "boundary");
|
|
}
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
ParMesh *new_pmesh = dynamic_cast<ParMesh*>(new_mesh);
|
|
m_comm = new_pmesh ? new_pmesh->GetComm() : MPI_COMM_NULL;
|
|
if (new_pmesh)
|
|
{
|
|
createMeshBlueprintAdjacencies(hasBP);
|
|
}
|
|
#endif
|
|
|
|
if (nodes)
|
|
{
|
|
// See the comment at the definition of 'hasBP' above.
|
|
if (hasBP)
|
|
{
|
|
// Get the bp mesh nodes name.
|
|
sidre::View *v_bp_nodes_name =
|
|
m_bp_grp->getView("topologies/mesh/grid_function");
|
|
std::string bp_nodes_name(v_bp_nodes_name->getString());
|
|
|
|
// Check that the names match, e.g. when loading the collection.
|
|
MFEM_VERIFY(m_meshNodesGFName == bp_nodes_name,
|
|
"mismatch of requested and blueprint mesh nodes names");
|
|
// Support renaming bp_nodes_name --> m_meshNodesGFName ?
|
|
}
|
|
|
|
if (m_owns_mesh_data)
|
|
{
|
|
// Make sure Sidre owns the data of the new_mesh's Nodes.
|
|
if (!GetNamedBuffer(m_meshNodesGFName))
|
|
{
|
|
int sz = new_mesh->GetNodalFESpace()->GetVSize();
|
|
double *gfData = AllocNamedBuffer(m_meshNodesGFName, sz)->getData();
|
|
|
|
// See the comment at the definition of 'hasBP' above.
|
|
if (!hasBP)
|
|
{
|
|
MFEM_ASSERT(nodes->Size() == sz, "");
|
|
std::memcpy(gfData, nodes->GetData(), sizeof(double) * sz);
|
|
}
|
|
}
|
|
// Since the named buffer for m_meshNodesGFName exists, the call to
|
|
// RegisterField() below will replace the data of the nodes with the
|
|
// data from the named buffer.
|
|
}
|
|
else
|
|
{
|
|
// Make sure Sidre does not have a named buffer for m_meshNodesGFName.
|
|
MFEM_VERIFY(GetNamedBuffer(m_meshNodesGFName) == NULL, "");
|
|
}
|
|
|
|
RegisterField(m_meshNodesGFName, nodes);
|
|
|
|
if (own_data)
|
|
{
|
|
// Avoid double delete calls (for the nodes gf) when (own_data == true)
|
|
// and the new_mesh owns its Nodes --> take ownership from new_mesh.
|
|
// When new_mesh does not own its Nodes and (own_data == true), we can
|
|
// not take ownership --> verify that does not happen.
|
|
MFEM_VERIFY(new_mesh->OwnsNodes(), "mesh does not own its nodes, "
|
|
"can not take ownership");
|
|
new_mesh->SetNodesOwner(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
void SidreDataCollection::SetMesh(MPI_Comm comm, Mesh *new_mesh)
|
|
{
|
|
// use SidreDataCollection's custom SetMesh, then set MPI info
|
|
SetMesh(new_mesh);
|
|
|
|
m_comm = comm;
|
|
MPI_Comm_rank(comm, &myid);
|
|
MPI_Comm_size(comm, &num_procs);
|
|
}
|
|
#endif
|
|
|
|
void SidreDataCollection::
|
|
SetGroupPointers(axom::sidre::Group *bp_index_grp,
|
|
axom::sidre::Group *domain_grp)
|
|
{
|
|
MFEM_VERIFY(domain_grp->hasGroup("blueprint"),
|
|
"Domain group does not contain a blueprint group.");
|
|
|
|
m_bp_grp = domain_grp->getGroup("blueprint");
|
|
m_bp_index_grp = bp_index_grp;
|
|
m_named_bufs_grp = domain_grp->getGroup("named_buffers");
|
|
}
|
|
|
|
void SidreDataCollection::Load(const std::string& path,
|
|
const std::string& protocol)
|
|
{
|
|
DataCollection::DeleteAll();
|
|
// Reset DataStore?
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
if (m_comm != MPI_COMM_NULL)
|
|
{
|
|
axom::sidre::IOManager reader(m_comm);
|
|
reader.read(m_bp_grp->getDataStore()->getRoot(), path);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
m_bp_grp->load(path, protocol);
|
|
}
|
|
|
|
// If the data collection created the datastore, it knows the layout of where
|
|
// the domain and global groups are, and can restore them after the Load().
|
|
//
|
|
// If the data collection did not create the datastore, the host code must
|
|
// reset these pointers after the load operation and also reset the state
|
|
// variables.
|
|
if (m_owns_datastore)
|
|
{
|
|
SetGroupPointers(m_datastore_ptr->getRoot()->getGroup(name + "_global"),
|
|
m_datastore_ptr->getRoot()->getGroup(name));
|
|
|
|
UpdateStateFromDS();
|
|
}
|
|
}
|
|
|
|
void SidreDataCollection::LoadExternalData(const std::string& path)
|
|
{
|
|
#ifdef MFEM_USE_MPI
|
|
if (m_comm != MPI_COMM_NULL)
|
|
{
|
|
axom::sidre::IOManager reader(m_comm);
|
|
reader.loadExternalData(m_bp_grp->getDataStore()->getRoot(), path);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
m_bp_grp->loadExternalData(path);
|
|
}
|
|
}
|
|
|
|
void SidreDataCollection::UpdateStateFromDS()
|
|
{
|
|
SetTime( m_bp_grp->getView("state/time")->getData<double>() );
|
|
SetCycle( m_bp_grp->getView("state/cycle")->getData<int>() );
|
|
SetTimeStep( m_bp_grp->getView("state/time_step")->getData<double>() );
|
|
}
|
|
|
|
void SidreDataCollection::UpdateStateToDS()
|
|
{
|
|
m_bp_grp->getView("state/cycle")->setScalar(GetCycle());
|
|
m_bp_grp->getView("state/time")->setScalar(GetTime());
|
|
m_bp_grp->getView("state/time_step")->setScalar(GetTimeStep());
|
|
|
|
if (myid == 0)
|
|
{
|
|
m_bp_index_grp->getView("state/cycle")->setScalar(GetCycle());
|
|
m_bp_index_grp->getView("state/time")->setScalar(time);
|
|
}
|
|
}
|
|
|
|
void SidreDataCollection::PrepareToSave()
|
|
{
|
|
verifyMeshBlueprint();
|
|
UpdateStateToDS();
|
|
}
|
|
|
|
void SidreDataCollection::Save()
|
|
{
|
|
std::string filename = name;
|
|
std::string protocol = "sidre_hdf5";
|
|
|
|
Save(filename, protocol);
|
|
}
|
|
|
|
void SidreDataCollection::Save(const std::string& filename,
|
|
const std::string& protocol)
|
|
{
|
|
PrepareToSave();
|
|
|
|
create_directory(prefix_path, mesh, myid);
|
|
|
|
std::string file_path = get_file_path(filename);
|
|
|
|
sidre::Group * blueprint_indicies_grp = m_bp_index_grp->getParent();
|
|
#ifdef MFEM_USE_MPI
|
|
if (m_comm != MPI_COMM_NULL)
|
|
{
|
|
axom::sidre::IOManager writer(m_comm);
|
|
sidre::DataStore *datastore = m_bp_grp->getDataStore();
|
|
writer.write(datastore->getRoot(), num_procs, file_path, protocol);
|
|
if (myid == 0)
|
|
{
|
|
if (protocol == "sidre_hdf5")
|
|
{
|
|
writer.writeGroupToRootFile(blueprint_indicies_grp,
|
|
file_path + ".root");
|
|
}
|
|
// Root file support only available in hdf5.
|
|
else
|
|
{
|
|
writer.write(blueprint_indicies_grp, 1,
|
|
file_path + ".root", protocol);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// If serial, use sidre group writer.
|
|
m_bp_grp->save(file_path, protocol);
|
|
|
|
blueprint_indicies_grp
|
|
->save(file_path + ".root", protocol);
|
|
}
|
|
}
|
|
|
|
// private method
|
|
void SidreDataCollection::
|
|
addScalarBasedGridFunction(const std::string &field_name, GridFunction *gf,
|
|
const std::string &buffer_name,
|
|
axom::sidre::IndexType offset)
|
|
{
|
|
sidre::Group* grp = m_bp_grp->getGroup("fields/" + field_name);
|
|
MFEM_ASSERT(grp != NULL, "field " << field_name << " does not exist");
|
|
|
|
const int numDofs = gf->FESpace()->GetVSize();
|
|
|
|
if (gf->GetData() == NULL)
|
|
{
|
|
AllocNamedBuffer(buffer_name, offset + numDofs);
|
|
// gf->data is set below.
|
|
}
|
|
|
|
/*
|
|
* Mesh blueprint for a scalar-based grid function is of the form
|
|
* /fields/field_name/basis
|
|
* -- string value is GridFunction's FEC::Name
|
|
* /fields/field_name/values
|
|
* -- array of size numDofs
|
|
*/
|
|
|
|
// Make sure we have the View "values".
|
|
sidre::View *vv = alloc_view(grp, "values");
|
|
|
|
// Describe and apply the "values" View.
|
|
// If the data store has buffer for field_name (e.g. AllocNamedBuffer was
|
|
// called, or it was loaded from file), use that buffer.
|
|
sidre::View *bv = named_buffers_grp()->getView(buffer_name);
|
|
if (bv)
|
|
{
|
|
MFEM_ASSERT(bv->hasBuffer() && bv->isDescribed(), "");
|
|
|
|
// named buffers always have offset 0
|
|
MFEM_ASSERT(bv->getSchema().dtype().offset() == 0, "");
|
|
MFEM_ASSERT(bv->getNumElements() >= offset + numDofs, "");
|
|
|
|
if (vv->isEmpty())
|
|
{
|
|
vv->attachBuffer(bv->getBuffer())
|
|
->apply(sidre::DOUBLE_ID, numDofs, offset);
|
|
}
|
|
|
|
gf->NewDataAndSize(vv->getData(), numDofs);
|
|
}
|
|
else
|
|
{
|
|
// If we are not managing the grid function's data,
|
|
// create a view with the external data
|
|
vv->setExternalDataPtr(sidre::DOUBLE_ID, numDofs, gf->GetData());
|
|
}
|
|
MFEM_ASSERT((numDofs > 0 && vv->isApplied()) ||
|
|
(numDofs == 0 && vv->isEmpty() && vv->isDescribed()),
|
|
"invalid View state");
|
|
MFEM_ASSERT(numDofs == 0 || vv->getData() == gf->GetData(),
|
|
"View data is different from GridFunction data");
|
|
MFEM_ASSERT(vv->getNumElements() == numDofs,
|
|
"View size is different from GridFunction size");
|
|
}
|
|
|
|
// private method
|
|
void SidreDataCollection::
|
|
addVectorBasedGridFunction(const std::string& field_name, GridFunction *gf,
|
|
const std::string &buffer_name,
|
|
axom::sidre::IndexType offset)
|
|
{
|
|
sidre::Group* grp = m_bp_grp->getGroup("fields/" + field_name);
|
|
MFEM_ASSERT(grp != NULL, "field " << field_name << " does not exist");
|
|
|
|
const int FLD_SZ = 20;
|
|
char fidxName[FLD_SZ];
|
|
|
|
int vdim = gf->FESpace()->GetVDim();
|
|
int ndof = gf->FESpace()->GetNDofs();
|
|
Ordering::Type ordering = gf->FESpace()->GetOrdering();
|
|
|
|
if (gf->GetData() == NULL)
|
|
{
|
|
AllocNamedBuffer(buffer_name, offset + vdim*ndof);
|
|
// gf->data is set below.
|
|
}
|
|
|
|
/*
|
|
* Mesh blueprint for a vector-based grid function is of the form
|
|
* /fields/field_name/basis
|
|
* -- string value is GridFunction's FEC::Name
|
|
* /fields/field_name/values/x0
|
|
* /fields/field_name/values/x1
|
|
* ...
|
|
* /fields/field_name/values/xn
|
|
* -- each coordinate is an array of size ndof
|
|
*/
|
|
|
|
// Get/create the Group "values".
|
|
sidre::Group *vg = alloc_group(grp, "values");
|
|
|
|
// Create the Views "x0", "x1", etc inside the "values" Group, vg.
|
|
// If we have a named buffer for field_name, attach it to the Views;
|
|
// otherwise set the Views to use gf->GetData() as external data.
|
|
sidre::DataType dtype = sidre::DataType::c_double(ndof);
|
|
const int entry_stride = (ordering == Ordering::byNODES ? 1 : vdim);
|
|
const int vdim_stride = (ordering == Ordering::byNODES ? ndof : 1);
|
|
dtype.set_stride(dtype.stride()*entry_stride);
|
|
|
|
sidre::View *bv = named_buffers_grp()->getView(buffer_name);
|
|
if (bv)
|
|
{
|
|
MFEM_ASSERT(bv->hasBuffer() && bv->isDescribed(), "");
|
|
|
|
// named buffers always have offset 0
|
|
MFEM_ASSERT(bv->getSchema().dtype().offset() == 0, "");
|
|
dtype.set_offset(dtype.element_bytes()*offset);
|
|
|
|
for (int d = 0; d < vdim; d++)
|
|
{
|
|
std::snprintf(fidxName, FLD_SZ, "x%d", d);
|
|
sidre::View *xv = alloc_view(vg, fidxName, dtype);
|
|
xv->attachBuffer(bv->getBuffer());
|
|
dtype.set_offset(dtype.offset() + dtype.element_bytes()*vdim_stride);
|
|
}
|
|
|
|
gf->NewDataAndSize(bv->getData<double*>() + offset, vdim*ndof);
|
|
}
|
|
else
|
|
{
|
|
for (int d = 0; d < vdim; d++)
|
|
{
|
|
std::snprintf(fidxName, FLD_SZ, "x%d", d);
|
|
sidre::View *xv = alloc_view(vg, fidxName, dtype);
|
|
xv->setExternalDataPtr(gf->GetData());
|
|
dtype.set_offset(dtype.offset() + dtype.element_bytes()*vdim_stride);
|
|
}
|
|
}
|
|
|
|
#ifdef MFEM_DEBUG
|
|
for (int d = 0; d < vdim; d++)
|
|
{
|
|
std::snprintf(fidxName, FLD_SZ, "x%d", d);
|
|
sidre::View *xv = vg->getView(fidxName);
|
|
MFEM_ASSERT((ndof > 0 && xv->isApplied()) ||
|
|
(ndof == 0 && xv->isEmpty() && xv->isDescribed()),
|
|
"invalid View state");
|
|
MFEM_ASSERT(ndof == 0 || xv->getData() == gf->GetData() + d*vdim_stride,
|
|
"View data is different from GridFunction data");
|
|
MFEM_ASSERT(xv->getNumElements() == ndof,
|
|
"View size is different from GridFunction size");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// private method
|
|
// Should only be called on mpi rank 0 ( or if serial problem ).
|
|
void SidreDataCollection::
|
|
RegisterFieldInBPIndex(const std::string& field_name, GridFunction *gf)
|
|
{
|
|
sidre::Group *bp_field_grp = m_bp_grp->getGroup("fields/" + field_name);
|
|
sidre::Group *bp_index_field_grp =
|
|
m_bp_index_grp->createGroup("fields/" + field_name);
|
|
|
|
bp_index_field_grp->createViewString( "path", bp_field_grp->getPathName() );
|
|
bp_index_field_grp->copyView( bp_field_grp->getView("topology") );
|
|
bp_index_field_grp->copyView( bp_field_grp->getView("basis") );
|
|
|
|
// Note: The bp index requires GridFunction::VectorDim()
|
|
// since the GF might be scalar valued and have a vector basis
|
|
// (e.g. hdiv and hcurl spaces)
|
|
const int number_of_components = gf->VectorDim();
|
|
bp_index_field_grp->createViewScalar("number_of_components",
|
|
number_of_components);
|
|
}
|
|
|
|
// private method
|
|
// Should only be called on mpi rank 0 ( or if serial problem ).
|
|
void SidreDataCollection::
|
|
DeregisterFieldInBPIndex(const std::string& field_name)
|
|
{
|
|
sidre::Group * fields_grp = m_bp_index_grp->getGroup("fields");
|
|
MFEM_VERIFY(fields_grp->hasGroup(field_name),
|
|
"No field exists in blueprint index with name " << name);
|
|
|
|
// Note: This will destroy all orphaned views or buffer classes under this
|
|
// group also. If sidre owns this field data, the memory will be deleted
|
|
// unless it's referenced somewhere else in sidre.
|
|
fields_grp->destroyGroup(field_name);
|
|
}
|
|
|
|
void SidreDataCollection::RegisterField(const std::string &field_name,
|
|
GridFunction *gf,
|
|
const std::string &buffer_name,
|
|
axom::sidre::IndexType offset)
|
|
{
|
|
if ( field_name.empty() || buffer_name.empty() ||
|
|
gf == NULL || gf->FESpace() == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Register field_name in the blueprint group.
|
|
sidre::Group* f = m_bp_grp->getGroup("fields");
|
|
|
|
if (f->hasGroup( field_name ))
|
|
{
|
|
// There are two possibilities:
|
|
// 1. If HasField(field_name) is true - we are overwriting a field that
|
|
// was previously registered.
|
|
// 2. Otherwise, the field was loaded from a file, or defined outside of
|
|
// the data collection.
|
|
if (HasField(field_name))
|
|
{
|
|
#ifdef MFEM_DEBUG
|
|
// Warn about overwriting field.
|
|
// Skip warning when re-registering the nodal grid function
|
|
if (field_name != m_meshNodesGFName)
|
|
{
|
|
MFEM_WARNING("field with the name '" << field_name<< "' is already "
|
|
"registered, overwriting the old field");
|
|
}
|
|
#endif
|
|
DeregisterField(field_name);
|
|
}
|
|
}
|
|
|
|
sidre::Group* grp = f->createGroup( field_name );
|
|
|
|
// Set the "basis" string using the gf's finite element space, overwrite if
|
|
// necessary.
|
|
sidre::View *v = alloc_view(grp, "basis");
|
|
v->setString(gf->FESpace()->FEColl()->Name());
|
|
|
|
// Set the topology of the GridFunction.
|
|
// This is always 'mesh' except for a special case with the boundary material
|
|
// attributes field.
|
|
v = alloc_view(grp, "topology")->setString("mesh");
|
|
|
|
MFEM_ASSERT(gf->Size() == gf->FESpace()->GetVSize(),
|
|
"GridFunction size does not match FiniteElementSpace size");
|
|
|
|
// Set the data views of the grid function
|
|
// e.g. the number of coefficients per DoF -- either scalar-valued or
|
|
// vector-valued
|
|
bool const isScalarValued = (gf->FESpace()->GetVDim() == 1);
|
|
if (isScalarValued)
|
|
{
|
|
// Set the View "<m_bp_grp>/fields/<field_name>/values"
|
|
addScalarBasedGridFunction(field_name, gf, buffer_name, offset);
|
|
}
|
|
else // vector valued
|
|
{
|
|
// Set the Group "<m_bp_grp>/fields/<field_name>/values"
|
|
addVectorBasedGridFunction(field_name, gf, buffer_name, offset);
|
|
}
|
|
|
|
// Register field_name in the blueprint_index group.
|
|
if (myid == 0)
|
|
{
|
|
RegisterFieldInBPIndex(field_name, gf);
|
|
}
|
|
|
|
// Register field_name + gf in field_map.
|
|
DataCollection::RegisterField(field_name, gf);
|
|
}
|
|
|
|
void SidreDataCollection::RegisterAttributeField(const std::string& attr_name,
|
|
bool is_bdry)
|
|
{
|
|
MFEM_ASSERT(
|
|
mesh != NULL,
|
|
"Need to set mesh before registering attributes in SidreDataCollection.");
|
|
|
|
// Register attr_name in the blueprint group.
|
|
sidre::Group* f = m_bp_grp->getGroup("fields");
|
|
if (f->hasGroup( attr_name ))
|
|
{
|
|
bool isAttr = attr_map.Has(attr_name);
|
|
bool isFld = field_map.Has(attr_name);
|
|
|
|
if (isAttr)
|
|
{
|
|
MFEM_WARNING("field with the name '" << attr_name << "' is already "
|
|
" registered as an attribute, overwriting old values.");
|
|
DeregisterAttributeField(attr_name);
|
|
}
|
|
else if (isFld)
|
|
{
|
|
MFEM_WARNING("field with the name '" << attr_name << "' is already "
|
|
" registered as a field, skipping register attribute.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Generate sidre views and groups for this mesh attribute and allocate space
|
|
addIntegerAttributeField(attr_name, is_bdry);
|
|
|
|
if (myid == 0)
|
|
{
|
|
RegisterAttributeFieldInBPIndex(attr_name);
|
|
}
|
|
|
|
// Register new attribute array with attr_map
|
|
sidre::View* a =
|
|
m_bp_grp->getGroup("fields")->getGroup(attr_name)->getView("values");
|
|
Array<int>* attr = new Array<int>(a->getData<int*>(), a->getNumElements());
|
|
|
|
attr_map.Register(attr_name, attr, true);
|
|
}
|
|
|
|
void SidreDataCollection::RegisterAttributeFieldInBPIndex(
|
|
const std::string& attr_name)
|
|
{
|
|
const std::string m_bp_grp_path = m_bp_grp->getPathName();
|
|
|
|
MFEM_ASSERT(m_bp_grp->getGroup("fields") != NULL,
|
|
"Mesh blueprint does not have 'fields' group");
|
|
MFEM_ASSERT(m_bp_index_grp->getGroup("fields") != NULL,
|
|
"Mesh blueprint index does not have 'fields' group");
|
|
|
|
// get the BP attr group
|
|
sidre::Group* attr_grp =
|
|
m_bp_grp->getGroup("fields")->getGroup(attr_name);
|
|
|
|
// create blueprint index for this attribute
|
|
sidre::Group *bp_index_attr_grp =
|
|
m_bp_index_grp->getGroup("fields")->createGroup(attr_name);
|
|
|
|
bp_index_attr_grp->createViewString("path", attr_grp->getPathName() );
|
|
bp_index_attr_grp->copyView( attr_grp->getView("association") );
|
|
bp_index_attr_grp->copyView( attr_grp->getView("topology") );
|
|
bp_index_attr_grp->createViewScalar("number_of_components", 1);
|
|
}
|
|
|
|
void SidreDataCollection::DeregisterAttributeField(const std::string& attr_name)
|
|
{
|
|
attr_map.Deregister(name, true);
|
|
|
|
sidre::Group * attr_grp = m_bp_grp->getGroup("fields");
|
|
MFEM_VERIFY(attr_grp->hasGroup(attr_name),
|
|
"No field exists in blueprint with name " << attr_name);
|
|
|
|
// Delete attr_name from the blueprint group.
|
|
|
|
// Note: This will destroy all orphaned views or buffer classes under this
|
|
// group also. If sidre owns this field data, the memory will be deleted
|
|
// unless it's referenced somewhere else in sidre.
|
|
attr_grp->destroyGroup(attr_name);
|
|
|
|
// Delete field_name from the blueprint_index group.
|
|
if (myid == 0)
|
|
{
|
|
DeregisterAttributeFieldInBPIndex(attr_name);
|
|
}
|
|
|
|
// Delete field_name from the named_buffers group, if allocated.
|
|
FreeNamedBuffer(attr_name);
|
|
}
|
|
|
|
void SidreDataCollection::DeregisterAttributeFieldInBPIndex(
|
|
const std::string& attr_name)
|
|
{
|
|
sidre::Group * fields_grp = m_bp_index_grp->getGroup("fields");
|
|
MFEM_VERIFY(fields_grp->hasGroup(attr_name),
|
|
"No attribute exists in blueprint index with name " << attr_name);
|
|
|
|
// Note: This will destroy all orphaned views or buffer classes under this
|
|
// group also. If sidre owns this field data, the memory will be deleted
|
|
// unless it's referenced somewhere else in sidre.
|
|
fields_grp->destroyGroup(attr_name);
|
|
}
|
|
|
|
void SidreDataCollection::
|
|
addIntegerAttributeField(const std::string& attr_name, bool is_bdry)
|
|
{
|
|
sidre::Group* fld_grp = m_bp_grp->getGroup("fields");
|
|
MFEM_ASSERT(fld_grp != NULL, "'fields' group does not exist");
|
|
|
|
const int num_elem = is_bdry? mesh->GetNBE() : mesh->GetNE();
|
|
std::string topo_name = is_bdry ? "boundary" : "mesh";
|
|
|
|
sidre::Group* attr_grp = fld_grp->createGroup(attr_name);
|
|
attr_grp->createViewString("association", "element");
|
|
attr_grp->createViewAndAllocate("values", sidre::INT_ID, num_elem);
|
|
attr_grp->createViewString("topology", topo_name);
|
|
}
|
|
|
|
void SidreDataCollection::DeregisterField(const std::string& field_name)
|
|
{
|
|
// Deregister field_name from field_map.
|
|
DataCollection::DeregisterField(field_name);
|
|
|
|
sidre::Group * fields_grp = m_bp_grp->getGroup("fields");
|
|
MFEM_VERIFY(fields_grp->hasGroup(field_name),
|
|
"No field exists in blueprint with name " << field_name);
|
|
|
|
// Delete field_name from the blueprint group.
|
|
|
|
// Note: This will destroy all orphaned views or buffer classes under this
|
|
// group also. If sidre owns this field data, the memory will be deleted
|
|
// unless it's referenced somewhere else in sidre.
|
|
fields_grp->destroyGroup(field_name);
|
|
|
|
// Delete field_name from the blueprint_index group.
|
|
if (myid == 0)
|
|
{
|
|
DeregisterFieldInBPIndex(field_name);
|
|
}
|
|
|
|
// Delete field_name from the named_buffers group, if allocated.
|
|
FreeNamedBuffer(field_name);
|
|
}
|
|
|
|
// private method
|
|
std::string SidreDataCollection::getElementName(Element::Type elementEnum)
|
|
{
|
|
// Note -- the mapping from Element::Type to string is based on
|
|
// enum Element::Type { POINT, SEGMENT, TRIANGLE, QUADRILATERAL,
|
|
// TETRAHEDRON, HEXAHEDRON };
|
|
// Note: -- the string names are from conduit's blueprint
|
|
|
|
switch (elementEnum)
|
|
{
|
|
case Element::POINT: return "point";
|
|
case Element::SEGMENT: return "line";
|
|
case Element::TRIANGLE: return "tri";
|
|
case Element::QUADRILATERAL: return "quad";
|
|
case Element::TETRAHEDRON: return "tet";
|
|
case Element::HEXAHEDRON: return "hex";
|
|
case Element::WEDGE:
|
|
default: ;
|
|
}
|
|
|
|
return "unknown";
|
|
}
|
|
|
|
} // end namespace mfem
|
|
|
|
#endif
|