Intrepid2
Intrepid2_CellTopology.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Intrepid2 Package
4 //
5 // Copyright 2007 NTESS and the Intrepid2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
18 #ifndef Intrepid2_CellTopology_h
19 #define Intrepid2_CellTopology_h
20 
21 #include <Shards_CellTopology.hpp>
22 
23 namespace Intrepid2
24 {
28  class CellTopology {
29  public:
30  using CellTopoPtr = Teuchos::RCP<CellTopology>;
31  using CellTopologyKey = std::pair<ordinal_type,ordinal_type>;
32  protected:
33  shards::CellTopology shardsBaseTopology_;
34  ordinal_type tensorialDegree_; // number of tensorial extrusions of the base topology
35 
36  std::string name_;
37 
38  std::vector< std::vector<CellTopoPtr> > subcells_; // ordered by dimension, then ordinal
39  public:
47  CellTopology(const shards::CellTopology &baseTopo, ordinal_type tensorialDegree)
48  :
49  shardsBaseTopology_(baseTopo),
50  tensorialDegree_(tensorialDegree)
51  {
52  using std::vector;
53  if (tensorialDegree_ == 0)
54  {
55  name_ = baseTopo.getName();
56  }
57  else
58  {
59  std::ostringstream nameStream;
60  nameStream << baseTopo.getName();
61  for (int tensorialOrdinal = 0; tensorialOrdinal < tensorialDegree; tensorialOrdinal++)
62  {
63  nameStream << " x Line_2";
64  }
65  name_ = nameStream.str();
66  }
67 
68  int baseDim = baseTopo.getDimension();
69  vector<ordinal_type> subcellCounts = vector<ordinal_type>(baseDim + tensorialDegree_ + 1);
70  subcells_ = vector< vector< CellTopoPtr > >(baseDim + tensorialDegree_ + 1);
71 
72  if (tensorialDegree_==0)
73  {
74  for (int d=0; d<=baseDim; d++)
75  {
76  subcellCounts[d] = static_cast<ordinal_type>(baseTopo.getSubcellCount(d));
77  }
78  }
79  else
80  {
81  CellTopoPtr tensorComponentTopo = getTensorialComponent();
82  subcellCounts[0] = 2 * tensorComponentTopo->getSubcellCount(0);
83  for (int d=1; d < baseDim+tensorialDegree_; d++)
84  {
85  subcellCounts[d] = 2 * tensorComponentTopo->getSubcellCount(d) + tensorComponentTopo->getSubcellCount(d-1);
86  }
87  subcellCounts[baseDim + tensorialDegree_] = 1; // the volume topology
88  }
89  for (int d=0; d<baseDim+tensorialDegree_; d++)
90  {
91  subcells_[d] = vector< CellTopoPtr >(subcellCounts[d]);
92  int subcellCount = subcells_[d].size();
93  for (int scord=0; scord<subcellCount; scord++)
94  {
95  subcells_[d][scord] = getSubcell(d, scord);
96  }
97  }
98  subcells_[baseDim+tensorialDegree_] = vector<CellTopoPtr>(1);
99  subcells_[baseDim+tensorialDegree_][0] = Teuchos::rcp(this, false); // false: does not own memory (self-reference)
100  }
101 
103  const shards::CellTopology & getBaseTopology() const
104  {
105  return shardsBaseTopology_;
106  }
107 
109  ordinal_type getTensorialDegree() const
110  {
111  return tensorialDegree_;
112  }
113 
115  ordinal_type getDimension() const
116  {
117  return shardsBaseTopology_.getDimension() + tensorialDegree_;
118  }
119 
120  static ordinal_type getNodeCount(const shards::CellTopology &shardsTopo)
121  {
122  if (shardsTopo.getDimension()==0) return 1; // Node topology; by my lights shards returns the wrong thing (0) here
123  return shardsTopo.getNodeCount();
124  }
125 
127  ordinal_type getNodeCount() const
128  {
129  ordinal_type two_pow = 1 << tensorialDegree_;
130  return getNodeCount(shardsBaseTopology_) * two_pow;
131  }
132 
134  ordinal_type getVertexCount() const
135  {
136  return getNodeCount();
137  }
138 
140  ordinal_type getEdgeCount() const
141  {
142  return getSubcellCount(1);
143  }
144 
146  ordinal_type getFaceCount() const
147  {
148  return getSubcellCount(2);
149  }
150 
152  ordinal_type getSideCount() const
153  {
154  ordinal_type spaceDim = getDimension();
155  if (spaceDim == 0)
156  {
157  return 0;
158  }
159  else
160  {
161  int sideDim = spaceDim - 1;
162  return getSubcellCount(sideDim);
163  }
164  }
165 
168  std::pair<ordinal_type,ordinal_type> getKey() const
169  {
170  return std::make_pair(static_cast<ordinal_type>(shardsBaseTopology_.getKey()), tensorialDegree_);
171  }
172 
177  ordinal_type getNodeCount( const ordinal_type subcell_dim ,
178  const ordinal_type subcell_ord ) const
179  {
180  return subcells_[subcell_dim][subcell_ord]->getNodeCount();
181  }
182 
185  std::string getName() const
186  {
187  return name_;
188  }
189 
194  ordinal_type getVertexCount( const ordinal_type subcell_dim ,
195  const ordinal_type subcell_ord ) const
196  {
197  return subcells_[subcell_dim][subcell_ord]->getVertexCount();
198  }
199 
204  ordinal_type getEdgeCount( const ordinal_type subcell_dim ,
205  const ordinal_type subcell_ord ) const
206  {
207  return subcells_[subcell_dim][subcell_ord]->getEdgeCount();
208  }
209 
217  ordinal_type getExtrudedSubcellOrdinal( const ordinal_type subcell_dim_in_component_topo ,
218  const ordinal_type subcell_ord_in_component_topo ) const
219  {
220  // The rule is that the two copies (unextruded) of subcells of dimension
221  // (subcell_dim_in_component_topo + 1) come first, and then the ones built from the extrusion of
222  // subcells of dimension subcell_dim_in_component_topo in the component topology.
223  if (tensorialDegree_==0)
224  {
225  INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "getExtrudedSubcellOrdinal() is not valid for un-extruded topologies");
226  }
227  else
228  {
229  ordinal_type componentSubcellCount = getTensorialComponent()->getSubcellCount(subcell_dim_in_component_topo + 1);
230  return subcell_ord_in_component_topo + componentSubcellCount * 2;
231  }
232  }
233 
238  ordinal_type getSideCount( const ordinal_type subcell_dim ,
239  const ordinal_type subcell_ord ) const
240  {
241  return subcells_[subcell_dim][subcell_ord]->getSideCount();
242  }
243 
244 
248  ordinal_type getSubcellCount( const ordinal_type subcell_dim ) const
249  {
250  if (subcell_dim >= ordinal_type(subcells_.size())) return 0;
251  else return subcells_[subcell_dim].size();
252  }
253 
258  ordinal_type getNodeFromTensorialComponentNodes(const std::vector<ordinal_type> &tensorComponentNodes) const
259  {
260  if (ordinal_type(tensorComponentNodes.size()) != tensorialDegree_ + 1)
261  {
262  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "tensorComponentNodes.size() != _tensorialDegree + 1");
263  }
264  /*
265  Example: we have a base topology of 4 nodes x line x line. Read addresses from right to left.
266 
267  address (1,0,0) --> 0 * (2 * 4) + 0 * 4 + 1 = 1
268  address (0,1,0) --> 0 * (2 * 4) + 1 * 4 + 0 = 4
269  address (0,0,1) --> 1 * (2 * 4) + 0 * 4 + 0 = 8
270  address (0,1,1) --> 1 * (2 * 4) + 1 * 4 + 0 = 12
271 
272  */
273 
274  ordinal_type node = 0;
275  CellTopoPtr line = CellTopology::line();
276  std::vector<CellTopoPtr> componentTopos(tensorialDegree_ + 1, line);
277  componentTopos[0] = cellTopology(shardsBaseTopology_);
278  for (int i=tensorComponentNodes.size()-1; i >= 0; i--)
279  {
280  ordinal_type componentNode = tensorComponentNodes[i];
281  node *= componentTopos[i]->getNodeCount();
282  node += componentNode;
283  }
284  return node;
285  }
286 
293  ordinal_type getNodeMap( const ordinal_type subcell_dim ,
294  const ordinal_type subcell_ord ,
295  const ordinal_type subcell_node_ord ) const
296  {
297  if (subcell_dim == getDimension())
298  {
299  // map from topology to itself
300  if (subcell_ord != 0)
301  {
302  TEUCHOS_TEST_FOR_EXCEPTION(subcell_ord != 0, std::invalid_argument, "subcell ordinal out of bounds");
303  }
304  return subcell_node_ord;
305  }
306  else if (subcell_dim==0)
307  {
308  // mapping a node--the subcell_node_ord must be 0, then, and we should just return the subcell_ord (which is the node ordinal)
309  if (subcell_node_ord != 0)
310  {
311  TEUCHOS_TEST_FOR_EXCEPTION(subcell_node_ord != 0, std::invalid_argument, "subcell node ordinal out of bounds");
312  }
313  return subcell_ord;
314  }
315  if (tensorialDegree_==0)
316  {
317  return shardsBaseTopology_.getNodeMap(subcell_dim, subcell_ord, subcell_node_ord);
318  }
319  else
320  {
321  CellTopoPtr tensorComponentTopo = CellTopology::cellTopology(shardsBaseTopology_, tensorialDegree_ - 1);
322  ordinal_type componentSubcellCount = tensorComponentTopo->getSubcellCount(subcell_dim);
323  if (subcell_ord < componentSubcellCount * 2) // subcell belongs to one of the two component topologies
324  {
325  ordinal_type subcell_ord_comp = subcell_ord % componentSubcellCount; // subcell ordinal in the component topology
326  ordinal_type compOrdinal = subcell_ord / componentSubcellCount; // which component topology? 0 or 1.
327  ordinal_type mappedNodeInsideComponentTopology = tensorComponentTopo->getNodeMap(subcell_dim, subcell_ord_comp, subcell_node_ord);
328  return mappedNodeInsideComponentTopology + compOrdinal * tensorComponentTopo->getNodeCount();
329  }
330  else
331  {
332  // otherwise, the subcell is a tensor product of a component's (subcell_dim-1)-dimensional subcell with the line topology.
333  ordinal_type subcell_ord_comp = subcell_ord - componentSubcellCount * 2;
334  ordinal_type subcell_dim_comp = subcell_dim - 1;
335  CellTopoPtr subcellTensorComponent = tensorComponentTopo->getSubcell(subcell_dim_comp, subcell_ord_comp);
336  // which of the two copies of the subcell tensor component owns the node subcell_node_ord?
337  ordinal_type scCompOrdinal = subcell_node_ord / subcellTensorComponent->getNodeCount(); // 0 or 1
338  // what's the node ordinal inside the subcell component?
339  ordinal_type scCompNodeOrdinal = subcell_node_ord % subcellTensorComponent->getNodeCount();
340  ordinal_type mappedNodeInsideComponentTopology = tensorComponentTopo->getNodeMap(subcell_dim_comp, subcell_ord_comp, scCompNodeOrdinal);
341  return mappedNodeInsideComponentTopology + scCompOrdinal * tensorComponentTopo->getNodeCount();
342  }
343  }
344  }
345 
347  ordinal_type getNodePermutationCount() const;
348 
353  ordinal_type getNodePermutation( const ordinal_type permutation_ord ,
354  const ordinal_type node_ord ) const;
355 
360  ordinal_type getNodePermutationInverse( const ordinal_type permutation_ord ,
361  const ordinal_type node_ord ) const;
362 
365  CellTopoPtr getSide( ordinal_type sideOrdinal ) const;
366 
376  CellTopoPtr getSubcell( ordinal_type scdim, ordinal_type scord ) const
377  {
378  if (tensorialDegree_==0)
379  {
380  return cellTopology(shardsBaseTopology_.getCellTopologyData(scdim, scord), 0);
381  }
382  else
383  {
384  CellTopoPtr tensorComponentTopo = getTensorialComponent();
385  ordinal_type componentSubcellCount = tensorComponentTopo->getSubcellCount(scdim);
386  if (scord < componentSubcellCount * 2)
387  {
388  scord = scord % componentSubcellCount;
389  return tensorComponentTopo->getSubcell(scdim, scord);
390  }
391  // otherwise, the subcell is a tensor product of one of the components (scdim-1)-dimensional subcells with the line topology.
392  scord = scord - componentSubcellCount * 2;
393  scdim = scdim - 1;
394  CellTopoPtr subcellTensorComponent = tensorComponentTopo->getSubcell(scdim, scord);
395  return cellTopology(subcellTensorComponent->getBaseTopology(), subcellTensorComponent->getTensorialDegree() + 1);
396  }
397  }
398 
403  static ordinal_type getSubcellOrdinalMap(CellTopoPtr cellTopo, ordinal_type subcdim, ordinal_type subcord, ordinal_type subsubcdim, ordinal_type subsubcord)
404  {
405  // static map<> …
406  // TODO: implement this method
407 
408  // maps from a subcell's ordering of its subcells (the sub-subcells) to the cell topology's ordering of those subcells.
409  typedef ordinal_type SubcellOrdinal;
410  typedef ordinal_type SubcellDimension;
411  typedef ordinal_type SubSubcellOrdinal;
412  typedef ordinal_type SubSubcellDimension;
413  typedef ordinal_type SubSubcellOrdinalInCellTopo;
414  typedef std::pair< SubcellDimension, SubcellOrdinal > SubcellIdentifier; // dim, ord in cellTopo
415  typedef std::pair< SubSubcellDimension, SubSubcellOrdinal > SubSubcellIdentifier; // dim, ord in subcell
416  typedef std::map< SubcellIdentifier, std::map< SubSubcellIdentifier, SubSubcellOrdinalInCellTopo > > OrdinalMap;
417  static std::map< CellTopologyKey, OrdinalMap > ordinalMaps;
418 
419  if (subsubcdim==subcdim)
420  {
421  if (subsubcord==0) // i.e. the "subsubcell" is really just the subcell
422  {
423  return subcord;
424  }
425  else
426  {
427  std::cout << "request for subsubcell of the same dimension as subcell, but with subsubcord > 0.\n";
428  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "request for subsubcell of the same dimension as subcell, but with subsubcord > 0.");
429  }
430  }
431 
432  if (subcdim==cellTopo->getDimension())
433  {
434  if (subcord==0) // i.e. the subcell is the cell itself
435  {
436  return subsubcord;
437  }
438  else
439  {
440  std::cout << "request for subcell of the same dimension as cell, but with subsubcord > 0.\n";
441  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "request for subcell of the same dimension as cell, but with subsubcord > 0.");
442  }
443  }
444 
445  CellTopologyKey key = cellTopo->getKey();
446  if (ordinalMaps.find(key) == ordinalMaps.end())
447  {
448  // then we construct the map for this cellTopo
449  OrdinalMap ordinalMap;
450  ordinal_type sideDim = cellTopo->getDimension() - 1;
451  typedef ordinal_type NodeOrdinal;
452  std::map< std::set<NodeOrdinal>, SubcellIdentifier > subcellMap; // given set of nodes in cellTopo, what subcell is it?)
453 
454  for (ordinal_type d=1; d<=sideDim; d++) // only things of dimension >= 1 will have subcells
455  {
456  ordinal_type subcellCount = cellTopo->getSubcellCount(d);
457  for (ordinal_type subcellOrdinal=0; subcellOrdinal<subcellCount; subcellOrdinal++)
458  {
459  std::set<NodeOrdinal> nodes;
460  ordinal_type nodeCount = cellTopo->getNodeCount(d, subcellOrdinal);
461  for (NodeOrdinal subcNode=0; subcNode<nodeCount; subcNode++)
462  {
463  nodes.insert(cellTopo->getNodeMap(d, subcellOrdinal, subcNode));
464  }
465  SubcellIdentifier subcell = std::make_pair(d, subcellOrdinal);
466  subcellMap[nodes] = subcell;
467 
468  CellTopoPtr subcellTopo = cellTopo->getSubcell(d, subcellOrdinal);
469  // now, go over all the subsubcells, and look them up...
470  for (ordinal_type subsubcellDim=0; subsubcellDim<d; subsubcellDim++)
471  {
472  ordinal_type subsubcellCount = subcellTopo->getSubcellCount(subsubcellDim);
473  for (ordinal_type subsubcellOrdinal=0; subsubcellOrdinal<subsubcellCount; subsubcellOrdinal++)
474  {
475  SubSubcellIdentifier subsubcell = std::make_pair(subsubcellDim,subsubcellOrdinal);
476  if (subsubcellDim==0) // treat vertices separately
477  {
478  ordinalMap[subcell][subsubcell] = cellTopo->getNodeMap(subcell.first, subcell.second, subsubcellOrdinal);
479  continue;
480  }
481  ordinal_type nodeCount_inner = subcellTopo->getNodeCount(subsubcellDim, subsubcellOrdinal);
482  std::set<NodeOrdinal> subcellNodes; // NodeOrdinals index into cellTopo, though!
483  for (NodeOrdinal subsubcNode=0; subsubcNode<nodeCount_inner; subsubcNode++)
484  {
485  NodeOrdinal subcNode = subcellTopo->getNodeMap(subsubcellDim, subsubcellOrdinal, subsubcNode);
486  NodeOrdinal node = cellTopo->getNodeMap(d, subcellOrdinal, subcNode);
487  subcellNodes.insert(node);
488  }
489 
490  SubcellIdentifier subsubcellInCellTopo = subcellMap[subcellNodes];
491  ordinalMap[ subcell ][ subsubcell ] = subsubcellInCellTopo.second;
492  // cout << "ordinalMap( (" << subcell.first << "," << subcell.second << "), (" << subsubcell.first << "," << subsubcell.second << ") ) ";
493  // cout << " ---> " << subsubcellInCellTopo.second << endl;
494  }
495  }
496  }
497  }
498  ordinalMaps[key] = ordinalMap;
499  }
500  SubcellIdentifier subcell = std::make_pair(subcdim, subcord);
501  SubSubcellIdentifier subsubcell = std::make_pair(subsubcdim, subsubcord);
502  if (ordinalMaps[key][subcell].find(subsubcell) != ordinalMaps[key][subcell].end())
503  {
504  return ordinalMaps[key][subcell][subsubcell];
505  }
506  else
507  {
508  std::cout << "For topology " << cellTopo->getName() << " and subcell " << subcord << " of dim " << subcdim;
509  std::cout << ", subsubcell " << subsubcord << " of dim " << subsubcdim << " not found.\n";
510  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument, "subsubcell not found");
511  return -1; // NOT FOUND
512  }
513  }
514 
518  CellTopoPtr getTensorialComponent() const
519  {
520  if (tensorialDegree_ > 0)
521  {
522  return cellTopology(shardsBaseTopology_, tensorialDegree_ - 1);
523  }
524  else
525  {
526  return Teuchos::null;
527  }
528  }
529 
533  ordinal_type getTensorialComponentSideOrdinal(ordinal_type extrusionNodeOrdinal)
534  {
535  // our ordering places the "copies" of the tensorial component first, so these have side ordinal 0 or 1.
536  return extrusionNodeOrdinal;
537  }
538 
542  bool sideIsExtrudedInFinalDimension( ordinal_type sideOrdinal ) const
543  {
544  int sideCount = getSideCount();
545  if (tensorialDegree_ == 0) return false;
546 
547  return (sideOrdinal > 1) && (sideOrdinal < sideCount);
548  }
549 
554  static CellTopoPtr cellTopology(const shards::CellTopology &shardsCellTopo, ordinal_type tensorialDegree = 0)
555  {
556  ordinal_type shardsKey = static_cast<ordinal_type>(shardsCellTopo.getBaseKey());
557  std::pair<ordinal_type,ordinal_type> key = std::make_pair(shardsKey, tensorialDegree);
558 
559  static std::map< CellTopologyKey, CellTopoPtr > tensorizedShardsTopologies; // (shards key, n) --> our CellTopoPtr for that cellTopo's nth-order tensor product with a line topology. I.e. (shard::CellTopology::Line<2>::key, 2) --> a tensor-product hexahedron. (This differs from the Shards hexahedron, because the enumeration of the sides of the quad in Shards goes counter-clockwise.)
560 
561  if (tensorizedShardsTopologies.find(key) == tensorizedShardsTopologies.end())
562  {
563  tensorizedShardsTopologies[key] = Teuchos::rcp( new CellTopology(shardsCellTopo, tensorialDegree));
564  }
565  return tensorizedShardsTopologies[key];
566  }
567 
568  static CellTopoPtr point()
569  {
570  return cellTopology(shards::getCellTopologyData<shards::Node >());
571  }
572 
573  static CellTopoPtr line()
574  {
575  return cellTopology(shards::getCellTopologyData<shards::Line<> >());
576  }
577 
578  static CellTopoPtr quad()
579  {
580  return cellTopology(shards::getCellTopologyData<shards::Quadrilateral<> >());
581  }
582 
583  static CellTopoPtr hexahedron()
584  {
585  return cellTopology(shards::getCellTopologyData<shards::Hexahedron<> >());
586  }
587 
588  static CellTopoPtr triangle()
589  {
590  return cellTopology(shards::getCellTopologyData<shards::Triangle<> >());
591  }
592 
593  static CellTopoPtr tetrahedron()
594  {
595  return cellTopology(shards::getCellTopologyData<shards::Tetrahedron<> >());
596  }
597 
598  static CellTopoPtr wedge()
599  {
600  return cellTopology(shards::getCellTopologyData<shards::Wedge<> >());
601  }
602  };
603 }
604 
605 #endif /* Intrepid2_CellTopology_h */
ordinal_type getFaceCount() const
Face (dimension 2) subcell count of this cell topology.
std::pair< ordinal_type, ordinal_type > getKey() const
Key that&#39;s unique for standard shards topologies and any tensorial degree.
ordinal_type getNodePermutationInverse(const ordinal_type permutation_ord, const ordinal_type node_ord) const
Inverse permutation of a cell&#39;s node ordinals.
ordinal_type getNodePermutationCount() const
Number of node permutations defined for this cell.
ordinal_type getEdgeCount() const
Edge (dimension 1) subcell count of this cell topology.
ordinal_type getDimension() const
Dimension of this tensor topology.
ordinal_type getTensorialDegree() const
The number of times we have taken a tensor product between a line topology and the shards topology to...
ordinal_type getVertexCount(const ordinal_type subcell_dim, const ordinal_type subcell_ord) const
Vertex count of a subcell of the given dimension and ordinal.
ordinal_type getNodeMap(const ordinal_type subcell_dim, const ordinal_type subcell_ord, const ordinal_type subcell_node_ord) const
Mapping from a subcell&#39;s node ordinal to a node ordinal of this parent cell topology.
ordinal_type getVertexCount() const
Vertex count of this cell topology.
const shards::CellTopology & getBaseTopology() const
Returns the underlying shards CellTopology.
ordinal_type getNodeCount() const
Node count of this cell topology.
ordinal_type getNodePermutation(const ordinal_type permutation_ord, const ordinal_type node_ord) const
Permutation of a cell&#39;s node ordinals.
std::string getName() const
Human-readable name of the CellTopology.
ordinal_type getNodeCount(const ordinal_type subcell_dim, const ordinal_type subcell_ord) const
Node count of a subcell of the given dimension and ordinal.
ordinal_type getExtrudedSubcellOrdinal(const ordinal_type subcell_dim_in_component_topo, const ordinal_type subcell_ord_in_component_topo) const
Mapping from the tensorial component CellTopology&#39;s subcell ordinal to the corresponding subcell ordi...
bool sideIsExtrudedInFinalDimension(ordinal_type sideOrdinal) const
Returns true if the specified side has extension in the final tensorial dimension. For topologies with zero tensorialDegree_, returns false.
CellTopology(const shards::CellTopology &baseTopo, ordinal_type tensorialDegree)
Constructor.
ordinal_type getSideCount() const
Side (dimension N-1) subcell count of this cell topology.
CellTopoPtr getSubcell(ordinal_type scdim, ordinal_type scord) const
Get the subcell of dimension scdim with ordinal scord.
ordinal_type getEdgeCount(const ordinal_type subcell_dim, const ordinal_type subcell_ord) const
Edge count of a subcell of the given dimension and ordinal.
Implements arbitrary-dimensional extrusion of a base shards::CellTopology.
CellTopoPtr getTensorialComponent() const
For cell topologies of positive tensorial degree, returns the cell topology of tensorial degree one l...
ordinal_type getNodeFromTensorialComponentNodes(const std::vector< ordinal_type > &tensorComponentNodes) const
Mapping from the tensorial component node ordinals to the node ordinal of this tensor cell topology...
ordinal_type getTensorialComponentSideOrdinal(ordinal_type extrusionNodeOrdinal)
Returns the side corresponding to the provided node in the final extrusion dimension.
ordinal_type getSideCount(const ordinal_type subcell_dim, const ordinal_type subcell_ord) const
Side count of a subcell of the given dimension and ordinal.
static CellTopoPtr cellTopology(const shards::CellTopology &shardsCellTopo, ordinal_type tensorialDegree=0)
static accessor that returns a CellTopoPtr; these are lazily constructed and cached.
CellTopoPtr getSide(ordinal_type sideOrdinal) const
Returns a CellTopoPtr for the specified side.
static ordinal_type getSubcellOrdinalMap(CellTopoPtr cellTopo, ordinal_type subcdim, ordinal_type subcord, ordinal_type subsubcdim, ordinal_type subsubcord)
Maps the from a subcell within a subcell of the present CellTopology to the subcell in the present Ce...
ordinal_type getSubcellCount(const ordinal_type subcell_dim) const
Subcell count of subcells of the given dimension.