Intrepid2
Intrepid2_SerendipityBasis.hpp
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//
10// Intrepid2_SerendipityBasis.hpp
11// intrepid2
12//
13// Created by Roberts, Nathan V on 1/4/22.
14//
15
16#ifndef Intrepid2_SerendipityBasis_h
17#define Intrepid2_SerendipityBasis_h
18
20
21namespace Intrepid2
22{
23
27template<typename BasisBaseClass = void>
29:
30public BasisBaseClass
31{
32public:
33 using BasisBase = BasisBaseClass;
34 using BasisPtr = Teuchos::RCP<BasisBase>;
35
36protected:
37 BasisPtr fullBasis_;
38
39 std::string name_; // name of the basis
40
41 int numTensorialExtrusions_; // relative to cell topo returned by getBaseCellTopology().
42public:
43 using DeviceType = typename BasisBase::DeviceType;
44 using ExecutionSpace = typename BasisBase::ExecutionSpace;
45 using OutputValueType = typename BasisBase::OutputValueType;
46 using PointValueType = typename BasisBase::PointValueType;
47
48 using OrdinalTypeArray1D = typename BasisBase::OrdinalTypeArray1D;
49 using OrdinalTypeArray1DHost = typename BasisBase::OrdinalTypeArray1DHost;
50 using OrdinalTypeArray2DHost = typename BasisBase::OrdinalTypeArray2DHost;
51 using OutputViewType = typename BasisBase::OutputViewType;
52 using PointViewType = typename BasisBase::PointViewType;
53protected:
54 OrdinalTypeArray1D ordinalMap_; // our field ordinal --> full basis field ordinal
55public:
59 SerendipityBasis(BasisPtr fullBasis)
60 :
61 fullBasis_(fullBasis)
62 {
63 INTREPID2_TEST_FOR_EXCEPTION(fullBasis_->getBasisType() != BASIS_FEM_HIERARCHICAL, std::invalid_argument, "SerendipityBasis only supports full bases whose type is BASIS_FEM_HIERARCHICAL");
64 this->basisType_ = fullBasis_->getBasisType(); // BASIS_FEM_HIERARCHICAL
65
66 this->functionSpace_ = fullBasis_->getFunctionSpace();
67 this->basisDegree_ = fullBasis_->getDegree();
68
69 {
70 std::ostringstream basisName;
71 basisName << "Serendipity(" << fullBasis_->getName() << ")";
72 name_ = basisName.str();
73 }
74
75 using std::vector;
76 vector<ordinal_type> fullBasisOrdinals;
77 vector<vector<ordinal_type>> polynomialDegreeOfField;
78 vector<vector<ordinal_type>> polynomialH1DegreeOfField;
79 ordinal_type fullCardinality = fullBasis_->getCardinality();
80 ordinal_type basisH1Degree = (this->functionSpace_ == FUNCTION_SPACE_HVOL) ? this->basisDegree_ + 1 : this->basisDegree_;
81 for (ordinal_type i=0; i<fullCardinality; i++)
82 {
83 vector<ordinal_type> fieldDegree = fullBasis_->getPolynomialDegreeOfFieldAsVector(i);
84 vector<ordinal_type> fieldH1Degree = fullBasis_->getH1PolynomialDegreeOfFieldAsVector(i);
85 ordinal_type superlinearDegree = 0;
86 for (const ordinal_type & p : fieldH1Degree)
87 {
88 if (p > 1)
89 {
90 // superlinear; contributes to superlinearDegree
91 superlinearDegree += p;
92 }
93 }
94 if (superlinearDegree <= basisH1Degree)
95 {
96 // satisfies serendipity criterion
97 fullBasisOrdinals.push_back(i);
98 polynomialDegreeOfField.push_back(fieldDegree);
99 polynomialH1DegreeOfField.push_back(fieldH1Degree);
100 }
101 }
102 this->basisCardinality_ = fullBasisOrdinals.size();
103 ordinalMap_ = OrdinalTypeArray1D("serendipity ordinal map",fullBasisOrdinals.size());
104
105 auto ordinalMapHost = Kokkos::create_mirror_view(ordinalMap_);
106 const ordinal_type fullBasisCardinality = fullBasisOrdinals.size();
107 for (ordinal_type i=0; i<fullBasisCardinality; i++)
108 {
109 ordinalMapHost(i) = fullBasisOrdinals[i];
110 }
111 Kokkos::deep_copy(ordinalMap_, ordinalMapHost);
112
113 // set cell topology
114 this->basisCellTopologyKey_ = fullBasis_->getBaseCellTopology().getKey();
115 this->numTensorialExtrusions_ = fullBasis_->getNumTensorialExtrusions();
116 const ordinal_type spaceDim = fullBasis_->getBaseCellTopology().getDimension() + numTensorialExtrusions_;
117
118 this->basisCoordinates_ = COORDINATES_CARTESIAN;
119
120 // fill in degree lookup:
121 int degreeSize = fullBasis_->getPolynomialDegreeLength();
122 this->fieldOrdinalPolynomialDegree_ = OrdinalTypeArray2DHost("TensorBasis - field ordinal polynomial degree", this->basisCardinality_, degreeSize);
123 this->fieldOrdinalH1PolynomialDegree_ = OrdinalTypeArray2DHost("TensorBasis - field ordinal H^1 degree", this->basisCardinality_, degreeSize);
124
125 for (ordinal_type fieldOrdinal1 = 0; fieldOrdinal1 < this->basisCardinality_; fieldOrdinal1++)
126 {
127 for (int d=0; d<degreeSize; d++)
128 {
129 this->fieldOrdinalPolynomialDegree_ (fieldOrdinal1,d) = polynomialDegreeOfField [fieldOrdinal1][d];
130 this->fieldOrdinalH1PolynomialDegree_(fieldOrdinal1,d) = polynomialH1DegreeOfField[fieldOrdinal1][d];
131 }
132 }
133
134 // build tag view
135 const auto & cardinality = this->basisCardinality_;
136
137 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
138 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
139 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
140 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
141 const ordinal_type posDfCnt = 3; // position in the tag, counting from 0, of DoF count for the subcell
142
143 OrdinalTypeArray1DHost tagView("tag view", cardinality*tagSize);
144 auto cellTopo = CellTopology::cellTopology(fullBasis_->getBaseCellTopology(), numTensorialExtrusions_);
145 const OrdinalTypeArray2DHost fullBasisOrdinalToTag = fullBasis->getAllDofTags();
146
147 using std::map;
148 vector<vector<ordinal_type>> subcellDofCount(spaceDim+1); // outer: dimension of subcell; inner: subcell ordinal. Entry: number of dofs.
149 vector<vector<ordinal_type>> subcellDofOrdinal(spaceDim+1); // outer: dimension of subcell; inner: subcell ordinal. Entry: ordinal relative to subcell.
150 for (ordinal_type d=0; d<=spaceDim; d++)
151 {
152 const ordinal_type numSubcells = cellTopo->getSubcellCount(d);
153 subcellDofCount[d] = vector<ordinal_type>(numSubcells,0);
154 subcellDofOrdinal[d] = vector<ordinal_type>(numSubcells,0);
155 }
156 for (ordinal_type fieldOrdinal=0; fieldOrdinal<fullBasisCardinality; fieldOrdinal++)
157 {
158 const ordinal_type fullFieldOrdinal = fullBasisOrdinals[fieldOrdinal];
159 const ordinal_type subcellDim = fullBasisOrdinalToTag(fullFieldOrdinal,posScDim);
160 const ordinal_type subcellOrd = fullBasisOrdinalToTag(fullFieldOrdinal,posScOrd);
161 subcellDofCount[subcellDim][subcellOrd]++;
162 }
163 for (ordinal_type fieldOrdinal=0; fieldOrdinal<fullBasisCardinality; fieldOrdinal++)
164 {
165 const ordinal_type fullFieldOrdinal = fullBasisOrdinals[fieldOrdinal];
166 const ordinal_type subcellDim = fullBasisOrdinalToTag(fullFieldOrdinal,posScDim);
167 const ordinal_type subcellOrd = fullBasisOrdinalToTag(fullFieldOrdinal,posScOrd);
168 const ordinal_type subcellDfCnt = subcellDofCount[subcellDim][subcellOrd];
169 const ordinal_type subcellDfOrd = subcellDofOrdinal[subcellDim][subcellOrd]++;
170
171 tagView(tagSize*fieldOrdinal + posScDim) = subcellDim; // subcellDim
172 tagView(tagSize*fieldOrdinal + posScOrd) = subcellOrd; // subcell ordinal
173 tagView(tagSize*fieldOrdinal + posDfOrd) = subcellDfOrd; // ordinal of the specified DoF relative to the subcell
174 tagView(tagSize*fieldOrdinal + posDfCnt) = subcellDfCnt; // total number of DoFs associated with the subcell
175 }
176 // // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
177 // // tags are constructed on host
178 this->setOrdinalTagData(this->tagToOrdinal_,
179 this->ordinalToTag_,
180 tagView,
181 this->basisCardinality_,
182 tagSize,
183 posScDim,
184 posScOrd,
185 posDfOrd);
186 }
187
188 virtual int getNumTensorialExtrusions() const override
189 {
190 return numTensorialExtrusions_;
191 }
192
197 virtual BasisValues<OutputValueType,DeviceType> allocateBasisValues( TensorPoints<PointValueType,DeviceType> points, const EOperator operatorType = OPERATOR_VALUE) const override
198 {
199 auto basisValues = fullBasis_->allocateBasisValues(points,operatorType);
200 basisValues.setOrdinalFilter(this->ordinalMap_);
201 return basisValues;
202 }
203
204 // since the getValues() below only overrides the FEM variant, we specify that
205 // we use the base class's getValues(), which implements the FVD variant by throwing an exception.
206 // (It's an error to use the FVD variant on this basis.)
207 using BasisBase::getValues;
208
213 virtual
214 const char*
215 getName() const override {
216 return name_.c_str();
217 }
218
230 virtual
231 void
234 const EOperator operatorType = OPERATOR_VALUE ) const override
235 {
236 fullBasis_->getValues(outputValues, inputPoints, operatorType);
237 outputValues.setOrdinalFilter(this->ordinalMap_);
238 }
239
258 virtual
259 void getValues( OutputViewType outputValues, const PointViewType inputPoints,
260 const EOperator operatorType = OPERATOR_VALUE ) const override
261 {
262 INTREPID2_TEST_FOR_EXCEPTION( true, std::logic_error,
263 ">>> ERROR (Basis::getValues): this method is not supported by SerendipityBasis (use the getValues() method that accepts a BasisValues object instead).");
264 }
265
271 getHostBasis() const override {
273 using HostBasis = SerendipityBasis<HostBasisBase>;
274 auto hostBasis = Teuchos::rcp(new HostBasis(fullBasis_->getHostBasis()));
275 return hostBasis;
276 }
277
282 BasisPtr getUnderlyingBasis() const
283 {
284 return fullBasis_;
285 }
286
291 OrdinalTypeArray1D ordinalMap() const
292 {
293 return ordinalMap_;
294 }
295}; // SerendipityBasis
296
297} // namespace Intrepid2
298#endif /* Intrepid2_SerendipityBasis_h */
BasisPtr< typename Kokkos::HostSpace::device_type, OutputType, PointType > HostBasisPtr
Pointer to a Basis whose device type is on the host (Kokkos::HostSpace::device_type),...
Implements arbitrary-dimensional extrusion of a base shards::CellTopology.
The data containers in Intrepid2 that support sum factorization and other reduced-data optimizations ...
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
static CellTopoPtr cellTopology(const shards::CellTopology &shardsCellTopo, ordinal_type tensorialDegree=0)
static accessor that returns a CellTopoPtr; these are lazily constructed and cached.
Serendipity Basis, defined as the sub-basis of a provided basis, consisting of basis elements for whi...
SerendipityBasis(BasisPtr fullBasis)
Constructor.
virtual void getValues(BasisValues< OutputValueType, DeviceType > outputValues, const TensorPoints< PointValueType, DeviceType > inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell, using point and output value containers that allow pre...
virtual HostBasisPtr< OutputValueType, PointValueType > getHostBasis() const override
Creates and returns a Basis object whose DeviceType template argument is Kokkos::HostSpace::device_ty...
BasisPtr getUnderlyingBasis() const
Returns a pointer to the underlying full basis.
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
OrdinalTypeArray1D ordinalMap() const
Returns the ordinal map from the Serendipity basis ordinal to the ordinal in the underlying full basi...
virtual const char * getName() const override
Returns basis name.
virtual BasisValues< OutputValueType, DeviceType > allocateBasisValues(TensorPoints< PointValueType, DeviceType > points, const EOperator operatorType=OPERATOR_VALUE) const override
Allocate BasisValues container suitable for passing to the getValues() variant that takes a TensorPoi...
View-like interface to tensor points; point components are stored separately; the appropriate coordin...