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
23namespace Intrepid2
24{
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 */
Implements arbitrary-dimensional extrusion of a base shards::CellTopology.
CellTopoPtr getSide(ordinal_type sideOrdinal) const
Returns a CellTopoPtr for the specified side.
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's subcell ordinal to the corresponding subcell ordi...
ordinal_type getVertexCount() const
Vertex count of this cell topology.
ordinal_type getNodePermutation(const ordinal_type permutation_ord, const ordinal_type node_ord) const
Permutation of a cell's node ordinals.
static CellTopoPtr cellTopology(const shards::CellTopology &shardsCellTopo, ordinal_type tensorialDegree=0)
static accessor that returns a CellTopoPtr; these are lazily constructed and cached.
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 getNodeCount() const
Node count of this cell topology.
CellTopology(const shards::CellTopology &baseTopo, ordinal_type tensorialDegree)
Constructor.
std::string getName() const
Human-readable name of the CellTopology.
ordinal_type getSubcellCount(const ordinal_type subcell_dim) const
Subcell count of subcells of the given dimension.
ordinal_type getTensorialComponentSideOrdinal(ordinal_type extrusionNodeOrdinal)
Returns the side corresponding to the provided node in the final extrusion dimension.
ordinal_type getNodeMap(const ordinal_type subcell_dim, const ordinal_type subcell_ord, const ordinal_type subcell_node_ord) const
Mapping from a subcell's node ordinal to a node ordinal of this parent cell topology.
ordinal_type getFaceCount() const
Face (dimension 2) subcell count of this cell topology.
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.
std::pair< ordinal_type, ordinal_type > getKey() const
Key that's unique for standard shards topologies and any tensorial degree.
ordinal_type getSideCount() const
Side (dimension N-1) subcell count of this cell topology.
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.
CellTopoPtr getSubcell(ordinal_type scdim, ordinal_type scord) const
Get the subcell of dimension scdim with ordinal scord.
bool sideIsExtrudedInFinalDimension(ordinal_type sideOrdinal) const
Returns true if the specified side has extension in the final tensorial dimension....
ordinal_type getNodePermutationCount() const
Number of node permutations defined for this cell.
const shards::CellTopology & getBaseTopology() const
Returns the underlying shards CellTopology.
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 getEdgeCount(const ordinal_type subcell_dim, const ordinal_type subcell_ord) const
Edge count of a subcell of the given dimension and ordinal.
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 getNodePermutationInverse(const ordinal_type permutation_ord, const ordinal_type node_ord) const
Inverse permutation of a cell's node ordinals.
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.
CellTopoPtr getTensorialComponent() const
For cell topologies of positive tensorial degree, returns the cell topology of tensorial degree one l...
ordinal_type getEdgeCount() const
Edge (dimension 1) subcell count of this cell topology.
ordinal_type getDimension() const
Dimension of this tensor topology.