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 
260  // fill in the cell to node matrix
261  const unsigned int num_local_cells = owned_cells_to_nodes.extent(0);
262  const unsigned int num_nodes_per_cell = owned_cells_to_nodes.extent(1);
263 
264  // The matrix is indexed by (global cell, global node) = local node
265  cell_to_node = rcp(new crs_type(cell_map,num_nodes_per_cell,
266  Tpetra::StaticProfile));
267 
268  std::vector<panzer::LocalOrdinal> local_node_indexes(num_nodes_per_cell);
269  std::vector<panzer::GlobalOrdinal> global_node_indexes(num_nodes_per_cell);
270  for(unsigned int i=0;i<num_local_cells;i++) {
271  const panzer::GlobalOrdinal global_cell_index = owned_cells(i);
272  // std::vector<panzer::LocalOrdinal> vals(cells_to_nodes.extent(1));
273  // std::vector<panzer::GlobalOrdinal> cols(cells_to_nodes.extent(1));
274  for(unsigned int j=0;j<num_nodes_per_cell;j++) {
275  // vals[j] = Teuchos::as<panzer::LocalOrdinal>(j);
276  // cols[j] = cells_to_nodes(i,j);
277  local_node_indexes[j] = Teuchos::as<panzer::LocalOrdinal>(j);
278  global_node_indexes[j] = owned_cells_to_nodes(i,j);
279  }
280 
281  // cell_to_node_mat->insertGlobalValues(cells(i),cols,vals);
282  cell_to_node->insertGlobalValues(global_cell_index,global_node_indexes,local_node_indexes);
283  }
284  cell_to_node->fillComplete(unique_node_map,cell_map);
285 
286  }
287 
288  // Transpose the cell_to_node array to create the node_to_cell array
289  RCP<crs_type> node_to_cell;
290  {
291  PANZER_FUNC_TIME_MONITOR_DIFF("Tranpose matrix",TransposeMatrix);
292  // Create an object designed to transpose the (global cell, global node) matrix to give
293  // a (global node, global cell) matrix
294  Tpetra::RowMatrixTransposer<panzer::LocalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> transposer(cell_to_node);
295 
296  // Create the transpose crs matrix
297  auto trans = transposer.createTranspose();
298 
299  // We want to import the portion of the transposed matrix relating to all nodes on this process
300  // The importer must import nodes required by this process (node_map) from the unique nodes (nodes living on a process)
301  RCP<import_type> import = rcp(new import_type(unique_node_map,node_map));
302 
303  // Create the crs matrix to store (ghost node, global cell) array
304  // This CRS matrix will have overlapping rows for shared global nodes
305  node_to_cell = rcp(new crs_type(node_map,0));
306 
307  // Transfer data from the transpose array (associated with unique_node_map) to node_to_cell (associated with node_map)
308  node_to_cell->doImport(*trans,*import,Tpetra::INSERT);
309 
310  // Set the fill - basicially locks down the structured of the CRS matrix - required before doing some operations
311  //node_to_cell->fillComplete();
312  node_to_cell->fillComplete(cell_map,unique_node_map);
313  }
314 
315  // Return the node to cell array
316  return node_to_cell;
317 }
318 
321 Kokkos::View<const panzer::GlobalOrdinal*>
322 buildGhostedCellOneRing(const Teuchos::RCP<const Teuchos::Comm<int> > & comm,
323  Kokkos::View<const panzer::GlobalOrdinal*> cells,
324  Kokkos::View<const panzer::GlobalOrdinal**> cells_to_nodes)
325 {
326 
327  PANZER_FUNC_TIME_MONITOR_DIFF("panzer_stk::buildGhostedCellOneRing",BGCOR);
328  typedef Tpetra::CrsMatrix<int,int,panzer::GlobalOrdinal,panzer::TpetraNodeType> crs_type;
329 
330  // cells : (local cell index) -> global cell index
331  // cells_to_nodes : (local cell index, local node_index) -> global node index
332 
333  /*
334 
335  This function creates a list of global indexes relating to ghost cells
336 
337  It is a little misleading how it does this, but the idea is to use the indexing of a CRS matrix to identify
338  what global cells are connected to which global nodes. The values in the CRS matrix are meaningless, however,
339  the fact that they are filled allows us to ping what index combinations exist.
340 
341  To do this we are going to use cell 'nodes' which could also be cell 'vertices'. It is unclear.
342 
343  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)
344 
345  cell_to_node : cell_to_node[global cell index][global node index] = some value (not important, just has to exist)
346 
347  We are then going to transpose that array
348 
349  node_to_cell : node_to_cell[global node index][global cell index] = some value (not important, just has to exist)
350 
351  The coloring of the node_to_cell array tells us what global cells are connected to a given global node.
352 
353 
354  */
355 
356  // the node to cell matrix: Row = Global Node Id, Cell = Global Cell Id, Value = Cell Local Node Id
357  Teuchos::RCP<crs_type> node_to_cell = buildNodeToCellMatrix(comm,cells,cells_to_nodes);
358 
359  // the set of cells already known
360  std::unordered_set<panzer::GlobalOrdinal> unique_cells;
361 
362  // mark all owned cells as already known, e.g. and not in the list of
363  // ghstd cells to be constructed
364  for(size_t i=0;i<cells.extent(0);i++) {
365  unique_cells.insert(cells(i));
366  }
367 
368  // The set of ghost cells that share a global node with an owned cell
369  std::set<panzer::GlobalOrdinal> ghstd_cells_set;
370 
371  // Get a list of global node indexes associated with the cells owned by this process
372 // auto node_map = node_to_cell->getRangeMap()->getMyGlobalIndices();
373  auto node_map = node_to_cell->getMap()->getMyGlobalIndices();
374 
375  // Iterate through the global node indexes associated with this process
376  for(size_t i=0;i<node_map.extent(0);i++) {
377  const panzer::GlobalOrdinal global_node_index = node_map(i);
378  size_t numEntries = node_to_cell->getNumEntriesInGlobalRow(node_map(i));
379  Teuchos::Array<panzer::GlobalOrdinal> indices(numEntries);
380  Teuchos::Array<int> values(numEntries);
381 
382  // Copy the row for a global node index into a local vector
383  node_to_cell->getGlobalRowCopy(global_node_index,indices,values,numEntries);
384 
385  for(auto index : indices) {
386  // if this is a new index (not owned, not previously found ghstd index
387  // add it to the list of ghstd cells
388  if(unique_cells.find(index)==unique_cells.end()) {
389  ghstd_cells_set.insert(index);
390  unique_cells.insert(index); // make sure you don't find it again
391  }
392  }
393  }
394 
395  // build an array containing only the ghstd cells
396  int indx = 0;
397  Kokkos::View<panzer::GlobalOrdinal*> ghstd_cells("ghstd_cells",ghstd_cells_set.size());
398  for(auto global_cell_index : ghstd_cells_set) {
399  ghstd_cells(indx) = global_cell_index;
400  indx++;
401  }
402 
403 // print_view_1D("ghstd_cells",ghstd_cells);
404 
405  return ghstd_cells;
406 }
407 
411 Kokkos::DynRankView<double,PHX::Device>
412 buildGhostedVertices(const Tpetra::Import<int,panzer::GlobalOrdinal,panzer::TpetraNodeType> & importer,
413  Kokkos::DynRankView<const double,PHX::Device> owned_vertices)
414 {
415  using Teuchos::RCP;
416  using Teuchos::rcp;
417 
418  typedef Tpetra::MultiVector<double,int,panzer::GlobalOrdinal,panzer::TpetraNodeType> mvec_type;
419  typedef typename mvec_type::dual_view_type dual_view_type;
420 
421  size_t owned_cell_cnt = importer.getSourceMap()->getNodeNumElements();
422  size_t ghstd_cell_cnt = importer.getTargetMap()->getNodeNumElements();
423  int vertices_per_cell = owned_vertices.extent(1);
424  int space_dim = owned_vertices.extent(2);
425 
426  TEUCHOS_ASSERT(owned_vertices.extent(0)==owned_cell_cnt);
427 
428  // build vertex multivector
429  RCP<mvec_type> owned_vertices_mv = rcp(new mvec_type(importer.getSourceMap(),vertices_per_cell*space_dim));
430  RCP<mvec_type> ghstd_vertices_mv = rcp(new mvec_type(importer.getTargetMap(),vertices_per_cell*space_dim));
431 
432  {
433  auto owned_vertices_view = owned_vertices_mv->template getLocalView<dual_view_type>();
434  for(size_t i=0;i<owned_cell_cnt;i++) {
435  int l = 0;
436  for(int j=0;j<vertices_per_cell;j++)
437  for(int k=0;k<space_dim;k++,l++)
438  owned_vertices_view(i,l) = owned_vertices(i,j,k);
439  }
440  }
441 
442  // communicate ghstd vertices
443  ghstd_vertices_mv->doImport(*owned_vertices_mv,importer,Tpetra::INSERT);
444 
445  // copy multivector into ghstd vertex structure
446  Kokkos::DynRankView<double,PHX::Device> ghstd_vertices("ghstd_vertices",ghstd_cell_cnt,vertices_per_cell,space_dim);
447  {
448  auto ghstd_vertices_view = ghstd_vertices_mv->template getLocalView<dual_view_type>();
449  for(size_t i=0;i<ghstd_cell_cnt;i++) {
450  int l = 0;
451  for(int j=0;j<vertices_per_cell;j++)
452  for(int k=0;k<space_dim;k++,l++)
453  ghstd_vertices(i,j,k) = ghstd_vertices_view(i,l);
454  }
455  }
456 
457  return ghstd_vertices;
458 } // end build ghstd vertices
459 
460 void
461 setupLocalMeshBlockInfo(const panzer_stk::STK_Interface & mesh,
462  panzer::ConnManager & conn,
463  const panzer::LocalMeshInfo & mesh_info,
464  const std::string & element_block_name,
465  panzer::LocalMeshBlockInfo & block_info)
466 {
467 
468  // This function identifies all cells in mesh_info that belong to element_block_name
469  // and creates a block_info from it.
470 
471  const int num_parent_owned_cells = mesh_info.num_owned_cells;
472 
473  // Make sure connectivity is setup for interfaces between cells
474  {
475  const shards::CellTopology & topology = *(mesh.getCellTopology(element_block_name));
477  if(topology.getDimension() == 1){
478  cell_pattern = Teuchos::rcp(new panzer::EdgeFieldPattern(topology));
479  } else if(topology.getDimension() == 2){
480  cell_pattern = Teuchos::rcp(new panzer::FaceFieldPattern(topology));
481  } else if(topology.getDimension() == 3){
482  cell_pattern = Teuchos::rcp(new panzer::ElemFieldPattern(topology));
483  }
484 
485  {
486  PANZER_FUNC_TIME_MONITOR("Build connectivity");
487  conn.buildConnectivity(*cell_pattern);
488  }
489  }
490 
491  std::vector<panzer::LocalOrdinal> owned_block_cells;
492  for(int parent_owned_cell=0;parent_owned_cell<num_parent_owned_cells;++parent_owned_cell){
493  const panzer::LocalOrdinal local_cell = mesh_info.local_cells(parent_owned_cell);
494  const bool is_in_block = conn.getBlockId(local_cell) == element_block_name;
495 
496  if(is_in_block){
497  owned_block_cells.push_back(parent_owned_cell);
498  }
499 
500  }
501 
502  if ( owned_block_cells.size() == 0 )
503  return;
504  block_info.num_owned_cells = owned_block_cells.size();
505  block_info.element_block_name = element_block_name;
506  block_info.cell_topology = mesh.getCellTopology(element_block_name);
507  {
508  PANZER_FUNC_TIME_MONITOR("panzer::partitioning_utilities::setupSubLocalMeshInfo");
509  panzer::partitioning_utilities::setupSubLocalMeshInfo(mesh_info, owned_block_cells, block_info);
510  }
511 }
512 
513 
514 void
515 setupLocalMeshSidesetInfo(const panzer_stk::STK_Interface & mesh,
516  panzer::ConnManager& /* conn */,
517  const panzer::LocalMeshInfo & mesh_info,
518  const std::string & element_block_name,
519  const std::string & sideset_name,
520  panzer::LocalMeshSidesetInfo & sideset_info)
521 {
522 
523  // We use these typedefs to make the algorithm slightly more clear
524  using LocalOrdinal = panzer::LocalOrdinal;
525  using ParentOrdinal = int;
526  using SubcellOrdinal = short;
527 
528  // This function identifies all cells in mesh_info that belong to element_block_name
529  // and creates a block_info from it.
530 
531  // This is a list of all entities that make up the 'side'
532  std::vector<stk::mesh::Entity> side_entities;
533 
534  // Grab the side entities associated with this sideset on the mesh
535  // Note: Throws exception if element block or sideset doesn't exist
536  try{
537 
538  mesh.getAllSides(sideset_name, element_block_name, side_entities);
539 
540  } catch(STK_Interface::SidesetException & e) {
541  std::stringstream ss;
542  std::vector<std::string> sideset_names;
543  mesh.getSidesetNames(sideset_names);
544 
545  // build an error message
546  ss << e.what() << "\nChoose existing sideset:\n";
547  for(const auto & optional_sideset_name : sideset_names){
548  ss << "\t\"" << optional_sideset_name << "\"\n";
549  }
550 
551  TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true,std::logic_error,ss.str());
552 
553  } catch(STK_Interface::ElementBlockException & e) {
554  std::stringstream ss;
555  std::vector<std::string> element_block_names;
556  mesh.getElementBlockNames(element_block_names);
557 
558  // build an error message
559  ss << e.what() << "\nChoose existing element block:\n";
560  for(const auto & optional_element_block_name : element_block_names){
561  ss << "\t\"" << optional_element_block_name << "\"\n";
562  }
563 
564  TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true,std::logic_error,ss.str());
565 
566  } catch(std::logic_error & e) {
567  std::stringstream ss;
568  ss << e.what() << "\nUnrecognized logic error.\n";
569 
570  TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true,std::logic_error,ss.str());
571 
572  }
573 
574  // We now have a list of sideset entities, lets unwrap them and create the sideset_info!
575  std::map<ParentOrdinal,std::vector<SubcellOrdinal> > owned_parent_cell_to_subcell_indexes;
576  {
577 
578  // This is the subcell dimension we are trying to line up on the sideset
579  const size_t face_subcell_dimension = static_cast<size_t>(mesh.getCellTopology(element_block_name)->getDimension()-1);
580 
581  // List of local subcell indexes indexed by element:
582  // For example: a Tet (element) would have
583  // - 4 triangular faces (subcell_index 0-3, subcell_dimension=2)
584  // - 6 edges (subcell_index 0-5, subcell_dimension=1)
585  // - 4 vertices (subcell_index 0-3, subcell_dimension=0)
586  // Another example: a Line (element) would have
587  // - 2 vertices (subcell_index 0-1, subcell_dimension=0)
588  std::vector<stk::mesh::Entity> elements;
589  std::vector<size_t> subcell_indexes;
590  std::vector<size_t> subcell_dimensions;
591  panzer_stk::workset_utils::getSideElementCascade(mesh, element_block_name, side_entities, subcell_dimensions, subcell_indexes, elements);
592  const size_t num_elements = subcell_dimensions.size();
593 
594  // We need a fast lookup for maping local indexes to parent indexes
595  std::unordered_map<LocalOrdinal,ParentOrdinal> local_to_parent_lookup;
596  for(ParentOrdinal parent_index=0; parent_index<static_cast<ParentOrdinal>(mesh_info.local_cells.extent(0)); ++parent_index)
597  local_to_parent_lookup[mesh_info.local_cells(parent_index)] = parent_index;
598 
599  // Add the subcell indexes for each element on the sideset
600  // TODO: There is a lookup call here to map from local indexes to parent indexes which slows things down. Maybe there is a way around that
601  for(size_t element_index=0; element_index<num_elements; ++element_index) {
602  const size_t subcell_dimension = subcell_dimensions[element_index];
603 
604  // Add subcell to map
605  if(subcell_dimension == face_subcell_dimension){
606  const SubcellOrdinal subcell_index = static_cast<SubcellOrdinal>(subcell_indexes[element_index]);
607  const LocalOrdinal element_local_index = static_cast<LocalOrdinal>(mesh.elementLocalId(elements[element_index]));
608 
609  // Look up the parent cell index using the local cell index
610  const auto itr = local_to_parent_lookup.find(element_local_index);
611  TEUCHOS_ASSERT(itr!= local_to_parent_lookup.end());
612  const ParentOrdinal element_parent_index = itr->second;
613 
614  owned_parent_cell_to_subcell_indexes[element_parent_index].push_back(subcell_index);
615  }
616  }
617  }
618 
619  // We now know the mapping of parent cell indexes to subcell indexes touching the sideset
620 
621  const panzer::LocalOrdinal num_owned_cells = owned_parent_cell_to_subcell_indexes.size();
622 
623  sideset_info.element_block_name = element_block_name;
624  sideset_info.sideset_name = sideset_name;
625  sideset_info.cell_topology = mesh.getCellTopology(element_block_name);
626 
627  sideset_info.num_owned_cells = num_owned_cells;
628 
629  struct face_t{
630  face_t(const ParentOrdinal c0,
631  const ParentOrdinal c1,
632  const SubcellOrdinal sc0,
633  const SubcellOrdinal sc1)
634  {
635  cell_0=c0;
636  cell_1=c1;
637  subcell_index_0=sc0;
638  subcell_index_1=sc1;
639  }
640  ParentOrdinal cell_0;
641  ParentOrdinal cell_1;
642  SubcellOrdinal subcell_index_0;
643  SubcellOrdinal subcell_index_1;
644  };
645 
646 
647  // Figure out how many cells on the other side of the sideset are ghost or virtual
648  std::unordered_set<panzer::LocalOrdinal> owned_parent_cells_set, ghstd_parent_cells_set, virtual_parent_cells_set;
649  std::vector<face_t> faces;
650  {
651 
652  panzer::LocalOrdinal parent_virtual_cell_offset = mesh_info.num_owned_cells + mesh_info.num_ghstd_cells;
653  for(const auto & local_cell_index_pair : owned_parent_cell_to_subcell_indexes){
654 
655  const ParentOrdinal parent_cell = local_cell_index_pair.first;
656  const auto & subcell_indexes = local_cell_index_pair.second;
657 
658  owned_parent_cells_set.insert(parent_cell);
659 
660  for(const SubcellOrdinal & subcell_index : subcell_indexes){
661 
662  const LocalOrdinal face = mesh_info.cell_to_faces(parent_cell, subcell_index);
663  const LocalOrdinal face_other_side = (mesh_info.face_to_cells(face,0) == parent_cell) ? 1 : 0;
664 
665  TEUCHOS_ASSERT(subcell_index == mesh_info.face_to_lidx(face, 1-face_other_side));
666 
667  const ParentOrdinal other_side_cell = mesh_info.face_to_cells(face, face_other_side);
668  const SubcellOrdinal other_side_subcell_index = mesh_info.face_to_lidx(face, face_other_side);
669 
670  faces.push_back(face_t(parent_cell, other_side_cell, subcell_index, other_side_subcell_index));
671 
672  if(other_side_cell >= parent_virtual_cell_offset){
673  virtual_parent_cells_set.insert(other_side_cell);
674  } else {
675  ghstd_parent_cells_set.insert(other_side_cell);
676  }
677  }
678  }
679  }
680 
681  std::vector<ParentOrdinal> all_cells;
682  all_cells.insert(all_cells.end(),owned_parent_cells_set.begin(),owned_parent_cells_set.end());
683  all_cells.insert(all_cells.end(),ghstd_parent_cells_set.begin(),ghstd_parent_cells_set.end());
684  all_cells.insert(all_cells.end(),virtual_parent_cells_set.begin(),virtual_parent_cells_set.end());
685 
686  sideset_info.num_ghstd_cells = ghstd_parent_cells_set.size();
687  sideset_info.num_virtual_cells = virtual_parent_cells_set.size();
688 
689  const LocalOrdinal num_real_cells = sideset_info.num_owned_cells + sideset_info.num_ghstd_cells;
690  const LocalOrdinal num_total_cells = num_real_cells + sideset_info.num_virtual_cells;
691  const LocalOrdinal num_vertices_per_cell = mesh_info.cell_vertices.extent(1);
692  const LocalOrdinal num_dims = mesh_info.cell_vertices.extent(2);
693 
694  // Copy local indexes, global indexes, and cell vertices to sideset info
695  {
696  sideset_info.global_cells = Kokkos::View<panzer::GlobalOrdinal*>("global_cells", num_total_cells);
697  sideset_info.local_cells = Kokkos::View<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(LocalOrdinal i=0; i<num_total_cells; ++i){
702  const ParentOrdinal 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(LocalOrdinal j=0; j<num_vertices_per_cell; ++j)
706  for(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  // Now we have to set the connectivity for the faces.
712 
713  const LocalOrdinal num_faces = faces.size();
714  const LocalOrdinal num_faces_per_cell = mesh_info.cell_to_faces.extent(1);
715 
716  sideset_info.face_to_cells = Kokkos::View<LocalOrdinal*[2]>("face_to_cells", num_faces);
717  sideset_info.face_to_lidx = Kokkos::View<LocalOrdinal*[2]>("face_to_lidx", num_faces);
718  sideset_info.cell_to_faces = Kokkos::View<LocalOrdinal**>("cell_to_faces", num_total_cells, num_faces_per_cell);
719 
720  // Default the system with invalid cell index - this will be most of the entries
721  Kokkos::deep_copy(sideset_info.cell_to_faces, -1);
722 
723  // Lookup for sideset cell index given parent cell index
724  std::unordered_map<ParentOrdinal,ParentOrdinal> parent_to_sideset_lookup;
725  for(unsigned int i=0; i<all_cells.size(); ++i)
726  parent_to_sideset_lookup[all_cells[i]] = i;
727 
728  for(int face_index=0;face_index<num_faces;++face_index){
729  const face_t & face = faces[face_index];
730  const ParentOrdinal & parent_cell_0 = face.cell_0;
731  const ParentOrdinal & parent_cell_1 = face.cell_1;
732 
733  // Convert the parent cell index into a sideset cell index
734  const auto itr_0 = parent_to_sideset_lookup.find(parent_cell_0);
735  TEUCHOS_ASSERT(itr_0 != parent_to_sideset_lookup.end());
736  const ParentOrdinal sideset_cell_0 = itr_0->second;
737 
738  const auto itr_1 = parent_to_sideset_lookup.find(parent_cell_1);
739  TEUCHOS_ASSERT(itr_1 != parent_to_sideset_lookup.end());
740  const ParentOrdinal sideset_cell_1 = itr_1->second;
741 
742 // const ParentOrdinal sideset_cell_0 = std::distance(all_cells.begin(), std::find(all_cells.begin(), all_cells.end(), parent_cell_0));
743 // const ParentOrdinal sideset_cell_1 = std::distance(all_cells.begin(), std::find(all_cells.begin()+num_owned_cells, all_cells.end(), parent_cell_1));
744 
745  sideset_info.face_to_cells(face_index,0) = sideset_cell_0;
746  sideset_info.face_to_cells(face_index,1) = sideset_cell_1;
747 
748  sideset_info.face_to_lidx(face_index,0) = face.subcell_index_0;
749  sideset_info.face_to_lidx(face_index,1) = face.subcell_index_1;
750 
751  sideset_info.cell_to_faces(sideset_cell_0,face.subcell_index_0) = face_index;
752  sideset_info.cell_to_faces(sideset_cell_1,face.subcell_index_1) = face_index;
753 
754  }
755 
756 }
757 
758 } // namespace
759 
760 void
762  panzer::LocalMeshInfo & mesh_info)
763 {
764  using Teuchos::RCP;
765  using Teuchos::rcp;
766 
767  //typedef Tpetra::CrsMatrix<int,panzer::LocalOrdinal,panzer::GlobalOrdinal> crs_type;
768  typedef Tpetra::Map<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> map_type;
769  typedef Tpetra::Import<panzer::LocalOrdinal,panzer::GlobalOrdinal,panzer::TpetraNodeType> import_type;
770  //typedef Tpetra::MultiVector<double,panzer::LocalOrdinal,panzer::GlobalOrdinal> mvec_type;
771  //typedef Tpetra::MultiVector<panzer::GlobalOrdinal,panzer::LocalOrdinal,panzer::GlobalOrdinal> ordmvec_type;
772 
773  // Make sure the STK interface is valid
775 
776  // This is required by some of the STK stuff
777  TEUCHOS_ASSERT(typeid(panzer::LocalOrdinal) == typeid(int));
778 
780 
781  TEUCHOS_FUNC_TIME_MONITOR_DIFF("panzer_stk::generateLocalMeshInfo",GenerateLocalMeshInfo);
782 
783  // This horrible line of code is required since the connection manager only takes rcps of a mesh
784  RCP<const panzer_stk::STK_Interface> mesh_rcp = Teuchos::rcpFromRef(mesh);
785  // We're allowed to do this since the connection manager only exists in this scope... even though it is also an RCP...
786 
787  // extract topology handle
788  RCP<panzer::ConnManager> conn_rcp = rcp(new panzer_stk::STKConnManager(mesh_rcp));
789  panzer::ConnManager & conn = *conn_rcp;
790 
791  // build cell to node map
792  Kokkos::View<panzer::GlobalOrdinal**> owned_cell_to_nodes;
793  buildCellToNodes(conn, owned_cell_to_nodes);
794 
795  // build the local to global cell ID map
797  Kokkos::View<panzer::GlobalOrdinal*> owned_cells;
798  buildCellGlobalIDs(conn, owned_cells);
799 
800  // get neighboring cells
802  Kokkos::View<const panzer::GlobalOrdinal*> ghstd_cells = buildGhostedCellOneRing(comm,owned_cells,owned_cell_to_nodes);
803 
804  // build cell maps
806 
807  RCP<map_type> owned_cell_map = rcp(new map_type(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),owned_cells, 0,comm));
808  RCP<map_type> ghstd_cell_map = rcp(new map_type(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),ghstd_cells,0,comm));
809 
810  // build importer: cell importer, owned to ghstd
811  RCP<import_type> cellimport_own2ghst = rcp(new import_type(owned_cell_map,ghstd_cell_map));
812 
813  // read all the vertices associated with these elements, get ghstd contributions
815  std::vector<std::size_t> localCells(owned_cells.extent(0),Teuchos::OrdinalTraits<std::size_t>::invalid());
816  for(size_t i=0;i<localCells.size();i++){
817  localCells[i] = i;
818  }
819 
820  // TODO: This all needs to be rewritten for when element blocks have different cell topologies
821  std::vector<std::string> element_block_names;
822  mesh.getElementBlockNames(element_block_names);
823 
824  const shards::CellTopology & cell_topology = *(mesh.getCellTopology(element_block_names[0]));
825 
826  const int space_dim = cell_topology.getDimension();
827  const int vertices_per_cell = cell_topology.getVertexCount();
828  const int faces_per_cell = cell_topology.getSubcellCount(space_dim-1);
829 
830  // Kokkos::View<double***> owned_vertices("owned_vertices",localCells.size(),vertices_per_cell,space_dim);
831  Kokkos::DynRankView<double,PHX::Device> owned_vertices("owned_vertices",localCells.size(),vertices_per_cell,space_dim);
832  mesh.getElementVerticesNoResize(localCells,owned_vertices);
833 
834  // this builds a ghstd vertex array
835  Kokkos::DynRankView<double,PHX::Device> ghstd_vertices = buildGhostedVertices(*cellimport_own2ghst,owned_vertices);
836 
837  // build edge to cell neighbor mapping
839 
840  std::unordered_map<panzer::GlobalOrdinal,int> global_to_local;
841  global_to_local[-1] = -1; // this is the "no neighbor" flag
842  for(size_t i=0;i<owned_cells.extent(0);i++)
843  global_to_local[owned_cells(i)] = i;
844  for(size_t i=0;i<ghstd_cells.extent(0);i++)
845  global_to_local[ghstd_cells(i)] = i+Teuchos::as<int>(owned_cells.extent(0));
846 
847  // this class comes from Mini-PIC and Matt B
849  faceToElement->initialize(conn);
850  auto elems_by_face = faceToElement->getFaceToElementsMap();
851  auto face_to_lidx = faceToElement->getFaceToCellLocalIdxMap();
852 
853  const int num_owned_cells =owned_cells.extent(0);
854  const int num_ghstd_cells =ghstd_cells.extent(0);
855 
856 // print_view("elems_by_face",elems_by_face);
857 
858  // We also need to consider faces that connect to cells that do not exist, but are needed for boundary conditions
859  // We dub them virtual cell since there should be no geometry associated with them, or topology really
860  // They exist only for datastorage so that they are consistent with 'real' cells from an algorithm perspective
861 
862  // Each virtual face (face linked to a '-1' cell) requires a virtual cell (i.e. turn the '-1' into a virtual cell)
863  // Virtual cells are those that do not exist but are connected to an owned cell
864  // 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.
865 
866  // Iterate over all faces and identify the faces connected to a potential virtual cell
867  std::vector<int> all_boundary_faces;
868  const int num_faces = elems_by_face.extent(0);
869  for(int face=0;face<num_faces;++face){
870  if(elems_by_face(face,0) < 0 or elems_by_face(face,1) < 0){
871  all_boundary_faces.push_back(face);
872  }
873  }
874  const panzer::LocalOrdinal num_virtual_cells = all_boundary_faces.size();
875 
876  // total cells and faces include owned, ghosted, and virtual
877  const panzer::LocalOrdinal num_real_cells = num_owned_cells + num_ghstd_cells;
878  const panzer::LocalOrdinal num_total_cells = num_real_cells + num_virtual_cells;
879  const panzer::LocalOrdinal num_total_faces = elems_by_face.extent(0);
880 
881  // Create some global indexes associated with the virtual cells
882  // Note: We are assuming that virtual cells belong to ranks and are not 'shared' - this will change later on
883  Kokkos::View<panzer::GlobalOrdinal*> virtual_cells = Kokkos::View<panzer::GlobalOrdinal*>("virtual_cells",num_virtual_cells);
884  {
885  PANZER_FUNC_TIME_MONITOR_DIFF("Initial global index creation",InitialGlobalIndexCreation);
886 
887  const int num_ranks = comm->getSize();
888  const int rank = comm->getRank();
889 
890  std::vector<panzer::GlobalOrdinal> owned_cell_distribution(num_ranks,0);
891  {
892  std::vector<panzer::GlobalOrdinal> my_owned_cell_distribution(num_ranks,0);
893  my_owned_cell_distribution[rank] = num_owned_cells;
894 
895  Teuchos::reduceAll(*comm,Teuchos::REDUCE_SUM, num_ranks, my_owned_cell_distribution.data(),owned_cell_distribution.data());
896  }
897 
898  std::vector<panzer::GlobalOrdinal> virtual_cell_distribution(num_ranks,0);
899  {
900  std::vector<panzer::GlobalOrdinal> my_virtual_cell_distribution(num_ranks,0);
901  my_virtual_cell_distribution[rank] = num_virtual_cells;
902 
903  Teuchos::reduceAll(*comm,Teuchos::REDUCE_SUM, num_ranks, my_virtual_cell_distribution.data(),virtual_cell_distribution.data());
904  }
905 
906  panzer::GlobalOrdinal num_global_real_cells=0;
907  for(int i=0;i<num_ranks;++i){
908  num_global_real_cells+=owned_cell_distribution[i];
909  }
910 
911  panzer::GlobalOrdinal global_virtual_start_idx = num_global_real_cells;
912  for(int i=0;i<rank;++i){
913  global_virtual_start_idx += virtual_cell_distribution[i];
914  }
915 
916  for(int i=0;i<num_virtual_cells;++i){
917  virtual_cells(i) = global_virtual_start_idx + panzer::GlobalOrdinal(i);
918  }
919 
920  }
921 
922  // Lookup cells connected to a face
923  Kokkos::View<panzer::LocalOrdinal*[2]> face_to_cells = Kokkos::View<panzer::LocalOrdinal*[2]>("face_to_cells",num_total_faces);
924 
925  // Lookup local face indexes given cell and left/right state (0/1)
926  Kokkos::View<panzer::LocalOrdinal*[2]> face_to_localidx = Kokkos::View<panzer::LocalOrdinal*[2]>("face_to_localidx",num_total_faces);
927 
928  // Lookup face index given a cell and local face index
929  Kokkos::View<panzer::LocalOrdinal**> cell_to_face = Kokkos::View<panzer::LocalOrdinal**>("cell_to_face",num_total_cells,faces_per_cell);
930 
931  // initialize with negative one cells that are not associated with a face
932  Kokkos::deep_copy(cell_to_face,-1);
933 
934  // Transfer information from 'faceToElement' datasets to local arrays
935  {
936  PANZER_FUNC_TIME_MONITOR_DIFF("Transer faceToElement to local",TransferFaceToElementLocal);
937 
938  int virtual_cell_index = num_real_cells;
939  for(size_t f=0;f<elems_by_face.extent(0);f++) {
940 
941  const panzer::GlobalOrdinal global_c0 = elems_by_face(f,0);
942  const panzer::GlobalOrdinal global_c1 = elems_by_face(f,1);
943 
944  // make sure that no bonus cells get in here
945  TEUCHOS_ASSERT(global_to_local.find(global_c0)!=global_to_local.end());
946  TEUCHOS_ASSERT(global_to_local.find(global_c1)!=global_to_local.end());
947 
948  auto c0 = global_to_local[global_c0];
949  auto lidx0 = face_to_lidx(f,0);
950  auto c1 = global_to_local[global_c1];
951  auto lidx1 = face_to_lidx(f,1);
952 
953  // Test for virtual cells
954 
955  // Left cell
956  if(c0 < 0){
957  // Virtual cell - create it!
958  c0 = virtual_cell_index++;
959 
960  // We need the subcell_index to line up between real and virtual cell
961  // This way the face has the same geometry... though the face normal
962  // will point in the wrong direction
963  lidx0 = lidx1;
964  }
965  cell_to_face(c0,lidx0) = f;
966 
967 
968  // Right cell
969  if(c1 < 0){
970  // Virtual cell - create it!
971  c1 = virtual_cell_index++;
972 
973  // We need the subcell_index to line up between real and virtual cell
974  // This way the face has the same geometry... though the face normal
975  // will point in the wrong direction
976  lidx1 = lidx0;
977  }
978  cell_to_face(c1,lidx1) = f;
979 
980  // Faces point from low cell index to high cell index
981  if(c0<c1){
982  face_to_cells(f,0) = c0;
983  face_to_localidx(f,0) = lidx0;
984  face_to_cells(f,1) = c1;
985  face_to_localidx(f,1) = lidx1;
986  } else {
987  face_to_cells(f,0) = c1;
988  face_to_localidx(f,0) = lidx1;
989  face_to_cells(f,1) = c0;
990  face_to_localidx(f,1) = lidx0;
991  }
992 
993  // We should avoid having two virtual cells linked together.
994  TEUCHOS_ASSERT(c0<num_real_cells or c1<num_real_cells)
995 
996  }
997  }
998 
999  // at this point all the data structures have been built, so now we can "do" DG.
1000  // There are two of everything, an "owned" data structured corresponding to "owned"
1001  // cells. And a "ghstd" data structure corresponding to ghosted cells
1003  {
1004  PANZER_FUNC_TIME_MONITOR_DIFF("Assign Indices",AssignIndices);
1005  mesh_info.cell_to_faces = cell_to_face;
1006  mesh_info.face_to_cells = face_to_cells; // faces
1007  mesh_info.face_to_lidx = face_to_localidx;
1008 
1009  mesh_info.num_owned_cells = owned_cells.extent(0);
1010  mesh_info.num_ghstd_cells = ghstd_cells.extent(0);
1011  mesh_info.num_virtual_cells = virtual_cells.extent(0);
1012 
1013  mesh_info.global_cells = Kokkos::View<panzer::GlobalOrdinal*>("global_cell_indices",num_total_cells);
1014  mesh_info.local_cells = Kokkos::View<panzer::LocalOrdinal*>("local_cell_indices",num_total_cells);
1015 
1016  for(int i=0;i<num_owned_cells;++i){
1017  mesh_info.global_cells(i) = owned_cells(i);
1018  mesh_info.local_cells(i) = i;
1019  }
1020 
1021  for(int i=0;i<num_ghstd_cells;++i){
1022  mesh_info.global_cells(i+num_owned_cells) = ghstd_cells(i);
1023  mesh_info.local_cells(i+num_owned_cells) = i+num_owned_cells;
1024  }
1025 
1026  for(int i=0;i<num_virtual_cells;++i){
1027  mesh_info.global_cells(i+num_real_cells) = virtual_cells(i);
1028  mesh_info.local_cells(i+num_real_cells) = i+num_real_cells;
1029  }
1030 
1031  mesh_info.cell_vertices = Kokkos::View<double***, PHX::Device>("cell_vertices",num_total_cells,vertices_per_cell,space_dim);
1032 
1033  // Initialize coordinates to zero
1034  Kokkos::deep_copy(mesh_info.cell_vertices, 0.);
1035 
1036  for(int i=0;i<num_owned_cells;++i){
1037  for(int j=0;j<vertices_per_cell;++j){
1038  for(int k=0;k<space_dim;++k){
1039  mesh_info.cell_vertices(i,j,k) = owned_vertices(i,j,k);
1040  }
1041  }
1042  }
1043 
1044  for(int i=0;i<num_ghstd_cells;++i){
1045  for(int j=0;j<vertices_per_cell;++j){
1046  for(int k=0;k<space_dim;++k){
1047  mesh_info.cell_vertices(i+num_owned_cells,j,k) = ghstd_vertices(i,j,k);
1048  }
1049  }
1050  }
1051 
1052  // 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
1053  // This way we can define a virtual cell geometry without extruding the face outside of the domain
1054  {
1055  PANZER_FUNC_TIME_MONITOR_DIFF("Assign geometry traits",AssignGeometryTraits);
1056  for(int i=0;i<num_virtual_cells;++i){
1057 
1058  const panzer::LocalOrdinal virtual_cell = i+num_real_cells;
1059  bool exists = false;
1060  for(int local_face=0; local_face<faces_per_cell; ++local_face){
1061  const panzer::LocalOrdinal face = cell_to_face(virtual_cell, local_face);
1062  if(face >= 0){
1063  exists = true;
1064  const panzer::LocalOrdinal other_side = (face_to_cells(face, 0) == virtual_cell) ? 1 : 0;
1065  const panzer::LocalOrdinal real_cell = face_to_cells(face,other_side);
1066  TEUCHOS_ASSERT(real_cell < num_real_cells);
1067  for(int j=0;j<vertices_per_cell;++j){
1068  for(int k=0;k<space_dim;++k){
1069  mesh_info.cell_vertices(virtual_cell,j,k) = mesh_info.cell_vertices(real_cell,j,k);
1070  }
1071  }
1072  break;
1073  }
1074  }
1075  TEUCHOS_TEST_FOR_EXCEPT_MSG(!exists, "panzer_stk::generateLocalMeshInfo : Virtual cell is not linked to real cell");
1076  }
1077  }
1078  }
1079 
1080  // Setup element blocks and sidesets
1081  std::vector<std::string> sideset_names;
1082  mesh.getSidesetNames(sideset_names);
1083 
1084  for(const std::string & element_block_name : element_block_names){
1085  PANZER_FUNC_TIME_MONITOR_DIFF("Set up setupLocalMeshBlockInfo",SetupLocalMeshBlockInfo);
1086  panzer::LocalMeshBlockInfo & block_info = mesh_info.element_blocks[element_block_name];
1087  setupLocalMeshBlockInfo(mesh, conn, mesh_info, element_block_name, block_info);
1088 
1089  // Setup sidesets
1090  for(const std::string & sideset_name : sideset_names){
1091  PANZER_FUNC_TIME_MONITOR_DIFF("Setup LocalMeshSidesetInfo",SetupLocalMeshSidesetInfo);
1092  panzer::LocalMeshSidesetInfo & sideset_info = mesh_info.sidesets[element_block_name][sideset_name];
1093  setupLocalMeshSidesetInfo(mesh, conn, mesh_info, element_block_name, sideset_name, sideset_info);
1094  }
1095 
1096  }
1097 
1098 }
1099 
1100 }
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
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.
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
void getAllSides(const std::string &sideName, std::vector< stk::mesh::Entity > &sides) const
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