diff --git a/.gitignore b/.gitignore index 319d66928..122f619cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ build/* +_codeql_build_dir/ Makefile *.lo @@ -25,3 +26,5 @@ src/exp src/user/CylindricalDisk.cc src/user/EllipsoidForce.cc src/user/SLSphere.cc +_codeql_build_dir +_codeql_detected_source_root diff --git a/expui/BiorthBasis.H b/expui/BiorthBasis.H index 7f4528966..f772ad9ba 100644 --- a/expui/BiorthBasis.H +++ b/expui/BiorthBasis.H @@ -1044,7 +1044,7 @@ namespace BasisClasses int lmaxfid, nmaxfid, mmax, mlim, nmax; int ncylodd, ncylnx, ncylny, ncylr, cmap, cmapR, cmapZ, vflag; int rnum, pnum, tnum; - double rcylmin, rcylmax, acyl, hcyl; + double rcylmin, rcylmax, acyl, hcyl, bias; bool expcond, logarithmic, density, EVEN_M, sech2 = true; std::vector potd, dpot, dpt2, dend; diff --git a/expui/BiorthBasis.cc b/expui/BiorthBasis.cc index 56d732e11..b7723992f 100644 --- a/expui/BiorthBasis.cc +++ b/expui/BiorthBasis.cc @@ -1186,6 +1186,7 @@ namespace BasisClasses "rcylmin", "rcylmax", "acyl", + "bias", "hcyl", "sech2", "snr", @@ -1376,6 +1377,7 @@ namespace BasisClasses rcylmin = 0.001; rcylmax = 20.0; acyl = 0.01; + bias = 1.0; hcyl = 0.002; nmax = 18; mmax = 6; @@ -1400,7 +1402,7 @@ namespace BasisClasses EVEN_M = false; cmapR = 1; cmapZ = 1; - mtype = "exponential"; + mtype = "Exponential"; dtype = "exponential"; vflag = 0; @@ -1454,6 +1456,7 @@ namespace BasisClasses if (conf["rcylmax" ]) rcylmax = conf["rcylmax" ].as(); if (conf["acyl" ]) acyl = conf["acyl" ].as(); + if (conf["bias" ]) bias = conf["bias" ].as(); if (conf["hcyl" ]) hcyl = conf["hcyl" ].as(); if (conf["sech2" ]) sech2 = conf["sech2" ].as(); if (conf["lmaxfid" ]) lmaxfid = conf["lmaxfid" ].as(); @@ -1540,6 +1543,17 @@ namespace BasisClasses pnum = std::max(1, pnum); tnum = std::max(10, tnum); + // Validate bias parameter + // + if (!std::isfinite(bias)) { + throw std::runtime_error("Cylindrical: 'bias' parameter must be finite"); + } + if (bias <= 0.0) { + std::ostringstream sout; + sout << "Cylindrical: 'bias' parameter must be positive, got " << bias; + throw std::runtime_error(sout.str()); + } + EmpCylSL::RMIN = rcylmin; EmpCylSL::RMAX = rcylmax; EmpCylSL::NUMX = ncylnx; @@ -1550,6 +1564,40 @@ namespace BasisClasses EmpCylSL::logarithmic = logarithmic; EmpCylSL::VFLAG = vflag; + // Set deprojected model type + // + // Convert mtype string to lower case + std::transform(mtype.begin(), mtype.end(), mtype.begin(), + [](unsigned char c){ return std::tolower(c); }); + + // Set EmpCylSL mtype. This is the spherical function used to + // generate the EOF basis. If "deproject" is set, this will be + // overriden in EmpCylSL. + // + EmpCylSL::mtype = EmpCylSL::Exponential; // Default + if (mtype.compare("exponential")==0) { + EmpCylSL::mtype = EmpCylSL::Exponential; + if (myid==0) { + std::cout << "---- Cylindrical: using original exponential deprojected disk for EOF conditioning" << std::endl; + std::cout << "---- Cylindrical: consider using the exact, spherically deprojected exponential with 'mtype: ExpSphere'" << std::endl; + } + } else if (mtype.compare("expsphere")==0) + EmpCylSL::mtype = EmpCylSL::ExpSphere; + else if (mtype.compare("gaussian")==0) + EmpCylSL::mtype = EmpCylSL::Gaussian; + else if (mtype.compare("plummer")==0) + EmpCylSL::mtype = EmpCylSL::Plummer; + else if (mtype.compare("power")==0) { + EmpCylSL::mtype = EmpCylSL::Power; + EmpCylSL::PPOW = ppow; + } else { + if (myid==0) std::cout << "No EmpCylSL EmpModel named <" + << mtype << ">, valid types are: " + << "Exponential, ExpSphere, Gaussian, Plummer, Power " + << "(not case sensitive)" << std::endl; + throw std::runtime_error("Cylindrical:initialize: EmpCylSL bad parameter"); + } + // Check for non-null cache file name. This must be specified // to prevent recomputation and unexpected behavior. // @@ -1565,7 +1613,7 @@ namespace BasisClasses // Make the empirical orthogonal basis instance // sl = std::make_shared - (nmaxfid, lmaxfid, mmax, nmax, acyl, hcyl, ncylodd, cachename); + (nmaxfid, lmaxfid, mmax, nmax, bias*acyl, hcyl, ncylodd, cachename); // Set azimuthal harmonic order restriction? // @@ -1598,33 +1646,6 @@ namespace BasisClasses << "---- remove 'ignore' from your YAML configuration." << std::endl; } - // Convert mtype string to lower case - // - std::transform(mtype.begin(), mtype.end(), mtype.begin(), - [](unsigned char c){ return std::tolower(c); }); - - // Set EmpCylSL mtype. This is the spherical function used to - // generate the EOF basis. If "deproject" is set, this will be - // overriden in EmpCylSL. - // - EmpCylSL::mtype = EmpCylSL::Exponential; - if (mtype.compare("exponential")==0) - EmpCylSL::mtype = EmpCylSL::Exponential; - else if (mtype.compare("gaussian")==0) - EmpCylSL::mtype = EmpCylSL::Gaussian; - else if (mtype.compare("plummer")==0) - EmpCylSL::mtype = EmpCylSL::Plummer; - else if (mtype.compare("power")==0) { - EmpCylSL::mtype = EmpCylSL::Power; - EmpCylSL::PPOW = ppow; - } else { - if (myid==0) std::cout << "No EmpCylSL EmpModel named <" - << mtype << ">, valid types are: " - << "Exponential, Gaussian, Plummer, Power " - << "(not case sensitive)" << std::endl; - throw std::runtime_error("Cylindrical:initialize: EmpCylSL bad parameter"); - } - // Convert dtype string to lower case // std::transform(dtype.begin(), dtype.end(), dtype.begin(), @@ -5184,6 +5205,7 @@ namespace BasisClasses file.createAttribute("rcylmin", HighFive::DataSpace::From(rcylmin)).write(rcylmin); file.createAttribute("rcylmax", HighFive::DataSpace::From(rcylmax)).write(rcylmax); file.createAttribute("acyl", HighFive::DataSpace::From(acyl)).write(acyl); + file.createAttribute("bias", HighFive::DataSpace::From(bias)).write(bias); file.createAttribute("hcyl", HighFive::DataSpace::From(hcyl)).write(hcyl); } diff --git a/exputil/CMakeLists.txt b/exputil/CMakeLists.txt index 0a029c2ec..1124b101e 100644 --- a/exputil/CMakeLists.txt +++ b/exputil/CMakeLists.txt @@ -11,7 +11,7 @@ set(QUAD_SRC qadapt.cc gauleg.cc qadapt2d.cc gint2.cc rombe2d.cc set(UTIL_SRC nrutil.cc elemfunc.cc euler.cc euler_slater.cc rotmatrix.cc wordSplit.cc FileUtils.cc BarrierWrapper.cc stack.cc localmpi.cc TableGrid.cc writePVD.cc libvars.cc - TransformFFT.cc QDHT.cc YamlCheck.cc # Hankel.cc + TransformFFT.cc QDHT.cc YamlCheck.cc ExpDeproj.cc # Hankel.cc parseVersionString.cc EXPmath.cc laguerre_polynomial.cpp YamlConfig.cc orthoTest.cc OrthoFunction.cc VtkGrid.cc Sutils.cc fpetrap.cc) diff --git a/exputil/EmpCylSL.cc b/exputil/EmpCylSL.cc index f3b73b841..2b84bee38 100644 --- a/exputil/EmpCylSL.cc +++ b/exputil/EmpCylSL.cc @@ -17,6 +17,7 @@ #include #include "exp_thread.h" #include "EXPException.H" +#include "ExpDeproj.H" #include "exputils.H" #include @@ -73,6 +74,7 @@ EmpCylSL::EmpModel EmpCylSL::mtype = Exponential; std::map EmpCylSL::EmpModelLabs = { {Exponential, "Exponential"}, + {ExpSphere, "ExpSphere" }, {Gaussian, "Gaussian" }, {Plummer, "Plummer" }, {Power, "Power" }, @@ -552,6 +554,9 @@ double EmpCylSL::massR(double R) case Exponential: ans = 1.0 - (1.0 + R)*exp(-R); break; + case ExpSphere: + ans = expdeproj.mass(R); + break; case Gaussian: arg = 0.5*R*R; ans = 1.0 - exp(-arg); @@ -589,6 +594,9 @@ double EmpCylSL::densR(double R) case Exponential: ans = exp(-R)/(4.0*M_PI*R); break; + case ExpSphere: + ans = expdeproj.density(R); + break; case Gaussian: arg = 0.5*R*R; ans = exp(-arg)/(4.0*M_PI*R); @@ -2403,6 +2411,15 @@ void EmpCylSL::generate_eof(int numr, int nump, int numt, int cntr = 0; // Loop counter for spreading load to nodes + // Debug info output + // + if (VFLAG & 8 && myid==0) { + std::cout << "---- EmpCylSL: Generating EOF with" + << " Rmin=" << xi_to_r(XMIN) + << " Rmax=" << xi_to_r(XMAX) + << " numt=" << numt << std::endl; + } + // *** Radial quadrature loop // for (int qr=0; qr +#include +#include +#include +#include +#include +#include +#include +#include + +#include "EXPmath.H" + + +void ExpDeproj::initialize() +{ + if (ngrid < 2) { + throw std::invalid_argument("n must be at least 2"); + } + + rv.resize(ngrid); + mv.resize(ngrid); + + std::vector dv(ngrid); + + double log_rmin = std::log(rmin); + double log_rmax = std::log(rmax); + double dlogr = (log_rmax - log_rmin)/static_cast(ngrid - 1); + + for (int i = 0; i < ngrid; ++i) { + rv[i] = std::exp(log_rmin + i*dlogr); + dv[i] = 4.0*M_PI*rv[i]*rv[i]*density(rv[i]); + } + + mv[0] = 0.0; + for (int i=1; i rmax) return mv.back(); + + auto it = std::lower_bound(rv.begin(), rv.end(), R); + // If R is slightly larger than the largest grid point due to rounding, + // lower_bound may return rv.end(); in that case, use the last mass value. + if (it == rv.end()) { + return mv.back(); + } + + std::size_t idx = static_cast(std::distance(rv.begin(), it)); + if (idx >= rv.size()) { + // Defensive guard; should not happen after the it == rv.end() check. + return mv.back(); + } + if (rv[idx] == R) { + return mv[idx]; + } else { + // Ensure idx-1 is valid + if (idx == 0) idx++; + // Linear interpolation + double x0 = rv[idx-1]; + double x1 = rv[idx ]; + double y0 = mv[idx-1]; + double y1 = mv[idx ]; + + return y0 + (y1 - y0)*(R - x0)/(x1 - x0); + } +} diff --git a/include/EmpCylSL.H b/include/EmpCylSL.H index 3ccb6fe38..9811a0059 100644 --- a/include/EmpCylSL.H +++ b/include/EmpCylSL.H @@ -18,6 +18,7 @@ #include #endif +#include "ExpDeproj.H" #include "Particle.H" #include "SLGridMP2.H" #include "coef.H" @@ -81,6 +82,9 @@ protected: int rank2, rank3; + //! Precomputed exponential deprojection profile + ExpDeproj expdeproj; + //@{ //! Storage buffers for MPI std::vector MPIin, MPIout, MPIin2, MPIout2; @@ -364,6 +368,7 @@ public: //! Type of density model to use enum EmpModel { Exponential, + ExpSphere, Gaussian, Plummer, Power, @@ -427,7 +432,21 @@ public: //! No extrapolating beyond grid (default: false) static bool enforce_limits; - //! Density model type + /** + @brief Density model type + Available options: + - Exponential = approximate exponential disk deprojection + - ExpSphere = exact exponential spherical deprojection + - Gaussian = Gaussian sphere + - Plummer = Plummer sphere + - Power = power-law sphere + - Deproject = numerical deprojection of axisymmetric disk surface density (see create_deprojection) + + @note The default option is Exponential for backwards + compatibility. The ExpSphere is the exact spherical deproject + for the exponential disk and should be used instead of + Exponential for new projects. + */ static EmpModel mtype; //! Radial basis grid in radial direction diff --git a/include/ExpDeproj.H b/include/ExpDeproj.H new file mode 100644 index 000000000..a0ff35659 --- /dev/null +++ b/include/ExpDeproj.H @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +class ExpDeproj +{ + const double rmin = 1.0e-4; + const double rmax = 30.0; + + // Precomputed radial grid + int ngrid; + std::vector rv, mv; + void initialize(); + +public: + //! Constructor + ExpDeproj(int n=4000) : ngrid(n) { initialize(); } + + //! Destructor + virtual ~ExpDeproj() {} + + //! Density profile at radius R + double density(double R); + + //! Enclosed mass at radius R + double mass(double R); +}; diff --git a/src/Cylinder.H b/src/Cylinder.H index 5cadda2f8..897427d01 100644 --- a/src/Cylinder.H +++ b/src/Cylinder.H @@ -35,6 +35,8 @@ class MixtureBasis; @param acyl is the scale length + @param bias is the O(1) bias correction for deprojected scale length + @param hcyl is the scale height @param lmaxfid is the maximum spherical harmonic index for EOF construction @@ -112,6 +114,13 @@ class MixtureBasis; @param cmapz is the vertical coordinate mapping type + @param mtype is the deprojected model type for conditioning the + basis. See ExpCylSL::mtype for options. + + @param ppower is the power-law index for the Power spherical model + used as the deprojected model for basis conditioning (default: 2.0). + Only used when mtype is set to the Power model. + @param self_consistent set to false turns off potential expansion; only performed the first time @@ -151,7 +160,7 @@ private: void initialize(void); // Parameters - double rcylmin, rcylmax, zmax, acyl; + double rcylmin, rcylmax, zmax, acyl, bias; int nmaxfid, lmaxfid, mmax, mlim, nint; int ncylnx, ncylny, ncylr; double hcyl, hexp, snr, rem; @@ -333,6 +342,12 @@ protected: //! Valid keys for YAML configurations static const std::set valid_keys; + //! Power-law index for deprojected spherical model for basis conditioning + double ppow = 2.0; + + //! Deprojection model for basis conditioning + std::string mtype = "Exponential"; + //! Write basis-specific parameters to HDF5 covariance file void writeCovarH5Params(HighFive::File& file); @@ -350,6 +365,7 @@ public: //! //! Parameters settable in the configuration line include: //! \param acyl is the disk scale length for the basis + //! \param bias is the disk scale length bias factor for the basis //! \param hcyl is the disk scale height for the basis //! \param nmaxfid is the radial order for the underlying spherical basis //! \param lmaxfid is the harmonic order for the underlying spherical basis diff --git a/src/Cylinder.cc b/src/Cylinder.cc index 9c7f84203..63a5ca1d0 100644 --- a/src/Cylinder.cc +++ b/src/Cylinder.cc @@ -28,6 +28,7 @@ Cylinder::valid_keys = { "rcylmin", "rcylmax", "acyl", + "bias", "hcyl", "sech2", "hexp", @@ -70,6 +71,8 @@ Cylinder::valid_keys = { "cmapr", "cmapz", "vflag", + "mtype", + "ppower", "self_consistent", "playback", "coefCompute", @@ -107,6 +110,7 @@ Cylinder::Cylinder(Component* c0, const YAML::Node& conf, MixtureBasis *m) : ncylr = 2000; acyl = 0.01; + bias = 1.0; lmaxfid = 128; nmaxfid = 64; mmax = 6; @@ -177,10 +181,44 @@ Cylinder::Cylinder(Component* c0, const YAML::Node& conf, MixtureBasis *m) : if (cachename.size()==0) throw std::runtime_error("EmpCylSL: you must specify a cachename"); + + // Set deprojected model type + // + // Convert mtype string to lower case + std::transform(mtype.begin(), mtype.end(), mtype.begin(), + [](unsigned char c){ return std::tolower(c); }); + + // Set EmpCylSL mtype. This is the spherical function used to + // generate the EOF basis. + // + EmpCylSL::mtype = EmpCylSL::Exponential; // Default + if (mtype.compare("exponential")==0) { + EmpCylSL::mtype = EmpCylSL::Exponential; + if (myid==0) { + std::cout << "---- Cylindrical: using original exponential deprojected disk for EOF conditioning" << std::endl; + std::cout << "---- Cylindrical: consider using the exact, spherically deprojected exponential with 'mtype: ExpSphere'" << std::endl; + } + } else if (mtype.compare("expsphere")==0) + EmpCylSL::mtype = EmpCylSL::ExpSphere; + else if (mtype.compare("gaussian")==0) + EmpCylSL::mtype = EmpCylSL::Gaussian; + else if (mtype.compare("plummer")==0) + EmpCylSL::mtype = EmpCylSL::Plummer; + else if (mtype.compare("power")==0) { + EmpCylSL::mtype = EmpCylSL::Power; + EmpCylSL::PPOW = ppow; + } else { + if (myid==0) std::cout << "No EmpCylSL EmpModel named <" + << mtype << ">, valid types are: " + << "Exponential, ExpSphere, Gaussian, Plummer, Power " + << "(not case sensitive)" << std::endl; + throw std::runtime_error("Cylinder:initialize: EmpCylSL bad parameter"); + } + // Make the empirical orthogonal basis instance // ortho = std::make_shared - (nmaxfid, lmaxfid, mmax, nmax, acyl, hcyl, ncylodd, cachename); + (nmaxfid, lmaxfid, mmax, nmax, bias*acyl, hcyl, ncylodd, cachename); // Set azimuthal harmonic order restriction? // @@ -337,6 +375,7 @@ Cylinder::Cylinder(Component* c0, const YAML::Node& conf, MixtureBasis *m) : << std::endl << sep << "rcylmin=" << rcylmin << std::endl << sep << "rcylmax=" << rcylmax << std::endl << sep << "acyl=" << acyl + << std::endl << sep << "bias=" << bias << std::endl << sep << "hcyl=" << hcyl << std::endl << sep << "precond=" << precond << std::endl << sep << "pcavar=" << pcavar @@ -366,6 +405,7 @@ Cylinder::Cylinder(Component* c0, const YAML::Node& conf, MixtureBasis *m) : << std::endl << sep << "rcylmin=" << rcylmin << std::endl << sep << "rcylmax=" << rcylmax << std::endl << sep << "acyl=" << acyl + << std::endl << sep << "bias=" << bias << std::endl << sep << "hcyl=" << hcyl << std::endl << sep << "precond=" << precond << std::endl << sep << "pcavar=" << pcavar @@ -422,6 +462,7 @@ void Cylinder::initialize() if (conf["rcylmax" ]) rcylmax = conf["rcylmax" ].as(); if (conf["acyl" ]) acyl = conf["acyl" ].as(); + if (conf["bias" ]) bias = conf["bias" ].as(); if (conf["hcyl" ]) hcyl = conf["hcyl" ].as(); if (conf["sech2" ]) sech2 = conf["sech2" ].as(); if (conf["hexp" ]) hexp = conf["hexp" ].as(); @@ -464,6 +505,9 @@ void Cylinder::initialize() if (conf["cmapz" ]) cmapZ = conf["cmapz" ].as(); if (conf["vflag" ]) vflag = conf["vflag" ].as(); + if (conf["mtype" ]) mtype = conf["mtype" ].as(); + if (conf["ppower" ]) ppow = conf["ppower" ].as(); + // Deprecation warning if (not sech2 and not conf["pyname"]) { if (myid==0) diff --git a/utils/ICs/check_coefs.cc b/utils/ICs/check_coefs.cc index 47b0d25f4..b8556090b 100644 --- a/utils/ICs/check_coefs.cc +++ b/utils/ICs/check_coefs.cc @@ -418,7 +418,7 @@ main(int ac, char **av) cxxopts::value(cachefile)->default_value(".eof.cache.file")) ("disktype", "Desired disktype for analytic computation of basis (constant, gaussian, mn, exponential)", cxxopts::value(disktype)->default_value("exponential")) - ("mtype", "Desired deprojection sphericla models (Exponential, Gaussian, Plummer)", + ("mtype", "Desired deprojection spherical models (Exponential, ExpSphere, Gaussian, Plummer)", cxxopts::value(mtype)->default_value("Exponential")) ; @@ -471,21 +471,30 @@ main(int ac, char **av) } } + // Convert mtype string to lower case + // + std::transform(mtype.begin(), mtype.end(), mtype.begin(), + [](unsigned char c){ return std::tolower(c); }); + // Set EmpCylSL mtype // EmpCylSL::mtype = EmpCylSL::Exponential; if (vm.count("mtype")) { - if (mtype.compare("Exponential")==0) + if (mtype.compare("exponential")==0) EmpCylSL::mtype = EmpCylSL::Exponential; - else if (mtype.compare("Gaussian")==0) + else if (mtype.compare("expsphere")==0) + EmpCylSL::mtype = EmpCylSL::ExpSphere; + else if (mtype.compare("gaussian")==0) EmpCylSL::mtype = EmpCylSL::Gaussian; - else if (mtype.compare("Plummer")==0) { + else if (mtype.compare("plummer")==0) EmpCylSL::mtype = EmpCylSL::Plummer; + else if (mtype.compare("power")==0) { + EmpCylSL::mtype = EmpCylSL::Power; EmpCylSL::PPOW = ppower; } else { if (myid==0) std::cout << "No EmpCylSL EmpModel named <" << mtype << ">, valid types are: " - << "Exponential, Gaussian, Plummer" << std::endl; + << "Exponential, ExpSphere, Gaussian, Plummer, Power" << std::endl; MPI_Finalize(); return -1; } diff --git a/utils/ICs/check_coefs2.cc b/utils/ICs/check_coefs2.cc index 9e8f6f566..923a0edb4 100644 --- a/utils/ICs/check_coefs2.cc +++ b/utils/ICs/check_coefs2.cc @@ -419,7 +419,7 @@ main(int ac, char **av) cxxopts::value(cachefile)->default_value(".eof.cache.file")) ("disktype", "Desired disktype for analytic computation of basis (constant, gaussian, mn, exponential)", cxxopts::value(disktype)->default_value("exponential")) - ("mtype", "Desired deprojection sphericla models (Exponential, Gaussian, Plummer)", + ("mtype", "Desired deprojection spherical models (Exponential, ExpSphere, Gaussian, Plummer, Power)", cxxopts::value(mtype)->default_value("Exponential")) ("prefix", "Output file prefix", cxxopts::value(prefix)->default_value("checkcoefs2")) @@ -474,21 +474,30 @@ main(int ac, char **av) } } + // Convert mtype string to lower case + // + std::transform(mtype.begin(), mtype.end(), mtype.begin(), + [](unsigned char c){ return std::tolower(c); }); + // Set EmpCylSL mtype // EmpCylSL::mtype = EmpCylSL::Exponential; if (vm.count("mtype")) { - if (mtype.compare("Exponential")==0) + if (mtype.compare("exponential")==0) EmpCylSL::mtype = EmpCylSL::Exponential; - else if (mtype.compare("Gaussian")==0) + else if (mtype.compare("expsphere")==0) + EmpCylSL::mtype = EmpCylSL::ExpSphere; + else if (mtype.compare("gaussian")==0) EmpCylSL::mtype = EmpCylSL::Gaussian; - else if (mtype.compare("Plummer")==0) { + else if (mtype.compare("plummer")==0) { EmpCylSL::mtype = EmpCylSL::Plummer; + } else if (mtype.compare("power")==0) { + EmpCylSL::mtype = EmpCylSL::Power; EmpCylSL::PPOW = ppower; } else { if (myid==0) std::cout << "No EmpCylSL EmpModel named <" << mtype << ">, valid types are: " - << "Exponential, Gaussian, Plummer" << std::endl; + << "Exponential, ExpSphere, Gaussian, Plummer, Power" << std::endl; MPI_Finalize(); return -1; } diff --git a/utils/ICs/initial.cc b/utils/ICs/initial.cc index fc4f43c40..5f2201aa6 100644 --- a/utils/ICs/initial.cc +++ b/utils/ICs/initial.cc @@ -413,7 +413,7 @@ main(int ac, char **av) ("T,template", "Write template options file with current and all default values") ("sech2", "Use sech^2 vertical profile for disk density", cxxopts::value()->default_value("true")) - ("mtype", "EmpCylSL spherical model type (one of: Exponential, Gaussian, Plummer, Power)", + ("mtype", "EmpCylSL spherical model type (one of: Exponential, ExpSphere, Gaussian, Plummer, Power)", cxxopts::value(mtype)->default_value("Exponential")) ("ppow", "Power-law index for EmpCylSL Power spherical model", cxxopts::value(PPower)->default_value("2.0")) @@ -693,6 +693,8 @@ main(int ac, char **av) if (vm.count("mtype")) { if (mtype.compare("exponential")==0) EmpCylSL::mtype = EmpCylSL::Exponential; + else if (mtype.compare("expsphere")==0) + EmpCylSL::mtype = EmpCylSL::ExpSphere; else if (mtype.compare("gaussian")==0) EmpCylSL::mtype = EmpCylSL::Gaussian; else if (mtype.compare("plummer")==0) diff --git a/utils/Test/CMakeLists.txt b/utils/Test/CMakeLists.txt index 6d7ed3a45..5a8a6fc4b 100644 --- a/utils/Test/CMakeLists.txt +++ b/utils/Test/CMakeLists.txt @@ -1,5 +1,5 @@ -set(bin_PROGRAMS testBarrier expyaml orthoTest) +set(bin_PROGRAMS testBarrier expyaml orthoTest testED) set(common_LINKLIB OpenMP::OpenMP_CXX MPI::MPI_CXX expui exputil yaml-cpp ${VTK_LIBRARIES}) @@ -32,6 +32,7 @@ endif() add_executable(testBarrier test_barrier.cc) add_executable(expyaml test_config.cc) add_executable(orthoTest orthoTest.cc Biorth2Ortho.cc) +add_executable(testED testED.cc) foreach(program ${bin_PROGRAMS}) target_link_libraries(${program} ${common_LINKLIB}) diff --git a/utils/Test/testED.cc b/utils/Test/testED.cc new file mode 100644 index 000000000..9fb09d4dc --- /dev/null +++ b/utils/Test/testED.cc @@ -0,0 +1,55 @@ +#include +#include +#include "ExpDeproj.H" + +double projectedDensity(double R, double rmax, int nsteps, ExpDeproj & deproj) +{ + double dz = rmax / double(nsteps-1); + double sum = 0.0; + double curr = deproj.density(R), last = 0.0; + for (int i=1; i