311 KOKKOS_FUNCTION
typename LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
315 const size_t& localDOF,
316 const LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
317 FieldRHS>::point_t& localPoint)
const {
319 static_assert(Order == 1 &&
"Only order 1 is supported at the moment");
322 assert(localDOF < numElementDOFs &&
"The local vertex index is invalid");
324 assert(this->ref_element_m.isPointInRefElement(localPoint)
325 &&
"Point is not in reference element");
328 const vertex_points_t local_vertex_points = this->ref_element_m.getLocalVertices();
330 const point_t& local_vertex_point = local_vertex_points[localDOF];
338 for (
size_t d = 0; d < Dim; d++) {
342 for (
size_t d2 = 0; d2 < Dim; d2++) {
344 if (localPoint[d] < local_vertex_point[d]) {
350 if (localPoint[d2] < local_vertex_point[d2]) {
351 product *= localPoint[d2];
353 product *= 1.0 - localPoint[d2];
358 gradient[d] = product;
368 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
369 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
370 template <
typename F>
371 FieldLHS
LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
372 FieldRHS>::evaluateAx(FieldLHS& field, F& evalFunction) {
376 static IpplTimings::TimerRef evalAx = IpplTimings::getTimer(
"evaluateAx");
377 static IpplTimings::TimerRef evalAx_outer = IpplTimings::getTimer(
"evaluateAx: outer loop");
378 static IpplTimings::TimerRef evalAx_bc = IpplTimings::getTimer(
"evaluateAx: BCs");
379 static IpplTimings::TimerRef evalAx_setup = IpplTimings::getTimer(
"evaluateAx: setup");
380 static IpplTimings::TimerRef accumHalo = IpplTimings::getTimer(
"evaluateAx: accumHalo");
383 IpplTimings::startTimer(evalAx);
384 IpplTimings::startTimer(evalAx_setup);
391 this->quadrature_m.getWeightsForRefElement();
395 this->quadrature_m.getIntegrationNodesForRefElement();
400 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
401 for (
size_t i = 0; i < numElementDOFs; ++i) {
402 b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
403 grad_b_q[k][i] = this->evaluateRefElementShapeFunctionGradient(i, q[k]);
412 for (
size_t i = 0; i < numElementDOFs; ++i) {
413 for (
size_t j = 0; j < numElementDOFs; ++j) {
415 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
416 A_K[i][j] += w[k] * evalFunction(
424 ViewType view = field.getView();
425 AtomicViewType resultView = resultField.getView();
429 FieldBC bcType = bcField[0]->getBCType();
432 auto ldom = (field.getLayout()).getLocalNDIndex();
434 const int nghost = field.getNghost();
436 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
437 using policy_type = Kokkos::RangePolicy<exec_space>;
439 IpplTimings::stopTimer(evalAx_setup);
442 IpplTimings::startTimer(evalAx_outer);
445 Kokkos::parallel_for(
446 "Loop over elements", policy_type(0, elementIndices.extent(0)),
447 KOKKOS_CLASS_LAMBDA(
const size_t index) {
448 const size_t elementIndex = elementIndices(index);
453 for (
size_t i = 0; i < numElementDOFs; ++i) {
454 global_dof_ndindices[i] = this->getMeshVertexNDIndex(global_dofs[i]);
465 for (i = 0; i < numElementDOFs; ++i) {
466 I_nd = global_dof_ndindices[i];
471 if ((bcType == CONSTANT_FACE) && (this->isDOFOnBoundary(I_nd))) {
472 for (
unsigned d = 0; d < Dim; ++d) {
473 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
477 }
else if ((bcType == ZERO_FACE) && (this->isDOFOnBoundary(I_nd))) {
482 for (
unsigned d = 0; d < Dim; ++d) {
483 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
486 for (j = 0; j < numElementDOFs; ++j) {
487 J_nd = global_dof_ndindices[j];
490 if (((bcType == ZERO_FACE) || (bcType == CONSTANT_FACE))
491 && this->isDOFOnBoundary(J_nd)) {
496 for (
unsigned d = 0; d < Dim; ++d) {
497 J_nd[d] = J_nd[d] - ldom[d].first() + nghost;
500 apply(resultView, I_nd) += A_K[i][j] *
apply(view, J_nd);
504 IpplTimings::stopTimer(evalAx_outer);
507 IpplTimings::startTimer(evalAx_bc);
509 if (bcType == PERIODIC_FACE) {
510 IpplTimings::startTimer(accumHalo);
511 resultField.accumulateHalo();
512 IpplTimings::stopTimer(accumHalo);
513 bcField.apply(resultField);
514 bcField.assignGhostToPhysical(resultField);
516 resultField.accumulateHalo_noghost();
519 IpplTimings::stopTimer(evalAx_bc);
520 IpplTimings::stopTimer(evalAx);
525 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
526 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
527 template <
typename F>
528 FieldLHS
LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
529 FieldRHS>::evaluateAx_lower(FieldLHS& field, F& evalFunction) {
533 static IpplTimings::TimerRef evalAx_lower = IpplTimings::getTimer(
"evaluateAxLower");
536 IpplTimings::startTimer(evalAx_lower);
543 this->quadrature_m.getWeightsForRefElement();
547 this->quadrature_m.getIntegrationNodesForRefElement();
552 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
553 for (
size_t i = 0; i < numElementDOFs; ++i) {
554 b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
555 grad_b_q[k][i] = this->evaluateRefElementShapeFunctionGradient(i, q[k]);
564 for (
size_t i = 0; i < numElementDOFs; ++i) {
565 for (
size_t j = 0; j < numElementDOFs; ++j) {
567 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
568 A_K[i][j] += w[k] * evalFunction(
569 i, j, QuadratureData<T, point_t, numElementDOFs>{b_q[k], grad_b_q[k]});
576 ViewType view = field.getView();
577 AtomicViewType resultView = resultField.getView();
580 BConds<FieldLHS, Dim>& bcField = field.getFieldBC();
581 FieldBC bcType = bcField[0]->getBCType();
584 auto ldom = (field.getLayout()).getLocalNDIndex();
586 const int nghost = field.getNghost();
588 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
589 using policy_type = Kokkos::RangePolicy<exec_space>;
592 Kokkos::parallel_for(
593 "Loop over elements", policy_type(0, elementIndices.extent(0)),
594 KOKKOS_CLASS_LAMBDA(
const size_t index) {
595 const size_t elementIndex = elementIndices(index);
600 for (
size_t i = 0; i < numElementDOFs; ++i) {
601 global_dof_ndindices[i] = this->getMeshVertexNDIndex(global_dofs[i]);
609 indices_t I_nd, J_nd;
612 for (i = 0; i < numElementDOFs; ++i) {
613 I_nd = global_dof_ndindices[i];
618 if ((bcType == CONSTANT_FACE) && (this->isDOFOnBoundary(I_nd))) {
619 for (
unsigned d = 0; d < Dim; ++d) {
620 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
624 }
else if ((bcType == ZERO_FACE) && (this->isDOFOnBoundary(I_nd))) {
629 for (
unsigned d = 0; d < Dim; ++d) {
630 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
633 for (j = 0; j < numElementDOFs; ++j) {
634 J_nd = global_dof_ndindices[j];
636 if (global_dofs[i] >= global_dofs[j]) {
641 if (((bcType == ZERO_FACE) || (bcType == CONSTANT_FACE))
642 && this->isDOFOnBoundary(J_nd)) {
647 for (
unsigned d = 0; d < Dim; ++d) {
648 J_nd[d] = J_nd[d] - ldom[d].first() + nghost;
651 apply(resultView, I_nd) += A_K[i][j] *
apply(view, J_nd);
656 if (bcType == PERIODIC_FACE) {
657 resultField.accumulateHalo();
658 bcField.apply(resultField);
659 bcField.assignGhostToPhysical(resultField);
661 resultField.accumulateHalo_noghost();
664 IpplTimings::stopTimer(evalAx_lower);
669 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
670 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
671 template <
typename F>
672 FieldLHS LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
673 FieldRHS>::evaluateAx_upper(FieldLHS& field, F& evalFunction) {
677 static IpplTimings::TimerRef evalAx_upper = IpplTimings::getTimer(
"evaluateAxUpper");
680 IpplTimings::startTimer(evalAx_upper);
687 this->quadrature_m.getWeightsForRefElement();
691 this->quadrature_m.getIntegrationNodesForRefElement();
696 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
697 for (
size_t i = 0; i < numElementDOFs; ++i) {
698 b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
699 grad_b_q[k][i] = this->evaluateRefElementShapeFunctionGradient(i, q[k]);
708 for (
size_t i = 0; i < numElementDOFs; ++i) {
709 for (
size_t j = 0; j < numElementDOFs; ++j) {
711 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
712 A_K[i][j] += w[k] * evalFunction(
713 i, j, QuadratureData<T, point_t, numElementDOFs>{b_q[k], grad_b_q[k]});
720 ViewType view = field.getView();
721 AtomicViewType resultView = resultField.getView();
724 BConds<FieldLHS, Dim>& bcField = field.getFieldBC();
725 FieldBC bcType = bcField[0]->getBCType();
728 auto ldom = (field.getLayout()).getLocalNDIndex();
730 const int nghost = field.getNghost();
732 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
733 using policy_type = Kokkos::RangePolicy<exec_space>;
736 Kokkos::parallel_for(
737 "Loop over elements", policy_type(0, elementIndices.extent(0)),
738 KOKKOS_CLASS_LAMBDA(
const size_t index) {
739 const size_t elementIndex = elementIndices(index);
744 for (
size_t i = 0; i < numElementDOFs; ++i) {
745 global_dof_ndindices[i] = this->getMeshVertexNDIndex(global_dofs[i]);
753 indices_t I_nd, J_nd;
756 for (i = 0; i < numElementDOFs; ++i) {
757 I_nd = global_dof_ndindices[i];
762 if ((bcType == CONSTANT_FACE) && (this->isDOFOnBoundary(I_nd))) {
763 for (
unsigned d = 0; d < Dim; ++d) {
764 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
768 }
else if ((bcType == ZERO_FACE) && (this->isDOFOnBoundary(I_nd))) {
773 for (
unsigned d = 0; d < Dim; ++d) {
774 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
777 for (j = 0; j < numElementDOFs; ++j) {
778 J_nd = global_dof_ndindices[j];
780 if (global_dofs[i] <= global_dofs[j]) {
785 if (((bcType == ZERO_FACE) || (bcType == CONSTANT_FACE))
786 && this->isDOFOnBoundary(J_nd)) {
791 for (
unsigned d = 0; d < Dim; ++d) {
792 J_nd[d] = J_nd[d] - ldom[d].first() + nghost;
795 apply(resultView, I_nd) += A_K[i][j] *
apply(view, J_nd);
800 if (bcType == PERIODIC_FACE) {
801 resultField.accumulateHalo();
802 bcField.apply(resultField);
803 bcField.assignGhostToPhysical(resultField);
805 resultField.accumulateHalo_noghost();
808 IpplTimings::stopTimer(evalAx_upper);
813 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
814 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
815 template <
typename F>
816 FieldLHS LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
817 FieldRHS>::evaluateAx_upperlower(FieldLHS& field, F& evalFunction) {
821 static IpplTimings::TimerRef evalAx_upperlower = IpplTimings::getTimer(
"evaluateAxUpperLower");
824 IpplTimings::startTimer(evalAx_upperlower);
831 this->quadrature_m.getWeightsForRefElement();
835 this->quadrature_m.getIntegrationNodesForRefElement();
841 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
842 for (
size_t i = 0; i < numElementDOFs; ++i) {
843 b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
844 grad_b_q[k][i] = this->evaluateRefElementShapeFunctionGradient(i, q[k]);
853 for (
size_t i = 0; i < numElementDOFs; ++i) {
854 for (
size_t j = 0; j < numElementDOFs; ++j) {
856 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
857 A_K[i][j] += w[k] * evalFunction(
858 i, j, QuadratureData<T, point_t, numElementDOFs>{b_q[k], grad_b_q[k]});
865 ViewType view = field.getView();
866 AtomicViewType resultView = resultField.getView();
869 BConds<FieldLHS, Dim>& bcField = field.getFieldBC();
870 FieldBC bcType = bcField[0]->getBCType();
873 auto ldom = (field.getLayout()).getLocalNDIndex();
875 const int nghost = field.getNghost();
877 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
878 using policy_type = Kokkos::RangePolicy<exec_space>;
881 Kokkos::parallel_for(
882 "Loop over elements", policy_type(0, elementIndices.extent(0)),
883 KOKKOS_CLASS_LAMBDA(
const size_t index) {
884 const size_t elementIndex = elementIndices(index);
889 for (
size_t i = 0; i < numElementDOFs; ++i) {
890 global_dof_ndindices[i] = this->getMeshVertexNDIndex(global_dofs[i]);
898 indices_t I_nd, J_nd;
901 for (i = 0; i < numElementDOFs; ++i) {
902 I_nd = global_dof_ndindices[i];
907 if ((bcType == CONSTANT_FACE) && (this->isDOFOnBoundary(I_nd))) {
908 for (
unsigned d = 0; d < Dim; ++d) {
909 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
913 }
else if ((bcType == ZERO_FACE) && (this->isDOFOnBoundary(I_nd))) {
918 for (
unsigned d = 0; d < Dim; ++d) {
919 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
922 for (j = 0; j < i; ++j) {
923 J_nd = global_dof_ndindices[j];
926 if (((bcType == ZERO_FACE) || (bcType == CONSTANT_FACE))
927 && this->isDOFOnBoundary(J_nd)) {
932 for (
unsigned d = 0; d < Dim; ++d) {
933 J_nd[d] = J_nd[d] - ldom[d].first() + nghost;
936 apply(resultView, I_nd) += A_K[i][j] *
apply(view, J_nd);
937 apply(resultView, J_nd) += A_K[j][i] *
apply(view, I_nd);
942 if (bcType == PERIODIC_FACE) {
943 resultField.accumulateHalo();
944 bcField.apply(resultField);
945 bcField.assignGhostToPhysical(resultField);
947 resultField.accumulateHalo_noghost();
950 IpplTimings::stopTimer(evalAx_upperlower);
955 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
956 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
957 template <
typename F>
958 FieldLHS LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
959 FieldRHS>::evaluateAx_inversediag(FieldLHS& field, F& evalFunction) {
963 static IpplTimings::TimerRef evalAx_invdiag = IpplTimings::getTimer(
"evaluateAxInvDiag");
966 IpplTimings::startTimer(evalAx_invdiag);
973 this->quadrature_m.getWeightsForRefElement();
977 this->quadrature_m.getIntegrationNodesForRefElement();
982 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
983 for (
size_t i = 0; i < numElementDOFs; ++i) {
984 b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
985 grad_b_q[k][i] = this->evaluateRefElementShapeFunctionGradient(i, q[k]);
994 for (
size_t i = 0; i < numElementDOFs; ++i) {
996 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
997 A_K_diag[i] += w[k] * evalFunction(
998 i, i, QuadratureData<T, point_t, numElementDOFs>{b_q[k], grad_b_q[k]});
1004 ViewType view = field.getView();
1005 AtomicViewType resultView = resultField.getView();
1008 BConds<FieldLHS, Dim>& bcField = field.getFieldBC();
1009 FieldBC bcType = bcField[0]->getBCType();
1012 auto ldom = (field.getLayout()).getLocalNDIndex();
1014 const int nghost = field.getNghost();
1016 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
1017 using policy_type = Kokkos::RangePolicy<exec_space>;
1020 Kokkos::parallel_for(
1021 "Loop over elements", policy_type(0, elementIndices.extent(0)),
1022 KOKKOS_CLASS_LAMBDA(
const size_t index) {
1023 const size_t elementIndex = elementIndices(index);
1028 for (
size_t i = 0; i < numElementDOFs; ++i) {
1029 global_dof_ndindices[i] = this->getMeshVertexNDIndex(global_dofs[i]);
1040 for (i = 0; i < numElementDOFs; ++i) {
1041 I_nd = global_dof_ndindices[i];
1046 if ((bcType == CONSTANT_FACE) && (this->isDOFOnBoundary(I_nd))) {
1047 for (
unsigned d = 0; d < Dim; ++d) {
1048 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
1050 apply(resultView, I_nd) = 1.0;
1052 }
else if ((bcType == ZERO_FACE) && (this->isDOFOnBoundary(I_nd))) {
1057 for (
unsigned d = 0; d < Dim; ++d) {
1058 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
1061 apply(resultView, I_nd) += A_K_diag[i];
1065 if (bcType == PERIODIC_FACE) {
1066 resultField.accumulateHalo();
1067 bcField.apply(resultField);
1068 bcField.assignGhostToPhysical(resultField);
1070 resultField.accumulateHalo_noghost();
1074 using index_array_type =
typename RangePolicy<Dim, exec_space>::index_array_type;
1075 ippl::parallel_for(
"Loop over result view to apply inverse", field.getFieldRangePolicy(),
1076 KOKKOS_LAMBDA(
const index_array_type& args) {
1077 if (
apply(resultView, args) != 0.0) {
1078 apply(resultView, args) = (1.0 /
apply(resultView, args)) *
apply(view, args);
1081 IpplTimings::stopTimer(evalAx_invdiag);
1086 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1087 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
1088 template <
typename F>
1089 FieldLHS LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
1090 FieldRHS>::evaluateAx_diag(FieldLHS& field, F& evalFunction) {
1094 static IpplTimings::TimerRef evalAx_diag = IpplTimings::getTimer(
"evaluateAxDiag");
1097 IpplTimings::startTimer(evalAx_diag);
1104 this->quadrature_m.getWeightsForRefElement();
1108 this->quadrature_m.getIntegrationNodesForRefElement();
1113 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1114 for (
size_t i = 0; i < numElementDOFs; ++i) {
1115 b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
1116 grad_b_q[k][i] = this->evaluateRefElementShapeFunctionGradient(i, q[k]);
1125 for (
size_t i = 0; i < numElementDOFs; ++i) {
1127 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1128 A_K_diag[i] += w[k] * evalFunction(
1129 i, i, QuadratureData<T, point_t, numElementDOFs>{b_q[k], grad_b_q[k]});
1135 ViewType view = field.getView();
1136 AtomicViewType resultView = resultField.getView();
1139 BConds<FieldLHS, Dim>& bcField = field.getFieldBC();
1140 FieldBC bcType = bcField[0]->getBCType();
1143 auto ldom = (field.getLayout()).getLocalNDIndex();
1145 const int nghost = field.getNghost();
1147 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
1148 using policy_type = Kokkos::RangePolicy<exec_space>;
1151 Kokkos::parallel_for(
1152 "Loop over elements", policy_type(0, elementIndices.extent(0)),
1153 KOKKOS_CLASS_LAMBDA(
const size_t index) {
1154 const size_t elementIndex = elementIndices(index);
1159 for (
size_t i = 0; i < numElementDOFs; ++i) {
1160 global_dof_ndindices[i] = this->getMeshVertexNDIndex(global_dofs[i]);
1171 for (i = 0; i < numElementDOFs; ++i) {
1172 I_nd = global_dof_ndindices[i];
1177 if ((bcType == CONSTANT_FACE) && (this->isDOFOnBoundary(I_nd))) {
1178 for (
unsigned d = 0; d < Dim; ++d) {
1179 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
1183 }
else if ((bcType == ZERO_FACE) && (this->isDOFOnBoundary(I_nd))) {
1188 for (
unsigned d = 0; d < Dim; ++d) {
1189 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
1191 apply(resultView, I_nd) += A_K_diag[i] *
apply(view, I_nd);
1195 if (bcType == PERIODIC_FACE) {
1196 resultField.accumulateHalo();
1197 bcField.apply(resultField);
1198 bcField.assignGhostToPhysical(resultField);
1200 resultField.accumulateHalo_noghost();
1203 IpplTimings::stopTimer(evalAx_diag);
1208 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1209 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
1210 template <
typename F>
1211 FieldLHS LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
1212 FieldRHS>::evaluateAx_lift(FieldLHS& field, F& evalFunction) {
1216 static IpplTimings::TimerRef evalLifting = IpplTimings::getTimer(
"evaluateLifting");
1219 IpplTimings::startTimer(evalLifting);
1226 this->quadrature_m.getWeightsForRefElement();
1230 this->quadrature_m.getIntegrationNodesForRefElement();
1235 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1236 for (
size_t i = 0; i < numElementDOFs; ++i) {
1237 b_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
1238 grad_b_q[k][i] = this->evaluateRefElementShapeFunctionGradient(i, q[k]);
1247 for (
size_t i = 0; i < numElementDOFs; ++i) {
1248 for (
size_t j = 0; j < numElementDOFs; ++j) {
1250 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1251 A_K[i][j] += w[k] * evalFunction(
1259 ViewType view = field.getView();
1260 AtomicViewType resultView = resultField.getView();
1263 auto ldom = (field.getLayout()).getLocalNDIndex();
1265 const int nghost = field.getNghost();
1267 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
1268 using policy_type = Kokkos::RangePolicy<exec_space>;
1271 Kokkos::parallel_for(
1272 "Loop over elements", policy_type(0, elementIndices.extent(0)),
1273 KOKKOS_CLASS_LAMBDA(
const size_t index) {
1274 const size_t elementIndex = elementIndices(index);
1279 for (
size_t i = 0; i < numElementDOFs; ++i) {
1280 global_dof_ndindices[i] = this->getMeshVertexNDIndex(global_dofs[i]);
1291 for (i = 0; i < numElementDOFs; ++i) {
1292 I_nd = global_dof_ndindices[i];
1295 if (this->isDOFOnBoundary(I_nd)) {
1300 for (
unsigned d = 0; d < Dim; ++d) {
1301 I_nd[d] = I_nd[d] - ldom[d].first() + nghost;
1304 for (j = 0; j < numElementDOFs; ++j) {
1305 J_nd = global_dof_ndindices[j];
1308 if (this->isDOFOnBoundary(J_nd)) {
1310 for (
unsigned d = 0; d < Dim; ++d) {
1311 J_nd[d] = J_nd[d] - ldom[d].first() + nghost;
1313 apply(resultView, I_nd) += A_K[i][j] *
apply(view, J_nd);
1320 resultField.accumulateHalo();
1322 IpplTimings::stopTimer(evalLifting);
1327 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1328 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
1329 void LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
1330 FieldRHS>::evaluateLoadVector(FieldRHS& field)
const {
1334 static IpplTimings::TimerRef evalLoadV = IpplTimings::getTimer(
"evaluateLoadVector");
1337 IpplTimings::startTimer(evalLoadV);
1341 this->quadrature_m.getWeightsForRefElement();
1345 this->quadrature_m.getIntegrationNodesForRefElement();
1351 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1352 for (
size_t i = 0; i < numElementDOFs; ++i) {
1353 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
1358 const T absDetDPhi = Kokkos::abs(this->ref_element_m.getDeterminantOfTransformationJacobian(
1359 this->getElementMeshVertexPoints(zeroNdIndex)));
1362 auto ldom = (field.getLayout()).getLocalNDIndex();
1363 const int nghost = field.getNghost();
1367 FieldBC bcType = bcField[0]->getBCType();
1369 FieldRHS temp_field(field.get_mesh(), field.getLayout(), nghost);
1370 temp_field.setFieldBC(bcField);
1376 AtomicViewType atomic_view = temp_field.getView();
1378 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
1379 using policy_type = Kokkos::RangePolicy<exec_space>;
1382 Kokkos::parallel_for(
1383 "Loop over elements", policy_type(0, elementIndices.extent(0)),
1384 KOKKOS_CLASS_LAMBDA(
size_t index) {
1385 const size_t elementIndex = elementIndices(index);
1392 for (i = 0; i < numElementDOFs; ++i) {
1396 auto dof_ndindex_I = this->getMeshVertexNDIndex(I);
1399 if (((bcType == ZERO_FACE) || (bcType == CONSTANT_FACE))
1400 && (this->isDOFOnBoundary(dof_ndindex_I))) {
1406 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1408 for (
size_t j = 0; j < numElementDOFs; ++j) {
1410 size_t J = global_dofs[j];
1411 auto dof_ndindex_J = this->getMeshVertexNDIndex(J);
1412 for (
unsigned d = 0; d < Dim; ++d) {
1413 dof_ndindex_J[d] = dof_ndindex_J[d] - ldom[d].first() + nghost;
1417 val += basis_q[k][j] *
apply(field, dof_ndindex_J);
1420 contrib += w[k] * basis_q[k][i] * absDetDPhi * val;
1424 for (
unsigned d = 0; d < Dim; ++d) {
1425 dof_ndindex_I[d] = dof_ndindex_I[d] - ldom[d].first() + nghost;
1429 apply(atomic_view, dof_ndindex_I) += contrib;
1433 temp_field.accumulateHalo();
1435 if (bcType == PERIODIC_FACE) {
1436 bcField.apply(temp_field);
1437 bcField.assignGhostToPhysical(temp_field);
1442 IpplTimings::stopTimer(evalLoadV);
1449 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1450 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
1451 void LagrangeSpace<T, Dim, Order, ElementType, QuadratureType, FieldLHS,
1452 FieldRHS>::evaluateLumpedMass(FieldRHS& field)
const {
1455 this->quadrature_m.getWeightsForRefElement();
1459 this->quadrature_m.getIntegrationNodesForRefElement();
1465 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1466 for (
size_t i = 0; i < numElementDOFs; ++i) {
1467 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
1472 const T absDetDPhi = Kokkos::abs(this->ref_element_m.getDeterminantOfTransformationJacobian(
1473 this->getElementMeshVertexPoints(zeroNdIndex)));
1477 AtomicViewType atomic_view = field.getView();
1480 auto ldom = (field.getLayout()).getLocalNDIndex();
1481 const int nghost = field.getNghost();
1483 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
1484 using policy_type = Kokkos::RangePolicy<exec_space>;
1487 Kokkos::parallel_for(
1488 "Loop over elements", policy_type(0, elementIndices.extent(0)),
1489 KOKKOS_CLASS_LAMBDA(
size_t index) {
1490 const size_t elementIndex = elementIndices(index);
1497 for (i = 0; i < numElementDOFs; ++i) {
1501 auto dof_ndindex_I = this->getMeshVertexNDIndex(I);
1505 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1506 contrib += w[k] * basis_q[k][i] * absDetDPhi;
1510 for (
unsigned d = 0; d < Dim; ++d) {
1511 dof_ndindex_I[d] = dof_ndindex_I[d] - ldom[d].first() + nghost;
1515 apply(atomic_view, dof_ndindex_I) += contrib;
1518 field.accumulateHalo();
1522 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1523 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
1524 template <
typename F>
1526 const FieldLHS& u_h,
const F& u_sol)
const {
1527 if (this->quadrature_m.getOrder() < (2 * Order + 1)) {
1530 "LagrangeSpace::computeErrorL2()",
1531 "Order of quadrature rule for error computation should be > 2*p + 1");
1536 this->quadrature_m.getWeightsForRefElement();
1540 this->quadrature_m.getIntegrationNodesForRefElement();
1544 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1545 for (
size_t i = 0; i < numElementDOFs; ++i) {
1546 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
1553 const T absDetDPhi = Kokkos::abs(this->ref_element_m.getDeterminantOfTransformationJacobian(
1554 this->getElementMeshVertexPoints(zeroNdIndex)));
1560 auto ldom = (u_h.getLayout()).getLocalNDIndex();
1561 const int nghost = u_h.getNghost();
1563 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
1564 using policy_type = Kokkos::RangePolicy<exec_space>;
1567 Kokkos::parallel_reduce(
1568 "Compute error over elements", policy_type(0, elementIndices.extent(0)),
1569 KOKKOS_CLASS_LAMBDA(
size_t index,
double& local) {
1570 const size_t elementIndex = elementIndices(index);
1576 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1577 T val_u_sol = u_sol(this->ref_element_m.localToGlobal(
1578 this->getElementMeshVertexPoints(this->getElementNDIndex(elementIndex)),
1582 for (
size_t i = 0; i < numElementDOFs; ++i) {
1584 size_t I = global_dofs[i];
1585 auto dof_ndindex_I = this->getMeshVertexNDIndex(I);
1586 for (
unsigned d = 0; d < Dim; ++d) {
1587 dof_ndindex_I[d] = dof_ndindex_I[d] - ldom[d].first() + nghost;
1591 val_u_h += basis_q[k][i] *
apply(u_h, dof_ndindex_I);
1594 contrib += w[k] * Kokkos::pow(val_u_sol - val_u_h, 2) * absDetDPhi;
1598 Kokkos::Sum<double>(error));
1601 T global_error = 0.0;
1602 Comm->allreduce(error, global_error, 1, std::plus<T>());
1604 return Kokkos::sqrt(global_error);
1607 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1608 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
1610 const FieldLHS& u_h)
const {
1611 if (this->quadrature_m.getOrder() < (2 * Order + 1)) {
1614 "LagrangeSpace::computeAvg()",
1615 "Order of quadrature rule for error computation should be > 2*p + 1");
1620 this->quadrature_m.getWeightsForRefElement();
1624 this->quadrature_m.getIntegrationNodesForRefElement();
1628 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1629 for (
size_t i = 0; i < numElementDOFs; ++i) {
1630 basis_q[k][i] = this->evaluateRefElementShapeFunction(i, q[k]);
1637 const T absDetDPhi = Kokkos::abs(this->ref_element_m.getDeterminantOfTransformationJacobian(
1638 this->getElementMeshVertexPoints(zeroNdIndex)));
1644 auto ldom = (u_h.getLayout()).getLocalNDIndex();
1645 const int nghost = u_h.getNghost();
1647 using exec_space =
typename Kokkos::View<const size_t*>::execution_space;
1648 using policy_type = Kokkos::RangePolicy<exec_space>;
1651 Kokkos::parallel_reduce(
1652 "Compute average over elements", policy_type(0, elementIndices.extent(0)),
1653 KOKKOS_CLASS_LAMBDA(
size_t index,
double& local) {
1654 const size_t elementIndex = elementIndices(index);
1660 for (
size_t k = 0; k < QuadratureType::numElementNodes; ++k) {
1662 for (
size_t i = 0; i < numElementDOFs; ++i) {
1664 size_t I = global_dofs[i];
1665 auto dof_ndindex_I = this->getMeshVertexNDIndex(I);
1666 for (
unsigned d = 0; d < Dim; ++d) {
1667 dof_ndindex_I[d] = dof_ndindex_I[d] - ldom[d].first() + nghost;
1671 val_u_h += basis_q[k][i] *
apply(u_h, dof_ndindex_I);
1674 contrib += w[k] * val_u_h * absDetDPhi;
1678 Kokkos::Sum<double>(avg));
1682 Comm->allreduce(avg, global_avg, 1, std::plus<T>());
1692 template <
typename T,
unsigned Dim,
unsigned Order,
typename ElementType,
1693 typename QuadratureType,
typename FieldLHS,
typename FieldRHS>
1699 space_mirror.nr_m = this->nr_m;
1700 space_mirror.ref_element_m = this->ref_element_m;
1701 return space_mirror;