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 
26 namespace 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 
209  using typename BasisBase::OrdinalTypeArray1DHost;
210  using typename BasisBase::OrdinalTypeArray2DHost;
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
310  this->setOrdinalTagData(this->tagToOrdinal_,
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.)
338  using BasisBase::getValues;
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 
380  virtual BasisPtr<typename Kokkos::HostSpace::device_type, OutputScalar, PointScalar>
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 */
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.
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...
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
Kokkos::DynRankView< scalarType, Kokkos::LayoutStride, DeviceType > ScalarViewType
View type for scalars.
Free functions, callable from device code, that implement various polynomials useful in basis definit...
IntegratedLegendreBasis_HGRAD_LINE(int polyOrder, EPointType pointType=POINTTYPE_DEFAULT)
Constructor.
EFunctionSpace functionSpace_
The function space in which the basis is defined.
ordinal_type basisDegree_
Degree of the largest complete polynomial space that can be represented by the basis.
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.
Header function for Intrepid2::Util class and other utility functions.
Kokkos::View< ordinal_type **, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray2DHost
View type for 2d host array.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
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.
ordinal_type basisCardinality_
Cardinality of the basis, i.e., the number of basis functions/degrees-of-freedom. ...
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, DeviceType > OutputViewType
View type for basis value output.
OrdinalTypeArray3DHost tagToOrdinal_
DoF tag to ordinal lookup table.
OrdinalTypeArray2DHost ordinalToTag_
&quot;true&quot; if tagToOrdinal_ and ordinalToTag_ have been initialized
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
OrdinalTypeArray2DHost fieldOrdinalH1PolynomialDegree_
H^1 polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
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...
OrdinalTypeArray2DHost fieldOrdinalPolynomialDegree_
Polynomial degree for each degree of freedom. Only defined for hierarchical bases right now...
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.
Functor for computing values for the IntegratedLegendreBasis_HGRAD_LINE class.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
Header file for the abstract base class Intrepid2::Basis.
typename DeviceType::execution_space ExecutionSpace
(Kokkos) Execution space for basis.