6 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
7 typename QuadratureType,
typename FieldType>
10 const QuadratureType& quadrature,
const Layout_t& layout)
13 (mesh, ref_element, quadrature) {
15 static_assert(
Dim >= 2 &&
Dim <= 3,
16 "The Nedelec Finite Element space only supports 2D and3D meshes");
23 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
24 typename QuadratureType,
typename FieldType>
27 const QuadratureType& quadrature)
30 (mesh, ref_element, quadrature) {
33 static_assert(
Dim >= 2 &&
Dim <= 3,
34 "The Nedelec Finite Element space only supports 2D and 3D meshes");
40 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
41 typename QuadratureType,
typename FieldType>
49 initializeElementIndices(layout);
52 localDofPositions_m(0)(0) = 0.5;
53 localDofPositions_m(1)(1) = 0.5;
54 localDofPositions_m(2)(0) = 0.5; localDofPositions_m(2)(1) = 1;
55 localDofPositions_m(3)(0) = 1; localDofPositions_m(3)(1) = 0.5;
56 localDofPositions_m(4)(2) = 0.5;
57 localDofPositions_m(5)(0) = 1; localDofPositions_m(5)(2) = 0.5;
58 localDofPositions_m(6)(0) = 1; localDofPositions_m(6)(1) = 1;
59 localDofPositions_m(6)(2) = 0.5;
60 localDofPositions_m(7)(1) = 1; localDofPositions_m(7)(2) = 0.5;
61 localDofPositions_m(8)(0) = 0.5; localDofPositions_m(8)(2) = 1;
62 localDofPositions_m(9)(1) = 0.5; localDofPositions_m(9)(2) = 1;
63 localDofPositions_m(10)(0) = 0.5; localDofPositions_m(10)(1) = 1;
64 localDofPositions_m(10)(2) = 1;
65 localDofPositions_m(11)(0) = 1; localDofPositions_m(11)(1) = 0.5;
66 localDofPositions_m(11)(2) = 1;
70 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
71 typename QuadratureType,
typename FieldType>
77 int npoints = ldom.
size();
78 auto first = ldom.first();
79 auto last = ldom.last();
82 for (
size_t d = 0; d <
Dim; ++d) {
83 bounds[d] = this->nr_m[d] - 1;
86 int upperBoundaryPoints = -1;
88 Kokkos::View<size_t*> points(
"ComputeMapping", npoints);
90 "ComputePoints", npoints,
91 KOKKOS_CLASS_LAMBDA(
const int i,
int& local) {
94 bool isBoundary =
false;
95 for (
unsigned int d = 0; d <
Dim; ++d) {
96 int range = last[d] -
first[d] + 1;
97 val[d] =
first[d] + (idx % range);
99 if (val[d] == bounds[d]) {
103 points(i) = (!isBoundary) * (this->getElementIndex(val));
106 Kokkos::Sum<int>(upperBoundaryPoints));
109 int elementsPerRank = npoints - upperBoundaryPoints;
110 elementIndices = Kokkos::View<size_t*>(
"i", elementsPerRank);
111 Kokkos::View<size_t> index(
"index");
114 "RemoveNaNs", npoints, KOKKOS_CLASS_LAMBDA(
const int i) {
115 if ((points(i) != 0) || (i == 0)) {
116 const size_t idx = Kokkos::atomic_fetch_add(&index(), 1);
117 elementIndices(idx) = points(i);
127 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
128 typename QuadratureType,
typename FieldType>
132 size_t num_global_dofs = 0;
134 for (
size_t d = 0; d <
Dim; ++d) {
135 size_t accu = this->nr_m[d]-1;
136 for (
size_t d2 = 0; d2 <
Dim; ++d2) {
137 if (d == d2)
continue;
138 accu *= this->nr_m[d2];
140 num_global_dofs += accu;
143 return num_global_dofs;
146 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
147 typename QuadratureType,
typename FieldType>
150 const size_t& globalDOFIndex)
const {
152 static_assert(
Dim == 2 ||
Dim == 3,
"Dim must be 2 or 3");
160 dof_mapping = {0, 1, 2, 3};
161 }
else if (
Dim == 3) {
162 dof_mapping = {0, 1, 2, 3, 4, 5, 7, 6, 8, 9, 10, 11};
167 for (
size_t i = 0; i < dof_mapping.
dim; ++i) {
168 if (global_dofs[dof_mapping[i]] == globalDOFIndex) {
169 return dof_mapping[i];
177 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
178 typename QuadratureType,
typename FieldType>
181 const size_t& localDOFIndex)
const {
185 return global_dofs[localDOFIndex];
188 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
189 typename QuadratureType,
typename FieldType>
191 QuadratureType, FieldType>::numElementDOFs>
197 for (
size_t dof = 0; dof < numElementDOFs; ++dof) {
198 localDOFs[dof] = dof;
204 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
205 typename QuadratureType,
typename FieldType>
207 QuadratureType, FieldType>::numElementDOFs>
210 QuadratureType, FieldType>::indices_t& elementIndex)
const {
219 if constexpr (
Dim == 2) {
220 size_t nx = this->nr_m[0];
222 }
else if constexpr (
Dim == 3) {
223 size_t nx = this->nr_m[0];
224 size_t ny = this->nr_m[1];
226 v(2) = 3*nx*ny - nx - ny;
230 size_t nx = this->nr_m[0];
231 globalDOFs(0) = v.
dot(elementIndex);
232 globalDOFs(1) = globalDOFs(0) + nx - 1;
233 globalDOFs(2) = globalDOFs(1) + nx;
234 globalDOFs(3) = globalDOFs(1) + 1;
236 if constexpr (
Dim == 3) {
237 size_t ny = this->nr_m[1];
239 globalDOFs(4) = v(2)*elementIndex(2) + 2*nx*ny - nx - ny
240 + elementIndex(1)*nx + elementIndex(0);
241 globalDOFs(5) = globalDOFs(4) + 1;
242 globalDOFs(6) = globalDOFs(4) + nx + 1;
243 globalDOFs(7) = globalDOFs(4) + nx;
244 globalDOFs(8) = globalDOFs(0) + 3*nx*ny - nx - ny;
245 globalDOFs(9) = globalDOFs(8) + nx - 1;
246 globalDOFs(10) = globalDOFs(9) + nx;
247 globalDOFs(11) = globalDOFs(9) + 1;
254 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
255 typename QuadratureType,
typename FieldType>
257 QuadratureType, FieldType>::numElementDOFs>
261 indices_t elementPos = this->getElementNDIndex(elementIndex);
262 return getGlobalDOFIndices(elementPos);
267 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
268 typename QuadratureType,
typename FieldType>
270 QuadratureType, FieldType>::numElementDOFs>
273 QuadratureType, FieldType>::indices_t elementIndex,
286 elementIndex -= ldom.
first();
296 if constexpr (
Dim == 2) {
299 }
else if constexpr (
Dim == 3) {
303 v(2) = 3*nx*ny - nx - ny;
307 FEMVectorDOFs(0) = v.
dot(elementIndex);
308 FEMVectorDOFs(1) = FEMVectorDOFs(0) + nx - 1;
309 FEMVectorDOFs(2) = FEMVectorDOFs(1) + nx;
310 FEMVectorDOFs(3) = FEMVectorDOFs(1) + 1;
312 if constexpr (
Dim == 3) {
315 FEMVectorDOFs(4) = v(2)*elementIndex(2) + 2*nx*ny - nx - ny
316 + elementIndex(1)*nx + elementIndex(0);
317 FEMVectorDOFs(5) = FEMVectorDOFs(4) + 1;
318 FEMVectorDOFs(6) = FEMVectorDOFs(4) + nx + 1;
319 FEMVectorDOFs(7) = FEMVectorDOFs(4) + nx;
320 FEMVectorDOFs(8) = FEMVectorDOFs(0) + 3*nx*ny - nx - ny;
321 FEMVectorDOFs(9) = FEMVectorDOFs(8) + nx - 1;
322 FEMVectorDOFs(10) = FEMVectorDOFs(9) + nx;
323 FEMVectorDOFs(11) = FEMVectorDOFs(9) + 1;
327 return FEMVectorDOFs;
330 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
331 typename QuadratureType,
typename FieldType>
333 QuadratureType, FieldType>::numElementDOFs>
338 indices_t elementPos = this->getElementNDIndex(elementIndex);
339 return getFEMVectorDOFIndices(elementPos, ldom);
343 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
344 typename QuadratureType,
typename FieldType>
352 return localDofPositions_m(localDOFIndex);
360 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
361 typename QuadratureType,
typename FieldType>
362 template <
typename F>
373 FEMVector<T> resultVector = x.template skeletonCopy<T>();
377 this->quadrature_m.getWeightsForRefElement();
381 this->quadrature_m.getIntegrationNodesForRefElement();
387 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
388 for (
size_t i = 0; i < numElementDOFs; ++i) {
389 curl_b_q[k][i] = this->evaluateRefElementShapeFunctionCurl(i, q[k]);
390 val_b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
401 auto ldom = layout_m.getLocalNDIndex();
403 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
404 using policy_type = Kokkos::RangePolicy<exec_space>;
416 for (
size_t i = 0; i < numElementDOFs; ++i) {
417 for (
size_t j = 0; j < numElementDOFs; ++j) {
419 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
420 A[i][j] += w[k] * evalFunction(i, j, curl_b_q[k], val_b_q[k]);
432 "Loop over elements", policy_type(0, elementIndices.extent(0)),
433 KOKKOS_CLASS_LAMBDA(
const size_t index) {
434 const size_t elementIndex = elementIndices(index);
442 this->getFEMVectorDOFIndices(elementIndex, ldom);
452 for (i = 0; i < numElementDOFs; ++i) {
456 if (this->isDOFOnBoundary(I)) {
460 for (j = 0; j < numElementDOFs; ++j) {
464 if (this->isDOFOnBoundary(J)) {
468 resultView(vectorIndices[i]) += A[i][j] * view(vectorIndices[j]);
480 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
481 typename QuadratureType,
typename FieldType>
484 QuadratureType, FieldType>::point_t>& f)
const {
488 this->quadrature_m.getWeightsForRefElement();
492 this->quadrature_m.getIntegrationNodesForRefElement();
500 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
501 for (
size_t i = 0; i < numElementDOFs; ++i) {
502 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
511 quadratureDOFDistances;
512 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
513 for (
size_t i = 0; i < numElementDOFs; ++i) {
514 point_t dofPos = getLocalDOFPosition(i);
516 quadratureDOFDistances[k][i] = Kokkos::sqrt(d.
dot(d));
521 const T absDetDPhi = Kokkos::abs(this->ref_element_m.getDeterminantOfTransformationJacobian(
522 this->getElementMeshVertexPoints(zeroNdIndex)));
525 auto ldom = layout_m.getLocalNDIndex();
536 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
537 using policy_type = Kokkos::RangePolicy<exec_space>;
541 "Loop over elements", policy_type(0, elementIndices.extent(0)),
542 KOKKOS_CLASS_LAMBDA(
size_t index) {
543 const size_t elementIndex = elementIndices(index);
548 this->getFEMVectorDOFIndices(elementIndex, ldom);
552 for (i = 0; i < numElementDOFs; ++i) {
553 size_t I = global_dofs[i];
554 if (this->isDOFOnBoundary(I)) {
561 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
566 for (
size_t j = 0; j < numElementDOFs; ++j) {
570 T dist = quadratureDOFDistances[k][j];
576 interpolatedVal += 1./dist * view(vectorIndices<:j:>);
580 interpolatedVal /= distSum;
583 contrib += w[k] * basis_q[k][i].
dot(interpolatedVal) * absDetDPhi;
587 atomic_view(vectorIndices<:i:>) += contrib;
595 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
596 typename QuadratureType,
typename FieldType>
597 template <
typename F>
603 this->quadrature_m.getWeightsForRefElement();
607 this->quadrature_m.getIntegrationNodesForRefElement();
613 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
614 for (
size_t i = 0; i < numElementDOFs; ++i) {
615 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
621 const T absDetDPhi = Kokkos::abs(this->ref_element_m.getDeterminantOfTransformationJacobian(
622 this->getElementMeshVertexPoints(zeroNdIndex)));
625 auto ldom = layout_m.getLocalNDIndex();
635 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
636 using policy_type = Kokkos::RangePolicy<exec_space>;
641 "Loop over elements", policy_type(0, elementIndices.extent(0)),
642 KOKKOS_CLASS_LAMBDA(
size_t index) {
643 const size_t elementIndex = elementIndices(index);
648 this->getFEMVectorDOFIndices(elementIndex, ldom);
653 for (i = 0; i < numElementDOFs; ++i) {
657 if (this->isDOFOnBoundary(I)) {
663 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
665 point_t pos = this->ref_element_m.localToGlobal(
666 this->getElementMeshVertexPoints(this->getElementNDIndex(elementIndex)),
670 point_t interpolatedVal = f(pos);
673 contrib += w[k] * basis_q[k][i].
dot(interpolatedVal) * absDetDPhi;
677 atomic_view(vectorIndices[i]) += contrib;
691 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
692 typename QuadratureType,
typename FieldType>
697 QuadratureType, FieldType>::point_t& localPoint)
const {
700 assert(localDOF < numElementDOFs &&
"The local vertex index is invalid");
702 assert(this->ref_element_m.isPointInRefElement(localPoint)
703 &&
"Point is not in reference element");
709 if constexpr (
Dim == 2) {
714 case 0: result(0) = 1 - y;
break;
715 case 1: result(1) = 1 - x;
break;
716 case 2: result(0) = y;
break;
717 case 3: result(1) = x;
break;
719 }
else if constexpr (
Dim == 3) {
725 case 0: result(0) = y*z - y - z + 1;
break;
726 case 1: result(1) = x*z - x - z + 1;
break;
727 case 2: result(0) = y*(1 - z);
break;
728 case 3: result(1) = x*(1 - z);
break;
729 case 4: result(2) = x*y - x - y + 1;
break;
730 case 5: result(2) = x*(1 - y);
break;
731 case 6: result(2) = x*y;
break;
732 case 7: result(2) = y*(1 - x);
break;
733 case 8: result(0) = z*(1 - y);
break;
734 case 9: result(1) = z*(1 - x);
break;
735 case 10: result(0) = y*z;
break;
736 case 11: result(1) = x*z;
break;
745 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
746 typename QuadratureType,
typename FieldType>
748 QuadratureType, FieldType>::point_t
752 QuadratureType, FieldType>::point_t& localPoint)
const {
757 if constexpr (
Dim == 2) {
766 case 0: result(0) = 1;
break;
767 case 1: result(0) = -1;
break;
768 case 2: result(0) = -1;
break;
769 case 3: result(0) = 1;
break;
777 case 0: result(0) = 0; result(1) = -1+y; result(2) = 1-z;
break;
778 case 1: result(0) = 1-x; result(1) = 0; result(2) = -1+z;
break;
779 case 2: result(0) = 0; result(1) = -y; result(2) = -1+z;
break;
780 case 3: result(0) = x; result(1) = 0; result(2) = 1-z;
break;
781 case 4: result(0) = -1+x; result(1) = 1-y; result(2) = 0;
break;
782 case 5: result(0) = -x; result(1) = -1+y; result(2) = 0;
break;
783 case 6: result(0) = x; result(1) = -y; result(2) = 0;
break;
784 case 7: result(0) = 1-x; result(1) = y; result(2) = 0;
break;
785 case 8: result(0) = 0; result(1) = 1-y; result(2) = z;
break;
786 case 9: result(0) = -1+x; result(1) = 0; result(2) = -z;
break;
787 case 10: result(0) = 0; result(1) = y; result(2) = -z;
break;
788 case 11: result(0) = -x; result(1) = 0; result(2) = z;
break;
801 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
802 typename QuadratureType,
typename FieldType>
807 if constexpr (
Dim == 2) {
808 return createFEMVector2d();
810 return createFEMVector3d();
815 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
816 typename QuadratureType,
typename FieldType>
818 FieldType>::point_t*>
821 FieldType>::point_t*>& positions,
const FEMVector<T>& coef)
const {
824 auto ldom = layout_m.getLocalNDIndex();
827 auto gdom = layout_m.getDomain();
828 indices_t gextent = gdom.last() - gdom.first();
831 point_t domainSize = (this->nr_m-1) * this->hr_m;
834 auto coefView = coef.
getView();
836 Kokkos::View<point_t*> outView(
"reconstructed Func values at points", positions.extent(0));
839 KOKKOS_CLASS_LAMBDA(
size_t i) {
843 indices_t elemIdx = ((pos - this->origin_m) / domainSize) * gextent;
851 for (
size_t d = 0; d <
Dim; ++d) {
852 if (elemIdx<:d:> >=
static_cast<size_t>(ldom.
last()<:d:>)) {
860 this->getFEMVectorDOFIndices(elemIdx, ldom);
864 point_t locPos = pos - (elemIdx * this->hr_m + this->origin_m);
865 locPos /= this->hr_m;
871 for (
size_t d = 0; d <
Dim; ++d) {
880 for (
size_t j = 0; j < numElementDOFs; ++j) {
881 point_t funcVal = this->evaluateRefElementShapeFunction(j, locPos);
882 val += funcVal*coefView(vectorIndices<:j:>);
898 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
899 typename QuadratureType,
typename FieldType>
900 template <
typename F>
903 if (this->quadrature_m.getOrder() < (2 * Order + 1)) {
906 "Order of quadrature rule for error computation should be > 2*p + 1");
911 this->quadrature_m.getWeightsForRefElement();
915 this->quadrature_m.getIntegrationNodesForRefElement();
919 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
920 for (
size_t i = 0; i < numElementDOFs; ++i) {
921 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
928 const T absDetDPhi = Kokkos::abs(this->ref_element_m
929 .getDeterminantOfTransformationJacobian(this->getElementMeshVertexPoints(zeroNdIndex)));
935 auto ldom = layout_m.getLocalNDIndex();
937 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
938 using policy_type = Kokkos::RangePolicy<exec_space>;
945 policy_type(0, elementIndices.extent(0)),
946 KOKKOS_CLASS_LAMBDA(
size_t index,
double& local) {
947 const size_t elementIndex = elementIndices(index);
952 this->getFEMVectorDOFIndices(elementIndex, ldom);
957 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
960 point_t val_u_sol = u_sol(this->ref_element_m.localToGlobal(
961 this->getElementMeshVertexPoints(this->getElementNDIndex(elementIndex)),
967 for (
size_t j = 0; j < numElementDOFs; ++j) {
969 val_u_h += basis_q[k][j] * view(vectorIndices[j]);
973 point_t dif = (val_u_sol - val_u_h);
975 contrib += w[k] * x * absDetDPhi;
979 Kokkos::Sum<double>(error)
983 T global_error = 0.0;
984 Comm->allreduce(error, global_error, 1, std::plus<T>());
986 return Kokkos::sqrt(global_error);
989 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
990 typename QuadratureType,
typename FieldType>
994 bool onBoundary =
false;
995 if constexpr (
Dim == 2) {
996 size_t nx = this->nr_m[0];
997 size_t ny = this->nr_m[1];
999 bool sVal = (dofIdx < nx -1);
1000 onBoundary = onBoundary || sVal;
1002 onBoundary = onBoundary || (dofIdx > nx*(ny-1) + ny*(nx-1) - nx);
1004 onBoundary = onBoundary || ((dofIdx >= nx-1) && (dofIdx - (nx-1)) % (2*nx - 1) == 0);
1006 onBoundary = onBoundary || ((dofIdx >= 2*nx-2) && ((dofIdx - 2*nx + 2) % (2*nx - 1) == 0));
1009 if constexpr (
Dim == 3) {
1010 size_t nx = this->nr_m[0];
1011 size_t ny = this->nr_m[1];
1012 size_t nz = this->nr_m[2];
1014 size_t zOffset = dofIdx / (nx*(ny-1) + ny*(nx-1) + nx*ny);
1017 if (dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset >= (nx*(ny-1) + ny*(nx-1))) {
1021 size_t f = dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset
1022 - (nx*(ny-1) + ny*(nx-1));
1024 size_t yOffset = f / nx;
1026 onBoundary = onBoundary || yOffset == 0;
1028 onBoundary = onBoundary || yOffset == ny-1;
1030 size_t xOffset = f % nx;
1032 onBoundary = onBoundary || xOffset == 0;
1034 onBoundary = onBoundary || xOffset == nx-1;
1039 onBoundary = onBoundary || zOffset == 0;
1041 onBoundary = onBoundary || zOffset == nz-1;
1043 size_t f = dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset;
1044 size_t yOffset = f / (2*nx - 1);
1045 size_t xOffset = f - (2*nx - 1)*yOffset;
1047 if (xOffset < (nx-1)) {
1053 onBoundary = onBoundary || yOffset == 0;
1055 onBoundary = onBoundary || yOffset == ny-1;
1061 if (xOffset >= nx-1) {
1066 onBoundary = onBoundary || xOffset == 0;
1068 onBoundary = onBoundary || xOffset == nx-1;
1077 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1078 typename QuadratureType,
typename FieldType>
1082 if constexpr (
Dim == 2) {
1083 size_t nx = this->nr_m[0];
1084 size_t ny = this->nr_m[1];
1087 if (dofIdx < nx -1)
return 0;
1089 if ((dofIdx - (nx-1)) % (2*nx - 1) == 0)
return 1;
1091 if (dofIdx > nx*(ny-1) + ny*(nx-1) - nx)
return 2;
1093 if ((dofIdx >= 2*nx-2) && (dofIdx - 2*nx + 2) % (2*nx - 1) == 0)
return 3;
1098 if constexpr (
Dim == 3) {
1099 size_t nx = this->nr_m[0];
1100 size_t ny = this->nr_m[1];
1101 size_t nz = this->nr_m[2];
1103 size_t zOffset = dofIdx / (nx*(ny-1) + ny*(nx-1) + nx*ny);
1106 if (dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset >= (nx*(ny-1) + ny*(nx-1))) {
1110 size_t f = dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset
1111 - (nx*(ny-1) + ny*(nx-1));
1113 size_t yOffset = f / nx;
1115 if (yOffset == 0)
return 0;
1117 if (yOffset == ny-1)
return 2;
1119 size_t xOffset = f % nx;
1121 if (xOffset == 0)
return 1;
1123 if (xOffset == nx-1)
return 3;
1128 if (zOffset == 0)
return 4;
1130 if (zOffset == nz-1)
return 5;
1132 size_t f = dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset;
1133 size_t yOffset = f / (2*nx - 1);
1134 size_t xOffset = f - (2*nx - 1)*yOffset;
1136 if (xOffset < (nx-1)) {
1142 if (yOffset == 0)
return 0;
1144 if (yOffset == ny-1)
return 2;
1150 if (xOffset >= nx-1) {
1155 if (xOffset == 0)
return 1;
1157 if (xOffset == nx-1)
return 3;
1166 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1167 typename QuadratureType,
typename FieldType>
1194 auto ldom = layout_m.getLocalNDIndex();
1195 auto doms = layout_m.getHostLocalDomains();
1199 std::vector<size_t> neighbors;
1200 std::vector< Kokkos::View<size_t*> > sendIdxs;
1201 std::vector< Kokkos::View<size_t*> > recvIdxs;
1202 std::vector< std::vector<size_t> > sendIdxsTemp;
1203 std::vector< std::vector<size_t> > recvIdxsTemp;
1207 size_t myRank =
Comm->rank();
1208 for (
size_t i = 0; i < doms.extent(0); ++i) {
1213 auto odom = doms(i);
1216 if (ldom.
last()[0] == odom.first()[0]-1 &&
1217 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1])) {
1221 int pos = ldom.
last()[0];
1224 neighbors.push_back(i);
1225 sendIdxsTemp.push_back(std::vector<size_t>());
1226 recvIdxsTemp.push_back(std::vector<size_t>());
1227 size_t idx = neighbors.size() - 1;
1231 elementPosHalo(0) = pos;
1233 elementPosSend(0) = pos;
1234 for (
int k =
begin; k <=
end; ++k) {
1235 elementPosHalo(1) = k;
1236 elementPosSend(1) = k;
1238 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1239 recvIdxsTemp[idx].push_back(dofIndicesHalo[3]);
1241 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1242 sendIdxsTemp[idx].push_back(dofIndicesSend[0]);
1243 sendIdxsTemp[idx].push_back(dofIndicesSend[1]);
1246 if (
end == layout_m.getDomain().last()[1] || ldom.
last()[1] > odom.last()[1]) {
1247 elementPosSend(1) =
end;
1248 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1250 sendIdxsTemp[idx].push_back(dofIndicesSend[2]);
1255 if (ldom.
first()[0] == odom.last()[0]+1 &&
1256 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1])) {
1260 int pos = ldom.
first()[0];
1263 neighbors.push_back(i);
1264 sendIdxsTemp.push_back(std::vector<size_t>());
1265 recvIdxsTemp.push_back(std::vector<size_t>());
1266 size_t idx = neighbors.size() - 1;
1270 elementPosHalo(0) = pos-1;
1272 elementPosSend(0) = pos;
1273 for (
int k =
begin; k <=
end; ++k) {
1274 elementPosHalo(1) = k;
1275 elementPosSend(1) = k;
1277 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1278 recvIdxsTemp[idx].push_back(dofIndicesHalo[0]);
1279 recvIdxsTemp[idx].push_back(dofIndicesHalo[1]);
1281 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1282 sendIdxsTemp[idx].push_back(dofIndicesSend[1]);
1285 if (
end == layout_m.getDomain().last()[1] || odom.last()[1] > ldom.
last()[1]) {
1286 elementPosHalo(1) =
end;
1287 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1289 recvIdxsTemp[idx].push_back(dofIndicesHalo[2]);
1294 if (ldom.
last()[1] == odom.first()[1]-1 &&
1295 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0])) {
1299 int pos = ldom.
last()[1];
1302 neighbors.push_back(i);
1303 sendIdxsTemp.push_back(std::vector<size_t>());
1304 recvIdxsTemp.push_back(std::vector<size_t>());
1305 size_t idx = neighbors.size() - 1;
1309 elementPosHalo(1) = pos;
1311 elementPosSend(1) = pos;
1312 for (
int k =
begin; k <=
end; ++k) {
1313 elementPosHalo(0) = k;
1314 elementPosSend(0) = k;
1316 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1317 recvIdxsTemp[idx].push_back(dofIndicesHalo[2]);
1319 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1320 sendIdxsTemp[idx].push_back(dofIndicesSend[0]);
1321 sendIdxsTemp[idx].push_back(dofIndicesSend[1]);
1324 if (
end == layout_m.getDomain().last()[0] || ldom.
last()[0] > odom.last()[0]) {
1325 elementPosSend(0) =
end;
1326 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1328 sendIdxsTemp[idx].push_back(dofIndicesSend[3]);
1333 if (ldom.
first()[1] == odom.last()[1]+1 &&
1334 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0])) {
1338 int pos = ldom.
first()[1];
1341 neighbors.push_back(i);
1342 sendIdxsTemp.push_back(std::vector<size_t>());
1343 recvIdxsTemp.push_back(std::vector<size_t>());
1344 size_t idx = neighbors.size() - 1;
1348 elementPosHalo(1) = pos-1;
1350 elementPosSend(1) = pos;
1351 for (
int k =
begin; k <=
end; ++k) {
1352 elementPosHalo(0) = k;
1353 elementPosSend(0) = k;
1355 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1356 recvIdxsTemp[idx].push_back(dofIndicesHalo[0]);
1357 recvIdxsTemp[idx].push_back(dofIndicesHalo[1]);
1359 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1360 sendIdxsTemp[idx].push_back(dofIndicesSend[0]);
1363 if (
end == layout_m.getDomain().last()[0] || odom.last()[0] > ldom.
last()[0]) {
1364 elementPosHalo(0) =
end;
1365 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1367 recvIdxsTemp[idx].push_back(dofIndicesHalo[3]);
1377 for (
size_t i = 0; i < neighbors.size(); ++i) {
1378 sendIdxs.push_back(Kokkos::View<size_t*>(
"FEMvector::sendIdxs[" + std::to_string(i) +
1379 "]", sendIdxsTemp[i].size()));
1380 recvIdxs.push_back(Kokkos::View<size_t*>(
"FEMvector::recvIdxs[" + std::to_string(i) +
1381 "]", recvIdxsTemp[i].size()));
1382 auto sendView = sendIdxs[i];
1383 auto recvView = recvIdxs[i];
1384 auto hSendView = Kokkos::create_mirror_view(sendView);
1385 auto hRecvView = Kokkos::create_mirror_view(recvView);
1387 for (
size_t j = 0; j < sendIdxsTemp[i].size(); ++j) {
1388 hSendView(j) = sendIdxsTemp[i][j];
1391 for (
size_t j = 0; j < recvIdxsTemp[i].size(); ++j) {
1392 hRecvView(j) = recvIdxsTemp[i][j];
1395 Kokkos::deep_copy(sendView, hSendView);
1396 Kokkos::deep_copy(recvView, hRecvView);
1403 extents = (ldom.
last() - ldom.
first()) + 3;
1404 size_t nx = extents(0);
1405 size_t ny = extents(1);
1406 size_t n = nx*(ny-1) + ny*(nx-1);
1414 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1415 typename QuadratureType,
typename FieldType>
1453 auto ldom = layout_m.getLocalNDIndex();
1454 auto doms = layout_m.getHostLocalDomains();
1458 std::vector<size_t> neighbors;
1459 std::vector< Kokkos::View<size_t*> > sendIdxs;
1460 std::vector< Kokkos::View<size_t*> > recvIdxs;
1461 std::vector< std::vector<size_t> > sendIdxsTemp;
1462 std::vector< std::vector<size_t> > recvIdxsTemp;
1489 auto flatBoundaryExchange = [
this, &neighbors, &ldom](
1490 size_t i,
size_t a,
size_t f,
size_t s,
1491 std::vector<std::vector<size_t> >& va, std::vector<std::vector<size_t> >& vb,
1493 const std::vector<size_t>& idxsA,
const std::vector<size_t>& idxsB,
1496 int beginF =
std::max(bdom.first()[f], adom.first()[f]);
1497 int endF =
std::min(bdom.last()[f], adom.last()[f]);
1498 int beginS =
std::max(bdom.first()[s], adom.first()[s]);
1499 int endS =
std::min(bdom.last()[s], adom.last()[s]);
1501 neighbors.push_back(i);
1502 va.push_back(std::vector<size_t>());
1503 vb.push_back(std::vector<size_t>());
1504 size_t idx = neighbors.size() - 1;
1508 elementPosA(a) = posA;
1510 elementPosB(a) = posB;
1514 for (
int k = beginF; k <= endF; ++k) {
1517 for (
int l = beginS; l <= endS; ++l) {
1521 auto dofIndicesA = this->getFEMVectorDOFIndices(elementPosA, ldom);
1522 va[idx].push_back(dofIndicesA[idxsA[0]]);
1523 va[idx].push_back(dofIndicesA[idxsA[1]]);
1525 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1526 vb[idx].push_back(dofIndicesB[idxsB[0]]);
1527 vb[idx].push_back(dofIndicesB[idxsB[1]]);
1528 vb[idx].push_back(dofIndicesB[idxsB[2]]);
1537 if (endF == layout_m.getDomain().last()[f] ||
1538 bdom.last()[f] > adom.last()[f]) {
1539 va[idx].push_back(dofIndicesA[idxsA[2]]);
1542 if (endF == layout_m.getDomain().last()[f] ||
1543 adom.last()[f] > bdom.last()[f]) {
1544 vb[idx].push_back(dofIndicesB[idxsB[3]]);
1545 vb[idx].push_back(dofIndicesB[idxsB[4]]);
1552 if (bdom.first()[f] < adom.first()[f]) {
1554 tmpPos(f) = beginF-1;
1555 auto dofIndicestmp = this->getFEMVectorDOFIndices(tmpPos, ldom);
1556 va[idx].push_back(dofIndicestmp[idxsA[0]]);
1557 va[idx].push_back(dofIndicestmp[idxsA[1]]);
1568 if (endS == layout_m.getDomain().last()[s] || bdom.last()[s] > adom.last()[s]) {
1569 elementPosA(s) = endS;
1570 auto dofIndicesA = this->getFEMVectorDOFIndices(elementPosA, ldom);
1571 va[idx].push_back(dofIndicesA[idxsA[3]]);
1574 if (endS == layout_m.getDomain().last()[s] || adom.last()[s] > bdom.last()[s]) {
1575 elementPosB(s) = endS;
1576 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1577 vb[idx].push_back(dofIndicesB[idxsB[5]]);
1578 vb[idx].push_back(dofIndicesB[idxsB[6]]);
1585 if (bdom.first()[f] < adom.first()[f]) {
1587 tmpPos(s) = beginS-1;
1588 auto dofIndicestmp = this->getFEMVectorDOFIndices(tmpPos, ldom);
1589 va[idx].push_back(dofIndicestmp[idxsA[0]]);
1590 va[idx].push_back(dofIndicestmp[idxsA[1]]);
1595 if ((endF == layout_m.getDomain().last()[f] || adom.last()[f] > bdom.last()[f]) &&
1596 (endS == layout_m.getDomain().last()[s] || adom.last()[s] > bdom.last()[s])) {
1597 elementPosB(f) = endF;
1598 elementPosB(s) = endS;
1599 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1600 vb[idx].push_back(dofIndicesB[idxsB[7]]);
1623 auto negativeDiagonalExchange = [
this, &neighbors, &ldom](
1624 size_t i,
size_t a,
size_t f,
size_t s,
int ao,
int bo,
1625 std::vector<std::vector<size_t> >& va, std::vector<std::vector<size_t> >& vb,
1626 const std::vector<size_t>& idxsA,
const std::vector<size_t>& idxsB,
1629 neighbors.push_back(i);
1630 va.push_back(std::vector<size_t>());
1631 vb.push_back(std::vector<size_t>());
1632 size_t idx = neighbors.size() - 1;
1635 elementPosA(f) = ldom.
last()[f];
1636 elementPosA(s) = ldom.
first()[s] + ao;
1639 elementPosB(f) = ldom.
last()[f];
1640 elementPosB(s) = ldom.
first()[s] + bo;
1645 for (
int k =
begin; k <=
end; ++k) {
1649 auto dofIndicesA = this->getFEMVectorDOFIndices(elementPosA, ldom);
1650 va[idx].push_back(dofIndicesA[idxsA[0]]);
1651 va[idx].push_back(dofIndicesA[idxsA[1]]);
1653 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1654 vb[idx].push_back(dofIndicesB[idxsB[0]]);
1655 vb[idx].push_back(dofIndicesB[idxsB[1]]);
1677 auto positiveDiagonalExchange = [
this, &neighbors, &ldom](
1678 size_t i,
size_t a,
size_t f,
size_t s,
1680 std::vector<std::vector<size_t> >& va, std::vector<std::vector<size_t> >& vb,
1681 const std::vector<size_t>& idxsA,
const std::vector<size_t>& idxsB,
1684 neighbors.push_back(i);
1685 va.push_back(std::vector<size_t>());
1686 vb.push_back(std::vector<size_t>());
1687 size_t idx = neighbors.size() - 1;
1690 elementPosA(f) = posA(f);
1691 elementPosA(s) = posA(s);
1694 elementPosB(f) = posB(f);
1695 elementPosB(s) = posB(s);
1700 for (
int k =
begin; k <=
end; ++k) {
1704 auto dofIndicesA = this->getFEMVectorDOFIndices(elementPosA, ldom);
1705 va[idx].push_back(dofIndicesA[idxsA[0]]);
1706 va[idx].push_back(dofIndicesA[idxsA[1]]);
1707 va[idx].push_back(dofIndicesA[idxsA[2]]);
1709 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1710 vb[idx].push_back(dofIndicesB[idxsB[0]]);
1721 size_t myRank =
Comm->rank();
1722 for (
size_t i = 0; i < doms.extent(0); ++i) {
1727 auto odom = doms(i);
1730 if (ldom.
last()[0] == odom.first()[0]-1 &&
1731 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1]) &&
1732 !(odom.last()[2] < ldom.
first()[2] || odom.first()[2] > ldom.
last()[2])) {
1734 int pos = ldom.
last()[0];
1735 flatBoundaryExchange(
1737 recvIdxsTemp, sendIdxsTemp,
1739 {3,5,6,11}, {0,1,4,2,7,8,9,10},
1745 if (ldom.
first()[0] == odom.last()[0]+1 &&
1746 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1]) &&
1747 !(odom.last()[2] < ldom.
first()[2] || odom.first()[2] > ldom.
last()[2])) {
1749 int pos = ldom.
first()[0];
1750 flatBoundaryExchange(
1752 sendIdxsTemp, recvIdxsTemp,
1754 {1,4,7,9}, {0,1,4,2,7,8,9,10},
1760 if (ldom.
last()[1] == odom.first()[1]-1 &&
1761 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0]) &&
1762 !(odom.last()[2] < ldom.
first()[2] || odom.first()[2] > ldom.
last()[2])) {
1764 int pos = ldom.
last()[1];
1765 flatBoundaryExchange(
1767 recvIdxsTemp, sendIdxsTemp,
1769 {2,7,6,10}, {0,1,4,3,5,8,9,11},
1775 if (ldom.
first()[1] == odom.last()[1]+1 &&
1776 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0]) &&
1777 !(odom.last()[2] < ldom.
first()[2] || odom.first()[2] > ldom.
last()[2])) {
1779 int pos = ldom.
first()[1];
1780 flatBoundaryExchange(
1782 sendIdxsTemp, recvIdxsTemp,
1784 {0,4,5,8}, {0,1,4,3,5,8,9,11},
1791 if (ldom.
last()[2] == odom.first()[2]-1 &&
1792 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0]) &&
1793 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1])) {
1795 int pos = ldom.
last()[2];
1796 flatBoundaryExchange(
1798 recvIdxsTemp, sendIdxsTemp,
1800 {8,9,11,10}, {0,1,4,3,5,2,7,6},
1806 if (ldom.
first()[2] == odom.last()[2]+1 &&
1807 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0]) &&
1808 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1])) {
1810 int pos = ldom.
first()[2];
1811 flatBoundaryExchange(
1813 sendIdxsTemp, recvIdxsTemp,
1815 {0,1,3,2}, {0,1,4,3,5,2,7,6},
1825 if (ldom.
last()[0] == odom.first()[0]-1 && ldom.
first()[2] == odom.last()[2]+1 &&
1826 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1])) {
1828 negativeDiagonalExchange(
1830 sendIdxsTemp, recvIdxsTemp,
1837 if (ldom.
first()[0] == odom.last()[0]+1 && ldom.
last()[2] == odom.first()[2]-1 &&
1838 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1])) {
1840 negativeDiagonalExchange(
1842 recvIdxsTemp, sendIdxsTemp,
1850 if (ldom.
last()[1] == odom.first()[1]-1 && ldom.
first()[2] == odom.last()[2]+1 &&
1851 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0])) {
1852 negativeDiagonalExchange(
1854 sendIdxsTemp, recvIdxsTemp,
1861 if (ldom.
first()[1] == odom.last()[1]+1 && ldom.
last()[2] == odom.first()[2]-1 &&
1862 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0])) {
1863 negativeDiagonalExchange(
1865 recvIdxsTemp, sendIdxsTemp,
1873 if (ldom.
last()[0] == odom.first()[0]-1 && ldom.
first()[1] == odom.last()[1]+1 &&
1874 !(odom.last()[2] < ldom.
first()[2] || odom.first()[2] > ldom.
last()[2])) {
1875 negativeDiagonalExchange(
1877 sendIdxsTemp, recvIdxsTemp,
1884 if (ldom.
first()[0] == odom.last()[0]+1 && ldom.
last()[1] == odom.first()[1]-1 &&
1885 !(odom.last()[2] < ldom.
first()[2] || odom.first()[2] > ldom.
last()[2])) {
1886 negativeDiagonalExchange(
1888 recvIdxsTemp, sendIdxsTemp,
1898 if (ldom.
last()[0] == odom.first()[0]-1 && ldom.
last()[2] == odom.first()[2]-1 &&
1899 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1])) {
1900 positiveDiagonalExchange(
1903 sendIdxsTemp, recvIdxsTemp,
1910 if (ldom.
first()[0] == odom.last()[0]+1 && ldom.
first()[2] == odom.last()[2]+1 &&
1911 !(odom.last()[1] < ldom.
first()[1] || odom.first()[1] > ldom.
last()[1])) {
1912 positiveDiagonalExchange(
1915 recvIdxsTemp, sendIdxsTemp,
1923 if (ldom.
last()[1] == odom.first()[1]-1 && ldom.
last()[2] == odom.first()[2]-1 &&
1924 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0])) {
1925 positiveDiagonalExchange(
1928 sendIdxsTemp, recvIdxsTemp,
1935 if (ldom.
first()[1] == odom.last()[1]+1 && ldom.
first()[2] == odom.last()[2]+1 &&
1936 !(odom.last()[0] < ldom.
first()[0] || odom.first()[0] > ldom.
last()[0])) {
1937 positiveDiagonalExchange(
1940 recvIdxsTemp, sendIdxsTemp,
1948 if (ldom.
last()[0] == odom.first()[0]-1 && ldom.
last()[1] == odom.first()[1]-1 &&
1949 !(odom.last()[2] < ldom.
first()[2] || odom.first()[2] > ldom.
last()[2])) {
1950 positiveDiagonalExchange(
1953 sendIdxsTemp, recvIdxsTemp,
1960 if (ldom.
first()[0] == odom.last()[0]+1 && ldom.
first()[1] == odom.last()[1]+1 &&
1961 !(odom.last()[2] < ldom.
first()[2] || odom.first()[2] > ldom.
last()[2])) {
1962 positiveDiagonalExchange(
1965 recvIdxsTemp, sendIdxsTemp,
1979 for (
size_t i = 0; i < neighbors.size(); ++i) {
1980 sendIdxs.push_back(Kokkos::View<size_t*>(
"FEMvector::sendIdxs[" + std::to_string(i) +
1981 "]", sendIdxsTemp[i].size()));
1982 recvIdxs.push_back(Kokkos::View<size_t*>(
"FEMvector::recvIdxs[" + std::to_string(i) +
1983 "]", recvIdxsTemp[i].size()));
1984 auto sendView = sendIdxs[i];
1985 auto recvView = recvIdxs[i];
1986 auto hSendView = Kokkos::create_mirror_view(sendView);
1987 auto hRecvView = Kokkos::create_mirror_view(recvView);
1989 for (
size_t j = 0; j < sendIdxsTemp[i].size(); ++j) {
1990 hSendView(j) = sendIdxsTemp[i][j];
1993 for (
size_t j = 0; j < recvIdxsTemp[i].size(); ++j) {
1994 hRecvView(j) = recvIdxsTemp[i][j];
1997 Kokkos::deep_copy(sendView, hSendView);
1998 Kokkos::deep_copy(recvView, hRecvView);
2005 extents = (ldom.
last() - ldom.
first()) + 3;
2006 size_t nx = extents(0);
2007 size_t ny = extents(1);
2008 size_t nz = extents(2);
2009 size_t n = (nz-1)*(nx*(ny-1) + ny*(nx-1) + nx*ny) + nx*(ny-1) + ny*(nx-1);
PartBunch< T, Dim >::ConstIterator end(PartBunch< T, Dim > const &bunch)
PartBunch< T, Dim >::ConstIterator begin(PartBunch< T, Dim > const &bunch)
constexpr unsigned getNedelecNumElementDOFs(unsigned Dim, unsigned Order)
constexpr KOKKOS_INLINE_FUNCTION auto first()
Implementations for FFT constructor/destructor and transforms.
KOKKOS_INLINE_FUNCTION Vector< T, Dim > max(const Vector< T, Dim > &a, const Vector< T, Dim > &b)
KOKKOS_INLINE_FUNCTION Vector< T, Dim > min(const Vector< T, Dim > &a, const Vector< T, Dim > &b)
void parallel_for(const std::string &name, const ExecPolicy &policy, const FunctorType &functor)
void parallel_reduce(const std::string &name, const ExecPolicy &policy, const FunctorType &functor, ReducerArgument &&... reducer)
std::unique_ptr< mpi::Communicator > Comm
Kokkos::View< typename NPtr< T, Dim >::type, Properties... > view_type
1D vector used in the context of FEM.
const Kokkos::View< T * > & getView() const
Get underlying data view.
The FiniteElementSpace class handles the mesh index mapping to vertices and elements and is the base ...
A class representing a Nedelec space for finite element methods on a structured, rectilinear grid.
FEMVector< T > evaluateLoadVectorFunctor(const F &f) const
Assemble the load vector b of the system Ax = b, given a functional of the rhs.
KOKKOS_FUNCTION size_t getGlobalDOFIndex(const size_t &elementIndex, const size_t &localDOFIndex) const override
Get the global DOF index from the element index and local DOF.
detail::ViewType< T, 1 >::view_type ViewType
KOKKOS_FUNCTION Vector< size_t, numElementDOFs > getFEMVectorDOFIndices(const size_t &elementIndex, NDIndex< Dim > ldom) const
Get the DOF indices (vector of indices) corresponding to the position inside the FEMVector of an elem...
FEMVector< T > evaluateAx(FEMVector< T > &x, F &evalFunction) const
Assembly operations ///////////////////////////////////////////////.
T computeError(const FEMVector< T > &u_h, const F &u_sol) const
Error norm computations ///////////////////////////////////////////.
void initialize(UniformCartesian< T, Dim > &mesh, const Layout_t &layout)
Initialize a NedelecSpace object created with the default constructor.
void initializeElementIndices(const Layout_t &layout)
Initialize a Kokkos view containing the element indices.
KOKKOS_FUNCTION int getBoundarySide(const size_t &dofIdx) const
Returns which side the boundary is on.
KOKKOS_FUNCTION point_t getLocalDOFPosition(size_t localDOFIndex) const
Get the cartesion position of a local DOF in the reference element.
KOKKOS_FUNCTION point_t evaluateRefElementShapeFunctionCurl(const size_t &localDOF, const point_t &localPoint) const
Evaluate the curl of the shape function of a local degree of of freedom at ta given point in the refe...
FEMVector< T > createFEMVector3d() const
Implementation of the NedelecSpace::createFEMVector function for 3d.
KOKKOS_FUNCTION size_t numGlobalDOFs() const override
Degree of Freedom operations //////////////////////////////////////.
FEMVector< T > createFEMVector() const
FEMVector conversion and creation//////////////////////////////////.
KOKKOS_FUNCTION bool isDOFOnBoundary(const size_t &dofIdx) const
Check if a DOF is on the boundary of the mesh.
FEMVector< T > evaluateLoadVector(const FEMVector< point_t > &f) const
Assemble the load vector b of the system Ax = b, given a field of the right hand side defined at the ...
KOKKOS_FUNCTION point_t evaluateRefElementShapeFunction(const size_t &localDOF, const point_t &localPoint) const
Basis functions and gradients /////////////////////////////////////.
KOKKOS_FUNCTION Vector< size_t, numElementDOFs > getGlobalDOFIndices(const size_t &elementIndex) const override
Get the global DOF indices (vector of global DOF indices) of an element.
NedelecSpace(UniformCartesian< T, Dim > &mesh, ElementType &ref_element, const QuadratureType &quadrature, const Layout_t &layout)
Construct a new NedelecSpace object.
detail::ViewType< T, 1, Kokkos::MemoryTraits< Kokkos::Atomic > >::view_type AtomicViewType
KOKKOS_FUNCTION size_t getLocalDOFIndex(const size_t &elementIndex, const size_t &globalDOFIndex) const override
Get the elements local DOF from the element index and global DOF index.
KOKKOS_FUNCTION Vector< size_t, numElementDOFs > getLocalDOFIndices() const override
Get the local DOF indices (vector of local DOF indices) They are independent of the specific element ...
Kokkos::View< point_t * > reconstructToPoints(const Kokkos::View< point_t * > &positions, const FEMVector< T > &coef) const
Reconstructs function values at arbitrary points in the mesh given the Nedelec DOF coefficients.
FEMVector< T > createFEMVector2d() const
Implementation of the NedelecSpace::createFEMVector function for 2d.
const NDIndex_t & getLocalNDIndex() const
KOKKOS_INLINE_FUNCTION Vector< int, Dim > last() const
KOKKOS_INLINE_FUNCTION unsigned size() const noexcept
KOKKOS_INLINE_FUNCTION Vector< int, Dim > first() const
static constexpr unsigned dim
KOKKOS_INLINE_FUNCTION T dot(const Vector< T, Dim > &rhs) const
Timing::TimerRef TimerRef
static TimerRef getTimer(const char *nm)
static void stopTimer(TimerRef t)
static void startTimer(TimerRef t)