Panzer Version of the Day
Loading...
Searching...
No Matches
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"
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
20using Teuchos::RCP;
21using Teuchos::rcp;
22
23namespace 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;
32 RCP<Teuchos::ParameterList> pl = rcp(new Teuchos::ParameterList);
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
46QuadraticToLinearMeshFactory::QuadraticToLinearMeshFactory(const Teuchos::RCP<panzer_stk::STK_Interface>& quadMesh,
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
62Teuchos::RCP<STK_Interface> QuadraticToLinearMeshFactory::buildMesh(stk::ParallelMachine parallelMach) const
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
117Teuchos::RCP<STK_Interface> QuadraticToLinearMeshFactory::buildUncommitedMesh(stk::ParallelMachine parallelMach) const
118{
119 PANZER_FUNC_TIME_MONITOR("panzer::QuadraticToLinearMeshFactory::buildUncomittedMesh()");
120
121 RCP<STK_Interface> mesh = rcp(new STK_Interface(nDim_));
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
135void 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
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
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
175void QuadraticToLinearMeshFactory::setParameterList(const Teuchos::RCP<Teuchos::ParameterList> & paramList)
176{
177 paramList->validateParametersAndSetDefaults(*getValidParameters(),0);
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
190Teuchos::RCP<const Teuchos::ParameterList> QuadraticToLinearMeshFactory::getValidParameters() const
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
212void 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
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
298void 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
400
402{
403 mesh.beginModification();
404
405 Teuchos::RCP<stk::mesh::BulkData> bulkData = mesh.getBulkData();
406 Teuchos::RCP<stk::mesh::MetaData> metaData = mesh.getMetaData();
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
PHX::MDField< ScalarT, panzer::Cell, panzer::IP > result
A field that will be used to build up the result of the integral we're performing.
PHX::MDField< ScalarT, panzer::Cell, panzer::BASIS > field
A field to which we'll contribute, or in which we'll store, the result of computing this integral.
virtual void completeMeshConstruction(STK_Interface &mesh, stk::ParallelMachine parallelMach) const
void buildMetaData(stk::ParallelMachine parallelMach, STK_Interface &mesh) const
std::map< const std::string, const CellTopologyData * > outputTopoMap_
QuadraticToLinearMeshFactory(const std::string &quadMeshFileName, stk::ParallelMachine mpi_comm=MPI_COMM_WORLD, const bool print_debug=false)
Teuchos::RCP< const Teuchos::ParameterList > getValidParameters() const
Derived from ParameterListAcceptor.
void setParameterList(const Teuchos::RCP< Teuchos::ParameterList > &paramList)
Derived from ParameterListAcceptor.
Teuchos::RCP< STK_Interface > buildMesh(stk::ParallelMachine parallelMach) const
Build the mesh object.
void buildElements(stk::ParallelMachine parallelMach, STK_Interface &mesh) const
virtual Teuchos::RCP< STK_Interface > buildUncommitedMesh(stk::ParallelMachine parallelMach) const
std::vector< shards::CellTopology > supportedInputTopos_
Nodes in one element of the linear basis.
void initialize(stk::ParallelMachine parallelMach, bool setupIO=true, const bool buildRefinementSupport=false)
static const std::string edgeBlockString
stk::mesh::Part * getEdgeBlock(const std::string &name) const
get the block part
bool isInitialized() const
Has initialize been called on this mesh object?
stk::mesh::EntityRank getNodeRank() const
void addEdgeBlock(const std::string &elemBlockName, const std::string &edgeBlockName, const stk::topology &topology)
void buildSubcells()
force the mesh to build subcells: edges and faces
stk::mesh::EntityRank getElementRank() const
void addElement(const Teuchos::RCP< ElementDescriptor > &ed, stk::mesh::Part *block)
void addNode(stk::mesh::EntityId gid, const std::vector< double > &coord)
void addCellField(const std::string &fieldName, const std::string &blockId)
void addNodeset(const std::string &name)
void addSideset(const std::string &name, const CellTopologyData *ctData)
Teuchos::RCP< stk::mesh::MetaData > getMetaData() const
stk::mesh::Field< double > * getCellField(const std::string &fieldName, const std::string &blockId) const
void endModification(const bool find_and_set_shared_nodes_in_stk=true)
void addEntitiesToEdgeBlock(std::vector< stk::mesh::Entity > entities, stk::mesh::Part *edgeblock)
void addSolutionField(const std::string &fieldName, const std::string &blockId)
void addEntityToSideset(stk::mesh::Entity entity, stk::mesh::Part *sideset)
stk::mesh::EntityRank getSideRank() const
void getMyElements(std::vector< stk::mesh::Entity > &elements) const
void addElementBlock(const std::string &name, const CellTopologyData *ctData)
Teuchos::RCP< stk::mesh::BulkData > getBulkData() const
stk::mesh::EntityRank getEdgeRank() const
stk::mesh::Part * getSideset(const std::string &name) const
static void parsePeriodicBCList(const Teuchos::RCP< Teuchos::ParameterList > &pl, std::vector< Teuchos::RCP< const PeriodicBC_MatcherBase > > &periodicBC, bool &useBBoxSearch)
std::vector< Teuchos::RCP< const PeriodicBC_MatcherBase > > periodicBCVec_
Teuchos::RCP< ElementDescriptor > buildElementDescriptor(stk::mesh::EntityId elmtId, std::vector< stk::mesh::EntityId > &nodes)