diff --git a/src/cluster/cluster.cpp b/src/cluster/cluster.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e57added3ad108c00998cf37fa57770cba1a9d91 --- /dev/null +++ b/src/cluster/cluster.cpp @@ -0,0 +1,279 @@ +#include <cstdio> +#include <fstream> +#include <string> +#include <complex> +#ifndef INCLUDE_CONFIGURATION_H_ +#include "../include/Configuration.h" +#endif +#ifndef INCLUDE_CLU_SUBS_H_ +#include "../include/clu_subs.h" +#endif + +using namespace std; + +/* + * >>> WARNING: works only for IDFC >= 0, as the original code <<< + * + */ + +//! \brief C++ implementation of CLU +void cluster() { + printf("INFO: making legacy configuration ...\n"); + ScattererConfiguration *conf = ScattererConfiguration::from_dedfb("DEDFB_clu"); + conf->write_formatted("c_OEDFB_clu"); + conf->write_binary("c_TEDF_clu"); + delete conf; + printf("INFO: reading binary configuration ...\n"); + ScattererConfiguration *sconf = ScattererConfiguration::from_binary("c_TEDF_clu"); + GeometryConfiguration *gconf = GeometryConfiguration::from_legacy("DCLU"); + if (sconf->number_of_spheres == gconf->number_of_spheres) { + // Shortcuts to variables stored in configuration objects + int nsph = gconf->number_of_spheres; + int mxndm = gconf->mxndm; + int inpol = gconf->in_pol; + int npnt = gconf->npnt; + int npntts = gconf->npntts; + int iavm = gconf->iavm; + int isam = gconf->meridional_type; + int nxi = sconf->number_of_scales; + double th = gconf->in_theta_start; + double thstp = gconf->in_theta_step; + double thlst = gconf->in_theta_end; + double ths = gconf->sc_theta_start; + double thsstp = gconf->sc_theta_step; + double thslst = gconf->sc_theta_end; + double ph = gconf->in_phi_start; + double phstp = gconf->in_phi_step; + double phlst = gconf->in_phi_end; + double phs = gconf->sc_phi_start; + double phsstp = gconf->sc_phi_step; + double phslst = gconf->sc_phi_end; + double wp = sconf->wp; + // Global variables for CLU + double pi = 2.0 * acos(0.0); + int lm = gconf->l_max; + if (gconf->li > lm) lm = gconf->li; + if (gconf->le > lm) lm = gconf->le; + C1 *c1 = new C1(nsph, lm, sconf->nshl_vec, sconf->iog_vec); + C3 *c3 = new C3(); + for (int c1i = 0; c1i < nsph; c1i++) { + c1->rxx[c1i] = gconf->sph_x[c1i]; + c1->ryy[c1i] = gconf->sph_y[c1i]; + c1->rzz[c1i] = gconf->sph_z[c1i]; + c1->ros[c1i] = sconf->radii_of_spheres[c1i]; + int iogi = c1->iog[c1i]; + if (iogi >= c1i + 1) { + double gcss = pi * c1->ros[c1i] * c1->ros[c1i]; + c1->gcsv[c1i] = gcss; + int nsh = c1->nshl[c1i]; + for (int j16 = 1; j16 <= nsh; j16++) { + c1->rc[c1i][j16- 1] = sconf->rcf[c1i][j16] * c1->ros[c1i]; + } + c3->gcs += c1->gcsv[c1i - 1]; + } + } + C4 *c4 = new C4; + c4->li = gconf->li; + c4->le = gconf->le; + c4->lm = lm; + c4->lmpo = c4->lm + 1; + c4->litpo = 2 * gconf->li + 1; + c4->litpos = c4->litpo * c4->litpo; + c4->lmtpo = gconf->li + gconf->le + 1; + c4->lmtpos = c4->lmtpo * c4->lmtpo; + c4->nlim = c4->li * (c4->li + 2); + c4->nlem = c4->le * (c4->le + 2); + c4->nsph = nsph; + C6 *c6 = new C6(c4->lmtpo); + C1_AddOns *c1ao = new C1_AddOns(c4); + FILE *output = fopen("c_OCLU", "w"); + double ****zpv = new double***[c4->lm]; + for (int zi = 0; zi < c4->lm; zi++) { + zpv[zi] = new double**[3]; + for (int zj = 0; zj < 3; zj++) { + zpv[zi][zj] = new double*[2]; + zpv[zi][zj][0] = new double[2]; + zpv[zi][zj][1] = new double[2]; + } + } + int jer = 0, lcalc = 0; + complex<double> arg = complex<double>(0.0, 0.0); + int max_ici = 0; + for (int insh = 0; insh < nsph; insh++) { + int nsh = sconf->nshl_vec[insh]; + int ici = (nsh + 1) / 2; + if (ici > max_ici) max_ici = ici; + } + C2 *c2 = new C2(nsph, max_ici, npnt, npntts); + complex<double> **am = new complex<double>*[mxndm]; + for (int ai = 0; ai < mxndm; ai++) am[ai] = new complex<double>[mxndm]; + // End of global variables for CLU + fprintf(output, " READ(IR,*)NSPH,LI,LE,MXNDM,INPOL,NPNT,NPNTTS,IAVM,ISAM\n"); + fprintf(output, " %5d%5d%5d%5d%5d%5d%5d%5d%5d\n", + nsph, c4->li, c4->le, mxndm, inpol, npnt, npntts, iavm, isam + ); + fprintf(output, " READ(IR,*)RXX(I),RYY(I),RZZ(I)\n"); + for (int ri = 0; ri < nsph; ri++) fprintf(output, "%17.8lE%17.8lE%17.8lE\n", + gconf->sph_x[ri], gconf->sph_y[ri], gconf->sph_z[ri] + ); + fprintf(output, " READ(IR,*)TH,THSTP,THLST,THS,THSSTP,THSLST\n"); + fprintf( + output, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", + th, thstp, thlst, ths, thsstp, thslst + ); + fprintf(output, " READ(IR,*)PH,PHSTP,PHLST,PHS,PHSSTP,PHSLST\n"); + fprintf( + output, " %10.3lE%10.3lE%10.3lE%10.3lE%10.3lE%10.3lE\n", + ph, phstp, phlst, phs, phsstp, phslst + ); + fprintf(output, " READ(IR,*)JWTM\n"); + fprintf(output, " %5d\n", gconf->jwtm); + fprintf(output, " READ(ITIN)NSPHT\n"); + fprintf(output, " READ(ITIN)(IOG(I),I=1,NSPH)\n"); + fprintf(output, " READ(ITIN)EXDC,WP,XIP,IDFC,NXI\n"); + fprintf(output, " READ(ITIN)(XIV(I),I=1,NXI)\n"); + fprintf(output, " READ(ITIN)NSHL(I),ROS(I)\n"); + fprintf(output, " READ(ITIN)(RCF(I,NS),NS=1,NSH)\n"); + fprintf(output, " \n"); + double small = 1.0e-3; + int nth = 0, nph = 0; + if (thstp != 0.0) nth = int((thlst - th) / thstp + small); + nth++; + if (phstp != 0.0) nph = int((phlst - ph) / phstp + small); + nph++; + int nths = 0, nphs = 0; + double thsca = 0.0; + if (isam > 1) { + nths = 1; + thsca = ths - th; + } else { // ISAM <= 1 + if (thsstp == 0.0) nths = 0; + else nths = int ((thslst - ths) / thsstp + small); + nths++; + } + if (isam >= 1) { + nphs = 1; + } else { + if (phsstp == 0.0) nphs = 0; + else nphs = int((phslst - phs) / phsstp + small); + nphs++; + } + int nk = nth * nph; + int nks = nths * nphs; + int nkks = nk * nks; + double th1 = th, ph1 = ph, ths1 = ths, phs1 = phs; + str(c1, c1ao, c3, c4, c6); + thdps(c4->lm, zpv); + double exri = sqrt(sconf->exdc); + double vk = 0.0; // NOTE: Not really sure it should be initialized at 0 + fprintf(output, " REFR. INDEX OF EXTERNAL MEDIUM=%15.7lE\n", exri); + fstream tppoan; + tppoan.open("c_TPPOAN", ios::out | ios::binary); + if (tppoan.is_open()) { + tppoan.write(reinterpret_cast<char *>(&iavm), sizeof(int)); + tppoan.write(reinterpret_cast<char *>(&isam), sizeof(int)); + tppoan.write(reinterpret_cast<char *>(&inpol), sizeof(int)); + tppoan.write(reinterpret_cast<char *>(&nxi), sizeof(int)); + tppoan.write(reinterpret_cast<char *>(&nth), sizeof(int)); + tppoan.write(reinterpret_cast<char *>(&nph), sizeof(int)); + tppoan.write(reinterpret_cast<char *>(&nths), sizeof(int)); + tppoan.write(reinterpret_cast<char *>(&nphs), sizeof(int)); + int nlemt = c4->nlem + c4->nlem; + double wn = wp / 3.0e8; + double sqsfi = 1.0; + if (sconf->idfc < 0) { + vk = sconf->xip * wn; + fprintf(output, " VK=%15.7lE, XI IS SCALE FACTOR FOR LENGTHS\n", vk); + fprintf(output, " \n"); + } + for (int jxi488 = 1; jxi488 <= nxi; jxi488++) { + int jaw = 1; + fprintf(output, "========== JXI =%3d ====================\n", jxi488); + double xi = sconf->scale_vec[jxi488 - 1]; + double vkarg = 0.0; + if (sconf->idfc >= 0) { + vk = xi * wn; + vkarg = vk; + fprintf(output, " VK=%15.7lE, XI=%15.7lE\n", vk, xi); + } else { + vkarg = xi * vk; + sqsfi = 1.0 / (xi * xi); + fprintf(output, " XI=%15.7lE\n", xi); + } + // Would call HJV(EXRI, VKARG, JER, LCALC, ARG) + hjv(exri, vkarg, jer, lcalc, arg, c1, c1ao, c4); + //printf("INFO: calculation went up to %d and jer = %d\n", lcalc, jer); + //printf("INFO: arg = (%lE,%lE)\n", arg.real(), arg.imag()); + if (jer != 0) { + fprintf(output, " STOP IN HJV\n"); + break; // jxi488 loop: goes to memory cleaning and return + } + for (int i132 = 1; i132 <= nsph; i132++) { + int iogi = c1->iog[i132 - 1]; + if (iogi != i132) { + for (int l123 = 1; l123 <= gconf->li; l123++) { + c1->rmi[l123 - 1][i132 - 1] = c1->rmi[l123 - 1][iogi - 1]; + c1->rei[l123 - 1][i132 - 1] = c1->rei[l123 - 1][iogi - 1]; + } // l123 loop + } else { + int nsh = sconf->nshl_vec[i132 - 1]; + int ici = (nsh + 1) / 2; + int size_dc0 = (nsh % 2 == 0) ? ici + 1 : ici; + if (sconf->idfc == 0) { + for (int ic = 0; ic < ici; ic++) + c2->dc0[ic] = sconf->dc0_matrix[ic][i132 - 1][jxi488 - 1]; + } else { + if (jxi488 == 1) { + for (int ic = 0; ic < ici; ic++) + c2->dc0[ic] = sconf->dc0_matrix[ic][i132 - 1][0]; + } + } + if (nsh % 2 == 0) c2->dc0[ici] = sconf->exdc; + dme( + c4->li, i132, npnt, npntts, vkarg, sconf->exdc, exri, + c1, c2, jer, lcalc, arg + ); + //printf("INFO: DME returned jer = %d , lcalc = %d and arg = (%lE, %lE)\n", + // jer, lcalc, arg.real(), arg.imag()); + if (jer != 0) { + fprintf(output, " STOP IN DME\n"); + break; + } + } + if (jer != 0) break; + } // i132 loop + // Would call CMS(AM) + + if (jer != 0) break; + } // jxi488 loop + tppoan.close(); + } else { // In case TPPOAN could not be opened. Should never happen. + printf("ERROR: failed to open TPPOAN file.\n"); + } + fclose(output); + // Clean memory + delete c1; + delete c1ao; + delete c3; + delete c4; + delete c6; + for (int zi = c4->lm - 1; zi > -1; zi--) { + for (int zj = 2; zj > -1; zj--) { + delete[] zpv[zi][zj][1]; + delete[] zpv[zi][zj][0]; + delete[] zpv[zi][zj]; + } + delete[] zpv[zi]; + } + delete[] zpv; + for (int ai = mxndm - 1; ai > -1; ai--) delete[] am[ai]; + delete[] am; + } else { // NSPH mismatch between geometry and scatterer configurations. + throw UnrecognizedConfigurationException( + "Inconsistent geometry and scatterer configurations." + ); + } + delete sconf; + delete gconf; + printf("Done.\n"); +} diff --git a/src/include/clu_subs.h b/src/include/clu_subs.h new file mode 100644 index 0000000000000000000000000000000000000000..52568582d0184916ddc56603b05b538fff51f3b6 --- /dev/null +++ b/src/include/clu_subs.h @@ -0,0 +1,740 @@ +/*! \file clu_subs.h + * + * \brief C++ porting of CLU functions and subroutines. + * + * 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 INCLUDE_COMMONS_H_ +#include "Commons.h" +#endif + +#ifndef INCLUDE_CLU_SUBS_H_ +#define INCLUDE_CLU_SUBS_H_ + +#include <complex> + +// >>> DECLARATION OF SPH_SUBS <<< +extern std::complex<double> dconjg(std::complex<double> value); +extern 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 +); +extern void sphar(double cth, double sth, double cph, double sph, int lm, std::complex<double> *ylm); +extern void rbf(int n, double x, int &nm, double sj[]); +extern void rnf(int n, double x, int &nm, double sy[]); +extern void thdps(int lm, double ****zpv); +// >>> END OF SPH_SUBS DECLARATION <<< + +/*! \brief C++ porting of CGEV + * + * \param ipamo: `int` + * \param mu: `int` + * \param l: `int` + * \param m: `int` + */ +double cgev(int ipamo, int mu, int l, int m) { + double result = 0.0; + double xd = 0.0, xn = 0.0; + if (ipamo == 0) { + if (m != 0 || mu != 0) { // label 10 + if (mu != 0) { + xd = 2.0 * l * (l + 1); + if (mu <= 0) { + xn = 1.0 * (l + m) * (l - m + 1); + result = sqrt(xn / xd); + } else { // label 15 + xn = 1.0 * (l - m) * (l + m + 1); + result = -sqrt(xn / xd); + } + } else { // label 20 + xd = 1.0 * (l + 1) * l; + xn = -1.0 * m; + result = xn / sqrt(xd); + } + } + } else { // label 30 + xd = 2.0 * l * (l * 2 - 1); + if (mu < 0) { // label 35. CHECK: is clu.f code line 2466 a switch? + xn = 1.0 * (l - 1 + m) * (l + m); + } else if (mu == 0) { // label 40 + xn = 2.0 * (l - m) * (l + m); + } else { // mu > 0, label 45 + xn = 1.0 * (l - 1 - m) * (l - m); + } + result = sqrt(xn / xd); + } + return result; +} + +/*! \brief C++ porting of R3JJR + * + * \param j2: `int` + * \param j3: `int` + * \param m2: `int` + * \param m3: `int` + * \param c6: `C6 *` + */ +void r3jjr(int j2, int j3, int m2, int m3, C6 *c6) { + +} + + +/*! \brief C++ porting of GHIT + * + * \param ihi: `int` + * \param ipamo: `int` + * \param nbl: `int` + * \param l1: `int` + * \param m1: `int` + * \param l2: `int` + * \param m2: `int` + * \param c1: `C1 *` + * \param c1ao: `C1_AddOns *` + * \param c4: `C4 *` + * \param c6: `C6 *` + */ +std::complex<double> ghit( + int ihi, int ipamo, int nbl, int l1, int m1, int l2, int m2, C1 *c1, + C1_AddOns *c1ao, C4 *c4, C6 *c6 +) { + /* NBL identifies transfer vector going from N2 to N1; + * IHI=0 for Hankel, IHI=1 for Bessel, IHI=2 for Bessel from origin; + * depending on IHI, IPAM=0 gives H or I, IPAM= 1 gives K or L. */ + const std::complex<double> cc0 = std::complex<double>(0.0, 0.0); + const std::complex<double> uim = std::complex<double>(0.0, 1.0); + std::complex<double> result = cc0; + if (ihi == 2) { + if (!(c1->rxx[nbl - 1] != 0.0 || c1->ryy[nbl - 1] != 0.0 || c1->rzz[nbl - 1] != 0.0)) { + if (ipamo != 0) return result; + if (l1 == l2 && m1 == m2) result = std::complex<double>(1.0, 0.0); + return result; + } + } + int l1mp = l1 - ipamo; + int l1po = l1 + 1; + int m1mm2 = m1 - m2; + int m1mm2m = (m1mm2 > 0) ? m1mm2 + 1 : -m1mm2 + 1; + int lminpo = (l2 - l1mp > 0) ? l2 - l1mp + 1 : l1mp - l2 + 1; + int lmaxpo = l2 + l1mp + 1; + int i3j0in = c1ao->ind3j[l1mp][l2 - 1]; + int ilin = -1; + if (m1mm2m > lminpo && (m1mm2m - lminpo) % 2 != 0) ilin = 0; + int isn = 1; + if (m1 % 2 != 0) isn *= -1; + if (lminpo % 2 == 0) { + isn *= -1; + if (l2 > l1mp) isn *= -1; + } + int nblmo = nbl - 1; + if (ihi != 2) { + int nbhj = nblmo * c4->litpo; + int nby = nblmo * c4->litpos; + if (ihi != 1) { + for (int jm24 = 1; jm24 <= 3; jm24++) { + std::complex<double> csum = cc0; + int mu = jm24 - 2; + int mupm1 = mu + m1; + int mupm2 = mu + m2; + if (mupm1 < -l1mp || mupm1 > l1mp || mupm2 < -l2 || mupm2 > l2) + continue; //jm24 loop + int jsn = -isn; + if (mu == 0) jsn = isn; + double cr = cgev(ipamo, mu, l1, m1) * cgev(0, mu, l2, m2); + int i3j0 = i3j0in; + if (mupm1 == 0 && mupm2 == 0) { + int lt14 = lminpo; + while (lt14 <= lmaxpo) { + i3j0 += 1; + int l3 = lt14 - 1; + int ny = l3 * l3 + lt14; + double aors = 1.0 * (l3 + lt14); + double f3j = ( + c1ao->v3j0[i3j0 - 1] * c1ao->v3j0[i3j0 - 1] * + sqrt(aors) + ) * jsn; + std::complex<double> cfun = ( + c1ao->vh[nbhj + lt14 - 1] * c1ao->vyhj[nby + ny - 1] + ) * f3j; + csum += cfun; + jsn *= - 1; + lt14 += 2; + } + } else { // label 16 + // Would call R3JJR(L1MP, L2, -MUPM1, MUPM2) + int il = ilin; + int lt20 = lminpo; + while (lt20 <= lmaxpo) { + i3j0 += 1; + if (m1mm2m <= lt20) { + il = il + 2; + int l3 = lt20 - 1; + int ny = l3 * l3 + lt20 + m1mm2; + double aors = 1.0 * (l3 + lt20); + double f3j = ( + c6->rac3j[il - 1] * c1ao->v3j0[i3j0 - 1] * sqrt(aors) + ) * jsn; + std::complex<double> cfun = ( + c1ao->vh[nbhj + lt20 - 1] * c1ao->vyhj[nby + ny - 1] + ) * f3j; + csum += cfun; + } + jsn *= -1; + lt20 += 2; + } + } + csum *= cr; + result += csum; + } // jm24 loop + } else { // label 30, IHI = 1 + for (int jm44 = 1; jm44 <= 3; jm44 ++) { + std::complex<double> csum = cc0; + int mu = jm44 - 2; + int mupm1 = mu + m1; + int mupm2 = mu + m2; + if (mupm1 >= -l1mp && mupm1 <= l1mp && mupm2 >= -l2 && mupm2 >= l2) { + int jsn = -isn; + if (mu == 0) jsn = isn; + double cr = cgev(ipamo, mu, l1, m1) * cgev(0, mu, l2, m2); + int i3j0 = i3j0in; + if (mupm1 == 0 && mupm2 == 0) { + int lt34 = lminpo; + while (lt34 <= lmaxpo) { + i3j0++; + int l3 = lt34 - 1; + int ny = l3 * l3 + lt34; + double aors = 1.0 * (l3 + lt34); + std::complex<double> f3j = ( + c1ao->v3j0[i3j0 - 1] * c1ao->v3j0[i3j0 - 1] * sqrt(aors) + ) * jsn; + std::complex<double> cfun = ( + c1ao->vj[nbhj + lt34 - 1] * c1ao->vyhj[nby + ny - 1] + ) * f3j; + csum += cfun; + jsn *= -1; + lt34 += 2; + } + } else { // label 36 + // Would call R3JJR + int il = ilin; + int lt40 = lminpo; + while (lt40 <= lmaxpo) { + i3j0++; + if (m1mm2m <= lt40) { + il += 2; + int l3 = lt40 - 1; + int ny = l3 * l3 + lt40 + m1mm2; + double aors = 1.0 * (l3 + lt40); + std::complex<double> f3j = ( + c6->rac3j[il - 1] * c1ao->v3j0[i3j0 - 1] * sqrt(aors) + ) * jsn; + std::complex<double> cfun = ( + c1ao->vj[nbhj + lt40 - 1] * c1ao->vyhj[nby + ny - 1] + ) * f3j; + csum += cfun; + } + jsn *= -1; + lt40 += 2; + } + } + // label 42 + csum *= cr; + } + result += csum; + } // jm44 loop + } + } else { // label 50, IHI = 2 + int nbhj = nblmo * c4->lmtpo; + int nby = nblmo * c4->lmtpos; + for (int jm64 =1; jm64 <= 3; jm64++) { + std::complex<double> csum = cc0; + int mu = jm64 - 2; + int mupm1 = mu + m1; + int mupm2 = mu + m2; + if (mupm1 >= -l1mp && mupm1 < l1mp && mupm2 >= -l2 && mupm2 <= l2) { + int jsn = - isn; + if (mu == 0) jsn = isn; + double cr = cgev(ipamo, mu, l1, m1) * cgev(0, mu, l2, m2); + int i3j0 = i3j0in; + if (mupm1 == 0 && mupm2 == 0) { + int lt54 = lminpo; + while (lt54 <= lmaxpo) { + i3j0++; + int l3 = lt54 - 1; + int ny = l3 * l3 + lt54; + double aors = 1.0 * (l3 + lt54); + std::complex<double> f3j = ( + c1ao->v3j0[i3j0 - 1] * c1ao->v3j0[i3j0 - 1] * sqrt(aors) + ) * jsn; + std::complex<double> cfun = ( + c1ao->vj0[nbhj + lt54 - 1] * c1ao->vyj0[nby + ny - 1] + ) * f3j; + csum += cfun; + jsn *= -1; + lt54 += 2; + } + } else { // label 56 + // Would call R3JJR(L1MP, L2, -MUPM1, MUPM2) + int il = ilin; + int lt60 = lminpo; + while (lt60 <= lmaxpo) { + i3j0++; + if (m1mm2m <= lt60) { + il += 2; + int l3 = lt60 - 1; + int ny = l3 * l3 + lt60 + m1mm2; + double aors = 1.0 * (l3 + lt60); + std::complex<double> f3j = ( + c6->rac3j[il - 1] * c1ao->v3j0[i3j0 - 1] * sqrt(aors) + ) * jsn; + std::complex<double> cfun = ( + c1ao->vj0[nbhj + lt60 - 1] * c1ao->vyj0[nby + ny - 1] + ) * f3j; + csum += cfun; + } + jsn *= -1; + lt60 += 2; + } + } + // label 62 + csum *= cr; + } + result += csum; + } // jm64 loop + } + // label 70 + const double four_pi = acos(0.0) * 8.0; + if (ipamo != 1) { + double cr = sqrt(four_pi * (l1 + l1po) * (l2 + l2 + 1)); + result *= cr; + } else { + double cr = sqrt(four_pi * (l1 + l1mp) * (l1 + l1po) * (l2 + l2 + 1) / l1po); + result *= (cr * uim); + } + return result; +} + +/*! \brief C++ porting of CMS + * + * \param am: Matrix of complex. + * \param c1: `C1 *` + * \param c1ao: `C1_AddOns *` + * \param c4: `C4 *` + * \param c6: `C6 *` + */ +void cms(std::complex<double> **am, C1 *c1, C1_AddOns *c1ao, C4 *c4, C6 *c6) { + std::complex<double> dm, de, cgh, cgk; + const std::complex<double> cc0 = std::complex<double>(0.0, 0.0); + int ndi = c4->nsph * c4->nlim; + int nbl = 0; + int nsphmo = c4->nsph - 1; + for (int n1 = 1; n1 <= nsphmo; n1++) { // GPU portable? + int in1 = (n1 - 1) * c4->nlim; + int n1po = n1 + 1; + for (int n2 = n1po; n2 <= c4->nsph; n2++) { + int in2 = (n2 - 1) * c4->nlim; + nbl++; + for (int l1 = 1; l1 <= c4->li; l1++) { + int l1po = l1 + 1; + int il1 = l1po * l1; + int l1tpo = l1po + l1; + for (int im1 =1; im1 <= l1tpo; il1++) { + int m1 = im1 - l1po; + int ilm1 = il1 + m1; + int ilm1e = ilm1 + ndi; + int i1 = in1 + ilm1; + int i1e = in1 + ilm1e; + int j1 = in2 + ilm1; + int j1e = in2 + ilm1e; + for (int l2 =1; l2 <= c4->li; l2++) { + int l2po = l2 + 1; + int il2 = l2po * l2; + int l2tpo = l2po + l2; + int ish = ((l2 + l1) % 2 == 0) ? 1 : -1; + int isk = -ish; + for (int im2 = 1; im2 <= l2tpo; im2++) { + int m2 = im2 - l2po; + int ilm2 = il2 + m2; + int ilm2e = ilm2 + ndi; + int i2 = in2 + ilm2; + int i2e = in2 + ilm2e; + int j2 = in1 + ilm2; + int j2e = in1 + ilm2e; + cgh = ghit(0, 0, nbl, l1, m1, l2, m2, c1, c1ao, c4, c6); + cgk = ghit(0, 1, nbl, l1, m1, l2, m2, c1, c1ao, c4, c6); + am[i1 - 1][i2 - 1] = cgh; + am[i1 - 1][i2e - 1] = cgk; + am[i1e - 1][i2 - 1] = cgk; + am[i1e - 1][i2e - 1] = cgh; + am[j1 - 1][j2 - 1] = cgh * (1.0 * ish); + am[j1 - 1][j2e - 1] = cgk * (1.0 * isk); + am[j1e - 1][j2 - 1] = cgk * (1.0 * isk); + am[j1e - 1][j2e - 1] = cgh * (1.0 * ish); + } + } + } // im1 loop + } // l1 loop + } // n2 loop + } // n1 loop + for (int n1 = 1; n1 <= c4->nsph; n1++) { // GPU portable? + int in1 = (n1 - 1) * c4->nlim; + for (int l1 = 1; l1 <= c4->li; l1++) { + dm = c1->rmi[l1 - 1][n1 - 1]; + de = c1->rei[l1 - 1][n1 - 1]; + int l1po = l1 + 1; + int il1 = l1po * l1; + int l1tpo = l1po + l1; + for (int im1 = 1; im1 <= l1tpo; im1++) { + int m1 = im1 - l1po; + int ilm1 = il1 + m1; + int i1 = in1 + ilm1; + int i1e = i1 + ndi; + for (int ilm2 = 1; ilm2 <= c4->nlim; ilm2++) { + int i2 = in1 + ilm2; + int i2e = i2 + ndi; + am[i1 - 1][i2 - 1] = cc0; + am[i1 - 1][i2e - 1] = cc0; + am[i1e - 1][i2 - 1] = cc0; + am[i1e - 1][i2e - 1] = cc0; + } + am[i1 - 1][i1 - 1] = dm; + am[i1e - 1][i1e - 1] = de; + } // im1 loop + } // l1 loop + } // n1 loop +} + +/*! \brief C++ porting of HJV + * + * \param exri: `double` + * \param vk: `double` + * \param jer: `int &` + * \param lcalc: `int &` + * \param arg: `complex\<double\> &` + * \param c1: `C1 *` + * \param c1ao: `C1_AddOns *` + * \param c4: `C4 *` + */ +void hjv( + double exri, double vk, int &jer, int &lcalc, std::complex<double> &arg, + C1 *c1, C1_AddOns *c1ao, C4 *c4 +) { + int nsphmo = c4->nsph - 1; + int lit = c4->li + c4->li; + int lmt = c4->lm + c4->lm; + const int rfj_size = (lit > lmt) ? lit : lmt; + const int rfn_size = c4->litpo; + double *rfj, *rfn; + rfj = new double[rfj_size]; + rfn = new double[rfn_size]; + jer = 0; + int ivhb = 0; + for (int nf40 = 1; nf40 <= nsphmo; nf40++) { // GPU portable? + int nfpo = nf40 + 1; + for (int ns40 = nfpo; ns40 <= c4->nsph; ns40++) { + double rx = c1->rxx[nf40 - 1] - c1->rxx[ns40 - 1]; + double ry = c1->ryy[nf40 - 1] - c1->ryy[ns40 - 1]; + double rz = c1->rzz[nf40 - 1] - c1->rzz[ns40 - 1]; + double rr = sqrt(rx * rx + ry * ry + rz * rz); + double rarg = rr * vk * exri; + arg = std::complex<double>(rarg, 0.0); + rbf(lit, rarg, lcalc, rfj); + if (lcalc < lit) { + jer = 1; + delete[] rfj; + delete[] rfn; + return; + } + rnf(lit, rarg, lcalc, rfn); + if (lcalc < lit) { + jer = 2; + delete[] rfj; + delete[] rfn; + return; + } + for (int lpo38 = 1; lpo38 <= c4->litpo; lpo38++) { + c1ao->vh[lpo38 + ivhb - 1] = std::complex<double>(rfj[lpo38 - 1], rfn[lpo38 - 1]); + } + ivhb += c4->litpo; + } // ns40 loop + } // nf40 loop + ivhb = 0; + for (int nf50 = 1; nf50 <= c4->nsph; nf50++) { + double rx = c1->rxx[nf50 - 1]; + double ry = c1->ryy[nf50 - 1]; + double rz = c1->rzz[nf50 - 1]; + if (!(rx == 0.0 && ry == 0.0 && rz == 0.0)) { + double rr = sqrt(rx * rx + ry * ry + rz * rz); + double rarg = rr * vk * exri; + rbf(lmt, rarg, lcalc, rfj); + if (lcalc < lmt) { + jer = 3; + delete[] rfj; + delete[] rfn; + return; + } + for (int lpo47 = 1; lpo47 <= c4->lmtpo; lpo47++) { + c1ao->vj0[lpo47 + ivhb - 1] = rfj[lpo47 - 1]; + } + } + ivhb += c4->lmtpo; + } // nf50 loop + delete[] rfj; + delete[] rfn; +} + +/*! \brief C++ porting of POLAR + * + * \param x: `double` + * \param y: `double` + * \param z: `double` + * \param r: `double &` + * \param cth: `double &` + * \param sth: `double &` + * \param cph: `double &` + * \param sph: `double &` + */ +void polar( + double x, double y, double z, double &r, double &cth, double &sth, + double &cph, double &sph +) { + bool onx = (y == 0.0); + bool ony = (x == 0.0); + bool onz = (onx && ony); + double rho; + if (!(onz || onx || ony)) { + rho = sqrt(x * x + y * y); + cph = x / rho; + sph = y / rho; + } else { + if (onz) { + cph = 1.0; + sph = 0.0; + } else if (onx) { + rho = x; + cph = 1.0; + if (x < 0.0) { + rho *= -1.0; + cph *= -1.0; + } + sph = 0.0; + } else if (ony) { + rho = y; + sph = 1.0; + if (y < 0.0) { + rho *= -1.0; + sph *= -1.0; + } + cph = 0.0; + } + } + if (z == 0.0) { + if (!onz) { + r = rho; + cth = 0.0; + sth = 1.0; + return; + } else { + r = 0.0; + cth = 1.0; + sth = 0.0; + return; + } + } else { + if (!onz) { + r = sqrt(rho + z * z); + cth = z / r; + sth = rho / r; + } else { + r = z; + cth = 1.0; + sth = 0.0; + if (z < 0.0) { + r *= -1.0; + cth *= -1.0; + } + } + } +} + +/*! \brief C++ porting of R3J000 + * + * \param j2: `int` + * \param j3: `int` + * \param c6: `C6 *` Pointer to a C6 instance. + */ +void r3j000(int j2, int j3, C6 *c6) { + int jmx = j3 + j2; + if (jmx <= 0) { + c6->rac3j[0] = 1.0; + //printf("DEBUG: RAC3J(1) = %lE\n", c6->rac3j[0]); + return; + } + int jmn = j3 - j2; + if (jmn < 0) jmn *= -1; + int njmo = (jmx - jmn) / 2; + int jf = jmx + jmx + 1; + int isn = 1; + if (jmn % 2 != 0) isn = -1; + if (njmo <= 0) { + double sj = 1.0 * jf; + double cnr = (1 / sqrt(sj)) * isn; + c6->rac3j[0] = cnr; + //printf("DEBUG: RAC3J(1) = %lE\n", c6->rac3j[0]); + return; + } + double sjr = jf; + int jmxpos = (jmx + 1) * (jmx + 1); + int jmns = jmn * jmn; + int j1mo = jmx - 1; + int j1s = jmx * jmx; // a slight optimization was applied here + double cj = sqrt(1.0 * (jmxpos - j1s) * (j1s - jmns)); + int j1mos = j1mo * j1mo; + double cjmo = sqrt(1.0 * (jmxpos - j1mos) * (j1mos - jmns)); + if (njmo <= 1) { + c6->rac3j[0] = -cj / cjmo; + double sj = sjr + (c6->rac3j[0] * c6->rac3j[0]) * (jf - 4); + double cnr = (1.0 / sqrt(sj)) * isn; + c6->rac3j[1] = cnr; + c6->rac3j[0] *= cnr; + //printf("DEBUG: RAC3J(1) = %lE\n", c6->rac3j[0]); + //printf("DEBUG: RAC3J(2) = %lE\n", c6->rac3j[1]); + return; + } + int nj = njmo + 1; + int nmat = (nj + 1) / 2; + c6->rac3j[nj - 1] = 1.0; + c6->rac3j[njmo - 1] = -cj / cjmo; + if (nmat != njmo) { + int nbr = njmo - nmat; + for (int ibr45 = 1; ibr45 <= nbr; ibr45++) { + int irr = nj - ibr45; + jf = jf -4; + j1mo = j1mo - 2; + j1s = (j1mo + 1) * (j1mo + 1); + cj = sqrt(1.0 * (jmxpos - j1s) * (j1s - jmns)); + j1mos = j1mo * j1mo; + cjmo = sqrt(1.0 * (jmxpos - j1mos) * (j1s - jmns)); + c6->rac3j[irr - 2] = c6->rac3j[irr - 1] * (-cj / cjmo); + sjr = sjr + (c6->rac3j[irr - 1] * c6->rac3j[irr - 1]) * jf; + } + } + double racmat = c6->rac3j[nmat - 1]; + sjr = sjr + (racmat * racmat) * (jf - 4); + c6->rac3j[0] = 1.0; + jf = jmn + jmn + 1; + double sjl = 1.0 * jf; + int j1pt = jmn + 2; + int j1pos = (j1pt - 1) * (j1pt - 1); + double cjpo = sqrt(1.0 * (jmxpos - j1pos) * (j1pos - jmns)); + int j1pts = j1pt * j1pt; + double cjpt = sqrt(1.0 * (jmxpos - j1pts) * (j1pts - jmns)); + c6->rac3j[1] = -cjpo / cjpt; + int nmatmo = nmat - 1; + if (nmatmo >= 2) { + for (int irl70 = 2; irl70 <= nmatmo; irl70++) { + jf = jf + 4; + j1pt = j1pt + 2; + j1pos = (j1pt - 1) * (j1pt - 1); + cjpo = sqrt(1.0 * (jmxpos - j1pos) * (j1pos - jmns)); + j1pts = j1pt * j1pt; + cjpt = sqrt(1.0 * (jmxpos - j1pts) * (j1pts - jmns)); + c6->rac3j[irl70] = c6->rac3j[irl70 - 1] * (-cjpo / cjpt); + sjl = sjl + (c6->rac3j[irl70 - 1] * c6->rac3j[irl70 - 1]) * jf; + } + } + double ratrac = racmat / c6->rac3j[nmat - 1]; + double rats = ratrac * ratrac; + double sj = sjr + sjl * rats; + c6->rac3j[nmat - 1] = racmat; + double cnr = (1.0 / sqrt(sj)) * isn; + for (int irr80 = nmat; irr80 <= nj; irr80++) { + c6->rac3j[irr80 - 1] *= cnr; + } + double cnl = cnr * ratrac; + for (int irl85 = 1; irl85 <= nmatmo; irl85++) { + c6->rac3j[irl85 - 1] *= cnl; + } +} + +/*! \brief C++ porting of STR + * + * \param c1: `C1 *` Pointer to a C1 instance. + * \param c1ao: `C1_AddOns *` Pointer to a C1_AddOns instance. + * \param c3: `C3 *` Pointer to a C3 instance. + * \param c4: `C4 *` Pointer to a C4 structure. + * \param c6: `C6 *` Pointer to a C6 instance. + */ +void str(C1 *c1, C1_AddOns *c1ao, C3 *c3, C4 *c4, C6 *c6) { + std::complex<double> *ylm; + c3 = new C3(); // this makes up for GCS = 0.0D0 + int i = 0; + for (int l1po = 1; l1po <= c4->lmpo; l1po++) { + int l1 = l1po - 1; + for (int l2 = 1; l2 <= c4->lm; l2++) { + r3j000(l1, l2, c6); + c1ao->ind3j[l1po - 1][l2 - 1] = i; + int iabs = l2 - l1; + if (iabs < 0) iabs *= -1; + int lmnpo = iabs + 1; + int lmxpo = l2 + l1 + 1; + int il = 0; + int lpo = lmnpo; + while (lpo <= lmxpo) { + i++; + il++; + c1ao->v3j0[i - 1] = c6->rac3j[il - 1]; + lpo += 2; + } + } + } // l1po loop + int nsphmo = c4->nsph - 1; + int lit = c4->li + c4-> li; + int lmt = c4->li + c4->le; + int size40 = nsphmo * c4->nsph * c4->litpos; + int size50 = c4->nsph * c4->lmtpos; + int ylm_size = (size40 > size50) ? size40 : size50; + ylm = new std::complex<double>[ylm_size]; + int ivy = 0; + for (int nf40 = 1; nf40 <= nsphmo; nf40++) { + int nfpo = nf40 + 1; + for (int ns40 = nfpo; ns40 <= c4->nsph; ns40++) { + double rx = c1->rxx[nf40 - 1] - c1->rxx[ns40 - 1]; + double ry = c1->ryy[nf40 - 1] - c1->ryy[ns40 - 1]; + double rz = c1->rzz[nf40 - 1] - c1->rzz[ns40 - 1]; + double rr, crth, srth, crph, srph; + polar(rx, ry, rz, rr, crth, srth, crph, srph); + //printf("DEBUG: crth = %lE\n", crth); + //printf("DEBUG: srth = %lE\n", srth); + //printf("DEBUG: crph = %lE\n", crph); + //printf("DEBUG: srph = %lE\n", srph); + sphar(crth, srth, crph, srph, lit, ylm); + for (int iv38 = 1; iv38 <= c4->litpos; iv38++) { + c1ao->vyhj[iv38 + ivy - 1] = dconjg(ylm[iv38 - 1]); + } // iv38 loop + ivy += c4->litpos; + } // ns40 loop + } // nf40 loop + ivy = 0; + for (int nf50 = 1; nf50 <= c4->nsph; nf50++) { + double rx = c1->rxx[nf50 - 1]; + double ry = c1->ryy[nf50 - 1]; + double rz = c1->rzz[nf50 - 1]; + double rr, crth, srth, crph, srph; + if (rx == 0.0 && ry == 0.0 && rz == 0.0) continue; + polar(rx, ry, rz, rr, crth, srth, crph, srph); + sphar(crth, srth, crph, srph, lmt, ylm); + for (int iv48 = 1; iv48 <= c4->lmtpos; iv48++) { + c1ao->vyj0[iv48 + ivy - 1] = dconjg(ylm[iv48 - 1]); + } // iv48 loop + ivy += c4->lmtpos; + } // nf50 loop +} + +#endif