Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_STK_QuadraticToLinearMeshFactory.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Panzer: A partial differential equation assembly
4 // engine for strongly coupled complex multiphysics systems
5 //
6 // Copyright 2011 NTESS and the Panzer contributors.
7 // SPDX-License-Identifier: BSD-3-Clause
8 // *****************************************************************************
9 // @HEADER
10 
11 #include "PanzerAdaptersSTK_config.hpp"
14 #include "Panzer_STK_Interface.hpp"
15 #include "Teuchos_TimeMonitor.hpp"
16 #include "Teuchos_StandardParameterEntryValidators.hpp" // for plist validation
17 #include <stk_mesh/base/FieldBase.hpp>
18 #include <stk_mesh/base/DumpMeshInfo.hpp>
19 
20 using Teuchos::RCP;
21 using Teuchos::rcp;
22 
23 namespace panzer_stk {
24 
26  stk::ParallelMachine mpi_comm,
27  const bool print_debug)
28  : createEdgeBlocks_(false),
29  print_debug_(print_debug)
30 {
31  panzer_stk::STK_ExodusReaderFactory factory;
33  pl->set("File Name",quadMeshFileName);
34  factory.setParameterList(pl);
35  quadMesh_ = factory.buildMesh(mpi_comm);
36 
37  // TODO for currently supported input topologies, this should always be true
38  // but may need to be generalized in the future
40 
41  // check the conversion is supported
42  // and get output topology
43  this->getOutputTopology();
44 }
45 
47  const bool print_debug)
48  : quadMesh_(quadMesh),
49  createEdgeBlocks_(false),
50  print_debug_(print_debug)
51 {
52  // TODO for currently supported input topologies, this should always be true
53  // but may need to be generalized in the future
55 
56  // check the conversion is supported
57  // and get output topology
58  this->getOutputTopology();
59 }
60 
63 {
64  PANZER_FUNC_TIME_MONITOR("panzer::QuadraticToLinearMeshFactory::buildMesh()");
65 
66  // Make sure the Comms match between the meshes
67  {
68  int result = MPI_UNEQUAL;
69  MPI_Comm_compare(parallelMach, quadMesh_->getBulkData()->parallel(), &result);
70  TEUCHOS_ASSERT(result != MPI_UNEQUAL);
71  }
72 
73  // build all meta data
74  RCP<STK_Interface> mesh = this->buildUncommitedMesh(parallelMach);
75 
76  // commit meta data
77  mesh->initialize(parallelMach);
78 
79  // build bulk data
80  this->completeMeshConstruction(*mesh,parallelMach);
81 
82  return mesh;
83 }
84 
86 {
87  bool errFlag = false;
88 
89  std::vector<std::string> eblock_names;
90  quadMesh_->getElementBlockNames(eblock_names);
91 
92  // check that we have a supported topology
93  auto inputTopo = quadMesh_->getCellTopology(eblock_names[0]);
94  if (std::find(supportedInputTopos_.begin(),
95  supportedInputTopos_.end(),*inputTopo) == supportedInputTopos_.end()) errFlag = true;
96  TEUCHOS_TEST_FOR_EXCEPTION(errFlag,std::logic_error,
97  "ERROR :: Input topology " << inputTopo->getName() << " currently unsupported by QuadraticToLinearMeshFactory!");
98 
99  // check that the topology is the same over blocks
100  // not sure this is 100% foolproof
101  for (auto & eblock : eblock_names) {
102  auto cellTopo = quadMesh_->getCellTopology(eblock);
103  if (*cellTopo != *inputTopo) errFlag = true;
104  }
105 
106  TEUCHOS_TEST_FOR_EXCEPTION(errFlag, std::logic_error,
107  "ERROR :: The mesh has different topologies on different blocks!");
108 
109  outputTopoData_ = outputTopoMap_[inputTopo->getName()];
110 
111  nDim_ = outputTopoData_->dimension;
112  nNodes_ = outputTopoData_->node_count;
113 
114  return;
115 }
116 
118 {
119  PANZER_FUNC_TIME_MONITOR("panzer::QuadraticToLinearMeshFactory::buildUncomittedMesh()");
120 
122 
123  machRank_ = stk::parallel_machine_rank(parallelMach);
124  machSize_ = stk::parallel_machine_size(parallelMach);
125 
126  // build meta information: blocks and side set setups
127  this->buildMetaData(parallelMach,*mesh);
128 
129  mesh->addPeriodicBCs(periodicBCVec_);
130  mesh->setBoundingBoxSearchFlag(useBBoxSearch_);
131 
132  return mesh;
133 }
134 
135 void QuadraticToLinearMeshFactory::completeMeshConstruction(STK_Interface & mesh,stk::ParallelMachine parallelMach) const
136 {
137  PANZER_FUNC_TIME_MONITOR("panzer::QuadraticToLinearMeshFactory::completeMeshConstruction()");
138 
139  if(not mesh.isInitialized())
140  mesh.initialize(parallelMach);
141 
142  // add node and element information
143  this->buildElements(parallelMach,mesh);
144 
145  // finish up the edges
146 #ifndef ENABLE_UNIFORM
147  mesh.buildSubcells();
148 #endif
149  mesh.buildLocalElementIDs();
150  if(createEdgeBlocks_) {
151  mesh.buildLocalEdgeIDs();
152  }
153 
154  // now that edges are built, sidesets can be added
155 #ifndef ENABLE_UNIFORM
156  this->addSideSets(mesh);
157 #endif
158 
159  // add nodesets
160  this->addNodeSets(mesh);
161 
162  // TODO this functionality may be untested
163  if(createEdgeBlocks_) {
164  this->addEdgeBlocks(mesh);
165  }
166 
167  // Copy field data
168  this->copyCellFieldData(mesh);
169 
170  // calls Stk_MeshFactory::rebalance
171  // this->rebalance(mesh);
172 }
173 
176 {
178 
179  setMyParamList(paramList);
180 
181  // offsetGIDs_ = (paramList->get<std::string>("Offset mesh GIDs above 32-bit int limit") == "ON") ? true : false;
182 
183  createEdgeBlocks_ = paramList->get<bool>("Create Edge Blocks");
184 
185  // read in periodic boundary conditions
186  parsePeriodicBCList(Teuchos::rcpFromRef(paramList->sublist("Periodic BCs")),periodicBCVec_,useBBoxSearch_);
187 }
188 
191 {
192  static RCP<Teuchos::ParameterList> defaultParams;
193 
194  // fill with default values
195  if(defaultParams == Teuchos::null) {
196  defaultParams = rcp(new Teuchos::ParameterList);
197 
198  defaultParams->set<std::string>("Offset mesh GIDs above 32-bit int limit", "OFF",
199  "If 64-bit GIDs are supported, the mesh element and node global indices will start at a value greater than 32-bit limit.",
200  rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("OFF", "ON"))));
201 
202  // default to false for backward compatibility
203  defaultParams->set<bool>("Create Edge Blocks",false,"Create edge blocks in the mesh");
204 
205  Teuchos::ParameterList & bcs = defaultParams->sublist("Periodic BCs");
206  bcs.set<int>("Count",0); // no default periodic boundary conditions
207  }
208 
209  return defaultParams;
210 }
211 
212 void QuadraticToLinearMeshFactory::buildMetaData(stk::ParallelMachine /* parallelMach */, STK_Interface & mesh) const
213 {
214  if (print_debug_) {
215  std::cout << "\n\n**** DEBUG: begin printing source quad mesh exodus file metadata ****\n";
216  stk::mesh::impl::dump_all_meta_info(*(quadMesh_->getMetaData()), std::cout);
217  std::cout << "\n\n**** DEBUG: end printing source quad mesh exodus file metadata ****\n";
218  }
219 
220  // Required topologies
221  auto ctd = outputTopoData_;
222  // will only work for 2D and 3D meshes
223  const CellTopologyData * side_ctd = shards::CellTopology(ctd).getBaseCellTopologyData(nDim_-1,0);
224 
225  // Add in element blocks
226  std::vector<std::string> element_block_names;
227  quadMesh_->getElementBlockNames(element_block_names);
228  {
229  for (const auto& n : element_block_names)
230  mesh.addElementBlock(n,ctd);
231  }
232 
233  // Add in sidesets
234  {
235  std::vector<std::string> sideset_names;
236  quadMesh_->getSidesetNames(sideset_names);
237  for (const auto& n : sideset_names)
238  mesh.addSideset(n,side_ctd);
239  }
240 
241  // Add in nodesets
242  {
243  std::vector<std::string> nodeset_names;
244  quadMesh_->getNodesetNames(nodeset_names);
245  for (const auto& n : nodeset_names)
246  mesh.addNodeset(n);
247  }
248 
249  if(createEdgeBlocks_) {
250  const CellTopologyData * edge_ctd = shards::CellTopology(ctd).getBaseCellTopologyData(1,0);
251  std::vector<std::string> element_block_names2;
252  quadMesh_->getElementBlockNames(element_block_names2);
253  for (const auto& block_name : element_block_names2)
254  mesh.addEdgeBlock(block_name,edgeBlockName_,edge_ctd);
255  }
256 
257  // Add in nodal fields
258  {
259  const auto& fields = quadMesh_->getMetaData()->get_fields(mesh.getNodeRank());
260  for (const auto& f : fields) {
261  if (print_debug_)
262  std::cout << "Field=" << f->name() << ", rank=" << f->entity_rank() << std::endl;
263 
264  // Cull out the coordinate fields. That is a default field in
265  // stk that is automatically created by stk.
266  if (f->name() != "coordinates") {
267  for (const auto& n : element_block_names)
268  mesh.addSolutionField(f->name(),n);
269  }
270  }
271  }
272 
273  // Add in element fields
274  {
275  const auto& fields = quadMesh_->getMetaData()->get_fields(mesh.getElementRank());
276  for (const auto& f : fields) {
277  if (print_debug_)
278  std::cout << "Add Cell Field=" << f->name() << ", rank=" << f->entity_rank() << std::endl;
279 
280  for (const auto& n : element_block_names)
281  mesh.addCellField(f->name(),n);
282  }
283  }
284 
285  // NOTE: skipping edge and face fields for now. Can't error out since sidesets count as edge fields.
286  // TEUCHOS_TEST_FOR_EXCEPTION(quadMesh_->getMetaData()->get_fields(mesh.getEdgeRank()).size() != 0,std::runtime_error,
287  // "ERROR: the Quad8 mesh contains edge fields\""
288  // << quadMesh_->getMetaData()->get_fields(mesh.getEdgeRank())[0]->name()
289  // << "\". Edge fields are not supported in Quad8ToQuad4!");
290 
291  if (print_debug_) {
292  std::cout << "\n\n**** DEBUG: begin printing source linear mesh exodus file metadata ****\n";
293  stk::mesh::impl::dump_all_meta_info(*(mesh.getMetaData()), std::cout);
294  std::cout << "\n\n**** DEBUG: end printing source linear mesh exodus file metadata ****\n";
295  }
296 }
297 
298 void QuadraticToLinearMeshFactory::buildElements(stk::ParallelMachine parallelMach,STK_Interface & mesh) const
299 {
300  mesh.beginModification();
301 
302  auto metadata = mesh.getMetaData();
303  auto bulkdata = mesh.getBulkData();
304 
305  // Loop over element blocks
306  std::vector<std::string> block_names;
307  quadMesh_->getElementBlockNames(block_names);
308  for (const auto& block_name : block_names) {
309 
310  // Get the elements on this process
311  std::vector<stk::mesh::Entity> elements;
312  quadMesh_->getMyElements(block_name,elements);
313 
314  if (print_debug_) {
315  std::cout << "*************************************************" << std::endl;
316  std::cout << "block_name=" << block_name << ", num_my_elements=" << elements.size() << std::endl;
317  std::cout << "*************************************************" << std::endl;
318  }
319 
320  for (const auto& element : elements) {
321 
322  const auto element_gid = quadMesh_->getBulkData()->identifier(element);
323 
324  if (print_debug_) {
325  std::cout << "rank=" << machRank_
326  << ", block=" << block_name
327  << ", element entity_id=" << element
328  << ", gid=" << element_gid << std::endl;
329  }
330 
331  // Register nodes with the mesh
332  std::vector<stk::mesh::EntityId> nodes(nNodes_);
333  for (size_t i=0; i < nNodes_; ++i) {
334  // NOTE: this assumes that the linear topology is nested in
335  // the quadratic topology as an extended topology - i.e. the first n
336  // nodes of the quadratic topology are the corresponding linear
337  // nodes. Shards topologies enforce this through the concept
338  // of extended topologies.
339  stk::mesh::Entity node_entity = quadMesh_->findConnectivityById(element,mesh.getNodeRank(),i);
340  TEUCHOS_ASSERT(node_entity.is_local_offset_valid());
341  const auto node_gid = quadMesh_->getBulkData()->identifier(node_entity);
342  const double* node_coords = quadMesh_->getNodeCoordinates(node_entity);
343  std::vector<double> coords_vec(nDim_);
344  for (size_t j=0; j < nDim_; ++j) coords_vec[j] = node_coords[j];
345  mesh.addNode(node_gid,coords_vec);
346  nodes[i]=node_gid;
347  if (print_debug_) {
348  if (nDim_==2) {
349  std::cout << "elem gid=" << quadMesh_->getBulkData()->identifier(element)
350  << ", node_gid=" << node_gid << ", ("
351  << coords_vec[0] << "," << coords_vec[1] << ")\n";
352  } else {
353  std::cout << "elem gid=" << quadMesh_->getBulkData()->identifier(element)
354  << ", node_gid=" << node_gid << ", ("
355  << coords_vec[0] << "," << coords_vec[1] << "," << coords_vec[2] << ")\n";
356  }
357  }
358  }
359 
360  // Register element with the element block
361  auto element_descriptor = panzer_stk::buildElementDescriptor(element_gid,nodes);
362  auto element_block_part = mesh.getMetaData()->get_part(block_name);
363  mesh.addElement(element_descriptor,element_block_part);
364  }
365  }
366  mesh.endModification();
367 }
368 
370 {
371  mesh.beginModification();
372 
373  // Loop over sidesets
374  std::vector<std::string> sideset_names;
375  quadMesh_->getSidesetNames(sideset_names);
376  for (const auto& sideset_name : sideset_names) {
377 
378  stk::mesh::Part* sideset_part = mesh.getSideset(sideset_name);
379 
380  std::vector<stk::mesh::Entity> q_sides;
381  quadMesh_->getMySides(sideset_name,q_sides);
382 
383  // Loop over edges
384  for (const auto q_ent : q_sides) {
385  // The edge numbering scheme uses the element/node gids, so it
386  // should be consistent between the quadratic and linear meshes
387  // since we used the same gids. We use this fact to populate
388  // the quadratic sidesets.
389  stk::mesh::EntityId ent_gid = quadMesh_->getBulkData()->identifier(q_ent);
390  stk::mesh::Entity lin_ent = mesh.getBulkData()->get_entity(mesh.getSideRank(),ent_gid);
391  mesh.addEntityToSideset(lin_ent,sideset_part);
392  }
393  }
394 
395  mesh.endModification();
396 }
397 
399 {}
400 
402 {
403  mesh.beginModification();
404 
407 
408  stk::mesh::Part * edge_block = mesh.getEdgeBlock(edgeBlockName_);
409 
410  stk::mesh::Selector owned_block = metaData->locally_owned_part();
411 
412  std::vector<stk::mesh::Entity> edges;
413  bulkData->get_entities(mesh.getEdgeRank(), owned_block, edges);
414  mesh.addEntitiesToEdgeBlock(edges, edge_block);
415 
416  mesh.endModification();
417 }
418 
420 {
421  // Vector of pointers to field data
422  const auto& fields = lin_mesh.getMetaData()->get_fields(lin_mesh.getElementRank());
423 
424  // loop over fields and add the data to the new mesh.
425  for (const auto& field : fields) {
426 
427  if (print_debug_)
428  std::cout << "Adding field values for \"" << *field << "\" to the linear mesh!\n";
429 
430  auto field_name = field->name();
431 
432  // Divide into scalar and vector fields, ignoring any other types
433  // for now.
434  if (field->type_is<double>() &&
435  field_name != "coordinates" &&
436  field_name != "PROC_ID" &&
437  field_name != "LOAD_BAL") {
438 
439  // Loop over element blocks
440  std::vector<std::string> block_names;
441  quadMesh_->getElementBlockNames(block_names);
442  for (const auto& block : block_names) {
443 
444  auto* lin_field = lin_mesh.getCellField(field_name,block);
445  TEUCHOS_ASSERT(lin_field != nullptr);
446  // The q mesh doesn't have the field names set up, so a query
447  // fails. Go to stk directly in this case.
448  auto* q_field = quadMesh_->getMetaData()->get_field(quadMesh_->getElementRank(),field_name);
449 #ifdef PANZER_DEBUG
450  TEUCHOS_ASSERT(q_field != nullptr);
451 #endif
452 
453  // Get the elements for this block.
454  std::vector<stk::mesh::Entity> lin_elements;
455  lin_mesh.getMyElements(block,lin_elements);
456  std::vector<stk::mesh::Entity> q_elements;
457  quadMesh_->getMyElements(block,q_elements);
458  TEUCHOS_ASSERT(lin_elements.size() == q_elements.size());
459 
460  for (size_t i=0; i < lin_elements.size(); ++i) {
461 #ifdef PANZER_DEBUG
462  TEUCHOS_ASSERT(lin_mesh.getBulkData()->identifier(lin_elements[i]) ==
463  quadMesh_->getBulkData()->identifier(q_elements[i]));
464 #endif
465 
466  double* const lin_val = static_cast<double*>(stk::mesh::field_data(*lin_field,lin_elements[i]));
467  const double* const q_val = static_cast<double*>(stk::mesh::field_data(*q_field,q_elements[i]));
468  *lin_val = *q_val;
469 
470  if (print_debug_) {
471  std::cout << "field=" << field_name << ", block=" << block
472  << ", lin_e(" << lin_mesh.getBulkData()->identifier(lin_elements[i]) << ") = " << *lin_val
473  << ", q_e(" << quadMesh_->getBulkData()->identifier(q_elements[i]) << ") = " << *q_val
474  << std::endl;
475  }
476 
477  }
478  }
479  }
480  }
481 }
482 
483 } // end panzer_stk
QuadraticToLinearMeshFactory(const std::string &quadMeshFileName, stk::ParallelMachine mpi_comm=MPI_COMM_WORLD, const bool print_debug=false)
Teuchos::RCP< ElementDescriptor > buildElementDescriptor(stk::mesh::EntityId elmtId, std::vector< stk::mesh::EntityId > &nodes)
void getSidesetNames(std::vector< std::string > &name) const
void addNodeset(const std::string &name)
static void parsePeriodicBCList(const Teuchos::RCP< Teuchos::ParameterList > &pl, std::vector< Teuchos::RCP< const PeriodicBC_MatcherBase > > &periodicBC, bool &useBBoxSearch)
std::map< const std::string, const CellTopologyData * > outputTopoMap_
void getElementBlockNames(std::vector< std::string > &names) const
T & get(const std::string &name, T def_value)
void buildElements(stk::ParallelMachine parallelMach, STK_Interface &mesh) const
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void addEntityToSideset(stk::mesh::Entity entity, stk::mesh::Part *sideset)
void addSolutionField(const std::string &fieldName, const std::string &blockId)
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Teuchos::RCP< STK_Interface > buildMesh(stk::ParallelMachine parallelMach) const
Build the mesh object.
void addEdgeBlock(const std::string &elemBlockName, const std::string &edgeBlockName, const stk::topology &topology)
const double * getNodeCoordinates(stk::mesh::EntityId nodeId) const
stk::mesh::Part * getSideset(const std::string &name) const
void getMySides(const std::string &sideName, std::vector< stk::mesh::Entity > &sides) const
PHX::MDField< ScalarT, panzer::Cell, panzer::IP > result
A field that will be used to build up the result of the integral we&#39;re performing.
void addElement(const Teuchos::RCP< ElementDescriptor > &ed, stk::mesh::Part *block)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Derived from ParameterListAcceptor.
stk::mesh::EntityRank getSideRank() const
void initialize(stk::ParallelMachine parallelMach, bool setupIO=true, const bool buildRefinementSupport=false)
Teuchos::RCP< stk::mesh::BulkData > getBulkData() const
void setMyParamList(const RCP< ParameterList > &paramList)
void validateParametersAndSetDefaults(ParameterList const &validParamList, int const depth=1000)
static const std::string edgeBlockString
void buildMetaData(stk::ParallelMachine parallelMach, STK_Interface &mesh) const
void addNode(stk::mesh::EntityId gid, const std::vector< double > &coord)
void addEntitiesToEdgeBlock(std::vector< stk::mesh::Entity > entities, stk::mesh::Part *edgeblock)
void buildSubcells()
force the mesh to build subcells: edges and faces
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &paramList)
Derived from ParameterListAcceptor.
Teuchos::RCP< stk::mesh::MetaData > getMetaData() const
bool isInitialized() const
Has initialize been called on this mesh object?
stk::mesh::Entity findConnectivityById(stk::mesh::Entity src, stk::mesh::EntityRank tgt_rank, unsigned rel_id) const
void addSideset(const std::string &name, const CellTopologyData *ctData)
stk::mesh::Part * getEdgeBlock(const std::string &name) const
get the block part
PHX::MDField< ScalarT, panzer::Cell, panzer::BASIS > field
A field to which we&#39;ll contribute, or in which we&#39;ll store, the result of computing this integral...
std::vector< Teuchos::RCP< const PeriodicBC_MatcherBase > > periodicBCVec_
stk::mesh::EntityRank getEdgeRank() const
virtual void completeMeshConstruction(STK_Interface &mesh, stk::ParallelMachine parallelMach) const
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
void getMyElements(std::vector< stk::mesh::Entity > &elements) const
#define TEUCHOS_ASSERT(assertion_test)
stk::mesh::EntityRank getNodeRank() const
void addCellField(const std::string &fieldName, const std::string &blockId)
stk::mesh::EntityRank getElementRank() const
virtual Teuchos::RCP< STK_Interface > buildUncommitedMesh(stk::ParallelMachine parallelMach) const
void addElementBlock(const std::string &name, const CellTopologyData *ctData)
stk::mesh::Field< double > * getCellField(const std::string &fieldName, const std::string &blockId) const
void getNodesetNames(std::vector< std::string > &name) const
Teuchos::RCP< const shards::CellTopology > getCellTopology(const std::string &eBlock) const
std::vector< shards::CellTopology > supportedInputTopos_
Nodes in one element of the linear basis.