376 IpplTimings::TimerRef timerAxInit = IpplTimings::getTimer(
"Ax init");
377 IpplTimings::startTimer(timerAxInit);
381 FEMVector<T> resultVector = x.template skeletonCopy<T>();
385 this->quadrature_m.getWeightsForRefElement();
389 this->quadrature_m.getIntegrationNodesForRefElement();
395 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
396 for (
size_t i = 0; i < numElementDOFs; ++i) {
397 curl_b_q[k][i] = this->evaluateRefElementShapeFunctionCurl(i, q[k]);
398 val_b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
405 AtomicViewType resultView = resultVector.
getView();
409 auto ldom = layout_m.getLocalNDIndex();
411 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
412 using policy_type = Kokkos::RangePolicy<exec_space>;
415 IpplTimings::stopTimer(timerAxInit);
421 IpplTimings::TimerRef timerAxLocalMatrix = IpplTimings::getTimer(
"Ax local matrix");
422 IpplTimings::startTimer(timerAxLocalMatrix);
424 for (
size_t i = 0; i < numElementDOFs; ++i) {
425 for (
size_t j = 0; j < numElementDOFs; ++j) {
427 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
428 A[i][j] += w[k] * evalFunction(
435 IpplTimings::stopTimer(timerAxLocalMatrix);
438 IpplTimings::TimerRef timerAxLoop = IpplTimings::getTimer(
"Ax Loop");
439 IpplTimings::startTimer(timerAxLoop);
442 Kokkos::parallel_for(
443 "Loop over elements", policy_type(0, elementIndices.extent(0)),
444 KOKKOS_CLASS_LAMBDA(
const size_t index) {
445 const size_t elementIndex = elementIndices(index);
453 this->getFEMVectorDOFIndices(elementIndex, ldom);
463 for (i = 0; i < numElementDOFs; ++i) {
467 if (this->isDOFOnBoundary(I)) {
471 for (j = 0; j < numElementDOFs; ++j) {
475 if (this->isDOFOnBoundary(J)) {
479 resultView(vectorIndices[i]) += A[i][j] * view(vectorIndices[j]);
484 IpplTimings::stopTimer(timerAxLoop);
491 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
492 typename QuadratureType,
typename FieldType>
493 FEMVector<T> NedelecSpace<T, Dim, Order, ElementType, QuadratureType, FieldType>
495 QuadratureType, FieldType>::point_t>& f)
const {
499 this->quadrature_m.getWeightsForRefElement();
503 this->quadrature_m.getIntegrationNodesForRefElement();
511 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
512 for (
size_t i = 0; i < numElementDOFs; ++i) {
513 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
522 quadratureDOFDistances;
523 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
524 for (
size_t i = 0; i < numElementDOFs; ++i) {
525 point_t dofPos = getLocalDOFPosition(i);
527 quadratureDOFDistances[k][i] = Kokkos::sqrt(d.dot(d));
532 const T absDetDPhi = Kokkos::abs(this->ref_element_m.getDeterminantOfTransformationJacobian(
533 this->getElementMeshVertexPoints(zeroNdIndex)));
536 auto ldom = layout_m.getLocalNDIndex();
544 AtomicViewType atomic_view = resultVector.
getView();
545 typename detail::ViewType<point_t, 1>::view_type view = f.getView();
547 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
548 using policy_type = Kokkos::RangePolicy<exec_space>;
551 Kokkos::parallel_for(
552 "Loop over elements", policy_type(0, elementIndices.extent(0)),
553 KOKKOS_CLASS_LAMBDA(
size_t index) {
554 const size_t elementIndex = elementIndices(index);
559 this->getFEMVectorDOFIndices(elementIndex, ldom);
563 for (i = 0; i < numElementDOFs; ++i) {
564 size_t I = global_dofs[i];
565 if (this->isDOFOnBoundary(I)) {
572 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
577 for (
size_t j = 0; j < numElementDOFs; ++j) {
581 T dist = quadratureDOFDistances[k][j];
587 interpolatedVal += 1./dist * view(vectorIndices<:j:>);
591 interpolatedVal /= distSum;
594 contrib += w[k] * basis_q[k][i].dot(interpolatedVal) * absDetDPhi;
598 atomic_view(vectorIndices<:i:>) += contrib;
606 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
607 typename QuadratureType,
typename FieldType>
608 template <
typename F>
614 this->quadrature_m.getWeightsForRefElement();
618 this->quadrature_m.getIntegrationNodesForRefElement();
624 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
625 for (
size_t i = 0; i < numElementDOFs; ++i) {
626 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
632 const T absDetDPhi = Kokkos::abs(this->ref_element_m.getDeterminantOfTransformationJacobian(
633 this->getElementMeshVertexPoints(zeroNdIndex)));
636 auto ldom = layout_m.getLocalNDIndex();
644 AtomicViewType atomic_view = resultVector.
getView();
646 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
647 using policy_type = Kokkos::RangePolicy<exec_space>;
651 Kokkos::parallel_for(
652 "Loop over elements", policy_type(0, elementIndices.extent(0)),
653 KOKKOS_CLASS_LAMBDA(
size_t index) {
654 const size_t elementIndex = elementIndices(index);
659 this->getFEMVectorDOFIndices(elementIndex, ldom);
664 for (i = 0; i < numElementDOFs; ++i) {
668 if (this->isDOFOnBoundary(I)) {
674 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
676 point_t pos = this->ref_element_m.localToGlobal(
677 this->getElementMeshVertexPoints(this->getElementNDIndex(elementIndex)),
681 point_t interpolatedVal = f(pos);
684 contrib += w[k] * basis_q[k][i].dot(interpolatedVal) * absDetDPhi;
688 atomic_view(vectorIndices[i]) += contrib;
702 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
703 typename QuadratureType,
typename FieldType>
708 QuadratureType, FieldType>::point_t& localPoint)
const {
711 assert(localDOF < numElementDOFs &&
"The local vertex index is invalid");
713 assert(this->ref_element_m.isPointInRefElement(localPoint)
714 &&
"Point is not in reference element");
720 if constexpr (Dim == 2) {
725 case 0: result(0) = 1 - y;
break;
726 case 1: result(1) = 1 - x;
break;
727 case 2: result(0) = y;
break;
728 case 3: result(1) = x;
break;
730 }
else if constexpr (Dim == 3) {
736 case 0: result(0) = y*z - y - z + 1;
break;
737 case 1: result(1) = x*z - x - z + 1;
break;
738 case 2: result(0) = y*(1 - z);
break;
739 case 3: result(1) = x*(1 - z);
break;
740 case 4: result(2) = x*y - x - y + 1;
break;
741 case 5: result(2) = x*(1 - y);
break;
742 case 6: result(2) = x*y;
break;
743 case 7: result(2) = y*(1 - x);
break;
744 case 8: result(0) = z*(1 - y);
break;
745 case 9: result(1) = z*(1 - x);
break;
746 case 10: result(0) = y*z;
break;
747 case 11: result(1) = x*z;
break;
756 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
757 typename QuadratureType,
typename FieldType>
758 KOKKOS_FUNCTION
typename NedelecSpace<T, Dim, Order, ElementType,
759 QuadratureType, FieldType>::point_t
763 QuadratureType, FieldType>::point_t& localPoint)
const {
768 if constexpr (Dim == 2) {
777 case 0: result(0) = 1;
break;
778 case 1: result(0) = -1;
break;
779 case 2: result(0) = -1;
break;
780 case 3: result(0) = 1;
break;
788 case 0: result(0) = 0; result(1) = -1+y; result(2) = 1-z;
break;
789 case 1: result(0) = 1-x; result(1) = 0; result(2) = -1+z;
break;
790 case 2: result(0) = 0; result(1) = -y; result(2) = -1+z;
break;
791 case 3: result(0) = x; result(1) = 0; result(2) = 1-z;
break;
792 case 4: result(0) = -1+x; result(1) = 1-y; result(2) = 0;
break;
793 case 5: result(0) = -x; result(1) = -1+y; result(2) = 0;
break;
794 case 6: result(0) = x; result(1) = -y; result(2) = 0;
break;
795 case 7: result(0) = 1-x; result(1) = y; result(2) = 0;
break;
796 case 8: result(0) = 0; result(1) = 1-y; result(2) = z;
break;
797 case 9: result(0) = -1+x; result(1) = 0; result(2) = -z;
break;
798 case 10: result(0) = 0; result(1) = y; result(2) = -z;
break;
799 case 11: result(0) = -x; result(1) = 0; result(2) = z;
break;
812 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
813 typename QuadratureType,
typename FieldType>
818 if constexpr (Dim == 2) {
819 return createFEMVector2d();
821 return createFEMVector3d();
826 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
827 typename QuadratureType,
typename FieldType>
828 Kokkos::View<
typename NedelecSpace<T, Dim, Order, ElementType, QuadratureType,
829 FieldType>::point_t*>
831 const Kokkos::View<
typename NedelecSpace<T, Dim, Order, ElementType, QuadratureType,
832 FieldType>::point_t*>& positions,
const FEMVector<T>& coef)
const {
835 auto ldom = layout_m.getLocalNDIndex();
838 auto gdom = layout_m.getDomain();
839 indices_t gextent = gdom.last() - gdom.first();
842 point_t domainSize = (this->nr_m-1) * this->hr_m;
845 auto coefView = coef.
getView();
847 Kokkos::View<point_t*> outView(
"reconstructed Func values at points", positions.extent(0));
849 Kokkos::parallel_for(
"reconstructToPoints", positions.extent(0),
850 KOKKOS_CLASS_LAMBDA(
size_t i) {
854 indices_t elemIdx = ((pos - this->origin_m) / domainSize) * gextent;
862 for (
size_t d = 0; d < Dim; ++d) {
863 if (elemIdx<:d:> >=
static_cast<size_t>(ldom.last()<:d:>)) {
871 this->getFEMVectorDOFIndices(elemIdx, ldom);
875 point_t locPos = pos - (elemIdx * this->hr_m + this->origin_m);
876 locPos /= this->hr_m;
882 for (
size_t d = 0; d < Dim; ++d) {
883 locPos<:d:> = Kokkos::min(T(1), locPos<:d:>);
884 locPos<:d:> = Kokkos::max(T(0), locPos<:d:>);
891 for (
size_t j = 0; j < numElementDOFs; ++j) {
892 point_t funcVal = this->evaluateRefElementShapeFunction(j, locPos);
893 val += funcVal*coefView(vectorIndices<:j:>);
909 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
910 typename QuadratureType,
typename FieldType>
911 template <
typename F>
914 if (this->quadrature_m.getOrder() < (2 * Order + 1)) {
917 "Order of quadrature rule for error computation should be > 2*p + 1");
922 this->quadrature_m.getWeightsForRefElement();
926 this->quadrature_m.getIntegrationNodesForRefElement();
930 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
931 for (
size_t i = 0; i < numElementDOFs; ++i) {
932 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
939 const T absDetDPhi = Kokkos::abs(this->ref_element_m
940 .getDeterminantOfTransformationJacobian(this->getElementMeshVertexPoints(zeroNdIndex)));
946 auto ldom = layout_m.getLocalNDIndex();
948 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
949 using policy_type = Kokkos::RangePolicy<exec_space>;
955 Kokkos::parallel_reduce(
"Compute error over elements",
956 policy_type(0, elementIndices.extent(0)),
957 KOKKOS_CLASS_LAMBDA(
size_t index,
double& local) {
958 const size_t elementIndex = elementIndices(index);
963 this->getFEMVectorDOFIndices(elementIndex, ldom);
968 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
971 point_t val_u_sol = u_sol(this->ref_element_m.localToGlobal(
972 this->getElementMeshVertexPoints(this->getElementNDIndex(elementIndex)),
978 for (
size_t j = 0; j < numElementDOFs; ++j) {
980 val_u_h += basis_q[k][j] * view(vectorIndices[j]);
984 point_t dif = (val_u_sol - val_u_h);
986 contrib += w[k] * x * absDetDPhi;
990 Kokkos::Sum<double>(error)
994 T global_error = 0.0;
995 Comm->allreduce(error, global_error, 1, std::plus<T>());
997 return Kokkos::sqrt(global_error);
1000 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1001 typename QuadratureType,
typename FieldType>
1005 bool onBoundary =
false;
1006 if constexpr (Dim == 2) {
1007 size_t nx = this->nr_m[0];
1008 size_t ny = this->nr_m[1];
1010 bool sVal = (dofIdx < nx -1);
1011 onBoundary = onBoundary || sVal;
1013 onBoundary = onBoundary || (dofIdx > nx*(ny-1) + ny*(nx-1) - nx);
1015 onBoundary = onBoundary || ((dofIdx >= nx-1) && (dofIdx - (nx-1)) % (2*nx - 1) == 0);
1017 onBoundary = onBoundary || ((dofIdx >= 2*nx-2) && ((dofIdx - 2*nx + 2) % (2*nx - 1) == 0));
1020 if constexpr (Dim == 3) {
1021 size_t nx = this->nr_m[0];
1022 size_t ny = this->nr_m[1];
1023 size_t nz = this->nr_m[2];
1025 size_t zOffset = dofIdx / (nx*(ny-1) + ny*(nx-1) + nx*ny);
1028 if (dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset >= (nx*(ny-1) + ny*(nx-1))) {
1032 size_t f = dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset
1033 - (nx*(ny-1) + ny*(nx-1));
1035 size_t yOffset = f / nx;
1037 onBoundary = onBoundary || yOffset == 0;
1039 onBoundary = onBoundary || yOffset == ny-1;
1041 size_t xOffset = f % nx;
1043 onBoundary = onBoundary || xOffset == 0;
1045 onBoundary = onBoundary || xOffset == nx-1;
1050 onBoundary = onBoundary || zOffset == 0;
1052 onBoundary = onBoundary || zOffset == nz-1;
1054 size_t f = dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset;
1055 size_t yOffset = f / (2*nx - 1);
1056 size_t xOffset = f - (2*nx - 1)*yOffset;
1058 if (xOffset < (nx-1)) {
1064 onBoundary = onBoundary || yOffset == 0;
1066 onBoundary = onBoundary || yOffset == ny-1;
1072 if (xOffset >= nx-1) {
1077 onBoundary = onBoundary || xOffset == 0;
1079 onBoundary = onBoundary || xOffset == nx-1;
1088 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1089 typename QuadratureType,
typename FieldType>
1093 if constexpr (Dim == 2) {
1094 size_t nx = this->nr_m[0];
1095 size_t ny = this->nr_m[1];
1098 if (dofIdx < nx -1)
return 0;
1100 if ((dofIdx - (nx-1)) % (2*nx - 1) == 0)
return 1;
1102 if (dofIdx > nx*(ny-1) + ny*(nx-1) - nx)
return 2;
1104 if ((dofIdx >= 2*nx-2) && (dofIdx - 2*nx + 2) % (2*nx - 1) == 0)
return 3;
1109 if constexpr (Dim == 3) {
1110 size_t nx = this->nr_m[0];
1111 size_t ny = this->nr_m[1];
1112 size_t nz = this->nr_m[2];
1114 size_t zOffset = dofIdx / (nx*(ny-1) + ny*(nx-1) + nx*ny);
1117 if (dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset >= (nx*(ny-1) + ny*(nx-1))) {
1121 size_t f = dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset
1122 - (nx*(ny-1) + ny*(nx-1));
1124 size_t yOffset = f / nx;
1126 if (yOffset == 0)
return 0;
1128 if (yOffset == ny-1)
return 2;
1130 size_t xOffset = f % nx;
1132 if (xOffset == 0)
return 1;
1134 if (xOffset == nx-1)
return 3;
1139 if (zOffset == 0)
return 4;
1141 if (zOffset == nz-1)
return 5;
1143 size_t f = dofIdx - (nx*(ny-1) + ny*(nx-1) + nx*ny)*zOffset;
1144 size_t yOffset = f / (2*nx - 1);
1145 size_t xOffset = f - (2*nx - 1)*yOffset;
1147 if (xOffset < (nx-1)) {
1153 if (yOffset == 0)
return 0;
1155 if (yOffset == ny-1)
return 2;
1161 if (xOffset >= nx-1) {
1166 if (xOffset == 0)
return 1;
1168 if (xOffset == nx-1)
return 3;
1177 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1178 typename QuadratureType,
typename FieldType>
1205 auto ldom = layout_m.getLocalNDIndex();
1206 auto doms = layout_m.getHostLocalDomains();
1210 std::vector<size_t> neighbors;
1211 std::vector< Kokkos::View<size_t*> > sendIdxs;
1212 std::vector< Kokkos::View<size_t*> > recvIdxs;
1213 std::vector< std::vector<size_t> > sendIdxsTemp;
1214 std::vector< std::vector<size_t> > recvIdxsTemp;
1218 size_t myRank = Comm->rank();
1219 for (
size_t i = 0; i < doms.extent(0); ++i) {
1224 auto odom = doms(i);
1227 if (ldom.last()[0] == odom.first()[0]-1 &&
1228 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1])) {
1230 int begin = std::max(odom.first()[1], ldom.first()[1]);
1231 int end = std::min(odom.last()[1], ldom.last()[1]);
1232 int pos = ldom.last()[0];
1235 neighbors.push_back(i);
1236 sendIdxsTemp.push_back(std::vector<size_t>());
1237 recvIdxsTemp.push_back(std::vector<size_t>());
1238 size_t idx = neighbors.size() - 1;
1241 indices_t elementPosHalo(0);
1242 elementPosHalo(0) = pos;
1243 indices_t elementPosSend(0);
1244 elementPosSend(0) = pos;
1245 for (
int k = begin; k <= end; ++k) {
1246 elementPosHalo(1) = k;
1247 elementPosSend(1) = k;
1249 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1250 recvIdxsTemp[idx].push_back(dofIndicesHalo[3]);
1252 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1253 sendIdxsTemp[idx].push_back(dofIndicesSend[0]);
1254 sendIdxsTemp[idx].push_back(dofIndicesSend[1]);
1257 if (end == layout_m.getDomain().last()[1] || ldom.last()[1] > odom.last()[1]) {
1258 elementPosSend(1) = end;
1259 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1261 sendIdxsTemp[idx].push_back(dofIndicesSend[2]);
1266 if (ldom.first()[0] == odom.last()[0]+1 &&
1267 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1])) {
1269 int begin = std::max(odom.first()[1], ldom.first()[1]);
1270 int end = std::min(odom.last()[1], ldom.last()[1]);
1271 int pos = ldom.first()[0];
1274 neighbors.push_back(i);
1275 sendIdxsTemp.push_back(std::vector<size_t>());
1276 recvIdxsTemp.push_back(std::vector<size_t>());
1277 size_t idx = neighbors.size() - 1;
1280 indices_t elementPosHalo(0);
1281 elementPosHalo(0) = pos-1;
1282 indices_t elementPosSend(0);
1283 elementPosSend(0) = pos;
1284 for (
int k = begin; k <= end; ++k) {
1285 elementPosHalo(1) = k;
1286 elementPosSend(1) = k;
1288 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1289 recvIdxsTemp[idx].push_back(dofIndicesHalo[0]);
1290 recvIdxsTemp[idx].push_back(dofIndicesHalo[1]);
1292 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1293 sendIdxsTemp[idx].push_back(dofIndicesSend[1]);
1296 if (end == layout_m.getDomain().last()[1] || odom.last()[1] > ldom.last()[1]) {
1297 elementPosHalo(1) = end;
1298 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1300 recvIdxsTemp[idx].push_back(dofIndicesHalo[2]);
1305 if (ldom.last()[1] == odom.first()[1]-1 &&
1306 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0])) {
1308 int begin = std::max(odom.first()[0], ldom.first()[0]);
1309 int end = std::min(odom.last()[0], ldom.last()[0]);
1310 int pos = ldom.last()[1];
1313 neighbors.push_back(i);
1314 sendIdxsTemp.push_back(std::vector<size_t>());
1315 recvIdxsTemp.push_back(std::vector<size_t>());
1316 size_t idx = neighbors.size() - 1;
1319 indices_t elementPosHalo(0);
1320 elementPosHalo(1) = pos;
1321 indices_t elementPosSend(0);
1322 elementPosSend(1) = pos;
1323 for (
int k = begin; k <= end; ++k) {
1324 elementPosHalo(0) = k;
1325 elementPosSend(0) = k;
1327 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1328 recvIdxsTemp[idx].push_back(dofIndicesHalo[2]);
1330 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1331 sendIdxsTemp[idx].push_back(dofIndicesSend[0]);
1332 sendIdxsTemp[idx].push_back(dofIndicesSend[1]);
1335 if (end == layout_m.getDomain().last()[0] || ldom.last()[0] > odom.last()[0]) {
1336 elementPosSend(0) = end;
1337 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1339 sendIdxsTemp[idx].push_back(dofIndicesSend[3]);
1344 if (ldom.first()[1] == odom.last()[1]+1 &&
1345 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0])) {
1347 int begin = std::max(odom.first()[0], ldom.first()[0]);
1348 int end = std::min(odom.last()[0], ldom.last()[0]);
1349 int pos = ldom.first()[1];
1352 neighbors.push_back(i);
1353 sendIdxsTemp.push_back(std::vector<size_t>());
1354 recvIdxsTemp.push_back(std::vector<size_t>());
1355 size_t idx = neighbors.size() - 1;
1358 indices_t elementPosHalo(0);
1359 elementPosHalo(1) = pos-1;
1360 indices_t elementPosSend(0);
1361 elementPosSend(1) = pos;
1362 for (
int k = begin; k <= end; ++k) {
1363 elementPosHalo(0) = k;
1364 elementPosSend(0) = k;
1366 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1367 recvIdxsTemp[idx].push_back(dofIndicesHalo[0]);
1368 recvIdxsTemp[idx].push_back(dofIndicesHalo[1]);
1370 auto dofIndicesSend = getFEMVectorDOFIndices(elementPosSend, ldom);
1371 sendIdxsTemp[idx].push_back(dofIndicesSend[0]);
1374 if (end == layout_m.getDomain().last()[0] || odom.last()[0] > ldom.last()[0]) {
1375 elementPosHalo(0) = end;
1376 auto dofIndicesHalo = getFEMVectorDOFIndices(elementPosHalo, ldom);
1378 recvIdxsTemp[idx].push_back(dofIndicesHalo[3]);
1388 for (
size_t i = 0; i < neighbors.size(); ++i) {
1389 sendIdxs.push_back(Kokkos::View<size_t*>(
"FEMvector::sendIdxs[" + std::to_string(i) +
1390 "]", sendIdxsTemp[i].size()));
1391 recvIdxs.push_back(Kokkos::View<size_t*>(
"FEMvector::recvIdxs[" + std::to_string(i) +
1392 "]", recvIdxsTemp[i].size()));
1393 auto sendView = sendIdxs[i];
1394 auto recvView = recvIdxs[i];
1395 auto hSendView = Kokkos::create_mirror_view(sendView);
1396 auto hRecvView = Kokkos::create_mirror_view(recvView);
1398 for (
size_t j = 0; j < sendIdxsTemp[i].size(); ++j) {
1399 hSendView(j) = sendIdxsTemp[i][j];
1402 for (
size_t j = 0; j < recvIdxsTemp[i].size(); ++j) {
1403 hRecvView(j) = recvIdxsTemp[i][j];
1406 Kokkos::deep_copy(sendView, hSendView);
1407 Kokkos::deep_copy(recvView, hRecvView);
1413 indices_t extents(0);
1414 extents = (ldom.last() - ldom.first()) + 3;
1415 size_t nx = extents(0);
1416 size_t ny = extents(1);
1417 size_t n = nx*(ny-1) + ny*(nx-1);
1418 FEMVector<T> vec(n, neighbors, sendIdxs, recvIdxs);
1425 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1426 typename QuadratureType,
typename FieldType>
1427 FEMVector<T> NedelecSpace<T, Dim, Order, ElementType, QuadratureType, FieldType>
1428 ::createFEMVector3d()
const{
1464 auto ldom = layout_m.getLocalNDIndex();
1465 auto doms = layout_m.getHostLocalDomains();
1469 std::vector<size_t> neighbors;
1470 std::vector< Kokkos::View<size_t*> > sendIdxs;
1471 std::vector< Kokkos::View<size_t*> > recvIdxs;
1472 std::vector< std::vector<size_t> > sendIdxsTemp;
1473 std::vector< std::vector<size_t> > recvIdxsTemp;
1500 auto flatBoundaryExchange = [
this, &neighbors, &ldom](
1501 size_t i,
size_t a,
size_t f,
size_t s,
1502 std::vector<std::vector<size_t> >& va, std::vector<std::vector<size_t> >& vb,
1504 const std::vector<size_t>& idxsA,
const std::vector<size_t>& idxsB,
1505 NDIndex<3>& adom, NDIndex<3>& bdom) {
1507 int beginF = std::max(bdom.first()[f], adom.first()[f]);
1508 int endF = std::min(bdom.last()[f], adom.last()[f]);
1509 int beginS = std::max(bdom.first()[s], adom.first()[s]);
1510 int endS = std::min(bdom.last()[s], adom.last()[s]);
1512 neighbors.push_back(i);
1513 va.push_back(std::vector<size_t>());
1514 vb.push_back(std::vector<size_t>());
1515 size_t idx = neighbors.size() - 1;
1518 indices_t elementPosA(0);
1519 elementPosA(a) = posA;
1520 indices_t elementPosB(0);
1521 elementPosB(a) = posB;
1525 for (
int k = beginF; k <= endF; ++k) {
1528 for (
int l = beginS; l <= endS; ++l) {
1532 auto dofIndicesA = this->getFEMVectorDOFIndices(elementPosA, ldom);
1533 va[idx].push_back(dofIndicesA[idxsA[0]]);
1534 va[idx].push_back(dofIndicesA[idxsA[1]]);
1536 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1537 vb[idx].push_back(dofIndicesB[idxsB[0]]);
1538 vb[idx].push_back(dofIndicesB[idxsB[1]]);
1539 vb[idx].push_back(dofIndicesB[idxsB[2]]);
1548 if (endF == layout_m.getDomain().last()[f] ||
1549 bdom.last()[f] > adom.last()[f]) {
1550 va[idx].push_back(dofIndicesA[idxsA[2]]);
1553 if (endF == layout_m.getDomain().last()[f] ||
1554 adom.last()[f] > bdom.last()[f]) {
1555 vb[idx].push_back(dofIndicesB[idxsB[3]]);
1556 vb[idx].push_back(dofIndicesB[idxsB[4]]);
1563 if (bdom.first()[f] < adom.first()[f]) {
1564 indices_t tmpPos = elementPosA;
1565 tmpPos(f) = beginF-1;
1566 auto dofIndicestmp = this->getFEMVectorDOFIndices(tmpPos, ldom);
1567 va[idx].push_back(dofIndicestmp[idxsA[0]]);
1568 va[idx].push_back(dofIndicestmp[idxsA[1]]);
1579 if (endS == layout_m.getDomain().last()[s] || bdom.last()[s] > adom.last()[s]) {
1580 elementPosA(s) = endS;
1581 auto dofIndicesA = this->getFEMVectorDOFIndices(elementPosA, ldom);
1582 va[idx].push_back(dofIndicesA[idxsA[3]]);
1585 if (endS == layout_m.getDomain().last()[s] || adom.last()[s] > bdom.last()[s]) {
1586 elementPosB(s) = endS;
1587 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1588 vb[idx].push_back(dofIndicesB[idxsB[5]]);
1589 vb[idx].push_back(dofIndicesB[idxsB[6]]);
1596 if (bdom.first()[f] < adom.first()[f]) {
1597 indices_t tmpPos = elementPosA;
1598 tmpPos(s) = beginS-1;
1599 auto dofIndicestmp = this->getFEMVectorDOFIndices(tmpPos, ldom);
1600 va[idx].push_back(dofIndicestmp[idxsA[0]]);
1601 va[idx].push_back(dofIndicestmp[idxsA[1]]);
1606 if ((endF == layout_m.getDomain().last()[f] || adom.last()[f] > bdom.last()[f]) &&
1607 (endS == layout_m.getDomain().last()[s] || adom.last()[s] > bdom.last()[s])) {
1608 elementPosB(f) = endF;
1609 elementPosB(s) = endS;
1610 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1611 vb[idx].push_back(dofIndicesB[idxsB[7]]);
1634 auto negativeDiagonalExchange = [
this, &neighbors, &ldom](
1635 size_t i,
size_t a,
size_t f,
size_t s,
int ao,
int bo,
1636 std::vector<std::vector<size_t> >& va, std::vector<std::vector<size_t> >& vb,
1637 const std::vector<size_t>& idxsA,
const std::vector<size_t>& idxsB,
1640 neighbors.push_back(i);
1641 va.push_back(std::vector<size_t>());
1642 vb.push_back(std::vector<size_t>());
1643 size_t idx = neighbors.size() - 1;
1645 indices_t elementPosA(0);
1646 elementPosA(f) = ldom.last()[f];
1647 elementPosA(s) = ldom.first()[s] + ao;
1649 indices_t elementPosB(0);
1650 elementPosB(f) = ldom.last()[f];
1651 elementPosB(s) = ldom.first()[s] + bo;
1653 int begin = std::max(odom.first()[a], ldom.first()[a]);
1654 int end = std::min(odom.last()[a], ldom.last()[a]);
1656 for (
int k = begin; k <= end; ++k) {
1660 auto dofIndicesA = this->getFEMVectorDOFIndices(elementPosA, ldom);
1661 va[idx].push_back(dofIndicesA[idxsA[0]]);
1662 va[idx].push_back(dofIndicesA[idxsA[1]]);
1664 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1665 vb[idx].push_back(dofIndicesB[idxsB[0]]);
1666 vb[idx].push_back(dofIndicesB[idxsB[1]]);
1688 auto positiveDiagonalExchange = [
this, &neighbors, &ldom](
1689 size_t i,
size_t a,
size_t f,
size_t s,
1690 indices_t posA, indices_t posB,
1691 std::vector<std::vector<size_t> >& va, std::vector<std::vector<size_t> >& vb,
1692 const std::vector<size_t>& idxsA,
const std::vector<size_t>& idxsB,
1695 neighbors.push_back(i);
1696 va.push_back(std::vector<size_t>());
1697 vb.push_back(std::vector<size_t>());
1698 size_t idx = neighbors.size() - 1;
1700 indices_t elementPosA(0);
1701 elementPosA(f) = posA(f);
1702 elementPosA(s) = posA(s);
1704 indices_t elementPosB(0);
1705 elementPosB(f) = posB(f);
1706 elementPosB(s) = posB(s);
1708 int begin = std::max(odom.first()[a], ldom.first()[a]);
1709 int end = std::min(odom.last()[a], ldom.last()[a]);
1711 for (
int k = begin; k <= end; ++k) {
1715 auto dofIndicesA = this->getFEMVectorDOFIndices(elementPosA, ldom);
1716 va[idx].push_back(dofIndicesA[idxsA[0]]);
1717 va[idx].push_back(dofIndicesA[idxsA[1]]);
1718 va[idx].push_back(dofIndicesA[idxsA[2]]);
1720 auto dofIndicesB = this->getFEMVectorDOFIndices(elementPosB, ldom);
1721 vb[idx].push_back(dofIndicesB[idxsB[0]]);
1732 size_t myRank = Comm->rank();
1733 for (
size_t i = 0; i < doms.extent(0); ++i) {
1738 auto odom = doms(i);
1741 if (ldom.last()[0] == odom.first()[0]-1 &&
1742 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1]) &&
1743 !(odom.last()[2] < ldom.first()[2] || odom.first()[2] > ldom.last()[2])) {
1745 int pos = ldom.last()[0];
1746 flatBoundaryExchange(
1748 recvIdxsTemp, sendIdxsTemp,
1750 {3,5,6,11}, {0,1,4,2,7,8,9,10},
1756 if (ldom.first()[0] == odom.last()[0]+1 &&
1757 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1]) &&
1758 !(odom.last()[2] < ldom.first()[2] || odom.first()[2] > ldom.last()[2])) {
1760 int pos = ldom.first()[0];
1761 flatBoundaryExchange(
1763 sendIdxsTemp, recvIdxsTemp,
1765 {1,4,7,9}, {0,1,4,2,7,8,9,10},
1771 if (ldom.last()[1] == odom.first()[1]-1 &&
1772 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0]) &&
1773 !(odom.last()[2] < ldom.first()[2] || odom.first()[2] > ldom.last()[2])) {
1775 int pos = ldom.last()[1];
1776 flatBoundaryExchange(
1778 recvIdxsTemp, sendIdxsTemp,
1780 {2,7,6,10}, {0,1,4,3,5,8,9,11},
1786 if (ldom.first()[1] == odom.last()[1]+1 &&
1787 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0]) &&
1788 !(odom.last()[2] < ldom.first()[2] || odom.first()[2] > ldom.last()[2])) {
1790 int pos = ldom.first()[1];
1791 flatBoundaryExchange(
1793 sendIdxsTemp, recvIdxsTemp,
1795 {0,4,5,8}, {0,1,4,3,5,8,9,11},
1802 if (ldom.last()[2] == odom.first()[2]-1 &&
1803 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0]) &&
1804 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1])) {
1806 int pos = ldom.last()[2];
1807 flatBoundaryExchange(
1809 recvIdxsTemp, sendIdxsTemp,
1811 {8,9,11,10}, {0,1,4,3,5,2,7,6},
1817 if (ldom.first()[2] == odom.last()[2]+1 &&
1818 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0]) &&
1819 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1])) {
1821 int pos = ldom.first()[2];
1822 flatBoundaryExchange(
1824 sendIdxsTemp, recvIdxsTemp,
1826 {0,1,3,2}, {0,1,4,3,5,2,7,6},
1836 if (ldom.last()[0] == odom.first()[0]-1 && ldom.first()[2] == odom.last()[2]+1 &&
1837 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1])) {
1839 negativeDiagonalExchange(
1841 sendIdxsTemp, recvIdxsTemp,
1848 if (ldom.first()[0] == odom.last()[0]+1 && ldom.last()[2] == odom.first()[2]-1 &&
1849 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1])) {
1851 negativeDiagonalExchange(
1853 recvIdxsTemp, sendIdxsTemp,
1861 if (ldom.last()[1] == odom.first()[1]-1 && ldom.first()[2] == odom.last()[2]+1 &&
1862 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0])) {
1863 negativeDiagonalExchange(
1865 sendIdxsTemp, recvIdxsTemp,
1872 if (ldom.first()[1] == odom.last()[1]+1 && ldom.last()[2] == odom.first()[2]-1 &&
1873 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0])) {
1874 negativeDiagonalExchange(
1876 recvIdxsTemp, sendIdxsTemp,
1884 if (ldom.last()[0] == odom.first()[0]-1 && ldom.first()[1] == odom.last()[1]+1 &&
1885 !(odom.last()[2] < ldom.first()[2] || odom.first()[2] > ldom.last()[2])) {
1886 negativeDiagonalExchange(
1888 sendIdxsTemp, recvIdxsTemp,
1895 if (ldom.first()[0] == odom.last()[0]+1 && ldom.last()[1] == odom.first()[1]-1 &&
1896 !(odom.last()[2] < ldom.first()[2] || odom.first()[2] > ldom.last()[2])) {
1897 negativeDiagonalExchange(
1899 recvIdxsTemp, sendIdxsTemp,
1909 if (ldom.last()[0] == odom.first()[0]-1 && ldom.last()[2] == odom.first()[2]-1 &&
1910 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1])) {
1911 positiveDiagonalExchange(
1913 ldom.last(), ldom.last(),
1914 sendIdxsTemp, recvIdxsTemp,
1921 if (ldom.first()[0] == odom.last()[0]+1 && ldom.first()[2] == odom.last()[2]+1 &&
1922 !(odom.last()[1] < ldom.first()[1] || odom.first()[1] > ldom.last()[1])) {
1923 positiveDiagonalExchange(
1925 ldom.first()-1, ldom.first(),
1926 recvIdxsTemp, sendIdxsTemp,
1934 if (ldom.last()[1] == odom.first()[1]-1 && ldom.last()[2] == odom.first()[2]-1 &&
1935 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0])) {
1936 positiveDiagonalExchange(
1938 ldom.last(), ldom.last(),
1939 sendIdxsTemp, recvIdxsTemp,
1946 if (ldom.first()[1] == odom.last()[1]+1 && ldom.first()[2] == odom.last()[2]+1 &&
1947 !(odom.last()[0] < ldom.first()[0] || odom.first()[0] > ldom.last()[0])) {
1948 positiveDiagonalExchange(
1950 ldom.first()-1, ldom.first(),
1951 recvIdxsTemp, sendIdxsTemp,
1959 if (ldom.last()[0] == odom.first()[0]-1 && ldom.last()[1] == odom.first()[1]-1 &&
1960 !(odom.last()[2] < ldom.first()[2] || odom.first()[2] > ldom.last()[2])) {
1961 positiveDiagonalExchange(
1963 ldom.last(), ldom.last(),
1964 sendIdxsTemp, recvIdxsTemp,
1971 if (ldom.first()[0] == odom.last()[0]+1 && ldom.first()[1] == odom.last()[1]+1 &&
1972 !(odom.last()[2] < ldom.first()[2] || odom.first()[2] > ldom.last()[2])) {
1973 positiveDiagonalExchange(
1975 ldom.first()-1, ldom.first(),
1976 recvIdxsTemp, sendIdxsTemp,
1990 for (
size_t i = 0; i < neighbors.size(); ++i) {
1991 sendIdxs.push_back(Kokkos::View<size_t*>(
"FEMvector::sendIdxs[" + std::to_string(i) +
1992 "]", sendIdxsTemp[i].size()));
1993 recvIdxs.push_back(Kokkos::View<size_t*>(
"FEMvector::recvIdxs[" + std::to_string(i) +
1994 "]", recvIdxsTemp[i].size()));
1995 auto sendView = sendIdxs[i];
1996 auto recvView = recvIdxs[i];
1997 auto hSendView = Kokkos::create_mirror_view(sendView);
1998 auto hRecvView = Kokkos::create_mirror_view(recvView);
2000 for (
size_t j = 0; j < sendIdxsTemp[i].size(); ++j) {
2001 hSendView(j) = sendIdxsTemp[i][j];
2004 for (
size_t j = 0; j < recvIdxsTemp[i].size(); ++j) {
2005 hRecvView(j) = recvIdxsTemp[i][j];
2008 Kokkos::deep_copy(sendView, hSendView);
2009 Kokkos::deep_copy(recvView, hRecvView);
2015 indices_t extents(0);
2016 extents = (ldom.last() - ldom.first()) + 3;
2017 size_t nx = extents(0);
2018 size_t ny = extents(1);
2019 size_t nz = extents(2);
2020 size_t n = (nz-1)*(nx*(ny-1) + ny*(nx-1) + nx*ny) + nx*(ny-1) + ny*(nx-1);
2021 FEMVector<T> vec(n, neighbors, sendIdxs, recvIdxs);