345static int rhs_case2(sunrealtype , N_Vector yv, N_Vector ydotv,
347 int x_hi_i_win,
int x_hi_v_win) {
348 const double* y = N_VGetArrayPointer_Serial(yv);
349 double* dydt = N_VGetArrayPointer_Serial(ydotv);
352 const bool qss = (P.he_kinetics == 1);
355 const double* c_i = y;
356 const double* c_v = y + I;
357 const double Q_tot = std::max(y[I + V], 0.0);
361 : std::max(y[I + V + 1], 0.0);
363 const double ci1 = std::max(c_i[0], 0.0);
364 const double cv1 = std::max(c_v[0], 0.0);
366 for (
int k = 0; k < P.N_eq; ++k) dydt[k] = 0.0;
369 double* dcv = dydt + I;
372 double C_vac_tot = 0.0;
373 for (
int m = 0; m < V; ++m) C_vac_tot += std::max(c_v[m], 0.0);
374 const double ell_bar = (C_vac_tot > 1e-300) ? Q_tot / C_vac_tot : 0.0;
377 auto GVV_eff = [&](
int m_idx) ->
double {
378 const int m = m_idx + 1;
379 const double ell_m = ell_bar * std::pow(
static_cast<double>(m), 2.0/3.0);
380 if (ell_m < 1e-6)
return P.GVV[m_idx];
381 const double ratio = ell_m /
static_cast<double>(m);
382 if (ratio < 1e-10)
return P.GVV[m_idx];
383 const double dE = P.delta_He * P.beta_He_exp /
static_cast<double>(m)
384 * std::pow(ratio, P.beta_He_exp - 1.0);
385 return P.GVV[m_idx] * std::exp(std::min(-ell_m * dE / P.kBT, 0.0));
393#pragma omp parallel for schedule(static, 64) if(x_hi_i_win + x_hi_v_win > 500)
395 for (
int n = 0; n <= x_hi_i_win; ++n) {
396 const int sn = n + 1;
397 const double cn = std::max(c_i[n], 0.0);
400 dci[n] += P.Pr_SIA[n];
403 if (n + 1 < I) dci[n] += P.GII[n + 1] * std::max(c_i[n + 1], 0.0);
404 dci[n] -= P.GII[n] * cn;
411 for (
int np = 1; np <= std::min(sn - 1, P.i_mobile); ++np) {
412 const int npp = sn - np;
413 if (npp < 1 || npp > I)
continue;
414 const double c_np = std::max(c_i[np - 1], 0.0);
415 const double c_npp = std::max(c_i[npp - 1], 0.0);
416 dci[n] +=
K_ii_coal(P, npp, np) * c_np * c_npp;
419 for (
int np = 1; np <= P.i_mobile; ++np) {
420 const double c_np = std::max(c_i[np - 1], 0.0);
421 dci[n] -=
K_ii_coal(P, sn, np) * cn * c_np;
424 if (sn <= P.i_mobile) {
425 for (
int np = 1; np <= I; ++np) {
426 const double c_np = std::max(c_i[np - 1], 0.0);
427 dci[n] -=
K_ii_coal(P, np, sn) * cn * c_np;
434 dci[0] -= P.K_iv * cv1 * ci1;
437 dci[0] += P.KIV[1] * cv1 * std::max(c_i[1], 0.0);
439 for (
int mp = 2; mp <= P.v_mobile; ++mp) {
440 const double c_mp = std::max(c_v[mp - 1], 0.0);
441 if (sn + mp - 1 < I) {
443 const double c_target = std::max(c_i[sn + mp - 1], 0.0);
444 dci[0] +=
K_vi_coal(P, sn + mp, mp) * c_mp * c_target;
446 dci[0] -=
K_vi_coal(P, sn, mp) * c_mp * ci1;
450 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
451 const double c_mp = std::max(c_v[mp - 1], 0.0);
460 double K_gain = (mp == 1) ? P.KIV[n + mp] :
462 dci[n] += K_gain * c_mp * std::max(c_i[n + mp], 0.0);
464 dci[n] -= K_shrink * c_mp * cn;
470 for (
int m = 1; m < V; ++m)
471 dci[0] -= P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
472 }
else if (n < 3 && n < P.i_mobile) {
473 for (
int m = 0; m < V; ++m)
474 dci[n] -= P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
475 }
else if (n >= 3 && n < P.i_mobile) {
476 for (
int m = 0; m < V; ++m)
477 dci[n] -=
K_1D_eff(P, n, m) * cn * std::max(c_v[m], 0.0);
481 if (n >= 1 && n < P.i_mobile) {
482 for (
int m = 0; m < std::min(n, V); ++m) {
483 const double cvm = std::max(c_v[m], 0.0);
484 const double K_cav = (n < 3) ? P.K_3D_cav_pref * P.m13[m]
486 dci[n - m - 1] += K_cav * cn * cvm;
491 dci[n] -= P.k2_SIA[n] * cn;
499 if (P.sia_emission_monomer) {
500 double emit_mono_sia = 0.0;
501 for (
int n = 1; n <= x_hi_i_win; ++n)
502 emit_mono_sia += P.GII[n] * std::max(c_i[n], 0.0);
503 dci[0] += emit_mono_sia;
512 if (x_hi_i_win < I - 1) {
513 const int wlim = x_hi_i_win + 1;
514 for (
int np = 1; np <= P.i_mobile; ++np) {
515 const double c_np = std::max(c_i[np - 1], 0.0);
516 if (c_np < 1e-300)
continue;
520 const int k_lo = std::max(wlim - np + 1, 1);
521 const int k_hi = std::min(wlim, I - np);
522 for (
int k = k_lo; k <= k_hi; ++k) {
523 const double ck = std::max(c_i[k - 1], 0.0);
524 const double rate =
K_ii_coal(P, k, np) * c_np * ck;
533 if (P.boundary_flux == 1) {
534 for (
int np = 1; np <= P.i_mobile; ++np) {
535 const double c_np = std::max(c_i[np - 1], 0.0);
536 for (
int k = std::max(I - np + 1, 1); k <= I; ++k) {
537 const double rate =
K_ii_coal(P, k, np) * c_np * std::max(c_i[k - 1], 0.0);
550 double emit_mono = 0.0;
551 for (
int m = 1; m <= x_hi_v_win; ++m)
552 emit_mono += GVV_eff(m) * std::max(c_v[m], 0.0);
557#pragma omp parallel for schedule(static, 64) if(x_hi_i_win + x_hi_v_win > 500)
559 for (
int m = 0; m <= x_hi_v_win; ++m) {
560 const double cm = std::max(c_v[m], 0.0);
561 const double gvv_m = GVV_eff(m);
564 dcv[m] += P.Pr_VAC[m];
567 if (m + 1 < V) dcv[m] += GVV_eff(m + 1) * std::max(c_v[m + 1], 0.0);
568 dcv[m] -= gvv_m * cm;
571 const int sm = m + 1;
573 for (
int mp = 1; mp <= std::min(sm - 1, P.v_mobile); ++mp) {
574 const int mpp = sm - mp;
575 if (mpp < 1 || mpp > V)
continue;
576 const double c_mp = std::max(c_v[mp - 1], 0.0);
577 const double c_mpp = std::max(c_v[mpp - 1], 0.0);
578 dcv[m] +=
K_vv_coal(P, mpp, mp) * c_mp * c_mpp;
581 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
582 const double c_mp = std::max(c_v[mp - 1], 0.0);
583 dcv[m] -=
K_vv_coal(P, sm, mp) * cm * c_mp;
586 if (sm <= P.v_mobile) {
587 for (
int mp = 1; mp <= V; ++mp) {
588 const double c_mp = std::max(c_v[mp - 1], 0.0);
589 dcv[m] -=
K_vv_coal(P, mp, sm) * cm * c_mp;
596 dcv[0] -= P.K_iv * ci1 * cv1;
597 if (V >= 2) dcv[0] += P.KVI[1] * ci1 * std::max(c_v[1], 0.0);
601 double sia_shrink_sink = 0.0;
602 for (
int np = 1; np < I; ++np)
603 sia_shrink_sink += P.KIV[np] * std::max(c_i[np], 0.0);
604 dcv[0] -= cv1 * sia_shrink_sink;
607 dcv[m] -= P.KVI[m] * ci1 * cm;
608 if (m + 1 < V) dcv[m] += P.KVI[m + 1] * ci1 * std::max(c_v[m + 1], 0.0);
612 for (
int n = 1; n < std::min(3, P.i_mobile); ++n) {
613 const double cn = std::max(c_i[n], 0.0);
614 dcv[m] -= P.KVI[m] * cn * cm;
616 dcv[m] += P.KVI[m + n + 1] * cn * std::max(c_v[m + n + 1], 0.0);
620 for (
int n = 3; n < std::min(I, P.i_mobile); ++n) {
621 const double cn = std::max(c_i[n], 0.0);
622 dcv[m] -=
K_1D_eff(P, n, m) * cn * cm;
624 const int mp = m + n + 1;
625 const double k_gain =
K_1D_eff(P, n, mp);
626 dcv[m] += k_gain * cn * std::max(c_v[mp], 0.0);
633 if (sm >= 2 && sm <= P.v_mobile) {
634 for (
int sn = 1; sn <= I; ++sn) {
635 const double c_sn = std::max(c_i[sn - 1], 0.0);
636 dcv[m] -=
K_vi_coal(P, sn, sm) * cm * c_sn;
639 for (
int sn = 1; sm + sn <= P.v_mobile && sn <= I; ++sn) {
640 if (sm + sn > V)
break;
642 * std::max(c_v[sm + sn - 1], 0.0)
643 * std::max(c_i[sn - 1], 0.0);
647 if (m + 1 <= P.v_mobile)
648 dcv[m] -= P.k2_disl_v * cm;
655 if (!P.Lambda_net_void.empty())
656 dcv[m] -= P.Lambda_net_void[m] * cm;
661 if (x_hi_v_win < V - 1) {
662 const int wlim_v = x_hi_v_win + 1;
663 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
664 const double c_mp = std::max(c_v[mp - 1], 0.0);
665 if (c_mp < 1e-300)
continue;
666 const int k_lo = std::max(wlim_v - mp + 1, 1);
667 const int k_hi = std::min(wlim_v, V - mp);
668 for (
int k = k_lo; k <= k_hi; ++k) {
669 const double ck = std::max(c_v[k - 1], 0.0);
670 const double rate =
K_vv_coal(P, k, mp) * c_mp * ck;
678 if (P.boundary_flux == 1) {
679 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
680 const double c_mp = std::max(c_v[mp - 1], 0.0);
681 for (
int k = std::max(V - mp + 1, 1); k <= V; ++k) {
682 const double rate =
K_vv_coal(P, k, mp) * c_mp * std::max(c_v[k - 1], 0.0);
694 if (P.loop_conversion) {
695 const double* c_i100 = y + P.sia100_off;
696 double* dci100 = dydt + P.sia100_off;
697 const int nlm = P.conv_n_loop_min;
698 const int nhi = std::min(I, x_hi_i_win + 1);
701 for (
int n = nlm; n <= nhi; ++n) {
702 const double rate = P.Gamma_uni[n - 1] * std::max(c_i[n - 1], 0.0);
704 dci100[n - 1] += rate;
709 for (
int sn = 2; sn <= nhi; ++sn) {
711 for (
int np = 1; np <= std::min(sn - 1, P.i_mobile); ++np) {
712 const int npp = sn - np;
713 if (npp < 1 || npp > I)
continue;
715 if (ph <= 0.0)
continue;
717 * std::max(c_i[np - 1], 0.0)
718 * std::max(c_i[npp - 1], 0.0);
720 dci[sn - 1] -= moved;
721 dci100[sn - 1] += moved;
725 for (
int m = nlm; m <= I; ++m) {
726 const double cm100 = std::max(c_i100[m - 1], 0.0);
727 if (cm100 < 1e-300)
continue;
728 for (
int n = 1; n <= P.i_mobile && m + n <= I; ++n) {
730 * cm100 * std::max(c_i[n - 1], 0.0);
731 dci100[m - 1] -= rate;
733 dci100[m + n - 1] += rate;
738 for (
int n = nlm; n <= I; ++n) {
739 const double cn100 = std::max(c_i100[n - 1], 0.0);
740 if (cn100 < 1e-300)
continue;
743 const double g = P.K_100_grow[n - 1] * cn100 * ci1;
750 const double s = P.K_100_shrink[n - 1] * cn100 * cv1;
752 if (n - 1 >= nlm) dci100[n - 2] += s;
753 else if (n >= 2) dci[n - 2] += s;
758 const double e = P.G_100[n - 1] * cn100;
760 if (n - 1 >= nlm) dci100[n - 2] += e;
761 else if (n >= 2) dci[n - 2] += e;
767 dci100[n - 1] -= P.Lambda_net_100[n - 1] * cn100;
823 constexpr double LOOP_COAL_ABS = 2.0;
824 constexpr double LOOP_COAL_REL = 1e-6;
826 for (
int sn = P.i_mobile + 1; sn <= I; ++sn)
827 cmax = std::max(cmax, std::max(c_i[sn - 1], 0.0));
828 const double c_min = std::max(LOOP_COAL_ABS * P.C_floor,
829 LOOP_COAL_REL * cmax);
830 std::vector<int> idx;
832 for (
int sn = P.i_mobile + 1; sn <= I; ++sn)
833 if (std::max(c_i[sn - 1], 0.0) > c_min) idx.push_back(sn);
834 const int NC =
static_cast<int>(idx.size());
835 for (
int a = 0; a < NC; ++a) {
836 const int na = idx[a];
837 const double ca = std::max(c_i[na - 1], 0.0);
838 const double Da = P.D_loop_coal[na - 1];
839 const double Zt = (!P.Z_i_loop_arr.empty()) ? P.Z_i_loop_arr[na - 1]
841 for (
int b = a; b < NC; ++b) {
842 const int nb = idx[b];
843 const double cb = std::max(c_i[nb - 1], 0.0);
844 const double Db = P.D_loop_coal[nb - 1];
847 const double Dsum = Da + Db;
848 if (Dsum < 1e-300)
continue;
849 const double sf = std::sqrt(
static_cast<double>(na))
850 + std::sqrt(
static_cast<double>(nb));
851 const double K = P.Z_ii * Zt * P.A_loop_inv_O23 * sf * Dsum;
853 const double r = (a == b) ? 0.5 * K * ca * ca : K * ca * cb;
854 if (r < 1e-300)
continue;
855 if (a == b) dci[na - 1] -= 2.0 * r;
856 else { dci[na - 1] -= r; dci[nb - 1] -= r; }
864 const int prod = std::min(na + nb, I);
871 double He_uptake = 0.0;
872 for (
int m = 0; m < V; ++m)
873 He_uptake += P.KHeV[m] * c_h * std::max(c_v[m], 0.0);
874 const double He_emit = P.beta_He * Q_tot;
878 double He_sink = 0.0;
879 for (
int m = 0; m < std::min(V, P.v_mobile); ++m) {
880 const double ell_m = ell_bar * std::pow(
static_cast<double>(m + 1), 2.0/3.0);
881 He_sink += P.k2_disl_v * ell_m * std::max(c_v[m], 0.0);
883 dydt[I + V] = He_uptake - He_emit - He_sink;
887 dydt[I + V + 1] = P.G_He - He_uptake - P.k2_disl_He * c_h + He_emit;
892 double sia_fixed = 0.0;
893 for (
int n = 0; n < I; ++n)
894 sia_fixed +=
static_cast<double>(n + 1) * P.k2_SIA[n] * std::max(c_i[n], 0.0);
895 dydt[P.cons_off + 0] = sia_fixed;
904 for (
int n = 0; n < I; ++n) {
905 const int sn = n + 1;
906 const double cn = std::max(c_i[n], 0.0);
907 if (cn < 1e-300)
continue;
910 for (
int m = 1; m < V; ++m)
911 mutual += P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
912 }
else if (n < 3 && n < P.i_mobile) {
913 for (
int m = 0; m < V; ++m)
914 mutual += std::min(sn, m + 1) * P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
915 }
else if (n >= 3 && n < P.i_mobile) {
916 for (
int m = 0; m < V; ++m)
917 mutual += std::min(sn, m + 1) *
K_1D_eff(P, n, m) * cn * std::max(c_v[m], 0.0);
920 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
921 const double c_mp = std::max(c_v[mp - 1], 0.0);
922 if (c_mp < 1e-300)
continue;
924 if (mp == 1 && n > 0) K_s = P.KIV[n];
925 else if (mp == 1 && n == 0) K_s = P.K_iv;
927 mutual += std::min(mp, sn) * K_s * c_mp * cn;
930 dydt[P.cons_off + 1] = mutual;
935 double vac_fixed = 0.0;
936 for (
int m = 0; m < std::min(P.v_mobile, P.V); ++m)
937 vac_fixed +=
static_cast<double>(m + 1) * P.k2_disl_v * std::max(c_v[m], 0.0);
941 if (!P.Lambda_net_void.empty())
942 for (
int m = 0; m < P.V; ++m)
943 vac_fixed +=
static_cast<double>(m + 1) * P.Lambda_net_void[m]
944 * std::max(c_v[m], 0.0);
945 dydt[P.cons_off + 2] = vac_fixed;
953 dydt[P.cons_off + 3] = dydt[P.cons_off + 1];
958 if (P.loop_conversion) {
959 const double* c_i100 = y + P.sia100_off;
960 double s100_mut = 0.0, s100_fixed = 0.0;
961 for (
int n = P.conv_n_loop_min; n <= I; ++n) {
962 s100_mut += P.K_100_shrink[n - 1] * std::max(c_i100[n - 1], 0.0) * cv1;
965 s100_fixed +=
static_cast<double>(n) * P.Lambda_net_100[n - 1]
966 * std::max(c_i100[n - 1], 0.0);
968 dydt[P.cons_off + 1] += s100_mut;
969 dydt[P.cons_off + 3] += s100_mut;
970 dydt[P.cons_off + 0] += s100_fixed;
975 double he_sink = P.k2_disl_He * c_h;
976 if (C_vac_tot > 1e-300 && Q_tot > 0.0) {
977 double ell_bar_loc = Q_tot / C_vac_tot;
978 for (
int m = 0; m < std::min(P.v_mobile, P.V); ++m) {
979 double ell_m = ell_bar_loc * std::pow(
static_cast<double>(m + 1), 2.0/3.0);
980 he_sink += P.k2_disl_v * ell_m * std::max(c_v[m], 0.0);
983 dydt[P.cons_off + 4] = he_sink;
994static int rhs_case1(sunrealtype , N_Vector yv, N_Vector ydotv,
996 int x_hi_i_win,
int x_hi_v_win) {
997 const double* y = N_VGetArrayPointer_Serial(yv);
998 double* dydt = N_VGetArrayPointer_Serial(ydotv);
1001 const bool qss = (P.he_kinetics == 1);
1003 const double* c_i = y;
1004 const double* c_v = y + I;
1005 const double* Q_m = y + I + V;
1008 : std::max(y[I + 2*V], 0.0);
1010 const double ci1 = std::max(c_i[0], 0.0);
1011 const double cv1 = std::max(c_v[0], 0.0);
1013 for (
int k = 0; k < P.N_eq; ++k) dydt[k] = 0.0;
1016 double* dcv = dydt + I;
1017 double* dQ = dydt + I + V;
1020 auto ell_bar_m = [&](
int m_idx) ->
double {
1021 const double cm = std::max(c_v[m_idx], 1e-300);
1022 return std::max(Q_m[m_idx], 0.0) / cm;
1025 auto GVV_eff_m = [&](
int m_idx) ->
double {
1026 const int m = m_idx + 1;
1027 const double ell = ell_bar_m(m_idx);
1028 if (ell < 1e-6)
return P.GVV[m_idx];
1029 const double ratio = ell /
static_cast<double>(m);
1030 if (ratio < 1e-10)
return P.GVV[m_idx];
1031 const double dE = P.delta_He * P.beta_He_exp /
static_cast<double>(m)
1032 * std::pow(ratio, P.beta_He_exp - 1.0);
1033 return P.GVV[m_idx] * std::exp(std::min(-ell * dE / P.kBT, 0.0));
1038#ifdef CD_HAVE_OPENMP
1039#pragma omp parallel for schedule(static, 64) if(x_hi_i_win + x_hi_v_win > 500)
1041 for (
int n = 0; n <= x_hi_i_win; ++n) {
1042 const int sn = n + 1;
1043 const double cn = std::max(c_i[n], 0.0);
1044 dci[n] += P.Pr_SIA[n];
1045 if (n + 1 < I) dci[n] += P.GII[n+1] * std::max(c_i[n+1], 0.0);
1046 dci[n] -= P.GII[n] * cn;
1049 for (
int np = 1; np <= std::min(sn - 1, P.i_mobile); ++np) {
1050 const int npp = sn - np;
1051 if (npp < 1 || npp > I)
continue;
1052 const double c_np = std::max(c_i[np - 1], 0.0);
1053 const double c_npp = std::max(c_i[npp - 1], 0.0);
1054 dci[n] +=
K_ii_coal(P, npp, np) * c_np * c_npp;
1057 for (
int np = 1; np <= P.i_mobile; ++np) {
1058 dci[n] -=
K_ii_coal(P, sn, np) * cn * std::max(c_i[np - 1], 0.0);
1061 if (sn <= P.i_mobile) {
1062 for (
int np = 1; np <= I; ++np) {
1063 dci[n] -=
K_ii_coal(P, np, sn) * cn * std::max(c_i[np - 1], 0.0);
1070 dci[0] -= P.K_iv * cv1 * ci1;
1073 dci[0] += P.KIV[1] * cv1 * std::max(c_i[1], 0.0);
1075 for (
int mp = 2; mp <= P.v_mobile; ++mp) {
1076 const double c_mp = std::max(c_v[mp - 1], 0.0);
1077 if (sn + mp - 1 < I) {
1079 dci[0] +=
K_vi_coal(P, sn + mp, mp) * c_mp * std::max(c_i[sn + mp - 1], 0.0);
1081 dci[0] -=
K_vi_coal(P, sn, mp) * c_mp * ci1;
1084 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
1085 const double c_mp = std::max(c_v[mp - 1], 0.0);
1086 double K_s = (mp == 1) ? P.KIV[n] :
K_vi_coal(P, sn, mp);
1088 double K_g = (mp == 1) ? P.KIV[n + mp] :
K_vi_coal(P, sn + mp, mp);
1089 dci[n] += K_g * c_mp * std::max(c_i[n + mp], 0.0);
1091 dci[n] -= K_s * c_mp * cn;
1097 for (
int m = 1; m < V; ++m)
1098 dci[0] -= P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
1099 }
else if (n < 3 && n < P.i_mobile) {
1100 for (
int m = 0; m < V; ++m)
1101 dci[n] -= P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
1102 }
else if (n >= 3 && n < P.i_mobile) {
1103 for (
int m = 0; m < V; ++m)
1104 dci[n] -=
K_1D_eff(P, n, m) * cn * std::max(c_v[m], 0.0);
1107 if (n >= 1 && n < P.i_mobile) {
1108 for (
int m = 0; m < std::min(n, V); ++m) {
1109 const double cvm = std::max(c_v[m], 0.0);
1110 const double K_cav = (n < 3) ? P.K_3D_cav_pref * P.m13[m]
1112 dci[n - m - 1] += K_cav * cn * cvm;
1116 dci[n] -= P.k2_SIA[n] * cn;
1124 if (P.sia_emission_monomer) {
1125 double emit_mono_sia = 0.0;
1126 for (
int n = 1; n <= x_hi_i_win; ++n)
1127 emit_mono_sia += P.GII[n] * std::max(c_i[n], 0.0);
1128 dci[0] += emit_mono_sia;
1132 if (x_hi_i_win < I - 1) {
1133 const int wlim = x_hi_i_win + 1;
1134 for (
int np = 1; np <= P.i_mobile; ++np) {
1135 const double c_np = std::max(c_i[np - 1], 0.0);
1136 if (c_np < 1e-300)
continue;
1137 const int k_lo = std::max(wlim - np + 1, 1);
1138 const int k_hi = std::min(wlim, I - np);
1139 for (
int k = k_lo; k <= k_hi; ++k) {
1140 const double ck = std::max(c_i[k - 1], 0.0);
1141 const double rate =
K_ii_coal(P, k, np) * c_np * ck;
1143 dci[np - 1] += rate;
1149 if (P.boundary_flux == 1) {
1150 for (
int np = 1; np <= P.i_mobile; ++np) {
1151 const double c_np = std::max(c_i[np - 1], 0.0);
1152 for (
int k = std::max(I - np + 1, 1); k <= I; ++k) {
1153 const double rate =
K_ii_coal(P, k, np) * c_np * std::max(c_i[k - 1], 0.0);
1155 dci[np - 1] += rate;
1163 double emit_mono = 0.0;
1164 for (
int m = 1; m <= x_hi_v_win; ++m)
1165 emit_mono += GVV_eff_m(m) * std::max(c_v[m], 0.0);
1166 dcv[0] += emit_mono;
1169#ifdef CD_HAVE_OPENMP
1170#pragma omp parallel for schedule(static, 64) if(x_hi_i_win + x_hi_v_win > 500)
1172 for (
int m = 0; m <= x_hi_v_win; ++m) {
1173 const int sm = m + 1;
1174 const double cm = std::max(c_v[m], 0.0);
1175 const double gvv = GVV_eff_m(m);
1176 dcv[m] += P.Pr_VAC[m];
1177 if (m + 1 < V) dcv[m] += GVV_eff_m(m+1) * std::max(c_v[m+1], 0.0);
1181 for (
int mp = 1; mp <= std::min(sm - 1, P.v_mobile); ++mp) {
1182 const int mpp = sm - mp;
1183 if (mpp < 1 || mpp > V)
continue;
1184 const double c_mp = std::max(c_v[mp - 1], 0.0);
1185 const double c_mpp = std::max(c_v[mpp - 1], 0.0);
1186 dcv[m] +=
K_vv_coal(P, mpp, mp) * c_mp * c_mpp;
1189 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
1190 dcv[m] -=
K_vv_coal(P, sm, mp) * cm * std::max(c_v[mp - 1], 0.0);
1193 if (sm <= P.v_mobile) {
1194 for (
int mp = 1; mp <= V; ++mp) {
1195 dcv[m] -=
K_vv_coal(P, mp, sm) * cm * std::max(c_v[mp - 1], 0.0);
1201 dcv[0] -= P.K_iv * ci1 * cv1;
1202 if (V >= 2) dcv[0] += P.KVI[1] * ci1 * std::max(c_v[1], 0.0);
1206 double sia_shrink_sink = 0.0;
1207 for (
int np = 1; np < I; ++np)
1208 sia_shrink_sink += P.KIV[np] * std::max(c_i[np], 0.0);
1209 dcv[0] -= cv1 * sia_shrink_sink;
1212 dcv[m] -= P.KVI[m] * ci1 * cm;
1213 if (m + 1 < V) dcv[m] += P.KVI[m+1] * ci1 * std::max(c_v[m+1], 0.0);
1215 for (
int n = 1; n < std::min(3, P.i_mobile); ++n) {
1216 const double cn = std::max(c_i[n], 0.0);
1217 dcv[m] -= P.KVI[m] * cn * cm;
1219 dcv[m] += P.KVI[m + n + 1] * cn * std::max(c_v[m + n + 1], 0.0);
1221 for (
int n = 3; n < std::min(I, P.i_mobile); ++n) {
1222 const double cn = std::max(c_i[n], 0.0);
1223 dcv[m] -=
K_1D_eff(P, n, m) * cn * cm;
1224 if (m + n + 1 < V) {
1225 const int mp = m + n + 1;
1226 dcv[m] +=
K_1D_eff(P, n, mp) * cn * std::max(c_v[mp], 0.0);
1231 if (sm >= 2 && sm <= P.v_mobile) {
1232 for (
int sn = 1; sn <= I; ++sn) {
1233 const double c_sn = std::max(c_i[sn - 1], 0.0);
1234 dcv[m] -=
K_vi_coal(P, sn, sm) * cm * c_sn;
1237 for (
int sn = 1; sm + sn <= P.v_mobile && sn <= I; ++sn) {
1238 if (sm + sn > V)
break;
1240 * std::max(c_v[sm + sn - 1], 0.0)
1241 * std::max(c_i[sn - 1], 0.0);
1245 if (m + 1 <= P.v_mobile)
1246 dcv[m] -= P.k2_disl_v * cm;
1253 if (!P.Lambda_net_void.empty())
1254 dcv[m] -= P.Lambda_net_void[m] * cm;
1258 if (x_hi_v_win < V - 1) {
1259 const int wlim_v = x_hi_v_win + 1;
1260 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
1261 const double c_mp = std::max(c_v[mp - 1], 0.0);
1262 if (c_mp < 1e-300)
continue;
1263 const int k_lo = std::max(wlim_v - mp + 1, 1);
1264 const int k_hi = std::min(wlim_v, V - mp);
1265 for (
int k = k_lo; k <= k_hi; ++k) {
1266 const double ck = std::max(c_v[k - 1], 0.0);
1267 const double rate =
K_vv_coal(P, k, mp) * c_mp * ck;
1269 dcv[mp - 1] += rate;
1275 if (P.boundary_flux == 1) {
1276 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
1277 const double c_mp = std::max(c_v[mp - 1], 0.0);
1278 for (
int k = std::max(V - mp + 1, 1); k <= V; ++k) {
1279 const double rate =
K_vv_coal(P, k, mp) * c_mp * std::max(c_v[k - 1], 0.0);
1281 dcv[mp - 1] += rate;
1341 constexpr double LOOP_COAL_ABS = 2.0;
1342 constexpr double LOOP_COAL_REL = 1e-6;
1344 for (
int sn = P.i_mobile + 1; sn <= I; ++sn)
1345 cmax = std::max(cmax, std::max(c_i[sn - 1], 0.0));
1346 const double c_min = std::max(LOOP_COAL_ABS * P.C_floor,
1347 LOOP_COAL_REL * cmax);
1348 std::vector<int> idx;
1350 for (
int sn = P.i_mobile + 1; sn <= I; ++sn)
1351 if (std::max(c_i[sn - 1], 0.0) > c_min) idx.push_back(sn);
1352 const int NC =
static_cast<int>(idx.size());
1353 for (
int a = 0; a < NC; ++a) {
1354 const int na = idx[a];
1355 const double ca = std::max(c_i[na - 1], 0.0);
1356 const double Da = P.D_loop_coal[na - 1];
1357 const double Zt = (!P.Z_i_loop_arr.empty()) ? P.Z_i_loop_arr[na - 1]
1359 for (
int b = a; b < NC; ++b) {
1360 const int nb = idx[b];
1361 const double cb = std::max(c_i[nb - 1], 0.0);
1362 const double Db = P.D_loop_coal[nb - 1];
1365 const double Dsum = Da + Db;
1366 if (Dsum < 1e-300)
continue;
1367 const double sf = std::sqrt(
static_cast<double>(na))
1368 + std::sqrt(
static_cast<double>(nb));
1369 const double K = P.Z_ii * Zt * P.A_loop_inv_O23 * sf * Dsum;
1371 const double r = (a == b) ? 0.5 * K * ca * ca : K * ca * cb;
1372 if (r < 1e-300)
continue;
1373 if (a == b) dci[na - 1] -= 2.0 * r;
1374 else { dci[na - 1] -= r; dci[nb - 1] -= r; }
1382 const int prod = std::min(na + nb, I);
1390 double He_cap_total = 0.0;
1391 double He_emit_total = 0.0;
1392 for (
int m = 0; m <= x_hi_v_win; ++m) {
1393 const double cm = std::max(c_v[m], 0.0);
1394 const double qm = std::max(Q_m[m], 0.0);
1395 const double he_cap_m = P.KHeV[m] * c_h * cm;
1396 const double he_emit_m = P.beta_He * qm;
1400 if (m + 1 <= P.v_mobile)
1401 dQ[m] -= P.k2_disl_v * qm;
1402 He_cap_total += he_cap_m;
1403 He_emit_total += he_emit_m;
1408 dydt[I + 2*V] = P.G_He - He_cap_total - P.k2_disl_He * c_h + He_emit_total;
1413 double sia_fixed = 0.0;
1414 for (
int n = 0; n < I; ++n)
1415 sia_fixed +=
static_cast<double>(n + 1) * P.k2_SIA[n] * std::max(c_i[n], 0.0);
1416 dydt[P.cons_off + 0] = sia_fixed;
1424 double mutual = 0.0;
1425 for (
int n = 0; n < I; ++n) {
1426 const int sn = n + 1;
1427 const double cn = std::max(c_i[n], 0.0);
1428 if (cn < 1e-300)
continue;
1431 for (
int m = 1; m < V; ++m)
1432 mutual += P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
1433 }
else if (n < 3 && n < P.i_mobile) {
1434 for (
int m = 0; m < V; ++m)
1435 mutual += std::min(sn, m + 1) * P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
1436 }
else if (n >= 3 && n < P.i_mobile) {
1437 for (
int m = 0; m < V; ++m)
1438 mutual += std::min(sn, m + 1) *
K_1D_eff(P, n, m) * cn * std::max(c_v[m], 0.0);
1441 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
1442 const double c_mp = std::max(c_v[mp - 1], 0.0);
1443 if (c_mp < 1e-300)
continue;
1445 if (mp == 1 && n > 0) K_s = P.KIV[n];
1446 else if (mp == 1 && n == 0) K_s = P.K_iv;
1448 mutual += std::min(mp, sn) * K_s * c_mp * cn;
1451 dydt[P.cons_off + 1] = mutual;
1456 double vac_fixed = 0.0;
1457 for (
int m = 0; m < std::min(P.v_mobile, P.V); ++m)
1458 vac_fixed +=
static_cast<double>(m + 1) * P.k2_disl_v * std::max(c_v[m], 0.0);
1462 if (!P.Lambda_net_void.empty())
1463 for (
int m = 0; m < P.V; ++m)
1464 vac_fixed +=
static_cast<double>(m + 1) * P.Lambda_net_void[m]
1465 * std::max(c_v[m], 0.0);
1466 dydt[P.cons_off + 2] = vac_fixed;
1471 dydt[P.cons_off + 3] = dydt[P.cons_off + 1];
1480 double he_sink = P.k2_disl_He * c_h;
1481 for (
int m = 0; m < std::min(P.v_mobile, P.V); ++m)
1482 he_sink += P.k2_disl_v * std::max(Q_m[m], 0.0);
1483 dydt[P.cons_off + 4] = he_sink;
1523 const double* y = N_VGetArrayPointer_Serial(yv);
1524 double* dydt = N_VGetArrayPointer_Serial(ydotv);
1526 const int Ib = P.I_bin;
1529 const bool qss = (P.he_kinetics == 1);
1531 for (
int k = 0; k < P.N_eq; ++k) dydt[k] = 0.0;
1534 const int PM = P.n_mom;
1537 const int i_d = P.i_discrete;
1538 const int v_d = P.v_discrete;
1539 const int i_VAC = i_d + PM * Ib;
1546 const int*
const n_lo = P.sia_bin_lo.data();
1547 const int*
const n_hi = P.sia_bin_hi.data();
1552 auto softplus = [](
double x) ->
double {
1553 constexpr double eps = 1e-30;
1554 if (x > 20.0 * eps)
return x;
1555 if (x < -20.0 * eps)
return eps * std::exp(x / eps);
1556 return eps * std::log1p(std::exp(x / eps));
1564 Pm.
bm_c_n.assign(I, 0.0);
1565 double*
const c_n = Pm.
bm_c_n.data();
1567 for (
int n = 0; n < i_d; ++n)
1568 c_n[n] = std::max(y[n], 0.0);
1570 for (
int k = 0; k < Ib; ++k) {
1571 const double mu0_k = std::max(y[i_d + PM*k], 0.0);
1572 double mu1_k = (PM >= 2) ? y[i_d + PM*k + 1] : 0.0;
1573 double mu2_k = (PM >= 3) ? y[i_d + PM*k + 2] : 0.0;
1574 const double bw =
static_cast<double>(n_hi[k] - n_lo[k]);
1575 if (bw <= 0 || mu0_k <= 0.0)
continue;
1577 int ni = n_lo[k] - 1;
1578 if (ni >= 0 && ni < I) c_n[ni] = mu0_k;
1590 const double n_lo_f =
static_cast<double>(n_lo[k]);
1591 const double n_hi_f =
static_cast<double>(n_hi[k] - 1);
1592 const double n_mid = 0.5 * (n_lo_f + n_hi_f);
1593 double n_bar = mu1_k / std::max(mu0_k, 1e-300);
1594 if (n_bar < n_lo_f) mu1_k = mu0_k * n_lo_f;
1595 else if (n_bar > n_hi_f) mu1_k = mu0_k * n_hi_f;
1598 double n2_min = mu1_k * mu1_k / std::max(mu0_k, 1e-300) * 1.01;
1599 if (mu2_k < n2_min) mu2_k = n2_min;
1604 bool use_lognormal =
false;
1605 if (P.shape_function == 2 && PM >= 3) {
1606 const double n_bar = mu1_k / std::max(mu0_k, 1e-300);
1607 const double n2_bar = mu2_k / std::max(mu0_k, 1e-300);
1608 const double ratio = n2_bar / std::max(n_bar * n_bar, 1e-300);
1610 use_lognormal =
true;
1611 const double sig2 = std::log(ratio);
1612 const double m_k = std::log(std::max(n_bar, 1e-300)) - 0.5 * sig2;
1614 double max_log_f = -1e300;
1615 std::vector<double> log_f_arr(
static_cast<int>(bw));
1616 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
1617 double nf =
static_cast<double>(n);
1618 double ln_n = std::log(nf);
1619 double lf = std::max(-(ln_n - m_k) * (ln_n - m_k) / (2.0 * sig2), -500.0) - ln_n;
1620 log_f_arr[n - n_lo[k]] = lf;
1621 if (lf > max_log_f) max_log_f = lf;
1623 for (
int j = 0; j < static_cast<int>(bw); ++j) {
1624 log_f_arr[j] -= max_log_f;
1625 f_sum += std::exp(log_f_arr[j]);
1627 if (f_sum < 1e-300) {
1628 use_lognormal =
false;
1630 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
1631 if (n - 1 >= 0 && n - 1 < I)
1632 c_n[n - 1] = std::max(
1633 mu0_k * std::exp(log_f_arr[n - n_lo[k]]) / f_sum, 0.0);
1639 if (!use_lognormal) {
1640 if (P.shape_function == 0) {
1642 const double val = mu0_k / bw;
1643 for (
int n = n_lo[k]; n < n_hi[k]; ++n)
1644 if (n - 1 >= 0 && n - 1 < I) c_n[n - 1] = val;
1651 if (!P.bin_S1.empty()) {
1652 S1 = P.bin_S1[k]; S2 = P.bin_S2[k];
1655 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
1656 double nf =
static_cast<double>(n);
1657 S1 += nf; S2 += nf * nf;
1660 double det = bw * S2 - S1 * S1;
1661 if (std::abs(det) < 1e-30) {
1662 double val = mu0_k / bw;
1663 for (
int n = n_lo[k]; n < n_hi[k]; ++n)
1664 if (n - 1 >= 0 && n - 1 < I) c_n[n - 1] = val;
1669#ifdef CD_HAVE_OPENMP
1670#pragma omp parallel for schedule(static, 256) if(n_hi[k] - n_lo[k] > 2048)
1672 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
1673 if (n - 1 < 0 || n - 1 >= I)
continue;
1674 double nf =
static_cast<double>(n);
1675 double phi0 = (S2 - S1 * nf) / det;
1676 double phi1 = (bw * nf - S1) / det;
1677 c_n[n - 1] = softplus(phi0 * mu0_k + phi1 * mu1_k);
1685 const int Kv = P.V_bin;
1689 const int*
const m_lo = P.vac_bin_lo.data();
1690 const int*
const m_hi = P.vac_bin_hi.data();
1693 Pm.
bm_c_v.assign(V, 0.0);
1694 double*
const c_v_vec = Pm.
bm_c_v.data();
1696 for (
int m = 0; m < v_d; ++m)
1697 c_v_vec[m] = std::max(y[i_VAC + m], 0.0);
1700 const int vac_mom_start = i_VAC + v_d;
1701 for (
int k = 0; k < Kv; ++k) {
1702 const double mu0_k = std::max(y[vac_mom_start + PM*k], 0.0);
1703 double mu1_k = (PM >= 2) ? y[vac_mom_start + PM*k + 1] : 0.0;
1704 double mu2_k = (PM >= 3) ? y[vac_mom_start + PM*k + 2] : 0.0;
1705 const double bw =
static_cast<double>(m_hi[k] - m_lo[k]);
1706 if (bw <= 0 || mu0_k <= 0.0)
continue;
1708 int mi = m_lo[k] - 1;
1709 if (mi >= 0 && mi < V) c_v_vec[mi] = mu0_k;
1715 const double m_lo_f =
static_cast<double>(m_lo[k]);
1716 const double m_hi_f =
static_cast<double>(m_hi[k] - 1);
1717 double n_bar = mu1_k / std::max(mu0_k, 1e-300);
1718 if (n_bar < m_lo_f) mu1_k = mu0_k * m_lo_f;
1719 else if (n_bar > m_hi_f) mu1_k = mu0_k * m_hi_f;
1721 double n2_min = mu1_k * mu1_k / std::max(mu0_k, 1e-300) * 1.01;
1722 if (mu2_k < n2_min) mu2_k = n2_min;
1727 bool use_lognormal_v =
false;
1728 if (P.shape_function == 2 && PM >= 3) {
1729 const double n_bar = mu1_k / std::max(mu0_k, 1e-300);
1730 const double n2_bar = mu2_k / std::max(mu0_k, 1e-300);
1731 const double ratio = n2_bar / std::max(n_bar * n_bar, 1e-300);
1733 use_lognormal_v =
true;
1734 const double sig2 = std::log(ratio);
1735 const double m_k = std::log(std::max(n_bar, 1e-300)) - 0.5 * sig2;
1737 double max_log_f = -1e300;
1738 std::vector<double> log_f_arr(
static_cast<int>(bw));
1739 for (
int m = m_lo[k]; m < m_hi[k]; ++m) {
1740 double mf =
static_cast<double>(m);
1741 double ln_m = std::log(mf);
1742 double lf = std::max(-(ln_m - m_k) * (ln_m - m_k) / (2.0 * sig2), -500.0) - ln_m;
1743 log_f_arr[m - m_lo[k]] = lf;
1744 if (lf > max_log_f) max_log_f = lf;
1746 for (
int j = 0; j < static_cast<int>(bw); ++j) {
1747 log_f_arr[j] -= max_log_f;
1748 f_sum += std::exp(log_f_arr[j]);
1750 if (f_sum < 1e-300) {
1751 use_lognormal_v =
false;
1753 for (
int m = m_lo[k]; m < m_hi[k]; ++m) {
1754 if (m - 1 >= 0 && m - 1 < V)
1755 c_v_vec[m - 1] = std::max(
1756 mu0_k * std::exp(log_f_arr[m - m_lo[k]]) / f_sum, 0.0);
1762 if (!use_lognormal_v) {
1763 if (P.shape_function == 0) {
1765 double val = mu0_k / bw;
1766 for (
int m = m_lo[k]; m < m_hi[k]; ++m)
1767 if (m - 1 >= 0 && m - 1 < V) c_v_vec[m - 1] = std::max(val, 0.0);
1772 if (!P.vbin_S1.empty()) {
1773 S1 = P.vbin_S1[k]; S2 = P.vbin_S2[k];
1776 for (
int m = m_lo[k]; m < m_hi[k]; ++m) {
1777 double mf =
static_cast<double>(m);
1778 S1 += mf; S2 += mf * mf;
1781 double det = bw * S2 - S1 * S1;
1782 if (std::abs(det) < 1e-30) {
1783 double val = mu0_k / bw;
1784 for (
int m = m_lo[k]; m < m_hi[k]; ++m)
1785 if (m - 1 >= 0 && m - 1 < V) c_v_vec[m - 1] = std::max(val, 0.0);
1788#ifdef CD_HAVE_OPENMP
1789#pragma omp parallel for schedule(static, 256) if(m_hi[k] - m_lo[k] > 2048)
1791 for (
int m = m_lo[k]; m < m_hi[k]; ++m) {
1792 if (m - 1 < 0 || m - 1 >= V)
continue;
1793 double mf =
static_cast<double>(m);
1794 double phi0 = (S2 - S1 * mf) / det;
1795 double phi1 = (bw * mf - S1) / det;
1796 c_v_vec[m - 1] = softplus(phi0 * mu0_k + phi1 * mu1_k);
1803 const double*
const c_v = c_v_vec;
1808 const int i_Q_base = i_VAC + v_d + PM * Kv;
1811 const int n_Q_case1 = (Kv > 0) ? Kv : V;
1812 if (P.he_mode == 1) {
1813 for (
int k = 0; k < n_Q_case1; ++k) Q_tot += std::max(y[i_Q_base + k], 0.0);
1814 i_He_idx = qss ? -1 : i_Q_base + n_Q_case1;
1816 Q_tot = std::max(y[i_Q_base], 0.0);
1817 i_He_idx = qss ? -1 : i_Q_base + 1;
1829 c_h = std::max(y[i_He_idx], 0.0);
1830 }
else if (P.he_mode == 1 && Kv > 0) {
1831 double cap_sink = 0.0;
1832 for (
int k = 0; k < Kv; ++k)
1833 for (
int m = m_lo[k]; m < m_hi[k]; ++m) {
1834 const int mi = m - 1;
1835 if (mi >= 0 && mi < V)
1836 cap_sink += P.KHeV[mi] * std::max(c_v[mi], 0.0);
1838 const double sink = P.k2_disl_He + cap_sink;
1839 const double source = P.G_He + P.beta_He * Q_tot;
1840 c_h = source / (sink > 1e-300 ? sink : 1e-300);
1841 }
else if (P.he_mode == 1) {
1847 const double ci1 = (I <= 0) ? 0.0 : std::max(c_n[0], 0.0);
1848 const double cv1 = std::max(c_v[0], 0.0);
1857 double*
const dc_n = Pm.
bm_dc_n.data();
1877 const int n_head = std::min(std::max(std::max(i_d, P.i_mobile), 1), I);
1879 for (
int n = 0; n < n_head; ++n) {
1880 const int sn = n + 1;
1881 const double cn = std::max(c_n[n], 0.0);
1882 dc_n[n] += P.Pr_SIA[n];
1883 if (n + 1 < I) dc_n[n] += P.GII[n+1] * std::max(c_n[n+1], 0.0);
1884 dc_n[n] -= P.GII[n] * cn;
1890 for (
int np = 2; np <= std::min(sn - 1, i_d); ++np) {
1891 const int npp = sn - np;
1892 if (npp < 1 || npp > i_d)
continue;
1893 const double c_np = std::max(c_n[np - 1], 0.0);
1894 const double c_npp = std::max(c_n[npp - 1], 0.0);
1895 dc_n[n] +=
K_ii_coal(P, npp, np) * c_np * c_npp;
1898 for (
int np = 2; np <= std::min(i_d, P.i_mobile); ++np) {
1899 dc_n[n] -=
K_ii_coal(P, sn, np) * cn * std::max(c_n[np - 1], 0.0);
1904 if (sn >= 2 && sn <= P.i_mobile) {
1905 for (
int np = 1; np <= i_d; ++np) {
1906 dc_n[n] -=
K_ii_coal(P, np, sn) * cn * std::max(c_n[np - 1], 0.0);
1914 dc_n[n] +=
K_ii_coal(P, n, 1) * ci1 * std::max(c_n[n - 1], 0.0);
1916 dc_n[n] -=
K_ii_coal(P, sn, 1) * cn * ci1;
1919 double mono_sink = 0.0;
1920 for (
int np = 1; np <= I; ++np)
1921 mono_sink +=
K_ii_coal(P, np, 1) * std::max(c_n[np - 1], 0.0);
1922 dc_n[0] -= ci1 * mono_sink;
1928 dc_n[0] -= P.K_iv * cv1 * ci1;
1931 dc_n[0] += P.KIV[1] * cv1 * std::max(c_n[1], 0.0);
1933 for (
int mp = 2; mp <= P.v_mobile; ++mp) {
1934 const double c_mp = std::max(c_v[mp - 1], 0.0);
1935 if (sn + mp - 1 < I) {
1937 dc_n[0] +=
K_vi_coal(P, sn + mp, mp) * c_mp * std::max(c_n[sn + mp - 1], 0.0);
1939 dc_n[0] -=
K_vi_coal(P, sn, mp) * c_mp * ci1;
1942 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
1943 const double c_mp = std::max(c_v[mp - 1], 0.0);
1944 double K_s = (mp == 1) ? P.KIV[n] :
K_vi_coal(P, sn, mp);
1946 double K_g = (mp == 1) ? P.KIV[n + mp] :
K_vi_coal(P, sn + mp, mp);
1947 dc_n[n] += K_g * c_mp * std::max(c_n[n + mp], 0.0);
1949 dc_n[n] -= K_s * c_mp * cn;
1954 for (
int m = 1; m < V; ++m)
1955 dc_n[0] -= P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
1956 }
else if (n < 3 && n < P.i_mobile) {
1957 for (
int m = 0; m < V; ++m)
1958 dc_n[n] -= P.K_3D_cav_pref * P.m13[m] * cn * std::max(c_v[m], 0.0);
1959 }
else if (n >= 3 && n < P.i_mobile) {
1960 for (
int m = 0; m < V; ++m)
1961 dc_n[n] -=
K_1D_eff(P, n, m) * cn * std::max(c_v[m], 0.0);
1964 if (n >= 1 && n < P.i_mobile) {
1965 for (
int m = 0; m < std::min(n, V); ++m) {
1966 const double cvm = std::max(c_v[m], 0.0);
1967 const double K_cav = (n < 3) ? P.K_3D_cav_pref * P.m13[m]
1969 dc_n[n - m - 1] += K_cav * cn * cvm;
1973 dc_n[n] -= P.k2_SIA[n] * cn;
1986#ifdef CD_HAVE_OPENMP
1987#pragma omp parallel for schedule(static, 256) if(I - n_head > 2048)
1989 for (
int n = n_head; n < I; ++n) {
1990 const int sn = n + 1;
1991 const double cn = std::max(c_n[n], 0.0);
1992 dc_n[n] += P.Pr_SIA[n];
1993 if (n + 1 < I) dc_n[n] += P.GII[n+1] * std::max(c_n[n+1], 0.0);
1994 dc_n[n] -= P.GII[n] * cn;
1997 dc_n[n] +=
K_ii_coal(P, n, 1) * ci1 * std::max(c_n[n - 1], 0.0);
1998 dc_n[n] -=
K_ii_coal(P, sn, 1) * cn * ci1;
2001 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
2002 const double c_mp = std::max(c_v[mp - 1], 0.0);
2003 double K_s = (mp == 1) ? P.KIV[n] :
K_vi_coal(P, sn, mp);
2005 double K_g = (mp == 1) ? P.KIV[n + mp] :
K_vi_coal(P, sn + mp, mp);
2006 dc_n[n] += K_g * c_mp * std::max(c_n[n + mp], 0.0);
2008 dc_n[n] -= K_s * c_mp * cn;
2011 dc_n[n] -= P.k2_SIA[n] * cn;
2019 if (P.sia_emission_monomer) {
2020 double emit_mono_sia = 0.0;
2021 for (
int n = 1; n <= I - 1; ++n)
2022 emit_mono_sia += P.GII[n] * std::max(c_n[n], 0.0);
2023 dc_n[0] += emit_mono_sia;
2027 if (P.boundary_flux == 1) {
2029 const double rate_i = P.KII[I - 1] * ci1 * std::max(c_n[I - 1], 0.0);
2030 dc_n[I - 1] += rate_i;
2034 for (
int sn = 2; sn <= std::min(i_d, P.i_mobile); ++sn) {
2035 const double c_sn = std::max(c_n[sn - 1], 0.0);
2036 if (c_sn < 1e-300)
continue;
2037 for (
int np = std::max(I - sn + 1, 1); np <= i_d; ++np) {
2038 const double c_np = std::max(c_n[np - 1], 0.0);
2039 if (c_np < 1e-300)
continue;
2041 if (np >= 2 && np <= P.i_mobile) {
2042 const double rate_np =
K_ii_coal(P, sn, np) * c_sn * c_np;
2043 dc_n[sn - 1] += rate_np;
2046 const double rate_sn =
K_ii_coal(P, np, sn) * c_sn * c_np;
2047 dc_n[sn - 1] += rate_sn;
2081 for (
int n = 1; n < std::min(i_d, P.i_mobile); ++n) {
2082 const int sn = n + 1;
2083 const double cn = std::max(c_n[n], 0.0);
2084 if (cn < 1e-300)
continue;
2085 const double D_sn = P.D_SIA_eff[sn - 1];
2086 if (D_sn < 1e-300)
continue;
2087 const double pref = P.Z_ii * P.A_sph_inv_O23 * D_sn * cn;
2088 const double sn_cbrt =
sz_cbrt(P, sn);
2092 for (
int k = 0; k < Ib; ++k) {
2093 for (
int np = n_lo[k]; np < n_hi[k]; ++np) {
2094 if (np - 1 < 0 || np - 1 >= I)
continue;
2095 const double c_np = std::max(c_n[np - 1], 0.0);
2096 if (c_np < P.C_floor)
continue;
2097 const double nf =
static_cast<double>(np);
2098 const double sf =
sz_cbrt(P, np) + sn_cbrt;
2099 const double rate = pref * sf * c_np;
2105 coal_dmu0[k] -= rate;
2106 coal_dmu1[k] -= nf * rate;
2107 if (PM >= 3) coal_dmu2[k] -= nf * nf * rate;
2110 const int prod = sn + np;
2113 dc_n[prod - 1] += rate;
2115 while (kp < Ib && prod >= n_hi[kp]) ++kp;
2116 if (kp < Ib && prod >= n_lo[kp]) {
2117 const double pf =
static_cast<double>(prod);
2118 coal_dmu0[kp] += rate;
2119 coal_dmu1[kp] += pf * rate;
2120 if (PM >= 3) coal_dmu2[kp] += pf * pf * rate;
2123 }
else if (P.boundary_flux == 1) {
2126 coal_dmu0[k] += rate;
2127 coal_dmu1[k] += nf * rate;
2128 if (PM >= 3) coal_dmu2[k] += nf * nf * rate;
2143 for (
int n = 1; n < std::min(i_d, P.i_mobile); ++n) {
2144 const int sn = n + 1;
2145 const double cn = std::max(c_n[n], 0.0);
2146 if (cn < 1e-300)
continue;
2147 if (P.D_SIA_eff[sn - 1] < 1e-300)
continue;
2149 for (
int np = 1; np <= i_d; ++np) {
2150 const int prod = sn + np;
2151 if (prod <= i_d)
continue;
2152 if (prod > I)
continue;
2153 const double c_np = std::max(c_n[np - 1], 0.0);
2154 if (c_np < 1e-300)
continue;
2155 const double rate =
K_ii_coal(P, np, sn) * cn * c_np;
2156 while (kp < Ib && prod >= n_hi[kp]) ++kp;
2157 if (kp < Ib && prod >= n_lo[kp]) {
2158 const double pf =
static_cast<double>(prod);
2159 coal_dmu0[kp] += rate;
2160 if (PM >= 2) coal_dmu1[kp] += pf * rate;
2161 if (PM >= 3) coal_dmu2[kp] += pf * pf * rate;
2182 struct LoopCls {
double n_bar, cnt;
int kind, idx; };
2183 std::vector<LoopCls> cls;
2184 cls.reserve(std::max(0, i_d - P.i_mobile) + Ib);
2186 for (
int sn = P.i_mobile + 1; sn <= i_d; ++sn) {
2187 const double c = std::max(c_n[sn - 1], 0.0);
2189 cls.push_back({
static_cast<double>(sn), c, 0, sn - 1});
2191 for (
int k = 0; k < Ib; ++k) {
2192 const double m0 = std::max(y[i_d + PM*k], 0.0);
2193 if (m0 <= P.C_floor)
continue;
2194 double nb = (PM >= 2) ? y[i_d + PM*k + 1] / std::max(m0, 1e-300)
2195 : 0.5 * (n_lo[k] + n_hi[k] - 1);
2196 const double lo_f =
static_cast<double>(n_lo[k]);
2197 const double hi_f =
static_cast<double>(n_hi[k] - 1);
2198 if (nb < lo_f) nb = lo_f;
2199 else if (nb > hi_f) nb = hi_f;
2200 cls.push_back({nb, m0, 1, k});
2202 const int NC =
static_cast<int>(cls.size());
2204 auto deposit = [&](
double s,
double r) {
2205 if (s <= 0.0)
return;
2206 int si =
static_cast<int>(s + 0.5);
2212 for (
int k = 0; k < Ib; ++k) {
2213 if (si >= n_lo[k] && si < n_hi[k]) {
2215 if (PM >= 2) coal_dmu1[k] += s * r;
2216 if (PM >= 3) coal_dmu2[k] += s * s * r;
2220 coal_dmu0[Ib - 1] += r;
2221 if (PM >= 2) coal_dmu1[Ib - 1] += s * r;
2222 if (PM >= 3) coal_dmu2[Ib - 1] += s * s * r;
2224 auto remove = [&](
const LoopCls& a,
double r) {
2228 coal_dmu0[a.idx] -= r;
2229 if (PM >= 2) coal_dmu1[a.idx] -= a.n_bar * r;
2230 if (PM >= 3) coal_dmu2[a.idx] -= a.n_bar * a.n_bar * r;
2233 for (
int a = 0; a < NC; ++a) {
2234 const double na = cls[a].n_bar;
2235 const double Da = P.D_loop_coal[std::min(I, std::max(1,
2236 static_cast<int>(na + 0.5))) - 1];
2237 for (
int b = a; b < NC; ++b) {
2238 const double nb = cls[b].n_bar;
2239 const double Db = P.D_loop_coal[std::min(I, std::max(1,
2240 static_cast<int>(nb + 0.5))) - 1];
2244 const double Dsum = Da + Db;
2245 if (Dsum < 1e-300)
continue;
2246 const double sf = std::sqrt(na) + std::sqrt(nb);
2247 const int ia = std::min(I, std::max(1,
static_cast<int>(na + 0.5)));
2248 const double Zt = (!P.Z_i_loop_arr.empty())
2249 ? P.Z_i_loop_arr[ia - 1] : P.Z_i_loop;
2250 const double K = P.Z_ii * Zt * P.A_loop_inv_O23 * sf * Dsum;
2252 const double r = (a == b) ? 0.5 * K * cls[a].cnt * cls[a].cnt
2253 : K * cls[a].cnt * cls[b].cnt;
2254 if (r < 1e-300)
continue;
2256 remove(cls[a], 2.0 * r);
2261 deposit(na + nb, r);
2268 for (
int n = 0; n < i_d; ++n)
2275#ifdef CD_HAVE_OPENMP
2276#pragma omp parallel for schedule(dynamic, 1) if(I > 4096)
2278 for (
int k = 0; k < Ib; ++k) {
2279 double dmu0 = 0.0, dmu1 = 0.0, dmu2 = 0.0;
2280 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
2281 if (n - 1 >= 0 && n - 1 < I) {
2282 const double nf =
static_cast<double>(n);
2283 dmu0 += dc_n[n - 1];
2284 if (PM >= 2) dmu1 += nf * dc_n[n - 1];
2285 if (PM >= 3) dmu2 += nf * nf * dc_n[n - 1];
2288 dydt[i_d + PM*k] = dmu0 + coal_dmu0[k];
2289 if (PM >= 2) dydt[i_d + PM*k + 1] = dmu1 + coal_dmu1[k];
2290 if (PM >= 3) dydt[i_d + PM*k + 2] = dmu2 + coal_dmu2[k];
2297 double C_vac_tot = 0.0;
2298 for (
int m = 0; m < V; ++m) C_vac_tot += std::max(c_v[m], 0.0);
2299 const double ell_bar = (C_vac_tot > 1e-300) ? Q_tot / C_vac_tot : 0.0;
2303 double*
const GVV_eff = Pm.
bm_GVV_eff.data();
2307#ifdef CD_HAVE_OPENMP
2308#pragma omp parallel for schedule(static, 256) if(V > 2048)
2310 for (
int m = 0; m < V; ++m) {
2311 const double ell_m = ell_bar *
sz_pow23(P, m + 1);
2312 const double ratio = (ell_m > 1e-6) ? ell_m / (m+1) : 0.0;
2313 const double dE = (ratio > 1e-10) ? P.delta_He * P.beta_He_exp / (m+1)
2314 * std::pow(ratio, P.beta_He_exp - 1.0) : 0.0;
2315 GVV_eff[m] = P.GVV[m] * std::exp(std::min(-ell_m * dE / P.kBT, 0.0));
2319 double*
const dc_v = Pm.
bm_dc_v.data();
2323 double emit_mono = 0.0;
2324 for (
int m = 1; m < V; ++m)
2325 emit_mono += GVV_eff[m] * std::max(c_v[m], 0.0);
2326 dc_v[0] += emit_mono;
2335#ifdef CD_HAVE_OPENMP
2336#pragma omp parallel for schedule(dynamic, 256) if(V > 2048)
2338 for (
int m = 0; m < V; ++m) {
2339 const double cm = std::max(c_v[m], 0.0);
2340 const int sm = m + 1;
2341 dc_v[m] += P.Pr_VAC[m];
2343 if (m + 1 < V) dc_v[m] += GVV_eff[m+1] * std::max(c_v[m+1], 0.0);
2344 dc_v[m] -= GVV_eff[m] * cm;
2347 for (
int mp = 1; mp <= std::min(sm - 1, P.v_mobile); ++mp) {
2348 const int mpp = sm - mp;
2349 if (mpp < 1 || mpp > V)
continue;
2350 const double c_mp = std::max(c_v[mp - 1], 0.0);
2351 const double c_mpp = std::max(c_v[mpp - 1], 0.0);
2352 dc_v[m] +=
K_vv_coal(P, mpp, mp) * c_mp * c_mpp;
2355 for (
int mp = 1; mp <= P.v_mobile; ++mp)
2356 dc_v[m] -=
K_vv_coal(P, sm, mp) * cm * std::max(c_v[mp - 1], 0.0);
2358 if (sm <= P.v_mobile) {
2359 for (
int mp = 1; mp <= V; ++mp)
2360 dc_v[m] -=
K_vv_coal(P, mp, sm) * cm * std::max(c_v[mp - 1], 0.0);
2365 dc_v[0] -= P.K_iv * ci1 * cv1;
2366 if (V >= 2) dc_v[0] += P.KVI[1] * ci1 * std::max(c_v[1], 0.0);
2369 double sia_shrink_sink = 0.0;
2370 for (
int np = 1; np < I; ++np)
2371 sia_shrink_sink += P.KIV[np] * std::max(c_n[np], 0.0);
2372 dc_v[0] -= cv1 * sia_shrink_sink;
2374 dc_v[m] -= P.KVI[m] * ci1 * cm;
2375 if (m + 1 < V) dc_v[m] += P.KVI[m+1] * ci1 * std::max(c_v[m+1], 0.0);
2379 for (
int n = 1; n < std::min(3, P.i_mobile); ++n) {
2380 const double cn = std::max(c_n[n], 0.0);
2381 dc_v[m] -= P.KVI[m] * cn * cm;
2383 dc_v[m] += P.KVI[m + n + 1] * cn * std::max(c_v[m + n + 1], 0.0);
2387 for (
int n = 3; n < std::min(I, P.i_mobile); ++n) {
2388 const double cn = std::max(c_n[n], 0.0);
2389 dc_v[m] -=
K_1D_eff(P, n, m) * cn * cm;
2390 if (m + n + 1 < V) {
2391 const int mp = m + n + 1;
2392 const double k_gain =
K_1D_eff(P, n, mp);
2393 dc_v[m] += k_gain * cn * std::max(c_v[mp], 0.0);
2398 if (sm >= 2 && sm <= P.v_mobile) {
2399 for (
int sn = 1; sn <= I; ++sn) {
2400 const double c_sn = std::max(c_n[sn - 1], 0.0);
2401 dc_v[m] -=
K_vi_coal(P, sn, sm) * cm * c_sn;
2404 for (
int sn = 1; sm + sn <= P.v_mobile && sn <= I; ++sn) {
2405 if (sm + sn > V)
break;
2407 * std::max(c_v[sm + sn - 1], 0.0)
2408 * std::max(c_n[sn - 1], 0.0);
2412 if (m + 1 <= P.v_mobile)
2413 dc_v[m] -= P.k2_disl_v * cm;
2420 if (!P.Lambda_net_void.empty())
2421 dc_v[m] -= P.Lambda_net_void[m] * cm;
2425 if (P.boundary_flux == 1) {
2426 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
2427 const double c_mp = std::max(c_v[mp - 1], 0.0);
2428 for (
int k = std::max(V - mp + 1, 1); k <= V; ++k) {
2429 const double rate =
K_vv_coal(P, k, mp) * c_mp * std::max(c_v[k - 1], 0.0);
2430 dc_v[k - 1] += rate;
2431 dc_v[mp - 1] += rate;
2438 for (
int m = 0; m < v_d; ++m)
2439 dydt[i_VAC + m] = dc_v[m];
2441 const int vac_mom_start = i_VAC + v_d;
2444#ifdef CD_HAVE_OPENMP
2445#pragma omp parallel for schedule(dynamic, 1) if(V > 4096)
2447 for (
int k = 0; k < Kv; ++k) {
2448 double dmu0 = 0.0, dmu1 = 0.0, dmu2 = 0.0;
2449 for (
int m = m_lo[k]; m < m_hi[k]; ++m) {
2450 if (m - 1 >= 0 && m - 1 < V) {
2451 const double mf =
static_cast<double>(m);
2452 dmu0 += dc_v[m - 1];
2453 if (PM >= 2) dmu1 += mf * dc_v[m - 1];
2454 if (PM >= 3) dmu2 += mf * mf * dc_v[m - 1];
2457 dydt[vac_mom_start + PM*k] = dmu0;
2458 if (PM >= 2) dydt[vac_mom_start + PM*k + 1] = dmu1;
2459 if (PM >= 3) dydt[vac_mom_start + PM*k + 2] = dmu2;
2477 double* c_n100 =
nullptr;
2478 const bool c_n100_on = (P.loop_conversion != 0);
2479 if (P.loop_conversion) {
2482 const double* src = y + P.sia100_off;
2484 for (
int n = 0; n < i_d; ++n)
2485 c_n100[n] = std::max(src[n], 0.0);
2486 for (
int k = 0; k < Ib; ++k) {
2487 const double mu0_k = std::max(src[i_d + PM*k], 0.0);
2488 double mu1_k = (PM >= 2) ? src[i_d + PM*k + 1] : 0.0;
2489 double mu2_k = (PM >= 3) ? src[i_d + PM*k + 2] : 0.0;
2490 const double bw =
static_cast<double>(n_hi[k] - n_lo[k]);
2491 if (bw <= 0 || mu0_k <= 0.0)
continue;
2493 int ni = n_lo[k] - 1;
2494 if (ni >= 0 && ni < I) c_n100[ni] = mu0_k;
2498 const double n_lo_f =
static_cast<double>(n_lo[k]);
2499 const double n_hi_f =
static_cast<double>(n_hi[k] - 1);
2500 double n_bar = mu1_k / std::max(mu0_k, 1e-300);
2501 if (n_bar < n_lo_f) mu1_k = mu0_k * n_lo_f;
2502 else if (n_bar > n_hi_f) mu1_k = mu0_k * n_hi_f;
2504 double n2_min = mu1_k * mu1_k / std::max(mu0_k, 1e-300) * 1.01;
2505 if (mu2_k < n2_min) mu2_k = n2_min;
2508 bool use_lognormal =
false;
2509 if (P.shape_function == 2 && PM >= 3) {
2510 const double n_bar = mu1_k / std::max(mu0_k, 1e-300);
2511 const double n2_bar = mu2_k / std::max(mu0_k, 1e-300);
2512 const double ratio = n2_bar / std::max(n_bar * n_bar, 1e-300);
2514 use_lognormal =
true;
2515 const double sig2 = std::log(ratio);
2516 const double m_k = std::log(std::max(n_bar, 1e-300)) - 0.5 * sig2;
2517 double f_sum = 0.0, max_log_f = -1e300;
2518 std::vector<double> log_f_arr(
static_cast<int>(bw));
2519 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
2520 double ln_n = std::log(
static_cast<double>(n));
2521 double lf = std::max(-(ln_n - m_k) * (ln_n - m_k) / (2.0 * sig2), -500.0) - ln_n;
2522 log_f_arr[n - n_lo[k]] = lf;
2523 if (lf > max_log_f) max_log_f = lf;
2525 for (
int j = 0; j < static_cast<int>(bw); ++j) {
2526 log_f_arr[j] -= max_log_f;
2527 f_sum += std::exp(log_f_arr[j]);
2529 if (f_sum < 1e-300) {
2530 use_lognormal =
false;
2532 for (
int n = n_lo[k]; n < n_hi[k]; ++n)
2533 if (n - 1 >= 0 && n - 1 < I)
2534 c_n100[n - 1] = std::max(
2535 mu0_k * std::exp(log_f_arr[n - n_lo[k]]) / f_sum, 0.0);
2539 if (!use_lognormal) {
2540 if (P.shape_function == 0) {
2541 const double val = mu0_k / bw;
2542 for (
int n = n_lo[k]; n < n_hi[k]; ++n)
2543 if (n - 1 >= 0 && n - 1 < I) c_n100[n - 1] = val;
2547 if (!P.bin_S1.empty()) {
2548 S1 = P.bin_S1[k]; S2 = P.bin_S2[k];
2551 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
2552 double nf =
static_cast<double>(n);
2553 S1 += nf; S2 += nf * nf;
2556 double det = bw * S2 - S1 * S1;
2557 if (std::abs(det) < 1e-30) {
2558 double val = mu0_k / bw;
2559 for (
int n = n_lo[k]; n < n_hi[k]; ++n)
2560 if (n - 1 >= 0 && n - 1 < I) c_n100[n - 1] = val;
2563#ifdef CD_HAVE_OPENMP
2564#pragma omp parallel for schedule(static, 256) if(n_hi[k] - n_lo[k] > 2048)
2566 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
2567 if (n - 1 < 0 || n - 1 >= I)
continue;
2568 double nf =
static_cast<double>(n);
2569 double phi0 = (S2 - S1 * nf) / det;
2570 double phi1 = (bw * nf - S1) / det;
2571 c_n100[n - 1] = softplus(phi0 * mu0_k + phi1 * mu1_k);
2581 double*
const d111 = Pm.
bm_d111.data();
2582 double*
const d100 = Pm.
bm_d100.data();
2584 const int nlm = P.conv_n_loop_min;
2588#ifdef CD_HAVE_OPENMP
2589#pragma omp parallel for schedule(static, 256) if(I - nlm > 2048)
2591 for (
int n = nlm; n <= I; ++n) {
2592 const double rate = P.Gamma_uni[n - 1] * std::max(c_n[n - 1], 0.0);
2593 d111[n - 1] -= rate;
2594 d100[n - 1] += rate;
2603 const double*
const phiK = P.phiK_junc_tab.empty()
2604 ? nullptr : P.phiK_junc_tab.data();
2608#ifdef CD_HAVE_OPENMP
2609#pragma omp parallel for schedule(static, 256) if(I > 2048)
2611 for (
int sn = 2; sn <= I; ++sn) {
2613 for (
int np = 1; np <= std::min(sn - 1, P.i_mobile); ++np) {
2614 const int npp = sn - np;
2615 if (npp < 1 || npp > I)
continue;
2618 phK = phiK[
static_cast<size_t>(np - 1) * P.phiK_junc_stride
2622 phK = (ph <= 0.0) ? 0.0 : ph *
K_ii_coal(P, npp, np);
2624 if (phK == 0.0)
continue;
2626 * std::max(c_n[np - 1], 0.0)
2627 * std::max(c_n[npp - 1], 0.0);
2629 d111[sn - 1] -= moved;
2630 d100[sn - 1] += moved;
2633 for (
int m = nlm; m <= I; ++m) {
2634 const double cm100 = std::max(c_n100[m - 1], 0.0);
2635 if (cm100 < 1e-300)
continue;
2636 for (
int n = 1; n <= P.i_mobile && m + n <= I; ++n) {
2638 * cm100 * std::max(c_n[n - 1], 0.0);
2639 d100[m - 1] -= rate;
2640 d111[n - 1] -= rate;
2641 d100[m + n - 1] += rate;
2645 for (
int n = nlm; n <= I; ++n) {
2646 const double cn100 = std::max(c_n100[n - 1], 0.0);
2647 if (cn100 < 1e-300)
continue;
2649 const double g = P.K_100_grow[n - 1] * cn100 * ci1;
2655 const double s = P.K_100_shrink[n - 1] * cn100 * cv1;
2657 if (n - 1 >= nlm) d100[n - 2] += s;
2658 else if (n >= 2) d111[n - 2] += s;
2662 const double e = P.G_100[n - 1] * cn100;
2664 if (n - 1 >= nlm) d100[n - 2] += e;
2665 else if (n >= 2) d111[n - 2] += e;
2670 d100[n - 1] -= P.Lambda_net_100[n - 1] * cn100;
2674 for (
int n = 0; n < i_d; ++n) dydt[n] += d111[n];
2675#ifdef CD_HAVE_OPENMP
2676#pragma omp parallel for schedule(dynamic, 1) if(I > 4096)
2678 for (
int k = 0; k < Ib; ++k) {
2679 double dmu0 = 0.0, dmu1 = 0.0, dmu2 = 0.0;
2680 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
2681 if (n - 1 >= 0 && n - 1 < I) {
2682 const double nf =
static_cast<double>(n);
2683 dmu0 += d111[n - 1];
2684 if (PM >= 2) dmu1 += nf * d111[n - 1];
2685 if (PM >= 3) dmu2 += nf * nf * d111[n - 1];
2688 dydt[i_d + PM*k] += dmu0;
2689 if (PM >= 2) dydt[i_d + PM*k + 1] += dmu1;
2690 if (PM >= 3) dydt[i_d + PM*k + 2] += dmu2;
2693 dydt[i_VAC + 0] += dv1;
2697 const int s100 = P.sia100_off;
2698 for (
int n = 0; n < i_d; ++n) dydt[s100 + n] = d100[n];
2699#ifdef CD_HAVE_OPENMP
2700#pragma omp parallel for schedule(dynamic, 1) if(I > 4096)
2702 for (
int k = 0; k < Ib; ++k) {
2703 double dmu0 = 0.0, dmu1 = 0.0, dmu2 = 0.0;
2704 for (
int n = n_lo[k]; n < n_hi[k]; ++n) {
2705 if (n - 1 >= 0 && n - 1 < I) {
2706 const double nf =
static_cast<double>(n);
2707 dmu0 += d100[n - 1];
2708 if (PM >= 2) dmu1 += nf * d100[n - 1];
2709 if (PM >= 3) dmu2 += nf * nf * d100[n - 1];
2712 dydt[s100 + i_d + PM*k] = dmu0;
2713 if (PM >= 2) dydt[s100 + i_d + PM*k + 1] = dmu1;
2714 if (PM >= 3) dydt[s100 + i_d + PM*k + 2] = dmu2;
2722 double He_sink_state = 0.0;
2723 if (P.he_mode != 1) {
2726 for (
int m = 0; m < V; ++m)
2727 He_up += P.KHeV[m] * c_h * std::max(c_v[m], 0.0);
2728 const double He_emit = P.beta_He * Q_tot;
2730 double He_sink_2 = 0.0;
2731 for (
int m = 0; m < std::min(V, P.v_mobile); ++m) {
2732 const double ell_m = ell_bar * std::pow(
static_cast<double>(m + 1), 2.0/3.0);
2733 He_sink_2 += P.k2_disl_v * ell_m * std::max(c_v[m], 0.0);
2735 He_sink_state = He_sink_2;
2736 dydt[i_Q_base] = He_up - He_emit - He_sink_2;
2738 dydt[i_He_idx] = P.G_He - He_up - P.k2_disl_He * c_h + He_emit;
2742 double He_cap_total = 0.0, He_emit_total = 0.0;
2744 for (
int k = 0; k < Kv; ++k) {
2745 const double mu0_k = std::max(y[vac_mom_start + PM*k], 0.0);
2746 const double qk = std::max(y[i_Q_base + k], 0.0);
2747 const double ell_k = (mu0_k > 1e-200) ? qk / mu0_k : 0.0;
2749 for (
int m = m_lo[k]; m < m_hi[k]; ++m) {
2751 if (mi < 0 || mi >= V)
continue;
2752 const double cm = std::max(c_v[mi], 0.0);
2753 const double he_cap = P.KHeV[mi] * c_h * cm;
2754 const double q_approx = ell_k * cm;
2755 const double he_emit = P.beta_He * q_approx;
2756 dqk += he_cap - he_emit;
2757 if (m <= P.v_mobile) {
2758 dqk -= P.k2_disl_v * q_approx;
2759 He_sink_state += P.k2_disl_v * q_approx;
2761 He_cap_total += he_cap;
2762 He_emit_total += he_emit;
2764 dydt[i_Q_base + k] = dqk;
2767 for (
int m = 0; m < V; ++m) {
2768 const double cm = std::max(c_v[m], 0.0);
2769 const double qm = std::max(y[i_Q_base + m], 0.0);
2770 const double he_cap_m = P.KHeV[m] * c_h * cm;
2771 const double he_emit_m = P.beta_He * qm;
2772 dydt[i_Q_base + m] += he_cap_m - he_emit_m;
2773 if (m + 1 <= P.v_mobile) {
2774 dydt[i_Q_base + m] -= P.k2_disl_v * qm;
2775 He_sink_state += P.k2_disl_v * qm;
2777 He_cap_total += he_cap_m;
2778 He_emit_total += he_emit_m;
2782 dydt[i_He_idx] = P.G_He - He_cap_total - P.k2_disl_He * c_h + He_emit_total;
2788 double sia_fixed = 0.0;
2789 for (
int n = 0; n < I; ++n)
2790 sia_fixed +=
static_cast<double>(n + 1) * P.k2_SIA[n] * std::max(c_n[n], 0.0);
2791 dydt[P.cons_off + 0] = sia_fixed;
2798 double mutual = 0.0;
2799 for (
int n = 0; n < I; ++n) {
2800 const int sn = n + 1;
2801 const double cn_val = std::max(c_n[n], 0.0);
2802 if (cn_val < 1e-300)
continue;
2805 for (
int m = 1; m < V; ++m)
2806 mutual += P.K_3D_cav_pref * P.m13[m] * cn_val * std::max(c_v[m], 0.0);
2807 }
else if (n < 3 && n < P.i_mobile) {
2808 for (
int m = 0; m < V; ++m)
2809 mutual += std::min(sn, m + 1) * P.K_3D_cav_pref * P.m13[m] * cn_val * std::max(c_v[m], 0.0);
2810 }
else if (n >= 3 && n < P.i_mobile) {
2811 for (
int m = 0; m < V; ++m)
2812 mutual += std::min(sn, m + 1) *
K_1D_eff(P, n, m) * cn_val * std::max(c_v[m], 0.0);
2815 for (
int mp = 1; mp <= P.v_mobile; ++mp) {
2816 const double c_mp = std::max(c_v[mp - 1], 0.0);
2817 if (c_mp < 1e-300)
continue;
2819 if (mp == 1 && n > 0) K_s = P.KIV[n];
2820 else if (mp == 1 && n == 0) K_s = P.K_iv;
2822 mutual += std::min(mp, sn) * K_s * c_mp * cn_val;
2825 dydt[P.cons_off + 1] = mutual;
2830 double vac_fixed = 0.0;
2831 for (
int m = 0; m < std::min(P.v_mobile, P.V); ++m)
2832 vac_fixed +=
static_cast<double>(m + 1) * P.k2_disl_v * std::max(c_v[m], 0.0);
2836 if (!P.Lambda_net_void.empty())
2837 for (
int m = 0; m < P.V; ++m)
2838 vac_fixed +=
static_cast<double>(m + 1) * P.Lambda_net_void[m]
2839 * std::max(c_v[m], 0.0);
2840 dydt[P.cons_off + 2] = vac_fixed;
2848 dydt[P.cons_off + 3] = dydt[P.cons_off + 1];
2854 dydt[P.cons_off + 4] = P.k2_disl_He * c_h + He_sink_state;
2860 if (P.loop_conversion && c_n100_on) {
2861 double s100_mut = 0.0, s100_fixed = 0.0;
2862 for (
int n = P.conv_n_loop_min; n <= I; ++n) {
2863 s100_mut += P.K_100_shrink[n - 1] * std::max(c_n100[n - 1], 0.0) * cv1;
2864 s100_fixed +=
static_cast<double>(n) * P.Lambda_net_100[n - 1]
2865 * std::max(c_n100[n - 1], 0.0);
2867 dydt[P.cons_off + 1] += s100_mut;
2868 dydt[P.cons_off + 3] += s100_mut;
2869 dydt[P.cons_off + 0] += s100_fixed;
2879 const int n_sia = i_d + PM * Ib;
2880 const int n_vac = v_d + PM * P.V_bin;
2883 const int hi_i = std::min(ud->
x_hi_i, n_sia - 1);
2884 for (
int k = hi_i + 1; k < n_sia; ++k) dydt[k] = 0.0;
2887 const int hi_v = std::min(ud->
x_hi_v, n_vac - 1);
2888 for (
int k = hi_v + 1; k < n_vac; ++k) dydt[i_VAC + k] = 0.0;
2892 if (P.loop_conversion)
2893 for (
int k = hi_i + 1; k < P.sia100_len; ++k)
2894 dydt[P.sia100_off + k] = 0.0;