40 #include <vtkCellData.h> 41 #include <vtkIdList.h> 42 #include <vtkModelMetadata.h> 43 #include <vtkPolyData.h> 44 #include <vtkStringArray.h> 45 #include <vtkUnstructuredGrid.h> 55 const int &ndeIdOffset,
const int &elmIdOffset,
56 int &ins,
int &ieb,
int &iss, std::string mshName,
57 const bool &usePhys,
int &ndeIdOffset_local,
58 int &elmIdOffset_local,
59 const bool &makeFreeSurfSS,
60 const bool &splitTopBotSS,
61 std::vector<std::string> sideSetNames) {
72 for (
int iNde = 0; iNde < ns.
nNde; iNde++) {
73 ns.
ndeIds.emplace_back(iNde + 1);
76 ndeIdOffset_local += ns.
nNde;
87 std::map<int, std::map<NEM::MSH::EXOMesh::elementType, std::vector<int>>>
90 std::map<int, int> v2e_elemID_map;
99 static_cast<VTKCellType
>(mb->
getDataSet()->GetCellType(iElm));
113 elmBucket[
static_cast<int>(grpIds[iElm])][exoType].emplace_back(iElm);
117 int numUnsupported = 0;
118 for (
const auto &elmGroup : elmBucket)
119 if (elmGroup.second.count(NEM::MSH::EXOMesh::elementType::OTHER) != 0)
121 elmGroup.second.at(NEM::MSH::EXOMesh::elementType::OTHER).size();
122 if (numUnsupported > 0) {
123 std::cerr <<
"WARNING: Detected " << numUnsupported
124 <<
" unsupported elements.\n";
129 for (
const auto &elmGroup : elmBucket) {
130 for (
const auto &elmIds : elmGroup.second) {
131 if (elmIds.second.empty())
continue;
136 eb.
nElm = elmIds.second.size();
139 for (
int i = 0; i < elmIds.second.size(); ++i) {
140 int vtkId = elmIds.second[i];
141 int exoId = i + elmIdOffset_local + 1;
142 v2e_elemID_map.insert(std::pair<int, int>(vtkId, exoId));
146 eb.
name = mshName +
"_PhysGrp_" + std::to_string(ieb);
148 eb.
name = mshName +
"_" + std::to_string(ieb);
150 switch (elmIds.first) {
152 std::cout <<
"Number of triangular elements = " << eb.
nElm <<
"\n";
157 std::cout <<
"Number of quadrilateral elements = " << eb.
nElm <<
"\n";
162 std::cout <<
"Number of tetrahedral elements = " << eb.
nElm <<
"\n";
167 std::cout <<
"Number of hexahedral elements = " << eb.
nElm <<
"\n";
172 std::cout <<
"Number of wedge elements = " << eb.
nElm <<
"\n";
176 case NEM::MSH::EXOMesh::elementType::OTHER:
178 std::cerr <<
"WARNING: Processing unsupported element. Previous " 179 "sanity check failed!\n";
185 for (
const auto &iElm : elmIds.second) {
187 for (
int in = 0; in < eb.
ndePerElm; ++in) {
189 eb.
conn.emplace_back(nids->GetId(in) + 1);
201 elmIdOffset_local += eb.
nElm;
206 if (makeFreeSurfSS) {
214 vtkSmartPointer<vtkModelMetadata> metadata = mb->
getMetadata();
215 vtkSmartPointer<vtkStringArray> sdeSetNames = metadata->GetSideSetNames();
216 int *sdeSetElmLst = metadata->GetSideSetElementList();
217 int *sdeSetSdeLst = metadata->GetSideSetSideList();
218 int *sdeSetSze = metadata->GetSideSetSize();
220 for (
int iSS = 0; iSS < metadata->GetNumberOfSideSets(); iSS++) {
223 ss.
name = sdeSetNames->GetValue(iSS);
224 ss.
nSde = sdeSetSze[iSS];
225 ss.
elmIds.assign(sdeSetElmLst, sdeSetElmLst + sdeSetSze[iSS]);
226 ss.
sdeIds.assign(sdeSetSdeLst, sdeSetSdeLst + sdeSetSze[iSS]);
231 sdeSetElmLst += sdeSetSze[iSS];
232 sdeSetSdeLst += sdeSetSze[iSS];
237 const std::string &fname) {
238 bool usePhys =
false;
239 bool makeFreeSurfSS =
false;
240 bool splitTopBotSS =
false;
241 std::vector<std::string> sideSetNames;
243 std::cout <<
"Warning: this method does not support physical groups." 245 std::cout <<
"Warning: this method does not support post-processing." 248 int nMsh = meshes.size();
252 std::cerr <<
"Error: At least one mesh should be provided!\n";
265 int ndeIdOffset_local = 0;
266 int elmIdOffset_local = 0;
270 for (
auto itrMsh = meshes.begin(); itrMsh != meshes.end(); itrMsh++) {
271 mshName = (*itrMsh)->getFileName();
272 genExo(*itrMsh, em, ndeIdOffset, elmIdOffset, ins, ieb, iss, mshName,
273 usePhys, ndeIdOffset_local, elmIdOffset_local, makeFreeSurfSS,
274 splitTopBotSS, sideSetNames);
289 std::map<int, int> v2e_elemID_map,
bool splitTopBotSS,
290 std::vector<std::string> sideSetNames) {
291 std::cout <<
"Creating side set from free surface." << std::endl;
293 std::vector<std::pair<int, int>> freeSurfCellEdge;
294 std::vector<std::pair<int, int>> hexFreeSurfCellFace;
295 std::vector<std::pair<int, int>> wedgeFreeSurfCellFace;
296 std::vector<std::pair<int, int>> tetraFreeSurfCellFace;
297 std::vector<int> elementIds1, elementIds2, elementIds3, sideIds1, sideIds2,
299 std::vector<std::vector<int>> splitElemIds, splitSideIds;
302 std::map<int, int> v2e_hexFace_map = {{1, 4}, {2, 2}, {3, 1},
303 {4, 3}, {5, 5}, {6, 6}};
304 std::map<int, int> v2e_wedgeFace_map = {
305 {1, 4}, {2, 5}, {3, 1}, {4, 2}, {5, 3}};
306 std::map<int, int> v2e_tetraFace_map = {{1, 1}, {2, 2}, {3, 3}, {4, 4}};
309 vtkSmartPointer<vtkDataSet> ds = mb->
getDataSet();
311 std::cerr <<
"No dataset is associated to the meshbase." << std::endl;
314 bool tetWarning =
false;
316 int nCl = ds->GetNumberOfCells();
317 for (
int cell_i = 0; cell_i < nCl; cell_i++) {
318 vtkCell *vc = ds->GetCell(cell_i);
319 if (vc->GetCellDimension() == 2) {
321 int ne = vc->GetNumberOfEdges();
322 for (
int edge_i = 0; edge_i < ne; edge_i++) {
323 vtkCell *ve = vc->GetEdge(edge_i);
324 vtkIdList *pidl = ve->GetPointIds();
326 std::pair<int, int> adjPair;
330 ds->GetCellNeighbors(cell_i, pidl, cidl);
331 if (cidl->GetNumberOfIds() == 0) {
332 adjPair.first = cell_i;
333 adjPair.second = edge_i + 1;
334 freeSurfCellEdge.push_back(adjPair);
337 }
else if (vc->GetCellDimension() == 3) {
339 int nfc = vc->GetNumberOfFaces();
340 for (
int face_i = 0; face_i < nfc; face_i++) {
341 vtkCell *vf = vc->GetFace(face_i);
342 vtkIdList *facePoints = vf->GetPointIds();
344 std::pair<int, int> adjPair;
348 ds->GetCellNeighbors(cell_i, facePoints, cidl);
349 if (cidl->GetNumberOfIds() == 0) {
350 adjPair.first = cell_i;
351 adjPair.second = face_i + 1;
352 if (nfc == 6) hexFreeSurfCellFace.push_back(adjPair);
353 if (nfc == 5) wedgeFreeSurfCellFace.push_back(adjPair);
355 tetraFreeSurfCellFace.push_back(adjPair);
356 if (splitTopBotSS && tetWarning ==
false) {
358 <<
"Warning: Tetrahedral element found on free surface.\n" 359 <<
" Cannot split top and bottom into separate side " 361 <<
" Creating single side set." << std::endl;
362 splitTopBotSS =
false;
374 for (
int i = 0; i < hexFreeSurfCellFace.size(); i++) {
375 int exoId = v2e_elemID_map[hexFreeSurfCellFace[i].first];
376 int sId = v2e_hexFace_map[hexFreeSurfCellFace[i].second];
381 elementIds2.push_back(exoId);
382 sideIds2.push_back(sId);
383 }
else if (sId == 6) {
385 elementIds3.push_back(exoId);
386 sideIds3.push_back(sId);
388 elementIds1.push_back(exoId);
389 sideIds1.push_back(sId);
392 elementIds1.push_back(exoId);
393 sideIds1.push_back(sId);
397 for (
int i = 0; i < wedgeFreeSurfCellFace.size(); i++) {
398 int exoId = v2e_elemID_map[wedgeFreeSurfCellFace[i].first];
399 int sId = v2e_wedgeFace_map[wedgeFreeSurfCellFace[i].second];
404 elementIds2.push_back(exoId);
405 sideIds2.push_back(sId);
406 }
else if (sId == 5) {
408 elementIds3.push_back(exoId);
409 sideIds3.push_back(sId);
411 elementIds1.push_back(exoId);
412 sideIds1.push_back(sId);
415 elementIds1.push_back(exoId);
416 sideIds1.push_back(sId);
420 for (
int i = 0; i < tetraFreeSurfCellFace.size(); i++) {
421 int exoId = v2e_elemID_map[tetraFreeSurfCellFace[i].first];
422 int sId = v2e_tetraFace_map[tetraFreeSurfCellFace[i].second];
423 elementIds1.push_back(exoId);
424 sideIds1.push_back(sId);
430 for (
int i = 0; i < freeSurfCellEdge.size(); i++) {
432 int exoId = v2e_elemID_map[freeSurfCellEdge[i].first];
433 elementIds1.push_back(exoId);
434 sideIds1.push_back(freeSurfCellEdge[i].second);
439 splitElemIds = {elementIds1, elementIds2, elementIds3};
440 splitSideIds = {sideIds1, sideIds2, sideIds3};
442 splitElemIds = {elementIds1};
443 splitSideIds = {sideIds1};
446 for (
int i = 0; i < splitElemIds.size(); ++i) {
450 if (sideSetNames.size() == 1 && splitElemIds.size() == 1) {
451 ss.
name = sideSetNames[i];
453 if (sideSetNames.size() == 0) {
454 std::cout <<
"side set names size is zero" << std::endl;
455 ss.
name =
"side_set_000000" + std::to_string(i + 1);
457 if (sideSetNames.size() > 0 && sideSetNames.size() < 3 && splitTopBotSS) {
458 std::cerr <<
"Error: Expected 3 'Side Set Names', found " 459 << sideSetNames.size() << std::endl;
462 if (sideSetNames.size() == 3) {
463 ss.
name = sideSetNames[i];
468 ss.
nSde = (int)splitSideIds[i].size();
469 ss.
elmIds = splitElemIds[i];
470 ss.
sdeIds = splitSideIds[i];
477 const std::string &fname,
483 std::string opr = ppJson.get_with_default(
"Operation",
"");
484 if (opr ==
"Material Assignment") {
489 bool appDen = ppJson.get_with_default(
"Apply Density",
false);
491 std::map<std::pair<double, std::string>, std::set<int>> zoneGeom;
494 for (
const auto &zone : ppJson[
"Zones"].array_range()) {
497 std::string matName = zone[0].get_with_default(
"Material Name",
"N/A");
498 std::string shape = zone[0].get_with_default(
"Shape",
"N/A");
499 std::cout <<
"Processing zone: " << zone.object_range().begin()->key()
500 <<
" Material: " << matName <<
" Shape: " << shape;
502 double density = 1.0;
504 density = zone[0].get_with_default(
"Density", 1.0);
505 std::cout <<
" Density: " << density;
507 std::cout << std::endl;
509 std::vector<nemId_t> lst;
510 if (shape ==
"Box") {
512 std::vector<double> bb;
513 bb.push_back(zone[0][
"Params"][
"Min"][0].as<double>());
514 bb.push_back(zone[0][
"Params"][
"Max"][0].as<double>());
515 bb.push_back(zone[0][
"Params"][
"Min"][1].as<double>());
516 bb.push_back(zone[0][
"Params"][
"Max"][1].as<double>());
517 bb.push_back(zone[0][
"Params"][
"Min"][2].as<double>());
518 bb.push_back(zone[0][
"Params"][
"Max"][2].as<double>());
521 }
else if (shape ==
"STL") {
526 std::vector<std::vector<double>> crds;
527 std::vector<std::vector<vtkIdType>> conns;
528 for (
const auto &crd :
529 zone[0][
"Params"][
"Node Coordinates"].array_range())
530 crds.push_back(crd.as<std::vector<double>>());
531 for (
const auto &conn :
532 zone[0][
"Params"][
"Connectivities"].array_range())
533 conns.push_back(conn.as<std::vector<vtkIdType>>());
536 }
else if (shape ==
"Sphere") {
540 std::vector<double> center =
541 zone[0][
"Params"][
"Center"].as<std::vector<double>>();
542 auto radius = zone[0][
"Params"][
"Radius"].as<
double>();
546 std::cerr <<
"WARNING: Skipping unknown zone shape: " << shape
551 if (zone[0].contains(
"Only From Block")) {
552 std::string blkName = zone[0][
"Only From Block"].as<std::string>();
556 std::find(elmBlkNames.begin(), elmBlkNames.end(), blkName);
557 if (elmBlkName == elmBlkNames.end()) {
558 std::cerr <<
"WARNING: Only From Block " << blkName
559 <<
" matches no available blocks. Continuing with no " 562 std::vector<int> lst_int(lst.begin(), lst.end());
565 std::distance(elmBlkNames.begin(), elmBlkName), lst_int, allIn);
566 lst.assign(lst_int.begin(), lst_int.end());
569 zoneGeom[{1.0 / density, matName}].insert(lst.begin(), lst.end());
573 std::cout <<
"Applying material zones based on density ordering" 577 for (
const auto &zone : zoneGeom) {
579 std::vector<int> elmLst;
580 std::cout <<
"Manipulating ExodusDB for " << zone.first.second
582 elmLst.insert(elmLst.end(), zone.second.begin(), zone.second.end());
585 }
else if (opr ==
"Check Duplicate Elements") {
586 std::cout <<
"Checking for existence of duplicate elements ... ";
590 std::cerr <<
" The exodus database contains duplicate elements." 594 std::cout <<
"False" << std::endl;
596 }
else if (opr ==
"Remove Block") {
597 std::string blkName = ppJson.get_with_default(
"Block Name",
"");
598 std::cout <<
"Removing Block " << blkName << std::endl;
600 }
else if (opr ==
"Snap Node Coords To Zero") {
601 double tol = ppJson.get_with_default(
"Tolerance", 0.0);
602 std::cout <<
"Snapping nodal coordinates to zero using tolerance: " << tol
605 }
else if (opr ==
"Boundary Condition Assignment") {
612 jsoncons::json bcs = ppJson[
"Condition"];
613 for (
const auto &bc : bcs.array_range()) {
614 std::set<nemId_t> pntIds;
617 std::string bcName = bc[
"Name"].as<std::string>();
618 std::string bcTyp = bc[
"Boundary Type"].as<std::string>();
619 if (bcTyp ==
"Faces") {
620 std::vector<double> srfCrd;
621 std::vector<nemId_t> srfConn;
622 jsoncons::json nc = bc[
"Params"][
"Node Coordinates"];
623 for (
const auto &crds : nc.array_range())
624 for (
const auto &cmp : crds.array_range())
625 srfCrd.push_back(cmp.as<
double>());
626 jsoncons::json conn = bc[
"Params"][
"Connectivities"];
627 for (
const auto &tri : conn.array_range())
628 for (
const auto &idx : tri.array_range())
629 srfConn.push_back(idx.as<
nemId_t>());
631 std::cout <<
"Number of points residing on the boundary " << bcName
632 <<
" is " << pntIds.size() << std::endl;
633 }
else if (bcTyp ==
"Edges") {
634 std::vector<double> edgeCrd;
635 jsoncons::json ncs = bc[
"Params"][
"Start"];
636 for (
const auto &crds : ncs.array_range())
637 for (
const auto &cmp : crds.array_range())
638 edgeCrd.push_back(cmp.as<
double>());
639 jsoncons::json nce = bc[
"Params"][
"End"];
640 for (
const auto &crds : nce.array_range())
641 for (
const auto &cmp : crds.array_range())
642 edgeCrd.push_back(cmp.as<
double>());
644 std::cout <<
"Number of points residing on the boundary " << bcName
645 <<
" is " << pntIds.size() << std::endl;
647 std::cerr <<
"Warning: unsupported boundary type " << bcTyp
652 if (!pntIds.empty()) {
654 std::copy(pntIds.begin(), pntIds.end(), std::back_inserter(nv));
658 }
else if (opr ==
"Merge Nodes") {
660 }
else if (opr ==
"Mesh Scaling") {
663 std::cerr <<
"Unknown operation requested: " << opr << std::endl;
jsoncons::string_view getProgramType() const override
void addElmBlkByElmIdLst(const std::string &name, std::vector< int > &idLst)
Creates a new element block and augments previous owners.
elementType v2eEMap(VTKCellType vt)
Convert VTK cell type to EXODUS element type.
const std::vector< std::string > & getElmBlkNames() const
Returns the names of registered element blocks.
static constexpr const char * programType
int getDimension() const
Returns problem dimension.
A complete I/O class for EXODUS II file format.
std::vector< int > sdeIds
A brief description of meshBase.
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
static void freeSurfaceSideSet(const meshBase *mb, NEM::MSH::EXOMesh::exoMesh *em, int elmIdOffset, std::map< int, int > v2e_elemID_map, bool splitTopBotSS, std::vector< std::string > sideSetNames)
Creates side set(s) for the free surface, exterior surface, during conversion.
void addNde(double x, double y, double z)
Add nodes to the database.
std::vector< int > elmIds
static void procExo(const jsoncons::json &ppJson, const std::string &fname, NEM::MSH::EXOMesh::exoMesh *em)
static meshBase * Create(const std::string &fname)
Construct vtkMesh from filename.
vtkSmartPointer< vtkModelMetadata > getMetadata()
void snapNdeCrdsZero(double tol=1e-5)
Filter nodal coordinates and snap to zero.
Stores side set information.
void FindCellsInTriSrf(const std::vector< std::vector< double >> &crds, const std::vector< std::vector< vtkIdType >> &conns, std::vector< nemId_t > &ids, bool query3Donly=true, double tol=0.1e-15) const
vtkSmartPointer< vtkDataSet > getDataSet() const
get this meshes' dataSet
nemId_t getNumberOfPoints() const
return the number of points
void FindPntsOnTriSrf(const std::vector< double > &crds, const std::vector< nemId_t > &conn, std::set< nemId_t > &ids, double tol=0.1e-15) const
void addNdeSetByNdeIdLst(const std::string &name, const std::vector< int > &idLst)
Creates a new node set and augments previous ones if needed.
Stores element block information.
std::vector< int > lstElmInBlk(int blkIdx, const std::vector< int > &elmIds, bool &allIn) const
Finds all elements that are within the block and generates a list of them.
void FindCellsWithinBounds(std::vector< double > &bb, std::vector< nemId_t > &ids, bool fulImrsd=true)
void addSdeSet(const sdeSetType &ss)
Add side set to the database.
static meshSrch * Create(meshBase *mb)
void FindCellsInSphere(const std::vector< double > ¢er, double radius, std::vector< nemId_t > &ids, bool query3Donly=true, double tol=0.1e-15) const
void addElmBlk(const elmBlkType &eb)
Add element block to the database.
void addNdeSet(const ndeSetType &ns)
Add node set to the database.
void setDimension(int dim)
Sets/changes the problem dimensionality.
Stores node set information.
void scaleNodes(double sc=1.0)
scales the nodal coordinates
std::vector< int > ndeIds
virtual void getCellDataArray(const std::string &name, std::vector< double > &data)
<>
void FindPntsOnEdge(std::vector< double > &crds, std::set< nemId_t > &ids, double tol=0.1e-15) const
nemId_t getNumberOfCells() const
return the number of cells
void mergeNodes(double tol=1e-15)
Merges duplicated and nodes within given proximity.
void removeElmBlkByName(const std::string &blkName)
Remove an element block by name.
virtual std::vector< double > getPoint(nemId_t id) const =0
get point with id
static void genExo(std::vector< meshBase *> meshes, const std::string &fname)