396 xt::pyarray<double> &mesh_trial_ref,
397 xt::pyarray<double> &mesh_grad_trial_ref,
398 xt::pyarray<double> &mesh_dof,
399 xt::pyarray<int> &mesh_l2g,
400 xt::pyarray<double> &x_ref,
401 xt::pyarray<double> &dV_ref,
402 xt::pyarray<double> &u_trial_ref,
403 xt::pyarray<double> &u_grad_trial_ref,
404 xt::pyarray<double> &u_test_ref,
405 xt::pyarray<double> &u_grad_test_ref,
406 xt::pyarray<double> &elementDiameter,
407 xt::pyarray<double> &elementBoundaryDiameter,
408 xt::pyarray<double> &nodeDiametersArray,
409 xt::pyarray<double> &cfl,
415 xt::pyarray<double> &mesh_trial_trace_ref,
416 xt::pyarray<double> &mesh_grad_trial_trace_ref,
417 xt::pyarray<double> &dS_ref,
418 xt::pyarray<double> &u_trial_trace_ref,
419 xt::pyarray<double> &u_grad_trial_trace_ref,
420 xt::pyarray<double> &u_test_trace_ref,
421 xt::pyarray<double> &u_grad_test_trace_ref,
422 xt::pyarray<double> &normal_ref,
423 xt::pyarray<double> &boundaryJac_ref,
425 int nElements_global,
426 int nElementBoundaries_owned,
427 xt::pyarray<int> &u_l2g,
428 xt::pyarray<double> &u_dof,
429 xt::pyarray<int> &sd_rowptr,
430 xt::pyarray<int> &sd_colind,
431 xt::pyarray<double> &q_a,
432 xt::pyarray<double> &q_v,
433 xt::pyarray<double> &q_r,
434 int lag_shockCapturingDiffusion,
435 double shockCapturingDiffusion,
436 xt::pyarray<double> &q_numDiff_u,
437 xt::pyarray<double> &q_numDiff_u_last,
440 xt::pyarray<double> &elementResidual_u,
441 int nExteriorElementBoundaries_global,
442 xt::pyarray<int> &exteriorElementBoundariesArray,
443 xt::pyarray<int> &elementBoundariesArray,
444 xt::pyarray<int> &elementBoundaryElementsArray,
445 xt::pyarray<int> &elementBoundaryLocalElementBoundariesArray,
446 xt::pyarray<double> &element_u,
448 const bool embeddedBoundary,
449 const double embeddedBoundary_penalty,
450 xt::pyarray<double> &embeddedBoundary_normal_q,
451 xt::pyarray<double> &embeddedBoundary_u_q,
452 const bool immersedBoundary,
453 const double immersedBoundary_penalty,
454 xt::pyarray<double> &immersedBoundary_sdf_q,
455 xt::pyarray<double> &immersedBoundary_normal_q,
456 xt::pyarray<double> &immersedBoundary_u_q,
457 xt::pyarray<double> &immersedBoundary_fluxJump_q,
458 xt::pyarray<double> &immersedBoundary_fluxJumpVector_q,
459 xt::pyarray<double> &immersedBoundary_solutionJump_nodes,
460 double *element_phi_f,
461 bool &element_active,
466 double &Linfty_error,
469 xt::pyarray<double> &q_u_exact_inner,
470 xt::pyarray<double> &q_u_exact_outer,
477 for (
int i = 0; i < nDOF_test_element; i++)
479 elementResidual_u.data()[i] = 0.0;
483 for (
int k = 0; k < nQuadraturePoints_element; k++)
489 int eN_k = eN * nQuadraturePoints_element + k;
490 int eN_k_3d = eN_k * 3;
493 double grad_u[nSpace];
495 double grad_ua[nSpace];
497 double grad_ub[nSpace];
499 double grad_uja[nSpace];
501 double grad_ujb[nSpace];
506 double f_s[nSpace] = {0., 0.};
507 double df_s[nSpace] = {0., 0.};
509 double dham_s[nSpace] = {0., 0.};
510 double f_f[nSpace] = {0., 0.};
511 double df_f[nSpace] = {0., 0.};
513 double dham_f[nSpace] = {0., 0.};
516 double pdeResidual_u = 0.0;
517 double Lstar_u[nDOF_test_element];
518 double subgridError_u = 0.0;
522 double numDiff0 = 0.0;
523 double numDiff1 = 0.0;
530 double jac[nSpace * nSpace];
532 double jacInv[nSpace * nSpace];
533 double u_grad_trial[nDOF_trial_element * nSpace];
534 double u_test_dV[nDOF_trial_element];
535 double u_grad_test_dV[nDOF_test_element * nSpace];
536 double ua_grad_trial[nDOF_trial_element * nSpace];
537 double ua_test_dV[nDOF_trial_element];
538 double ua_grad_test_dV[nDOF_test_element * nSpace];
539 double ub_grad_trial[nDOF_trial_element * nSpace];
540 double ub_test_dV[nDOF_trial_element];
541 double ub_grad_test_dV[nDOF_test_element * nSpace];
546 double G[nSpace * nSpace];
552 ck.calculateMapping_element(eN,
556 mesh_trial_ref.data(),
557 mesh_grad_trial_ref.data(),
564 ck.calculateH_element(eN,
566 nodeDiametersArray.data(),
568 mesh_trial_ref.data(),
571 dV = fabs(jacDet) * dV_ref.data()[k];
573 ck.calculateG(jacInv, G, G_dd_G, tr_G);
576 ck.gradTrialFromRef(&u_grad_trial_ref.data()[k * nDOF_trial_element * nSpace], jacInv, u_grad_trial);
579 ck.valFromElementDOF(element_u.data(), &u_trial_ref.data()[k * nDOF_trial_element],
u);
581 ck.gradFromElementDOF(element_u.data(), u_grad_trial, grad_u);
583 for (
int j = 0; j < nDOF_trial_element; j++)
585 u_test_dV[j] = u_test_ref.data()[k * nDOF_trial_element + j] * dV;
586 for (
int I = 0; I < nSpace; I++)
588 u_grad_test_dV[j * nSpace + I] = u_grad_trial[j * nSpace + I] * dV;
596 double va[nDOF_trial_element], va_grad_trial[nDOF_trial_element * nSpace], vb[nDOF_trial_element], vb_grad_trial[nDOF_trial_element * nSpace];
597 for (
int i = 0; i < nDOF_trial_element; i++)
601 va_grad_trial[i * nSpace + 0] = gf_f.
VA_x(i);
603 va_grad_trial[i * nSpace + 1] = gf_f.
VA_y(i);
607 vb_grad_trial[i * nSpace + 0] = gf_f.
VB_x(i);
609 vb_grad_trial[i * nSpace + 1] = gf_f.
VB_y(i);
624 ck.valFromElementDOF(element_u.data(), va, ua);
625 ck.gradFromElementDOF(element_u.data(), va_grad_trial, grad_ua);
627 ck.valFromElementDOF(element_u.data(), vb, ub);
628 ck.gradFromElementDOF(element_u.data(), vb_grad_trial, grad_ub);
630 ck.valFromElementDOF(JA, va, uja);
631 ck.gradFromElementDOF(JA, va_grad_trial, grad_uja);
633 ck.valFromElementDOF(JB, vb, ujb);
634 ck.gradFromElementDOF(JB, vb_grad_trial, grad_ujb);
635 for (
int i = 0; i < nDOF_test_element; i++)
637 ua_test_dV[i] = va[i] * dV;
638 ub_test_dV[i] = vb[i] * dV;
639 for (
int I = 0; I < nSpace; I++)
641 ua_grad_test_dV[i * nSpace + I] = va_grad_trial[i * nSpace + I] * dV;
642 ub_grad_test_dV[i * nSpace + I] = vb_grad_trial[i * nSpace + I] * dV;
645 for (
int j = 0; j < nDOF_trial_element; j++)
647 for (
int I = 0; I < nSpace; I++)
649 ua_grad_trial[j * nSpace + I] = va_grad_trial[j * nSpace + I];
650 ub_grad_trial[j * nSpace + I] = vb_grad_trial[j * nSpace + I];
657 for (
int i = 0; i < nDOF_test_element; i++)
659 ua_test_dV[i] = u_test_dV[i];
660 ub_test_dV[i] = u_test_dV[i];
661 for (
int I = 0; I < nSpace; I++)
663 ua_grad_test_dV[i * nSpace + I] = u_grad_test_dV[i * nSpace + I];
664 ub_grad_test_dV[i * nSpace + I] = u_grad_test_dV[i * nSpace + I];
674 a = &q_a.data()[eN_k * sd_rowptr.data()[nSpace]];
675 r = q_r.data()[eN_k];
676 for (
int I = 0; I < nSpace; I++)
678 f[I] = q_v.data()[eN_k * nSpace + I] *
u;
679 df[I] = q_v.data()[eN_k * nSpace + I];
681 const double H_s = gf_s.
H(0., 0.);
682 const double D_s = gf_s.
D(0., 0.);
683 if (embeddedBoundary)
685 double level_set_normal[nSpace];
687 double norm_exact = 0.0, norm_cut = 0.0;
688 for (
int I = 0; I < nSpace; I++)
690 sign += embeddedBoundary_normal_q.data()[eN_k_3d + I] * gf_s.
get_normal()[I];
692 norm_cut += level_set_normal[I] * level_set_normal[I];
693 norm_exact += embeddedBoundary_normal_q.data()[eN_k_3d + I] * embeddedBoundary_normal_q.data()[eN_k_3d + I];
695 assert(std::fabs(1.0 - norm_cut) < 1.0e-8);
696 assert(std::fabs(1.0 - norm_exact) < 1.0e-8);
698 for (
int I = 0; I < nSpace; I++)
699 level_set_normal[I] *= -1.0;
703 embeddedBoundary_u_q.data()[eN_k],
715 const double ImH_f = gf_f.
ImH(0., 0.);
716 const double H_f = gf_f.
H(0., 0.);
717 const double D_f = gf_f.
D(0., 0.);
719 if (H_s != 0.0 || D_s != 0.0 || D_f != 0.0)
721 element_active =
true;
724 if (immersedBoundary)
726 double level_set_normal[nSpace];
728 double norm_exact = 0.0, norm_cut = 0.0;
729 for (
int I = 0; I < nSpace; I++)
731 sign += immersedBoundary_normal_q.data()[eN_k_3d + I] * gf_f.
get_normal()[I];
733 norm_cut += level_set_normal[I] * level_set_normal[I];
734 norm_exact += immersedBoundary_normal_q.data()[eN_k_3d + I] * immersedBoundary_normal_q.data()[eN_k_3d + I];
736 assert(std::fabs(1.0 - norm_cut) < 1.0e-8);
737 assert(std::fabs(1.0 - norm_exact) < 1.0e-8);
739 for (
int I = 0; I < nSpace; I++)
740 level_set_normal[I] *= -1.0;
747 immersedBoundary_u_q.data()[eN_k],
757 immersedBoundary_fluxJump_q.data()[eN_k],
758 &immersedBoundary_fluxJumpVector_q.data()[eN_k_3d],
786 pdeResidual_u =
ck.Advection_strong(
df, grad_u) +
ck.Reaction_strong(
r);
788 for (
int i = 0; i < nDOF_test_element; i++)
792 int i_nSpace = i * nSpace;
793 Lstar_u[i] =
ck.Advection_adjoint(
df, &u_grad_test_dV[i_nSpace]);
804 tau = useMetrics * tau1 + (1.0 - useMetrics) * tau0;
806 subgridError_u = -tau * pdeResidual_u;
810 ck.calculateNumericalDiffusion(shockCapturingDiffusion, elementDiameter.data()[eN], pdeResidual_u, grad_u, numDiff0);
811 ck.calculateNumericalDiffusion(shockCapturingDiffusion, sc_uref, sc_alpha, G, G_dd_G, pdeResidual_u, grad_u, numDiff1);
812 q_numDiff_u.data()[eN_k] = useMetrics * numDiff1 + (1.0 - useMetrics) * numDiff0;
817 double a_loc[nSpace * nSpace];
818 for (
int I = 0; I < nSpace * nSpace; I++) a_loc[I] = 0.0;
820 for (
int i = 0; i < nDOF_test_element; i++)
822 int i_nSpace = i * nSpace;
827 for (
int I = 0; I < nSpace; I++) a_loc[I * nSpace + I] = mua;
828 elementResidual_u.data()[i] += ImH_f * H_s * (
ck.Advection_weak(
f, &ua_grad_test_dV[i_nSpace]) +
829 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a_loc, grad_ua, &ua_grad_test_dV[i_nSpace]) +
830 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a_loc, grad_uja, &ua_grad_test_dV[i_nSpace]) +
831 ck.Reaction_weak(
r, ua_test_dV[i]) +
832 ck.NumericalDiffusion(q_numDiff_u_last.data()[eN_k], grad_ua, &ua_grad_test_dV[i_nSpace]));
834 for (
int I = 0; I < nSpace; I++) a_loc[I * nSpace + I] = mub;
835 elementResidual_u.data()[i] += H_f * H_s * (
ck.Advection_weak(
f, &ub_grad_test_dV[i_nSpace]) +
836 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a_loc, grad_ub, &ub_grad_test_dV[i_nSpace]) +
837 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a_loc, grad_ujb, &ub_grad_test_dV[i_nSpace]) +
838 ck.Reaction_weak(
r, ub_test_dV[i]) +
839 ck.NumericalDiffusion(q_numDiff_u_last.data()[eN_k], grad_ub, &ub_grad_test_dV[i_nSpace]));
841 else if (gf_f.
exact.edge == -1 || gf_f.
exact.corner == -1)
843 for (
int I = 0; I < nSpace; I++) a_loc[I * nSpace + I] = mua;
844 elementResidual_u.data()[i] += ImH_f * H_s * (
ck.Advection_weak(
f, &ua_grad_test_dV[i_nSpace]) +
845 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a_loc, grad_ua, &ua_grad_test_dV[i_nSpace]) +
846 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a_loc, grad_uja, &ua_grad_test_dV[i_nSpace]) +
847 ck.Reaction_weak(
r, ua_test_dV[i]) +
848 ck.NumericalDiffusion(q_numDiff_u_last.data()[eN_k], grad_ua, &ua_grad_test_dV[i_nSpace]));
850 else if (gf_f.
exact.edge == 1 || gf_f.
exact.corner == 1)
852 for (
int I = 0; I < nSpace; I++) a_loc[I * nSpace + I] = mub;
853 elementResidual_u.data()[i] += H_f * H_s * (
ck.Advection_weak(
f, &ub_grad_test_dV[i_nSpace]) +
854 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a_loc, grad_ub, &ub_grad_test_dV[i_nSpace]) +
855 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a_loc, grad_ujb, &ub_grad_test_dV[i_nSpace]) +
856 ck.Reaction_weak(
r, ub_test_dV[i]) +
857 ck.NumericalDiffusion(q_numDiff_u_last.data()[eN_k], grad_ub, &ub_grad_test_dV[i_nSpace]));
859 else assert(
false &&
"Invalid gf_f.exact.edge/corner values. Should be -1, 0 or +1.");
864 elementResidual_u.data()[i] += H_s * (
ck.Advection_weak(
f, &u_grad_test_dV[i_nSpace]) +
865 ck.Diffusion_weak(sd_rowptr.data(), sd_colind.data(), a, grad_u, &u_grad_test_dV[i_nSpace]) +
866 ck.Reaction_weak(
r, u_test_dV[i]) +
867 ck.SubgridError(subgridError_u, Lstar_u[i]) +
868 ck.NumericalDiffusion(q_numDiff_u_last.data()[eN_k], grad_u, &u_grad_test_dV[i_nSpace]));
870 if (embeddedBoundary)
872 if (gf_s.
exact.edge >= 0 && !gf_s.
exact.corner)
874 elementResidual_u.data()[i] += (
ck.Advection_weak(f_s, &u_grad_test_dV[i_nSpace]) +
875 ck.Reaction_weak(r_s, u_test_dV[i]) +
876 ck.Hamiltonian_weak(ham_s, u_test_dV[i]));
879 if (immersedBoundary)
881 if (gf_f.
exact.edge >= 0 && !gf_f.
exact.corner)
883 elementResidual_u.data()[i] += (
ck.Advection_weak(f_f, &u_grad_test_dV[i_nSpace]) +
884 ck.Reaction_weak(r_f, u_test_dV[i]) +
885 ck.Hamiltonian_weak(ham_f, u_test_dV[i]));
889 double L2_contrib = 0.0;
892 double sol_in = q_u_exact_inner.data()[eN_k];
893 double err_in = fabs(ua + uja - sol_in);
894 L2_contrib += ImH_f * err_in * err_in * dV;
895 double sol_out = q_u_exact_outer.data()[eN_k];
896 double err_out = fabs(ub + ujb - sol_out);
897 L2_contrib += H_f * err_out * err_out * dV;
899 Linfty_error = std::max(Linfty_error, err_in);
901 Linfty_error = std::max(Linfty_error, err_out);
907 double sol = q_u_exact_inner.data()[eN_k];
908 double err = fabs(
u -
sol);
909 L2_contrib += err * err * dV;
910 Linfty_error = std::max(Linfty_error, err);
914 double sol = q_u_exact_outer.data()[eN_k];
915 double err = fabs(
u -
sol);
916 L2_contrib += err * err * dV;
917 Linfty_error = std::max(Linfty_error, err);
920 L2_error += L2_contrib;
926 xt::pyarray<double> &mesh_trial_ref = args.
array<
double>(
"mesh_trial_ref");
927 xt::pyarray<double> &mesh_grad_trial_ref = args.
array<
double>(
"mesh_grad_trial_ref");
928 xt::pyarray<double> &mesh_dof = args.
array<
double>(
"mesh_dof");
929 xt::pyarray<int> &mesh_l2g = args.
array<
int>(
"mesh_l2g");
930 xt::pyarray<double> &dV_ref = args.
array<
double>(
"dV_ref");
931 xt::pyarray<double> &u_trial_ref = args.
array<
double>(
"u_trial_ref");
932 xt::pyarray<double> &u_grad_trial_ref = args.
array<
double>(
"u_grad_trial_ref");
933 xt::pyarray<double> &u_test_ref = args.
array<
double>(
"u_test_ref");
934 xt::pyarray<double> &u_grad_test_ref = args.
array<
double>(
"u_grad_test_ref");
935 xt::pyarray<double> &elementDiameter = args.
array<
double>(
"elementDiameter");
936 xt::pyarray<double> &cfl = args.
array<
double>(
"cfl");
937 double Ct_sge = args.
scalar<
double>(
"Ct_sge");
938 double sc_uref = args.
scalar<
double>(
"sc_uref");
939 double sc_alpha = args.
scalar<
double>(
"sc_alpha");
940 double useMetrics = args.
scalar<
double>(
"useMetrics");
941 xt::pyarray<double> &mesh_trial_trace_ref = args.
array<
double>(
"mesh_trial_trace_ref");
942 xt::pyarray<double> &mesh_grad_trial_trace_ref = args.
array<
double>(
"mesh_grad_trial_trace_ref");
943 xt::pyarray<double> &dS_ref = args.
array<
double>(
"dS_ref");
944 xt::pyarray<double> &u_trial_trace_ref = args.
array<
double>(
"u_trial_trace_ref");
945 xt::pyarray<double> &u_grad_trial_trace_ref = args.
array<
double>(
"u_grad_trial_trace_ref");
946 xt::pyarray<double> &u_test_trace_ref = args.
array<
double>(
"u_test_trace_ref");
947 xt::pyarray<double> &u_grad_test_trace_ref = args.
array<
double>(
"u_grad_test_trace_ref");
948 xt::pyarray<double> &normal_ref = args.
array<
double>(
"normal_ref");
949 xt::pyarray<double> &boundaryJac_ref = args.
array<
double>(
"boundaryJac_ref");
950 int nElements_global = args.
scalar<
int>(
"nElements_global");
951 xt::pyarray<int> &u_l2g = args.
array<
int>(
"u_l2g");
952 xt::pyarray<double> &u_dof = args.
array<
double>(
"u_dof");
953 xt::pyarray<int> &sd_rowptr = args.
array<
int>(
"sd_rowptr");
954 xt::pyarray<int> &sd_colind = args.
array<
int>(
"sd_colind");
955 xt::pyarray<double> &q_a = args.
array<
double>(
"q_a");
956 xt::pyarray<double> &q_v = args.
array<
double>(
"q_v");
957 xt::pyarray<double> &q_r = args.
array<
double>(
"q_r");
958 int lag_shockCapturing = args.
scalar<
int>(
"lag_shockCapturing");
959 double shockCapturingDiffusion = args.
scalar<
double>(
"shockCapturingDiffusion");
960 xt::pyarray<double> &q_numDiff_u = args.
array<
double>(
"q_numDiff_u");
961 xt::pyarray<double> &q_numDiff_u_last = args.
array<
double>(
"q_numDiff_u_last");
962 int offset_u = args.
scalar<
int>(
"offset_u");
963 int stride_u = args.
scalar<
int>(
"stride_u");
964 xt::pyarray<double> &globalResidual = args.
array<
double>(
"globalResidual");
965 int nExteriorElementBoundaries_global = args.
scalar<
int>(
"nExteriorElementBoundaries_global");
966 xt::pyarray<int> &exteriorElementBoundariesArray = args.
array<
int>(
"exteriorElementBoundariesArray");
967 xt::pyarray<int> &elementBoundaryElementsArray = args.
array<
int>(
"elementBoundaryElementsArray");
968 xt::pyarray<int> &elementBoundaryLocalElementBoundariesArray = args.
array<
int>(
"elementBoundaryLocalElementBoundariesArray");
969 xt::pyarray<double> &ebqe_a = args.
array<
double>(
"ebqe_a");
970 xt::pyarray<double> &ebqe_v = args.
array<
double>(
"ebqe_v");
971 xt::pyarray<int> &isDOFBoundary_u = args.
array<
int>(
"isDOFBoundary_u");
972 xt::pyarray<double> &ebqe_bc_u_ext = args.
array<
double>(
"ebqe_bc_u_ext");
973 xt::pyarray<int> &isDiffusiveFluxBoundary_u = args.
array<
int>(
"isDiffusiveFluxBoundary_u");
974 xt::pyarray<int> &isAdvectiveFluxBoundary_u = args.
array<
int>(
"isAdvectiveFluxBoundary_u");
975 xt::pyarray<double> &ebqe_bc_flux_u_ext = args.
array<
double>(
"ebqe_bc_flux_u_ext");
976 xt::pyarray<double> &ebqe_bc_advectiveFlux_u_ext = args.
array<
double>(
"ebqe_bc_advectiveFlux_u_ext");
977 xt::pyarray<double> &ebqe_penalty_ext = args.
array<
double>(
"ebqe_penalty_ext");
978 const bool embeddedBoundary = args.
scalar<
int>(
"embeddedBoundary");
979 const double embeddedBoundary_penalty = args.
scalar<
double>(
"embeddedBoundary_penalty");
980 const double embeddedBoundary_ghost_penalty = args.
scalar<
double>(
"embeddedBoundary_ghost_penalty");
981 xt::pyarray<double> &embeddedBoundary_sdf_nodes = args.
array<
double>(
"embeddedBoundary_sdf_nodes");
982 xt::pyarray<double> &embeddedBoundary_sdf_q = args.
array<
double>(
"embeddedBoundary_sdf_q");
983 xt::pyarray<double> &embeddedBoundary_normal_q = args.
array<
double>(
"embeddedBoundary_normal_q");
984 xt::pyarray<double> &embeddedBoundary_u_q = args.
array<
double>(
"embeddedBoundary_u_q");
985 const bool immersedBoundary = args.
scalar<
int>(
"immersedBoundary");
986 const double immersedBoundary_penalty = args.
scalar<
double>(
"immersedBoundary_penalty");
987 const double immersedSCIFEM_switch = args.
scalar<
double>(
"immersedSCIFEM_switch");
988 const double immersedSCIFEM_penalty = args.
scalar<
double>(
"immersedSCIFEM_penalty");
989 const bool PG = args.
scalar<
int>(
"PG");
990 xt::pyarray<double> &immersedBoundary_sdf_nodes = args.
array<
double>(
"immersedBoundary_sdf_nodes");
991 xt::pyarray<double> &immersedBoundary_sdf_q = args.
array<
double>(
"immersedBoundary_sdf_q");
992 xt::pyarray<double> &immersedBoundary_normal_q = args.
array<
double>(
"immersedBoundary_normal_q");
993 xt::pyarray<double> &immersedBoundary_u_q = args.
array<
double>(
"immersedBoundary_u_q");
994 xt::pyarray<double> &immersedBoundary_fluxJump_q = args.
array<
double>(
"immersedBoundary_fluxJump_q");
995 xt::pyarray<double> &immersedBoundary_fluxJumpVector_q = args.
array<
double>(
"immersedBoundary_fluxJumpVector_q");
996 xt::pyarray<double> &immersedBoundary_solutionJump_nodes = args.
array<
double>(
"immersedBoundary_solutionJump_nodes");
997 xt::pyarray<double> &isActiveDOF = args.
array<
double>(
"isActiveDOF");
998 const double eb_adjoint_sigma = args.
scalar<
double>(
"eb_adjoint_sigma");
999 xt::pyarray<double> &x_ref = args.
array<
double>(
"x_ref");
1000 xt::pyarray<double> &xB_ref = args.
array<
double>(
"xB_ref");
1001 xt::pyarray<int> &elementBoundariesArray = args.
array<
int>(
"elementBoundariesArray");
1002 const int nElementBoundaries_owned = args.
scalar<
int>(
"nElementBoundaries_owned");
1003 xt::pyarray<double> &elementBoundaryDiameter = args.
array<
double>(
"elementBoundaryDiameter");
1004 xt::pyarray<double> &nodeDiametersArray = args.
array<
double>(
"nodeDiametersArray");
1005 xt::pyarray<double> &L2_error = args.
array<
double>(
"L2_error");
1006 xt::pyarray<double> &Linfty_error = args.
array<
double>(
"Linfty_error");
1007 const double mua = args.
scalar<
double>(
"mua");
1008 const double mub = args.
scalar<
double>(
"mub");
1009 const double jf = args.
scalar<
double>(
"jf");
1010 xt::pyarray<double> &q_u_exact_inner = args.
array<
double>(
"q_u_exact_inner");
1011 xt::pyarray<double> &q_u_exact_outer = args.
array<
double>(
"q_u_exact_outer");
1012 const bool recomputeIFEMGeometry = args.
scalar<
int>(
"recomputeIFEMGeometry");
1014 if (recomputeIFEMGeometry)
1032 for (
int eN = 0; eN < nElements_global; eN++)
1037 auto elementResidual_u = xt::pyarray<double>::from_shape({nDOF_test_element});
1038 auto element_u = xt::pyarray<double>::from_shape({nDOF_trial_element});
1039 bool element_active =
false;
1041 for (
int i = 0; i < nDOF_trial_element; i++)
1043 int eN_i = eN * nDOF_trial_element + i;
1044 element_u.data()[i] = u_dof.data()[u_l2g.data()[eN_i]];
1047 double element_phi_s[nDOF_trial_element];
1048 for (
int j = 0; j < nDOF_trial_element; j++)
1050 int eN_j = eN * nDOF_trial_element + j;
1051 element_phi_s[j] = embeddedBoundary_sdf_nodes.data()[u_l2g.data()[eN_j]];
1053 double element_phi_f[nDOF_trial_element];
1054 for (
int j = 0; j < nDOF_trial_element; j++)
1056 int eN_j = eN * nDOF_trial_element + j;
1057 element_phi_f[j] = immersedBoundary_sdf_nodes.data()[u_l2g.data()[eN_j]];
1060 double element_nodes[nDOF_trial_element * 3];
1061 for (
int i = 0; i < nDOF_trial_element; i++)
1063 int eN_i = eN * nDOF_trial_element + i;
1064 for (
int I = 0; I < 3; I++)
1066 element_nodes[i * 3 + I] = mesh_dof.data()[u_l2g.data()[eN_i] * 3 + I];
1080 for (
int ebN_element = 0; ebN_element < nDOF_mesh_trial_element; ebN_element++)
1082 const int ebN = elementBoundariesArray.data()[eN * nDOF_mesh_trial_element + ebN_element];
1084 if (elementBoundaryElementsArray.data()[ebN * 2 + 1] != -1 && (ebN < nElementBoundaries_owned))
1094 double JA[nDOF_trial_element];
1095 double JB[nDOF_trial_element];
1096 std::fill(JA, JA + nDOF_trial_element, 0.0);
1097 std::fill(JB, JB + nDOF_trial_element, 0.0);
1102 for (
int ebN_element = 0; ebN_element < nDOF_mesh_trial_element; ebN_element++)
1106 const int ebN = elementBoundariesArray.data()[eN * nDOF_mesh_trial_element + ebN_element];
1119 if (elementBoundaryElementsArray.data()[ebN * 2 + 1] != -1 &&
1120 element_phi_f[(ebN_element + 1) % 3] * element_phi_f[(ebN_element + 2) % 3] < 0.0)
1131 const double eps_phi = 1.0e-12;
1132 auto assign_jump_side = [&](
int i,
bool isOuter,
double jump) {
1144 for (
int i = 0; i < nDOF_trial_element; i++)
1147 int eN_i = eN * nDOF_trial_element + i;
1148 const double jump_i = immersedBoundary_solutionJump_nodes.data()[u_l2g.data()[eN_i]];
1149 if (element_phi_f[i] > 0.0)
1151 assign_jump_side(i,
true, jump_i);
1153 else if (element_phi_f[i] <= 0.0)
1155 assign_jump_side(i,
false, jump_i);
1159 else if (icase_f == -1)
1162 else if (icase_f == 1)
1167 mesh_grad_trial_ref,
1177 elementBoundaryDiameter,
1184 mesh_trial_trace_ref,
1185 mesh_grad_trial_trace_ref,
1188 u_grad_trial_trace_ref,
1190 u_grad_test_trace_ref,
1194 nElementBoundaries_owned,
1203 shockCapturingDiffusion,
1208 nExteriorElementBoundaries_global,
1209 exteriorElementBoundariesArray,
1210 elementBoundariesArray,
1211 elementBoundaryElementsArray,
1212 elementBoundaryLocalElementBoundariesArray,
1216 embeddedBoundary_penalty,
1217 embeddedBoundary_normal_q,
1218 embeddedBoundary_u_q,
1220 immersedBoundary_penalty,
1221 immersedBoundary_sdf_q,
1222 immersedBoundary_normal_q,
1223 immersedBoundary_u_q,
1224 immersedBoundary_fluxJump_q,
1225 immersedBoundary_fluxJumpVector_q,
1226 immersedBoundary_solutionJump_nodes,
1233 Linfty_error.data()[0],
1242 for (
int i = 0; i < nDOF_test_element; i++)
1244 int eN_i = eN * nDOF_test_element + i;
1245 globalResidual.data()[offset_u + stride_u * u_l2g.data()[eN_i]] += elementResidual_u.data()[i];
1247 isActiveDOF.data()[offset_u + stride_u * u_l2g.data()[eN_i]] = 1.0;
1255 std::map<int, double> Dwp_Dn_jump, Dw_Dn_jump;
1256 double gamma_cutfem = embeddedBoundary_ghost_penalty, h_cutfem = elementBoundaryDiameter.data()[*it];
1257 for (
int kb = 0; kb < nQuadraturePoints_elementBoundary; kb++)
1259 double Du_Dn_jump = 0.0, dS;
1260 for (
int eN_side = 0; eN_side < 2; eN_side++)
1263 eN = elementBoundaryElementsArray.data()[ebN * 2 + eN_side];
1264 for (
int i = 0; i < nDOF_test_element; i++)
1266 Dw_Dn_jump[u_l2g.data()[eN * nDOF_test_element + i]] = 0.0;
1269 for (
int eN_side = 0; eN_side < 2; eN_side++)
1272 eN = elementBoundaryElementsArray.data()[ebN * 2 + eN_side],
1273 ebN_local = elementBoundaryLocalElementBoundariesArray.data()[ebN * 2 + eN_side],
1274 eN_nDOF_trial_element = eN * nDOF_trial_element,
1275 ebN_local_kb = ebN_local * nQuadraturePoints_elementBoundary + kb,
1276 ebN_local_kb_nSpace = ebN_local_kb * nSpace;
1278 grad_u_int[nSpace] = {0., 0.},
1279 jac_int[nSpace * nSpace],
1281 jacInv_int[nSpace * nSpace],
1282 boundaryJac[nSpace * (nSpace - 1)],
1283 metricTensor[(nSpace - 1) * (nSpace - 1)],
1284 metricTensorDetSqrt,
1285 u_test_dS[nDOF_test_element],
1286 u_grad_trial_trace[nDOF_trial_element * nSpace],
1287 u_grad_test_dS[nDOF_trial_element * nSpace],
1288 normal[2], x_int, y_int, z_int, xt_int, yt_int, zt_int, integralScaling,
1289 G[nSpace * nSpace], G_dd_G, tr_G, h_phi, h_penalty, penalty,
1290 force_x, force_y, force_z, force_p_x, force_p_y, force_p_z, force_v_x, force_v_y, force_v_z, r_x, r_y, r_z;
1292 ck.calculateMapping_elementBoundary(eN,
1298 mesh_trial_trace_ref.data(),
1299 mesh_grad_trial_trace_ref.data(),
1300 boundaryJac_ref.data(),
1306 metricTensorDetSqrt,
1309 x_int, y_int, z_int);
1310 dS = metricTensorDetSqrt * dS_ref.data()[kb];
1314 ck.gradTrialFromRef(&u_grad_trial_trace_ref.data()[ebN_local_kb_nSpace * nDOF_trial_element], jacInv_int, u_grad_trial_trace);
1316 ck.valFromDOF(u_dof.data(), &u_l2g.data()[eN_nDOF_trial_element], &u_trial_trace_ref.data()[ebN_local_kb * nDOF_test_element], u_int);
1317 ck.gradFromDOF(u_dof.data(), &u_l2g.data()[eN_nDOF_trial_element], u_grad_trial_trace, grad_u_int);
1318 for (
int I = 0; I < nSpace; I++)
1320 Du_Dn_jump += grad_u_int[I] * normal[I];
1322 for (
int i = 0; i < nDOF_test_element; i++)
1324 for (
int I = 0; I < nSpace; I++)
1325 Dw_Dn_jump[u_l2g.data()[eN_nDOF_trial_element + i]] += u_grad_trial_trace[i * nSpace + I] * normal[I];
1328 for (std::map<int, double>::iterator w_it = Dw_Dn_jump.begin(); w_it != Dw_Dn_jump.end(); ++w_it)
1330 int i_global = w_it->first;
1331 double Dw_Dn_jump_i = w_it->second;
1332 globalResidual.data()[offset_u + stride_u * i_global] += gamma_cutfem * h_cutfem * Du_Dn_jump * Dw_Dn_jump_i * dS;
1350 double xB_ref_faces[nDOF_mesh_trial_element * nQuadraturePoints_elementBoundary * 3];
1351 for (
int f = 0;
f < nDOF_mesh_trial_element;
f++)
1352 for (
int kb = 0; kb < nQuadraturePoints_elementBoundary; kb++)
1354 const int fkb =
f * nQuadraturePoints_elementBoundary + kb;
1355 const double *phi_m = &mesh_trial_trace_ref.data()[fkb * nDOF_mesh_trial_element];
1356 xB_ref_faces[fkb * 3 + 0] = phi_m[1];
1357 xB_ref_faces[fkb * 3 + 1] = phi_m[2];
1358 xB_ref_faces[fkb * 3 + 2] = 0.0;
1371 int eN_s[2], ebN_local_s[2];
1372 for (
int s = 0;
s < 2;
s++)
1374 eN_s[
s] = elementBoundaryElementsArray.data()[ebN * 2 +
s];
1375 ebN_local_s[
s] = elementBoundaryLocalElementBoundariesArray.data()[ebN * 2 +
s];
1388 double xq[2][nQuadraturePoints_elementBoundary][3];
1389 for (
int s = 0;
s < 2;
s++)
1390 for (
int kb = 0; kb < nQuadraturePoints_elementBoundary; kb++)
1392 double jac_t[nSpace * nSpace], jacDet_t, jacInv_t[nSpace * nSpace],
1393 bJac_t[nSpace * (nSpace - 1)], mT_t[(nSpace - 1) * (nSpace - 1)],
1394 mTDS_t, nrm_t[2], xt_ = 0.0, yt_ = 0.0, zt_ = 0.0;
1395 ck.calculateMapping_elementBoundary(eN_s[
s], ebN_local_s[
s], kb,
1396 ebN_local_s[
s] * nQuadraturePoints_elementBoundary + kb,
1397 mesh_dof.data(), mesh_l2g.data(),
1398 mesh_trial_trace_ref.data(), mesh_grad_trial_trace_ref.data(),
1399 boundaryJac_ref.data(), jac_t, jacDet_t, jacInv_t,
1400 bJac_t, mT_t, mTDS_t, normal_ref.data(), nrm_t,
1402 xq[
s][kb][0] = xt_; xq[
s][kb][1] = yt_; xq[
s][kb][2] = zt_;
1408 const double h_edge = elementBoundaryDiameter.data()[ebN];
1416 int kmap[2][nQuadraturePoints_elementBoundary];
1417 bool kmap_used[nQuadraturePoints_elementBoundary] = {};
1418 for (
int k = 0; k < nQuadraturePoints_elementBoundary; k++)
1422 double bestd = 1.0e300, nextd = 1.0e300;
1423 for (
int j = 0; j < nQuadraturePoints_elementBoundary; j++)
1426 for (
int I = 0; I < nSpace; I++)
1427 d += std::fabs(xq[1][j][I] - xq[0][k][I]);
1428 if (d < bestd) { nextd = bestd; bestd = d; best = j; }
1429 else if (d < nextd) { nextd = d; }
1431 if (best < 0 || kmap_used[best] || bestd >= 1.0e-8 * h_edge || nextd <= 2.0 * bestd)
1433 std::cerr <<
"ADR immersedSCIFEM: quadrature points on face " << ebN
1434 <<
" between elements " << eN_s[0] <<
" and " << eN_s[1]
1435 <<
" do not pair up (k=" << k <<
", best=" << best
1436 <<
", d=" << bestd <<
", runner-up=" << nextd
1437 <<
", h=" << h_edge <<
"); the mesh is non-conforming or the"
1438 <<
" boundary mapping is inconsistent." << std::endl;
1439 throw std::runtime_error(
"ADR immersedSCIFEM: face quadrature pairing failed");
1441 kmap_used[best] =
true;
1454 double edge_nodes[2][3], phi_edge[2];
1456 const int n0l = (ebN_local_s[0] + 1) % 3, n1l = (ebN_local_s[0] + 2) % 3;
1457 const int ln[2] = {n0l, n1l};
1458 for (
int e = 0; e < 2; e++)
1460 int eN_i = eN_s[0] * nDOF_trial_element + ln[e];
1461 phi_edge[e] = immersedBoundary_sdf_nodes.data()[u_l2g.data()[eN_i]];
1462 for (
int I = 0; I < 3; I++)
1463 edge_nodes[e][I] = mesh_dof.data()[u_l2g.data()[eN_i] * 3 + I];
1469 double edge_len2 = 0.0;
1470 for (
int I = 0; I < 3; I++)
1472 edge_vec[I] = edge_nodes[1][I] - edge_nodes[0][I];
1473 edge_len2 += edge_vec[I] * edge_vec[I];
1476 for (
int k = 0; k < nQuadraturePoints_elementBoundary; k++)
1479 double ua_s[2], ub_s[2], flux_a_s[2], flux_b_s[2];
1480 std::map<int, double> va_m[2], vb_m[2], fta_m[2], ftb_m[2];
1481 for (
int eN_side = 0; eN_side < 2; eN_side++)
1483 int eN = eN_s[eN_side],
1484 ebN_local = ebN_local_s[eN_side],
1485 kb = kmap[eN_side][k],
1486 eN_nDOF_trial_element = eN * nDOF_trial_element,
1487 ebN_local_kb = ebN_local * nQuadraturePoints_elementBoundary + kb;
1488 double ua = 0.0, ub = 0.0,
1489 grad_ua[nSpace] = {0., 0.}, grad_ub[nSpace] = {0., 0.},
1490 jac_int[nSpace * nSpace], jacDet_int, jacInv_int[nSpace * nSpace],
1491 boundaryJac[nSpace * (nSpace - 1)],
1492 metricTensor[(nSpace - 1) * (nSpace - 1)], metricTensorDetSqrt,
1493 normal[2], x_int, y_int, z_int;
1494 ck.calculateMapping_elementBoundary(eN, ebN_local, kb, ebN_local_kb,
1495 mesh_dof.data(), mesh_l2g.data(),
1496 mesh_trial_trace_ref.data(), mesh_grad_trial_trace_ref.data(),
1497 boundaryJac_ref.data(), jac_int, jacDet_int, jacInv_int,
1498 boundaryJac, metricTensor, metricTensorDetSqrt,
1499 normal_ref.data(), normal, x_int, y_int, z_int);
1503 dS = metricTensorDetSqrt * dS_ref.data()[kb];
1504 double sign_ne = (eN_side == 0) ? 1.0 : -1.0;
1506 auto element_u = xt::pyarray<double>::from_shape({nDOF_trial_element});
1507 double element_phi_f[nDOF_trial_element], element_nodes[nDOF_trial_element * 3];
1508 for (
int i = 0; i < nDOF_trial_element; i++)
1510 int eN_i = eN * nDOF_trial_element + i;
1511 element_u.data()[i] = u_dof.data()[u_l2g.data()[eN_i]];
1512 element_phi_f[i] = immersedBoundary_sdf_nodes.data()[u_l2g.data()[eN_i]];
1513 for (
int I = 0; I < 3; I++)
1514 element_nodes[i * 3 + I] = mesh_dof.data()[u_l2g.data()[eN_i] * 3 + I];
1524 double va[nDOF_trial_element], va_grad_trial[nDOF_trial_element * nSpace],
1525 vb[nDOF_trial_element], vb_grad_trial[nDOF_trial_element * nSpace];
1526 for (
int i = 0; i < nDOF_trial_element; i++)
1529 va_grad_trial[i * nSpace + 0] = gf_f.
VA_x(i);
1530 va_grad_trial[i * nSpace + 1] = gf_f.
VA_y(i);
1532 vb_grad_trial[i * nSpace + 0] = gf_f.
VB_x(i);
1533 vb_grad_trial[i * nSpace + 1] = gf_f.
VB_y(i);
1535 ck.valFromElementDOF(element_u.data(), va, ua);
1536 ck.gradFromElementDOF(element_u.data(), va_grad_trial, grad_ua);
1537 ck.valFromElementDOF(element_u.data(), vb, ub);
1538 ck.gradFromElementDOF(element_u.data(), vb_grad_trial, grad_ub);
1542 double fa = 0.0, fb = 0.0;
1543 for (
int I = 0; I < nSpace; I++)
1545 fa += mua * grad_ua[I] * normal[I];
1546 fb += mub * grad_ub[I] * normal[I];
1548 flux_a_s[eN_side] = sign_ne * fa;
1549 flux_b_s[eN_side] = sign_ne * fb;
1551 for (
int i = 0; i < nDOF_test_element; i++)
1553 int dof_i = u_l2g.data()[eN_nDOF_trial_element + i];
1554 va_m[eN_side][dof_i] = va[i];
1555 vb_m[eN_side][dof_i] = vb[i];
1556 double fta = 0.0, ftb = 0.0;
1557 for (
int I = 0; I < nSpace; I++)
1559 fta += mua * va_grad_trial[i * nSpace + I] * normal[I];
1560 ftb += mub * vb_grad_trial[i * nSpace + I] * normal[I];
1562 fta_m[eN_side][dof_i] = sign_ne * fta;
1563 ftb_m[eN_side][dof_i] = sign_ne * ftb;
1569 for (
int I = 0; I < 3; I++)
1570 proj += (xq[0][k][I] - edge_nodes[0][I]) * edge_vec[I];
1571 double t_edge = (edge_len2 > 1.0e-24) ? (proj / edge_len2) : 0.0;
1573 double ImH_e = 1.0 - H_e;
1575 double avg_flux_a = 0.5 * (flux_a_s[0] + flux_a_s[1]);
1576 double avg_flux_b = 0.5 * (flux_b_s[0] + flux_b_s[1]);
1577 double jump_ua = ua_s[0] - ua_s[1];
1578 double jump_ub = ub_s[0] - ub_s[1];
1582 for (
int side = 0; side < 2; side++)
1584 double v_sign = (side == 0) ? 1.0 : -1.0;
1585 for (std::map<int, double>::iterator
w = va_m[side].begin();
w != va_m[side].end(); ++
w)
1587 int dof_i =
w->first;
1588 double jva_i = v_sign * va_m[side][dof_i], jvb_i = v_sign * vb_m[side][dof_i];
1589 double Pa = avg_flux_a * jva_i + 0.5 * fta_m[side][dof_i] * jump_ua;
1590 double Pb = avg_flux_b * jvb_i + 0.5 * ftb_m[side][dof_i] * jump_ub;
1591 globalResidual.data()[offset_u + stride_u * dof_i] -=
1592 immersedSCIFEM_switch * (ImH_e * Pa + H_e * Pb) * dS;
1598 globalResidual.data()[offset_u + stride_u * dof_i] +=
1599 (immersedSCIFEM_penalty / h_edge) *
1600 (ImH_e * jump_ua * jva_i + H_e * jump_ub * jvb_i) * dS;
1617 for (
int ebNE = 0; ebNE < nExteriorElementBoundaries_global; ebNE++)
1619 int ebN = exteriorElementBoundariesArray.data()[ebNE],
1620 eN = elementBoundaryElementsArray.data()[ebN * 2 + 0],
1621 ebN_local = elementBoundaryLocalElementBoundariesArray.data()[ebN * 2 + 0],
1622 eN_nDOF_trial_element = eN * nDOF_trial_element;
1623 double elementResidual_u[nDOF_test_element];
1624 for (
int i = 0; i < nDOF_test_element; i++)
1626 elementResidual_u[i] = 0.0;
1628 for (
int kb = 0; kb < nQuadraturePoints_elementBoundary; kb++)
1630 int ebNE_kb = ebNE * nQuadraturePoints_elementBoundary + kb,
1631 ebNE_kb_nSpace = ebNE_kb * nSpace,
1632 ebN_local_kb = ebN_local * nQuadraturePoints_elementBoundary + kb,
1633 ebN_local_kb_nSpace = ebN_local_kb * nSpace;
1644 flux_diff_ext = 0.0,
1645 flux_advect_ext = 0.0,
1652 jac_ext[nSpace * nSpace],
1654 jacInv_ext[nSpace * nSpace],
1655 boundaryJac[nSpace * (nSpace - 1)],
1656 metricTensor[(nSpace - 1) * (nSpace - 1)],
1657 metricTensorDetSqrt,
1659 u_test_dS[nDOF_test_element],
1660 u_grad_trial_trace[nDOF_trial_element * nSpace],
1661 u_grad_test_dS[nDOF_trial_element * nSpace],
1662 normal[nSpace], x_ext, y_ext, z_ext, xt_ext, yt_ext, zt_ext, integralScaling,
1664 G[nSpace * nSpace], G_dd_G, tr_G;
1669 ck.calculateMapping_elementBoundary(eN,
1675 mesh_trial_trace_ref.data(),
1676 mesh_grad_trial_trace_ref.data(),
1677 boundaryJac_ref.data(),
1683 metricTensorDetSqrt,
1686 x_ext, y_ext, z_ext);
1700 dS = metricTensorDetSqrt * dS_ref.data()[kb];
1703 ck.calculateG(jacInv_ext, G, G_dd_G, tr_G);
1707 ck.gradTrialFromRef(&u_grad_trial_trace_ref.data()[ebN_local_kb_nSpace * nDOF_trial_element], jacInv_ext, u_grad_trial_trace);
1709 ck.valFromDOF(u_dof.data(), &u_l2g.data()[eN_nDOF_trial_element], &u_trial_trace_ref.data()[ebN_local_kb * nDOF_test_element], u_ext);
1710 ck.gradFromDOF(u_dof.data(), &u_l2g.data()[eN_nDOF_trial_element], u_grad_trial_trace, grad_u_ext);
1712 for (
int j = 0; j < nDOF_trial_element; j++)
1714 u_test_dS[j] = u_test_trace_ref.data()[ebN_local_kb * nDOF_test_element + j] * dS;
1715 for (
int I = 0; I < nSpace; I++)
1716 u_grad_test_dS[j * nSpace + I] = u_grad_trial_trace[j * nSpace + I] * dS;
1721 bc_u_ext = isDOFBoundary_u.data()[ebNE_kb] * ebqe_bc_u_ext.data()[ebNE_kb] + (1 - isDOFBoundary_u.data()[ebNE_kb]) * u_ext;
1726 a_ext = &ebqe_a.data()[ebNE_kb * sd_rowptr[nSpace]];
1727 for (
int I = 0; I < nSpace; I++)
1729 f_ext[I] = ebqe_v.data()[ebNE_kb * nSpace + I] * u_ext;
1730 df_ext[I] = ebqe_v.data()[ebNE_kb * nSpace + I];
1731 bc_f_ext[I] = ebqe_v.data()[ebNE_kb * nSpace + I] * bc_u_ext;
1732 bc_df_ext[I] = ebqe_v.data()[ebNE_kb * nSpace + I];
1767 isDOFBoundary_u.data()[ebNE_kb],
1768 isDiffusiveFluxBoundary_u.data()[ebNE_kb],
1772 ebqe_bc_flux_u_ext.data()[ebNE_kb],
1776 ebqe_penalty_ext.data()[ebNE_kb],
1779 isAdvectiveFluxBoundary_u.data()[ebNE_kb],
1782 ebqe_bc_flux_u_ext.data()[ebNE_kb],
1790 for (
int i = 0; i < nDOF_test_element; i++)
1793 elementResidual_u[i] +=
ck.ExteriorElementBoundaryFlux(flux_diff_ext + flux_advect_ext, u_test_dS[i]) +
1794 ck.ExteriorElementBoundaryDiffusionAdjoint(isDOFBoundary_u.data()[ebNE_kb],
1795 isDiffusiveFluxBoundary_u.data()[ebNE_kb],
1803 &u_grad_test_dS[i * nSpace]);
1809 for (
int i = 0; i < nDOF_test_element; i++)
1811 int eN_i = eN * nDOF_test_element + i;
1812 globalResidual.data()[offset_u + stride_u * u_l2g.data()[eN_i]] += elementResidual_u[i];
1819 xt::pyarray<double> &mesh_trial_ref,
1820 xt::pyarray<double> &mesh_grad_trial_ref,
1821 xt::pyarray<double> &mesh_dof,
1822 xt::pyarray<int> &mesh_l2g,
1823 xt::pyarray<double> &x_ref,
1824 xt::pyarray<double> &dV_ref,
1825 xt::pyarray<double> &u_trial_ref,
1826 xt::pyarray<double> &u_grad_trial_ref,
1827 xt::pyarray<double> &u_test_ref,
1828 xt::pyarray<double> &u_grad_test_ref,
1829 xt::pyarray<double> &elementDiameter,
1830 xt::pyarray<double> &elementBoundaryDiameter,
1831 xt::pyarray<double> &nodeDiametersArray,
1832 xt::pyarray<double> &cfl,
1838 xt::pyarray<double> &mesh_trial_trace_ref,
1839 xt::pyarray<double> &mesh_grad_trial_trace_ref,
1840 xt::pyarray<double> &dS_ref,
1841 xt::pyarray<double> &u_trial_trace_ref,
1842 xt::pyarray<double> &u_grad_trial_trace_ref,
1843 xt::pyarray<double> &u_test_trace_ref,
1844 xt::pyarray<double> &u_grad_test_trace_ref,
1845 xt::pyarray<double> &normal_ref,
1846 xt::pyarray<double> &boundaryJac_ref,
1848 int nElements_global,
1849 int nElementBoundaries_owned,
1850 xt::pyarray<int> &u_l2g,
1851 xt::pyarray<double> &u_dof,
1852 xt::pyarray<int> &sd_rowptr,
1853 xt::pyarray<int> &sd_colind,
1854 xt::pyarray<double> &q_a,
1855 xt::pyarray<double> &q_v,
1856 xt::pyarray<double> &q_r,
1857 int lag_shockCapturing,
1858 double shockCapturingDiffusion,
1859 xt::pyarray<double> &q_numDiff_u,
1860 xt::pyarray<double> &q_numDiff_u_last,
1861 xt::pyarray<double> &elementJacobian_u_u,
1862 xt::pyarray<double> &element_u,
1864 const bool embeddedBoundary,
1865 const double embeddedBoundary_penalty,
1866 xt::pyarray<double> &embeddedBoundary_normal_q,
1867 xt::pyarray<double> &embeddedBoundary_u_q,
1868 const bool immersedBoundary,
1869 const double immersedBoundary_penalty,
1870 xt::pyarray<double> &immersedBoundary_sdf_q,
1871 xt::pyarray<double> &immersedBoundary_normal_q,
1872 xt::pyarray<double> &immersedBoundary_u_q,
1873 xt::pyarray<double> &immersedBoundary_fluxJump_q,
1874 xt::pyarray<double> &immersedBoundary_fluxJumpVector_q,
1875 xt::pyarray<double> &immersedBoundary_solutionJump_nodes,
1876 double *element_phi_f,
1886 for (
int i = 0; i < nDOF_test_element; i++)
1887 for (
int j = 0; j < nDOF_trial_element; j++)
1889 elementJacobian_u_u.data()[i * nDOF_trial_element + j] = 0.0;
1891 for (
int k = 0; k < nQuadraturePoints_element; k++)
1896 int eN_k = eN * nQuadraturePoints_element + k;
1897 int eN_k_3d = eN_k * 3;
1907 r_s = 0.0, dr_s = 0.0,
1908 f[nSpace],
df[nSpace],
1909 f_s[nSpace] = {0., 0.}, df_s[nSpace] = {0., 0.},
1910 ham_s = 0.0, dham_s[nSpace] = {0., 0.},
1911 r_f = 0.0, dr_f = 0.0,
1912 f_f[nSpace] = {0., 0.}, df_f[nSpace] = {0., 0.},
1913 ham_f = 0.0, dham_f[nSpace] = {0., 0.},
1914 m_t = 0.0, dm_t = 0.0,
1915 dpdeResidual_u_u[nDOF_trial_element],
1916 Lstar_u[nDOF_test_element],
1917 dsubgridError_u_u[nDOF_trial_element],
1918 tau = 0.0, tau0 = 0.0, tau1 = 0.0,
1921 jac[nSpace * nSpace],
1923 jacInv[nSpace * nSpace],
1924 u_grad_trial[nDOF_trial_element * nSpace],
1925 ua_grad_trial[nDOF_trial_element * nSpace],
1926 ub_grad_trial[nDOF_trial_element * nSpace],
1928 ua_trial[nDOF_trial_element],
1929 ub_trial[nDOF_trial_element],
1930 u_test_dV[nDOF_test_element],
1931 ua_test_dV[nDOF_test_element],
1932 ub_test_dV[nDOF_test_element],
1933 u_grad_test_dV[nDOF_test_element * nSpace],
1934 ua_grad_test_dV[nDOF_test_element * nSpace],
1935 ub_grad_test_dV[nDOF_test_element * nSpace],
1937 G[nSpace * nSpace], G_dd_G, tr_G;
1941 ck.calculateMapping_element(eN,
1945 mesh_trial_ref.data(),
1946 mesh_grad_trial_ref.data(),
1951 ck.calculateH_element(eN,
1953 nodeDiametersArray.data(),
1955 mesh_trial_ref.data(),
1958 dV = fabs(jacDet) * dV_ref.data()[k];
1960 ck.calculateG(jacInv, G, G_dd_G, tr_G);
1963 ck.gradTrialFromRef(&u_grad_trial_ref.data()[k * nDOF_trial_element * nSpace], jacInv, u_grad_trial);
1965 ck.valFromElementDOF(element_u.data(), &u_trial_ref.data()[k * nDOF_trial_element],
u);
1967 ck.gradFromElementDOF(element_u.data(), u_grad_trial, grad_u);
1969 for (
int j = 0; j < nDOF_trial_element; j++)
1971 u_test_dV[j] = u_test_ref.data()[k * nDOF_trial_element + j] * dV;
1972 for (
int I = 0; I < nSpace; I++)
1974 u_grad_test_dV[j * nSpace + I] = u_grad_trial[j * nSpace + I] * dV;
1982 double va[nDOF_trial_element], va_grad_trial[nDOF_trial_element * nSpace],
1983 vb[nDOF_trial_element], vb_grad_trial[nDOF_trial_element * nSpace];
1984 for (
int i = 0; i < nDOF_trial_element; i++)
1987 va_grad_trial[i * nSpace + 0] = gf_f.
VA_x(i);
1988 va_grad_trial[i * nSpace + 1] = gf_f.
VA_y(i);
1990 vb_grad_trial[i * nSpace + 0] = gf_f.
VB_x(i);
1991 vb_grad_trial[i * nSpace + 1] = gf_f.
VB_y(i);
1997 ck.valFromElementDOF(element_u.data(), va, ua);
1998 ck.gradFromElementDOF(element_u.data(), va_grad_trial, grad_ua);
1999 ck.valFromElementDOF(element_u.data(), vb, ub);
2000 ck.gradFromElementDOF(element_u.data(), vb_grad_trial, grad_ub);
2001 for (
int i = 0; i < nDOF_test_element; i++)
2003 ua_test_dV[i] = va[i] * dV;
2004 ub_test_dV[i] = vb[i] * dV;
2005 for (
int I = 0; I < nSpace; I++)
2007 ua_grad_test_dV[i * nSpace + I] = va_grad_trial[i * nSpace + I] * dV;
2008 ub_grad_test_dV[i * nSpace + I] = vb_grad_trial[i * nSpace + I] * dV;
2011 for (
int j = 0; j < nDOF_trial_element; j++)
2013 ua_trial[j] = va[j];
2014 ub_trial[j] = vb[j];
2015 for (
int I = 0; I < nSpace; I++)
2017 ua_grad_trial[j * nSpace + I] = va_grad_trial[j * nSpace + I];
2018 ub_grad_trial[j * nSpace + I] = vb_grad_trial[j * nSpace + I];
2027 for (
int i = 0; i < nDOF_test_element; i++)
2029 ua_test_dV[i] = u_test_dV[i];
2030 ub_test_dV[i] = u_test_dV[i];
2031 for (
int I = 0; I < nSpace; I++)
2033 ua_grad_test_dV[i * nSpace + I] = u_grad_test_dV[i * nSpace + I];
2034 ub_grad_test_dV[i * nSpace + I] = u_grad_test_dV[i * nSpace + I];
2043 a = &q_a.data()[eN_k * sd_rowptr.data()[nSpace]];
2044 for (
int I = 0; I < nSpace; I++)
2045 df[I] = q_v.data()[eN_k * nSpace + I];
2047 const double H_s = gf_s.
H(0., 0.);
2048 const double D_s = gf_s.
D(0., 0.);
2049 if (embeddedBoundary)
2051 double level_set_normal[nSpace];
2053 double norm_exact = 0.0, norm_cut = 0.0;
2054 for (
int I = 0; I < nSpace; I++)
2056 sign += embeddedBoundary_normal_q.data()[eN_k_3d + I] * gf_s.
get_normal()[I];
2058 norm_cut += level_set_normal[I] * level_set_normal[I];
2059 norm_exact += embeddedBoundary_normal_q.data()[eN_k_3d + I] * embeddedBoundary_normal_q.data()[eN_k_3d + I];
2061 assert(std::fabs(1.0 - norm_cut) < 1.0e-8);
2062 assert(std::fabs(1.0 - norm_exact) < 1.0e-8);
2064 for (
int I = 0; I < nSpace; I++)
2065 level_set_normal[I] *= -1.0;
2069 embeddedBoundary_u_q.data()[eN_k],
2081 const double ImH_f = gf_f.
ImH(0., 0.);
2082 const double H_f = gf_f.
H(0., 0.);
2083 const double D_f = gf_f.
D(0., 0.);
2084 if (immersedBoundary)
2086 double level_set_normal[nSpace];
2088 double norm_exact = 0.0, norm_cut = 0.0;
2089 for (
int I = 0; I < nSpace; I++)
2091 sign += immersedBoundary_normal_q.data()[eN_k_3d + I] * gf_f.
get_normal()[I];
2093 norm_cut += level_set_normal[I] * level_set_normal[I];
2094 norm_exact += immersedBoundary_normal_q.data()[eN_k_3d + I] * immersedBoundary_normal_q.data()[eN_k_3d + I];
2096 assert(std::fabs(1.0 - norm_cut) < 1.0e-8);
2097 assert(std::fabs(1.0 - norm_exact) < 1.0e-8);
2099 for (
int I = 0; I < nSpace; I++)
2100 level_set_normal[I] *= -1.0;
2107 immersedBoundary_u_q.data()[eN_k],
2117 immersedBoundary_fluxJump_q.data()[eN_k],
2118 &immersedBoundary_fluxJumpVector_q.data()[eN_k_3d],
2125 for (
int i = 0; i < nDOF_test_element; i++)
2129 int i_nSpace = i * nSpace;
2130 Lstar_u[i] =
ck.Advection_adjoint(
df, &u_grad_test_dV[i_nSpace]);
2133 for (
int j = 0; j < nDOF_trial_element; j++)
2137 int j_nSpace = j * nSpace;
2138 dpdeResidual_u_u[j] =
ck.MassJacobian_strong(dm_t, u_trial_ref.data()[k * nDOF_trial_element + j]) +
2139 ck.AdvectionJacobian_strong(
df, &u_grad_trial[j_nSpace]);
2154 tau = useMetrics * tau1 + (1.0 - useMetrics) * tau0;
2156 for (
int j = 0; j < nDOF_trial_element; j++)
2157 dsubgridError_u_u[j] = -tau * dpdeResidual_u_u[j];
2160 double a_loc[nSpace * nSpace];
2161 for (
int I = 0; I < nSpace * nSpace; I++) a_loc[I] = 0.0;
2162 for (
int i = 0; i < nDOF_test_element; i++)
2164 int i_nSpace = i * nSpace;
2165 for (
int j = 0; j < nDOF_trial_element; j++)
2167 int j_nSpace = j * nSpace;
2172 for (
int I = 0; I < nSpace; I++) a_loc[I * nSpace + I] = mua;
2173 elementJacobian_u_u.data()[i * nDOF_trial_element + j] += ImH_f * H_s * (
ck.AdvectionJacobian_weak(
df, ua_trial[j], &ua_grad_test_dV[i_nSpace]) +
2174 ck.SimpleDiffusionJacobian_weak(sd_rowptr.data(), sd_colind.data(), a_loc, &ua_grad_trial[j_nSpace], &ua_grad_test_dV[i_nSpace]) +
2175 ck.ReactionJacobian_weak(dr, ua_trial[j], ua_test_dV[i]) +
2176 ck.NumericalDiffusionJacobian(q_numDiff_u_last.data()[eN_k], &ua_grad_trial[j_nSpace], &ua_grad_test_dV[i_nSpace]));
2178 for (
int I = 0; I < nSpace; I++) a_loc[I * nSpace + I] = mub;
2179 elementJacobian_u_u.data()[i * nDOF_trial_element + j] += H_f * H_s * (
ck.AdvectionJacobian_weak(
df, ub_trial[j], &ub_grad_test_dV[i_nSpace]) +
2180 ck.SimpleDiffusionJacobian_weak(sd_rowptr.data(), sd_colind.data(), a_loc, &ub_grad_trial[j_nSpace], &ub_grad_test_dV[i_nSpace]) +
2181 ck.ReactionJacobian_weak(dr, ub_trial[j], ub_test_dV[i]) +
2182 ck.NumericalDiffusionJacobian(q_numDiff_u_last.data()[eN_k], &ub_grad_trial[j_nSpace], &ub_grad_test_dV[i_nSpace]));
2184 else if (gf_f.
exact.edge == -1 || gf_f.
exact.corner == -1)
2186 for (
int I = 0; I < nSpace; I++) a_loc[I * nSpace + I] = mua;
2187 elementJacobian_u_u.data()[i * nDOF_trial_element + j] += ImH_f * H_s * (
ck.AdvectionJacobian_weak(
df, ua_trial[j], &ua_grad_test_dV[i_nSpace]) +
2188 ck.SimpleDiffusionJacobian_weak(sd_rowptr.data(), sd_colind.data(), a_loc, &ua_grad_trial[j_nSpace], &ua_grad_test_dV[i_nSpace]) +
2189 ck.ReactionJacobian_weak(dr, ua_trial[j], ua_test_dV[i]) +
2190 ck.NumericalDiffusionJacobian(q_numDiff_u_last.data()[eN_k], &ua_grad_trial[j_nSpace], &ua_grad_test_dV[i_nSpace]));
2192 else if (gf_f.
exact.edge == 1 || gf_f.
exact.corner == 1)
2194 for (
int I = 0; I < nSpace; I++) a_loc[I * nSpace + I] = mub;
2195 elementJacobian_u_u.data()[i * nDOF_trial_element + j] += H_f * H_s * (
ck.AdvectionJacobian_weak(
df, ub_trial[j], &ub_grad_test_dV[i_nSpace]) +
2196 ck.SimpleDiffusionJacobian_weak(sd_rowptr.data(), sd_colind.data(), a_loc, &ub_grad_trial[j_nSpace], &ub_grad_test_dV[i_nSpace]) +
2197 ck.ReactionJacobian_weak(dr, ub_trial[j], ub_test_dV[i]) +
2198 ck.NumericalDiffusionJacobian(q_numDiff_u_last.data()[eN_k], &ub_grad_trial[j_nSpace], &ub_grad_test_dV[i_nSpace]));
2200 else assert(
false &&
"Invalid gf_f.exact.edge/corner values. Should be -1, 0 or +1.");
2204 elementJacobian_u_u.data()[i * nDOF_trial_element + j] += H_s * (
ck.AdvectionJacobian_weak(
df, u_trial_ref.data()[k * nDOF_trial_element + j], &u_grad_test_dV[i_nSpace]) +
2205 ck.SimpleDiffusionJacobian_weak(sd_rowptr.data(), sd_colind.data(), a, &u_grad_trial[j_nSpace], &u_grad_test_dV[i_nSpace]) +
2206 ck.ReactionJacobian_weak(dr, u_trial_ref.data()[k * nDOF_trial_element + j], u_test_dV[i]) +
2207 ck.SubgridErrorJacobian(dsubgridError_u_u[j], Lstar_u[i]) +
2208 ck.NumericalDiffusionJacobian(q_numDiff_u_last.data()[eN_k], &u_grad_trial[j_nSpace], &u_grad_test_dV[i_nSpace]));
2210 if (embeddedBoundary)
2212 if (gf_s.
exact.edge >=0 && !gf_s.
exact.corner)
2214 elementJacobian_u_u.data()[i * nDOF_trial_element + j] += (
ck.AdvectionJacobian_weak(df_s, u_trial_ref.data()[k * nDOF_trial_element + j], &u_grad_test_dV[i_nSpace])
2215 +
ck.ReactionJacobian_weak(dr_s, u_trial_ref.data()[k * nDOF_trial_element + j], u_test_dV[i])
2216 +
ck.HamiltonianJacobian_weak(dham_s, &u_grad_trial[j_nSpace], u_test_dV[i]));
2219 if (immersedBoundary)
2221 if (gf_f.
exact.edge >=0 && !gf_f.
exact.corner){
2223 elementJacobian_u_u.data()[i * nDOF_trial_element + j] += (
ck.AdvectionJacobian_weak(df_f, u_trial_ref.data()[k * nDOF_trial_element + j], &u_grad_test_dV[i_nSpace]) +
2224 ck.ReactionJacobian_weak(dr_f, u_trial_ref.data()[k * nDOF_trial_element + j], u_test_dV[i]) +
2225 ck.HamiltonianJacobian_weak(dham_f, &u_grad_trial[j_nSpace], u_test_dV[i]));
2238 xt::pyarray<double> &mesh_trial_ref = args.
array<
double>(
"mesh_trial_ref");
2239 xt::pyarray<double> &mesh_grad_trial_ref = args.
array<
double>(
"mesh_grad_trial_ref");
2240 xt::pyarray<double> &mesh_dof = args.
array<
double>(
"mesh_dof");
2241 xt::pyarray<int> &mesh_l2g = args.
array<
int>(
"mesh_l2g");
2242 xt::pyarray<double> &dV_ref = args.
array<
double>(
"dV_ref");
2243 xt::pyarray<double> &u_trial_ref = args.
array<
double>(
"u_trial_ref");
2244 xt::pyarray<double> &u_grad_trial_ref = args.
array<
double>(
"u_grad_trial_ref");
2245 xt::pyarray<double> &u_test_ref = args.
array<
double>(
"u_test_ref");
2246 xt::pyarray<double> &u_grad_test_ref = args.
array<
double>(
"u_grad_test_ref");
2247 xt::pyarray<double> &elementDiameter = args.
array<
double>(
"elementDiameter");
2248 xt::pyarray<double> &cfl = args.
array<
double>(
"cfl");
2249 double Ct_sge = args.
scalar<
double>(
"Ct_sge");
2250 double sc_uref = args.
scalar<
double>(
"sc_uref");
2251 double sc_alpha = args.
scalar<
double>(
"sc_alpha");
2252 double useMetrics = args.
scalar<
double>(
"useMetrics");
2253 xt::pyarray<double> &mesh_trial_trace_ref = args.
array<
double>(
"mesh_trial_trace_ref");
2254 xt::pyarray<double> &mesh_grad_trial_trace_ref = args.
array<
double>(
"mesh_grad_trial_trace_ref");
2255 xt::pyarray<double> &dS_ref = args.
array<
double>(
"dS_ref");
2256 xt::pyarray<double> &u_trial_trace_ref = args.
array<
double>(
"u_trial_trace_ref");
2257 xt::pyarray<double> &u_grad_trial_trace_ref = args.
array<
double>(
"u_grad_trial_trace_ref");
2258 xt::pyarray<double> &u_test_trace_ref = args.
array<
double>(
"u_test_trace_ref");
2259 xt::pyarray<double> &u_grad_test_trace_ref = args.
array<
double>(
"u_grad_test_trace_ref");
2260 xt::pyarray<double> &normal_ref = args.
array<
double>(
"normal_ref");
2261 xt::pyarray<double> &boundaryJac_ref = args.
array<
double>(
"boundaryJac_ref");
2262 int nElements_global = args.
scalar<
int>(
"nElements_global");
2263 xt::pyarray<int> &u_l2g = args.
array<
int>(
"u_l2g");
2264 xt::pyarray<double> &u_dof = args.
array<
double>(
"u_dof");
2265 xt::pyarray<int> &sd_rowptr = args.
array<
int>(
"sd_rowptr");
2266 xt::pyarray<int> &sd_colind = args.
array<
int>(
"sd_colind");
2267 xt::pyarray<double> &q_a = args.
array<
double>(
"q_a");
2268 xt::pyarray<double> &q_v = args.
array<
double>(
"q_v");
2269 xt::pyarray<double> &q_r = args.
array<
double>(
"q_r");
2270 int lag_shockCapturing = args.
scalar<
int>(
"lag_shockCapturing");
2271 double shockCapturingDiffusion = args.
scalar<
double>(
"shockCapturingDiffusion");
2272 xt::pyarray<double> &q_numDiff_u = args.
array<
double>(
"q_numDiff_u");
2273 xt::pyarray<double> &q_numDiff_u_last = args.
array<
double>(
"q_numDiff_u_last");
2274 xt::pyarray<int> &csrRowIndeces_u_u = args.
array<
int>(
"csrRowIndeces_u_u");
2275 xt::pyarray<int> &csrColumnOffsets_u_u = args.
array<
int>(
"csrColumnOffsets_u_u");
2276 xt::pyarray<double> &globalJacobian = args.
array<
double>(
"globalJacobian");
2277 int nExteriorElementBoundaries_global = args.
scalar<
int>(
"nExteriorElementBoundaries_global");
2278 xt::pyarray<int> &exteriorElementBoundariesArray = args.
array<
int>(
"exteriorElementBoundariesArray");
2279 xt::pyarray<int> &elementBoundaryElementsArray = args.
array<
int>(
"elementBoundaryElementsArray");
2280 xt::pyarray<int> &elementBoundaryLocalElementBoundariesArray = args.
array<
int>(
"elementBoundaryLocalElementBoundariesArray");
2281 xt::pyarray<double> &ebqe_a = args.
array<
double>(
"ebqe_a");
2282 xt::pyarray<double> &ebqe_v = args.
array<
double>(
"ebqe_v");
2283 xt::pyarray<int> &isDOFBoundary_u = args.
array<
int>(
"isDOFBoundary_u");
2284 xt::pyarray<double> &ebqe_bc_u_ext = args.
array<
double>(
"ebqe_bc_u_ext");
2285 xt::pyarray<int> &isDiffusiveFluxBoundary_u = args.
array<
int>(
"isDiffusiveFluxBoundary_u");
2286 xt::pyarray<int> &isAdvectiveFluxBoundary_u = args.
array<
int>(
"isAdvectiveFluxBoundary_u");
2287 xt::pyarray<double> &ebqe_bc_flux_u_ext = args.
array<
double>(
"ebqe_bc_flux_u_ext");
2288 xt::pyarray<double> &ebqe_bc_advectiveFlux_u_ext = args.
array<
double>(
"ebqe_bc_advectiveFlux_u_ext");
2289 xt::pyarray<int> &csrColumnOffsets_eb_u_u = args.
array<
int>(
"csrColumnOffsets_eb_u_u");
2290 xt::pyarray<double> &ebqe_penalty_ext = args.
array<
double>(
"ebqe_penalty_ext");
2291 const bool embeddedBoundary = args.
scalar<
int>(
"embeddedBoundary");
2292 const double embeddedBoundary_penalty = args.
scalar<
double>(
"embeddedBoundary_penalty");
2293 const double embeddedBoundary_ghost_penalty = args.
scalar<
double>(
"embeddedBoundary_ghost_penalty");
2294 xt::pyarray<double> &embeddedBoundary_sdf_nodes = args.
array<
double>(
"embeddedBoundary_sdf_nodes");
2295 xt::pyarray<double> &embeddedBoundary_sdf_q = args.
array<
double>(
"embeddedBoundary_sdf_q");
2296 xt::pyarray<double> &embeddedBoundary_normal_q = args.
array<
double>(
"embeddedBoundary_normal_q");
2297 xt::pyarray<double> &embeddedBoundary_u_q = args.
array<
double>(
"embeddedBoundary_u_q");
2298 const bool immersedBoundary = args.
scalar<
int>(
"immersedBoundary");
2299 const double immersedBoundary_penalty = args.
scalar<
double>(
"immersedBoundary_penalty");
2300 const double immersedSCIFEM_switch = args.
scalar<
double>(
"immersedSCIFEM_switch");
2301 const double immersedSCIFEM_penalty = args.
scalar<
double>(
"immersedSCIFEM_penalty");
2302 const bool PG = args.
scalar<
int>(
"PG");
2303 xt::pyarray<double> &immersedBoundary_sdf_nodes = args.
array<
double>(
"immersedBoundary_sdf_nodes");
2304 xt::pyarray<double> &immersedBoundary_sdf_q = args.
array<
double>(
"immersedBoundary_sdf_q");
2305 xt::pyarray<double> &immersedBoundary_normal_q = args.
array<
double>(
"immersedBoundary_normal_q");
2306 xt::pyarray<double> &immersedBoundary_u_q = args.
array<
double>(
"immersedBoundary_u_q");
2307 xt::pyarray<double> &immersedBoundary_fluxJump_q = args.
array<
double>(
"immersedBoundary_fluxJump_q");
2308 xt::pyarray<double> &immersedBoundary_fluxJumpVector_q = args.
array<
double>(
"immersedBoundary_fluxJumpVector_q");
2309 xt::pyarray<double> &immersedBoundary_solutionJump_nodes = args.
array<
double>(
"immersedBoundary_solutionJump_nodes");
2310 xt::pyarray<double> &isActiveDOF = args.
array<
double>(
"isActiveDOF");
2311 const double eb_adjoint_sigma = args.
scalar<
double>(
"eb_adjoint_sigma");
2312 xt::pyarray<double> &x_ref = args.
array<
double>(
"x_ref");
2313 xt::pyarray<double> &xB_ref = args.
array<
double>(
"xB_ref");
2314 xt::pyarray<int> &elementBoundariesArray = args.
array<
int>(
"elementBoundariesArray");
2315 const int nElementBoundaries_owned = args.
scalar<
int>(
"nElementBoundaries_owned");
2316 xt::pyarray<double> &elementBoundaryDiameter = args.
array<
double>(
"elementBoundaryDiameter");
2317 xt::pyarray<double> &nodeDiametersArray = args.
array<
double>(
"nodeDiametersArray");
2318 const double mua = args.
scalar<
double>(
"mua");
2319 const double mub = args.
scalar<
double>(
"mub");
2320 const double jf = args.
scalar<
double>(
"jf");
2321 const bool recomputeIFEMGeometry = args.
scalar<
int>(
"recomputeIFEMGeometry");
2323 if (recomputeIFEMGeometry)
2329 for (
int eN = 0; eN < nElements_global; eN++)
2333 auto elementJacobian_u_u = xt::pyarray<double>::from_shape({nDOF_test_element * nDOF_trial_element});
2334 auto element_u = xt::pyarray<double>::from_shape({nDOF_trial_element});
2335 for (
int j = 0; j < nDOF_trial_element; j++)
2337 int eN_j = eN * nDOF_trial_element + j;
2338 element_u.data()[j] = u_dof.data()[u_l2g.data()[eN_j]];
2340 double element_phi_s[nDOF_trial_element];
2341 for (
int j = 0; j < nDOF_trial_element; j++)
2343 int eN_j = eN * nDOF_trial_element + j;
2344 element_phi_s[j] = embeddedBoundary_sdf_nodes.data()[u_l2g.data()[eN_j]];
2346 double element_phi_f[nDOF_trial_element];
2347 for (
int j = 0; j < nDOF_trial_element; j++)
2349 int eN_j = eN * nDOF_trial_element + j;
2350 element_phi_f[j] = immersedBoundary_sdf_nodes.data()[u_l2g.data()[eN_j]];
2352 double element_nodes[nDOF_trial_element * 3];
2353 for (
int i = 0; i < nDOF_trial_element; i++)
2355 int eN_i = eN * nDOF_trial_element + i;
2356 for (
int I = 0; I < 3; I++)
2358 element_nodes[i * 3 + I] = mesh_dof.data()[u_l2g.data()[eN_i] * 3 + I];
2375 mesh_grad_trial_ref,
2385 elementBoundaryDiameter,
2392 mesh_trial_trace_ref,
2393 mesh_grad_trial_trace_ref,
2396 u_grad_trial_trace_ref,
2398 u_grad_test_trace_ref,
2402 nElementBoundaries_owned,
2411 shockCapturingDiffusion,
2414 elementJacobian_u_u,
2418 embeddedBoundary_penalty,
2419 embeddedBoundary_normal_q,
2420 embeddedBoundary_u_q,
2422 immersedBoundary_penalty,
2423 immersedBoundary_sdf_q,
2424 immersedBoundary_normal_q,
2425 immersedBoundary_u_q,
2426 immersedBoundary_fluxJump_q,
2427 immersedBoundary_fluxJumpVector_q,
2428 immersedBoundary_solutionJump_nodes,
2436 for (
int i = 0; i < nDOF_test_element; i++)
2438 int eN_i = eN * nDOF_test_element + i;
2439 for (
int j = 0; j < nDOF_trial_element; j++)
2441 int eN_i_j = eN_i * nDOF_trial_element + j;
2442 globalJacobian.data()[csrRowIndeces_u_u.data()[eN_i] + csrColumnOffsets_u_u.data()[eN_i_j]] += elementJacobian_u_u.data()[i * nDOF_trial_element + j];
2446 std::cout << std::endl;
2450 std::map<int, double> Dw_Dn_jump;
2451 std::map<std::pair<int, int>,
int> u_u_nz;
2452 double gamma_cutfem = embeddedBoundary_ghost_penalty, h_cutfem = elementBoundaryDiameter.data()[*it];
2453 int eN_nDOF_trial_element = elementBoundaryElementsArray.data()[(*it) * 2 + 0] * nDOF_trial_element;
2454 for (
int kb = 0; kb < nQuadraturePoints_elementBoundary; kb++)
2456 double Dp_Dn_jump = 0.0, Du_Dn_jump = 0.0, Dv_Dn_jump = 0.0, dS;
2457 for (
int eN_side = 0; eN_side < 2; eN_side++)
2460 eN = elementBoundaryElementsArray.data()[ebN * 2 + eN_side];
2461 for (
int i = 0; i < nDOF_test_element; i++)
2462 Dw_Dn_jump[u_l2g.data()[eN * nDOF_test_element + i]] = 0.0;
2464 for (
int eN_side = 0; eN_side < 2; eN_side++)
2467 eN = elementBoundaryElementsArray.data()[ebN * 2 + eN_side],
2468 ebN_local = elementBoundaryLocalElementBoundariesArray.data()[ebN * 2 + eN_side],
2469 eN_nDOF_trial_element = eN * nDOF_trial_element,
2470 ebN_local_kb = ebN_local * nQuadraturePoints_elementBoundary + kb,
2471 ebN_local_kb_nSpace = ebN_local_kb * nSpace;
2474 grad_u_int[nSpace] = {0., 0.},
2475 jac_int[nSpace * nSpace],
2477 jacInv_int[nSpace * nSpace],
2478 boundaryJac[nSpace * (nSpace - 1)],
2479 metricTensor[(nSpace - 1) * (nSpace - 1)],
2480 metricTensorDetSqrt,
2481 u_test_dS[nDOF_test_element],
2482 u_grad_trial_trace[nDOF_trial_element * nSpace],
2483 u_grad_test_dS[nDOF_trial_element * nSpace],
2484 normal[2], x_int, y_int, z_int, xt_int, yt_int, zt_int, integralScaling,
2485 G[nSpace * nSpace], G_dd_G, tr_G, h_phi, h_penalty, penalty;
2487 ck.calculateMapping_elementBoundary(eN,
2493 mesh_trial_trace_ref.data(),
2494 mesh_grad_trial_trace_ref.data(),
2495 boundaryJac_ref.data(),
2501 metricTensorDetSqrt,
2504 x_int, y_int, z_int);
2505 dS = metricTensorDetSqrt * dS_ref.data()[kb];
2509 ck.gradTrialFromRef(&u_grad_trial_trace_ref.data()[ebN_local_kb_nSpace * nDOF_trial_element], jacInv_int, u_grad_trial_trace);
2510 for (
int i = 0; i < nDOF_test_element; i++)
2512 int eN_i = eN * nDOF_test_element + i;
2513 for (
int I = 0; I < nSpace; I++)
2514 Dw_Dn_jump[u_l2g.data()[eN_i]] += u_grad_trial_trace[i * nSpace + I] * normal[I];
2517 for (
int eN_side = 0; eN_side < 2; eN_side++)
2520 eN = elementBoundaryElementsArray.data()[ebN * 2 + eN_side];
2521 for (
int i = 0; i < nDOF_test_element; i++)
2523 int eN_i = eN * nDOF_test_element + i;
2524 for (
int eN_side2 = 0; eN_side2 < 2; eN_side2++)
2526 int eN2 = elementBoundaryElementsArray.data()[ebN * 2 + eN_side2];
2527 for (
int j = 0; j < nDOF_test_element; j++)
2529 int eN_i_j = eN_i * nDOF_test_element + j;
2530 int eN2_j = eN2 * nDOF_test_element + j;
2534 i * nDOF_trial_element +
2536 std::pair<int, int> ij = std::make_pair(u_l2g.data()[eN_i], u_l2g.data()[eN2_j]);
2537 if (u_u_nz.count(ij))
2539 assert(u_u_nz[ij] == csrRowIndeces_u_u.data()[eN_i] + csrColumnOffsets_eb_u_u.data()[ebN_i_j]);
2542 u_u_nz[ij] = csrRowIndeces_u_u.data()[eN_i] + csrColumnOffsets_eb_u_u.data()[ebN_i_j];
2547 for (std::map<int, double>::iterator wi_it = Dw_Dn_jump.begin(); wi_it != Dw_Dn_jump.end(); ++wi_it)
2548 for (std::map<int, double>::iterator wj_it = Dw_Dn_jump.begin(); wj_it != Dw_Dn_jump.end(); ++wj_it)
2550 int i_global = wi_it->first,
2551 j_global = wj_it->first;
2552 double Dw_Dn_jump_i = wi_it->second,
2553 Dw_Dn_jump_j = wj_it->second;
2554 std::pair<int, int> ij = std::make_pair(i_global, j_global);
2555 globalJacobian.data()[u_u_nz.at(ij)] += gamma_cutfem * h_cutfem * Dw_Dn_jump_j * Dw_Dn_jump_i * dS;
2567 double xB_ref_faces[nDOF_mesh_trial_element * nQuadraturePoints_elementBoundary * 3];
2568 for (
int f = 0;
f < nDOF_mesh_trial_element;
f++)
2569 for (
int kb = 0; kb < nQuadraturePoints_elementBoundary; kb++)
2571 const int fkb =
f * nQuadraturePoints_elementBoundary + kb;
2572 const double *phi_m = &mesh_trial_trace_ref.data()[fkb * nDOF_mesh_trial_element];
2573 xB_ref_faces[fkb * 3 + 0] = phi_m[1];
2574 xB_ref_faces[fkb * 3 + 1] = phi_m[2];
2575 xB_ref_faces[fkb * 3 + 2] = 0.0;
2585 std::map<std::pair<int, int>,
int> u_u_nz;
2587 for (
int eN_side = 0; eN_side < 2; eN_side++)
2589 int eN = elementBoundaryElementsArray.data()[ebN0 * 2 + eN_side];
2590 for (
int i = 0; i < nDOF_test_element; i++)
2592 int eN_i = eN * nDOF_test_element + i;
2593 for (
int eN_side2 = 0; eN_side2 < 2; eN_side2++)
2595 int eN2 = elementBoundaryElementsArray.data()[ebN0 * 2 + eN_side2];
2596 for (
int j = 0; j < nDOF_test_element; j++)
2598 int eN2_j = eN2 * nDOF_test_element + j;
2602 i * nDOF_trial_element + j;
2603 std::pair<int, int> ij = std::make_pair(u_l2g.data()[eN_i], u_l2g.data()[eN2_j]);
2604 if (!u_u_nz.count(ij))
2605 u_u_nz[ij] = csrRowIndeces_u_u.data()[eN_i] + csrColumnOffsets_eb_u_u.data()[ebN_i_j];
2612 int eN_s[2], ebN_local_s[2];
2613 for (
int s = 0;
s < 2;
s++)
2615 eN_s[
s] = elementBoundaryElementsArray.data()[ebN * 2 +
s];
2616 ebN_local_s[
s] = elementBoundaryLocalElementBoundariesArray.data()[ebN * 2 +
s];
2629 double xq[2][nQuadraturePoints_elementBoundary][3];
2630 for (
int s = 0;
s < 2;
s++)
2631 for (
int kb = 0; kb < nQuadraturePoints_elementBoundary; kb++)
2633 double jac_t[nSpace * nSpace], jacDet_t, jacInv_t[nSpace * nSpace],
2634 bJac_t[nSpace * (nSpace - 1)], mT_t[(nSpace - 1) * (nSpace - 1)],
2635 mTDS_t, nrm_t[2], xt_ = 0.0, yt_ = 0.0, zt_ = 0.0;
2636 ck.calculateMapping_elementBoundary(eN_s[
s], ebN_local_s[
s], kb,
2637 ebN_local_s[
s] * nQuadraturePoints_elementBoundary + kb,
2638 mesh_dof.data(), mesh_l2g.data(),
2639 mesh_trial_trace_ref.data(), mesh_grad_trial_trace_ref.data(),
2640 boundaryJac_ref.data(), jac_t, jacDet_t, jacInv_t,
2641 bJac_t, mT_t, mTDS_t, normal_ref.data(), nrm_t,
2643 xq[
s][kb][0] = xt_; xq[
s][kb][1] = yt_; xq[
s][kb][2] = zt_;
2649 const double h_edge = elementBoundaryDiameter.data()[ebN];
2657 int kmap[2][nQuadraturePoints_elementBoundary];
2658 bool kmap_used[nQuadraturePoints_elementBoundary] = {};
2659 for (
int k = 0; k < nQuadraturePoints_elementBoundary; k++)
2663 double bestd = 1.0e300, nextd = 1.0e300;
2664 for (
int j = 0; j < nQuadraturePoints_elementBoundary; j++)
2667 for (
int I = 0; I < nSpace; I++)
2668 d += std::fabs(xq[1][j][I] - xq[0][k][I]);
2669 if (d < bestd) { nextd = bestd; bestd = d; best = j; }
2670 else if (d < nextd) { nextd = d; }
2672 if (best < 0 || kmap_used[best] || bestd >= 1.0e-8 * h_edge || nextd <= 2.0 * bestd)
2674 std::cerr <<
"ADR immersedSCIFEM: quadrature points on face " << ebN
2675 <<
" between elements " << eN_s[0] <<
" and " << eN_s[1]
2676 <<
" do not pair up (k=" << k <<
", best=" << best
2677 <<
", d=" << bestd <<
", runner-up=" << nextd
2678 <<
", h=" << h_edge <<
"); the mesh is non-conforming or the"
2679 <<
" boundary mapping is inconsistent." << std::endl;
2680 throw std::runtime_error(
"ADR immersedSCIFEM: face quadrature pairing failed");
2682 kmap_used[best] =
true;
2695 double edge_nodes[2][3], phi_edge[2];
2697 const int n0l = (ebN_local_s[0] + 1) % 3, n1l = (ebN_local_s[0] + 2) % 3;
2698 const int ln[2] = {n0l, n1l};
2699 for (
int e = 0; e < 2; e++)
2701 int eN_i = eN_s[0] * nDOF_trial_element + ln[e];
2702 phi_edge[e] = immersedBoundary_sdf_nodes.data()[u_l2g.data()[eN_i]];
2703 for (
int I = 0; I < 3; I++)
2704 edge_nodes[e][I] = mesh_dof.data()[u_l2g.data()[eN_i] * 3 + I];
2710 double edge_len2 = 0.0;
2711 for (
int I = 0; I < 3; I++)
2713 edge_vec[I] = edge_nodes[1][I] - edge_nodes[0][I];
2714 edge_len2 += edge_vec[I] * edge_vec[I];
2717 for (
int k = 0; k < nQuadraturePoints_elementBoundary; k++)
2720 std::map<int, double> va_m[2], vb_m[2], fta_m[2], ftb_m[2];
2721 for (
int eN_side = 0; eN_side < 2; eN_side++)
2723 int eN = eN_s[eN_side],
2724 ebN_local = ebN_local_s[eN_side],
2725 kb = kmap[eN_side][k],
2726 eN_nDOF_trial_element = eN * nDOF_trial_element,
2727 ebN_local_kb = ebN_local * nQuadraturePoints_elementBoundary + kb;
2728 double jac_int[nSpace * nSpace], jacDet_int, jacInv_int[nSpace * nSpace],
2729 boundaryJac[nSpace * (nSpace - 1)],
2730 metricTensor[(nSpace - 1) * (nSpace - 1)], metricTensorDetSqrt,
2731 normal[2], x_int, y_int, z_int;
2732 ck.calculateMapping_elementBoundary(eN, ebN_local, kb, ebN_local_kb,
2733 mesh_dof.data(), mesh_l2g.data(),
2734 mesh_trial_trace_ref.data(), mesh_grad_trial_trace_ref.data(),
2735 boundaryJac_ref.data(), jac_int, jacDet_int, jacInv_int,
2736 boundaryJac, metricTensor, metricTensorDetSqrt,
2737 normal_ref.data(), normal, x_int, y_int, z_int);
2739 dS = metricTensorDetSqrt * dS_ref.data()[kb];
2740 double sign_ne = (eN_side == 0) ? 1.0 : -1.0;
2742 double element_phi_f[nDOF_trial_element], element_nodes[nDOF_trial_element * 3];
2743 for (
int i = 0; i < nDOF_trial_element; i++)
2745 int eN_i = eN * nDOF_trial_element + i;
2746 element_phi_f[i] = immersedBoundary_sdf_nodes.data()[u_l2g.data()[eN_i]];
2747 for (
int I = 0; I < 3; I++)
2748 element_nodes[i * 3 + I] = mesh_dof.data()[u_l2g.data()[eN_i] * 3 + I];
2758 for (
int i = 0; i < nDOF_test_element; i++)
2760 int dof_i = u_l2g.data()[eN_nDOF_trial_element + i];
2761 va_m[eN_side][dof_i] = gf_f.
VA(i);
2762 vb_m[eN_side][dof_i] = gf_f.
VB(i);
2763 double gax = gf_f.
VA_x(i), gay = gf_f.
VA_y(i),
2764 gbx = gf_f.
VB_x(i), gby = gf_f.
VB_y(i);
2765 fta_m[eN_side][dof_i] = sign_ne * mua * (gax * normal[0] + gay * normal[1]);
2766 ftb_m[eN_side][dof_i] = sign_ne * mub * (gbx * normal[0] + gby * normal[1]);
2772 for (
int I = 0; I < 3; I++)
2773 proj += (xq[0][k][I] - edge_nodes[0][I]) * edge_vec[I];
2774 double t_edge = (edge_len2 > 1.0e-24) ? (proj / edge_len2) : 0.0;
2776 double ImH_e = 1.0 - H_e;
2778 for (
int side_i = 0; side_i < 2; side_i++)
2780 double vi_sign = (side_i == 0) ? 1.0 : -1.0;
2781 for (std::map<int, double>::iterator wi = va_m[side_i].begin(); wi != va_m[side_i].end(); ++wi)
2783 int dof_i = wi->first;
2784 double jva_i = vi_sign * va_m[side_i][dof_i], jvb_i = vi_sign * vb_m[side_i][dof_i];
2785 double fta_i = fta_m[side_i][dof_i], ftb_i = ftb_m[side_i][dof_i];
2786 for (
int side_j = 0; side_j < 2; side_j++)
2788 double vj_sign = (side_j == 0) ? 1.0 : -1.0;
2789 for (std::map<int, double>::iterator wj = va_m[side_j].begin(); wj != va_m[side_j].end(); ++wj)
2791 int dof_j = wj->first;
2792 double jva_j = vj_sign * va_m[side_j][dof_j], jvb_j = vj_sign * vb_m[side_j][dof_j];
2793 double fta_j = fta_m[side_j][dof_j], ftb_j = ftb_m[side_j][dof_j];
2794 double dPa = 0.5 * fta_j * jva_i + 0.5 * fta_i * jva_j;
2795 double dPb = 0.5 * ftb_j * jvb_i + 0.5 * ftb_i * jvb_j;
2796 std::pair<int, int> ij = std::make_pair(dof_i, dof_j);
2797 globalJacobian.data()[u_u_nz.at(ij)] -=
2798 immersedSCIFEM_switch * (ImH_e * dPa + H_e * dPb) * dS;
2801 globalJacobian.data()[u_u_nz.at(ij)] +=
2802 (immersedSCIFEM_penalty / h_edge) *
2803 (ImH_e * jva_j * jva_i + H_e * jvb_j * jvb_i) * dS;
2814 for (
int ebNE = 0; ebNE < nExteriorElementBoundaries_global; ebNE++)
2816 int ebN = exteriorElementBoundariesArray.data()[ebNE];
2817 int eN = elementBoundaryElementsArray.data()[ebN * 2 + 0],
2818 ebN_local = elementBoundaryLocalElementBoundariesArray.data()[ebN * 2 + 0],
2819 eN_nDOF_trial_element = eN * nDOF_trial_element;
2820 for (
int kb = 0; kb < nQuadraturePoints_elementBoundary; kb++)
2822 int ebNE_kb = ebNE * nQuadraturePoints_elementBoundary + kb,
2823 ebNE_kb_nSpace = ebNE_kb * nSpace,
2824 ebN_local_kb = ebN_local * nQuadraturePoints_elementBoundary + kb,
2825 ebN_local_kb_nSpace = ebN_local_kb * nSpace;
2835 dflux_u_u_ext = 0.0,
2842 fluxJacobian_u_u[nDOF_trial_element],
2843 jac_ext[nSpace * nSpace],
2845 jacInv_ext[nSpace * nSpace],
2846 boundaryJac[nSpace * (nSpace - 1)],
2847 metricTensor[(nSpace - 1) * (nSpace - 1)],
2848 metricTensorDetSqrt,
2850 u_test_dS[nDOF_test_element],
2851 u_grad_trial_trace[nDOF_trial_element * nSpace],
2852 u_grad_test_dS[nDOF_trial_element * nSpace],
2853 normal[nSpace], x_ext, y_ext, z_ext, xt_ext, yt_ext, zt_ext, integralScaling,
2855 G[nSpace * nSpace], G_dd_G, tr_G;
2856 ck.calculateMapping_elementBoundary(eN,
2862 mesh_trial_trace_ref.data(),
2863 mesh_grad_trial_trace_ref.data(),
2864 boundaryJac_ref.data(),
2870 metricTensorDetSqrt,
2873 x_ext, y_ext, z_ext);
2874 dS = metricTensorDetSqrt * dS_ref.data()[kb];
2875 ck.calculateG(jacInv_ext, G, G_dd_G, tr_G);
2879 ck.gradTrialFromRef(&u_grad_trial_trace_ref.data()[ebN_local_kb_nSpace * nDOF_trial_element], jacInv_ext, u_grad_trial_trace);
2881 ck.valFromDOF(u_dof.data(), &u_l2g.data()[eN_nDOF_trial_element], &u_trial_trace_ref.data()[ebN_local_kb * nDOF_test_element], u_ext);
2882 ck.gradFromDOF(u_dof.data(), &u_l2g.data()[eN_nDOF_trial_element], u_grad_trial_trace, grad_u_ext);
2884 for (
int j = 0; j < nDOF_trial_element; j++)
2886 u_test_dS[j] = u_test_trace_ref.data()[ebN_local_kb * nDOF_test_element + j] * dS;
2887 for (
int I = 0; I < nSpace; I++)
2888 u_grad_test_dS[j * nSpace + I] = u_grad_trial_trace[j * nSpace + I] * dS;
2893 bc_u_ext = isDOFBoundary_u.data()[ebNE_kb] * ebqe_bc_u_ext.data()[ebNE_kb] + (1 - isDOFBoundary_u.data()[ebNE_kb]) * u_ext;
2894 a_ext = &ebqe_a.data()[ebNE_kb * sd_rowptr.data()[nSpace]];
2895 for (
int I = 0; I < nSpace; I++)
2897 df_ext[I] = ebqe_v.data()[ebNE_kb * nSpace + I];
2898 bc_df_ext[I] = ebqe_v.data()[ebNE_kb * nSpace + I];
2904 isAdvectiveFluxBoundary_u.data()[ebNE_kb],
2911 for (
int j = 0; j < nDOF_trial_element; j++)
2914 int j_nSpace = j * nSpace, ebN_local_kb_j = ebN_local_kb * nDOF_trial_element + j;
2917 isDOFBoundary_u.data()[ebNE_kb],
2918 isDiffusiveFluxBoundary_u.data()[ebNE_kb],
2921 u_trial_trace_ref.data()[ebN_local_kb_j],
2922 &u_grad_trial_trace[j_nSpace],
2923 ebqe_penalty_ext.data()[ebNE_kb]) +
2924 ck.ExteriorNumericalAdvectiveFluxJacobian(dflux_u_u_ext, u_trial_trace_ref.data()[ebN_local_kb_j]);
2929 for (
int i = 0; i < nDOF_test_element; i++)
2931 int eN_i = eN * nDOF_test_element + i;
2932 int i_nSpace = i * nSpace;
2933 for (
int j = 0; j < nDOF_trial_element; j++)
2936 int ebN_local_kb_j = ebN_local_kb * nDOF_trial_element + j;
2938 globalJacobian.data()[csrRowIndeces_u_u.data()[eN_i] + csrColumnOffsets_eb_u_u.data()[ebN_i_j]] += fluxJacobian_u_u[j] * u_test_dS[i] +
2939 ck.ExteriorElementBoundaryDiffusionAdjointJacobian(isDOFBoundary_u.data()[ebNE_kb],
2940 isDiffusiveFluxBoundary_u.data()[ebNE_kb],
2942 u_trial_trace_ref.data()[ebN_local_kb_j],
2947 &u_grad_test_dS[i_nSpace]);