Intrepid2
Intrepid2_OrientationToolsDefCoeffMatrix_HDIV.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 
10 
26 #ifndef __INTREPID2_ORIENTATIONTOOLS_DEF_COEFF_MATRIX_HDIV_HPP__
27 #define __INTREPID2_ORIENTATIONTOOLS_DEF_COEFF_MATRIX_HDIV_HPP__
28 
29 // disable clang warnings
30 #if defined (__clang__) && !defined (__INTEL_COMPILER)
31 #pragma clang system_header
32 #endif
33 
34 namespace Intrepid2 {
35 
36 namespace Impl {
37 
38 namespace Debug {
39 
40 #ifdef HAVE_INTREPID2_DEBUG
41 template<typename subcellBasisType,
42 typename cellBasisType>
43 inline
44 void
45 check_getCoeffMatrix_HDIV(const subcellBasisType& subcellBasis,
46  const cellBasisType& cellBasis,
47  const ordinal_type subcellId,
48  const ordinal_type subcellOrt) {
49  const shards::CellTopology cellTopo = cellBasis.getBaseCellTopology();
50  const shards::CellTopology subcellTopo = subcellBasis.getBaseCellTopology();
51 
52  const ordinal_type cellDim = cellTopo.getDimension();
53  const ordinal_type subcellDim = subcellTopo.getDimension();
54 
55  INTREPID2_TEST_FOR_EXCEPTION( subcellDim >= cellDim,
56  std::logic_error,
57  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_HDIV): " \
58  "cellDim must be greater than subcellDim.");
59 
60  const auto subcellBaseKey = subcellTopo.getBaseKey();
61  const auto cellBaseKey = cellTopo.getBaseKey();
62 
63  INTREPID2_TEST_FOR_EXCEPTION( subcellBaseKey != shards::Line<>::key &&
64  subcellBaseKey != shards::Quadrilateral<>::key &&
65  subcellBaseKey != shards::Triangle<>::key,
66  std::logic_error,
67  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_HDIV): " \
68  "subcellBasis must have line, quad, or triangle topology.");
69 
70  INTREPID2_TEST_FOR_EXCEPTION( cellBaseKey != shards::Quadrilateral<>::key &&
71  cellBaseKey != shards::Triangle<>::key &&
72  cellBaseKey != shards::Hexahedron<>::key &&
73  cellBaseKey != shards::Wedge<>::key &&
74  cellBaseKey != shards::Tetrahedron<>::key &&
75  cellBaseKey != shards::Pyramid<>::key,
76  std::logic_error,
77  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_HDIV): " \
78  "cellBasis must have quad, triangle, hexhedron or tetrahedron topology.");
79 
80  //
81  // Function space
82  //
83  {
84  const bool isHDIV = cellBasis.getFunctionSpace() == FUNCTION_SPACE_HDIV;
85  INTREPID2_TEST_FOR_EXCEPTION( !isHDIV,
86  std::logic_error,
87  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_HDIV): "
88  "cellBasis is not HDIV.");
89  {
90  const bool subcellBasisIsHGRAD = subcellBasis.getFunctionSpace() == FUNCTION_SPACE_HGRAD;
91  const bool subcellBasisIsHVOL = subcellBasis.getFunctionSpace() == FUNCTION_SPACE_HVOL;
92  const bool cellIsTri = cellBaseKey == shards::Triangle<>::key;
93  const bool cellIsTet = cellBaseKey == shards::Tetrahedron<>::key;
94  const bool cellIsHex = cellBaseKey == shards::Hexahedron<>::key;
95  const bool cellIsQuad = cellBaseKey == shards::Quadrilateral<>::key;
96 
97  switch (subcellDim) {
98  case 1: {
99  //TODO: Hex, QUAD, TET and TRI element should have the same 1d basis
100  if (cellIsHex || cellIsQuad) {
101  INTREPID2_TEST_FOR_EXCEPTION( !(subcellBasisIsHGRAD||subcellBasisIsHVOL),
102  std::logic_error,
103  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_DIV): "
104  "subcellBasis function space (1d) is not consistent to cellBasis, which should be open line hgrad, order -1.");
105  } else if (cellIsTet || cellIsTri) {
106  INTREPID2_TEST_FOR_EXCEPTION( !subcellBasisIsHVOL,
107  std::logic_error,
108  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_DIV): "
109  "subcellBasis function space (1d) is not consistent to cellBasis, which should be HVOL line, order -1.");
110  }
111  break;
112  }
113  case 2: {
114  if (subcellBaseKey == shards::Quadrilateral<>::key) {
115  // quad face basis is tensor product of open line basis functions
116  INTREPID2_TEST_FOR_EXCEPTION( !(subcellBasisIsHGRAD||subcellBasisIsHVOL),
117  std::logic_error,
118  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_HDIV): "
119  "subcellBasis function space is not compatible, which should be open line hgrad, order -1.");
120  } else if (subcellBaseKey == shards::Triangle<>::key) {
121  // triangle face basis comes from HVOL basis
122  INTREPID2_TEST_FOR_EXCEPTION( !subcellBasisIsHVOL,
123  std::logic_error,
124  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_HDIV): "
125  "subcellBasis function space is not compatible, which should HVOL, order-1.");
126  }
127  break;
128  }
129  }
130  }
131  }
132 }
133 #endif
134 } //Debug Namespace
135 
136 template<typename OutputViewType,
137 typename subcellBasisHostType,
138 typename cellBasisHostType>
139 inline
140 void
142 getCoeffMatrix_HDIV(OutputViewType &output,
143  const subcellBasisHostType& subcellBasis,
144  const cellBasisHostType& cellBasis,
145  const ordinal_type subcellId,
146  const ordinal_type subcellOrt,
147  const bool inverse) {
148 
149 #ifdef HAVE_INTREPID2_DEBUG
150  Debug::check_getCoeffMatrix_HDIV(subcellBasis,cellBasis,subcellId,subcellOrt);
151 #endif
152 
153  using value_type = typename OutputViewType::non_const_value_type;
154  using host_device_type = Kokkos::HostSpace::device_type;
155 
156  //
157  // Collocation points
158  //
159  const shards::CellTopology cellTopo = cellBasis.getBaseCellTopology();
160  const shards::CellTopology subcellTopo = subcellBasis.getBaseCellTopology();
161  const ordinal_type cellDim = cellTopo.getDimension();
162  const ordinal_type subcellDim = subcellTopo.getDimension();
163  const auto subcellBaseKey = subcellTopo.getBaseKey();
164  const ordinal_type numCellBasis = cellBasis.getCardinality();
165  const ordinal_type numSubcellBasis = subcellBasis.getCardinality();
166  const ordinal_type ndofSubcell = cellBasis.getDofCount(subcellDim,subcellId);
167 
168  //
169  // Reference points
170  //
171 
172  //use lattice to compute reference subcell points \xi_j
173  auto latticeDegree = (subcellBaseKey == shards::Triangle<>::key) ?
174  cellBasis.getDegree()+2 : cellBasis.getDegree()+1;
175 
176  // Reference points \xi_j on the subcell
177  Kokkos::DynRankView<value_type,host_device_type> refPtsSubcell("refPtsSubcell", ndofSubcell, subcellDim);
178  auto latticeSize=PointTools::getLatticeSize(subcellTopo, latticeDegree, 1);
179  INTREPID2_TEST_FOR_EXCEPTION( latticeSize != ndofSubcell,
180  std::logic_error,
181  ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_HDIV): " \
182  "Lattice size should be equal to the onber of subcell internal DoFs");
183  PointTools::getLattice(refPtsSubcell, subcellTopo, latticeDegree, 1);//, POINTTYPE_WARPBLEND);
184 
185  // evaluate values on the modified cell
186  auto subcellParam = Intrepid2::RefSubcellParametrization<host_device_type>::get(subcellDim, cellTopo.getKey());
187 
188  // refPtsCell = F_s (\eta_o (refPtsSubcell))
189  Kokkos::DynRankView<value_type,host_device_type> refPtsCell("refPtsCell", ndofSubcell, cellDim);
190  // map points from the subcell manifold into the cell one
191  mapSubcellCoordsToRefCell(refPtsCell,refPtsSubcell, subcellParam, subcellBaseKey, subcellId, subcellOrt);
192 
193  //computing normal to the subcell accounting for orientation
194  Kokkos::DynRankView<value_type,host_device_type> tangentsAndNormal("trJacobianF", cellDim, cellDim );
195  OrientationTools::getRefSideTangentsAndNormal(tangentsAndNormal, subcellParam, subcellBaseKey, subcellId, subcellOrt);
196  auto sideNormal = Kokkos::subview(tangentsAndNormal, cellDim-1, Kokkos::ALL());
197 
198 
199  //
200  // Basis evaluation on the collocation points
201  //
202 
203  // cellBasisValues = \psi_k(F_s (\eta_o (\xi_j)))
204  Kokkos::DynRankView<value_type,host_device_type> cellBasisValues("cellBasisValues", numCellBasis, ndofSubcell, cellDim);
205  cellBasis.getValues(cellBasisValues, refPtsCell, OPERATOR_VALUE);
206 
207  // subcellBasisValues = \phi_i (\xi_j)
208  Kokkos::DynRankView<value_type,host_device_type> subCellValues("subCellValues", numSubcellBasis, ndofSubcell);
209  subcellBasis.getValues(subCellValues, refPtsSubcell, OPERATOR_VALUE);
210 
211  //
212  // Compute Psi_jk = \psi_k(F_s (\eta_o (\xi_j))) \cdot (n_s det(J_\eta))
213  // and Phi_ji = \phi_i (\xi_j), and solve
214  // Psi A^T = Phi
215  //
216 
217  // construct Psi and Phi matrices. LAPACK wants left layout
218  Kokkos::DynRankView<value_type,Kokkos::LayoutLeft,host_device_type>
219  PsiMat("PsiMat", ndofSubcell, ndofSubcell),
220  PhiMat("PhiMat", ndofSubcell, ndofSubcell),
221  RefMat,
222  OrtMat;
223 
224  auto cellTagToOrdinal = cellBasis.getAllDofOrdinal();
225  auto subcellTagToOrdinal = subcellBasis.getAllDofOrdinal();
226 
227  for (ordinal_type i=0;i<ndofSubcell;++i) {
228  const ordinal_type ic = cellTagToOrdinal(subcellDim, subcellId, i);
229  const ordinal_type isc = subcellTagToOrdinal(subcellDim, 0, i);
230  for (ordinal_type j=0;j<ndofSubcell;++j) {
231  PhiMat(j,i) = get_scalar_value(subCellValues(isc,j));
232  for (ordinal_type k=0;k<cellDim;++k)
233  PsiMat(j,i) += get_scalar_value(cellBasisValues(ic,j,k))*sideNormal(k);
234  }
235  }
236 
237  RefMat = inverse ? PhiMat : PsiMat;
238  OrtMat = inverse ? PsiMat : PhiMat;
239 
240  // solve the system
241  {
242  Teuchos::LAPACK<ordinal_type,value_type> lapack;
243  ordinal_type info = 0;
244  Kokkos::DynRankView<ordinal_type,host_device_type> pivVec("pivVec", ndofSubcell);
245 
246  lapack.GESV(ndofSubcell, ndofSubcell,
247  RefMat.data(),
248  RefMat.stride_1(),
249  pivVec.data(),
250  OrtMat.data(),
251  OrtMat.stride_1(),
252  &info);
253 
254  if (info) {
255  std::stringstream ss;
256  ss << ">>> ERROR (Intrepid::OrientationTools::getCoeffMatrix_HDIV): "
257  << "LAPACK return with error code: "
258  << info;
259  INTREPID2_TEST_FOR_EXCEPTION( true, std::runtime_error, ss.str().c_str() );
260  }
261 
262  //After solving the system w/ LAPACK, Phi contains A^T
263 
264  // transpose and clean up numerical noise (for permutation matrices)
265  const double eps = tolerence();
266  for (ordinal_type i=0;i<ndofSubcell;++i) {
267  auto intmatii = std::round(OrtMat(i,i));
268  OrtMat(i,i) = (std::abs(OrtMat(i,i) - intmatii) < eps) ? intmatii : OrtMat(i,i);
269  for (ordinal_type j=i+1;j<ndofSubcell;++j) {
270  auto matij = OrtMat(i,j);
271 
272  auto intmatji = std::round(OrtMat(j,i));
273  OrtMat(i,j) = (std::abs(OrtMat(j,i) - intmatji) < eps) ? intmatji : OrtMat(j,i);
274 
275  auto intmatij = std::round(matij);
276  OrtMat(j,i) = (std::abs(matij - intmatij) < eps) ? intmatij : matij;
277  }
278  }
279 
280  // Print Matrix A
281  /*
282  {
283  std::cout << "|";
284  for (ordinal_type i=0;i<ndofSubcell;++i) {
285  for (ordinal_type j=0;j<ndofSubcell;++j) {
286  std::cout << OrtMat(i,j) << " ";
287  }
288  std::cout << "| ";
289  }
290  std::cout <<std::endl;
291  }
292  */
293 
294  }
295 
296  {
297  // move the data to original device memory
298  const Kokkos::pair<ordinal_type,ordinal_type> range(0, ndofSubcell);
299  auto suboutput = Kokkos::subview(output, range, range);
300  auto tmp = Kokkos::create_mirror_view_and_copy(typename OutputViewType::device_type::memory_space(), OrtMat);
301  Kokkos::deep_copy(suboutput, tmp);
302  }
303 }
304 }
305 
306 }
307 #endif
static KOKKOS_INLINE_FUNCTION void mapSubcellCoordsToRefCell(coordsViewType cellCoords, const subcellCoordsViewType subCellCoords, const ParamViewType subcellParametrization, const unsigned subcellTopoKey, const ordinal_type subCellOrd, const ordinal_type ort)
Maps points defined on the subCell manifold into the parent Cell accounting for orientation.
static ConstViewType get(const ordinal_type subcellDim, const unsigned parentCellKey)
Returns a Kokkos view with the coefficients of the parametrization maps for the edges or faces of a r...
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...
static void getCoeffMatrix_HDIV(OutputViewType &output, const subcellBasisHostType &subcellBasis, const cellBasisHostType &cellBasis, const ordinal_type subcellId, const ordinal_type subcellOrt, const bool inverse=false)
Compute orientation matrix for HDIV basis for a given subcell and its reference basis.
static KOKKOS_INLINE_FUNCTION void getRefSideTangentsAndNormal(TanNormViewType tangentsAndNormal, const ParamViewType subCellParametrization, const unsigned subcellTopoKey, const ordinal_type subCellOrd, const ordinal_type ort)
Computes the (oriented) tangents and normal of the side subCell The normals are only defined for side...
static ordinal_type getLatticeSize(const shards::CellTopology cellType, const ordinal_type order, const ordinal_type offset=0)
Computes the number of points in a lattice of a given order on a simplex (currently disabled for othe...