Intrepid2
Intrepid2_HGRAD_LINE_Cn_FEMDef.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 
16 #ifndef __INTREPID2_HGRAD_LINE_CN_FEM_DEF_HPP__
17 #define __INTREPID2_HGRAD_LINE_CN_FEM_DEF_HPP__
18 
19 namespace Intrepid2 {
20 
21  // -------------------------------------------------------------------------------------
22  namespace Impl {
23 
24  template<EOperator opType>
25  template<typename OutputViewType,
26  typename InputViewType,
27  typename WorkViewType,
28  typename VinvViewType>
29  KOKKOS_INLINE_FUNCTION
30  void
31  Basis_HGRAD_LINE_Cn_FEM::Serial<opType>::
32  getValues( OutputViewType output,
33  const InputViewType input,
34  WorkViewType work,
35  const VinvViewType vinv,
36  const ordinal_type operatorDn ) {
37  ordinal_type opDn = operatorDn;
38 
39  const ordinal_type card = vinv.extent(0);
40  const ordinal_type npts = input.extent(0);
41 
42  const ordinal_type order = card - 1;
43  const double alpha = 0.0, beta = 0.0;
44 
45  typedef typename Kokkos::DynRankView<typename InputViewType::value_type, typename WorkViewType::memory_space> ViewType;
46  auto vcprop = Kokkos::common_view_alloc_prop(input);
47 
48  switch (opType) {
49  case OPERATOR_VALUE: {
50  ViewType phis(Kokkos::view_wrap(work.data(), vcprop), card, npts);
51 
52  Impl::Basis_HGRAD_LINE_Cn_FEM_JACOBI::
53  Serial<opType>::getValues(phis, input, order, alpha, beta);
54 
55  for (ordinal_type i=0;i<card;++i)
56  for (ordinal_type j=0;j<npts;++j) {
57  output.access(i,j) = 0.0;
58  for (ordinal_type k=0;k<card;++k)
59  output.access(i,j) += vinv(k,i)*phis.access(k,j);
60  }
61  break;
62  }
63  case OPERATOR_GRAD:
64  case OPERATOR_D1:
65  case OPERATOR_D2:
66  case OPERATOR_D3:
67  case OPERATOR_D4:
68  case OPERATOR_D5:
69  case OPERATOR_D6:
70  case OPERATOR_D7:
71  case OPERATOR_D8:
72  case OPERATOR_D9:
73  case OPERATOR_D10:
74  opDn = getOperatorOrder(opType);
75  case OPERATOR_Dn: {
76  // dkcard is always 1 for 1D element
77  const ordinal_type dkcard = 1;
78  ViewType phis(Kokkos::view_wrap(work.data(), vcprop), card, npts, dkcard);
79  Impl::Basis_HGRAD_LINE_Cn_FEM_JACOBI::
80  Serial<opType>::getValues(phis, input, order, alpha, beta, opDn);
81 
82  for (ordinal_type i=0;i<card;++i)
83  for (ordinal_type j=0;j<npts;++j)
84  for (ordinal_type k=0;k<dkcard;++k) {
85  output.access(i,j,k) = 0.0;
86  for (ordinal_type l=0;l<card;++l)
87  output.access(i,j,k) += vinv(l,i)*phis.access(l,j,k);
88  }
89  break;
90  }
91  default: {
92  INTREPID2_TEST_FOR_ABORT( true,
93  ">>> ERROR: (Intrepid2::Basis_HGRAD_LINE_Cn_FEM::Serial::getValues) operator is not supported." );
94  }
95  }
96  }
97 
98 
99  template<typename DT, ordinal_type numPtsPerEval,
100  typename outputValueValueType, class ...outputValueProperties,
101  typename inputPointValueType, class ...inputPointProperties,
102  typename vinvValueType, class ...vinvProperties>
103  void
104  Basis_HGRAD_LINE_Cn_FEM::
105  getValues( const typename DT::execution_space& space,
106  Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValues,
107  const Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPoints,
108  const Kokkos::DynRankView<vinvValueType, vinvProperties...> vinv,
109  const EOperator operatorType ) {
110  typedef Kokkos::DynRankView<outputValueValueType,outputValueProperties...> outputValueViewType;
111  typedef Kokkos::DynRankView<inputPointValueType, inputPointProperties...> inputPointViewType;
112  typedef Kokkos::DynRankView<vinvValueType, vinvProperties...> vinvViewType;
113  typedef typename ExecSpace<typename inputPointViewType::execution_space,typename DT::execution_space>::ExecSpaceType ExecSpaceType;
114 
115  // loopSize corresponds to cardinality
116  const auto loopSizeTmp1 = (inputPoints.extent(0)/numPtsPerEval);
117  const auto loopSizeTmp2 = (inputPoints.extent(0)%numPtsPerEval != 0);
118  const auto loopSize = loopSizeTmp1 + loopSizeTmp2;
119  Kokkos::RangePolicy<ExecSpaceType,Kokkos::Schedule<Kokkos::Static> > policy(space, 0, loopSize);
120 
121  typedef typename inputPointViewType::value_type inputPointType;
122 
123  const ordinal_type cardinality = outputValues.extent(0);
124 
125  auto vcprop = Kokkos::common_view_alloc_prop(inputPoints);
126  typedef typename Kokkos::DynRankView< inputPointType, typename inputPointViewType::memory_space> workViewType;
127  workViewType work(Kokkos::view_alloc(space, "Basis_HGRAD_LINE_Cn_FEM::getValues::work", vcprop), cardinality, inputPoints.extent(0));
128 
129  switch (operatorType) {
130  case OPERATOR_VALUE: {
131  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
132  OPERATOR_VALUE,numPtsPerEval> FunctorType;
133  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work) );
134  break;
135  }
136  case OPERATOR_GRAD:
137  case OPERATOR_D1:
138  case OPERATOR_D2:
139  case OPERATOR_D3:
140  case OPERATOR_D4:
141  case OPERATOR_D5:
142  case OPERATOR_D6:
143  case OPERATOR_D7:
144  case OPERATOR_D8:
145  case OPERATOR_D9:
146  case OPERATOR_D10: {
147  typedef Functor<outputValueViewType,inputPointViewType,vinvViewType,workViewType,
148  OPERATOR_Dn,numPtsPerEval> FunctorType;
149  Kokkos::parallel_for( policy, FunctorType(outputValues, inputPoints, vinv, work,
150  getOperatorOrder(operatorType)) );
151  break;
152  }
153  default: {
154  INTREPID2_TEST_FOR_EXCEPTION( true , std::invalid_argument,
155  ">>> ERROR (Basis_HGRAD_LINE_Cn_FEM): Operator type not implemented" );
156  //break; commented out because this always throws
157  }
158  }
159  }
160  }
161 
162  // -------------------------------------------------------------------------------------
163  template<typename DT, typename OT, typename PT>
165  Basis_HGRAD_LINE_Cn_FEM( const ordinal_type order,
166  const EPointType pointType ) {
167  this->pointType_ = pointType;
168  this->basisCardinality_ = order+1;
169  this->basisDegree_ = order;
170  this->basisCellTopologyKey_ = shards::Line<2>::key;
171  this->basisType_ = BASIS_FEM_LAGRANGIAN;
172  this->basisCoordinates_ = COORDINATES_CARTESIAN;
173  this->functionSpace_ = FUNCTION_SPACE_HGRAD;
174 
175  const ordinal_type card = this->basisCardinality_;
176 
177  // points are computed in the host and will be copied
178  Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
179  dofCoords("Hgrad::Line::Cn::dofCoords", card, 1);
180 
181  //Default is Equispaced
182  auto pointT = (pointType == POINTTYPE_DEFAULT) ? POINTTYPE_EQUISPACED : pointType;
183 
184  switch (pointT) {
185  case POINTTYPE_EQUISPACED:
186  case POINTTYPE_WARPBLEND: {
187  // lattice ordering
188  {
189  shards::CellTopology cellTopo(shards::getCellTopologyData<shards::Line<2>>());
190  const ordinal_type offset = 0;
191  PointTools::getLattice( dofCoords,
192  cellTopo,
193  order, offset,
194  pointT );
195 
196  }
197  break;
198  }
199  default: {
200  INTREPID2_TEST_FOR_EXCEPTION( !isValidPointType(pointT),
201  std::invalid_argument ,
202  ">>> ERROR: (Intrepid2::Basis_HGRAD_LINE_Cn_FEM) invalid pointType." );
203  }
204  }
205 
206  this->dofCoords_ = Kokkos::create_mirror_view(typename DT::memory_space(), dofCoords);
207  Kokkos::deep_copy(this->dofCoords_, dofCoords);
208 
209  // form Vandermonde matrix; actually, this is the transpose of the VDM,
210  // this matrix is used in LAPACK so it should be column major and left layout
211  const ordinal_type lwork = card*card;
212  Kokkos::DynRankView<typename ScalarViewType::value_type,Kokkos::LayoutLeft,Kokkos::HostSpace>
213  vmat("Hgrad::Line::Cn::vmat", card, card),
214  work("Hgrad::Line::Cn::work", lwork),
215  ipiv("Hgrad::Line::Cn::ipiv", card);
216 
217  const double alpha = 0.0, beta = 0.0;
218  Impl::Basis_HGRAD_LINE_Cn_FEM_JACOBI::
219  getValues<Kokkos::HostSpace::execution_space,Parameters::MaxNumPtsPerBasisEval>
220  (typename Kokkos::HostSpace::execution_space{}, vmat, dofCoords, order, alpha, beta, OPERATOR_VALUE);
221 
222  ordinal_type info = 0;
223  Teuchos::LAPACK<ordinal_type,typename ScalarViewType::value_type> lapack;
224 
225  lapack.GETRF(card, card,
226  vmat.data(), vmat.stride_1(),
227  (ordinal_type*)ipiv.data(),
228  &info);
229 
230  INTREPID2_TEST_FOR_EXCEPTION( info != 0,
231  std::runtime_error ,
232  ">>> ERROR: (Intrepid2::Basis_HGRAD_LINE_Cn_FEM) lapack.GETRF returns nonzero info." );
233 
234  lapack.GETRI(card,
235  vmat.data(), vmat.stride_1(),
236  (ordinal_type*)ipiv.data(),
237  work.data(), lwork,
238  &info);
239 
240  INTREPID2_TEST_FOR_EXCEPTION( info != 0,
241  std::runtime_error ,
242  ">>> ERROR: (Intrepid2::Basis_HGRAD_LINE_Cn_FEM) lapack.GETRI returns nonzero info." );
243 
244  // create host mirror
245  Kokkos::DynRankView<typename ScalarViewType::value_type,typename DT::execution_space::array_layout,Kokkos::HostSpace>
246  vinv("Hgrad::Line::Cn::vinv", card, card);
247 
248  for (ordinal_type i=0;i<card;++i)
249  for (ordinal_type j=0;j<card;++j)
250  vinv(i,j) = vmat(j,i);
251 
252  this->vinv_ = Kokkos::create_mirror_view(typename DT::memory_space(), vinv);
253  Kokkos::deep_copy(this->vinv_ , vinv);
254 
255  // initialize tags
256  {
257  // Basis-dependent initializations
258  const ordinal_type tagSize = 4; // size of DoF tag, i.e., number of fields in the tag
259  const ordinal_type posScDim = 0; // position in the tag, counting from 0, of the subcell dim
260  const ordinal_type posScOrd = 1; // position in the tag, counting from 0, of the subcell ordinal
261  const ordinal_type posDfOrd = 2; // position in the tag, counting from 0, of DoF ordinal relative to the subcell
262 
263  // Note: the only reason why equispaced can't support higher order than Parameters::MaxOrder appears to be the fact that the tags below get stored into a fixed-length array.
264  // TODO: relax the maximum order requirement by setting up tags in a different container, perhaps directly into an OrdinalTypeArray1DHost (tagView, below). (As of this writing (1/25/22), looks like other nodal bases do this in a similar way -- those should be fixed at the same time; maybe search for Parameters::MaxOrder.)
265  INTREPID2_TEST_FOR_EXCEPTION( order > Parameters::MaxOrder, std::invalid_argument, "polynomial order exceeds the max supported by this class");
266  ordinal_type tags[Parameters::MaxOrder+1][4];
267 
268  // lattice order
269  {
270  const auto v0 = 0;
271  tags[v0][0] = 0; // vertex dof
272  tags[v0][1] = 0; // vertex id
273  tags[v0][2] = 0; // local dof id
274  tags[v0][3] = 1; // total number of dofs in this vertex
275 
276  const ordinal_type iend = card - 2;
277  for (ordinal_type i=0;i<iend;++i) {
278  const auto e = i + 1;
279  tags[e][0] = 1; // edge dof
280  tags[e][1] = 0; // edge id
281  tags[e][2] = i; // local dof id
282  tags[e][3] = iend; // total number of dofs in this edge
283  }
284 
285  const auto v1 = card -1;
286  tags[v1][0] = 0; // vertex dof
287  tags[v1][1] = 1; // vertex id
288  tags[v1][2] = 0; // local dof id
289  tags[v1][3] = 1; // total number of dofs in this vertex
290  }
291 
292  // topological order
293  // {
294  // tags[0][0] = 0; // vertex dof
295  // tags[0][1] = 0; // vertex id
296  // tags[0][2] = 0; // local dof id
297  // tags[0][3] = 1; // total number of dofs in this vertex
298 
299  // tags[1][0] = 0; // vertex dof
300  // tags[1][1] = 1; // vertex id
301  // tags[1][2] = 0; // local dof id
302  // tags[1][3] = 1; // total number of dofs in this vertex
303 
304  // const ordinal_type iend = card - 2;
305  // for (ordinal_type i=0;i<iend;++i) {
306  // const auto ii = i + 2;
307  // tags[ii][0] = 1; // edge dof
308  // tags[ii][1] = 0; // edge id
309  // tags[ii][2] = i; // local dof id
310  // tags[ii][3] = iend; // total number of dofs in this edge
311  // }
312  // }
313 
314 
315  OrdinalTypeArray1DHost tagView(&tags[0][0], card*4);
316 
317  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
318  // tags are constructed on host
319  this->setOrdinalTagData(this->tagToOrdinal_,
320  this->ordinalToTag_,
321  tagView,
322  this->basisCardinality_,
323  tagSize,
324  posScDim,
325  posScOrd,
326  posDfOrd);
327  }
328  }
329 
330  template<typename DT, typename OT, typename PT>
331  void
333  ordinal_type& perTeamSpaceSize,
334  ordinal_type& perThreadSpaceSize,
335  const PointViewType inputPoints,
336  const EOperator operatorType) const {
337  perTeamSpaceSize = 0;
338  perThreadSpaceSize = this->vinv_.extent(0)*get_dimension_scalar(inputPoints)*sizeof(typename BasisBase::scalarType);
339  }
340 
341  template<typename DT, typename OT, typename PT>
342  KOKKOS_INLINE_FUNCTION
343  void
345  OutputViewType outputValues,
346  const PointViewType inputPoints,
347  const EOperator operatorType,
348  const typename Kokkos::TeamPolicy<typename DT::execution_space>::member_type& team_member,
349  const typename DT::execution_space::scratch_memory_space & scratchStorage,
350  const ordinal_type subcellDim,
351  const ordinal_type subcellOrdinal) const {
352 
353  INTREPID2_TEST_FOR_ABORT( !((subcellDim == -1) && (subcellOrdinal == -1)),
354  ">>> ERROR: (Intrepid2::Basis_HGRAD_LINE_Cn_FEM::getValues), The capability of selecting subsets of basis functions has not been implemented yet.");
355 
356  const int numPoints = inputPoints.extent(0);
357  using ScalarType = typename ScalarTraits<typename PointViewType::value_type>::scalar_type;
358  using WorkViewType = Kokkos::DynRankView< ScalarType,typename DT::execution_space::scratch_memory_space,Kokkos::MemoryTraits<Kokkos::Unmanaged> >;
359  ordinal_type sizePerPoint = this->vinv_.extent(0)*get_dimension_scalar(inputPoints);
360  WorkViewType workView(scratchStorage, sizePerPoint*team_member.team_size());
361  using range_type = Kokkos::pair<ordinal_type,ordinal_type>;
362 
363  switch(operatorType) {
364  case OPERATOR_VALUE:
365  Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=] (ordinal_type& pt) {
366  auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type (pt,pt+1), Kokkos::ALL() );
367  const auto input = Kokkos::subview( inputPoints, range_type(pt, pt+1), Kokkos::ALL() );
368  WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
369  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_VALUE>::getValues( output, input, work, this->vinv_ );
370  });
371  break;
372  case OPERATOR_GRAD:
373  Kokkos::parallel_for (Kokkos::TeamThreadRange (team_member, numPoints), [=] (ordinal_type& pt) {
374  auto output = Kokkos::subview( outputValues, Kokkos::ALL(), range_type(pt,pt+1), Kokkos::ALL() );
375  const auto input = Kokkos::subview( inputPoints, range_type(pt,pt+1), Kokkos::ALL() );
376  WorkViewType work(workView.data() + sizePerPoint*team_member.team_rank(), sizePerPoint);
377  Impl::Basis_HGRAD_LINE_Cn_FEM::Serial<OPERATOR_GRAD>::getValues( output, input, work, this->vinv_ );
378  });
379  break;
380  default: {
381  INTREPID2_TEST_FOR_ABORT( true,
382  ">>> ERROR (Basis_HGRAD_LINE_Cn_FEM): getValues not implemented for this operator");
383  }
384  }
385  }
386 
387 }// namespace Intrepid2
388 
389 #endif
virtual void getValues(const ExecutionSpace &space, OutputViewType outputValues, const PointViewType inputPoints, const EOperator operatorType=OPERATOR_VALUE) const override
Evaluation of a FEM basis on a reference cell.
ScalarTraits< pointValueType >::scalar_type scalarType
Scalar type for point values.
Kokkos::DynRankView< PointValueType, Kokkos::LayoutStride, DeviceType > PointViewType
View type for input points.
static void getLattice(Kokkos::DynRankView< pointValueType, pointProperties...> points, const shards::CellTopology cellType, const ordinal_type order, const ordinal_type offset=0, const EPointType pointType=POINTTYPE_EQUISPACED)
Computes a lattice of points of a given order on a reference simplex, quadrilateral or hexahedron (cu...
Basis_HGRAD_LINE_Cn_FEM(const ordinal_type order, const EPointType pointType=POINTTYPE_EQUISPACED)
Constructor.
static constexpr ordinal_type MaxOrder
The maximum reconstruction order.
Kokkos::View< ordinal_type *, typename ExecutionSpace::array_layout, Kokkos::HostSpace > OrdinalTypeArray1DHost
View type for 1d host array.
virtual void getScratchSpaceSize(ordinal_type &perTeamSpaceSize, ordinal_type &perThreadSpaceSize, const PointViewType inputPointsconst, const EOperator operatorType=OPERATOR_VALUE) const override
Return the size of the scratch space, in bytes, needed for using the team-level implementation of get...