Intrepid2
Intrepid2_TransformedBasisValues.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_TransformedBasisValues_h
19 #define Intrepid2_TransformedBasisValues_h
20 
22 #include "Intrepid2_DataTools.hpp"
23 #include "Intrepid2_ScalarView.hpp"
24 #include "Intrepid2_Utils.hpp"
25 
26 namespace Intrepid2 {
32  template<class Scalar, typename DeviceType>
34  {
35  public:
36  using value_type = Scalar;
37 
38  ordinal_type numCells_;
39 
40  Data<Scalar,DeviceType> transform_; // vector case: (C,P,D,D) jacobian or jacobian inverse; can also be unset for identity transform. Scalar case: (C,P), or unset for identity. Contracted vector case: (C,P,D) transform, to be contracted with a vector field to produce a scalar result.
41 
43 
50  :
51  numCells_(transform.extent_int(0)),
52  transform_(transform),
53  basisValues_(basisValues)
54  {
55  // sanity check: when transform is diagonal, we expect there to be no pointwise variation.
56  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(transform_.isDiagonal() && (transform_.getVariationTypes()[1] != CONSTANT), std::invalid_argument, "When transform is diagonal, we assume in various places that there is no pointwise variation; the transform_ Data should have CONSTANT as its variation type in dimension 1.");
57  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE((transform_.rank() < 2) || (transform_.rank() > 4), std::invalid_argument, "Only transforms of rank 2, 3, or 4 are supported");
58  }
59 
64  TransformedBasisValues(const ordinal_type &numCells, const BasisValues<Scalar,DeviceType> &basisValues)
65  :
66  numCells_(numCells),
67  basisValues_(basisValues)
68  {}
69 
71  template<typename OtherDeviceType, class = typename std::enable_if<!std::is_same<DeviceType, OtherDeviceType>::value>::type>
73  :
74  numCells_(transformedVectorData.numCells()),
75  transform_(transformedVectorData.transform()),
76  basisValues_(transformedVectorData.basisValues())
77  {}
78 
83  :
84  numCells_(-1)
85  {}
86 
88  KOKKOS_INLINE_FUNCTION bool axisAligned() const
89  {
90  if (!transform_.isValid())
91  {
92  // null transform is understood as the identity
93  return true;
94  }
95  else
96  {
97  return transform_.isDiagonal();
98  }
99  }
100 
101  BasisValues<Scalar, DeviceType> basisValues() const
102  {
103  return basisValues_;
104  }
105 
107  KOKKOS_INLINE_FUNCTION int cellDataExtent() const
108  {
109  return transform_.getDataExtent(0);
110  }
111 
113  KOKKOS_INLINE_FUNCTION DataVariationType cellVariationType() const
114  {
115  return transform_.getVariationTypes()[0];
116  }
117 
119  template<class ViewType>
120  void multiplyByPointwiseWeights(const ViewType &weights)
121  {
122  ordinal_type weightRank = getFunctorRank(weights); // .rank() or ::rank, depending on weights type
123  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(weightRank != 2, std::invalid_argument, "pointwise weights must have shape (C,P).");
124 
125  Data<Scalar,DeviceType> weightData(weights);
126  if (!transform_.isValid())
127  {
128  // empty transform_ is understood as identity; multiplying by weightData is thus
129  // the same as transform_ = weightData
130  transform_ = weightData;
131  return;
132  }
133  else
134  {
135  if ((transform_.rank() == 4) || (transform_.rank() == 3))
136  {
137  transform_ = DataTools::multiplyByCPWeights(transform_,weightData);
138  }
139  else // transformRank == 2
140  {
141  auto result = Data<Scalar,DeviceType>::allocateInPlaceCombinationResult(weightData, transform_);
142 
143  result.storeInPlaceProduct(weightData,transform_);
144  transform_ = result;
145  }
146  }
147  }
148 
150  KOKKOS_INLINE_FUNCTION int numCells() const
151  {
152  return numCells_;
153  }
154 
156  KOKKOS_INLINE_FUNCTION int numFields() const
157  {
158  return basisValues_.extent_int(0);
159  }
160 
162  KOKKOS_INLINE_FUNCTION int numPoints() const
163  {
164  return basisValues_.extent_int(1);
165  }
166 
168  KOKKOS_INLINE_FUNCTION int spaceDim() const
169  {
170  if ((transform_.rank() == 3) && (basisValues_.rank() == 3)) // (C,P,D) contracted in D against (F,P,D)
171  {
172  return 1; // spaceDim contracted away
173  }
174  else if ((transform_.rank() == 3) && (basisValues_.rank() == 2)) // (C,P,D) weighting (F,P)
175  {
176  return transform_.extent_int(2);
177  }
178  else if (transform_.isValid())
179  {
180  return transform_.extent_int(2);
181  }
182  else
183  {
184  return basisValues_.extent_int(2);
185  }
186  }
187 
189  KOKKOS_INLINE_FUNCTION Scalar operator()(const int &cellOrdinal, const int &fieldOrdinal, const int &pointOrdinal) const
190  {
191  if (!transform_.isValid())
192  {
193  // null transform is understood as the identity
194  return basisValues_(fieldOrdinal,pointOrdinal);
195  }
196  else if (transform_.rank() == 2)
197  {
198  return transform_(cellOrdinal,pointOrdinal) * basisValues_(fieldOrdinal,pointOrdinal);
199  }
200  else if (transform_.rank() == 3)
201  {
202  Scalar value = 0;
203  for (int d=0; d<transform_.extent_int(2); d++)
204  {
205  value += transform_(cellOrdinal,pointOrdinal,d) * basisValues_(fieldOrdinal,pointOrdinal,d);
206  }
207  return value;
208  }
209  return 0; // should not be reachable
210  }
211 
213  KOKKOS_INLINE_FUNCTION Scalar operator()(const int &cellOrdinal, const int &fieldOrdinal, const int &pointOrdinal, const int &dim) const
214  {
215  if (!transform_.isValid())
216  {
217  // null transform is understood as the identity
218  return basisValues_(fieldOrdinal,pointOrdinal,dim);
219  }
220  else if (transform_.isDiagonal())
221  {
222  return transform_(cellOrdinal,pointOrdinal,dim,dim) * basisValues_(fieldOrdinal,pointOrdinal,dim);
223  }
224  else if (transform_.rank() == 4)
225  {
226  Scalar value = 0.0;
227  for (int d2=0; d2<transform_.extent_int(2); d2++)
228  {
229  value += transform_(cellOrdinal,pointOrdinal,dim,d2) * basisValues_(fieldOrdinal,pointOrdinal,d2);
230  }
231  return value;
232  }
233  else if (transform_.rank() == 3)
234  {
235  Scalar value = transform_(cellOrdinal,pointOrdinal,dim) * basisValues_(fieldOrdinal,pointOrdinal);
236  return value;
237  }
238  else // rank 2 transform
239  {
240  Scalar value = transform_(cellOrdinal,pointOrdinal) * basisValues_(fieldOrdinal,pointOrdinal,dim);
241  return value;
242  }
243  }
244 
246  KOKKOS_INLINE_FUNCTION Scalar transformWeight(const int &cellOrdinal, const int &pointOrdinal) const
247  {
248  if (!transform_.isValid())
249  {
250  // null transform is understood as identity
251  return 1.0;
252  }
253  else
254  {
255  return transform_(cellOrdinal,pointOrdinal);
256  }
257  }
258 
260  KOKKOS_INLINE_FUNCTION Scalar transformWeight(const int &cellOrdinal, const int &pointOrdinal, const int &d) const
261  {
262  if (!transform_.isValid())
263  {
264  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "three-argument transformWeight() is not supported for invalid transform_ object -- no meaningful interpretation for vector-valued identity");
265  }
266  else
267  {
268  return transform_(cellOrdinal,pointOrdinal,d);
269  }
270  }
271 
273  KOKKOS_INLINE_FUNCTION Scalar transformWeight(const int &cellOrdinal, const int &pointOrdinal, const int &dim1, const int &dim2) const
274  {
275  if (!transform_.isValid())
276  {
277  // null transform is understood as identity
278  return (dim1 == dim2) ? 1.0 : 0.0;
279  }
280  else
281  {
282  return transform_(cellOrdinal,pointOrdinal,dim1,dim2);
283  }
284  }
285 
288  {
289  return transform_;
290  }
291 
294  {
295  return basisValues_.vectorData();
296  }
297 
299  KOKKOS_INLINE_FUNCTION
300  unsigned rank() const
301  {
302  if ((transform_.rank() == 4) && (basisValues_.rank() == 3))
303  {
304  return 4; // (C,F,P,D)
305  }
306  else if (transform_.rank() == 2)
307  {
308  return basisValues_.rank() + 1; // transformation adds a cell dimension
309  }
310  else if (transform_.rank() == 3)
311  {
312  if (basisValues_.rank() == 3)
313  {
314  // transform contracts with basisValues in D dimension
315  return 3; // (C,F,P)
316  }
317  else if (basisValues_.rank() == 2) // (F,P)
318  {
319  return 4; // (C,F,P,D)
320  }
321  }
322  INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(true, std::invalid_argument, "Unhandled basisValues_/transform_ rank combination");
323  }
324 
326  KOKKOS_INLINE_FUNCTION
327  int extent_int(const int &r) const
328  {
329  if (r == 0) return numCells();
330  else if (r == 1) return numFields();
331  else if (r == 2) return numPoints();
332  else if (r == 3) return spaceDim();
333  else if (r > 3) return 1;
334 
335  return -1; // unreachable return; here to avoid compiler warnings.
336  }
337  };
338 }
339 
340 #endif /* Intrepid2_TransformedBasisValues_h */
TransformedBasisValues(const Data< Scalar, DeviceType > &transform, const BasisValues< Scalar, DeviceType > &basisValues)
Standard constructor.
static void multiplyByCPWeights(Data< Scalar, DeviceType > &resultMatrixData, const Data< Scalar, DeviceType > &matrixDataIn, const Data< Scalar, DeviceType > &scalarDataIn)
Utility methods for manipulating Intrepid2::Data objects.
static Data< DataScalar, DeviceType > allocateInPlaceCombinationResult(const Data< DataScalar, DeviceType > &A, const Data< DataScalar, DeviceType > &B)
KOKKOS_INLINE_FUNCTION int spaceDim() const
Returns the logical extent in the space dimension, which is the 3 dimension in this container...
#define INTREPID2_TEST_FOR_EXCEPTION_DEVICE_SAFE(test, x, msg)
KOKKOS_INLINE_FUNCTION DataVariationType cellVariationType() const
Returns the variation type corresponding to the cell dimension.
KOKKOS_INLINE_FUNCTION unsigned rank() const
Returns the rank of the container, which is 3 for scalar values, and 4 for vector values...
KOKKOS_INLINE_FUNCTION Scalar operator()(const int &cellOrdinal, const int &fieldOrdinal, const int &pointOrdinal, const int &dim) const
Vector accessor, with arguments (C,F,P,D).
void multiplyByPointwiseWeights(const ViewType &weights)
Replaces the internal pullback (transformation operator) with the result of the pullback multiplied b...
KOKKOS_INLINE_FUNCTION int cellDataExtent() const
Returns the true data extent in the cell dimension (e.g., will be 1 for transform matrices that do no...
KOKKOS_INLINE_FUNCTION Scalar operator()(const int &cellOrdinal, const int &fieldOrdinal, const int &pointOrdinal) const
Scalar accessor, with arguments (C,F,P).
KOKKOS_INLINE_FUNCTION const Kokkos::Array< DataVariationType, 7 > & getVariationTypes() const
Returns an array with the variation types in each logical dimension.
TransformedBasisValues()
Default constructor; an invalid container. Will return -1 for numCells().
KOKKOS_INLINE_FUNCTION int numPoints() const
Returns the logical extent in the points dimension, which is the 2 dimension in this container...
Header function for Intrepid2::Util class and other utility functions.
KOKKOS_INLINE_FUNCTION bool isDiagonal() const
returns true for containers that have two dimensions marked as BLOCK_PLUS_DIAGONAL for which the non-...
const Data< Scalar, DeviceType > & transform() const
Returns the transform matrix. An invalid/empty container indicates the identity transform.
TransformedBasisValues(const ordinal_type &numCells, const BasisValues< Scalar, DeviceType > &basisValues)
Constructor for the case of an identity transform.
The data containers in Intrepid2 that support sum factorization and other reduced-data optimizations ...
KOKKOS_INLINE_FUNCTION Scalar transformWeight(const int &cellOrdinal, const int &pointOrdinal) const
Returns the specified entry in the (scalar) transform. (Only valid for scalar-valued BasisValues; see...
KOKKOS_INLINE_FUNCTION constexpr bool isValid() const
returns true for containers that have data; false for those that don&#39;t (namely, those that have been ...
KOKKOS_INLINE_FUNCTION Scalar transformWeight(const int &cellOrdinal, const int &pointOrdinal, const int &dim1, const int &dim2) const
Returns the specified entry in the transform matrix.
KOKKOS_INLINE_FUNCTION unsigned rank() const
Returns the logical rank of the Data container.
KOKKOS_INLINE_FUNCTION int extent_int(const int &r) const
Returns the logical extent in the specified dimension.
TransformedBasisValues(const TransformedBasisValues< Scalar, OtherDeviceType > &transformedVectorData)
copy-like constructor for differing device types. This may do a deep_copy of underlying views...
KOKKOS_INLINE_FUNCTION int extent_int(const int &r) const
Returns the extent in the specified dimension as an int.
KOKKOS_INLINE_FUNCTION int numFields() const
Returns the logical extent in the fields dimension, which is the 1 dimension in this container...
KOKKOS_INLINE_FUNCTION int getDataExtent(const ordinal_type &d) const
returns the true extent of the data corresponding to the logical dimension provided; if the data does...
Structure-preserving representation of transformed vector data; reference space values and transforma...
const VectorData< Scalar, DeviceType > & vectorData() const
Returns the reference-space vector data.
KOKKOS_INLINE_FUNCTION Scalar transformWeight(const int &cellOrdinal, const int &pointOrdinal, const int &d) const
Returns the specified entry in the transformation vector.
Header file for the data-wrapper class Intrepid2::BasisValues.
Reference-space field values for a basis, designed to support typical vector-valued bases...
KOKKOS_INLINE_FUNCTION bool axisAligned() const
Returns true if the transformation matrix is diagonal.
KOKKOS_INLINE_FUNCTION int numCells() const
Returns the logical extent in the cell dimension, which is the 0 dimension in this container...