diff --git a/src/include/sph_subs.h b/src/include/sph_subs.h new file mode 100644 index 0000000000000000000000000000000000000000..97ea5d0873c1df715c069af076afe7503e1472e1 --- /dev/null +++ b/src/include/sph_subs.h @@ -0,0 +1,701 @@ +/*! \file sph_subs.h + * + * \brief C++ porting of SPH functions, subroutines and data structures. + * + * Remember that FORTRAN passes arguments by reference, so, every time we use + * a subroutine call, we need to add a referencing layer to the C++ variable. + * All the functions defined below need to be properly documented and ported + * to C++. + * + * Currently, only basic documenting information about functions and parameter + * types are given, to avoid doxygen warning messages. + */ + +#ifndef SRC_INCLUDE_SPH_SUBS_H_ +#define SRC_INCLUDE_SPH_SUBS_H_ + +#include <complex> + +//! \brief A structure representing the common block C1 +struct C1 { + std::complex<double> rmi[40][2]; + std::complex<double> rei[40][2]; + std::complex<double> w[3360][4]; + std::complex<double> fsas[2]; + std::complex<double> sas[2][2][2]; + std::complex<double> vints[2][16]; + double sscs[2]; + double sexs[2]; + double sabs[2]; + double sqscs[2]; + double sqexs[2]; + double sqabs[2]; + double gcsv[2]; + double rxx[1]; + double ryy[1]; + double rzz[1]; + double ros[2]; + double rc[2][8]; + int iog[2]; + int nshl[2]; +}; + +//! \brief A structure representing the common block C1 +struct C2 { + std::complex<double> ris[999]; + std::complex<double> dlri[999]; + std::complex<double> dc0[5]; + std::complex<double> vkt[2]; + double vsz[2]; +}; + +//! \brief Write a message to test FORTRAN -> C++ communication +extern "C" void testme_(); + +/*! \brief C++ porting of DIEL + * + * \param npntmo: `int` + * \param ns: `int` + * \param i: `int` + * \param ic: `int` + * \param vk: `double` + * \param c1: `C1 *` + * \param c2: `C2 *` + */ +void diel(int npntmo, int ns, int i, int ic, double vk, C1 *c1, C2 *c2) { + double dif = c1->rc[i - 1][ns] - c1->rc[i - 1][ns - 1]; + double half_step = 0.5 * dif / npntmo; + double rr = c1->rc[i - 1][ns - 1]; + std::complex<double> delta = c2->dc0[ic] - c2->dc0[ic - 1]; + int kpnt = npntmo + npntmo; + c2->ris[kpnt] = c2->dc0[ic]; + c2->dlri[kpnt] = std::complex<double>(0.0, 0.0); + for (int np90 = 0; np90 < kpnt; np90++) { + double ff = (rr - c1->rc[i - 1][ns - 1]) / dif; + c2->ris[np90] = delta * ff * ff * (-2.0 * ff + 3.0) + c2->dc0[ic - 1]; + c2->dlri[np90] = 3.0 * delta * ff * (1.0 - ff) / (dif * vk * c2->ris[np90]); + rr += half_step; + } +} + +/*! \brief C++ porting of ENVJ + * + * \param n: `int` + * \param x: `double` + * \return result: `double` + */ +double envj(int n, double x) { + double result = 0.0; + double xn; + if (n == 0) { + xn = 1.0e-100; + result = 0.5 * log10(6.28 * xn) - xn * log10(1.36 * x / xn); + } else { + result = 0.5 * log10(6.28 * n) - n * log10(1.36 * x / n); + } + return result; +} + +/*! \brief C++ porting of MSTA1 + * + * \param x: `double` + * \param mp: `int` + * \return result: `int` + */ +int msta1(double x, int mp) { + int result = 0; + double a0 = x; + if (a0 < 0.0) a0 *= -1.0; + int n0 = (int)(1.1 * a0) + 1; + double f0 = envj(n0, a0) - mp; + int n1 = n0 + 5; + double f1 = envj(n1, a0) - mp; + for (int it10 = 0; it10 < 20; it10++) { + int nn = n1 - (int)((n1 - n0) / (1.0 - f0 / f1)); + double f = envj(nn, a0) - mp; + int test_n = nn - n1; + if (test_n < 0) test_n *= -1; + if (test_n < 1) { + return nn; + } + n0 = n1; + f0 = f1; + n1 = nn; + f1 = f; + result = nn; + } + return result; +} + +/*! \brief C++ porting of MSTA2 + * + * \param x: `double` + * \param n: `int` + * \param mp: `int` + * \return result: `int` + */ +int msta2(double x, int n, int mp) { + int result = 0; + double a0 = x; + if (a0 < 0) a0 *= -1.0; + double half_mp = 0.5 * mp; + double ejn = envj(n, a0); + double obj; + int n0; + if (ejn <= half_mp) { + obj = 1.0 * mp; + n0 = (int)(1.1 * a0) + 1; + } else { + obj = half_mp + ejn; + n0 = n; + } + double f0 = envj(n0, a0) - obj; + int n1 = n0 + 5; + double f1 = envj(n1, a0) - obj; + for (int it10 = 0; it10 < 20; it10 ++) { + int nn = n1 - (int)((n1 - n0) / (1.0 - f0 / f1)); + double f = envj(nn, a0) - obj; + int test_n = nn - n1; + if (test_n < 0) test_n *= -1; + if (test_n < 1) return (nn + 10); + n0 = n1; + f0 = f1; + n1 = nn; + f1 = f; + result = nn + 10; + } + return result; +} + +/*! \brief C++ porting of CBF + * + * This is the Complex Bessel Function. + * + * \param n: `int` + * \param z: `complex\<double\>` + * \param nm: `int &` + * \param csj: Vector of complex. + */ +void cbf(int n, std::complex<double> z, int &nm, std::complex<double> csj[]) { + /* + * FROM CSPHJY OF LIBRARY specfun + * + * ========================================================== + * Purpose: Compute spherical Bessel functions j + * Input : z --- Complex argument of j + * n --- Order of j ( n = 0,1,2,... ) + * Output: csj(n+1) --- j + * nm --- Highest order computed + * Routines called: + * msta1 and msta2 for computing the starting + * point for backward recurrence + * ========================================================== + */ + double zz = z.real() * z.real() + z.imag() * z.imag(); + double a0 = sqrt(zz); + nm = n; + if (a0 < 1.0e-60) { + for (int k = 2; k <= n + 1; k++) { + csj[k - 1] = 0.0; + } + csj[0] = std::complex<double>(1.0, 0.0); + return; + } + csj[0] = std::sin(z) / z; + if (n == 0) { + return; + } + csj[1] = (csj[0] -std::cos(z)) / z; + if (n == 1) { + return; + } + std::complex<double> csa = csj[0]; + std::complex<double> csb = csj[1]; + int m = msta1(a0, 200); + if (m < n) nm = m; + else m = msta2(a0, n, 15); + std::complex<double> cf0 = 0.0; + std::complex<double> cf1 = 1.0e-100; + std::complex<double> cf, cs; + for (int k = m; k >= 0; k--) { + cf = (2.0 * k + 3.0) * cf1 / z - cf0; + if (k <= nm) csj[k] = cf; + cf0 = cf1; + cf1 = cf; + } + double abs_csa = sqrt(csa.real() * csa.real() + csa.imag() * csa.imag()); + double abs_csb = sqrt(csb.real() * csb.real() + csb.imag() * csb.imag()); + if (abs_csa > abs_csb) cs = csa / cf; + else cs = csb / cf0; + for (int k = 0; k <= nm; k++) { + csj[k] = cs * csj[k]; + } +} + +/*! \brief C++ porting of RBF + * + * This is the Real Bessel Function. + * + * \param n: `int` + * \param x: `double` + * \param nm: `int &` + * \param sj: `double[]` + */ +void rbf(int n, double x, int &nm, double sj[]) { + /* + * FROM SPHJ OF LIBRARY specfun + * + * ========================================================== + * Purpose: Compute spherical Bessel functions j + * Input : x --- Argument of j + * n --- Order of j ( n = 0,1,2,... ) + * Output: sj(n+1) --- j + * nm --- Highest order computed + * Routines called: + * msta1 and msta2 for computing the starting + * point for backward recurrence + * ========================================================== + */ + double a0 = x; + if (a0 < 0.0) a0 *= -1.0; + nm = n; + if (a0 < 1.0e-60) { + for (int k = 2; k <= n + 1; k++) + sj[k - 1] = 0.0; + sj[0] = 1.0; + return; + } + sj[0] = sin(x) / x; + if (n == 0) { + return; + } + sj[1] = (sj[0] - cos(x)) / x; + if (n == 1) { + return; + } + double sa = sj[0]; + double sb = sj[1]; + int m = msta1(a0, 200); + if (m < n) nm = m; + else m = msta2(a0, n, 15); + double f0 = 0.0; + double f1 = 1.0e-100; + double f; + for (int k = m; k >= 0; k--) { + f = (2.0 * k +3.0) * f1 / x - f0; + if (k <= nm) sj[k] = f; + f0 = f1; + f1 = f; + } + double cs; + double abs_sa = sa; + if (abs_sa < 0.0) abs_sa *= -1.0; + double abs_sb = sb; + if (abs_sb < 0.0) abs_sb *= -1.0; + if (abs_sa > abs_sb) cs = sa / f; + else cs = sb / f0; + for (int k = 0; k <= nm; k++) { + sj[k] = cs * sj[k]; + } +} + +/*! \brief C++ porting of RKC + * + * \param npntmo: `int` + * \param step: `double` + * \param dcc: `complex\<double\>` + * \param x: `double &` + * \param lpo: `int` + * \param y1: `complex\<double\> &` + * \param y2: `complex\<double\> &` + * \param dy1: `complex\<double\> &` + * \param dy2: `complex\<double\> &` + */ +void rkc( + int npntmo, double step, std::complex<double> dcc, double &x, int lpo, + std::complex<double> &y1, std::complex<double> &y2, std::complex<double> &dy1, + std::complex<double> &dy2 +) { + std::complex<double> cy1, cdy1, c11, cy23, yc2, c12, c13; + std::complex<double> cy4, yy, c14, c21, c22, c23, c24; + double half_step = 0.5 * step; + double cl = 1.0 * lpo * (lpo - 1); + for (int ipnt60 = 1; ipnt60 <= npntmo; ipnt60++) { + cy1 = cl / (x * x) - dcc; + cdy1 = -2.0 / x; + c11 = (cy1 * y1 + cdy1 * dy1) * step; + double xh = x + half_step; + cy23 = cl / (xh * xh) - dcc; + double cdy23 = -2.0 / xh; + yc2 = y1 + dy1 * half_step; + c12 = (cy23 * yc2 + cdy23 * (dy1 + 0.5 * c11)) * step; + c13 = (cy23 * (yc2 + 0.25 * c11 * step) + cdy23 * (dy1 + 0.5 * c12)) * step; + double xn = x + step; + cy4 = cl / (xn * xn) - dcc; + double cdy4 = -2.0 / xn; + yy = y1 + dy1 * step; + c14 = (cy4 * (yy + 0.5 * c12 * step) + cdy4 * (dy1 + c13)) * step; + y1 = yy + (c11 + c12 + c13) * step / 6.0; + dy1 += (0.5 * c11 + c12 + c13 + 0.5 * c14) / 3.0; + c21 = (cy1 * y2 + cdy1 * dy2) * step; + yc2 = y2 + dy2 * half_step; + c22 = (cy23 * yc2 + cdy23 * (dy2 + 0.5 * c21)) * step; + c23= (cy23 * (yc2 + 0.25 * c21 * step) + cdy23 * (dy2 + 0.5 * c22)) * step; + yy = y2 + dy2 * step; + c24 = (cy4 * (yc2 + 0.5 * c22 * step) + cdy4 * (dy2 + c23)) * step; + y2 = yy + (c21 + c22 + c23) * step / 6.0; + dy2 += (0.5 * c21 + c22 + c23 + 0.5 * c24) / 3.0; + x = xn; + } +} + +/*! \brief C++ porting of RKT + * + * \param npntmo: `int` + * \param step: `double` + * \param x: `double &` + * \param lpo: `int` + * \param y1: `complex\<double\> &` + * \param y2: `complex\<double\> &` + * \param dy1: `complex\<double\> &` + * \param dy2: `complex\<double\> &` + * \param c2: `C2 *` + */ +void rkt( + int npntmo, double step, double &x, int lpo, std::complex<double> &y1, + std::complex<double> &y2, std::complex<double> &dy1, std::complex<double> &dy2, + C2 *c2 +) { + std::complex<double> cy1, cdy1, c11, cy23, cdy23, yc2, c12, c13; + std::complex<double> cy4, cdy4, yy, c14, c21, c22, c23, c24; + double half_step = 0.5 * step; + double cl = 1.0 * lpo * (lpo - 1); + for (int ipnt60 = 1; ipnt60 <= npntmo; ipnt60++) { + int jpnt = ipnt60 + ipnt60 - 1; + cy1 = cl / (x * x) - c2->ris[jpnt - 1]; + cdy1 = -2.0 / x; + c11 = (cy1 * y1 + cdy1 * dy1) * step; + double xh = x + half_step; + int jpntpo = jpnt + 1; + cy23 = cl / (xh * xh) - c2->ris[jpntpo - 1]; + cdy23 = -2.0 / xh; + yc2 = y1 + dy1 * half_step; + c12 = (cy23 * yc2 + cdy23 * (dy1 + 0.5 * c11)) * step; + c13= (cy23 * (yc2 + 0.25 * c11 *step) + cdy23 * (dy1 + 0.5 * c12)) * step; + double xn = x + step; + int jpntpt = jpnt + 2; + cy4 = cl / (xn * xn) - c2->ris[jpntpt - 1]; + cdy4 = -2.0 / xn; + yy = y1 + dy1 * step; + c14 = (cy4 * (yy + 0.5 * c12 * step) + cdy4 * (dy1 + c13)) * step; + y1= yy + (c11 + c12 + c13) * step / 6.0; + dy1 += (0.5 * c11 + c12 + c13 + 0.5 *c14) /3.0; + cy1 -= cdy1 * c2->dlri[jpnt - 1]; + cdy1 += 2.0 * c2->dlri[jpnt - 1]; + c21 = (cy1 * y2 + cdy1 * dy2) * step; + cy23 -= cdy23 * c2->dlri[jpntpo - 1]; + cdy23 += 2.0 * c2->dlri[jpntpo - 1]; + yc2 = y2 + dy2 * half_step; + c22 = (cy23 * yc2 + cdy23 * (dy2 + 0.5 * c21)) * step; + c23 = (cy23 * (yc2 + 0.25 * c21 * step) + cdy23 * (dy2 + 0.5 * c22)) * step; + cy4 -= cdy4 * c2->dlri[jpntpt - 1]; + cdy4 += 2.0 * c2->dlri[jpntpt - 1]; + yy = y2 + dy2 * step; + c24 = (cy4 * (yc2 + 0.5 * c22 * step) + cdy4 * (dy2 + c23)) * step; + y2 = yy + (c21 + c22 + c23) * step / 6.0; + dy2 += (0.5 * c21 + c22 + c23 + 0.5 * c24) / 3.0; + x = xn; + } +} + +/*! \brief C++ porting of RNF + * + * This is a real spherical Bessel function. + * + * \param n: `int` + * \param x: `double` + * \param nm: `int &` + * \param sj: `double[]` + */ +void rnf(int n, double x, int &nm, double sy[]) { + /* + * FROM SPHJY OF LIBRARY specfun + * + * ========================================================== + * Purpose: Compute spherical Bessel functions y + * Input : x --- Argument of y ( x > 0 ) + * n --- Order of y ( n = 0,1,2,... ) + * Output: sy(n+1) --- y + * nm --- Highest order computed + * ========================================================== + */ + if (x < 1.0e-60) { + for (int k = 0; k <= n; k++) + sy[k] = -1.0e300; + return; + } + sy[0] = -1.0 * cos(x) / x; + if (n == 0) { + return; + } + sy[1] = (sy[0] - sin(x)) / x; + if (n == 1) { + return; + } + double f0 = sy[0]; + double f1 = sy[1]; + double f; + for (int k = 2; k <= n; k++) { + f = (2.0 * k - 1.0) * f1 / x - f0; + sy[k] = f; + double abs_f = f; + if (abs_f < 0.0) abs_f *= -1.0; + if (abs_f >= 1.0e300) { + nm = k; + break; + } + f0 = f1; + f1 = f; + nm = k; + } + return; +} + +/*! \brief C++ porting of SSCR0 + * + * \param tfsas: `complex<double> &` + * \param nsph: `int` + * \param lm: `int` + * \param vk: `double` + * \param exri: `double` + * \param c1: `C1 *` + */ +void sscr0(std::complex<double> &tfsas, int nsph, int lm, double vk, double exri, C1 *c1) { + std::complex<double> sum21, rm, re, cc0, csam; + cc0 = std::complex<double>(0.0, 0.0); + double exdc = exri * exri; + double ccs = 4.0 * acos(0.0) / (vk * vk); + double cccs = ccs / exdc; + csam = -(ccs / (exri * vk)) * std::complex<double>(0.0, 0.5); + tfsas = cc0; + for (int i12 = 1; i12 <= nsph; i12++) { + int iogi = c1->iog[i12 - 1]; + if (iogi >= i12) { + double sums = 0.0; + std::complex<double> sum21 = cc0; + for (int l10 = 1; l10 <= lm; l10++) { + double fl = 1.0 + l10 + l10; + rm = 1.0 / c1->rmi[l10 - 1][i12 - 1]; + re = 1.0 / c1->rei[l10 - 1][i12 - 1]; + std::complex<double> rm_cnjg = std::complex<double>(rm.real(), -rm.imag()); + std::complex<double> re_cnjg = std::complex<double>(re.real(), -re.imag()); + sums += (rm_cnjg * rm + re_cnjg * re).real() * fl; + sum21 += (rm + re) * fl; + } + sum21 *= -1.0; + double scasec = cccs * sums; + double extsec = -cccs * sum21.real(); + double abssec = extsec - scasec; + c1->sscs[i12 - 1] = scasec; + c1->sexs[i12 - 1] = extsec; + c1->sabs[i12 - 1] = abssec; + double gcss = c1-> gcsv[i12 - 1]; + c1->sqscs[i12 - 1] = scasec / gcss; + c1->sqexs[i12 - 1] = extsec / gcss; + c1->sqabs[i12 - 1] = abssec / gcss; + c1->fsas[i12 - 1] = sum21 * csam; + } + tfsas += c1->fsas[iogi - 1]; + } +} + +/*! \brief C++ porting of THDPS + * + * \param lm: `int` + * \param zpv: `double ****` + */ +void thdps(int lm, double ****zpv) { + // WARNING: unclear nested loop in THDPS + // The optimized interpretation was adopted here. + for (int l10 = 1; l10 <= lm; l10++) { + for (int ilmp = 1; ilmp <= 3; ilmp++) { + zpv[l10 - 1][ilmp - 1][0][0] = 0.0; + zpv[l10 - 1][ilmp - 1][0][1] = 0.0; + zpv[l10 - 1][ilmp - 1][1][0] = 0.0; + zpv[l10 - 1][ilmp - 1][1][1] = 0.0; + } + } + for (int l15 = 1; l15 <= lm; l15++) { + double xd = 1.0 * l15 * (l15 + 1); + double zp = -1.0 / sqrt(xd); + zpv[l15 - 1][1][0][1] = zp; + zpv[l15 - 1][1][1][0] = zp; + } + if (lm != 1) { + for (int l20 = 2; l20 <= lm; l20++) { + double xn = 1.0 * (l20 - 1) * (l20 + 1); + double xd = 1.0 * l20 * (l20 + l20 + 1); + double zp = sqrt(xn / xd); + zpv[l20 - 1][0][0][0] = zp; + zpv[l20 - 1][0][1][1] = zp; + } + int lmmo = lm - 1; + for (int l25 = 1; l25 <= lmmo; l25++) { + double xn = 1.0 * l25 * (l25 + 2); + double xd = (l25 + 1) * (l25 + l25 + 1); + double zp = -1.0 * sqrt(xn / xd); + zpv[l25 - 1][2][0][0] = zp; + zpv[l25 - 1][2][1][1] = zp; + } + } +} + +/*! \brief C++ porting of DME + * + * \param li: `int` + * \param i: `int` + * \param npnt: `int` + * \param npntts: `int` + * \param vk: `double` + * \param exdc: `double` + * \param exri: `double` + * \param c1: `C1 *` + * \param c2: `C2 *` + * \param jer: `int &` + * \param lcalc: `int &` + * \param arg: `complex<double> &`. + */ +void dme( + int li, int i, int npnt, int npntts, double vk, double exdc, double exri, + C1 *c1, C2 *c2, int &jer, int &lcalc, std::complex<double> &arg) { + //double rfj[42], rfn[42]; + double *rfj = new double[42]; + double *rfn = new double[42]; + std::complex<double> cfj[42], fbi[42], fb[42], fn[42]; + std::complex<double> rmf[40], drmf[40], ref[40], dref[40]; + std::complex<double> dfbi, dfb, dfn, ccna, ccnb, ccnc, ccnd; + std::complex<double> y1, dy1, y2, dy2, arin, cri, uim; + jer = 0; + uim = std::complex<double>(0.0, 1.0); + int nstp = npnt - 1; + int nstpts = npntts - 1; + int lipo = li + 1; + int lipt = li + 2; + double sz = vk * c1->ros[i - 1]; + c2->vsz[i - 1] = sz; + double vkr1 = vk * c1->rc[i - 1][0]; + int nsh = c1->nshl[i - 1]; + c2->vkt[i - 1] = std::sqrt(c2->dc0[0]); + arg = vkr1 * c2->vkt[i - 1]; + arin = arg; + bool goto32 = false; + if (arg.imag() != 0.0) { + cbf(lipo, arg, lcalc, cfj); + if (lcalc < lipo) { + jer = 5; + return; + } + for (int j24 = 1; j24 <= lipt; j24++) fbi[j24 - 1] = cfj[j24 - 1]; + goto32 = true; + } + if (!goto32) { + rbf(lipo, arg.real(), lcalc, rfj); + if (lcalc < lipo) { + jer = 5; + return; + } + for (int j30 = 1; j30 <= lipt; j30++) fbi[j30 - 1] = rfj[j30 - 1]; + } + double arex = sz * exri; + arg = arex; + rbf(lipo, arex, lcalc, rfj); + if (lcalc < lipo) { + jer = 7; + return; + } + rnf(lipo, arex, lcalc, rfn); + if (lcalc < lipo) { + jer = 8; + return; + } + for (int j43 = 1; j43 <= lipt; j43++) { + fb[j43 - 1] = rfj[j43 - 1]; + //printf("DEBUG: fb[%d] = (%lE,%lE)\n", j43, fb[j43 - 1].real(), fb[j43 - 1].imag()); + fn[j43 - 1] = rfn[j43 - 1]; + //printf("DEBUG: fn[%d] = (%lE,%lE)\n", j43, fn[j43 - 1].real(), fn[j43 - 1].imag()); + } + if (nsh <= 1) { + cri = c2->dc0[0] / exdc; + for (int l60 = 1; l60 <= li; l60++) { + int lpo = l60 + 1; + int ltpo = lpo + l60; + int lpt = lpo + 1; + dfbi = ((1.0 * l60) * fbi[l60 - 1] - (1.0 * lpo) * fbi[lpt - 1]) * arin + fbi[lpo - 1] * (1.0 * ltpo); + dfb = ((1.0 * l60) * fb[l60 - 1] - (1.0 * lpo) * fb[lpt - 1]) * arex + fb[lpo - 1] * (1.0 * ltpo); + dfn = ((1.0 * l60) * fn[l60 - 1] - (1.0 * lpo) * fn[lpt - 1]) * arex + fn[lpo - 1] * (1.0 * ltpo); + ccna = fbi[lpo - 1] * dfn; + ccnb = fn[lpo - 1] * dfbi; + ccnc = fbi[lpo - 1] * dfb; + ccnd = fb[lpo - 1] * dfbi; + c1->rmi[l60 - 1][i - 1] = 1.0 + uim * (ccna - ccnb) / (ccnc - ccnd); + c1->rei[l60 - 1][i - 1] = 1.0 + uim * (cri * ccna - ccnb) / (cri * ccnc - ccnd); + } + } else { // nsh > 1 + int ic = 1; + for (int l80 = 1; l80 <= li; l80++) { + int lpo = l80 + 1; + int ltpo = lpo + l80; + int lpt = lpo + 1; + int dltpo = ltpo; + y1 = fbi[lpo - 1]; + dy1 = ((1.0 * l80) * fbi[l80 - 1] - (1.0 * lpo) * fbi[lpt - 1]) * c2->vkt[i - 1] / (1.0 * dltpo); + y2 = y1; + dy2 = dy1; + ic = 1; + for (int ns76 = 2; ns76 <= nsh; ns76++) { + int nsmo = ns76 - 1; + double vkr = vk * c1->rc[i - 1][nsmo - 1]; + if (ns76 % 2 != 0) { + ic += 1; + double step = 1.0 * nstp; + step = vk * (c1->rc[i - 1][ns76 - 1] - c1->rc[i - 1][nsmo - 1]) / step; + arg = c2->dc0[ic - 1]; + rkc(nstp, step, arg, vkr, lpo, y1, y2, dy1, dy2); + } else { + diel(nstpts, nsmo, i, ic, vk, c1, c2); + double stepts = 1.0 * nstpts; + stepts = vk * (c1->rc[i - 1][ns76 - 1] - c1->rc[i - 1][nsmo - 1]) / stepts; + rkt(nstpts, stepts, vkr, lpo, y1, y2, dy1, dy2, c2); + } + } + rmf[l80 - 1] = y1 * sz; + drmf[l80 - 1] = dy1 * sz + y1; + ref[l80 - 1] = y2 * sz; + dref[l80 - 1] = dy2 * sz + y2; + } + cri = 1.0 + uim * 0.0; + if (nsh % 2 != 0) cri = c2->dc0[ic - 1] / exdc; + for (int l90 = 1; l90 <= li; l90++) { + int lpo = l90 + 1; + int ltpo = lpo + l90; + int lpt = lpo + 1; + dfb = ((1.0 * l90) * fb[l90 - 1] - (1.0 * lpo) * fb[lpt - 1]) * arex + fb[lpo - 1] * (1.0 * ltpo); + dfn = ((1.0 * l90) * fn[l90 - 1] - (1.0 * lpo) * fn[lpt - 1]) * arex + fn[lpo - 1] * (1.0 * ltpo); + ccna = rmf[l90 - 1] * dfn; + ccnb = drmf[l90 - 1] * fn[lpo - 1] * (1.0 * sz * ltpo); + ccnc = rmf[l90 - 1] * dfb; + ccnd = drmf[l90 - 1] * fb[lpo -1] * (1.0 * sz * ltpo); + c1->rmi[l90 - 1][i - 1] = 1.0 + uim *(ccna - ccnb) / (ccnc - ccnd); + //printf("DEBUG: gone 90, rmi[%d][%d] = (%lE,%lE)\n", l90, i, c1->rmi[l90 - 1][i - 1].real(), c1->rmi[l90 - 1][i - 1].imag()); + ccna = ref[l90 - 1] * dfn; + ccnb = dref[l90 - 1] * fn[lpo - 1] * (1.0 * sz * ltpo); + ccnc = ref[l90 - 1] * dfb; + ccnd = dref[l90 - 1] *fb[lpo - 1] * (1.0 * sz * ltpo); + c1->rei[l90 - 1][i - 1] = 1.0 + uim * (cri * ccna - ccnb) / (cri * ccnc - ccnd); + //printf("DEBUG: gone 90, rei[%d][%d] = (%lE,%lE)\n", l90, i, c1->rei[l90 - 1][i - 1].real(), c1->rei[l90 - 1][i - 1].imag()); + } + } // nsh <= 1 ? + return; +} + +#endif /* SRC_INCLUDE_SPH_SUBS_H_ */