Intrepid2
Intrepid2_LegendreBasis_HVOL_TET.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
15#ifndef Intrepid2_LegendreBasis_HVOL_TET_h
16#define Intrepid2_LegendreBasis_HVOL_TET_h
17
18#include <Kokkos_DynRankView.hpp>
19
20#include <Intrepid2_config.h>
21
22#include "Intrepid2_Basis.hpp"
26#include "Intrepid2_Utils.hpp"
27
28namespace Intrepid2
29{
35 template<class DeviceType, class OutputScalar, class PointScalar,
36 class OutputFieldType, class InputPointsType>
38 {
39 using ExecutionSpace = typename DeviceType::execution_space;
40 using ScratchSpace = typename ExecutionSpace::scratch_memory_space;
41 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
42 using PointScratchView = Kokkos::View<PointScalar*, ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
43
44 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
45 using TeamMember = typename TeamPolicy::member_type;
46
47 EOperator opType_;
48
49 OutputFieldType output_; // F,P
50 InputPointsType inputPoints_; // P,D
51
52 int polyOrder_;
53 int numFields_, numPoints_;
54
55 size_t fad_size_output_;
56
57 Hierarchical_HVOL_TET_Functor(EOperator opType, OutputFieldType output, InputPointsType inputPoints, int polyOrder)
58 : opType_(opType), output_(output), inputPoints_(inputPoints),
59 polyOrder_(polyOrder),
60 fad_size_output_(getScalarDimensionForView(output))
61 {
62 numFields_ = output.extent_int(0);
63 numPoints_ = output.extent_int(1);
64 INTREPID2_TEST_FOR_EXCEPTION(numPoints_ != inputPoints.extent_int(0), std::invalid_argument, "point counts need to match!");
65 INTREPID2_TEST_FOR_EXCEPTION(numFields_ != (polyOrder_+1)*(polyOrder_+2)*(polyOrder_+3)/6, std::invalid_argument, "output field size does not match basis cardinality");
66 }
67
68 KOKKOS_INLINE_FUNCTION
69 void operator()( const TeamMember & teamMember ) const
70 {
71 // values are product of [P_i](lambda_0,lambda_1), [P^{2i+1}_j](lambda_0 + lambda_1, lambda_2), and [P^{2*(i+j+1)}_k](1-lambda_3,lambda_3),
72 // times ((grad lambda_1) x (grad lambda_2)) \cdot (grad lambda_3).
73 // For the canonical orientation (all we support), the last term evaluates to 1, and
74 // lambda_0 = 1 - x - y - z
75 // lambda_1 = x
76 // lambda_2 = y
77 // lambda_3 = z
78 // [P_i](lambda_0, lambda_1) = P_i(lambda_1; lambda_0 + lambda_1) = P_i(x; 1 - y - z) -- a shifted, scaled Legendre function
79 // [P^{2i+1}_j](lambda_0 + lambda_1, lambda_2) = P^{2i+1}_j(lambda_2; lambda_0 + lambda_1 + lambda_2) = P^{2i+1}_j(y; 1 - z) -- a shifted, scaled Jacobi function
80 // [P^{2*(i+j+1)}_k](1-lambda_3,lambda_3) = P^{2*(i+j+1)}_k(lambda_3; 1) = P^{2*(i+j+1)}_k(z; 1) -- another shifted, scaled Jacobi function
81 auto pointOrdinal = teamMember.league_rank();
82 OutputScratchView P, P_2p1, P_2ipjp1;
83 if (fad_size_output_ > 0) {
84 P = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
85 P_2p1 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
86 P_2ipjp1 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1, fad_size_output_);
87 }
88 else {
89 P = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
90 P_2p1 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
91 P_2ipjp1 = OutputScratchView(teamMember.team_shmem(), polyOrder_ + 1);
92 }
93
94 const auto & x = inputPoints_(pointOrdinal,0);
95 const auto & y = inputPoints_(pointOrdinal,1);
96 const auto & z = inputPoints_(pointOrdinal,2);
97
98 // write as barycentric coordinates:
99 const PointScalar lambda[4] = {1. - x - y - z, x, y, z};
100
101 switch (opType_)
102 {
103 case OPERATOR_VALUE:
104 {
105 // face functions
106 {
107 const PointScalar tLegendre = lambda[0] + lambda[1];
108 Polynomials::shiftedScaledLegendreValues(P, polyOrder_, lambda[1], tLegendre);
109
110 int fieldOrdinalOffset = 0;
111
112 const int min_i = 0;
113 const int min_j = 0;
114 const int min_k = 0;
115 const int min_ij = min_i + min_j;
116 const int min_ijk = min_ij + min_k;
117 for (int totalPolyOrder_ijk=min_ijk; totalPolyOrder_ijk <= polyOrder_; totalPolyOrder_ijk++)
118 {
119 for (int totalPolyOrder_ij=min_ij; totalPolyOrder_ij <= totalPolyOrder_ijk-min_j; totalPolyOrder_ij++)
120 {
121 for (int i=min_i; i <= totalPolyOrder_ij-min_j; i++)
122 {
123 const int j = totalPolyOrder_ij - i;
124 const int k = totalPolyOrder_ijk - totalPolyOrder_ij;
125
126 const double alpha1 = i * 2.0 + 1.;
127 const PointScalar tJacobi1 = lambda[0] + lambda[1] + lambda[2];
128 const PointScalar & xJacobi1 = lambda[2];
129 Polynomials::shiftedScaledJacobiValues(P_2p1, alpha1, polyOrder_, xJacobi1, tJacobi1);
130
131 const double alpha2 = 2. * (i + j + 1.);
132 const PointScalar tJacobi2 = 1.0; // 1 - lambda[3] + lambda[3]
133 const PointScalar & xJacobi2 = lambda[3];
134 Polynomials::shiftedScaledJacobiValues(P_2ipjp1, alpha2, polyOrder_, xJacobi2, tJacobi2);
135
136 const auto & P_i = P(i);
137 const auto & P_2p1_j = P_2p1(j);
138 const auto & P_2ipjp1_k = P_2ipjp1(k);
139
140 output_(fieldOrdinalOffset,pointOrdinal) = P_i * P_2p1_j * P_2ipjp1_k;
141 fieldOrdinalOffset++;
142 }
143 }
144 }
145 }
146 } // end OPERATOR_VALUE
147 break;
148 default:
149 // unsupported operator type
150 device_assert(false);
151 }
152 }
153
154 // Provide the shared memory capacity.
155 // This function takes the team_size as an argument,
156 // which allows team_size-dependent allocations.
157 size_t team_shmem_size (int team_size) const
158 {
159 // we will use shared memory to create a fast buffer for basis computations
160 size_t shmem_size = 0;
161 if (fad_size_output_ > 0)
162 shmem_size += 3 * OutputScratchView::shmem_size(polyOrder_ + 1, fad_size_output_);
163 else
164 shmem_size += 3 * OutputScratchView::shmem_size(polyOrder_ + 1);
165
166 return shmem_size;
167 }
168 };
169
180 template<typename DeviceType,
181 typename OutputScalar = double,
182 typename PointScalar = double>
184 : public Basis<DeviceType,OutputScalar,PointScalar>
185 {
186 public:
188
191
192 using typename BasisBase::OutputViewType;
193 using typename BasisBase::PointViewType;
194 using typename BasisBase::ScalarViewType;
195
196 using typename BasisBase::ExecutionSpace;
197
198 protected:
199 int polyOrder_; // the maximum order of the polynomial
200 EPointType pointType_;
201 public:
208 LegendreBasis_HVOL_TET(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
209 :
210 polyOrder_(polyOrder),
211 pointType_(pointType)
212 {
213 INTREPID2_TEST_FOR_EXCEPTION(pointType!=POINTTYPE_DEFAULT,std::invalid_argument,"PointType not supported");
214
215 this->basisCardinality_ = ((polyOrder+3) * (polyOrder+2) * (polyOrder+1)) / 6;
216 this->basisDegree_ = polyOrder;
217 this->basisCellTopologyKey_ = shards::Tetrahedron<>::key;
218 this->basisType_ = BASIS_FEM_HIERARCHICAL;
219 this->basisCoordinates_ = COORDINATES_CARTESIAN;
220 this->functionSpace_ = FUNCTION_SPACE_HVOL;
221
222 const int degreeLength = 1;
223 this->fieldOrdinalPolynomialDegree_ = OrdinalTypeArray2DHost("Integrated Legendre H(vol) triangle polynomial degree lookup", this->basisCardinality_, degreeLength);
224
225 int fieldOrdinalOffset = 0;
226 // **** volume/interior functions **** //
227 const int min_i = 0;
228 const int min_j = 0;
229 const int min_k = 0;
230 const int min_ij = min_i + min_j;
231 const int min_ijk = min_ij + min_k;
232 for (int totalPolyOrder_ijk=min_ijk; totalPolyOrder_ijk <= polyOrder_; totalPolyOrder_ijk++)
233 {
234 for (int totalPolyOrder_ij=min_ij; totalPolyOrder_ij <= totalPolyOrder_ijk-min_j; totalPolyOrder_ij++)
235 {
236 for (int i=min_i; i <= totalPolyOrder_ij-min_j; i++)
237 {
238 const int j = totalPolyOrder_ij - i;
239 const int k = totalPolyOrder_ijk - totalPolyOrder_ij;
240
241 this->fieldOrdinalPolynomialDegree_(fieldOrdinalOffset,0) = i+j+k;
242 fieldOrdinalOffset++;
243 }
244 }
245 }
246 INTREPID2_TEST_FOR_EXCEPTION(fieldOrdinalOffset != this->basisCardinality_, std::invalid_argument, "Internal error: basis enumeration is incorrect");
247
248 // initialize tags
249 {
250 const auto & cardinality = this->basisCardinality_;
251
252 // Basis-dependent initializations
253 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
254 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
255 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
256 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
257
258 OrdinalTypeArray1DHost tagView("tag view", cardinality*tagSize);
259 const int volumeDim = 3;
260
261 for (ordinal_type i=0;i<cardinality;++i) {
262 tagView(i*tagSize+0) = volumeDim; // volume dimension
263 tagView(i*tagSize+1) = 0; // volume id
264 tagView(i*tagSize+2) = i; // local dof id
265 tagView(i*tagSize+3) = cardinality; // total number of dofs on this face
266 }
267
268 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
269 // tags are constructed on host
271 this->ordinalToTag_,
272 tagView,
273 this->basisCardinality_,
274 tagSize,
275 posScDim,
276 posScOrd,
277 posDfOrd);
278 }
279 }
280
285 const char* getName() const override {
286 return "Intrepid2_LegendreBasis_HVOL_TET";
287 }
288
291 virtual bool requireOrientation() const override {
292 return (this->getDegree() > 2);
293 }
294
295 // since the getValues() below only overrides the FEM variant, we specify that
296 // we use the base class's getValues(), which implements the FVD variant by throwing an exception.
297 // (It's an error to use the FVD variant on this basis.)
299
318 virtual void getValues( OutputViewType outputValues, const PointViewType inputPoints,
319 const EOperator operatorType = OPERATOR_VALUE ) const override
320 {
321 auto numPoints = inputPoints.extent_int(0);
322
324
325 FunctorType functor(operatorType, outputValues, inputPoints, polyOrder_);
326
327 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputScalar>();
328 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointScalar>();
329 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
330 const int teamSize = 1; // because of the way the basis functions are computed, we don't have a second level of parallelism...
331
332 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(numPoints,teamSize,vectorSize);
333 Kokkos::parallel_for("Hierarchical_HVOL_TET_Functor", policy , functor);
334 }
335
341 getHostBasis() const override {
342 using HostDeviceType = typename Kokkos::HostSpace::device_type;
344 return Teuchos::rcp( new HostBasisType(polyOrder_, pointType_) );
345 }
346 };
347} // end namespace Intrepid2
348
349#endif /* Intrepid2_LegendreBasis_HVOL_TET_h */
Header file for the abstract base class Intrepid2::Basis.
Teuchos::RCP< Basis< DeviceType, OutputType, PointType > > BasisPtr
Basis Pointer.
KOKKOS_INLINE_FUNCTION void device_assert(bool val)
H(vol) basis on the line based on Legendre polynomials.
H(vol) basis on the triangle based on integrated Legendre polynomials.
Free functions, callable from device code, that implement various polynomials useful in basis definit...
Header function for Intrepid2::Util class and other utility functions.
KOKKOS_INLINE_FUNCTION constexpr unsigned getScalarDimensionForView(const ViewType &view)
Returns the size of the Scalar dimension for the View. This is 0 for non-AD types....
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
virtual KOKKOS_INLINE_FUNCTION void getValues(OutputViewType, const PointViewType, const EOperator, const typename Kokkos::TeamPolicy< ExecutionSpace >::member_type &teamMember, const typename ExecutionSpace::scratch_memory_space &scratchStorage, const ordinal_type subcellDim=-1, const ordinal_type subcellOrdinal=-1) const
Team-level evaluation of basis functions on a reference cell.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
EBasis basisType_
Type of the basis.
ordinal_type basisDegree_
Degree of the largest complete polynomial space that can be represented by the basis.
ordinal_type getDegree() const
Returns the degree of the basis.
void setOrdinalTagData(OrdinalTypeView3D &tagToOrdinal, OrdinalTypeView2D &ordinalToTag, const OrdinalTypeView1D tags, const ordinal_type basisCard, const ordinal_type tagSize, const ordinal_type posScDim, const ordinal_type posScOrd, const ordinal_type posDfOrd)
Fills ordinalToTag_ and tagToOrdinal_ by basis-specific tag data.
Kokkos::DynRankView< scalarType, Kokkos::LayoutStride, DeviceType > ScalarViewType
View type for scalars.
OrdinalTypeArray2DHost ordinalToTag_
"true" if tagToOrdinal_ and ordinalToTag_ have been initialized
Kokkos::View< ordinal_type **, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
ordinal_type basisCardinality_
Cardinality of the basis, i.e., the number of basis functions/degrees-of-freedom.
OrdinalTypeArray3DHost tagToOrdinal_
DoF tag to ordinal lookup table.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
unsigned basisCellTopologyKey_
Identifier of the base topology of the cells for which the basis is defined. See the Shards package f...
typename DeviceType::execution_space ExecutionSpace
(Kokkos) Execution space for basis.
OrdinalTypeArray2DHost fieldOrdinalPolynomialDegree_
Polynomial degree for each degree of freedom. Only defined for hierarchical bases right now....
EFunctionSpace functionSpace_
The function space in which the basis is defined.
Basis defining Legendre basis on the line, a polynomial subspace of H(vol) on the line: extension to ...
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
const char * getName() const override
Returns basis name.
LegendreBasis_HVOL_TET(int polyOrder, const EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
Kokkos::View< ordinal_type **, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
virtual bool requireOrientation() const override
True if orientation is required.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
virtual BasisPtr< typename Kokkos::HostSpace::device_type, OutputScalar, PointScalar > getHostBasis() const override
Creates and returns a Basis object whose DeviceType template argument is Kokkos::HostSpace::device_ty...
Functor for computing values for the LegendreBasis_HVOL_TET class.