// // ******************************************************************** // * License and Disclaimer * // * * // * The Geant4 software is copyright of the Copyright Holders of * // * the Geant4 Collaboration. It is provided under the terms and * // * conditions of the Geant4 Software License, included in the file * // * LICENSE and available at http://cern.ch/geant4/license . These * // * include a list of copyright holders. * // * * // * Neither the authors of this software system, nor their employing * // * institutes,nor the agencies providing financial support for this * // * work make any representation or warranty, express or implied, * // * regarding this software system or assume any liability for its * // * use. Please see the license in the file LICENSE and URL above * // * for the full disclaimer and the limitation of liability. * // * * // * This code implementation is the result of the scientific and * // * technical work of the GEANT4 collaboration. * // * By using, copying, modifying or distributing the software (or * // * any work based on the software) you agree to acknowledge its * // * use in resulting scientific publications, and indicate your * // * acceptance of all terms of the Geant4 Software license. * // ******************************************************************** // // G4QSS3 // // G4QSS3 simulator // Authors: Lucio Santi, Rodrigo Castro (Univ. Buenos Aires), 2018-2021 // -------------------------------------------------------------------- #ifndef G4QSS3_HH #define G4QSS3_HH #include "G4Types.hh" #include "G4qss_misc.hh" #include /** * @brief G4QSS3 defines the QSS3 simulator engine used in QSS field stepper. */ class G4QSS3 { public: G4QSS3(QSS_simulator); inline QSS_simulator getSimulator() const { return this->simulator; } inline G4int order() const { return 3; } inline void full_definition(G4double coeff) { G4double* const x = simulator->q; G4double* const dx = simulator->x; G4double* const alg = simulator->alg; dx[1] = x[12]; dx[2] = 0; dx[3] = 0; dx[5] = x[16]; dx[6] = 0; dx[7] = 0; dx[9] = x[20]; dx[10] = 0; dx[11] = 0; dx[13] = coeff * (alg[2] * x[16] - alg[1] * x[20]); dx[14] = 0; dx[15] = 0; dx[17] = coeff * (alg[0] * x[20] - alg[2] * x[12]); dx[18] = 0; dx[19] = 0; dx[21] = coeff * (alg[1] * x[12] - alg[0] * x[16]); dx[22] = 0; dx[23] = 0; } inline void dependencies(G4int i, G4double coeff) { G4double* const x = simulator->q; G4double* const der = simulator->x; G4double* const alg = simulator->alg; switch (i) { case 0: der[13] = coeff * (alg[2] * x[16] - alg[1] * x[20]); der[14] = ((alg[2] * x[17] - x[21] * alg[1]) * coeff) / 2; der[15] = (coeff * (alg[2] * x[18] - x[22] * alg[1])) / 3; der[17] = coeff * (alg[0] * x[20] - alg[2] * x[12]); der[18] = ((alg[0] * x[21] - alg[2] * x[13]) * coeff) / 2; der[19] = (coeff * (alg[0] * x[22] - alg[2] * x[14])) / 3; der[21] = coeff * (alg[1] * x[12] - alg[0] * x[16]); der[22] = (coeff * (x[13] * alg[1] - alg[0] * x[17])) / 2; der[23] = (coeff * (alg[1] * x[14] - x[18] * alg[0])) / 3; return; case 1: der[13] = coeff * (alg[2] * x[16] - alg[1] * x[20]); der[14] = ((alg[2] * x[17] - x[21] * alg[1]) * coeff) / 2; der[15] = (coeff * (alg[2] * x[18] - x[22] * alg[1])) / 3; der[17] = coeff * (alg[0] * x[20] - alg[2] * x[12]); der[18] = ((alg[0] * x[21] - alg[2] * x[13]) * coeff) / 2; der[19] = (coeff * (alg[0] * x[22] - alg[2] * x[14])) / 3; der[21] = coeff * (alg[1] * x[12] - alg[0] * x[16]); der[22] = (coeff * (x[13] * alg[1] - alg[0] * x[17])) / 2; der[23] = (coeff * (alg[1] * x[14] - x[18] * alg[0])) / 3; return; case 2: der[13] = coeff * (alg[2] * x[16] - alg[1] * x[20]); der[14] = ((alg[2] * x[17] - x[21] * alg[1]) * coeff) / 2; der[15] = (coeff * (alg[2] * x[18] - x[22] * alg[1])) / 3; der[17] = coeff * (alg[0] * x[20] - alg[2] * x[12]); der[18] = ((alg[0] * x[21] - alg[2] * x[13]) * coeff) / 2; der[19] = (coeff * (alg[0] * x[22] - alg[2] * x[14])) / 3; der[21] = coeff * (alg[1] * x[12] - alg[0] * x[16]); der[22] = (coeff * (x[13] * alg[1] - alg[0] * x[17])) / 2; der[23] = (coeff * (alg[1] * x[14] - x[18] * alg[0])) / 3; return; case 3: der[1] = x[12]; der[2] = x[13] / 2; der[3] = x[14] / 3; der[17] = coeff * (alg[0] * x[20] - alg[2] * x[12]); der[18] = ((alg[0] * x[21] - alg[2] * x[13]) * coeff) / 2; der[19] = (coeff * (alg[0] * x[22] - alg[2] * x[14])) / 3; der[21] = coeff * (alg[1] * x[12] - alg[0] * x[16]); der[22] = (coeff * (x[13] * alg[1] - alg[0] * x[17])) / 2; der[23] = (coeff * (alg[1] * x[14] - x[18] * alg[0])) / 3; return; case 4: der[5] = x[16]; der[6] = x[17] / 2; der[7] = x[18] / 3; der[13] = coeff * (alg[2] * x[16] - alg[1] * x[20]); der[14] = ((alg[2] * x[17] - x[21] * alg[1]) * coeff) / 2; der[15] = (coeff * (alg[2] * x[18] - x[22] * alg[1])) / 3; der[21] = coeff * (alg[1] * x[12] - alg[0] * x[16]); der[22] = (coeff * (x[13] * alg[1] - alg[0] * x[17])) / 2; der[23] = (coeff * (alg[1] * x[14] - x[18] * alg[0])) / 3; return; case 5: der[9] = x[20]; der[10] = x[21] / 2; der[11] = x[22] / 3; der[13] = coeff * (alg[2] * x[16] - alg[1] * x[20]); der[14] = ((alg[2] * x[17] - x[21] * alg[1]) * coeff) / 2; der[15] = (coeff * (alg[2] * x[18] - x[22] * alg[1])) / 3; der[17] = coeff * (alg[0] * x[20] - alg[2] * x[12]); der[18] = ((alg[0] * x[21] - alg[2] * x[13]) * coeff) / 2; der[19] = (coeff * (alg[0] * x[22] - alg[2] * x[14])) / 3; return; } } void recompute_next_times(G4int* inf, G4double t); // __attribute__((hot)); inline void recompute_all_state_times(G4double t) { G4double mpr; G4double* const x = simulator->x; G4double* const lqu = simulator->lqu; G4double* const time = simulator->nextStateTime; for (G4int var = 0, icf0 = 0; var < 6; var++, icf0 += 4) { const G4int icf1 = icf0 + 1; if (x[icf1] == 0) { time[var] = Qss_misc::INF; } else { mpr = lqu[var] / x[icf1]; if (mpr < 0) { mpr *= -1; } time[var] = t + mpr; } } } inline void next_time(G4int i, G4double t) { const G4int cf3 = 4 * i + 3; G4double* const x = simulator->x; G4double* const lqu = simulator->lqu; G4double* const time = simulator->nextStateTime; if (likely(x[cf3])) { time[i] = t + std::cbrt(lqu[i] / std::fabs(x[cf3])); } else { time[i] = Qss_misc::INF; } } inline void update_quantized_state(G4int i) { const G4int cf0 = i * 4, cf1 = cf0 + 1, cf2 = cf1 + 1; G4double* const q = simulator->q; G4double* const x = simulator->x; q[cf0] = x[cf0]; q[cf1] = x[cf1]; q[cf2] = x[cf2]; } inline void reset_state(G4int i, G4double value) { G4double* const x = simulator->x; G4double* const q = simulator->q; G4double* const tq = simulator->tq; G4double* const tx = simulator->tx; const G4int idx = 4 * i; x[idx] = value; simulator->lqu[i] = simulator->dQRel[i] * std::fabs(value); if (simulator->lqu[i] < simulator->dQMin[i]) { simulator->lqu[i] = simulator->dQMin[i]; } q[idx] = value; q[idx + 1] = q[idx + 2] = tq[i] = tx[i] = 0; } inline G4double evaluate_x_poly(G4int i, G4double dt, G4double* p) { return ((p[i + 3] * dt + p[i + 2]) * dt + p[i + 1]) * dt + p[i]; } inline void advance_time_q(G4int i, G4double dt) // __attribute__((hot)) { G4double* const p = simulator->q; const G4int i0 = i, i1 = i0 + 1, i2 = i1 + 1; p[i0] = (p[i2] * dt + p[i1]) * dt + p[i0]; p[i1] = p[i1] + 2 * dt * p[i2]; } inline void advance_time_x(G4int i, G4double dt) // __attribute__((hot)) { G4double* const p = simulator->x; const G4int i0 = i, i1 = i0 + 1, i2 = i1 + 1, i3 = i2 + 1; p[i0] = ((p[i3] * dt + p[i2]) * dt + p[i1]) * dt + p[i0]; p[i1] = (3 * p[i3] * dt + 2 * p[i2]) * dt + p[i1]; p[i2] = p[i2] + 3 * dt * p[i3]; } G4double min_pos_root(G4double* coeff, G4int order); inline G4double min_pos_root_2(G4double* coeff) { G4double mpr = Qss_misc::INF; if (coeff[2] == 0 || (1000 * std::fabs(coeff[2])) < std::fabs(coeff[1])) { if (coeff[1] == 0) { mpr = Qss_misc::INF; } else { mpr = -coeff[0] / coeff[1]; } if (mpr < 0) { mpr = Qss_misc::INF; } } else { G4double disc; disc = coeff[1] * coeff[1] - 4 * coeff[2] * coeff[0]; if (disc < 0) // no real roots { mpr = Qss_misc::INF; } else { G4double sd, r1; G4double cf2_d2 = 2 * coeff[2]; sd = std::sqrt(disc); r1 = (-coeff[1] + sd) / cf2_d2; if (r1 > 0) { mpr = r1; } else { mpr = Qss_misc::INF; } r1 = (-coeff[1] - sd) / cf2_d2; if ((r1 > 0) && (r1 < mpr)) { mpr = r1; } } } return mpr; } // __attribute__((hot)) inline G4double min_pos_root_3(G4double* coeff) { G4double mpr = Qss_misc::INF; static const G4double sqrt3 = std::sqrt(3); if ((coeff[3] == 0) || (1000 * std::fabs(coeff[3]) < std::fabs(coeff[2]))) { mpr = min_pos_root_2(coeff); } else if (coeff[0] == 0) { if (coeff[1] == 0) { mpr = -coeff[2] / coeff[3]; } else { coeff[0] = coeff[1]; coeff[1] = coeff[2]; coeff[2] = coeff[3]; mpr = min_pos_root_2(coeff); } } else { G4double q, r, disc, q3; G4double val = coeff[2] / 3 / coeff[3]; G4double cf32 = coeff[3] * coeff[3]; G4double cf22 = coeff[2] * coeff[2]; G4double denq = 9 * cf32; G4double denr = 6 * coeff[3] * denq; G4double rcomm = 9 * coeff[3] * coeff[2] * coeff[1] - 2 * cf22 * coeff[2]; q = (3 * coeff[3] * coeff[1] - cf22) / denq; q3 = q * q * q; r = (rcomm - 27 * cf32 * coeff[0]) / denr; disc = q3 + r * r; mpr = Qss_misc::INF; if (disc >= 0) { G4double sd, sx, t, r1, rsd; sd = std::sqrt(disc); rsd = r + sd; if (rsd > 0) { sx = std::cbrt(rsd); } else { sx = -std::cbrt(std::fabs(rsd)); } rsd = r - sd; if (rsd > 0) { t = std::cbrt(rsd); } else { t = -std::cbrt(std::fabs(rsd)); } r1 = sx + t - val; if (r1 > 0) { mpr = r1; } } else { // three real roots G4double rho, th, rho13, costh3, sinth3, spt, smti32, r1; rho = std::sqrt(-q3); th = std::acos(r / rho); rho13 = std::cbrt(rho); costh3 = std::cos(th / 3); sinth3 = std::sin(th / 3); spt = rho13 * 2 * costh3; smti32 = -rho13 * sinth3 * sqrt3; r1 = spt - val; if (r1 > 0) { mpr = r1; } r1 = -spt / 2 - val + smti32; if ((r1 > 0) && (r1 < mpr)) { mpr = r1; } r1 = r1 - 2 * smti32; if ((r1 > 0) && (r1 < mpr)) { mpr = r1; } } } return mpr; } // __attribute__((hot)) inline G4double min_pos_root_2_alt(G4double* coeff, G4double cf0Alt) { G4double mpr = Qss_misc::INF; G4double mpr2; if (coeff[2] == 0 || (1000 * std::fabs(coeff[2])) < std::fabs(coeff[1])) { if (coeff[1] == 0) { mpr = Qss_misc::INF; } else { mpr = -coeff[0] / coeff[1]; mpr2 = -cf0Alt / coeff[1]; if (mpr < 0 || (mpr2 > 0 && mpr2 < mpr)) { mpr = mpr2; } } if (mpr < 0) { mpr = Qss_misc::INF; } } else { G4double cf1_2 = coeff[1] * coeff[1]; G4double cf2_4 = 4 * coeff[2]; G4double disc1 = cf1_2 - cf2_4 * coeff[0]; G4double disc2 = cf1_2 - cf2_4 * cf0Alt; G4double cf2_d2 = 2 * coeff[2]; if (unlikely(disc1 < 0 && disc2 < 0)) { mpr = Qss_misc::INF; } else if (disc2 < 0) { G4double sd, r1; sd = std::sqrt(disc1); r1 = (-coeff[1] + sd) / cf2_d2; if (r1 > 0) { mpr = r1; } else { mpr = Qss_misc::INF; } r1 = (-coeff[1] - sd) / cf2_d2; if ((r1 > 0) && (r1 < mpr)) { mpr = r1; } } else if (disc1 < 0) { G4double sd, r1; sd = std::sqrt(disc2); r1 = (-coeff[1] + sd) / cf2_d2; if (r1 > 0) { mpr = r1; } else { mpr = Qss_misc::INF; } r1 = (-coeff[1] - sd) / cf2_d2; if ((r1 > 0) && (r1 < mpr)) { mpr = r1; } } else { G4double sd1, r1, sd2, r2; sd1 = std::sqrt(disc1); sd2 = std::sqrt(disc2); r1 = (-coeff[1] + sd1) / cf2_d2; r2 = (-coeff[1] + sd2) / cf2_d2; if (r1 > 0) { mpr = r1; } else { mpr = Qss_misc::INF; } r1 = (-coeff[1] - sd1) / cf2_d2; if ((r1 > 0) && (r1 < mpr)) { mpr = r1; } if (r2 > 0 && r2 < mpr) { mpr = r2; } r2 = (-coeff[1] - sd2) / cf2_d2; if ((r2 > 0) && (r2 < mpr)) { mpr = r2; } } } return mpr; } // __attribute__((hot)) inline G4double min_pos_root_3_alt(G4double* coeff, G4double cf0Alt) { G4double mpr = Qss_misc::INF; static const G4double sqrt3 = std::sqrt(3); if ((coeff[3] == 0) || (1000 * std::fabs(coeff[3]) < std::fabs(coeff[2]))) { mpr = min_pos_root_2_alt(coeff, cf0Alt); } else if (coeff[0] == 0) { G4double mpr2; coeff[0] = cf0Alt; mpr = min_pos_root_3(coeff); if (coeff[1] == 0) { mpr2 = -coeff[2] / coeff[3]; } else { coeff[0] = coeff[1]; coeff[1] = coeff[2]; coeff[2] = coeff[3]; mpr2 = min_pos_root_2(coeff); } if (mpr2 > 0 && mpr2 < mpr) { mpr = mpr2; } } else if (cf0Alt == 0) { G4double mpr2; mpr = min_pos_root_3(coeff); if (coeff[1] == 0) { mpr2 = -coeff[2] / coeff[3]; } else { coeff[0] = coeff[1]; coeff[1] = coeff[2]; coeff[2] = coeff[3]; mpr2 = min_pos_root_2(coeff); } if (mpr2 > 0 && mpr2 < mpr) { mpr = mpr2; } } else { G4double q, r, rAlt, disc, discAlt, q3; G4double val = coeff[2] / 3 / coeff[3]; G4double cf32 = coeff[3] * coeff[3]; G4double cf22 = coeff[2] * coeff[2]; G4double denq = 9 * cf32; G4double denr = 6 * coeff[3] * denq; G4double rcomm = 9 * coeff[3] * coeff[2] * coeff[1] - 2 * cf22 * coeff[2]; q = (3 * coeff[3] * coeff[1] - cf22) / denq; q3 = q * q * q; r = (rcomm - 27 * cf32 * coeff[0]) / denr; rAlt = (rcomm - 27 * cf32 * cf0Alt) / denr; disc = q3 + r * r; discAlt = q3 + rAlt * rAlt; mpr = Qss_misc::INF; if (disc >= 0) { G4double sd, sx, t, r1, rsd; sd = std::sqrt(disc); rsd = r + sd; if (rsd > 0) { sx = std::cbrt(rsd); } else { sx = -std::cbrt(std::fabs(rsd)); } rsd = r - sd; if (rsd > 0) { t = std::cbrt(rsd); } else { t = -std::cbrt(std::fabs(rsd)); } r1 = sx + t - val; if (r1 > 0) { mpr = r1; } if (discAlt >= 0) { G4double sdAlt, sAlt, tAlt, r1Alt, rsdAlt; sdAlt = std::sqrt(discAlt); rsdAlt = rAlt + sdAlt; if (rsdAlt > 0) { sAlt = std::cbrt(rsdAlt); } else { sAlt = -std::cbrt(std::fabs(rsdAlt)); } rsdAlt = rAlt - sdAlt; if (rsdAlt > 0) { tAlt = std::cbrt(rsdAlt); } else { tAlt = -std::cbrt(std::fabs(rsdAlt)); } r1Alt = sAlt + tAlt - val; if (r1Alt > 0 && r1Alt < mpr) { mpr = r1Alt; } } else { G4double rho, th, rho13, costh3, sinth3, spt, smti32, r1Alt; rho = std::sqrt(-q3); th = std::acos(rAlt / rho); rho13 = std::cbrt(rho); costh3 = std::cos(th / 3); sinth3 = std::sin(th / 3); spt = rho13 * 2 * costh3; smti32 = -rho13 * sinth3 * sqrt3; r1Alt = spt - val; if (r1Alt > 0 && r1Alt < mpr) { mpr = r1Alt; } r1Alt = -spt / 2 - val + smti32; if (r1Alt > 0 && r1Alt < mpr) { mpr = r1Alt; } r1Alt = r1Alt - 2 * smti32; if (r1Alt > 0 && r1Alt < mpr) { mpr = r1Alt; } } } else { G4double rho, th, rho13, costh3, sinth3, spt, smti32, r1; rho = std::sqrt(-q3); th = std::acos(r / rho); rho13 = std::cbrt(rho); costh3 = std::cos(th / 3); sinth3 = std::sin(th / 3); spt = rho13 * 2 * costh3; smti32 = -rho13 * sinth3 * sqrt3; r1 = spt - val; if (r1 > 0) { mpr = r1; } r1 = -spt / 2 - val + smti32; if ((r1 > 0) && (r1 < mpr)) { mpr = r1; } r1 = r1 - 2 * smti32; if ((r1 > 0) && (r1 < mpr)) { mpr = r1; } if (discAlt >= 0) { G4double sdAlt, sAlt, tAlt, r1Alt, rsdAlt; sdAlt = std::sqrt(discAlt); rsdAlt = rAlt + sdAlt; if (rsdAlt > 0) { sAlt = std::cbrt(rsdAlt); } else { sAlt = -std::cbrt(std::fabs(rsdAlt)); } rsdAlt = rAlt - sdAlt; if (rsdAlt > 0) { tAlt = std::cbrt(rsdAlt); } else { tAlt = -std::cbrt(std::fabs(rsdAlt)); } r1Alt = sAlt + tAlt - val; if (r1Alt > 0 && r1Alt < mpr) { mpr = r1Alt; } } else { G4double thAlt, costh3Alt, sinth3Alt, sptAlt, smti32Alt, r1Alt; thAlt = std::acos(rAlt / rho); costh3Alt = std::cos(thAlt / 3); sinth3Alt = std::sin(thAlt / 3); sptAlt = rho13 * 2 * costh3Alt; smti32Alt = -rho13 * sinth3Alt * sqrt3; r1Alt = sptAlt - val; if (r1Alt > 0 && r1Alt < mpr) { mpr = r1Alt; } r1Alt = -sptAlt / 2 - val + smti32Alt; if (r1Alt > 0 && r1Alt < mpr) { mpr = r1Alt; } r1Alt = r1Alt - 2 * smti32Alt; if (r1Alt > 0 && r1Alt < mpr) { mpr = r1Alt; } } } } return mpr; } private: QSS_simulator simulator; }; #endif