Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_STK_LocalMeshUtilities.cpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Panzer: A partial differential equation assembly
5 // engine for strongly coupled complex multiphysics systems
6 // Copyright (2011) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Roger P. Pawlowski (rppawlo@sandia.gov) and
39 // Eric C. Cyr (eccyr@sandia.gov)
40 // ***********************************************************************
41 // @HEADER
42 
43 #include "Panzer_NodeType.hpp"
45 #include "Panzer_STK_Interface.hpp"
48 
49 #include "Panzer_HashUtils.hpp"
50 #include "Panzer_LocalMeshInfo.hpp"
52 #include "Panzer_FaceToElement.hpp"
53 
54 #include "Panzer_ConnManager.hpp"
55 #include "Panzer_FieldPattern.hpp"
60 
61 #include "Phalanx_KokkosDeviceTypes.hpp"
62 
63 #include "Teuchos_Assert.hpp"
65 
66 #include "Tpetra_Import.hpp"
67 #include "Tpetra_CrsMatrix.hpp"
68 #include "Tpetra_RowMatrixTransposer.hpp"
69 
70 #include <string>
71 #include <map>
72 #include <vector>
73 #include <unordered_set>
74 
75 namespace panzer_stk
76 {
77 
78 // No external access
79 namespace
80 {
81 
85 void
86 buildCellGlobalIDs(panzer::ConnManager & conn,
87  Kokkos::View<panzer::GlobalOrdinal*> & globals)
88 {
89  // extract topologies, and build global connectivity...currently assuming only one topology
90  std::vector<shards::CellTopology> elementBlockTopologies;
91  conn.getElementBlockTopologies(elementBlockTopologies);
92  const shards::CellTopology & topology = elementBlockTopologies[0];
93 
94  // FIXME: We assume that all element blocks have the same topology.
95  for(const auto & other_topology : elementBlockTopologies){
96  TEUCHOS_ASSERT(other_topology.getKey() == topology.getKey());
97  }
98 
100  if(topology.getDimension() == 1){
101  cell_pattern = Teuchos::rcp(new panzer::EdgeFieldPattern(topology));
102  } else if(topology.getDimension() == 2){
103  cell_pattern = Teuchos::rcp(new panzer::FaceFieldPattern(topology));
104  } else if(topology.getDimension() == 3){
105  cell_pattern = Teuchos::rcp(new panzer::ElemFieldPattern(topology));
106  }
107 
108 // panzer::EdgeFieldPattern cell_pattern(elementBlockTopologies[0]);
109  conn.buildConnectivity(*cell_pattern);
110 
111  // calculate total number of local cells
112  std::vector<std::string> block_ids;
113  conn.getElementBlockIds(block_ids);
114 
115  std::size_t totalSize = 0;
116  for (std::size_t which_blk=0;which_blk<block_ids.size();which_blk++) {
117  // get the elem to face mapping
118  const std::vector<int> & localIDs = conn.getElementBlock(block_ids[which_blk]);
119  totalSize += localIDs.size();
120  }
121  globals = Kokkos::View<panzer::GlobalOrdinal*>("global_cells",totalSize);
122 
123  for (std::size_t id=0;id<totalSize; ++id) {
124  // sanity check
125  int n_conn = conn.getConnectivitySize(id);
126  TEUCHOS_ASSERT(n_conn==1);
127 
128  const panzer::GlobalOrdinal * connectivity = conn.getConnectivity(id);
129  globals(id) = connectivity[0];
130  }
131 
132 // print_view_1D("buildCellGlobalIDs : globals",globals);
133 }
134 
138 void
139 buildCellToNodes(panzer::ConnManager & conn, Kokkos::View<panzer::GlobalOrdinal**> & globals)
140 {
141  // extract topologies, and build global connectivity...currently assuming only one topology
142  std::vector<shards::CellTopology> elementBlockTopologies;
143  conn.getElementBlockTopologies(elementBlockTopologies);
144  const shards::CellTopology & topology = elementBlockTopologies[0];
145 
146  // FIXME: We assume that all element blocks have the same topology.
147  for(const auto & other_topology : elementBlockTopologies){
148  TEUCHOS_ASSERT(other_topology.getKey() == topology.getKey());
149  }
150 
151  panzer::NodalFieldPattern pattern(topology);
152  conn.buildConnectivity(pattern);
153 
154  // calculate total number of local cells
155  std::vector<std::string> block_ids;
156  conn.getElementBlockIds(block_ids);
157 
158  // compute total cells and maximum nodes
159  std::size_t totalCells=0, maxNodes=0;
160  for (std::size_t which_blk=0;which_blk<block_ids.size();which_blk++) {
161  // get the elem to face mapping
162  const std::vector<int> & localIDs = conn.getElementBlock(block_ids[which_blk]);
163  if ( localIDs.size() == 0 )
164  continue;
165  int thisSize = conn.getConnectivitySize(localIDs[0]);
166 
167  totalCells += localIDs.size();
168  maxNodes = maxNodes<Teuchos::as<std::size_t>(thisSize) ? Teuchos::as<std::size_t>(thisSize) : maxNodes;
169  }
170  globals = Kokkos::View<panzer::GlobalOrdinal**>("cell_to_node",totalCells,maxNodes);
171 
172  // build connectivity array
173  for (std::size_t id=0;id<totalCells; ++id) {
174  const panzer::GlobalOrdinal * connectivity = conn.getConnectivity(id);
175  int nodeCnt = conn.getConnectivitySize(id);
176 
177  for(int n=0;n<nodeCnt;n++)
178  globals(id,n) = connectivity[n];
179  }
180 
181 // print_view("buildCellToNodes : globals",globals);
182 }
183 
185 buildNodeMap(const Teuchos::RCP<const Teuchos::Comm<int> > & comm,
186  Kokkos::View<const panzer::GlobalOrdinal**> cells_to_nodes)
187 {
188  using Teuchos::RCP;
189  using Teuchos::rcp;
190 
191  /*
192 
193  This function converts
194 
195  cells_to_nodes(local cell, local node) = global node index
196 
197  to a map describing which global nodes are found on this process
198 
199  Note that we have to ensure that that the global nodes found on this process are unique.
200 
201  */
202 
203  typedef Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> map_type;
204 
205  // get locally unique global ids
206  std::set<panzer::GlobalOrdinal> global_nodes;
207  for(unsigned int i=0;i<cells_to_nodes.extent(0);i++)
208  for(unsigned int j=0;j<cells_to_nodes.extent(1);j++)
209  global_nodes.insert(cells_to_nodes(i,j));
210 
211  // build local vector contribution
212  Kokkos::View<panzer::GlobalOrdinal*> node_ids("global_nodes",global_nodes.size());
213  int i = 0;
214  for(auto itr=global_nodes.begin();itr!=global_nodes.end();++itr,++i)
215  node_ids(i) = *itr;
216 
217 // print_view("buildNodeMap : cells_to_nodes",cells_to_nodes);
218 // print_view_1D("buildNodeMap : node_ids",node_ids);
219 
220  return rcp(new map_type(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),node_ids,0,comm));
221 }
222 
227 buildNodeToCellMatrix(const Teuchos::RCP<const Teuchos::Comm<int> > & comm,
228  Kokkos::View<const panzer::GlobalOrdinal*> owned_cells,
229  Kokkos::View<const panzer::GlobalOrdinal**> owned_cells_to_nodes)
230 {
231  using Teuchos::RCP;
232  using Teuchos::rcp;
233 
234  typedef Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> map_type;
235  typedef Tpetra::CrsMatrix<panzer::LocalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> crs_type;
236  typedef Tpetra::Import<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> import_type;
237 
238 
239  PANZER_FUNC_TIME_MONITOR_DIFF("panzer_stk::buildNodeToCellMatrix",BNTCM);
240 
241  TEUCHOS_ASSERT(owned_cells.extent(0)==owned_cells_to_nodes.extent(0));
242 
243  // build a unque node map to use with fill complete
244 
245  // This map identifies all nodes linked to cells on this process
246  auto node_map = buildNodeMap(comm,owned_cells_to_nodes);
247 
248  // This map identifies nodes owned by this process
249  auto unique_node_map = Tpetra::createOneToOne(node_map);
250 
251  // This map identifies the cells owned by this process
252  RCP<map_type> cell_map = rcp(new map_type(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),owned_cells,0,comm));
253 
254  // Create a CRS matrix that stores a pointless value for every global node that belongs to a global cell
255  // This is essentially another way to store cells_to_nodes
256  RCP<crs_type> cell_to_node;
257  {
258  PANZER_FUNC_TIME_MONITOR_DIFF("Build matrix",BuildMatrix);
259  // The matrix is indexed by (global cell, global node) = local node
260  cell_to_node = rcp(new crs_type(cell_map,0));
261 
262  // fill in the cell to node matrix
263  const unsigned int num_local_cells = owned_cells_to_nodes.extent(0);
264  const unsigned int num_nodes_per_cell = owned_cells_to_nodes.extent(1);
265  std::vector<panzer::LocalOrdinal> local_node_indexes(num_nodes_per_cell);
266  std::vector<panzer::GlobalOrdinal> global_node_indexes(num_nodes_per_cell);
267  for(unsigned int i=0;i<num_local_cells;i++) {
268  const panzer::GlobalOrdinal global_cell_index = owned_cells(i);
269  // std::vector<panzer::LocalOrdinal> vals(cells_to_nodes.extent(1));
270  // std::vector<panzer::GlobalOrdinal> cols(cells_to_nodes.extent(1));
271  for(unsigned int j=0;j<num_nodes_per_cell;j++) {
272  // vals[j] = Teuchos::as<panzer::LocalOrdinal>(j);
273  // cols[j] = cells_to_nodes(i,j);
274  local_node_indexes[j] = Teuchos::as<panzer::LocalOrdinal>(j);
275  global_node_indexes[j] = owned_cells_to_nodes(i,j);
276  }
277 
278  // cell_to_node_mat->insertGlobalValues(cells(i),cols,vals);
279  cell_to_node->insertGlobalValues(global_cell_index,global_node_indexes,local_node_indexes);
280  }
281  cell_to_node->fillComplete(unique_node_map,cell_map);
282 
283  }
284 
285  // Transpose the cell_to_node array to create the node_to_cell array
286  RCP<crs_type> node_to_cell;
287  {
288  PANZER_FUNC_TIME_MONITOR_DIFF("Tranpose matrix",TransposeMatrix);
289  // Create an object designed to transpose the (global cell, global node) matrix to give
290  // a (global node, global cell) matrix
291  Tpetra::RowMatrixTransposer<panzer::LocalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> transposer(cell_to_node);
292 
293  // Create the transpose crs matrix
294  auto trans = transposer.createTranspose();
295 
296  // We want to import the portion of the transposed matrix relating to all nodes on this process
297  // The importer must import nodes required by this process (node_map) from the unique nodes (nodes living on a process)
298  RCP<import_type> import = rcp(new import_type(unique_node_map,node_map));
299 
300  // Create the crs matrix to store (ghost node, global cell) array
301  // This CRS matrix will have overlapping rows for shared global nodes
302  node_to_cell = rcp(new crs_type(node_map,0));
303 
304  // Transfer data from the transpose array (associated with unique_node_map) to node_to_cell (associated with node_map)
305  node_to_cell->doImport(*trans,*import,Tpetra::INSERT);
306 
307  // Set the fill - basicially locks down the structured of the CRS matrix - required before doing some operations
308  //node_to_cell->fillComplete();
309  node_to_cell->fillComplete(cell_map,unique_node_map);
310  }
311 
312  // Return the node to cell array
313  return node_to_cell;
314 }
315 
318 Kokkos::View<const panzer::GlobalOrdinal*>
319 buildGhostedCellOneRing(const Teuchos::RCP<const Teuchos::Comm<int> > & comm,
320  Kokkos::View<const panzer::GlobalOrdinal*> cells,
321  Kokkos::View<const panzer::GlobalOrdinal**> cells_to_nodes)
322 {
323 
324  PANZER_FUNC_TIME_MONITOR_DIFF("panzer_stk::buildGhostedCellOneRing",BGCOR);
325  typedef Tpetra::CrsMatrix<int,int,panzer::GlobalOrdinal,panzer::TpetraNodeType> crs_type;
326 
327  // cells : (local cell index) -> global cell index
328  // cells_to_nodes : (local cell index, local node_index) -> global node index
329 
330  /*
331 
332  This function creates a list of global indexes relating to ghost cells
333 
334  It is a little misleading how it does this, but the idea is to use the indexing of a CRS matrix to identify
335  what global cells are connected to which global nodes. The values in the CRS matrix are meaningless, however,
336  the fact that they are filled allows us to ping what index combinations exist.
337 
338  To do this we are going to use cell 'nodes' which could also be cell 'vertices'. It is unclear.
339 
340  First we construct an array that stores that global node indexes make up the connectivity for a given global cell index (order doesn't matter)
341 
342  cell_to_node : cell_to_node[global cell index][global node index] = some value (not important, just has to exist)
343 
344  We are then going to transpose that array
345 
346  node_to_cell : node_to_cell[global node index][global cell index] = some value (not important, just has to exist)
347 
348  The coloring of the node_to_cell array tells us what global cells are connected to a given global node.
349 
350 
351  */
352 
353  // the node to cell matrix: Row = Global Node Id, Cell = Global Cell Id, Value = Cell Local Node Id
354  Teuchos::RCP<crs_type> node_to_cell = buildNodeToCellMatrix(comm,cells,cells_to_nodes);
355 
356  // the set of cells already known
357  std::unordered_set<panzer::GlobalOrdinal> unique_cells;
358 
359  // mark all owned cells as already known, e.g. and not in the list of
360  // ghstd cells to be constructed
361  for(size_t i=0;i<cells.extent(0);i++) {
362  unique_cells.insert(cells(i));
363  }
364 
365  // The set of ghost cells that share a global node with an owned cell
366  std::set<panzer::GlobalOrdinal> ghstd_cells_set;
367 
368  // Get a list of global node indexes associated with the cells owned by this process
369 // auto node_map = node_to_cell->getRangeMap()->getMyGlobalIndices();
370  auto node_map = node_to_cell->getMap()->getMyGlobalIndices();
371 
372  // Iterate through the global node indexes associated with this process
373  for(size_t i=0;i<node_map.extent(0);i++) {
374  const panzer::GlobalOrdinal global_node_index = node_map(i);
375  size_t numEntries = node_to_cell->getNumEntriesInGlobalRow(node_map(i));
376  Teuchos::Array<panzer::GlobalOrdinal> indices(numEntries);
377  Teuchos::Array<int> values(numEntries);
378 
379  // Copy the row for a global node index into a local vector
380  node_to_cell->getGlobalRowCopy(global_node_index,indices,values,numEntries);
381 
382  for(auto index : indices) {
383  // if this is a new index (not owned, not previously found ghstd index
384  // add it to the list of ghstd cells
385  if(unique_cells.find(index)==unique_cells.end()) {
386  ghstd_cells_set.insert(index);
387  unique_cells.insert(index); // make sure you don't find it again
388  }
389  }
390  }
391 
392  // build an array containing only the ghstd cells
393  int indx = 0;
394  Kokkos::View<panzer::GlobalOrdinal*> ghstd_cells("ghstd_cells",ghstd_cells_set.size());
395  for(auto global_cell_index : ghstd_cells_set) {
396  ghstd_cells(indx) = global_cell_index;
397  indx++;
398  }
399 
400 // print_view_1D("ghstd_cells",ghstd_cells);
401 
402  return ghstd_cells;
403 }
404 
408 Kokkos::DynRankView<double,PHX::Device>
409 buildGhostedVertices(const Tpetra::Import<int,panzer::GlobalOrdinal,panzer::TpetraNodeType> & importer,
410  Kokkos::DynRankView<const double,PHX::Device> owned_vertices)
411 {
412  using Teuchos::RCP;
413  using Teuchos::rcp;
414 
415  typedef Tpetra::MultiVector<double,int,panzer::GlobalOrdinal,panzer::TpetraNodeType> mvec_type;
416  typedef typename mvec_type::dual_view_type dual_view_type;
417 
418  size_t owned_cell_cnt = importer.getSourceMap()->getNodeNumElements();
419  size_t ghstd_cell_cnt = importer.getTargetMap()->getNodeNumElements();
420  int vertices_per_cell = owned_vertices.extent(1);
421  int space_dim = owned_vertices.extent(2);
422 
423  TEUCHOS_ASSERT(owned_vertices.extent(0)==owned_cell_cnt);
424 
425  // build vertex multivector
426  RCP<mvec_type> owned_vertices_mv = rcp(new mvec_type(importer.getSourceMap(),vertices_per_cell*space_dim));
427  RCP<mvec_type> ghstd_vertices_mv = rcp(new mvec_type(importer.getTargetMap(),vertices_per_cell*space_dim));
428 
429  {
430  auto owned_vertices_view = owned_vertices_mv->template getLocalView<dual_view_type>();
431  for(size_t i=0;i<owned_cell_cnt;i++) {
432  int l = 0;
433  for(int j=0;j<vertices_per_cell;j++)
434  for(int k=0;k<space_dim;k++,l++)
435  owned_vertices_view(i,l) = owned_vertices(i,j,k);
436  }
437  }
438 
439  // communicate ghstd vertices
440  ghstd_vertices_mv->doImport(*owned_vertices_mv,importer,Tpetra::INSERT);
441 
442  // copy multivector into ghstd vertex structure
443  Kokkos::DynRankView<double,PHX::Device> ghstd_vertices("ghstd_vertices",ghstd_cell_cnt,vertices_per_cell,space_dim);
444  {
445  auto ghstd_vertices_view = ghstd_vertices_mv->template getLocalView<dual_view_type>();
446  for(size_t i=0;i<ghstd_cell_cnt;i++) {
447  int l = 0;
448  for(int j=0;j<vertices_per_cell;j++)
449  for(int k=0;k<space_dim;k++,l++)
450  ghstd_vertices(i,j,k) = ghstd_vertices_view(i,l);
451  }
452  }
453 
454  return ghstd_vertices;
455 } // end build ghstd vertices
456 
457 void
458 setupLocalMeshBlockInfo(const panzer_stk::STK_Interface & mesh,
459  panzer::ConnManager & conn,
460  const panzer::LocalMeshInfo & mesh_info,
461  const std::string & element_block_name,
462  panzer::LocalMeshBlockInfo & block_info)
463 {
464 
465  // This function identifies all cells in mesh_info that belong to element_block_name
466  // and creates a block_info from it.
467 
468  const int num_parent_owned_cells = mesh_info.num_owned_cells;
469 
470  // Make sure connectivity is setup for interfaces between cells
471  {
472  const shards::CellTopology & topology = *(mesh.getCellTopology(element_block_name));
474  if(topology.getDimension() == 1){
475  cell_pattern = Teuchos::rcp(new panzer::EdgeFieldPattern(topology));
476  } else if(topology.getDimension() == 2){
477  cell_pattern = Teuchos::rcp(new panzer::FaceFieldPattern(topology));
478  } else if(topology.getDimension() == 3){
479  cell_pattern = Teuchos::rcp(new panzer::ElemFieldPattern(topology));
480  }
481 
482  {
483  PANZER_FUNC_TIME_MONITOR("Build connectivity");
484  conn.buildConnectivity(*cell_pattern);
485  }
486  }
487 
488  std::vector<panzer::LocalOrdinal> owned_block_cells;
489  for(int parent_owned_cell=0;parent_owned_cell<num_parent_owned_cells;++parent_owned_cell){
490  const panzer::LocalOrdinal local_cell = mesh_info.local_cells(parent_owned_cell);
491  const bool is_in_block = conn.getBlockId(local_cell) == element_block_name;
492 
493  if(is_in_block){
494  owned_block_cells.push_back(parent_owned_cell);
495  }
496 
497  }
498 
499  if ( owned_block_cells.size() == 0 )
500  return;
501  block_info.num_owned_cells = owned_block_cells.size();
502  block_info.element_block_name = element_block_name;
503  block_info.cell_topology = mesh.getCellTopology(element_block_name);
504  {
505  PANZER_FUNC_TIME_MONITOR("panzer::partitioning_utilities::setupSubLocalMeshInfo");
506  panzer::partitioning_utilities::setupSubLocalMeshInfo(mesh_info, owned_block_cells, block_info);
507  }
508 }
509 
510 
511 void
512 setupLocalMeshSidesetInfo(const panzer_stk::STK_Interface & mesh,
513  panzer::ConnManager& /* conn */,
514  const panzer::LocalMeshInfo & mesh_info,
515  const std::string & element_block_name,
516  const std::string & sideset_name,
517  panzer::LocalMeshSidesetInfo & sideset_info)
518 {
519 
520  // This function identifies all cells in mesh_info that belong to element_block_name
521  // and creates a block_info from it.
522 
523  const size_t face_subcell_dimension = mesh.getCellTopology(element_block_name)->getDimension()-1;
524 
525  Kokkos::DynRankView<double,PHX::Device> data_allocation;
526 
527  // This is a list of all entities that make up the 'side'
528  std::vector<stk::mesh::Entity> side_entities;
529 
530  // Grab the side entities associated with this sideset on the mesh
531  // Note: Throws exception if element block or sideset doesn't exist
532  try{
533 
534  mesh.getMySides(sideset_name, element_block_name, side_entities);
535 
536  } catch(STK_Interface::SidesetException & e) {
537  std::stringstream ss;
538  std::vector<std::string> sideset_names;
539  mesh.getSidesetNames(sideset_names);
540 
541  // build an error message
542  ss << e.what() << "\nChoose existing sideset:\n";
543  for(const auto & optional_sideset_name : sideset_names){
544  ss << "\t\"" << optional_sideset_name << "\"\n";
545  }
546 
547  TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true,std::logic_error,ss.str());
548 
549  } catch(STK_Interface::ElementBlockException & e) {
550  std::stringstream ss;
551  std::vector<std::string> element_block_names;
552  mesh.getElementBlockNames(element_block_names);
553 
554  // build an error message
555  ss << e.what() << "\nChoose existing element block:\n";
556  for(const auto & optional_element_block_name : element_block_names){
557  ss << "\t\"" << optional_element_block_name << "\"\n";
558  }
559 
560  TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true,std::logic_error,ss.str());
561 
562  } catch(std::logic_error & e) {
563  std::stringstream ss;
564  ss << e.what() << "\nUnrecognized logic error.\n";
565 
566  TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true,std::logic_error,ss.str());
567 
568  }
569 
570  // We now have a list of sideset entities, lets unwrap them and create the sideset_info!
571 
572  // (subcell_dimension, subcell_index) -> list of cells
573  std::map<std::pair<size_t,size_t>, std::vector<size_t> > local_cell_indexes_by_subcell;
574 
575  // List of local subcell indexes indexed by element:
576  // For example: a Tet (element) would have
577  // - 4 triangular faces (subcell_index 0-3, subcell_dimension=2)
578  // - 6 edges (subcell_index 0-5, subcell_dimension=1)
579  // - 4 vertices (subcell_index 0-3, subcell_dimension=0)
580  // Another example: a Line (element) would have
581  // - 2 vertices (subcell_index 0-1, subcell_dimension=0)
582  std::vector<stk::mesh::Entity> elements;
583  std::vector<size_t> subcell_indexes;
584  std::vector<size_t> subcell_dimensions;
585  panzer_stk::workset_utils::getSideElementCascade(mesh, element_block_name, side_entities, subcell_dimensions, subcell_indexes, elements);
586  const panzer::LocalOrdinal num_elements = subcell_dimensions.size();
587 
588  // build local cell_ids, mapped by local side id
589  for(panzer::LocalOrdinal element_index=0; element_index<num_elements; ++element_index) {
590  const size_t subcell_dimension = subcell_dimensions[element_index];
591  const size_t subcell_index = subcell_indexes[element_index];
592  const size_t element_local_index = mesh.elementLocalId(elements[element_index]);
593 
594  // Add subcell to map
595  local_cell_indexes_by_subcell[std::pair<size_t,size_t>(subcell_dimension, subcell_index)].push_back(element_local_index);
596  }
597 
598  // We now have a list of all local cells 'touching' the side set, as well as the faces, edges, and vertices that define the 'touch'
599 
600  // For our purposes we only really want the cells and faces associated with the side
601 
602  // Each cell can have multiple faces on the sideset
603  std::unordered_set<panzer::LocalOrdinal> owned_parent_cells_set;
604  std::map<panzer::LocalOrdinal,std::vector<panzer::LocalOrdinal> > owned_parent_cell_index_map;
605  {
606  // We use a set to avoid duplicates
607  for(const auto & cell_subcell_pair : local_cell_indexes_by_subcell){
608  const std::pair<size_t,size_t> & subcell_definition = cell_subcell_pair.first;
609  const panzer::LocalOrdinal subcell_index = panzer::LocalOrdinal(subcell_definition.second);
610  if(subcell_definition.first == face_subcell_dimension){
611  const std::vector<size_t> & local_cell_indexes_for_subcell = cell_subcell_pair.second;
612  for(const size_t & local_cell_index : local_cell_indexes_for_subcell){
613 
614  // TODO: Super slow - fix this!!
615  for(panzer::LocalOrdinal i=0;i<panzer::LocalOrdinal(mesh_info.local_cells.extent(0)); ++i){
616  if(mesh_info.local_cells(i) == panzer::LocalOrdinal(local_cell_index)){
617  owned_parent_cell_index_map[i].push_back(subcell_index);
618  }
619  }
620  }
621  }
622  }
623 
624  for(const auto & pair : owned_parent_cell_index_map){
625  owned_parent_cells_set.insert(pair.first);
626  }
627 
628  }
629 
630  const panzer::LocalOrdinal num_owned_cells = owned_parent_cell_index_map.size();
631 
632  sideset_info.element_block_name = element_block_name;
633  sideset_info.sideset_name = sideset_name;
634  sideset_info.cell_topology = mesh.getCellTopology(element_block_name);
635 
636  sideset_info.num_owned_cells = num_owned_cells;
637 
638  struct face_t{
639  face_t(panzer::LocalOrdinal c0, panzer::LocalOrdinal c1, panzer::LocalOrdinal sc0, panzer::LocalOrdinal sc1)
640  {
641  cell_0=c0;
642  cell_1=c1;
643  subcell_index_0=sc0;
644  subcell_index_1=sc1;
645  }
646  panzer::LocalOrdinal cell_0;
647  panzer::LocalOrdinal cell_1;
648  panzer::LocalOrdinal subcell_index_0;
649  panzer::LocalOrdinal subcell_index_1;
650  };
651 
652 
653  // Figure out how many cells on the other side of the sideset are ghost or virtual
654  std::unordered_set<panzer::LocalOrdinal> ghstd_parent_cells_set, virtual_parent_cells_set;
655  std::vector<face_t> faces;
656  {
657  panzer::LocalOrdinal parent_virtual_cell_offset = mesh_info.num_owned_cells + mesh_info.num_ghstd_cells;
658  for(const auto & local_cell_index_pair : owned_parent_cell_index_map){
659  const panzer::LocalOrdinal local_cell = local_cell_index_pair.first;
660  const std::vector<panzer::LocalOrdinal> & subcell_indexes_vec = local_cell_index_pair.second;
661 
662  for(const panzer::LocalOrdinal & subcell_index : subcell_indexes_vec){
663 
664  const panzer::LocalOrdinal face = mesh_info.cell_to_faces(local_cell, subcell_index);
665  const panzer::LocalOrdinal face_other_side = (mesh_info.face_to_cells(face,0) == local_cell) ? 1 : 0;
666 
667  TEUCHOS_ASSERT(subcell_index == mesh_info.face_to_lidx(face, 1-face_other_side));
668 
669  const panzer::LocalOrdinal other_side_cell = mesh_info.face_to_cells(face, face_other_side);
670  const panzer::LocalOrdinal other_side_subcell_index = mesh_info.face_to_lidx(face, face_other_side);
671 
672  faces.push_back(face_t(local_cell, other_side_cell, subcell_index, other_side_subcell_index));
673 
674  if(other_side_cell >= parent_virtual_cell_offset){
675  virtual_parent_cells_set.insert(other_side_cell);
676  } else {
677  ghstd_parent_cells_set.insert(other_side_cell);
678  }
679  }
680  }
681  }
682 
683  std::vector<panzer::LocalOrdinal> all_cells;
684  all_cells.insert(all_cells.end(),owned_parent_cells_set.begin(),owned_parent_cells_set.end());
685  all_cells.insert(all_cells.end(),ghstd_parent_cells_set.begin(),ghstd_parent_cells_set.end());
686  all_cells.insert(all_cells.end(),virtual_parent_cells_set.begin(),virtual_parent_cells_set.end());
687 
688  sideset_info.num_ghstd_cells = ghstd_parent_cells_set.size();
689  sideset_info.num_virtual_cells = virtual_parent_cells_set.size();
690 
691  const panzer::LocalOrdinal num_real_cells = sideset_info.num_owned_cells + sideset_info.num_ghstd_cells;
692  const panzer::LocalOrdinal num_total_cells = num_real_cells + sideset_info.num_virtual_cells;
693  const panzer::LocalOrdinal num_vertices_per_cell = mesh_info.cell_vertices.extent(1);
694  const panzer::LocalOrdinal num_dims = mesh_info.cell_vertices.extent(2);
695 
696  sideset_info.global_cells = Kokkos::View<panzer::GlobalOrdinal*>("global_cells", num_total_cells);
697  sideset_info.local_cells = Kokkos::View<panzer::LocalOrdinal*>("local_cells", num_total_cells);
698  sideset_info.cell_vertices = Kokkos::View<double***,PHX::Device>("cell_vertices", num_total_cells, num_vertices_per_cell, num_dims);
699  Kokkos::deep_copy(sideset_info.cell_vertices,0.);
700 
701  for(panzer::LocalOrdinal i=0; i<num_total_cells; ++i){
702  const panzer::LocalOrdinal parent_cell = all_cells[i];
703  sideset_info.local_cells(i) = mesh_info.local_cells(parent_cell);
704  sideset_info.global_cells(i) = mesh_info.global_cells(parent_cell);
705  for(panzer::LocalOrdinal j=0; j<num_vertices_per_cell; ++j){
706  for(panzer::LocalOrdinal k=0; k<num_dims; ++k){
707  sideset_info.cell_vertices(i,j,k) = mesh_info.cell_vertices(parent_cell,j,k);
708  }
709  }
710  }
711 
712  // Now we have to set the connectivity for the faces.
713 
714  const panzer::LocalOrdinal num_faces = faces.size();
715  const panzer::LocalOrdinal num_faces_per_cell = mesh_info.cell_to_faces.extent(1);
716 
717  sideset_info.face_to_cells = Kokkos::View<panzer::LocalOrdinal*[2]>("face_to_cells", num_faces);
718  sideset_info.face_to_lidx = Kokkos::View<panzer::LocalOrdinal*[2]>("face_to_lidx", num_faces);
719  sideset_info.cell_to_faces = Kokkos::View<panzer::LocalOrdinal**>("cell_to_faces", num_total_cells, num_faces_per_cell);
720 
721  // Default the system with invalid cell index - this will be most of the entries
722  Kokkos::deep_copy(sideset_info.cell_to_faces, -1);
723 
724  for(int face_index=0;face_index<num_faces;++face_index){
725  const face_t & face = faces[face_index];
726  const panzer::LocalOrdinal & cell_0 = face.cell_0;
727  const panzer::LocalOrdinal & cell_1 = face.cell_1;
728 
729  // TODO: Super expensive... need to find a better way
730  const panzer::LocalOrdinal sideset_cell_0 = std::distance(all_cells.begin(), std::find(all_cells.begin(), all_cells.end(), cell_0));
731  const panzer::LocalOrdinal sideset_cell_1 = std::distance(all_cells.begin(), std::find(all_cells.begin()+num_owned_cells, all_cells.end(), cell_1));
732 
733  sideset_info.face_to_cells(face_index,0) = sideset_cell_0;
734  sideset_info.face_to_cells(face_index,1) = sideset_cell_1;
735 
736  sideset_info.face_to_lidx(face_index,0) = face.subcell_index_0;
737  sideset_info.face_to_lidx(face_index,1) = face.subcell_index_1;
738 
739  sideset_info.cell_to_faces(sideset_cell_0,face.subcell_index_0) = face_index;
740  sideset_info.cell_to_faces(sideset_cell_1,face.subcell_index_1) = face_index;
741 
742  }
743 
744 }
745 
746 } // namespace
747 
748 void
750  panzer::LocalMeshInfo & mesh_info)
751 {
752  using Teuchos::RCP;
753  using Teuchos::rcp;
754 
755  //typedef Tpetra::CrsMatrix<int,panzer::LocalOrdinal,panzer::GlobalOrdinal> crs_type;
756  typedef Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> map_type;
757  typedef Tpetra::Import<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> import_type;
758  //typedef Tpetra::MultiVector<double,panzer::LocalOrdinal,panzer::GlobalOrdinal> mvec_type;
759  //typedef Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal> ordmvec_type;
760 
761  // Make sure the STK interface is valid
763 
764  // This is required by some of the STK stuff
765  TEUCHOS_ASSERT(typeid(panzer::LocalOrdinal) == typeid(int));
766 
768 
769  TEUCHOS_FUNC_TIME_MONITOR_DIFF("panzer_stk::generateLocalMeshInfo",GenerateLocalMeshInfo);
770 
771  // This horrible line of code is required since the connection manager only takes rcps of a mesh
772  RCP<const panzer_stk::STK_Interface> mesh_rcp = Teuchos::rcpFromRef(mesh);
773  // We're allowed to do this since the connection manager only exists in this scope... even though it is also an RCP...
774 
775  // extract topology handle
776  RCP<panzer::ConnManager> conn_rcp = rcp(new panzer_stk::STKConnManager(mesh_rcp));
777  panzer::ConnManager & conn = *conn_rcp;
778 
779  // build cell to node map
780  Kokkos::View<panzer::GlobalOrdinal**> owned_cell_to_nodes;
781  buildCellToNodes(conn, owned_cell_to_nodes);
782 
783  // build the local to global cell ID map
785  Kokkos::View<panzer::GlobalOrdinal*> owned_cells;
786  buildCellGlobalIDs(conn, owned_cells);
787 
788  // get neighboring cells
790  Kokkos::View<const panzer::GlobalOrdinal*> ghstd_cells = buildGhostedCellOneRing(comm,owned_cells,owned_cell_to_nodes);
791 
792  // build cell maps
794 
795  RCP<map_type> owned_cell_map = rcp(new map_type(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),owned_cells, 0,comm));
796  RCP<map_type> ghstd_cell_map = rcp(new map_type(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),ghstd_cells,0,comm));
797 
798  // build importer: cell importer, owned to ghstd
799  RCP<import_type> cellimport_own2ghst = rcp(new import_type(owned_cell_map,ghstd_cell_map));
800 
801  // read all the vertices associated with these elements, get ghstd contributions
803  std::vector<std::size_t> localCells(owned_cells.extent(0),Teuchos::OrdinalTraits<std::size_t>::invalid());
804  for(size_t i=0;i<localCells.size();i++){
805  localCells[i] = i;
806  }
807 
808  // TODO: This all needs to be rewritten for when element blocks have different cell topologies
809  std::vector<std::string> element_block_names;
810  mesh.getElementBlockNames(element_block_names);
811 
812  const shards::CellTopology & cell_topology = *(mesh.getCellTopology(element_block_names[0]));
813 
814  const int space_dim = cell_topology.getDimension();
815  const int vertices_per_cell = cell_topology.getVertexCount();
816  const int faces_per_cell = cell_topology.getSubcellCount(space_dim-1);
817 
818  // Kokkos::View<double***> owned_vertices("owned_vertices",localCells.size(),vertices_per_cell,space_dim);
819  Kokkos::DynRankView<double,PHX::Device> owned_vertices("owned_vertices",localCells.size(),vertices_per_cell,space_dim);
820  mesh.getElementVerticesNoResize(localCells,owned_vertices);
821 
822  // this builds a ghstd vertex array
823  Kokkos::DynRankView<double,PHX::Device> ghstd_vertices = buildGhostedVertices(*cellimport_own2ghst,owned_vertices);
824 
825  // build edge to cell neighbor mapping
827 
828  std::unordered_map<panzer::GlobalOrdinal,int> global_to_local;
829  global_to_local[-1] = -1; // this is the "no neighbor" flag
830  for(size_t i=0;i<owned_cells.extent(0);i++)
831  global_to_local[owned_cells(i)] = i;
832  for(size_t i=0;i<ghstd_cells.extent(0);i++)
833  global_to_local[ghstd_cells(i)] = i+Teuchos::as<int>(owned_cells.extent(0));
834 
835  // this class comes from Mini-PIC and Matt B
837  faceToElement->initialize(conn);
838  auto elems_by_face = faceToElement->getFaceToElementsMap();
839  auto face_to_lidx = faceToElement->getFaceToCellLocalIdxMap();
840 
841  const int num_owned_cells =owned_cells.extent(0);
842  const int num_ghstd_cells =ghstd_cells.extent(0);
843 
844 // print_view("elems_by_face",elems_by_face);
845 
846  // We also need to consider faces that connect to cells that do not exist, but are needed for boundary conditions
847  // We dub them virtual cell since there should be no geometry associated with them, or topology really
848  // They exist only for datastorage so that they are consistent with 'real' cells from an algorithm perspective
849 
850  // Each virtual face (face linked to a '-1' cell) requires a virtual cell (i.e. turn the '-1' into a virtual cell)
851  // Virtual cells are those that do not exist but are connected to an owned cell
852  // Note - in the future, ghosted cells will also need to connect to virtual cells at boundary conditions, but for the moment we will ignore this.
853 
854  // Iterate over all faces and identify the faces connected to a potential virtual cell
855  std::vector<int> all_boundary_faces;
856  const int num_faces = elems_by_face.extent(0);
857  for(int face=0;face<num_faces;++face){
858  if(elems_by_face(face,0) < 0 or elems_by_face(face,1) < 0){
859  all_boundary_faces.push_back(face);
860  }
861  }
862  const panzer::LocalOrdinal num_virtual_cells = all_boundary_faces.size();
863 
864  // total cells and faces include owned, ghosted, and virtual
865  const panzer::LocalOrdinal num_real_cells = num_owned_cells + num_ghstd_cells;
866  const panzer::LocalOrdinal num_total_cells = num_real_cells + num_virtual_cells;
867  const panzer::LocalOrdinal num_total_faces = elems_by_face.extent(0);
868 
869  // Create some global indexes associated with the virtual cells
870  // Note: We are assuming that virtual cells belong to ranks and are not 'shared' - this will change later on
871  Kokkos::View<panzer::GlobalOrdinal*> virtual_cells = Kokkos::View<panzer::GlobalOrdinal*>("virtual_cells",num_virtual_cells);
872  {
873  PANZER_FUNC_TIME_MONITOR_DIFF("Initial global index creation",InitialGlobalIndexCreation);
874 
875  const int num_ranks = comm->getSize();
876  const int rank = comm->getRank();
877 
878  std::vector<panzer::GlobalOrdinal> owned_cell_distribution(num_ranks,0);
879  {
880  std::vector<panzer::GlobalOrdinal> my_owned_cell_distribution(num_ranks,0);
881  my_owned_cell_distribution[rank] = num_owned_cells;
882 
883  Teuchos::reduceAll(*comm,Teuchos::REDUCE_SUM, num_ranks, my_owned_cell_distribution.data(),owned_cell_distribution.data());
884  }
885 
886  std::vector<panzer::GlobalOrdinal> virtual_cell_distribution(num_ranks,0);
887  {
888  std::vector<panzer::GlobalOrdinal> my_virtual_cell_distribution(num_ranks,0);
889  my_virtual_cell_distribution[rank] = num_virtual_cells;
890 
891  Teuchos::reduceAll(*comm,Teuchos::REDUCE_SUM, num_ranks, my_virtual_cell_distribution.data(),virtual_cell_distribution.data());
892  }
893 
894  panzer::GlobalOrdinal num_global_real_cells=0;
895  for(int i=0;i<num_ranks;++i){
896  num_global_real_cells+=owned_cell_distribution[i];
897  }
898 
899  panzer::GlobalOrdinal global_virtual_start_idx = num_global_real_cells;
900  for(int i=0;i<rank;++i){
901  global_virtual_start_idx += virtual_cell_distribution[i];
902  }
903 
904  for(int i=0;i<num_virtual_cells;++i){
905  virtual_cells(i) = global_virtual_start_idx + panzer::GlobalOrdinal(i);
906  }
907 
908  }
909 
910  // Lookup cells connected to a face
911  Kokkos::View<panzer::LocalOrdinal*[2]> face_to_cells = Kokkos::View<panzer::LocalOrdinal*[2]>("face_to_cells",num_total_faces);
912 
913  // Lookup local face indexes given cell and left/right state (0/1)
914  Kokkos::View<panzer::LocalOrdinal*[2]> face_to_localidx = Kokkos::View<panzer::LocalOrdinal*[2]>("face_to_localidx",num_total_faces);
915 
916  // Lookup face index given a cell and local face index
917  Kokkos::View<panzer::LocalOrdinal**> cell_to_face = Kokkos::View<panzer::LocalOrdinal**>("cell_to_face",num_total_cells,faces_per_cell);
918 
919  // initialize with negative one cells that are not associated with a face
920  Kokkos::deep_copy(cell_to_face,-1);
921 
922  // Transfer information from 'faceToElement' datasets to local arrays
923  {
924  PANZER_FUNC_TIME_MONITOR_DIFF("Transer faceToElement to local",TransferFaceToElementLocal);
925 
926  int virtual_cell_index = num_real_cells;
927  for(size_t f=0;f<elems_by_face.extent(0);f++) {
928 
929  const panzer::GlobalOrdinal global_c0 = elems_by_face(f,0);
930  const panzer::GlobalOrdinal global_c1 = elems_by_face(f,1);
931 
932  // make sure that no bonus cells get in here
933  TEUCHOS_ASSERT(global_to_local.find(global_c0)!=global_to_local.end());
934  TEUCHOS_ASSERT(global_to_local.find(global_c1)!=global_to_local.end());
935 
936  auto c0 = global_to_local[global_c0];
937  auto lidx0 = face_to_lidx(f,0);
938  auto c1 = global_to_local[global_c1];
939  auto lidx1 = face_to_lidx(f,1);
940 
941  // Test for virtual cells
942 
943  // Left cell
944  if(c0 < 0){
945  // Virtual cell - create it!
946  c0 = virtual_cell_index++;
947 
948  // We need the subcell_index to line up between real and virtual cell
949  // This way the face has the same geometry... though the face normal
950  // will point in the wrong direction
951  lidx0 = lidx1;
952  }
953  cell_to_face(c0,lidx0) = f;
954 
955 
956  // Right cell
957  if(c1 < 0){
958  // Virtual cell - create it!
959  c1 = virtual_cell_index++;
960 
961  // We need the subcell_index to line up between real and virtual cell
962  // This way the face has the same geometry... though the face normal
963  // will point in the wrong direction
964  lidx1 = lidx0;
965  }
966  cell_to_face(c1,lidx1) = f;
967 
968  // Faces point from low cell index to high cell index
969  if(c0<c1){
970  face_to_cells(f,0) = c0;
971  face_to_localidx(f,0) = lidx0;
972  face_to_cells(f,1) = c1;
973  face_to_localidx(f,1) = lidx1;
974  } else {
975  face_to_cells(f,0) = c1;
976  face_to_localidx(f,0) = lidx1;
977  face_to_cells(f,1) = c0;
978  face_to_localidx(f,1) = lidx0;
979  }
980 
981  // We should avoid having two virtual cells linked together.
982  TEUCHOS_ASSERT(c0<num_real_cells or c1<num_real_cells)
983 
984  }
985  }
986 
987  // at this point all the data structures have been built, so now we can "do" DG.
988  // There are two of everything, an "owned" data structured corresponding to "owned"
989  // cells. And a "ghstd" data structure corresponding to ghosted cells
991  {
992  PANZER_FUNC_TIME_MONITOR_DIFF("Assign Indices",AssignIndices);
993  mesh_info.cell_to_faces = cell_to_face;
994  mesh_info.face_to_cells = face_to_cells; // faces
995  mesh_info.face_to_lidx = face_to_localidx;
996 
997  mesh_info.num_owned_cells = owned_cells.extent(0);
998  mesh_info.num_ghstd_cells = ghstd_cells.extent(0);
999  mesh_info.num_virtual_cells = virtual_cells.extent(0);
1000 
1001  mesh_info.global_cells = Kokkos::View<panzer::GlobalOrdinal*>("global_cell_indices",num_total_cells);
1002  mesh_info.local_cells = Kokkos::View<panzer::LocalOrdinal*>("local_cell_indices",num_total_cells);
1003 
1004  for(int i=0;i<num_owned_cells;++i){
1005  mesh_info.global_cells(i) = owned_cells(i);
1006  mesh_info.local_cells(i) = i;
1007  }
1008 
1009  for(int i=0;i<num_ghstd_cells;++i){
1010  mesh_info.global_cells(i+num_owned_cells) = ghstd_cells(i);
1011  mesh_info.local_cells(i+num_owned_cells) = i+num_owned_cells;
1012  }
1013 
1014  for(int i=0;i<num_virtual_cells;++i){
1015  mesh_info.global_cells(i+num_real_cells) = virtual_cells(i);
1016  mesh_info.local_cells(i+num_real_cells) = i+num_real_cells;
1017  }
1018 
1019  mesh_info.cell_vertices = Kokkos::View<double***, PHX::Device>("cell_vertices",num_total_cells,vertices_per_cell,space_dim);
1020 
1021  // Initialize coordinates to zero
1022  Kokkos::deep_copy(mesh_info.cell_vertices, 0.);
1023 
1024  for(int i=0;i<num_owned_cells;++i){
1025  for(int j=0;j<vertices_per_cell;++j){
1026  for(int k=0;k<space_dim;++k){
1027  mesh_info.cell_vertices(i,j,k) = owned_vertices(i,j,k);
1028  }
1029  }
1030  }
1031 
1032  for(int i=0;i<num_ghstd_cells;++i){
1033  for(int j=0;j<vertices_per_cell;++j){
1034  for(int k=0;k<space_dim;++k){
1035  mesh_info.cell_vertices(i+num_owned_cells,j,k) = ghstd_vertices(i,j,k);
1036  }
1037  }
1038  }
1039 
1040  // This will backfire at some point, but we're going to make the virtual cell have the same geometry as the cell it interfaces with
1041  // This way we can define a virtual cell geometry without extruding the face outside of the domain
1042  {
1043  PANZER_FUNC_TIME_MONITOR_DIFF("Assign geometry traits",AssignGeometryTraits);
1044  for(int i=0;i<num_virtual_cells;++i){
1045 
1046  const panzer::LocalOrdinal virtual_cell = i+num_real_cells;
1047  bool exists = false;
1048  for(int local_face=0; local_face<faces_per_cell; ++local_face){
1049  const panzer::LocalOrdinal face = cell_to_face(virtual_cell, local_face);
1050  if(face >= 0){
1051  exists = true;
1052  const panzer::LocalOrdinal other_side = (face_to_cells(face, 0) == virtual_cell) ? 1 : 0;
1053  const panzer::LocalOrdinal real_cell = face_to_cells(face,other_side);
1054  TEUCHOS_ASSERT(real_cell < num_real_cells);
1055  for(int j=0;j<vertices_per_cell;++j){
1056  for(int k=0;k<space_dim;++k){
1057  mesh_info.cell_vertices(virtual_cell,j,k) = mesh_info.cell_vertices(real_cell,j,k);
1058  }
1059  }
1060  break;
1061  }
1062  }
1063  TEUCHOS_TEST_FOR_EXCEPT_MSG(!exists, "panzer_stk::generateLocalMeshInfo : Virtual cell is not linked to real cell");
1064  }
1065  }
1066  }
1067 
1068  // Setup element blocks and sidesets
1069  std::vector<std::string> sideset_names;
1070  mesh.getSidesetNames(sideset_names);
1071 
1072  for(const std::string & element_block_name : element_block_names){
1073  PANZER_FUNC_TIME_MONITOR_DIFF("Set up setupLocalMeshBlockInfo",SetupLocalMeshBlockInfo);
1074  panzer::LocalMeshBlockInfo & block_info = mesh_info.element_blocks[element_block_name];
1075  setupLocalMeshBlockInfo(mesh, conn, mesh_info, element_block_name, block_info);
1076 
1077  // Setup sidesets
1078  for(const std::string & sideset_name : sideset_names){
1079  PANZER_FUNC_TIME_MONITOR_DIFF("Setup LocalMeshSidesetInfo",SetupLocalMeshSidesetInfo);
1080  panzer::LocalMeshSidesetInfo & sideset_info = mesh_info.sidesets[element_block_name][sideset_name];
1081  setupLocalMeshSidesetInfo(mesh, conn, mesh_info, element_block_name, sideset_name, sideset_info);
1082  }
1083 
1084  }
1085 
1086 }
1087 
1088 }
void getSidesetNames(std::vector< std::string > &name) const
std::map< std::string, std::map< std::string, LocalMeshSidesetInfo > > sidesets
Kokkos::View< double ***, PHX::Device > cell_vertices
void getElementVerticesNoResize(const std::vector< std::size_t > &localIds, ArrayT &vertices) const
Kokkos::View< panzer::LocalOrdinal * > local_cells
void getElementBlockNames(std::vector< std::string > &names) const
Teuchos::RCP< const shards::CellTopology > cell_topology
void generateLocalMeshInfo(const panzer_stk::STK_Interface &mesh, panzer::LocalMeshInfo &mesh_info)
virtual LocalOrdinal getConnectivitySize(LocalOrdinal localElmtId) const =0
Kokkos::View< panzer::GlobalOrdinal * > global_cells
panzer::LocalOrdinal num_owned_cells
Kokkos::View< panzer::LocalOrdinal *[2]> face_to_cells
void getMySides(const std::string &sideName, std::vector< stk::mesh::Entity > &sides) const
std::size_t elementLocalId(stk::mesh::Entity elmt) const
panzer::LocalOrdinal num_virtual_cells
Teuchos::RCP< const shards::CellTopology > cell_topology
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
#define TEUCHOS_TEST_FOR_EXCEPT_MSG(throw_exception_test, msg)
virtual const std::vector< LocalOrdinal > & getElementBlock(const std::string &blockID) const =0
virtual void getElementBlockIds(std::vector< std::string > &elementBlockIds) const =0
Pure virtual base class for supplying mesh connectivity information to the DOF Manager.
TEUCHOS_DEPRECATED void reduceAll(const Comm< Ordinal > &comm, const EReductionType reductType, const Packet &send, Packet *globalReduct)
virtual void getElementBlockTopologies(std::vector< shards::CellTopology > &elementBlockTopologies) const =0
panzer::LocalOrdinal num_ghstd_cells
std::map< std::string, LocalMeshBlockInfo > element_blocks
bool isInitialized() const
Has initialize been called on this mesh object?
Kokkos::View< panzer::LocalOrdinal *[2]> face_to_lidx
Kokkos::View< panzer::LocalOrdinal ** > cell_to_faces
Teuchos::RCP< const Teuchos::Comm< int > > getComm() const
get the comm associated with this mesh
#define TEUCHOS_ASSERT(assertion_test)
void getSideElementCascade(const panzer_stk::STK_Interface &mesh, const std::string &blockId, const std::vector< stk::mesh::Entity > &sides, std::vector< std::size_t > &localSubcellDim, std::vector< std::size_t > &localSubcellIds, std::vector< stk::mesh::Entity > &elements)
void setupSubLocalMeshInfo(const panzer::LocalMeshInfoBase &parent_info, const std::vector< panzer::LocalOrdinal > &owned_parent_cells, panzer::LocalMeshInfoBase &sub_info)
virtual void buildConnectivity(const FieldPattern &fp)=0
Teuchos::RCP< const shards::CellTopology > getCellTopology(const std::string &eBlock) const
#define TEUCHOS_FUNC_TIME_MONITOR_DIFF(FUNCNAME, DIFF)
virtual std::string getBlockId(LocalOrdinal localElmtId) const =0
#define TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(throw_exception_test, Exception, msg)
virtual const GlobalOrdinal * getConnectivity(LocalOrdinal localElmtId) const =0