From cf492655e739465fbacc6c8ac2c903ff82e87f0e Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Thu, 16 Jan 2025 19:53:31 -0500 Subject: [PATCH 01/12] Added ring generation routine, position quick start to gensph, and modernized the gen_point API --- exputil/EXPmath.cc | 42 ++-- exputil/realize_model.cc | 514 +++++++++++++++++++++++++++++++-------- include/massmodel.H | 73 ++++-- utils/ICs/CMakeLists.txt | 4 +- utils/ICs/Disk2dHalo.cc | 4 +- utils/ICs/DiskHalo.cc | 7 +- utils/ICs/addring.cc | 192 +++++++++++++++ utils/ICs/gensph.cc | 73 +++++- 8 files changed, 734 insertions(+), 175 deletions(-) create mode 100644 utils/ICs/addring.cc diff --git a/exputil/EXPmath.cc b/exputil/EXPmath.cc index 74189d649..feed74357 100644 --- a/exputil/EXPmath.cc +++ b/exputil/EXPmath.cc @@ -61,12 +61,12 @@ namespace AltMath return ans; } -#define ACC 40.0 -#define BIGNO 1.0e10 -#define BIGNI 1.0e-10 - double bessj(int n,double x) { + const double ACC = 40.0; + const double BIGNO = 1.0e10; + const double BIGNI = 1.0e-10; + int j,jsum,m; double ax,bj,bjm,bjp,sum,tox,ans; @@ -114,10 +114,6 @@ namespace AltMath return x < 0.0 && n%2 == 1 ? -ans : ans; } -#undef ACC -#undef BIGNO -#undef BIGNI - double bessk0(double x) { double y,ans; @@ -174,12 +170,12 @@ namespace AltMath return ans; } -#define ACC 40.0 -#define BIGNO 1.0e10 -#define BIGNI 1.0e-10 - double bessi(int n,double x) { + const double ACC = 40.0; + const double BIGNO = 1.0e10; + const double BIGNI = 1.0e-10; + int j; double bi,bim,bip,tox,ans; double bessi0(double ); @@ -207,10 +203,6 @@ namespace AltMath } } -#undef ACC -#undef BIGNO -#undef BIGNI - double bessi0(double x) { double ax,ans; @@ -253,12 +245,12 @@ namespace AltMath return x < 0.0 ? -ans : ans; } -#define ACC 40.0 -#define BIGNO 1.0e10 -#define BIGNI 1.0e-10 - double jn_sph(int n, double x) { + const double ACC = 40.0; + const double BIGNO = 1.0e10; + const double BIGNI = 1.0e-10; + int j,m; double ax,bj,bjm,bjp,tox,ans; double jn_sph0(double x),jn_sph1(double x),jn_sphm1(double x); @@ -306,13 +298,10 @@ namespace AltMath return x < 0.0 && n%2 == 1 ? -ans : ans; } -#undef ACC -#undef BIGNO -#undef BIGNI - -#define TOL 1.0e-7 double jn_sph0(double x) { + const double TOL = 1.0e-7; + if (fabs(x)(get_min_radius(), gen_rmin); double Emax = get_pot(get_max_radius()); @@ -525,7 +517,9 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(int& ierr) if (Unit(random_gen)<0.5) vr *= -1.0; - azi = 2.0*M_PI*Unit(random_gen); + // Orientation of tangential velocity vector + // + double azi = 2.0*M_PI*Unit(random_gen); vt1 = vt*cos(azi); vt2 = vt*sin(azi); @@ -544,13 +538,10 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(int& ierr) << std::setw(12) << fmax << " %=" << std::setw(12) << static_cast(++toomany)/totcnt << std::endl; - ierr = 1; out.setZero(); - return out; + return {out, 1}; } - ierr = 0; - if (Unit(random_gen)>=0.5) vr *= -1.0; phi = 2.0*M_PI*Unit(random_gen); @@ -583,17 +574,139 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(int& ierr) #endif - return out; + return {out, 0}; } -Eigen::VectorXd AxiSymModel::gen_point_3d(double Emin, double Emax, - double Kmin, double Kmax, int& ierr) +AxiSymModel::PSret AxiSymModel::gen_point_3d(double r, double theta, double phi) { if (!dist_defined) { - std::cerr << "AxiSymModel: must define distribution before realizing!" - << std::endl; - exit (-1); + throw std::runtime_error("AxiSymModel: must define distribution before realizing!"); + } + + int it; // Iteration counter + double pot, vmax, vr=0.0, vt=0.0, eee, fmax; + double rmin = max(get_min_radius(), gen_rmin); + double Emax = get_pot(get_max_radius()); + + if (gen_firstime) { + + double tol = 1.0e-5; + double dx = (1.0 - 2.0*tol)/(numr-1); + double dy = (1.0 - 2.0*tol)/(numj-1); + + gen_mass.resize(gen_N); + gen_rloc.resize(gen_N); + gen_fmax.resize(gen_N); + +#ifdef DEBUG + std::cout << "gen_point_3d[" << ModelID << "]: " << rmin + << ", " << get_max_radius() << std::endl; +#endif + + double dr = (get_max_radius() - rmin)/gen_N; + + for (int i=0; ifmax ? zzz : fmax; + } + } + gen_fmax[i] = fmax*(1.0 + ftol); + + } + gen_firstime = false; + } + + fmax = odd2(r, gen_rloc, gen_fmax, 1); + pot = get_pot(r); + vmax = sqrt(2.0*fabs(Emax - pot)); + + // Trial velocity point + // + for (it=0; it distf(eee, r*vt)/fmax ) continue; + + if (Unit(random_gen)<0.5) vr *= -1.0; + + break; + } + + Eigen::VectorXd out(7); + + if (std::isnan(vr) or std::isnan(vt)) { + if (verbose) std::cout << "NaN found in AxiSymModel::gen_point_3d with r=" + << r << " theta=" << theta << " phi=" << phi + << std::endl; + out.setZero(); + return {out, 1}; + } + + static unsigned totcnt = 0, toomany = 0; + totcnt++; + + if (it==gen_itmax) { + if (verbose) + std::cerr << "Velocity selection failed [" << myid << "]: r=" + << std::setw(12) << r + << std::setw(12) << fmax + << " %=" << std::setw(12) + << static_cast(++toomany)/totcnt << std::endl; + out.setZero(); + return {out, 1}; + } + + double tv = 2.0*M_PI*Unit(random_gen); + double vth = vt*cos(tv); + double vph = vt*sin(tv); + + double cost = cos(theta); + double sint = sin(theta); + + double cosp = cos(phi); + double sinp = sin(phi); + + out[0] = 1.0; + out[1] = r*sint*cosp; + out[2] = r*sint*sinp; + out[3] = r*cost; + out[4] = vr*sint*cosp - vph*sinp + vth*cost*cosp; + out[5] = vr*sint*sinp + vph*cosp + vth*cost*sinp; + out[6] = vr*cost - vth*sint; + + return {out, 0}; +} + + +AxiSymModel::PSret AxiSymModel::gen_point_3d(double Emin, double Emax, + double Kmin, double Kmax) +{ + if (!dist_defined) { + throw std::runtime_error("AxiSymModel: must define distribution before realizing!"); } #ifdef DEBUG @@ -602,7 +715,7 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(double Emin, double Emax, #endif double r, vr, vt, vt1, vt2, E, K, J, jmax, w1t, eee, pot; - double phi, sint, cost, sinp, cosp, azi; + double phi, sint, cost, sinp, cosp; double rmin = max(get_min_radius(), gen_rmin); double rmax = get_max_radius(); @@ -688,7 +801,8 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(double Emin, double Emax, #endif } - // Enforce limits + // Enforce limits + // Emin = max(Emin, Emin_grid); Emin = min(Emin, Emax_grid); Emax = max(Emax, Emin_grid); @@ -733,9 +847,10 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(double Emin, double Emax, pot = get_pot(r); vt = J/r; - ierr = 0; - // Interpolation check (should be rare) - // Error condition is set + int ierr = 0; + + // Interpolation check (should be rare). Error condition is set. + // if (2.0*(E - pot) - vt*vt < 0.0) { ierr = 1; if (E < pot) E = pot; @@ -745,7 +860,9 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(double Emin, double Emax, if (Unit(random_gen)<0.5) vr *= -1.0; - azi = 2.0*M_PI*Unit(random_gen); + // Orientation of tangential velocity vector + // + double azi = 2.0*M_PI*Unit(random_gen); vt1 = vt*cos(azi); vt2 = vt*sin(azi); @@ -767,7 +884,7 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(double Emin, double Emax, #ifdef DEBUG - if (ierr) return out; + if (ierr) return {out, ierr}; eee = pot + 0.5*(out[4]*out[4]+out[5]*out[5]+out[6]*out[6]); orb.new_orbit(eee, 0.5); @@ -787,15 +904,15 @@ Eigen::VectorXd AxiSymModel::gen_point_3d(double Emin, double Emax, << std::endl; #endif - return out; + return {out, ierr}; } -Eigen::VectorXd AxiSymModel::gen_point_jeans_3d(int& ierr) +AxiSymModel::PSret AxiSymModel::gen_point_jeans_3d() { double r, d, vr, vt, vt1, vt2, vv, vtot; - double phi, sint, cost, sinp, cosp, azi; + double phi, sint, cost, sinp, cosp; double rmin = max(get_min_radius(), gen_rmin); if (gen_firstime_jeans) { @@ -838,8 +955,8 @@ Eigen::VectorXd AxiSymModel::gen_point_jeans_3d(int& ierr) // Debug - - ofstream test("test.grid"); + // + std::ofstream test("test.grid"); if (test) { test << "# [Jeans] Rmin=" << rmin @@ -885,7 +1002,9 @@ Eigen::VectorXd AxiSymModel::gen_point_jeans_3d(int& ierr) vr = vtot*xxx; vt = vtot*sqrt(yyy); - azi = 2.0*M_PI*Unit(random_gen); + // Orientation of tangential velocity vector + // + double azi = 2.0*M_PI*Unit(random_gen); vt1 = vt*cos(azi); vt2 = vt*sin(azi); @@ -907,24 +1026,20 @@ Eigen::VectorXd AxiSymModel::gen_point_jeans_3d(int& ierr) out[5] = vr * sint*sinp + vt1 * cost*sinp + vt2*cosp; out[6] = vr * cost - vt1 * sint; - ierr = 0; - - return out; + return {out, 0}; } -void AxiSymModel::gen_velocity(double* pos, double* vel, int& ierr) +int AxiSymModel::gen_velocity(double* pos, double* vel) { if (dof()!=3) bomb( "AxiSymModel: gen_velocity only implemented for 3d model!" ); - + if (!dist_defined) { - std::cerr << "AxiSymModel: must define distribution before realizing!" - << std::endl; - exit (-1); + throw std::runtime_error("AxiSymModel: must define distribution before realizing!"); } double r, pot, vmax, vr=0.0, vt, eee, vt1=0.0, vt2=0.0, fmax; - double phi, sint, cost, sinp, cosp, azi; + double phi, sint, cost, sinp, cosp; double rmin = max(get_min_radius(), gen_rmin); double Emax = get_pot(get_max_radius()); @@ -1021,7 +1136,9 @@ void AxiSymModel::gen_velocity(double* pos, double* vel, int& ierr) if (Unit(random_gen)<0.5) vr *= -1.0; - azi = 2.0*M_PI*Unit(random_gen); + // Orientation of tangential velocity vector + // + double azi = 2.0*M_PI*Unit(random_gen); vt1 = vt*cos(azi); vt2 = vt*sin(azi); @@ -1038,12 +1155,9 @@ void AxiSymModel::gen_velocity(double* pos, double* vel, int& ierr) << std::setw(12) << fmax << " %=" << std::setw(12) << static_cast(++toomany)/totcnt << std::endl; - ierr = 1; - return; + return 1; } - ierr = 0; - if (Unit(random_gen)>=0.5) vr *= -1.0; phi = atan2(pos[1], pos[0]); @@ -1055,18 +1169,19 @@ void AxiSymModel::gen_velocity(double* pos, double* vel, int& ierr) vel[0] = vr * sint*cosp + vt1 * cost*cosp - vt2*sinp; vel[1] = vr * sint*sinp + vt1 * cost*sinp + vt2*cosp; vel[2] = vr * cost - vt1 * sint; + + return 0; } -Eigen::VectorXd SphericalModelMulti::gen_point(int& ierr) +AxiSymModel::PSret SphericalModelMulti::gen_point() { if (!real->dist_defined || !fake->dist_defined) { - std::cerr << "SphericalModelMulti: input distribution functions must be defined before realizing!" << std::endl; - exit (-1); + throw std::runtime_error("SphericalModelMulti: input distribution functions must be defined before realizing!"); } double r, pot, vmax; double vr=0.0, vt=0.0, eee=0.0, vt1=0.0, vt2=0.0, fmax, emax; - double mass, phi, sint, cost, sinp, cosp, azi; + double mass, phi, sint, cost, sinp, cosp; double Emax = get_pot(get_max_radius()); @@ -1271,6 +1386,7 @@ Eigen::VectorXd SphericalModelMulti::gen_point(int& ierr) for (it=0; itget_mass(r); -Eigen::VectorXd - SphericalModelMulti::gen_point(double Emin, double Emax, double Kmin, - double Kmax, int& ierr) + pot = get_pot(r); + vmax = sqrt(2.0*fabs(Emax - pot)); + + fmax = 0.0; + for (int j=0; jdistf(eee, r*vt); + fmax = zzz>fmax ? zzz : fmax; + } + } + gen_fmax[i] = fmax*(1.0 + ftol); + + } + + // Debug + // + ofstream test("test_multi.grid"); + if (test) { + + test << "# Rmin=" << rmin_gen + << " Rmax=" << rmax_gen + << std::endl; + + for (int i=0; idistf(get_pot(exp(gen_rloc[i])), 0.5) + << std::endl; + } + } + + gen_firstime = false; + } + + r = max(rmin_gen, min(rmax_gen, radius)); + fmax = odd2(r, gen_rloc, gen_fmax, 1); + if (gen_logr) r = exp(r); + + pot = get_pot(r); + vmax = sqrt(2.0*max(Emax - pot, 0.0)); + + // Trial velocity point + // + // Diagnostic counters + int reject=0; + int it; // Iteration counter + for (it=0; it fake->distf(eee, r*vt)/fmax ) { + reject++; + continue; + } + + if (Unit(random_gen)<0.5) vr *= -1.0; + + // Orientation of tangential velocity vector + // + double azi = 2.0*M_PI*Unit(random_gen); + vt1 = vt*cos(azi); + vt2 = vt*sin(azi); + + break; + } + + Eigen::VectorXd out(7); + + if (it==gen_itmax) { + if (verbose) { + static unsigned totcnt = 0; + std::cerr << "Velocity selection failed [" << std::setw(7) << ++totcnt + << "," << std::setw(4) << myid << "]: r=" + << std::setw(12) << r + << std::setw(12) << fmax + << " reject=" << std::setw( 6) << reject + << std::endl; + } + out.setZero(); + return {out, 1}; + } + + if (Unit(random_gen)>=0.5) vr *= -1.0; + + double dfr = real->distf(eee, r*vt); + double dfn = fake->distf(eee, r*vt); + double rat = dfr/dfn; + + // Deep debug + // +#ifdef DEBUG + if (rat <= 0.0) { + std::cout << "[" << std::setw(3) << myid << "] Bad mass: rat=" + << std::setw(16) << rat + << " df(M)=" << std::setw(16) << dfr + << " df(N)=" << std::setw(16) << dfn + << " r=" << std::setw(16) << r + << " E=" << std::setw(16) << eee + << std::endl; + } +#endif + + double cost = cos(theta); + double sint = sin(theta); + double cosp = cos(phi); + double sinp = sin(phi); + + out[0] = rat; + out[1] = r * sint*cosp; + out[2] = r * sint*sinp; + out[3] = r * cost; + out[4] = vr * sint*cosp + vt1 * cost*cosp - vt2*sinp; + out[5] = vr * sint*sinp + vt1 * cost*sinp + vt2*cosp; + out[6] = vr * cost - vt1 * sint; + + int ierr = 0; + for (int i=0; i<7; i++) { + if (std::isnan(out[i]) || std::isinf(out[i])) ierr = 1; + } + + return {out, ierr}; +} + +AxiSymModel::PSret SphericalModelMulti::gen_point +(double Emin, double Emax, double Kmin, double Kmax) { if (!real->dist_defined || !fake->dist_defined) { - std::cerr << "SphericalModelMulti: input distribution functions must be defined before realizing!" << std::endl; - exit (-1); + throw std::runtime_error("SphericalModelMulti: input distribution functions must be defined before realizing!"); } double r, vr, vt, vt1, vt2, E, K, J, jmax, w1t, pot; - double phi, sint, cost, sinp, cosp, azi; + double phi, sint, cost, sinp, cosp; double rmin = max(get_min_radius(), gen_rmin); double rmax = get_max_radius(); @@ -1619,7 +1911,9 @@ Eigen::VectorXd vector wrvec; for (int j=0; j(Emin, Emin_grid); Emin = min(Emin, Emax_grid); Emax = max(Emax, Emin_grid); @@ -1714,9 +2009,10 @@ Eigen::VectorXd pot = get_pot(r); vt = J/r; - ierr = 0; - // Interpolation check (should be rare) - // Error condition is set + + // Interpolation check (should be rare). Error condition is set. + // + int ierr = 0; if (2.0*(E - pot) - vt*vt < 0.0) { ierr = 1; if (E < pot) E = pot; @@ -1726,7 +2022,9 @@ Eigen::VectorXd if (Unit(random_gen)<0.5) vr *= -1.0; - azi = 2.0*M_PI*Unit(random_gen); + // Orientation of the tangential velocity vector + // + double azi = 2.0*M_PI*Unit(random_gen); vt1 = vt*cos(azi); vt2 = vt*sin(azi); @@ -1750,7 +2048,7 @@ Eigen::VectorXd if (std::isnan(out[i]) || std::isinf(out[i])) ierr = 1; } - return out; + return {out, ierr}; } diff --git a/include/massmodel.H b/include/massmodel.H index 88939322d..a9a6a75a3 100644 --- a/include/massmodel.H +++ b/include/massmodel.H @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -111,6 +112,10 @@ public: class AxiSymModel : public MassModel, public std::enable_shared_from_this { +public: + + using PSret = std::tuple; + protected: //@{ //! Stuff for gen_point @@ -126,11 +131,12 @@ protected: double gen_fomax, gen_ecut; //@} - Eigen::VectorXd gen_point_2d(int& ierr); - Eigen::VectorXd gen_point_2d(double r, int& ierr); - Eigen::VectorXd gen_point_3d(int& ierr); - Eigen::VectorXd gen_point_3d(double Emin, double Emax, double Kmin, double Kmax, int& ierr); - Eigen::VectorXd gen_point_jeans_3d(int& ierr); + PSret gen_point_2d(); + PSret gen_point_2d(double r); + PSret gen_point_3d(); + PSret gen_point_3d(double Emin, double Emax, double Kmin, double Kmax); + PSret gen_point_jeans_3d(); + PSret gen_point_3d(double r, double theta, double phi); double Emin_grid, Emax_grid, dEgrid, dKgrid; vector Egrid, Kgrid, EgridMass; @@ -212,55 +218,73 @@ public: void set_Ecut(double cut) { gen_ecut = cut; } //! Generate a phase-space point - virtual Eigen::VectorXd gen_point(int& ierr) { + virtual PSret gen_point() + { if (dof()==2) - return gen_point_2d(ierr); + return gen_point_2d(); else if (dof()==3) - return gen_point_3d(ierr); + return gen_point_3d(); else bomb( "dof must be 2 or 3" ); - return Eigen::VectorXd(); + return {Eigen::VectorXd(), 1}; } //! Generate a phase-space point using Jeans' equations - virtual Eigen::VectorXd gen_point_jeans(int& ierr) { + virtual PSret gen_point_jeans() + { if (dof()==2) bomb( "AxiSymModel: gen_point_jeans_2d(ierr) not implemented!" ); else if (dof()==3) - return gen_point_jeans_3d(ierr); + return gen_point_jeans_3d(); else bomb( "dof must be 2 or 3" ); - return Eigen::VectorXd(); + return {Eigen::VectorXd(), 1}; } //! Generate a phase-space point at a particular radius - virtual Eigen::VectorXd gen_point(double r, int& ierr) { + virtual PSret gen_point(double r) { + if (dof()==2) + return gen_point_2d(r); + else if (dof()==3) + bomb( "AxiSymModel: gen_point(r) not implemented!" ); + else + bomb( "AxiSymModel: dof must be 2 or 3" ); + + return {Eigen::VectorXd(), 1}; + } + + //! Generate a phase-space point at a particular radius, theta, and phi + virtual PSret + gen_point(double r, double theta, double phi) + { if (dof()==2) - return gen_point_2d(r, ierr); + bomb( "AxiSymModel: gen_point(r, theta, phi) not implemented!" ); else if (dof()==3) - bomb( "AxiSymModel: gen_point(r, ierr) not implemented!" ); + return gen_point_3d(r, theta, phi); else bomb( "AxiSymModel: dof must be 2 or 3" ); - return Eigen::VectorXd(); + return {Eigen::VectorXd(), 1}; } //! Generate a phase-space point at a particular energy and angular momentum - virtual Eigen::VectorXd gen_point(double Emin, double Emax, double Kmin, double Kmax, int& ierr) { + virtual PSret + gen_point(double Emin, double Emax, double Kmin, double Kmax) + { if (dof()==2) - bomb( "AxiSymModel: gen_point(r, ierr) not implemented!" ); + bomb( "AxiSymModel: gen_point(r) not implemented!" ); else if (dof()==3) - return gen_point_3d(Emin, Emax, Kmin, Kmax, ierr); + return gen_point_3d(Emin, Emax, Kmin, Kmax); else bomb( "AxiSymModel: dof must be 2 or 3" ); - return Eigen::VectorXd(); + return {Eigen::VectorXd(), 1}; } //! Generate a the velocity variate from a position - virtual void gen_velocity(double *pos, double *vel, int& ierr); + virtual int gen_velocity(double *pos, double *vel); }; @@ -501,9 +525,10 @@ public: //@{ //! Overloaded to provide mass distribution from Real and Number distribution from Fake - Eigen::VectorXd gen_point(int& ierr); - Eigen::VectorXd gen_point(double r, int& ierr); - Eigen::VectorXd gen_point(double Emin, double Emax, double Kmin, double Kmax, int& ierr); + PSret gen_point(); + PSret gen_point(double r); + PSret gen_point(double Emin, double Emax, double Kmin, double Kmax); + PSret gen_point(double r, double theta, double phi); //@} diff --git a/utils/ICs/CMakeLists.txt b/utils/ICs/CMakeLists.txt index 0c89b9942..281695e52 100644 --- a/utils/ICs/CMakeLists.txt +++ b/utils/ICs/CMakeLists.txt @@ -2,7 +2,7 @@ set(bin_PROGRAMS shrinkics gensph gendisk gendisk2d gsphere pstmod empinfo empdump eofbasis eofcomp testcoefs testcoefs2 testdeval forcetest hdf52accel forcetest2 cylcache modelfit test2d addsphmod - cubeics zangics slabics) + cubeics zangics slabics addring) set(common_LINKLIB OpenMP::OpenMP_CXX MPI::MPI_CXX yaml-cpp exputil ${VTK_LIBRARIES} ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES} @@ -88,6 +88,8 @@ add_executable(zangics ZangICs.cc) add_executable(slabics genslab.cc massmodel1d.cc) +add_executable(addring addring.cc) + foreach(program ${bin_PROGRAMS}) target_link_libraries(${program} ${common_LINKLIB}) target_include_directories(${program} PUBLIC ${common_INCLUDE}) diff --git a/utils/ICs/Disk2dHalo.cc b/utils/ICs/Disk2dHalo.cc index f923e4792..ad0e9a61b 100644 --- a/utils/ICs/Disk2dHalo.cc +++ b/utils/ICs/Disk2dHalo.cc @@ -401,7 +401,7 @@ void Disk2dHalo::set_halo(vector& phalo, int nhalo, int npart) for (int i=0; igen_point(ierr); + std::tie(ps, ierr) = multi->gen_point(); if (ierr) count1++; } while (ierr); @@ -2329,7 +2329,7 @@ void Disk2dHalo::set_vel_halo(vector& part) // Use Eddington if (DF && 0.5*(1.0+erf((r-R_DF)/DR_DF)) > rndU(gen)) { - halo2->gen_velocity(&p.pos[0], &p.vel[0], nok); + nok = halo2->gen_velocity(&p.pos[0], &p.vel[0]); if (nok) { std::cout << "gen_velocity failed: " diff --git a/utils/ICs/DiskHalo.cc b/utils/ICs/DiskHalo.cc index c64a75c6a..0ff393af6 100644 --- a/utils/ICs/DiskHalo.cc +++ b/utils/ICs/DiskHalo.cc @@ -411,7 +411,7 @@ void DiskHalo::set_halo(vector& phalo, int nhalo, int npart) for (int i=0; igen_point(ierr); + std::tie(ps, ierr) = multi->gen_point(); if (ierr) count1++; } while (ierr); @@ -631,7 +631,7 @@ set_halo_coordinates(vector& phalo, int nhalo, int npart) p.pos[2] = r*costh; do { - ps = halo2->gen_point(ierr); + std::tie(ps, ierr) = halo2->gen_point(); } while (ierr); massp1 += p.mass; @@ -2560,7 +2560,8 @@ void DiskHalo::set_vel_halo(vector& part) // Use Eddington if (DF && 0.5*(1.0+erf((r-R_DF)/DR_DF)) > rndU(gen)) { - halo2->gen_velocity(&p.pos[0], &p.vel[0], nok); + + nok = halo2->gen_velocity(&p.pos[0], &p.vel[0]); if (nok) { std::cout << "gen_velocity failed: " diff --git a/utils/ICs/addring.cc b/utils/ICs/addring.cc new file mode 100644 index 000000000..6e4cedafe --- /dev/null +++ b/utils/ICs/addring.cc @@ -0,0 +1,192 @@ +/* + Add a ring of particles to an existing realization +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#ifdef HAVE_OMP_H +#include +#endif + +// EXP classes +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Library globals +#include // Command-line parsing +#include // Ini-style config + + // Local headers +#include +#include + +int +main(int ac, char **av) +{ + //==================== + // Inialize MPI stuff + //==================== + + local_init_mpi(ac, av); + + //==================== + // Begin opt parsing + //==================== + + std::string halofile; + int DIVERGE, N; + double DIVERGE_RFAC, mass, radius, width, vdisp; + std::string outfile, config; + + const std::string mesg("Make a model from the combination of two spherical models. E.g. a DM halo and a bulge.\n"); + + cxxopts::Options options(av[0], mesg); + + options.add_options() + ("h,help", "Print this help message") + ("s,spline", "Set interplation in SphericalModelTable to 'spline' (default: linear)") + ("T,template", "Write template options file with current and all default values") + ("c,config", "Parameter configuration file", + cxxopts::value(config)) + ("N,number", "Number of particles", + cxxopts::value(N)->default_value("100000")) + ("DIVERGE", "Cusp power-law density extrapolation (0 means off)", + cxxopts::value(DIVERGE)->default_value("0")) + ("DIVERGE_RFAC", "Exponent for inner cusp extrapolation", + cxxopts::value(DIVERGE_RFAC)->default_value("1.0")) + ("i,halofile", "Halo spherical model table", + cxxopts::value(halofile)->default_value("SLGridSph.one")) + ("o,outfile", "Output particle file", + cxxopts::value(outfile)->default_value("addring.bods")) + ("M,mass", "Mass of ring", + cxxopts::value(mass)->default_value("0.1")) + ("R,radius", "Radius of ring", + cxxopts::value(radius)->default_value("1.0")) + ("W,width", "Width of ring", + cxxopts::value(width)->default_value("0.1")) + ("V,disp", "Velocity dispersion", + cxxopts::value(vdisp)->default_value("0.1")) + ; + + cxxopts::ParseResult vm; + + try { + vm = options.parse(ac, av); + } catch (cxxopts::OptionException& e) { + if (myid==0) std::cout << "Option error: " << e.what() << std::endl; + MPI_Finalize(); + exit(-1); + } + + // Write YAML template config file and exit + // + if (vm.count("template")) { + // Write template file + // + if (myid==0) SaveConfig(vm, options, "template.yaml"); + + MPI_Finalize(); + return 0; + } + + // Print help message and exit + // + if (vm.count("help")) { + if (myid == 0) { + std::cout << options.help() << std::endl << std::endl + << "Examples: " << std::endl + << "\t" << "Use parameters read from a YAML config file" << std::endl + << "\t" << av[0] << " --config=addsphmod.config" << std::endl << std::endl + << "\t" << "Generate a template YAML config file from current defaults" << std::endl + << "\t" << av[0] << " --template=template.yaml" << std::endl << std::endl; + } + MPI_Finalize(); + return 0; + } + + // Read parameters fron the YAML config file + // + if (vm.count("config")) { + try { + vm = LoadConfig(options, config); + } catch (cxxopts::OptionException& e) { + if (myid==0) std::cout << "Option error in configuration file: " + << e.what() << std::endl; + MPI_Finalize(); + return 0; + } + } + + if (vm.count("spline")) { + SphericalModelTable::linear = 0; + } else { + SphericalModelTable::linear = 1; + } + + // Open output file + // + std::ofstream out(outfile); + if (not out) throw std::runtime_error("Cannot open output file " + outfile); + + // Model + // + SphericalModelTable model(halofile, DIVERGE, DIVERGE_RFAC); + + + // Random setup + // + std::random_device rd{}; + std::mt19937 gen{rd()}; + + // Unit normal distribution + // + std::normal_distribution<> d{0.0, 1.0}; + std::uniform_real_distribution<> u{0.0, 1.0}; + + + double pmass = mass/N; + Eigen::Vector3d pos, vel; + + for (int i=0; i(ELIMIT)->default_value("false")) ("VTEST", "Test gen_velocity() generation", cxxopts::value(VTEST)->default_value("false")) + ("Vquiet", "Number of angular points on a regular spherical grid (0 means no quiet)", + cxxopts::value(Vquiet)->default_value("0")) ("Emin0", "Minimum energy (if ELIMIT=true)", cxxopts::value(Emin0)->default_value("-3.0")) ("Emax0", "Maximum energy (if ELIMIT=true)", @@ -703,23 +705,72 @@ main(int argc, char **argv) std::vector PS; Eigen::VectorXd zz = Eigen::VectorXd::Zero(7); + std::vector rmass; + int nradial=0, nphi=0, ncost=0; + if (Vquiet) { + nphi = 2*Vquiet; + ncost = Vquiet; + nradial = floor(N/(nphi*ncost)); + if (nradial*nphi*ncost < N) nradial++; + rmass.resize(nradial); + + // Set up mass grid + double rmin = hmodel->get_min_radius(); + double rmax = hmodel->get_max_radius(); + double mmas = hmodel->get_mass(rmax); + double dmas = mmas/nradial; + for (int i=0; i double + { return (mas - hmodel->get_mass(r)); }; + rmass[i] = zbrent(loc, rmin, rmax, 1.0e-8); + } + } + for (int n=beg; ngen_point(Emin0, Emax0, Kmin0, Kmax0, ierr); + if (Vquiet) { + // which radial ring + int nr = floor(n/(nphi*ncost)); + int rm = n - nr*nphi*ncost; + // which elevational plane + int nt = rm/nphi; + // which azimuth + int np = rm - nt*nphi; + + assert((nr>=0 && nr=0 && nt=0 && npgen_point(r, acos(cost), phi); + + for (int i=0; i<3; i++) { + if (std::isnan(ps[i+3])) { + std::cout << "Vel NaN with r=" << r << " cost=" << cost << " phi=" << phi << std::endl; + } + } + } + else if (ELIMIT) + std::tie(ps, ierr) = rmodel->gen_point(Emin0, Emax0, Kmin0, Kmax0); else if (VTEST) { - ps = rmodel->gen_point(ierr); - rmodel->gen_velocity(&ps[1], &ps[4], ierr); - if (ierr) { - std::cout << "gen_velocity failed: " - << ps[0] << " " - << ps[1] << " " - << ps[2] << "\n"; + std::tie(ps, ierr) = rmodel->gen_point(); + if (ierr==0) { + ierr = rmodel->gen_velocity(&ps[1], &ps[4]); + if (ierr) { + std::cout << "gen_velocity failed: " + << ps[0] << " " + << ps[1] << " " + << ps[2] << "\n"; + } } } else - ps = rmodel->gen_point(ierr); + std::tie(ps, ierr) = rmodel->gen_point(); if (ierr) count++; } while (ierr); From 2ee5f3b7c99b881c25af97775f31adc75a5be03b Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Fri, 17 Jan 2025 13:51:59 -0500 Subject: [PATCH 02/12] Use additive machine constants to set epsilon in Legendre functions on CPU and GPU --- src/Basis.cc | 2 +- src/cudaSphericalBasis.cu | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Basis.cc b/src/Basis.cc index e7f7a6c6a..1db4dc2da 100644 --- a/src/Basis.cc +++ b/src/Basis.cc @@ -4,7 +4,7 @@ // Machine constant for Legendre // -constexpr double MINEPS = 20.0*std::numeric_limits::min(); +constexpr double MINEPS = 3.0*std::numeric_limits::epsilon(); Basis::Basis(Component* c0, const YAML::Node& conf) : PotAccel(c0, conf) { diff --git a/src/cudaSphericalBasis.cu b/src/cudaSphericalBasis.cu index 38d8bf008..2acb86066 100644 --- a/src/cudaSphericalBasis.cu +++ b/src/cudaSphericalBasis.cu @@ -19,7 +19,7 @@ // Global symbols for coordinate transformation in SphericalBasis // __device__ __constant__ -cuFP_t sphScale, sphRscale, sphHscale, sphXmin, sphXmax, sphDxi, sphCen[3]; +cuFP_t sphScale, sphRscale, sphHscale, sphXmin, sphXmax, sphDxi, sphCen[3], sphEPS; __device__ __constant__ int sphNumr, sphCmap; @@ -80,7 +80,7 @@ void legendre_v(int lmax, cuFP_t x, cuFP_t* p) } -__host__ __device__ +__device__ void legendre_v2(int lmax, cuFP_t x, cuFP_t* p, cuFP_t* dp) { cuFP_t fact, somx2, pll, pl1, pl2; @@ -106,9 +106,9 @@ void legendre_v2(int lmax, cuFP_t x, cuFP_t* p, cuFP_t* dp) } } - if (1.0-fabs(x) < MINEPS) { - if (x>0) x = 1.0 - MINEPS; - else x = -(1.0 - MINEPS); + if (1.0-fabs(x) < sphEPS) { + if (x>0) x = 1.0 - sphEPS; + else x = -(1.0 - sphEPS); } somx2 = 1.0/(x*x - 1.0); @@ -134,6 +134,7 @@ void testConstantsSph() printf(" Dxi = %f\n", sphDxi ); printf(" Numr = %d\n", sphNumr ); printf(" Cmap = %d\n", sphCmap ); + printf(" Feps = %d\n", sphEPS ); printf("-------------------------\n"); } @@ -231,6 +232,15 @@ void SphericalBasis::initialize_mapping_constants() __FILE__, __LINE__, "Error copying sphEVEN_M"); cuda_safe_call(cudaMemcpyToSymbol(sphM0only, &M0_only, sizeof(bool), size_t(0), cudaMemcpyHostToDevice), __FILE__, __LINE__, "Error copying sphM0only"); + +#if cuREAL == 4 + cuFP_t feps = 3.0*std::numeric_limits::epsilon(); +#else + cuFP_t feps = 3.0*std::numeric_limits::epsilon(); +#endif + + cuda_safe_call(cudaMemcpyToSymbol(sphEPS, &feps, sizeof(cuFP_t), size_t(0), cudaMemcpyHostToDevice), + __FILE__, __LINE__, "Error copying sphEPS"); } From 51298caccf2a586d1a91b38c527578ddb6b28cf4 Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Fri, 17 Jan 2025 14:19:06 -0500 Subject: [PATCH 03/12] Update particle numbers to exactly fill each radial shell --- utils/ICs/gensph.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/utils/ICs/gensph.cc b/utils/ICs/gensph.cc index d885f1282..8bfe6ca5f 100644 --- a/utils/ICs/gensph.cc +++ b/utils/ICs/gensph.cc @@ -522,6 +522,16 @@ main(int argc, char **argv) } + int nradial=0, nphi=0, ncost=0; + if (Vquiet) { + nphi = 2*Vquiet; + ncost = Vquiet; + nradial = floor(N/(nphi*ncost)); + + // Reset N + N = nradial*nphi*ncost; + } + double mass = hmodel->get_mass(hmodel->get_max_radius())/N; AxiSymModPtr rmodel = hmodel; @@ -706,12 +716,7 @@ main(int argc, char **argv) Eigen::VectorXd zz = Eigen::VectorXd::Zero(7); std::vector rmass; - int nradial=0, nphi=0, ncost=0; if (Vquiet) { - nphi = 2*Vquiet; - ncost = Vquiet; - nradial = floor(N/(nphi*ncost)); - if (nradial*nphi*ncost < N) nradial++; rmass.resize(nradial); // Set up mass grid From 37cbf888de7ca9cdfba4b75a908c8667ef7efa0c Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Fri, 17 Jan 2025 14:22:14 -0500 Subject: [PATCH 04/12] Stagger radial bins from mass end points; add diagnostic mass ring profile --- exputil/realize_model.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/exputil/realize_model.cc b/exputil/realize_model.cc index 6cb6c6ffa..4b7c4ee13 100644 --- a/exputil/realize_model.cc +++ b/exputil/realize_model.cc @@ -607,7 +607,7 @@ AxiSymModel::PSret AxiSymModel::gen_point_3d(double r, double theta, double phi) double dr = (get_max_radius() - rmin)/gen_N; for (int i=0; i Date: Sat, 18 Jan 2025 12:50:50 -0500 Subject: [PATCH 05/12] Added Fibonacci spiral mapped to the sphere for uniform coverage of shells --- utils/ICs/gensph.cc | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/utils/ICs/gensph.cc b/utils/ICs/gensph.cc index 8bfe6ca5f..ea2b8bcc9 100644 --- a/utils/ICs/gensph.cc +++ b/utils/ICs/gensph.cc @@ -72,7 +72,7 @@ main(int argc, char **argv) double X0, Y0, Z0, U0, V0, W0, TOLE; double Emin0, Emax0, Kmin0, Kmax0, RBAR, MBAR, BRATIO, CRATIO, SMOOTH; bool LOGR, ELIMIT, VERBOSE, GRIDPOT, MODELS, EBAR, zeropos, zerovel; - bool VTEST; + bool VTEST, FIB=false; std::string INFILE, MMFILE, OUTFILE, OUTPS, config; #ifdef DEBUG @@ -94,6 +94,7 @@ main(int argc, char **argv) options.add_options() ("h,help", "Print this help message") ("v,verbose", "Print additional diagnostic information") + ("f,Fibonacci", "Use a Fibonacci lattice to tile the spherical shells") ("T,template", "Write template options file with current and all default values") ("c,config", "Parameter configuration file", cxxopts::value(config)) @@ -256,6 +257,8 @@ main(int argc, char **argv) if (vm.count("verbose")) VERBOSE = true; else VERBOSE = false; + if (vm.count("Fibonacci")) FIB = true; + // Prepare output streams and create new files // std::ostringstream sout; @@ -524,11 +527,12 @@ main(int argc, char **argv) int nradial=0, nphi=0, ncost=0; if (Vquiet) { - nphi = 2*Vquiet; - ncost = Vquiet; + nphi = 2*Vquiet; // # of aximuthal angles + ncost = Vquiet; // # of colatitude angles + // # of radial shells nradial = floor(N/(nphi*ncost)); - // Reset N + // Reset N to fill all spherical shells N = nradial*nphi*ncost; } @@ -736,21 +740,28 @@ main(int argc, char **argv) do { if (Vquiet) { - // which radial ring + // Which radial ring? int nr = floor(n/(nphi*ncost)); int rm = n - nr*nphi*ncost; - // which elevational plane + // Which elevational plane? int nt = rm/nphi; - // which azimuth + // Which azimuth? int np = rm - nt*nphi; assert((nr>=0 && nr=0 && nt=0 && npgen_point(r, acos(cost), phi); From 846e4f4292428b9ddde2e853cc5105a8c9c65e24 Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Sat, 18 Jan 2025 12:51:16 -0500 Subject: [PATCH 06/12] Fixed error in velocity assignment at fixed radius --- exputil/realize_model.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/exputil/realize_model.cc b/exputil/realize_model.cc index 4b7c4ee13..df43b69fc 100644 --- a/exputil/realize_model.cc +++ b/exputil/realize_model.cc @@ -655,10 +655,11 @@ AxiSymModel::PSret AxiSymModel::gen_point_3d(double r, double theta, double phi) for (it=0; it distf(eee, r*vt)/fmax ) continue; From 87666df9c24af38ce8373304d19f72364ce3676b Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Tue, 21 Jan 2025 15:20:25 -0500 Subject: [PATCH 07/12] Updates to gensph for quiet start variations --- exputil/massmodel_dist.cc | 40 +++-- exputil/realize_model.cc | 158 +++++++++++++++++-- include/massmodel.H | 21 ++- utils/ICs/gensph.cc | 319 ++++++++++++++++++++++++++++---------- 4 files changed, 434 insertions(+), 104 deletions(-) diff --git a/exputil/massmodel_dist.cc b/exputil/massmodel_dist.cc index 27e2d877f..618a4bd8e 100644 --- a/exputil/massmodel_dist.cc +++ b/exputil/massmodel_dist.cc @@ -49,14 +49,14 @@ #include #include -#define OFFSET 1.0e-3 -#define OFFTOL 1.2 +const double OFFSET=1.0e-3; +const double OFFTOL=1.2; extern double gint_0(double a, double b, std::function f, int NGauss); extern double gint_2(double a, double b, std::function f, int NGauss); -#define TSTEP 1.0e-8 -#define NGauss 96 +const double TSTEP=1.0e-8; +const int NGauss=96; static int DIVERGE=0; @@ -109,6 +109,10 @@ void SphericalModelTable::setup_df(int NUM, double RA) rhoQy.resize(num); rhoQy2.resize(num); + rhoQx. setZero(); + rhoQy. setZero(); + rhoQy2.setZero(); + for (int i=0; i::max(); + // foffset = -std::numeric_limits::max(); + foffset = -1.0e42; dfc.Q[dfc.num-1] = Qmax; dfc.ffQ[dfc.num-1] = 0.0; fac = 1.0/(sqrt(8.0)*M_PI*M_PI); @@ -184,6 +194,13 @@ void SphericalModelTable::setup_df(int NUM, double RA) df.ffQ .resize(NUM); df.fQ2 .resize(NUM); df.ffQ2.resize(NUM); + + df.Q .setZero(); + df.fQ .setZero(); + df.ffQ .setZero(); + df.fQ2 .setZero(); + df.ffQ2.setZero(); + df.num = NUM; df.ra2 = ra2; @@ -194,7 +211,8 @@ void SphericalModelTable::setup_df(int NUM, double RA) df.Q[df.num-1] = Qmax; df.ffQ[df.num-1] = 0.0; fac = 1.0/(sqrt(8.0)*M_PI*M_PI); - foffset = -std::numeric_limits::max(); + // foffset = -std::numeric_limits::max(); + foffset = -1.0e42; for (int i=df.num-2; i>=0; i--) { df.Q[i] = df.Q[i+1] - dQ; Q = df.Q[i]; @@ -233,7 +251,7 @@ void SphericalModelTable::setup_df(int NUM, double RA) dist_defined = true; - debug_fdist(); + // debug_fdist(); } @@ -294,7 +312,7 @@ double SphericalModelTable::distf(double E, double L) if (!dist_defined) bomb("distribution function not defined"); - double d, g; + double d=0.0, g=0.0; if (chebyN) { @@ -341,7 +359,7 @@ double SphericalModelTable::dfde(double E, double L) if (!dist_defined) bomb("distribution function not defined"); - double d, g, h, d1; + double d=0, g=0, h=0, d1=0; if (chebyN) { @@ -399,7 +417,7 @@ double SphericalModelTable::dfdl(double E, double L) if (!dist_defined) bomb("distribution function not defined"); - double d, g, h, d1; + double d=0, g=0, h=0, d1=0; if (chebyN) { @@ -451,7 +469,7 @@ double SphericalModelTable::d2fde2(double E, double L) { if (!dist_defined) bomb("distribution function not defined"); - double d, g, h, k, d2; + double d=0, g=0, h=0, k=0, d2=0; if (chebyN) { diff --git a/exputil/realize_model.cc b/exputil/realize_model.cc index df43b69fc..3b2361adb 100644 --- a/exputil/realize_model.cc +++ b/exputil/realize_model.cc @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef DEBUG #include @@ -107,9 +108,9 @@ AxiSymModel::PSret AxiSymModel::gen_point_2d() gen_orb.new_orbit(xxx, yyy); - double zzz = distf(xxx, gen_orb.AngMom())*gen_orb.Jmax() - /gen_orb.get_freq(1); - gen_fomax = zzz>gen_fomax ? zzz : gen_fomax; + double zzz = distf(xxx, gen_orb.AngMom())*gen_orb.Jmax()/gen_orb.get_freq(1); + + if (zzz>gen_fomax) gen_fomax = zzz; } } @@ -203,7 +204,7 @@ AxiSymModel::PSret AxiSymModel::gen_point_2d() eee = pot + 0.5*(vr*vr + vt*vt); double zzz = distf(eee, gen_rloc[i]*vt); - fmax = zzz>fmax ? zzz : fmax; + if (zzz > fmax) fmax = zzz; } } gen_fmax[i] = fmax*(1.0 + ftol); @@ -232,7 +233,7 @@ AxiSymModel::PSret AxiSymModel::gen_point_2d() if (Unit(random_gen) > distf(eee, r*vt)/fmax ) continue; - if (Unit(random_gen)<0.5) vr *= -1.0; + if (Unit(random_gen) < 0.5) vr *= -1.0; phi = 2.0*M_PI*Unit(random_gen); @@ -321,7 +322,7 @@ AxiSymModel::PSret AxiSymModel::gen_point_2d(double r) eee = pot + 0.5*(vr*vr + vt*vt); double zzz = distf(eee, gen_rloc[i]*vt); - fmax = zzz>fmax ? zzz : fmax; + if (zzz>fmax) fmax = zzz; } } gen_fmax[i] = fmax*(1.0 + ftol); @@ -347,7 +348,7 @@ AxiSymModel::PSret AxiSymModel::gen_point_2d(double r) if (Unit(random_gen) > distf(eee, r*vt)/fmax ) continue; - if (Unit(random_gen)<0.5) vr *= -1.0; + if (Unit(random_gen) < 0.5) vr *= -1.0; phi = 2.0*M_PI*Unit(random_gen); @@ -453,7 +454,7 @@ AxiSymModel::PSret AxiSymModel::gen_point_3d() eee = pot + 0.5*(vr*vr + vt*vt); double zzz = distf(eee, r*vt); - fmax = zzz>fmax ? zzz : fmax; + if (zzz>fmax) fmax = zzz; } } gen_fmax[i] = fmax*(1.0 + ftol); @@ -625,7 +626,7 @@ AxiSymModel::PSret AxiSymModel::gen_point_3d(double r, double theta, double phi) eee = pot + 0.5*(vr*vr + vt*vt); double zzz = distf(eee, gen_rloc[i]*vt); - fmax = zzz>fmax ? zzz : fmax; + if (zzz>fmax) fmax = zzz; } } gen_fmax[i] = fmax*(1.0 + ftol); @@ -714,6 +715,137 @@ AxiSymModel::PSret AxiSymModel::gen_point_3d(double r, double theta, double phi) return {out, 0}; } +AxiSymModel::PSret AxiSymModel::gen_point_3d_iso +(double r, double theta, double phi, int N, int nv, int na, + double PHI, double THETA, double PSI) +{ + if (!dist_defined) { + throw std::runtime_error("AxiSymModel: must define distribution before realizing!"); + } + + double Emax = get_pot(get_max_radius()); + double vpot = get_pot(r); + double v3 = pow(2.0*fabs(Emax - vpot), 1.5); + int knots = 20; + + // Sanity check + assert((N < nv*na)); + + // Rotation matrix + static Eigen::Matrix3d rotate; + + // Assume isotropic and generate new r slice + if (fabs(gen_lastr-r) > 1.0e-14) { + gen_mass.resize(gen_N+1); + gen_rloc.resize(gen_N+1); + gen_lastr = r; + +#ifdef DEBUG + std::cout << "gen_point_3d_iso[" << ModelID << "]: " << rmin + << ", " << get_max_radius() << std::endl; +#endif + + LegeQuad lv(knots); + + double dv3 = v3/gen_N; + + gen_rloc[0] = 0.0; + gen_mass[0] = 0.0; + for (int i=0; ifmax ? zzz : fmax; + if (zzz>fmax) fmax = zzz; } } gen_fmax[i] = fmax*(1.0 + ftol); @@ -1567,7 +1699,8 @@ AxiSymModel::PSret SphericalModelMulti::gen_point(double radius) eee = pot + 0.5*(vr*vr + vt*vt); double zzz = fake->distf(eee, r*vt); - fmax = zzz>fmax ? zzz : fmax; + + if (zzz>fmax) fmax = zzz; } } gen_fmax[i] = fmax*(1.0 + ftol); @@ -1750,7 +1883,8 @@ SphericalModelMulti::gen_point(double radius, double theta, double phi) eee = pot + 0.5*(vr*vr + vt*vt); double zzz = fake->distf(eee, r*vt); - fmax = zzz>fmax ? zzz : fmax; + + if (zzz>fmax) fmax = zzz; } } gen_fmax[i] = fmax*(1.0 + ftol); diff --git a/include/massmodel.H b/include/massmodel.H index a9a6a75a3..233e2f257 100644 --- a/include/massmodel.H +++ b/include/massmodel.H @@ -128,7 +128,7 @@ protected: bool gen_firstime_jeans; Eigen::VectorXd gen_rloc, gen_mass, gen_fmax; SphericalOrbit gen_orb; - double gen_fomax, gen_ecut; + double gen_fomax, gen_ecut, gen_lastr=-1.0; //@} PSret gen_point_2d(); @@ -137,6 +137,9 @@ protected: PSret gen_point_3d(double Emin, double Emax, double Kmin, double Kmax); PSret gen_point_jeans_3d(); PSret gen_point_3d(double r, double theta, double phi); + PSret gen_point_3d_iso(double r, double theta, double phi, + int N, int nv, int na, + double PHI=0, double THETA=0, double PSI=0); double Emin_grid, Emax_grid, dEgrid, dKgrid; vector Egrid, Kgrid, EgridMass; @@ -269,6 +272,22 @@ public: return {Eigen::VectorXd(), 1}; } + //! Generate a phase-space point at a particular radius, theta, and phi + virtual PSret + gen_point_iso(double r, double theta, double phi, int N, int nv, int na, + double PHI, double THETA, double PSI) + { + if (dof()==2) + bomb( "AxiSymModel: gen_point(r, theta, phi) not implemented!" ); + else if (dof()==3) + return gen_point_3d_iso(r, theta, phi, N, nv, na, + PHI, THETA, PSI); + else + bomb( "AxiSymModel: dof must be 2 or 3" ); + + return {Eigen::VectorXd(), 1}; + } + //! Generate a phase-space point at a particular energy and angular momentum virtual PSret gen_point(double Emin, double Emax, double Kmin, double Kmax) diff --git a/utils/ICs/gensph.cc b/utils/ICs/gensph.cc index ea2b8bcc9..9541ee21f 100644 --- a/utils/ICs/gensph.cc +++ b/utils/ICs/gensph.cc @@ -61,18 +61,21 @@ using namespace __EXP__; #include #endif +#include + // Global variables int main(int argc, char **argv) { int HMODEL, N, NUMDF, NUMR, NUMJ, NUME, NUMG, NREPORT, SEED, ITMAX; - int NUMMODEL, RNUM, DIVERGE, DIVERGE2, LINEAR, NUMINT, NI, ND, Vquiet; + int NUMMODEL, RNUM, DIVERGE, DIVERGE2, LINEAR, NUMINT, NI, ND, Nangle; + int Nrepl=1, Nfib=1; double DIVERGE_RFAC, DIVERGE_RFAC2, NN, MM, RA, RMODMIN, RMOD, EPS; double X0, Y0, Z0, U0, V0, W0, TOLE; double Emin0, Emax0, Kmin0, Kmax0, RBAR, MBAR, BRATIO, CRATIO, SMOOTH; bool LOGR, ELIMIT, VERBOSE, GRIDPOT, MODELS, EBAR, zeropos, zerovel; - bool VTEST, FIB=false; + bool VTEST; std::string INFILE, MMFILE, OUTFILE, OUTPS, config; #ifdef DEBUG @@ -94,7 +97,6 @@ main(int argc, char **argv) options.add_options() ("h,help", "Print this help message") ("v,verbose", "Print additional diagnostic information") - ("f,Fibonacci", "Use a Fibonacci lattice to tile the spherical shells") ("T,template", "Write template options file with current and all default values") ("c,config", "Parameter configuration file", cxxopts::value(config)) @@ -180,8 +182,12 @@ main(int argc, char **argv) cxxopts::value(ELIMIT)->default_value("false")) ("VTEST", "Test gen_velocity() generation", cxxopts::value(VTEST)->default_value("false")) - ("Vquiet", "Number of angular points on a regular spherical grid (0 means no quiet)", - cxxopts::value(Vquiet)->default_value("0")) + ("Nangle", "Number of angular points on a regular spherical grid (0 skips this algorithm). Nangle>0 takes precidence over other algorithms.", + cxxopts::value(Nangle)->default_value("0")) + ("Nrepl", "Number of replicates in orbital plane (1 skips the Sellwood 1997 algorithm)", + cxxopts::value(Nrepl)->default_value("1")) + ("Nfib", "Number of points on the sphere for each orbit. Replicate the orbits by tiling the angular momentum direction on the sphere using a Fibonnaci sequence. Default value of 1 implies one plane per orbit.", + cxxopts::value(Nfib)->default_value("1")) ("Emin0", "Minimum energy (if ELIMIT=true)", cxxopts::value(Emin0)->default_value("-3.0")) ("Emax0", "Maximum energy (if ELIMIT=true)", @@ -257,7 +263,15 @@ main(int argc, char **argv) if (vm.count("verbose")) VERBOSE = true; else VERBOSE = false; - if (vm.count("Fibonacci")) FIB = true; + // Use Fibonnaci for space-filling grid points + // + if (Nangle>0) { + Nfib = Nrepl = 1; + } + else { + Nfib = std::max(1, Nfib ); + Nrepl = std::max(1, Nrepl); + } // Prepare output streams and create new files // @@ -525,15 +539,34 @@ main(int argc, char **argv) } - int nradial=0, nphi=0, ncost=0; - if (Vquiet) { - nphi = 2*Vquiet; // # of aximuthal angles - ncost = Vquiet; // # of colatitude angles - // # of radial shells - nradial = floor(N/(nphi*ncost)); + int nfib=0, nangle=0, nshell=0; + if (Nangle) { + nangle = Nangle; + nfib = floor(sqrt(double(N)/(nangle*nangle))); + nshell = nfib*nangle; - // Reset N to fill all spherical shells - N = nradial*nphi*ncost; + // Shells in radius and velocity + // + N = nshell*nshell; + if (myid==0) + std::cout << std::setw(60) << std::setfill('-') << '-' + << std::setfill(' ') << std::endl + << "Fibonacci: N=" << N << " Nangle=" << Nangle + << " Nmag=" << nfib << " Nshell=" << nshell<< std::endl; + } + + // For replication algorithm; Nrepl=1 is the standard algorithm. + // + Nrepl *= Nfib; + int nplane = N/Nrepl; + N = Nrepl * nplane; + NREPORT = std::max(1, NREPORT/Nrepl); + + if (Nrepl > 1 and myid==0) { + std::cout << std::setw(60) << std::setfill('-') << '-' + << std::setfill(' ') << std::endl + << "Replication: N=" << N << " Nrepl=" << Nrepl/Nfib + << " Nfib=" << Nfib << " Norbits=" << nplane << std::endl; } double mass = hmodel->get_mass(hmodel->get_max_radius())/N; @@ -707,28 +740,29 @@ main(int argc, char **argv) double TT=0.0, WW=0.0, VC=0.0; if (myid==0) - std::cout << "-----------" << std::endl + std::cout << std::setw(60) << std::setfill('-') << '-' << std::endl + << std::setfill('-') << "Body count:" << std::endl; - int npernode = N/numprocs; + int npernode = nplane/numprocs; int beg = myid*npernode; int end = beg + npernode; - if (myid==numprocs-1) end = N; + if (myid==numprocs-1) end = nplane; std::vector PS; Eigen::VectorXd zz = Eigen::VectorXd::Zero(7); std::vector rmass; - if (Vquiet) { - rmass.resize(nradial); + if (Nangle) { + rmass.resize(nfib); // Set up mass grid double rmin = hmodel->get_min_radius(); double rmax = hmodel->get_max_radius(); double mmas = hmodel->get_mass(rmax); - double dmas = mmas/nradial; - for (int i=0; i double { return (mas - hmodel->get_mass(r)); }; @@ -736,34 +770,38 @@ main(int argc, char **argv) } } + constexpr double goldenRatio = 0.5*(1.0 + sqrt(5.0)); + for (int n=beg; n=0 && nr=0 && nt=0 && np=0 && nspace=0 && nveloc=0 && rmgen_point(r, acos(cost), phi); + double PHI = 2.0*M_PI * nr / goldenRatio; + double COST = 1.0 - 2.0 * nr / nangle; + double THETA = acos(COST) + 0.5*M_PI; + + // Get velocity coorindates + std::tie(ps, ierr) = rmodel->gen_point_iso(r, acos(cost), phi, + nveloc, nfib, nangle, + PHI, THETA, PHI); for (int i=0; i<3; i++) { if (std::isnan(ps[i+3])) { @@ -792,39 +830,156 @@ main(int argc, char **argv) if (ps[0] <= 0.0) negms++; - double RR=0.0; - for (int i=1; i<=3; i++) { - RR += ps[i]*ps[i]; - TT += 0.5*mass*ps[0]*ps[3+i]*ps[3+i]; - } - RR = sqrt(RR); - if (RR>=rmin) { - VC += -mass*ps[0]*rmodel->get_mass(RR)/RR; - WW += 0.5*mass*ps[0]*rmodel->get_pot(RR); - } + Eigen::Vector3d pos(ps[1], ps[2], ps[3]), pos1; + Eigen::Vector3d vel(ps[4], ps[5], ps[6]), vel1; + Eigen::Matrix3d proj, Iprj, rot = Eigen::Matrix3d::Identity(); + Eigen::Matrix3d projM, IprjM; - if (zeropos or zerovel) { - ps[0] *= mass; - PS.push_back(ps); - zz[0] += ps[0]; - if (zeropos) for (int i=1; i<3; i++) zz[i] -= ps[0]*ps[i]; - if (zerovel) for (int i=4; i<7; i++) zz[i] -= ps[0]*ps[i]; + double dq = 2.0*M_PI * Nfib / Nrepl, mfac = ps[0]; + + // Compute orbital plane basis + // + if (Nrepl>1) { + auto L = pos.cross(vel); // The angular momentum vector + if (pos.norm() < 1.0e-10 or L.norm() < 1.0e-10) { + proj = Iprj = Eigen::Matrix3d::Identity(); + } else { + auto X = pos/pos.norm(); // Radial unit vector, X. + auto Y = L.cross(X); // Choose a right-hand3d coordinate + Y = Y/Y.norm(); // system perpendicular to X and L. + auto Z = L/L.norm(); // Unit vector in the ang. mom. direction. + + // Azimuth of vertical plane containing L + double Phi = atan2(Z(1), Z(0)) + 0.5*M_PI; + + // Tilt of plane w.r.t to polar axis + double Theta = acos(Z(2)); + + // Location of X in orbital plane w.r.t line of nodes + Eigen::Vector3d lon(cos(Phi), sin(Phi), 0.0); + double dotp = lon.dot(X); + double Psi = acos(dotp); + auto dir = lon.cross(X); + + proj.row(0) = X; // Project to orbital plane frame + proj.row(1) = Y; + proj.row(2) = Z; + + Iprj.col(0) = X; // Project from orbital plane to original + Iprj.col(1) = Y; + Iprj.col(2) = Z; + + if (Nfib>1) { + // Quadrant geometry + int sgn1 = 1, sgn2 = 1; + if (Theta > 0.5*M_PI) sgn1 = -1; + if (dir(2) < 0.0) sgn2 = -1; + + // Sanity check for debugging + if (true) { + double norm = 0.0; + if (sgn1*sgn2==1) + norm = (proj - return_euler(Phi, Theta, Psi, 0)).norm(); + else + norm = (proj - return_euler(Phi, Theta, -Psi, 0)).norm(); + + if (fabs(norm) > 1.0e-10) { + std::cout << "Theta=" << Theta + << " dir(2)=" << dir(2) << std::endl; + } + } + + if (sgn1*sgn2==1) { + projM = return_euler(Phi, -Theta, Psi, 0); + IprjM = return_euler(Phi, -Theta, Psi, 1); + } else { + projM = return_euler(Phi, -Theta, -Psi, 0); + IprjM = return_euler(Phi, -Theta, -Psi, 1); + } + } + } } - else { - out << std::setw(20) << mass * ps[0]; - for (int i=1; i<=6; i++) out << std::setw(20) << ps[i]+ps0[i]; - if (NI) { - for (int n=0; n=rmin) { + VC += -mass*ps[0]*rmodel->get_mass(RR)/RR; + WW += 0.5*mass*ps[0]*rmodel->get_pot(RR); } - out << std::endl; + if (zeropos or zerovel) { + ps[0] *= mass; + PS.push_back(ps); + zz[0] += ps[0]; + if (zeropos) for (int i=1; i<3; i++) zz[i] -= ps[0]*ps[i]; + if (zerovel) for (int i=4; i<7; i++) zz[i] -= ps[0]*ps[i]; + } + else { + out << std::setw(20) << mass * ps[0]; + for (int i=1; i<=6; i++) out << std::setw(20) << ps[i]+ps0[i]; + + if (NI) { + for (int n=0; n1) { + + Eigen::Matrix3d invt; + double Q = dq*(q/Nfib+1), phi=0.0, cost=0.0; + int nfib = q % Nfib; + + if (Nfib>1) { + phi = 2.0*M_PI * nfib / goldenRatio; + cost = 1.0 - 2.0 * nfib/Nfib; + cost = (cost < -1.0 ? -1.0 : (cost > 1.0 ? 1.0 : cost)); + invt = return_euler(phi, acos(cost), 0, 1); + } + + // Update rotation matrix + rot(0, 0) = rot(1, 1) = cos(Q); + rot(0, 1) = -sin(Q); + rot(1, 0) = sin(Q); + + // Full rotation matrix + Eigen::Matrix3d trans; + if (Nfib>1) trans = invt * rot * proj; + else trans = Iprj * rot * proj; + + // Rotate position and velocity + pos1 = trans * pos; + vel1 = -trans * vel; + + // Reset the phase-space vector + // + ps[0] = mfac; + + ps[1] = pos1(0); + ps[2] = pos1(1); + ps[3] = pos1(2); + + ps[4] = vel1(0); + ps[5] = vel1(1); + ps[6] = vel1(2); + } } - if (myid==0 and !((n+1)%NREPORT)) cout << '\r' << (n+1)*numprocs << flush; + if (myid==0 and !((n+1)%NREPORT)) cout << '\r' << (n+1)*numprocs*Nrepl + << flush; } if (zeropos or zerovel) { @@ -864,16 +1019,20 @@ main(int argc, char **argv) MPI_Reduce(MPI_IN_PLACE, &WW, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); MPI_Reduce(MPI_IN_PLACE, &VC, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); - cout << std::endl << "-----------" << std::endl << std::endl; - cout << std::setw(20) << "States rejected: " << count << std::endl; - cout << std::setw(20) << "Negative masses: " << negms << std::endl; - cout << std::setw(60) << setfill('-') << '-' << std::endl << setfill(' '); - cout << std::setw(20) << "KE=" << TT << std::endl; - cout << std::setw(20) << "PE=" << WW << std::endl; - cout << std::setw(20) << "VC=" << VC << std::endl; - cout << std::setw(20) << "Ratio (-2T/W)=" << -2.0*TT/WW << std::endl; - cout << std::setw(20) << "Ratio (-2T/C)=" << -2.0*TT/VC << std::endl; - std::cout << std::setw(60) << std::setfill('-') << '-' << std::endl << std::setfill(' '); + std::cout << std::endl + << std::setw(60) << std::setfill('-') << '-' << std::endl + << std::setfill(' ') + << std::setw(20) << "States rejected: " << count << std::endl + << std::setw(20) << "Negative masses: " << negms << std::endl + << std::setw(60) << setfill('-') << '-' << std::endl + << setfill(' ') + << std::setw(20) << "KE=" << TT << std::endl + << std::setw(20) << "PE=" << WW << std::endl + << std::setw(20) << "VC=" << VC << std::endl + << std::setw(20) << "Ratio (-2T/W)=" << -2.0*TT/WW << std::endl + << std::setw(20) << "Ratio (-2T/C)=" << -2.0*TT/VC << std::endl + << std::setw(60) << std::setfill('-') << '-' << std::endl + << std::setfill(' '); } out.close(); From 8539dc51ceceb3144e1ff2020e1e55ad3405d641 Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Tue, 21 Jan 2025 15:28:57 -0500 Subject: [PATCH 08/12] Make goldenRatio a const rather than a constexpr --- exputil/realize_model.cc | 3 ++- utils/ICs/gensph.cc | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/exputil/realize_model.cc b/exputil/realize_model.cc index 3b2361adb..14ffc230c 100644 --- a/exputil/realize_model.cc +++ b/exputil/realize_model.cc @@ -799,7 +799,8 @@ AxiSymModel::PSret AxiSymModel::gen_point_3d_iso // Fibonacci lattice for velocities // - constexpr double goldenRatio = 0.5*(1.0 + sqrt(5.0)); + const double goldenRatio = 1.618033988749895; + double vphi = 2.0*M_PI * ja / goldenRatio; double vcost = 1.0 - 2.0*ja/na; double vsint = sqrt(fabs(1.0 - vcost*vcost)); diff --git a/utils/ICs/gensph.cc b/utils/ICs/gensph.cc index 9541ee21f..c5aa441a7 100644 --- a/utils/ICs/gensph.cc +++ b/utils/ICs/gensph.cc @@ -78,6 +78,8 @@ main(int argc, char **argv) bool VTEST; std::string INFILE, MMFILE, OUTFILE, OUTPS, config; + const double goldenRatio = 1.618033988749895; + #ifdef DEBUG set_fpu_handler(); #endif @@ -770,8 +772,6 @@ main(int argc, char **argv) } } - constexpr double goldenRatio = 0.5*(1.0 + sqrt(5.0)); - for (int n=beg; n Date: Fri, 24 Jan 2025 13:18:32 -0500 Subject: [PATCH 09/12] Print mismatched cache variables --- exputil/EmpCyl2d.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/exputil/EmpCyl2d.cc b/exputil/EmpCyl2d.cc index efd29bcdf..fac8f21b5 100644 --- a/exputil/EmpCyl2d.cc +++ b/exputil/EmpCyl2d.cc @@ -780,19 +780,31 @@ bool EmpCyl2d::ReadH5Cache() auto checkInt = [&file](int value, std::string name) { int v; HighFive::Attribute vv = file.getAttribute(name); vv.read(v); - if (value == v) return true; return false; + if (value == v) return true; + if (myid==0) std::cout << "---- EmpCyl2d::ReadH5Cache: " + << name << " expected " << value << " but found " + << v << std::endl; + return false; }; auto checkDbl = [&file](double value, std::string name) { double v; HighFive::Attribute vv = file.getAttribute(name); vv.read(v); - if (fabs(value - v) < 1.0e-16) return true; return false; + if (fabs(value - v) < 1.0e-16) return true; + if (myid==0) std::cout << "---- EmpCyl2d::ReadH5Cache: " + << name << " expected " << value << " but found " + << v << std::endl; + return false; }; auto checkStr = [&file](std::string value, std::string name) { std::string v; HighFive::Attribute vv = file.getAttribute(name); vv.read(v); - if (value.compare(v)==0) return true; return false; + if (value.compare(v)==0) return true; + if (myid==0) std::cout << "---- EmpCyl2d::ReadH5Cache: " + << name << " expected " << value << " but found " + << v << std::endl; + return false; }; // From 95d9a9985542d32501a7c55ac8cca31befcabd23 Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Fri, 24 Jan 2025 13:18:56 -0500 Subject: [PATCH 10/12] Add quiet-start method --- utils/ICs/ZangICs.cc | 52 +++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/utils/ICs/ZangICs.cc b/utils/ICs/ZangICs.cc index 638c6c755..660a7633c 100644 --- a/utils/ICs/ZangICs.cc +++ b/utils/ICs/ZangICs.cc @@ -27,6 +27,7 @@ main(int ac, char **av) //===================== int N; // Number of particles + int Nrepl; // Number of particle replicates per orbit double mu, nu, Ri, Ro; // Taper paramters double Rmin, Rmax; // Radial range double sigma; // Velocity dispersion @@ -59,6 +60,8 @@ main(int ac, char **av) cxxopts::value(sigma)->default_value("1.0")) ("s,seed", "Random number seed. Default: use /dev/random", cxxopts::value(seed)) + ("q,Nrepl", "Number of particle replicates per orbit", + cxxopts::value(Nrepl)->default_value("1")) ("f,file", "Output body file", cxxopts::value(bodyfile)->default_value("zang.bods")) ; @@ -84,6 +87,10 @@ main(int ac, char **av) seed = std::random_device{}(); } + // Set particle number consitent with even replicants + if (Nrepl<1) Nrepl = 1; + if (Nrepl>1) N = (N/Nrepl)*Nrepl; + // Make sure N>0 if (N<=0) { std::cerr << av[0] << ": you must requiest at least one body" @@ -107,6 +114,11 @@ main(int ac, char **av) 1.0, Rmin, Rmax); model->setup_df(sigma); + // Replicant logic + // + int Number = N/Nrepl; + double dPhi = 2.0*M_PI/Nrepl; + // Progress bar // std::shared_ptr progress; @@ -115,7 +127,7 @@ main(int ac, char **av) { nomp = omp_get_num_threads(); if (omp_get_thread_num()==0) { - progress = std::make_shared(N/nomp); + progress = std::make_shared(Number/nomp); } } @@ -190,7 +202,7 @@ main(int ac, char **av) // Generation loop with OpenMP // #pragma omp parallel for reduction(+:over) - for (int n=0; n M_PI) vr *= -1.0; // Branch of radial motion - // Convert from polar to Cartesian - // - pos[n][0] = r*cos(phi); - pos[n][1] = r*sin(phi); - pos[n][2] = 0.0; - - vel[n][0] = vr*cos(phi) - vt*sin(phi); - vel[n][1] = vr*sin(phi) + vt*cos(phi); - vel[n][2] = 0.0; - - // Accumulate mean position and velocity - // - for (int k=0; k<3; k++) { - zeropos[tid][k] += pos[n][k]; - zerovel[tid][k] += vel[n][k]; + for (int nn=0; nn Date: Tue, 4 Feb 2025 16:29:23 -0500 Subject: [PATCH 11/12] Report cache name tagged for recomputation --- exputil/EmpCyl2d.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exputil/EmpCyl2d.cc b/exputil/EmpCyl2d.cc index fac8f21b5..37f36cfb0 100644 --- a/exputil/EmpCyl2d.cc +++ b/exputil/EmpCyl2d.cc @@ -815,8 +815,8 @@ bool EmpCyl2d::ReadH5Cache() if (not checkStr(Version, "Version")) return false; } else { if (myid==0) - std::cout << "---- EmpCyl2d::ReadH5Cache: " - << "recomputing cache for HighFive API change" + std::cout << "---- EmpCyl2d::ReadH5Cache: " << "<" << cache_name_2d + << "> recomputing cache for HighFive API change" << std::endl; return false; } From 72fc23b17fa5735a827f55dbb10d5271458b8a0a Mon Sep 17 00:00:00 2001 From: "Martin D. Weinberg" Date: Wed, 19 Feb 2025 19:12:28 -0500 Subject: [PATCH 12/12] Removed the angle-only quick start for the sphere, which leaves too much even-order noise to be worth keeping --- utils/ICs/gensph.cc | 78 +++------------------------------------------ 1 file changed, 4 insertions(+), 74 deletions(-) diff --git a/utils/ICs/gensph.cc b/utils/ICs/gensph.cc index c5aa441a7..045d48f28 100644 --- a/utils/ICs/gensph.cc +++ b/utils/ICs/gensph.cc @@ -69,7 +69,7 @@ int main(int argc, char **argv) { int HMODEL, N, NUMDF, NUMR, NUMJ, NUME, NUMG, NREPORT, SEED, ITMAX; - int NUMMODEL, RNUM, DIVERGE, DIVERGE2, LINEAR, NUMINT, NI, ND, Nangle; + int NUMMODEL, RNUM, DIVERGE, DIVERGE2, LINEAR, NUMINT, NI, ND; int Nrepl=1, Nfib=1; double DIVERGE_RFAC, DIVERGE_RFAC2, NN, MM, RA, RMODMIN, RMOD, EPS; double X0, Y0, Z0, U0, V0, W0, TOLE; @@ -184,8 +184,6 @@ main(int argc, char **argv) cxxopts::value(ELIMIT)->default_value("false")) ("VTEST", "Test gen_velocity() generation", cxxopts::value(VTEST)->default_value("false")) - ("Nangle", "Number of angular points on a regular spherical grid (0 skips this algorithm). Nangle>0 takes precidence over other algorithms.", - cxxopts::value(Nangle)->default_value("0")) ("Nrepl", "Number of replicates in orbital plane (1 skips the Sellwood 1997 algorithm)", cxxopts::value(Nrepl)->default_value("1")) ("Nfib", "Number of points on the sphere for each orbit. Replicate the orbits by tiling the angular momentum direction on the sphere using a Fibonnaci sequence. Default value of 1 implies one plane per orbit.", @@ -267,13 +265,8 @@ main(int argc, char **argv) // Use Fibonnaci for space-filling grid points // - if (Nangle>0) { - Nfib = Nrepl = 1; - } - else { - Nfib = std::max(1, Nfib ); - Nrepl = std::max(1, Nrepl); - } + Nfib = std::max(1, Nfib ); + Nrepl = std::max(1, Nrepl); // Prepare output streams and create new files // @@ -542,20 +535,6 @@ main(int argc, char **argv) } int nfib=0, nangle=0, nshell=0; - if (Nangle) { - nangle = Nangle; - nfib = floor(sqrt(double(N)/(nangle*nangle))); - nshell = nfib*nangle; - - // Shells in radius and velocity - // - N = nshell*nshell; - if (myid==0) - std::cout << std::setw(60) << std::setfill('-') << '-' - << std::setfill(' ') << std::endl - << "Fibonacci: N=" << N << " Nangle=" << Nangle - << " Nmag=" << nfib << " Nshell=" << nshell<< std::endl; - } // For replication algorithm; Nrepl=1 is the standard algorithm. // @@ -756,60 +735,11 @@ main(int argc, char **argv) Eigen::VectorXd zz = Eigen::VectorXd::Zero(7); std::vector rmass; - if (Nangle) { - rmass.resize(nfib); - - // Set up mass grid - double rmin = hmodel->get_min_radius(); - double rmax = hmodel->get_max_radius(); - double mmas = hmodel->get_mass(rmax); - double dmas = mmas/nfib; - for (int i=0; i double - { return (mas - hmodel->get_mass(r)); }; - rmass[i] = zbrent(loc, rmin, rmax, 1.0e-8); - } - } for (int n=beg; n=0 && nspace=0 && nveloc=0 && rmgen_point_iso(r, acos(cost), phi, - nveloc, nfib, nangle, - PHI, THETA, PHI); - - for (int i=0; i<3; i++) { - if (std::isnan(ps[i+3])) { - std::cout << "Vel NaN with r=" << r << " cost=" << cost << " phi=" << phi << std::endl; - } - } - } - else if (ELIMIT) + if (ELIMIT) std::tie(ps, ierr) = rmodel->gen_point(Emin0, Emax0, Kmin0, Kmax0); else if (VTEST) { std::tie(ps, ierr) = rmodel->gen_point();