Intrepid2
Intrepid2_OrientationToolsDefMatrixData.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
15#ifndef __INTREPID2_ORIENTATIONTOOLS_DEF_MATRIX_DATA_HPP__
16#define __INTREPID2_ORIENTATIONTOOLS_DEF_MATRIX_DATA_HPP__
17
18// disable clang warnings
19#if defined (__clang__) && !defined (__INTEL_COMPILER)
20#pragma clang system_header
21#endif
22
23namespace Intrepid2 {
24
25 template<typename DT>
26 template<typename BasisHostType>
28 OrientationTools<DT>::createCoeffMatrixInternal(const BasisHostType* basis, const bool inverse) {
29 const std::string name(basis->getName());
30 CoeffMatrixDataViewType matData;
31
32 const auto cellTopo = basis->getBaseCellTopology();
33 const ordinal_type numEdges = cellTopo.getSubcellCount(1);
34 const ordinal_type numFaces = cellTopo.getSubcellCount(2);
35 ordinal_type matDim = 0, matDim1 = 0, matDim2 = 0, numOrts = 0, numSubCells;
36 for(ordinal_type i=0; i<numEdges; ++i) {
37 matDim1 = std::max(matDim1, basis->getDofCount(1,i));
38 numOrts = std::max(numOrts,2);
39 }
40 for(ordinal_type i=0; i<numFaces; ++i) {
41 matDim2 = std::max(matDim2, basis->getDofCount(2,i));
42 numOrts = std::max(numOrts,2*ordinal_type(cellTopo.getSideCount(2,i)));
43 }
44 matDim = std::max(matDim1,matDim2);
45 numSubCells = (matDim1>0)*numEdges + (matDim2>0)*numFaces;
46
47
48 matData = CoeffMatrixDataViewType("Orientation::CoeffMatrix::"+name,
49 numSubCells,
50 numOrts,
51 matDim,
52 matDim);
53
54 if(basis->getFunctionSpace() == FUNCTION_SPACE_HGRAD) {
55 init_HGRAD(matData, basis, inverse);
56 } else if (basis->getFunctionSpace() == FUNCTION_SPACE_HCURL) {
57 init_HCURL(matData, basis, inverse);
58 } else if (basis->getFunctionSpace() == FUNCTION_SPACE_HDIV) {
59 init_HDIV(matData, basis, inverse);
60 } else if (basis->getFunctionSpace() == FUNCTION_SPACE_HVOL) {
61 init_HVOL(matData, basis, inverse);
62 }
63 return matData;
64 }
65
66 template<typename DT>
67 template<typename BasisHostType>
69 OrientationTools<DT>::createEdgeOperatorsInternal(const BasisHostType* basis, CoeffMatrixDataViewType matData)
70 {
71 const int EDGE_DIM = 1;
72 const int FACE_DIM = 2;
73
74 const std::string name(basis->getName());
75 OperatorViewType operators;
76
77 auto matDataHost = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), matData);
78
79 ordinal_type matDim1 = 0, matDim2 = 0, numOrts = 0, numEdgeOrts = 0;
80 const auto cellTopo = basis->getBaseCellTopology();
81 {
82 const ordinal_type numEdges = cellTopo.getSubcellCount(EDGE_DIM);
83 const ordinal_type numFaces = cellTopo.getSubcellCount(FACE_DIM);
84 for(ordinal_type i=0; i<numEdges; ++i) {
85 matDim1 = std::max(matDim1, basis->getDofCount(EDGE_DIM,i));
86 numEdgeOrts = std::max(numOrts,2);
87 numOrts = numEdgeOrts;
88 }
89 for(ordinal_type i=0; i<numFaces; ++i) {
90 matDim2 = std::max(matDim2, basis->getDofCount(2,i));
91 numOrts = std::max(numOrts,2*ordinal_type(cellTopo.getSideCount(FACE_DIM,i)));
92 }
93
94 operators = OperatorViewType("Orientation::EdgeOperators::"+name,
95 numEdges, numOrts, 2);
96 }
97
98 // NOTE: the OrientationOperators within operatorsHost contain raw device pointers.
99 auto operatorsHost = Kokkos::create_mirror_view(operators);
100
101 // Initialize all entries to identity. Kokkos::View allocation does not guarantee
102 // that each OrientationOperator object has been semantically initialized, and
103 // uninitialized pointer/extent fields can cause non-UVM CUDA failures.
104 for (ordinal_type subcellOrdinal=0; subcellOrdinal<static_cast<ordinal_type>(operatorsHost.extent(0)); ++subcellOrdinal)
105 {
106 for (ordinal_type ortOrdinal=0; ortOrdinal<static_cast<ordinal_type>(operatorsHost.extent(1)); ++ortOrdinal)
107 {
108 for (ordinal_type transposeInt=0; transposeInt<static_cast<ordinal_type>(operatorsHost.extent(2)); ++transposeInt)
109 {
110 operatorsHost(subcellOrdinal, ortOrdinal, transposeInt) = OrientationOperator<DT>();
111 }
112 }
113 }
114
115 if (matDim1 == 0)
116 {
117 // no non-trivial edge operators (no edge dofs)
118 Kokkos::deep_copy(operators, operatorsHost);
119 return operators;
120 }
121
122 {
123 auto ordinalToTag = basis->getAllDofTags();
124 auto tagToOrdinal = basis->getAllDofOrdinal();
125
126 const ordinal_type numEdges = cellTopo.getSubcellCount(1);
127
128 if (numEdges > 0)
129 {
130 for (ordinal_type edgeId=0;edgeId<numEdges;++edgeId)
131 {
132 for (ordinal_type edgeOrt=0; edgeOrt<numEdgeOrts; edgeOrt++)
133 {
134 std::vector<ordinal_type> nonIdentityDofs;
135 std::vector<ordinal_type> rowOffsets; // within the column storage
136 std::vector<ordinal_type> colIDs;
137 std::vector<double> weights;
138
139 const ordinal_type ordEdge = (1 < tagToOrdinal.extent(0) ? (static_cast<size_type>(edgeId) < tagToOrdinal.extent(1) ? tagToOrdinal(EDGE_DIM, edgeId, 0) : -1) : -1);
140
141 ordinal_type rowOffset = 0;
142 if (ordEdge != -1) {
143 const ordinal_type ndofEdge = ordinalToTag(ordEdge, 3);
144 const auto mat = Kokkos::subview(matDataHost,
145 edgeId, edgeOrt,
146 Kokkos::ALL(), Kokkos::ALL());
147
148 for (ordinal_type i=0;i<ndofEdge;++i) {
149 const ordinal_type ii = tagToOrdinal(EDGE_DIM, edgeId, i);
150
151 // first pass for ii:
152 // check whether this is different from the identity
153 // count number of nonzeros in this row
154 int nnz = 0;
155 bool deviatesFromIdentity = false;
156 for (ordinal_type l=0;l<ndofEdge;++l) {
157 const ordinal_type ll = tagToOrdinal(EDGE_DIM, edgeId, l);
158 auto & mat_il = mat(i,l);
159 if (mat_il != 0.0)
160 {
161 nnz++;
162 if ((mat_il != 1.0) || (ii != ll))
163 {
164 deviatesFromIdentity = true;
165 }
166 }
167 else if (ii == ll)
168 {
169 // zero entry on the diagonal is also a deviation from the identity
170 deviatesFromIdentity = true;
171 }
172 } // column
173 INTREPID2_TEST_FOR_EXCEPTION(nnz == 0, std::invalid_argument, "Each dof should have *some* nonzero weight");
174 if (deviatesFromIdentity)
175 {
176 // then we store the nonzeros for ii
177 nonIdentityDofs.push_back(ii);
178 rowOffsets.push_back(rowOffset);
179 rowOffset += nnz;
180
181 for (ordinal_type l=0;l<ndofEdge;++l)
182 {
183 const ordinal_type ll = tagToOrdinal(EDGE_DIM, edgeId, l);
184 auto & mat_il = mat(i,l);
185 if (mat_il != 0.0)
186 {
187 colIDs.push_back(ll);
188 weights.push_back(mat_il);
189 }
190 }
191 }
192 } // row
193 rowOffsets.push_back(rowOffset);
194 }
195
196 std::vector<bool> transposeVector {false, true};
197 for (const bool transpose : transposeVector)
198 {
199 ordinal_type transposeInt = transpose ? 1 : 0;
200 OrientationOperator<DT> orientationOperator = constructOrientationOperatorInternal(nonIdentityDofs, rowOffsets, colIDs, weights, transpose);
201 operatorsHost(edgeId, edgeOrt, transposeInt) = orientationOperator;
202 }
203 }
204 }
205 }
206 }
207
208 Kokkos::deep_copy(operators, operatorsHost);
209
210 return operators;
211 }
212
213 template<typename DT>
214 template<typename BasisHostType>
216 OrientationTools<DT>::createFaceOperatorsInternal(const BasisHostType* basis, CoeffMatrixDataViewType matData)
217 {
218 const int EDGE_DIM = 1;
219 const int FACE_DIM = 2;
220
221 const std::string name(basis->getName());
222 OperatorViewType operators;
223
224 auto matDataHost = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), matData);
225
226 ordinal_type matDim1 = 0, matDim2 = 0, numOrts = 0, numEdgeOrts = 0, maxFaceOrts = 0;
227 const auto cellTopo = basis->getBaseCellTopology();
228 {
229 const ordinal_type numEdges = cellTopo.getSubcellCount(EDGE_DIM);
230 const ordinal_type numFaces = cellTopo.getSubcellCount(FACE_DIM);
231 for(ordinal_type i=0; i<numEdges; ++i) {
232 matDim1 = std::max(matDim1, basis->getDofCount(EDGE_DIM,i));
233 numEdgeOrts = std::max(numOrts,2);
234 numOrts = numEdgeOrts;
235 }
236 for(ordinal_type i=0; i<numFaces; ++i) {
237 matDim2 = std::max(matDim2, basis->getDofCount(FACE_DIM,i));
238 const ordinal_type faceEdgeCount = static_cast<ordinal_type>(cellTopo.getSideCount(FACE_DIM,i));
239 maxFaceOrts = std::max(maxFaceOrts,2*faceEdgeCount);
240 // 2*(#face edges): a formula that happens to work for triangles and quads: 6 triangle orientations, 8 quad orientations.
241 numOrts = std::max(numOrts,maxFaceOrts);
242
243 }
244
245 operators = OperatorViewType("Orientation::FaceOperators::"+name,
246 numFaces, numOrts, 2);
247 }
248
249 // NOTE: the OrientationOperators within operatorsHost contain raw device pointers.
250 auto operatorsHost = Kokkos::create_mirror_view(operators);
251
252 // Initialize all entries to identity. Kokkos::View allocation does not guarantee
253 // that each OrientationOperator object has been semantically initialized, and
254 // uninitialized pointer/extent fields can cause non-UVM CUDA failures.
255 for (ordinal_type subcellOrdinal=0; subcellOrdinal<static_cast<ordinal_type>(operatorsHost.extent(0)); ++subcellOrdinal)
256 {
257 for (ordinal_type ortOrdinal=0; ortOrdinal<static_cast<ordinal_type>(operatorsHost.extent(1)); ++ortOrdinal)
258 {
259 for (ordinal_type transposeInt=0; transposeInt<static_cast<ordinal_type>(operatorsHost.extent(2)); ++transposeInt)
260 {
261 operatorsHost(subcellOrdinal, ortOrdinal, transposeInt) = OrientationOperator<DT>();
262 }
263 }
264 }
265
266 if (matDim2 == 0)
267 {
268 // no non-trivial face operators (no face dofs)
269 Kokkos::deep_copy(operators, operatorsHost);
270 return operators;
271 }
272
273 // determine if there are edge dofs
274 ordinal_type existEdgeDofs = (matDim1 > 0) ? 1 : 0;
275
276 if ((basis->getFunctionSpace() != FUNCTION_SPACE_HDIV) || (cellTopo.getDimension() == 3)) // no face orientations for H(div) except in 3D
277 {
278 auto ordinalToTag = basis->getAllDofTags();
279 auto tagToOrdinal = basis->getAllDofOrdinal();
280
281 const ordinal_type numEdges = cellTopo.getSubcellCount(1);
282 const ordinal_type numFaces = cellTopo.getSubcellCount(2);
283
284 if (numFaces > 0)
285 {
286 for (ordinal_type faceId=0;faceId<numFaces;++faceId)
287 {
288 const ordinal_type ordFace = (2 < tagToOrdinal.extent(0) ? (static_cast<size_type>(faceId) < tagToOrdinal.extent(1) ? tagToOrdinal(FACE_DIM, faceId, 0) : -1) : -1);
289
290 const ordinal_type numFaceOrts = 2*ordinal_type(cellTopo.getSideCount(FACE_DIM,faceId));
291 // 2*(#face edges): a formula that happens to work for triangles and quads: 6 triangle orientations, 8 quad orientations.
292 for (ordinal_type faceOrt=0; faceOrt<numFaceOrts; faceOrt++)
293 {
294 std::vector<ordinal_type> nonIdentityDofs;
295 std::vector<ordinal_type> rowOffsets; // within the column storage
296 std::vector<ordinal_type> colIDs;
297 std::vector<double> weights;
298
299 ordinal_type rowOffset = 0;
300
301 if (ordFace != -1) {
302 const ordinal_type ndofFace = ordinalToTag(ordFace, 3);
303 const auto mat = Kokkos::subview(matDataHost,
304 numEdges*existEdgeDofs+faceId, faceOrt,
305 Kokkos::ALL(), Kokkos::ALL());
306 for (ordinal_type i=0;i<ndofFace;++i) {
307
308 const ordinal_type ii = tagToOrdinal(FACE_DIM, faceId, i);
309
310 // first pass for ii:
311 // check whether this is different from the identity
312 // count number of nonzeros
313 int nnz = 0;
314 bool deviatesFromIdentity = false;
315 for (ordinal_type l=0;l<ndofFace;++l) {
316 const ordinal_type ll = tagToOrdinal(FACE_DIM, faceId, l);
317 auto & mat_il = mat(i,l);
318 if (mat_il != 0.0)
319 {
320 nnz++;
321 if ((mat_il != 1.0) || (ii != ll))
322 {
323 deviatesFromIdentity = true;
324 }
325 }
326 else if (ii == ll)
327 {
328 // zero entry on the diagonal is also a deviation from the identity
329 deviatesFromIdentity = true;
330 }
331 } // column
332 INTREPID2_TEST_FOR_EXCEPTION(nnz == 0, std::invalid_argument, "Each dof should have *some* nonzero weight");
333 if (deviatesFromIdentity)
334 {
335 // then we store the nonzeros for ii
336 nonIdentityDofs.push_back(ii);
337 rowOffsets.push_back(rowOffset);
338 rowOffset += nnz;
339
340 for (ordinal_type l=0;l<ndofFace;++l)
341 {
342 const ordinal_type ll = tagToOrdinal(FACE_DIM, faceId, l);
343 auto & mat_il = mat(i,l);
344 if (mat_il != 0.0)
345 {
346 colIDs.push_back(ll);
347 weights.push_back(mat_il);
348 }
349 }
350 } // if (deviatesFromIdentity)
351 } // row
352 rowOffsets.push_back(rowOffset);
353 std::vector<bool> transposeVector {false, true};
354 for (const bool transpose : transposeVector)
355 {
356 ordinal_type transposeInt = transpose ? 1 : 0;
357 OrientationOperator<DT> orientationOperator = constructOrientationOperatorInternal(nonIdentityDofs, rowOffsets, colIDs, weights, transpose);
358 operatorsHost(faceId, faceOrt, transposeInt) = orientationOperator;
359 }
360 } // if (ordFace != -1)
361 }
362 }
363 }
364 }
365
366 Kokkos::deep_copy(operators, operatorsHost);
367
368 return operators;
369 }
370
371 //
372 // HGRAD elements
373 //
374 template<typename DT>
375 template<typename BasisHostType>
376 void
379 BasisHostType const *cellBasis,
380 const bool inverse) {
381
382 const auto cellTopo = cellBasis->getBaseCellTopology();
383 const ordinal_type numEdges = cellTopo.getSubcellCount(1);
384 const ordinal_type numFaces = cellTopo.getSubcellCount(2);
385 Intrepid2::BasisPtr<typename BasisHostType::DeviceType,
386 typename BasisHostType::OutputValueType,
387 typename BasisHostType::PointValueType>
388 basisPtr;
389 BasisHostType const *subcellBasis;
390
391 { //edges
392 subcellBasis = cellBasis; // if (dim==1)
393 const ordinal_type numOrt = 2;
394 for (ordinal_type edgeId=0;edgeId<numEdges;++edgeId) {
395 if(cellBasis->getDofCount(1, edgeId) < 1) continue;
396 if(cellTopo.getDimension()!=1) {
397 basisPtr = cellBasis->getSubCellRefBasis(1,edgeId);
398 subcellBasis = basisPtr.get();
399 }
400
401 for (ordinal_type edgeOrt=0;edgeOrt<numOrt;++edgeOrt) {
402 auto mat = Kokkos::subview(matData,
403 edgeId, edgeOrt,
404 Kokkos::ALL(), Kokkos::ALL());
406 (mat,
407 *subcellBasis, *cellBasis,
408 edgeId, edgeOrt, inverse);
409 }
410 }
411 }
412 { //faces
413 subcellBasis = cellBasis; // if(dim==2)
414 for (ordinal_type faceId=0;faceId<numFaces;++faceId) {
415 // this works for triangles (numOrt=6) and quadrilaterals (numOrt=8)
416 const ordinal_type numOrt = 2*cellTopo.getSideCount(2,faceId);
417 if(cellBasis->getDofCount(2, faceId) < 1) continue;
418 if(cellTopo.getDimension()!=2) {
419 basisPtr = cellBasis->getSubCellRefBasis(2,faceId);
420 subcellBasis = basisPtr.get();
421 }
422 for (ordinal_type faceOrt=0;faceOrt<numOrt;++faceOrt) {
423 auto mat = Kokkos::subview(matData,
424 numEdges+faceId, faceOrt,
425 Kokkos::ALL(), Kokkos::ALL());
427 (mat,
428 *subcellBasis, *cellBasis,
429 faceId, faceOrt, inverse);
430 }
431 }
432 }
433 }
434
435 //
436 // HCURL elements
437 //
438 template<typename DT>
439 template<typename BasisHostType>
440 void
443 BasisHostType const *cellBasis, const bool inverse) {
444 const auto cellTopo = cellBasis->getBaseCellTopology();
445 const ordinal_type numEdges = cellTopo.getSubcellCount(1);
446 const ordinal_type numFaces = cellTopo.getSubcellCount(2);
447 Intrepid2::BasisPtr<typename BasisHostType::DeviceType,
448 typename BasisHostType::OutputValueType,
449 typename BasisHostType::PointValueType>
450 basisPtr;
451 BasisHostType const* subcellBasis;
452
453 { // edges
454 subcellBasis = cellBasis; // if (dim==1)
455 const ordinal_type numOrt = 2;
456 for (ordinal_type edgeId=0;edgeId<numEdges;++edgeId) {
457 if(cellBasis->getDofCount(1, edgeId) < 1) continue;
458 if(cellTopo.getDimension()!=1) {
459 basisPtr = cellBasis->getSubCellRefBasis(1,edgeId);
460 subcellBasis = basisPtr.get();
461 }
462 for (ordinal_type edgeOrt=0;edgeOrt<numOrt;++edgeOrt) {
463 auto mat = Kokkos::subview(matData,
464 edgeId, edgeOrt,
465 Kokkos::ALL(), Kokkos::ALL());
467 *subcellBasis, *cellBasis,
468 edgeId, edgeOrt, inverse);
469 }
470 }
471 }
472 { //faces
473 subcellBasis = cellBasis; // if (dim==2)
474 for (ordinal_type faceId=0;faceId<numFaces;++faceId) {
475 // this works for triangles (numOrt=6) and quadrilaterals (numOrt=8)
476 const ordinal_type numOrt = 2*cellTopo.getSideCount(2,faceId);
477 if(cellBasis->getDofCount(2, faceId) < 1) continue;
478 if(cellTopo.getDimension()!=2) {
479 basisPtr = cellBasis->getSubCellRefBasis(2,faceId);
480 subcellBasis = basisPtr.get();
481 }
482 for (ordinal_type faceOrt=0;faceOrt<numOrt;++faceOrt) {
483 auto mat = Kokkos::subview(matData,
484 numEdges+faceId, faceOrt,
485 Kokkos::ALL(), Kokkos::ALL());
487 (mat,
488 *subcellBasis, *cellBasis,
489 faceId, faceOrt, inverse);
490 }
491 }
492 }
493 }
494
495 //
496 // HDIV elements
497 //
498 template<typename DT>
499 template<typename BasisHostType>
500 void
503 BasisHostType const *cellBasis, const bool inverse) {
504 const auto cellTopo = cellBasis->getBaseCellTopology();
505 const ordinal_type numSides = cellTopo.getSideCount();
506 const ordinal_type sideDim = cellTopo.getDimension()-1;
507 Intrepid2::BasisPtr<typename BasisHostType::DeviceType,
508 typename BasisHostType::OutputValueType,
509 typename BasisHostType::PointValueType>
510 subcellBasisPtr;
511
512 {
513 for (ordinal_type sideId=0;sideId<numSides;++sideId) {
514 if(cellBasis->getDofCount(sideDim, sideId) < 1) continue;
515 const ordinal_type numOrt = (sideDim == 1) ? 2 : 2*cellTopo.getSideCount(sideDim,sideId);
516 subcellBasisPtr = cellBasis->getSubCellRefBasis(sideDim,sideId);
517 for (ordinal_type faceOrt=0;faceOrt<numOrt;++faceOrt) {
518 auto mat = Kokkos::subview(matData,
519 sideId, faceOrt,
520 Kokkos::ALL(), Kokkos::ALL());
522 *subcellBasisPtr, *cellBasis,
523 sideId, faceOrt, inverse);
524 }
525 }
526 }
527 }
528
529 //
530 // HVOL elements (used for 2D and 1D side cells)
531 //
532 template<typename DT>
533 template<typename BasisHostType>
534 void
537 BasisHostType const *cellBasis, const bool inverse) {
538
539 const auto cellTopo = cellBasis->getBaseCellTopology();
540 const ordinal_type numEdges = (cellTopo.getDimension()==1);
541 const ordinal_type numFaces = (cellTopo.getDimension()==2);
542
543 {
544 const ordinal_type numOrt = 2;
545 for (ordinal_type edgeId=0;edgeId<numEdges;++edgeId) {
546 if(cellBasis->getDofCount(1, edgeId) < 1) continue;
547 for (ordinal_type edgeOrt=0;edgeOrt<numOrt;++edgeOrt) {
548 auto mat = Kokkos::subview(matData,
549 edgeId, edgeOrt,
550 Kokkos::ALL(), Kokkos::ALL());
552 (mat, *cellBasis, edgeOrt, inverse);
553 }
554 }
555 }
556 {
557 for (ordinal_type faceId=0;faceId<numFaces;++faceId) {
558 // this works for triangles (numOrt=6) and quadratures (numOrt=8)
559 const ordinal_type numOrt = 2*cellTopo.getSideCount(2,faceId);
560 if(cellBasis->getDofCount(2, faceId) < 1) continue;
561 for (ordinal_type faceOrt=0;faceOrt<numOrt;++faceOrt) {
562 auto mat = Kokkos::subview(matData,
563 numEdges+faceId, faceOrt,
564 Kokkos::ALL(), Kokkos::ALL());
566 (mat, *cellBasis, faceOrt, inverse);
567 }
568 }
569 }
570 }
571
572 template<typename DT>
573 template<typename BasisType>
576 static bool hookRegistered = false;
577 if (!hookRegistered)
578 {
579 Kokkos::push_finalize_hook( [=] {
580 ortCoeffData.clear();
581 });
582 hookRegistered = true;
583 }
584
585 const KeyType key(basis->getName(), basis->getDegree());
586 const auto found = ortCoeffData.find(key);
587
589 if (found == ortCoeffData.end()) {
590 {
591 auto basis_host = basis->getHostBasis();
592 matData = createCoeffMatrixInternal(basis_host.getRawPtr());
593 ortCoeffData.insert(std::make_pair(key, matData));
594 }
595 } else {
596 matData = found->second;
597 }
598
599 return matData;
600 }
601
602 template<typename DT>
603 template<typename BasisType>
606 static bool hookRegistered = false;
607 if (!hookRegistered)
608 {
609 Kokkos::push_finalize_hook( [=] {
610 ortInvCoeffData.clear();
611 });
612 hookRegistered = true;
613 }
614
615 const KeyType key(basis->getName(), basis->getDegree());
616 const auto found = ortInvCoeffData.find(key);
617
619 if (found == ortInvCoeffData.end()) {
620 {
621 auto basis_host = basis->getHostBasis();
622 matData = createCoeffMatrixInternal(basis_host.getRawPtr(),true);
623 ortInvCoeffData.insert(std::make_pair(key, matData));
624 }
625 } else {
626 matData = found->second;
627 }
628
629 return matData;
630 }
631
632 template<typename DT>
633 template<typename BasisType>
634 std::tuple<typename OrientationTools<DT>::OperatorViewType, typename OrientationTools<DT>::OperatorViewType>
635 OrientationTools<DT>::createOperators(const BasisType* basis) {
636 static bool hookRegistered = false;
637 if (!hookRegistered)
638 {
639 Kokkos::push_finalize_hook( [=] {
640 edgeOperatorData.clear();
641 faceOperatorData.clear();
642 });
643 hookRegistered = true;
644 }
645
646 const std::pair<std::string,ordinal_type> key(basis->getName(), basis->getDegree());
647 const auto edgeFound = edgeOperatorData.find(key);
648 const auto faceFound = faceOperatorData.find(key);
649
650 OperatorViewType edgeOperator, faceOperator;
651 if (edgeFound == edgeOperatorData.end()) {
652 {
653 auto basis_host = basis->getHostBasis();
654 auto matData = createCoeffMatrix(basis);
655
656 edgeOperator = createEdgeOperatorsInternal(basis_host.get(), matData);
657
658 edgeOperatorData.insert(std::make_pair(key, edgeOperator));
659
660 faceOperator = createFaceOperatorsInternal(basis_host.get(), matData);
661 faceOperatorData.insert(std::make_pair(key, faceOperator));
662 }
663 } else {
664 edgeOperator = edgeFound->second;
665 INTREPID2_TEST_FOR_EXCEPTION(faceFound == faceOperatorData.end(), std::invalid_argument, "edgeOperator found while faceOperator was not");
666 faceOperator = faceFound->second;
667 }
668
669 return std::make_tuple(edgeOperator,faceOperator);
670 }
671
672 template<typename DT>
673 template<typename BasisType>
674 std::tuple<typename OrientationTools<DT>::OperatorViewType, typename OrientationTools<DT>::OperatorViewType>
675 OrientationTools<DT>::createInvOperators(const BasisType* basis) {
676 static bool hookRegistered = false;
677 if (!hookRegistered)
678 {
679 Kokkos::push_finalize_hook( [=] {
680 invEdgeOperatorData.clear();
681 invFaceOperatorData.clear();
682 });
683 hookRegistered = true;
684 }
685
686 const std::pair<std::string,ordinal_type> key(basis->getName(), basis->getDegree());
687 const auto edgeFound = invEdgeOperatorData.find(key);
688 const auto faceFound = invFaceOperatorData.find(key);
689
690 OperatorViewType edgeOperator, faceOperator;
691 if (edgeFound == invEdgeOperatorData.end()) {
692 {
693 auto basis_host = basis->getHostBasis();
694 auto matData = createInvCoeffMatrix(basis);
695
696 edgeOperator = createEdgeOperatorsInternal(basis_host.get(), matData);
697 invEdgeOperatorData.insert(std::make_pair(key, edgeOperator));
698
699 faceOperator = createFaceOperatorsInternal(basis_host.get(), matData);
700 invFaceOperatorData.insert(std::make_pair(key, faceOperator));
701 }
702 } else {
703 edgeOperator = edgeFound->second;
704 INTREPID2_TEST_FOR_EXCEPTION(faceFound == invFaceOperatorData.end(), std::invalid_argument, "edgeOperator found while faceOperator was not");
705 faceOperator = faceFound->second;
706 }
707
708 return std::make_tuple(edgeOperator,faceOperator);
709 }
710
711 template<typename DT>
713 ortCoeffData.clear();
714 ortInvCoeffData.clear();
715
716 edgeOperatorData.clear();
717 invEdgeOperatorData.clear();
718 faceOperatorData.clear();
719 invFaceOperatorData.clear();
720
721 doubleViewAllocations.clear();
722 ordinalViewAllocations.clear();
723 }
724
725 template<typename DT>
727 const std::vector<ordinal_type> &rowOffsets,
728 const std::vector<ordinal_type> &colIDs,
729 const std::vector<double> &weights, const bool transpose)
730 {
731 static bool hookRegistered = false;
732 if (!hookRegistered)
733 {
734 Kokkos::push_finalize_hook( [=] {
735 doubleViewAllocations.clear();
736 ordinalViewAllocations.clear();
737 });
738 hookRegistered = true;
739 }
740
741 const int numRows = static_cast<int>(nonIdentityDofs.size());
742 if (numRows > 0)
743 {
744 if (!transpose)
745 {
746 const int numWeights = rowOffsets[numRows];
747
748 const bool isWeightedPermutation = (nonIdentityDofs.size() == weights.size());
749 const int numOffsetsToStore = isWeightedPermutation ? 0 : numRows+1; // convenient to be able to check the "next" row offset to get a column count, even when on the last row
750
751 Kokkos::View<ordinal_type*,DT> rowIndices("OrientationOperator: rowIndices", numRows);
752 Kokkos::View<ordinal_type*,DT> offsetForRowOrdinal("OrientationOperator: rowOffsets", numOffsetsToStore);
753 Kokkos::View<ordinal_type*,DT> packedColumnIndices("OrientationOperator: packedColumnIndices", numWeights);
754 Kokkos::View<double*, DT> packedWeights("OrientationOperator: packedWeights", numWeights);
755
756 auto rowIndicesHost = Kokkos::create_mirror_view(rowIndices);
757 auto offsetForRowOrdinalHost = Kokkos::create_mirror_view(offsetForRowOrdinal);
758 auto packedColumnIndicesHost = Kokkos::create_mirror_view(packedColumnIndices);
759 auto packedWeightsHost = Kokkos::create_mirror_view(packedWeights);
760
761 for (int rowOrdinal=0; rowOrdinal<numRows; rowOrdinal++)
762 {
763 rowIndicesHost(rowOrdinal) = nonIdentityDofs[rowOrdinal];
764 int thisRowOffset = rowOffsets[rowOrdinal];
765 int nextRowOffset = rowOffsets[rowOrdinal+1];
766 if (isWeightedPermutation)
767 {
768 INTREPID2_TEST_FOR_EXCEPTION(nextRowOffset - thisRowOffset != 1, std::invalid_argument, "Invalid orientation operator arguments: if number of weights is equal to the number of row indices, then row offsets should exactly match row ordinals (i.e., there should be exactly one column for every row entry).");
769 }
770 else
771 {
772 offsetForRowOrdinalHost(rowOrdinal) = thisRowOffset;
773 }
774 for (int i=thisRowOffset; i<nextRowOffset; i++)
775 {
776 packedColumnIndicesHost(i) = colIDs[i];
777 packedWeightsHost(i) = weights[i];
778 }
779 }
780 if (!isWeightedPermutation)
781 {
782 offsetForRowOrdinalHost(numRows) = numWeights;
783 }
784
785 Kokkos::deep_copy(rowIndices, rowIndicesHost);
786 Kokkos::deep_copy(offsetForRowOrdinal, offsetForRowOrdinalHost);
787 Kokkos::deep_copy(packedColumnIndices, packedColumnIndicesHost);
788 Kokkos::deep_copy(packedWeights, packedWeightsHost);
789
790 // statically store the managed views
791 ordinalViewAllocations.push_back(rowIndices);
792 ordinalViewAllocations.push_back(offsetForRowOrdinal);
793 ordinalViewAllocations.push_back(packedColumnIndices);
794 doubleViewAllocations.push_back(packedWeights);
795
796 using UnmanagedDoubleView = typename OrientationOperator<DT>::UnmanagedDoubleView;
797 using UnmanagedOrdinalView = typename OrientationOperator<DT>::UnmanagedOrdinalView;
798
799 UnmanagedOrdinalView rowIndicesUnmanaged (rowIndices.data(), rowIndices.extent(0));
800 UnmanagedOrdinalView offsetForRowOrdinalUnmanaged(offsetForRowOrdinal.data(), offsetForRowOrdinal.extent(0));
801 UnmanagedOrdinalView packedColumnIndicesUnmanaged(packedColumnIndices.data(), packedColumnIndices.extent(0));
802 UnmanagedDoubleView packedWeightsUnmanaged (packedWeights.data(), packedWeights.extent(0));
803
804 if (!isWeightedPermutation)
805 {
806 OrientationOperator<DT> orientationOperator(rowIndicesUnmanaged, offsetForRowOrdinalUnmanaged,
807 packedColumnIndicesUnmanaged, packedWeightsUnmanaged);
808
809 return orientationOperator;
810 }
811 else
812 {
813 OrientationOperator<DT> orientationOperator(rowIndicesUnmanaged,
814 packedColumnIndicesUnmanaged, packedWeightsUnmanaged);
815
816 return orientationOperator;
817 }
818 }
819 else
820 {
821 // for the transpose case, we construct the arguments for the non-transpose case,
822 // and then call this method with transpose = false.
823 std::map<ordinal_type, std::map<ordinal_type,double> > transposeOperator; // column to (row -> weight) lookup
824 std::set<ordinal_type> opRows(nonIdentityDofs.begin(), nonIdentityDofs.end());
825
826 for (ordinal_type rowOrdinal = 0; rowOrdinal < numRows; rowOrdinal++)
827 {
828 const ordinal_type & rowID = nonIdentityDofs[rowOrdinal];
829 const ordinal_type & rowOffset = rowOffsets[rowOrdinal];
830
831 const ordinal_type numCols = rowOffsets[rowOrdinal+1] - rowOffset;
832 for (ordinal_type colOrdinal=0; colOrdinal<numCols; colOrdinal++)
833 {
834 const ordinal_type & colID = colIDs[rowOffset + colOrdinal];
835 const double & weight = weights[rowOffset + colOrdinal];
836 transposeOperator[colID][rowID] = weight;
837 if (opRows.find(colID) == opRows.end())
838 {
839 // then the original operator had an implicit identity row for colID; the transpose should have a 1 in diagonal
840 transposeOperator[colID][colID] = 1.0;
841 }
842 }
843 }
844
845 std::vector<ordinal_type> nonIdentityColDofs;
846 std::vector<ordinal_type> colOffsets;
847 std::vector<ordinal_type> rowIDs;
848 std::vector<double> weightsTranspose;
849
850 colOffsets.push_back(0);
851 for (const auto & entry : transposeOperator)
852 {
853 const ordinal_type & colID = entry.first;
854 nonIdentityColDofs.push_back(colID);
855 const auto & rowMap = entry.second;
856 for (const auto & rowEntry : rowMap)
857 {
858 const ordinal_type & rowID = rowEntry.first;
859 const double & weight = rowEntry.second;
860
861 rowIDs.push_back(rowID);
862 weightsTranspose.push_back(weight);
863 }
864 colOffsets.push_back(static_cast<ordinal_type>(rowIDs.size()));
865 }
866
867 return constructOrientationOperatorInternal(nonIdentityColDofs, colOffsets, rowIDs, weightsTranspose, false);
868 }
869 }
870 // identity; nothing to allocate or store
872 }
873}
874
875#endif
Teuchos::RCP< Basis< DeviceType, OutputType, PointType > > BasisPtr
Basis Pointer.
static void getCoeffMatrix_HGRAD(OutputViewType &output, const subcellBasisHostType &subcellBasis, const cellBasisHostType &cellBasis, const ordinal_type subcellId, const ordinal_type subcellOrt, const bool inverse=false)
Compute orientation matrix for HGRAD basis for a given subcell and its reference basis.
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 void getCoeffMatrix_HVOL(OutputViewType &output, const cellBasisHostType &cellBasis, const ordinal_type cellOrt, const bool inverse=false)
Compute orientation matrix for HVOL basis for a given (2D or 1D) cell and its reference basis....
static void getCoeffMatrix_HCURL(OutputViewType &output, const subcellBasisHostType &subcellBasis, const cellBasisHostType &cellBasis, const ordinal_type subcellId, const ordinal_type subcellOrt, const bool inverse=false)
Compute orientation matrix for HCURL basis for a given subcell and its reference basis.
static void init_HVOL(CoeffMatrixDataViewType matData, BasisHostType const *cellBasis, const bool inverse=false)
Compute orientation matrix for HVOL basis.
static CoeffMatrixDataViewType createCoeffMatrix(const BasisType *basis)
Create coefficient matrix.
std::pair< const std::string, ordinal_type > KeyType
key :: basis name, order, value :: matrix data view type
static std::tuple< OperatorViewType, OperatorViewType > createInvOperators(const BasisType *basis)
Create inverse orientation operators.
static OrientationOperator< DeviceType > constructOrientationOperatorInternal(const std::vector< ordinal_type > &nonIdentityDofs, const std::vector< ordinal_type > &rowOffsets, const std::vector< ordinal_type > &colIDs, const std::vector< double > &weights, const bool transpose)
allocates managed static storage in doubleViewAllocations and ordinalViewAllocations; constructs Orie...
static void init_HCURL(CoeffMatrixDataViewType matData, BasisHostType const *cellBasis, const bool inverse=false)
Compute orientation matrix for HCURL basis.
static CoeffMatrixDataViewType createInvCoeffMatrix(const BasisType *basis)
Create inverse of coefficient matrix.
static void clearCoeffMatrix()
Clear coefficient matrix.
static std::tuple< OperatorViewType, OperatorViewType > createOperators(const BasisType *basis)
Create orientation operators.
Kokkos::View< double ****, DeviceType > CoeffMatrixDataViewType
subcell ordinal, orientation, matrix m x n
static void init_HDIV(CoeffMatrixDataViewType matData, BasisHostType const *cellBasis, const bool inverse=false)
Compute orientation matrix for HDIV basis.
static void init_HGRAD(CoeffMatrixDataViewType matData, BasisHostType const *cellBasis, const bool inverse=false)
Compute orientation matrix for HGRAD basis.
Kokkos::View< OrientationOperator< DeviceType > ***, DeviceType > OperatorViewType
subcell ordinal, orientation, transpose (0 or 1)