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
34namespace Intrepid2 {
35
36namespace Impl {
37
38namespace Debug {
39
40#ifdef HAVE_INTREPID2_DEBUG
41template<typename subcellBasisType,
42typename cellBasisType>
43inline
44void
45check_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
136template<typename OutputViewType,
137typename subcellBasisHostType,
138typename cellBasisHostType>
139inline
140void
142getCoeffMatrix_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
KOKKOS_FORCEINLINE_FUNCTION constexpr std::enable_if<!(std::is_standard_layout< T >::value &&std::is_trivial< T >::value), typenameScalarTraits< T >::scalar_type >::type get_scalar_value(const T &obj)
functions returning the scalar value. for pod types, they return the input object itself....
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 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 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...
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 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...