Intrepid2
Intrepid2_DirectSumBasis.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ************************************************************************
3 //
4 // Intrepid2 Package
5 // Copyright (2007) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Kyungjoo Kim (kyukim@sandia.gov),
38 // Mauro Perego (mperego@sandia.gov), or
39 // Nate Roberts (nvrober@sandia.gov)
40 //
41 // ************************************************************************
42 // @HEADER
43 
49 #ifndef Intrepid2_DirectSumBasis_h
50 #define Intrepid2_DirectSumBasis_h
51 
52 #include <Kokkos_View.hpp>
53 #include <Kokkos_DynRankView.hpp>
54 
55 namespace Intrepid2
56 {
67  template<typename Basis1, typename Basis2>
69  : public Basis<typename Basis1::ExecutionSpace,
70  typename Basis1::OutputValueType,
71  typename Basis1::PointValueType>
72  {
73  protected:
74  Basis1 basis1_;
75  Basis2 basis2_;
76 
77  std::string name_;
78  public:
79  using OrdinalTypeArray1DHost = typename Basis1::OrdinalTypeArray1DHost;
80  using OrdinalTypeArray2DHost = typename Basis1::OrdinalTypeArray2DHost;
81 
82  using ExecutionSpace = typename Basis1::ExecutionSpace;
83  using OutputValueType = typename Basis1::OutputValueType;
84  using PointValueType = typename Basis1::PointValueType;
85 
86  using OutputViewType = typename Basis1::OutputViewType;
87  using PointViewType = typename Basis1::PointViewType;
88  using ScalarViewType = typename Basis1::ScalarViewType;
89  public:
94  Basis_DirectSumBasis(Basis1 basis1, Basis2 basis2)
95  :
96  basis1_(basis1),basis2_(basis2)
97  {
98  INTREPID2_TEST_FOR_EXCEPTION(basis1.getBasisType() != basis2.getBasisType(), std::invalid_argument, "basis1 and basis2 must agree in basis type");
99  INTREPID2_TEST_FOR_EXCEPTION(basis1.getBaseCellTopology().getKey() != basis2.getBaseCellTopology().getKey(),
100  std::invalid_argument, "basis1 and basis2 must agree in cell topology");
101  INTREPID2_TEST_FOR_EXCEPTION(basis1.getCoordinateSystem() != basis2.getCoordinateSystem(),
102  std::invalid_argument, "basis1 and basis2 must agree in coordinate system");
103 
104  this->basisCardinality_ = basis1.getCardinality() + basis2.getCardinality();
105  this->basisDegree_ = std::max(basis1.getDegree(), basis2.getDegree());
106 
107  {
108  std::ostringstream basisName;
109  basisName << basis1.getName() << " + " << basis2.getName();
110  name_ = basisName.str();
111  }
112 
113  this->basisCellTopology_ = basis1.getBaseCellTopology();
114  this->basisType_ = basis1.getBasisType();
115  this->basisCoordinates_ = basis1.getCoordinateSystem();
116 
117  if (this->basisType_ == BASIS_FEM_HIERARCHICAL)
118  {
119  int degreeLength = basis1_.getPolynomialDegreeLength();
120  INTREPID2_TEST_FOR_EXCEPTION(degreeLength != basis2_.getPolynomialDegreeLength(), std::invalid_argument, "Basis1 and Basis2 must agree on polynomial degree length");
121 
122  this->fieldOrdinalPolynomialDegree_ = OrdinalTypeArray2DHost("DirectSumBasis degree lookup",this->basisCardinality_,degreeLength);
123  // our field ordinals start with basis1_; basis2_ follows
124  for (int fieldOrdinal1=0; fieldOrdinal1<basis1_.getCardinality(); fieldOrdinal1++)
125  {
126  int fieldOrdinal = fieldOrdinal1;
127  auto polynomialDegree = basis1.getPolynomialDegreeOfField(fieldOrdinal1);
128  for (int d=0; d<degreeLength; d++)
129  {
130  this->fieldOrdinalPolynomialDegree_(fieldOrdinal,d) = polynomialDegree(d);
131  }
132  }
133  for (int fieldOrdinal2=0; fieldOrdinal2<basis2_.getCardinality(); fieldOrdinal2++)
134  {
135  int fieldOrdinal = basis1.getCardinality() + fieldOrdinal2;
136 
137  auto polynomialDegree = basis2.getPolynomialDegreeOfField(fieldOrdinal2);
138  for (int d=0; d<degreeLength; d++)
139  {
140  this->fieldOrdinalPolynomialDegree_(fieldOrdinal,d) = polynomialDegree(d);
141  }
142  }
143  }
144 
145  // initialize tags
146  {
147  const auto & cardinality = this->basisCardinality_;
148 
149  // Basis-dependent initializations
150  const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
151  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
152  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
153  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
154 
155  OrdinalTypeArray1DHost tagView("tag view", cardinality*tagSize);
156 
157  shards::CellTopology cellTopo = this->basisCellTopology_;
158 
159  unsigned spaceDim = cellTopo.getDimension();
160 
161  ordinal_type basis2Offset = basis1_.getCardinality();
162 
163  for (unsigned d=0; d<=spaceDim; d++)
164  {
165  unsigned subcellCount = cellTopo.getSubcellCount(d);
166  for (unsigned subcellOrdinal=0; subcellOrdinal<subcellCount; subcellOrdinal++)
167  {
168  ordinal_type subcellDofCount1 = basis1.getDofCount(d, subcellOrdinal);
169  ordinal_type subcellDofCount2 = basis2.getDofCount(d, subcellOrdinal);
170 
171  ordinal_type subcellDofCount = subcellDofCount1 + subcellDofCount2;
172  for (ordinal_type localDofID=0; localDofID<subcellDofCount; localDofID++)
173  {
174  ordinal_type fieldOrdinal;
175  if (localDofID < subcellDofCount1)
176  {
177  // first basis: field ordinal matches the basis1 ordinal
178  fieldOrdinal = basis1_.getDofOrdinal(d, subcellOrdinal, localDofID);
179  }
180  else
181  {
182  // second basis: field ordinal is offset by basis1 cardinality
183  fieldOrdinal = basis2Offset + basis2_.getDofOrdinal(d, subcellOrdinal, localDofID - subcellDofCount1);
184  }
185  tagView(fieldOrdinal*tagSize+0) = d; // subcell dimension
186  tagView(fieldOrdinal*tagSize+1) = subcellOrdinal;
187  tagView(fieldOrdinal*tagSize+2) = localDofID;
188  tagView(fieldOrdinal*tagSize+3) = subcellDofCount;
189  }
190  }
191  }
192  // // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
193  // // tags are constructed on host
194  this->setOrdinalTagData(this->tagToOrdinal_,
195  this->ordinalToTag_,
196  tagView,
197  this->basisCardinality_,
198  tagSize,
199  posScDim,
200  posScOrd,
201  posDfOrd);
202  }
203  }
204 
213  virtual void getDofCoords( ScalarViewType dofCoords ) const override {
214  const int basisCardinality1 = basis1_.getCardinality();
215  const int basisCardinality2 = basis2_.getCardinality();
216  const int basisCardinality = basisCardinality1 + basisCardinality2;
217 
218  auto dofCoords1 = Kokkos::subview(dofCoords, std::make_pair(0,basisCardinality1), Kokkos::ALL());
219  auto dofCoords2 = Kokkos::subview(dofCoords, std::make_pair(basisCardinality1,basisCardinality), Kokkos::ALL());
220 
221  basis1_.getDofCoords(dofCoords1);
222  basis2_.getDofCoords(dofCoords2);
223  }
224 
229  virtual
230  const char*
231  getName() const override {
232  return name_.c_str();
233  }
234 
235  // since the getValues() below only overrides the FEM variant, we specify that
236  // we use the base class's getValues(), which implements the FVD variant by throwing an exception.
237  // (It's an error to use the FVD variant on this basis.)
239 
258  virtual void getValues( OutputViewType outputValues, const PointViewType inputPoints,
259  const EOperator operatorType = OPERATOR_VALUE ) const override
260  {
261  int cardinality1 = basis1_.getCardinality();
262  int cardinality2 = basis2_.getCardinality();
263 
264  auto range1 = std::make_pair(0,cardinality1);
265  auto range2 = std::make_pair(cardinality1,cardinality1+cardinality2);
266  if (outputValues.rank() == 2) // F,P
267  {
268  auto outputValues1 = Kokkos::subview(outputValues, range1, Kokkos::ALL());
269  auto outputValues2 = Kokkos::subview(outputValues, range2, Kokkos::ALL());
270 
271  basis1_.getValues(outputValues1, inputPoints, operatorType);
272  basis2_.getValues(outputValues2, inputPoints, operatorType);
273  }
274  else if (outputValues.rank() == 3) // F,P,D
275  {
276  auto outputValues1 = Kokkos::subview(outputValues, range1, Kokkos::ALL(), Kokkos::ALL());
277  auto outputValues2 = Kokkos::subview(outputValues, range2, Kokkos::ALL(), Kokkos::ALL());
278 
279  basis1_.getValues(outputValues1, inputPoints, operatorType);
280  basis2_.getValues(outputValues2, inputPoints, operatorType);
281  }
282  else if (outputValues.rank() == 4) // F,P,D,D
283  {
284  auto outputValues1 = Kokkos::subview(outputValues, range1, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
285  auto outputValues2 = Kokkos::subview(outputValues, range2, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
286 
287  basis1_.getValues(outputValues1, inputPoints, operatorType);
288  basis2_.getValues(outputValues2, inputPoints, operatorType);
289  }
290  else if (outputValues.rank() == 5) // F,P,D,D,D
291  {
292  auto outputValues1 = Kokkos::subview(outputValues, range1, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
293  auto outputValues2 = Kokkos::subview(outputValues, range2, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
294 
295  basis1_.getValues(outputValues1, inputPoints, operatorType);
296  basis2_.getValues(outputValues2, inputPoints, operatorType);
297  }
298  else if (outputValues.rank() == 6) // F,P,D,D,D,D
299  {
300  auto outputValues1 = Kokkos::subview(outputValues, range1, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
301  auto outputValues2 = Kokkos::subview(outputValues, range2, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
302 
303  basis1_.getValues(outputValues1, inputPoints, operatorType);
304  basis2_.getValues(outputValues2, inputPoints, operatorType);
305  }
306  else if (outputValues.rank() == 7) // F,P,D,D,D,D,D
307  {
308  auto outputValues1 = Kokkos::subview(outputValues, range1, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
309  auto outputValues2 = Kokkos::subview(outputValues, range2, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL());
310 
311  basis1_.getValues(outputValues1, inputPoints, operatorType);
312  basis2_.getValues(outputValues2, inputPoints, operatorType);
313  }
314  else
315  {
316  INTREPID2_TEST_FOR_EXCEPTION(true, std::invalid_argument, "Unsupported outputValues rank");
317  }
318  }
319  };
320 } // end namespace Intrepid2
321 
322 #endif /* Intrepid2_DirectSumBasis_h */
Kokkos::View< ordinal_type *, typename Basis_Derived_HDIV_Family1_QUAD< HGRAD_LINE, HVOL_LINE >::ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
Kokkos::View< ordinal_type **, typename Basis_Derived_HDIV_Family1_QUAD< HGRAD_LINE, HVOL_LINE >::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. ...
ECoordinates basisCoordinates_
The coordinate system for which the basis is defined.
virtual void getDofCoords(ScalarViewType dofCoords) const override
Fills in spatial locations (coordinates) of degrees of freedom (nodes) on the reference cell...
An abstract base class that defines interface for concrete basis implementations for Finite Element (...
virtual void getValues(OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
ordinal_type basisDegree_
Degree of the largest complete polynomial space that can be represented by the basis.
virtual const char * getName() const override
Returns basis name.
Basis_DirectSumBasis(Basis1 basis1, Basis2 basis2)
Constructor.
A basis that is the direct sum of two other bases.
Kokkos::DynRankView< OutputValueType, Kokkos::LayoutStride, Basis_Derived_HDIV_Family1_QUAD< HGRAD_LINE, HVOL_LINE >::ExecutionSpace > OutputViewType
View type for basis value output.
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.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, Basis_Derived_HDIV_Family1_QUAD< HGRAD_LINE, HVOL_LINE >::ExecutionSpace > PointViewType
View type for input points.
OrdinalTypeArray2DHost ordinalToTag_
&quot;true&quot; if tagToOrdinal_ and ordinalToTag_ have been initialized
shards::CellTopology basisCellTopology_
Base topology of the cells for which the basis is defined. See the Shards package for definition of b...