Intrepid2
Intrepid2_IntegratedLegendreBasis_HGRAD_LINE.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_IntegratedLegendreBasis_HGRAD_LINE_h
16#define Intrepid2_IntegratedLegendreBasis_HGRAD_LINE_h
17
18#include <Kokkos_DynRankView.hpp>
19
20#include <Intrepid2_config.h>
21
22#include "Intrepid2_Basis.hpp"
24#include "Intrepid2_Utils.hpp"
25
26namespace Intrepid2
27{
33 template<class DeviceType, class OutputScalar, class PointScalar,
34 class OutputFieldType, class InputPointsType>
36 {
37 using ExecutionSpace = typename DeviceType::execution_space;
38 using ScratchSpace = typename ExecutionSpace::scratch_memory_space;
39 using OutputScratchView = Kokkos::View<OutputScalar*,ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
40 using PointScratchView = Kokkos::View<PointScalar*, ScratchSpace,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
41
42 using TeamPolicy = Kokkos::TeamPolicy<ExecutionSpace>;
43 using TeamMember = typename TeamPolicy::member_type;
44
45 EOperator opType_; // OPERATOR_VALUE or OPERATOR_GRAD
46
47 OutputFieldType output_; // F,P
48 InputPointsType inputPoints_; // P,D
49
50 int polyOrder_;
51 bool defineVertexFunctions_;
52 int numFields_, numPoints_;
53
54 size_t fad_size_output_;
55
56 Hierarchical_HGRAD_LINE_Functor(EOperator opType, OutputFieldType output, InputPointsType inputPoints,
57 int polyOrder, bool defineVertexFunctions)
58 : opType_(opType), output_(output), inputPoints_(inputPoints),
59 polyOrder_(polyOrder), defineVertexFunctions_(defineVertexFunctions),
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, 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 auto pointOrdinal = teamMember.league_rank();
72 OutputScratchView field_values_at_point;
73 if (fad_size_output_ > 0) {
74 field_values_at_point = OutputScratchView(teamMember.team_shmem(), numFields_, fad_size_output_);
75 }
76 else {
77 field_values_at_point = OutputScratchView(teamMember.team_shmem(), numFields_);
78 }
79
80 const auto & input_x = inputPoints_(pointOrdinal,0);
81 const bool taking_derivative = (opType_ != OPERATOR_VALUE);
82 const bool callingShiftedScaledLegendre = (opType_ == OPERATOR_VALUE) || (opType_ == OPERATOR_GRAD) || (opType_ == OPERATOR_D1);
83
84 // shiftedScaledIntegratedLegendreValues{_dx} expects x in [0,1]
85 const PointScalar x = callingShiftedScaledLegendre ? PointScalar((input_x + 1.0)/2.0) : PointScalar(input_x);
86 const double legendreScaling = 1.0;
87 const double outputScaling = taking_derivative ? 0.5 : 1.0; // output scaling -- 0.5 if we take derivatives, 1.0 otherwise
88
89 switch (opType_)
90 {
91 case OPERATOR_VALUE:
92 // field values are integrated Legendre polynomials, except for the first and second field,
93 // which may be 1 and x or x and 1-x, depending on whether the vertex compatibility flag is set.
94 Polynomials::shiftedScaledIntegratedLegendreValues(field_values_at_point, polyOrder_, x, legendreScaling);
95
96 // note that because shiftedScaledIntegratedLegendreValues determines field values recursively, there is not much
97 // opportunity at that level for further parallelism
98
99 if (defineVertexFunctions_)
100 {
101 field_values_at_point(0) = 1. - x;
102 field_values_at_point(1) = x;
103 }
104 break;
105 case OPERATOR_GRAD:
106 case OPERATOR_D1:
107 // field values are Legendre polynomials, except for the first and second field,
108 // which may be 0 and 1 or -1 and 1, depending on whether the vertex compatibility flag is set.
109 Polynomials::shiftedScaledIntegratedLegendreValues_dx(field_values_at_point, polyOrder_, x, legendreScaling);
110
111 // note that because shiftedScaledIntegratedLegendreValues_dx determines field values recursively, there is not much
112 // opportunity at that level for further parallelism
113
114 if (defineVertexFunctions_)
115 {
116 field_values_at_point(0) = -1.0; // derivative of 1-x
117 field_values_at_point(1) = 1.0; // derivative of x
118 }
119 break;
120 case OPERATOR_D2:
121 case OPERATOR_D3:
122 case OPERATOR_D4:
123 case OPERATOR_D5:
124 case OPERATOR_D6:
125 case OPERATOR_D7:
126 case OPERATOR_D8:
127 case OPERATOR_D9:
128 case OPERATOR_D10:
129 {
130 auto derivativeOrder = getOperatorOrder(opType_) - 1;
131 Polynomials::legendreDerivativeValues(field_values_at_point, polyOrder_, x, derivativeOrder);
132
133 // L_i is defined in terms of an integral of P_(i-1), so we need to shift the values by 1
134 if (numFields_ >= 3)
135 {
136 OutputScalar Pn_minus_one = field_values_at_point(1);
137 for (int fieldOrdinal=2; fieldOrdinal<numFields_; fieldOrdinal++)
138 {
139 OutputScalar Pn = field_values_at_point(fieldOrdinal);
140 field_values_at_point(fieldOrdinal) = Pn_minus_one;
141 Pn_minus_one = Pn;
142 }
143 }
144 if (numFields_ >= 1) field_values_at_point(0) = 0.0;
145 if (numFields_ >= 2) field_values_at_point(1) = 0.0;
146 // legendreDerivativeValues works on [-1,1], so no per-derivative scaling is necessary
147 // however, there is a factor of 0.5 that comes from the scaling of the Legendre polynomials prior to integration
148 // in the shiftedScaledIntegratedLegendreValues -- the first derivative of our integrated polynomials is 0.5 times the Legendre polynomial
149 break;
150 }
151 default:
152 // unsupported operator type
153 device_assert(false);
154 }
155
156 // copy the values into the output container
157 for (int fieldOrdinal=0; fieldOrdinal<numFields_; fieldOrdinal++)
158 {
159 // access() allows us to write one line that applies both to gradient (for which outputValues has rank 3, but third rank has only one entry) and to value (rank 2)
160 output_.access(fieldOrdinal,pointOrdinal,0) = outputScaling * field_values_at_point(fieldOrdinal);
161 }
162 }
163
164 // Provide the shared memory capacity.
165 // This function takes the team_size as an argument,
166 // which allows team_size-dependent allocations.
167 size_t team_shmem_size (int team_size) const
168 {
169 // we want to use shared memory to create a fast buffer that we can use for basis computations
170 size_t shmem_size = 0;
171 if (fad_size_output_ > 0)
172 shmem_size += OutputScratchView::shmem_size(numFields_, fad_size_output_);
173 else
174 shmem_size += OutputScratchView::shmem_size(numFields_);
175
176 return shmem_size;
177 }
178 };
179
197 template<typename DeviceType,
198 typename OutputScalar = double,
199 typename PointScalar = double,
200 bool defineVertexFunctions = true, // if defineVertexFunctions is true, first and second basis functions are x and 1-x. Otherwise, they are 1 and x.
201 bool useMinusOneToOneReferenceElement = true> // if useMinusOneToOneReferenceElement is true, basis is define on [-1,1]. Otherwise, [0,1].
203 : public Basis<DeviceType,OutputScalar,PointScalar>
204 {
205 public:
208
211
212 using typename BasisBase::OutputViewType;
213 using typename BasisBase::PointViewType;
214 using typename BasisBase::ScalarViewType;
215
216 using typename BasisBase::ExecutionSpace;
217
218 protected:
219 int polyOrder_; // the maximum order of the polynomial
220 bool defineVertexFunctions_; // if true, first and second basis functions are x and 1-x. Otherwise, they are 1 and x.
221 EPointType pointType_;
222 public:
233 IntegratedLegendreBasis_HGRAD_LINE(int polyOrder, EPointType pointType=POINTTYPE_DEFAULT)
234 :
235 polyOrder_(polyOrder),
236 pointType_(pointType)
237 {
238 INTREPID2_TEST_FOR_EXCEPTION(pointType!=POINTTYPE_DEFAULT,std::invalid_argument,"PointType not supported");
239
240 this->basisCardinality_ = polyOrder+1;
241 this->basisDegree_ = polyOrder;
242 this->basisCellTopologyKey_ = shards::Line<2>::key;
243 this->basisType_ = BASIS_FEM_HIERARCHICAL;
244 this->basisCoordinates_ = COORDINATES_CARTESIAN;
245 this->functionSpace_ = FUNCTION_SPACE_HGRAD;
246
247 const int degreeLength = 1;
248 this->fieldOrdinalPolynomialDegree_ = OrdinalTypeArray2DHost("Integrated Legendre H(grad) line polynomial degree lookup", this->basisCardinality_, degreeLength);
249 this->fieldOrdinalH1PolynomialDegree_ = OrdinalTypeArray2DHost("Integrated Legendre H(grad) line polynomial H^1 degree lookup", this->basisCardinality_, degreeLength);
250
251 for (int i=0; i<this->basisCardinality_; i++)
252 {
253 // for H(grad) line, if defineVertexFunctions is false, first basis member is constant, second is first-degree, etc.
254 // if defineVertexFunctions is true, then the only difference is that the entry is also degree 1
255 this->fieldOrdinalPolynomialDegree_ (i,0) = i;
256 this->fieldOrdinalH1PolynomialDegree_(i,0) = i;
257 }
258 if (defineVertexFunctions)
259 {
260 this->fieldOrdinalPolynomialDegree_ (0,0) = 1;
261 this->fieldOrdinalH1PolynomialDegree_(0,0) = 1;
262 }
263
264 // initialize tags
265 {
266 const auto & cardinality = this->basisCardinality_;
267
268 // Basis-dependent initializations
269 const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
270 const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
271 const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
272 const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
273
274 OrdinalTypeArray1DHost tagView("tag view", cardinality*tagSize);
275
276 if (defineVertexFunctions) {
277 {
278 const ordinal_type v0 = 0;
279 tagView(v0*tagSize+0) = 0; // vertex dof
280 tagView(v0*tagSize+1) = 0; // vertex id
281 tagView(v0*tagSize+2) = 0; // local dof id
282 tagView(v0*tagSize+3) = 1; // total number of dofs in this vertex
283
284 const ordinal_type v1 = 1;
285 tagView(v1*tagSize+0) = 0; // vertex dof
286 tagView(v1*tagSize+1) = 1; // vertex id
287 tagView(v1*tagSize+2) = 0; // local dof id
288 tagView(v1*tagSize+3) = 1; // total number of dofs in this vertex
289
290 const ordinal_type iend = cardinality - 2;
291 for (ordinal_type i=0;i<iend;++i) {
292 const auto e = i + 2;
293 tagView(e*tagSize+0) = 1; // edge dof
294 tagView(e*tagSize+1) = 0; // edge id
295 tagView(e*tagSize+2) = i; // local dof id
296 tagView(e*tagSize+3) = iend; // total number of dofs in this edge
297 }
298 }
299 } else {
300 for (ordinal_type i=0;i<cardinality;++i) {
301 tagView(i*tagSize+0) = 1; // edge dof
302 tagView(i*tagSize+1) = 0; // edge id
303 tagView(i*tagSize+2) = i; // local dof id
304 tagView(i*tagSize+3) = cardinality; // total number of dofs in this edge
305 }
306 }
307
308 // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
309 // tags are constructed on host
311 this->ordinalToTag_,
312 tagView,
313 this->basisCardinality_,
314 tagSize,
315 posScDim,
316 posScOrd,
317 posDfOrd);
318 }
319 }
320
325 const char* getName() const override {
326 return "Intrepid2_IntegratedLegendreBasis_HGRAD_LINE";
327 }
328
331 virtual bool requireOrientation() const override {
332 return false;
333 }
334
335 // since the getValues() below only overrides the FEM variant, we specify that
336 // we use the base class's getValues(), which implements the FVD variant by throwing an exception.
337 // (It's an error to use the FVD variant on this basis.)
339
358 virtual void getValues( OutputViewType outputValues, const PointViewType inputPoints,
359 const EOperator operatorType = OPERATOR_VALUE ) const override
360 {
361 auto numPoints = inputPoints.extent_int(0);
362
364
365 FunctorType functor(operatorType, outputValues, inputPoints, polyOrder_, defineVertexFunctions);
366
367 const int outputVectorSize = getVectorSizeForHierarchicalParallelism<OutputScalar>();
368 const int pointVectorSize = getVectorSizeForHierarchicalParallelism<PointScalar>();
369 const int vectorSize = std::max(outputVectorSize,pointVectorSize);
370 const int teamSize = 1; // because of the way the basis functions are computed, we don't have a second level of parallelism...
371
372 auto policy = Kokkos::TeamPolicy<ExecutionSpace>(numPoints,teamSize,vectorSize);
373 Kokkos::parallel_for("Hierarchical_HGRAD_LINE_Functor", policy, functor);
374 }
375
381 getHostBasis() const override {
382 using HostDeviceType = typename Kokkos::HostSpace::device_type;
384 return Teuchos::rcp( new HostBasisType(polyOrder_, pointType_) );
385 }
386 };
387} // end namespace Intrepid2
388
389#endif /* Intrepid2_IntegratedLegendreBasis_HGRAD_LINE_h */
Header file for the abstract base class Intrepid2::Basis.
KOKKOS_INLINE_FUNCTION ordinal_type getOperatorOrder(const EOperator operatorType)
Returns order of an operator.
Teuchos::RCP< Basis< DeviceType, OutputType, PointType > > BasisPtr
Basis Pointer.
KOKKOS_INLINE_FUNCTION void device_assert(bool val)
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.
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
OrdinalTypeArray2DHost fieldOrdinalH1PolynomialDegree_
H^1 polynomial degree for each degree of freedom. Only defined for hierarchical bases right now....
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 integrated Legendre basis on the line, a polynomial subspace of H(grad) on the line.
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 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...
IntegratedLegendreBasis_HGRAD_LINE(int polyOrder, EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
Kokkos::View< ordinal_type **, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
virtual bool requireOrientation() const override
True if orientation is required.
Functor for computing values for the IntegratedLegendreBasis_HGRAD_LINE class.