diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/Utils/WarpXUtil.H | 29 | ||||
-rw-r--r-- | Source/Utils/WarpXUtil.cpp | 103 | ||||
-rw-r--r-- | Source/WarpX.cpp | 72 |
3 files changed, 165 insertions, 39 deletions
diff --git a/Source/Utils/WarpXUtil.H b/Source/Utils/WarpXUtil.H index 592eaa5d6..93a1f8e27 100644 --- a/Source/Utils/WarpXUtil.H +++ b/Source/Utils/WarpXUtil.H @@ -164,9 +164,21 @@ T trilinear_interp(T x0, T x1,T y0, T y1, T z0, T z1, } /** +* \brief Do a safe cast of a real to an int +* This ensures that the float value is within the range of ints and if not, +* raises an exception. +* +* \param x Real value to cast +* \param real_name String, the name of the variable being casted to use in the error message +*/ +int +safeCastToInt(amrex::Real x, const std::string& real_name); + +/** * \brief Initialize an amrex::Parser object from a string containing a math expression * * \param parse_function String to read to initialize the parser. +* \param varnames A list of predefined independent variables */ amrex::Parser makeParser (std::string const& parse_function, amrex::Vector<std::string> const& varnames); @@ -186,15 +198,20 @@ amrex::ParserExecutor<N> compileParser (amrex::Parser const* parser) * amrex::ParmParse::query reads a name and a value from the input file. This function does the * same, and applies the amrex::Parser to the value, so the user has the choice to specify a value or * a math expression (including user-defined constants). - * Only works for amrex::Real numbers, one would need another version for integers etc. + * Works for amrex::Real numbers and integers. * * \param[in] a_pp amrex::ParmParse object * \param[in] str name of the parameter to read - * \param[out] val where the value queried and parsed is stored + * \param[out] val where the value queried and parsed is stored, either a scalar or vector + * \param[in] start_ix start index in the list of inputs values (optional with arrays) + * \param[in] num_val number of input values to use (optional with arrays) */ int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, amrex::Real& val); int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<amrex::Real>& val, const int start_ix, const int num_val); +int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, int& val); +int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val, + const int start_ix, const int num_val); /** * \brief Similar to amrex::ParmParse::get, but also supports math expressions for the value. @@ -202,16 +219,22 @@ int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, st * amrex::ParmParse::get reads a name and a value from the input file. This function does the * same, and applies the Parser to the value, so the user has the choice to specify a value or * a math expression (including user-defined constants). - * Only works for amrex::Real numbers, one would need another version for integers etc. + * Works for amrex::Real numbers and integers. * * \param[in] a_pp amrex::ParmParse object * \param[in] str name of the parameter to read * \param[out] val where the value queried and parsed is stored + * \param[in] start_ix start index in the list of inputs values (optional with arrays) + * \param[in] num_val number of input values to use (optional with arrays) */ void getWithParser (const amrex::ParmParse& a_pp, char const * const str, amrex::Real& val); void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<amrex::Real>& val); void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<amrex::Real>& val, const int start_ix, const int num_val); +void getWithParser (const amrex::ParmParse& a_pp, char const * const str, int& val); +void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val); +void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val, + const int start_ix, const int num_val); namespace WarpXUtilMsg{ diff --git a/Source/Utils/WarpXUtil.cpp b/Source/Utils/WarpXUtil.cpp index 03e800e54..6124e8afa 100644 --- a/Source/Utils/WarpXUtil.cpp +++ b/Source/Utils/WarpXUtil.cpp @@ -34,11 +34,27 @@ #include <fstream> #include <set> #include <string> +#include <limits> using namespace amrex; +void PreparseAMReXInputIntArray(amrex::ParmParse& a_pp, char const * const input_str, const bool replace) +{ + const int cnt = a_pp.countval(input_str); + if (cnt > 0) { + Vector<int> input_array; + getArrWithParser(a_pp, input_str, input_array); + if (replace) { + a_pp.remove(input_str); + } + a_pp.addarr(input_str, input_array); + } +} + void ParseGeometryInput() { + // Parse prob_lo and hi, evaluating any expressions since geometry does not + // parse its input ParmParse pp_geometry("geometry"); Vector<Real> prob_lo(AMREX_SPACEDIM); @@ -66,6 +82,22 @@ void ParseGeometryInput() pp_geometry.addarr("prob_lo", prob_lo); pp_geometry.addarr("prob_hi", prob_hi); + + // Parse amr input, evaluating any expressions since amr does not parse its input + ParmParse pp_amr("amr"); + + // Note that n_cell is replaced so that only the parsed version is written out to the + // warpx_job_info file. This must be done since yt expects to be able to parse + // the value of n_cell from that file. For the rest, this doesn't matter. + PreparseAMReXInputIntArray(pp_amr, "n_cell", true); + PreparseAMReXInputIntArray(pp_amr, "max_grid_size", false); + PreparseAMReXInputIntArray(pp_amr, "max_grid_size_x", false); + PreparseAMReXInputIntArray(pp_amr, "max_grid_size_y", false); + PreparseAMReXInputIntArray(pp_amr, "max_grid_size_z", false); + PreparseAMReXInputIntArray(pp_amr, "blocking_factor", false); + PreparseAMReXInputIntArray(pp_amr, "blocking_factor_x", false); + PreparseAMReXInputIntArray(pp_amr, "blocking_factor_y", false); + PreparseAMReXInputIntArray(pp_amr, "blocking_factor_z", false); } void ReadBoostedFrameParameters(Real& gamma_boost, Real& beta_boost, @@ -239,6 +271,30 @@ void Store_parserString(const amrex::ParmParse& pp, std::string query_string, f.clear(); } +int safeCastToInt(const amrex::Real x, const std::string& real_name) { + int result = 0; + bool error_detected = false; + std::string assert_msg; + // (2.0*(numeric_limits<int>::max()/2+1)) converts numeric_limits<int>::max()+1 to a real ensuring accuracy to all digits + // This accepts x = 2**31-1 but rejects 2**31. + if (x < (2.0*(std::numeric_limits<int>::max()/2+1))) { + if (std::ceil(x) >= std::numeric_limits<int>::min()) { + result = static_cast<int>(x); + } else { + error_detected = true; + assert_msg = "Error: Negative overflow detected when casting " + real_name + " = " + std::to_string(x) + " to int"; + } + } else if (x > 0) { + error_detected = true; + assert_msg = "Error: Overflow detected when casting " + real_name + " = " + std::to_string(x) + " to int"; + } else { + error_detected = true; + assert_msg = "Error: NaN detected when casting " + real_name + " to int"; + } + WarpXUtilMsg::AlwaysAssert(!error_detected, assert_msg); + return result; +} + Parser makeParser (std::string const& parse_function, amrex::Vector<std::string> const& varnames) { // Since queryWithParser recursively calls this routine, keep track of symbols @@ -391,6 +447,53 @@ getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vec } } +int queryWithParser (const amrex::ParmParse& a_pp, char const * const str, int& val) { + amrex::Real rval; + const int result = queryWithParser(a_pp, str, rval); + if (result) { + val = safeCastToInt(std::round(rval), str); + } + return result; +} + +void getWithParser (const amrex::ParmParse& a_pp, char const * const str, int& val) { + amrex::Real rval; + getWithParser(a_pp, str, rval); + val = safeCastToInt(std::round(rval), str); +} + +int queryArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val, + const int start_ix, const int num_val) { + std::vector<amrex::Real> rval; + const int result = queryArrWithParser(a_pp, str, rval, start_ix, num_val); + if (result) { + val.resize(rval.size()); + for (unsigned long i = 0 ; i < val.size() ; i++) { + val[i] = safeCastToInt(std::round(rval[i]), str); + } + } + return result; +} + +void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val) { + std::vector<amrex::Real> rval; + getArrWithParser(a_pp, str, rval); + val.resize(rval.size()); + for (unsigned long i = 0 ; i < val.size() ; i++) { + val[i] = safeCastToInt(std::round(rval[i]), str); + } +} + +void getArrWithParser (const amrex::ParmParse& a_pp, char const * const str, std::vector<int>& val, + const int start_ix, const int num_val) { + std::vector<amrex::Real> rval; + getArrWithParser(a_pp, str, rval, start_ix, num_val); + val.resize(rval.size()); + for (unsigned long i = 0 ; i < val.size() ; i++) { + val[i] = safeCastToInt(std::round(rval[i]), str); + } +} + /** * \brief Ensures that the blocks are setup correctly for the RZ spectral solver * When using the RZ spectral solver, the Hankel transform cannot be diff --git a/Source/WarpX.cpp b/Source/WarpX.cpp index 76d3d5456..680ac150f 100644 --- a/Source/WarpX.cpp +++ b/Source/WarpX.cpp @@ -405,7 +405,7 @@ WarpX::ReadParameters () { { ParmParse pp;// Traditionally, max_step and stop_time do not have prefix. - pp.query("max_step", max_step); + queryWithParser(pp, "max_step", max_step); queryWithParser(pp, "stop_time", stop_time); pp.query("authors", authors); } @@ -425,7 +425,7 @@ WarpX::ReadParameters () ParmParse pp_warpx("warpx"); std::vector<int> numprocs_in; - pp_warpx.queryarr("numprocs", numprocs_in); + queryArrWithParser(pp_warpx, "numprocs", numprocs_in, 0, AMREX_SPACEDIM); if (not numprocs_in.empty()) { AMREX_ALWAYS_ASSERT_WITH_MESSAGE (numprocs_in.size() == AMREX_SPACEDIM, @@ -460,7 +460,7 @@ WarpX::ReadParameters () queryWithParser(pp_warpx, "cfl", cfl); pp_warpx.query("verbose", verbose); - pp_warpx.query("regrid_int", regrid_int); + queryWithParser(pp_warpx, "regrid_int", regrid_int); pp_warpx.query("do_subcycling", do_subcycling); pp_warpx.query("do_multi_J", do_multi_J); if (do_multi_J) @@ -489,8 +489,8 @@ WarpX::ReadParameters () pp_warpx.query("do_moving_window", do_moving_window); if (do_moving_window) { - pp_warpx.query("start_moving_window_step", start_moving_window_step); - pp_warpx.query("end_moving_window_step", end_moving_window_step); + queryWithParser(pp_warpx, "start_moving_window_step", start_moving_window_step); + queryWithParser(pp_warpx, "end_moving_window_step", end_moving_window_step); std::string s; pp_warpx.get("moving_window_dir", s); if (s == "x" || s == "X") { @@ -531,7 +531,7 @@ WarpX::ReadParameters () AMREX_ALWAYS_ASSERT_WITH_MESSAGE( (s == "z" || s == "Z"), "The boosted frame diagnostic currently only works if the boost is in the z direction."); - pp_warpx.get("num_snapshots_lab", num_snapshots_lab); + queryWithParser(pp_warpx, "num_snapshots_lab", num_snapshots_lab); // Read either dz_snapshots_lab or dt_snapshots_lab bool snapshot_interval_is_specified = 0; @@ -561,7 +561,7 @@ WarpX::ReadParameters () if (do_electrostatic == ElectrostaticSolverAlgo::LabFrame) { queryWithParser(pp_warpx, "self_fields_required_precision", self_fields_required_precision); - pp_warpx.query("self_fields_max_iters", self_fields_max_iters); + queryWithParser(pp_warpx, "self_fields_max_iters", self_fields_max_iters); pp_warpx.query("self_fields_verbosity", self_fields_verbosity); // Note that with the relativistic version, these parameters would be // input for each species. @@ -580,7 +580,7 @@ WarpX::ReadParameters () pp_warpx.query("use_filter", use_filter); pp_warpx.query("use_filter_compensation", use_filter_compensation); Vector<int> parse_filter_npass_each_dir(AMREX_SPACEDIM,1); - pp_warpx.queryarr("filter_npass_each_dir", parse_filter_npass_each_dir); + queryArrWithParser(pp_warpx, "filter_npass_each_dir", parse_filter_npass_each_dir, 0, AMREX_SPACEDIM); filter_npass_each_dir[0] = parse_filter_npass_each_dir[0]; filter_npass_each_dir[1] = parse_filter_npass_each_dir[1]; #if (AMREX_SPACEDIM == 3) @@ -623,8 +623,8 @@ WarpX::ReadParameters () pp_warpx.query("refine_plasma", refine_plasma); pp_warpx.query("do_dive_cleaning", do_dive_cleaning); pp_warpx.query("do_divb_cleaning", do_divb_cleaning); - pp_warpx.query("n_field_gather_buffer", n_field_gather_buffer); - pp_warpx.query("n_current_deposition_buffer", n_current_deposition_buffer); + queryWithParser(pp_warpx, "n_field_gather_buffer", n_field_gather_buffer); + queryWithParser(pp_warpx, "n_current_deposition_buffer", n_current_deposition_buffer); #ifdef AMREX_USE_GPU std::vector<std::string>sort_intervals_string_vec = {"4"}; #else @@ -634,7 +634,7 @@ WarpX::ReadParameters () sort_intervals = IntervalsParser(sort_intervals_string_vec); Vector<int> vect_sort_bin_size(AMREX_SPACEDIM,1); - bool sort_bin_size_is_specified = pp_warpx.queryarr("sort_bin_size", vect_sort_bin_size); + bool sort_bin_size_is_specified = queryArrWithParser(pp_warpx, "sort_bin_size", vect_sort_bin_size, 0, AMREX_SPACEDIM); if (sort_bin_size_is_specified){ for (int i=0; i<AMREX_SPACEDIM; i++) sort_bin_size[i] = vect_sort_bin_size[i]; @@ -666,8 +666,8 @@ WarpX::ReadParameters () } } - pp_warpx.query("pml_ncell", pml_ncell); - pp_warpx.query("pml_delta", pml_delta); + queryWithParser(pp_warpx, "pml_ncell", pml_ncell); + queryWithParser(pp_warpx, "pml_delta", pml_delta); pp_warpx.query("pml_has_particles", pml_has_particles); pp_warpx.query("do_pml_j_damping", do_pml_j_damping); pp_warpx.query("do_pml_in_domain", do_pml_in_domain); @@ -758,11 +758,11 @@ WarpX::ReadParameters () ParmParse pp_vismf("vismf"); pp_vismf.add("usesingleread", use_single_read); pp_vismf.add("usesinglewrite", use_single_write); - pp_warpx.query("mffile_nstreams", mffile_nstreams); + queryWithParser(pp_warpx, "mffile_nstreams", mffile_nstreams); VisMF::SetMFFileInStreams(mffile_nstreams); - pp_warpx.query("field_io_nfiles", field_io_nfiles); + queryWithParser(pp_warpx, "field_io_nfiles", field_io_nfiles); VisMF::SetNOutFiles(field_io_nfiles); - pp_warpx.query("particle_io_nfiles", particle_io_nfiles); + queryWithParser(pp_warpx, "particle_io_nfiles", particle_io_nfiles); ParmParse pp_particles("particles"); pp_particles.add("particles_nfiles", particle_io_nfiles); } @@ -782,7 +782,7 @@ WarpX::ReadParameters () if (do_nodal) galerkin_interpolation = false; // Only needs to be set with WARPX_DIM_RZ, otherwise defaults to 1 - pp_warpx.query("n_rz_azimuthal_modes", n_rz_azimuthal_modes); + queryWithParser(pp_warpx, "n_rz_azimuthal_modes", n_rz_azimuthal_modes); // If true, the current is deposited on a nodal grid and then interpolated onto a Yee grid pp_warpx.query("do_current_centering", do_current_centering); @@ -868,7 +868,7 @@ WarpX::ReadParameters () if (!species_names.empty() || !lasers_names.empty()) { int particle_shape; - if (pp_algo.query("particle_shape", particle_shape) == false) + if (queryWithParser(pp_algo, "particle_shape", particle_shape) == false) { amrex::Abort("\nalgo.particle_shape must be set in the input file:" "\nplease set algo.particle_shape to 1, 2, or 3"); @@ -908,16 +908,16 @@ WarpX::ReadParameters () // For momentum-conserving field gathering, read from input the order of // interpolation from the staggered positions to the grid nodes if (WarpX::field_gathering_algo == GatheringAlgo::MomentumConserving) { - pp_interpolation.query("field_centering_nox", field_centering_nox); - pp_interpolation.query("field_centering_noy", field_centering_noy); - pp_interpolation.query("field_centering_noz", field_centering_noz); + queryWithParser(pp_interpolation, "field_centering_nox", field_centering_nox); + queryWithParser(pp_interpolation, "field_centering_noy", field_centering_noy); + queryWithParser(pp_interpolation, "field_centering_noz", field_centering_noz); } // Read order of finite-order centering of currents (nodal to staggered) if (WarpX::do_current_centering) { - pp_interpolation.query("current_centering_nox", current_centering_nox); - pp_interpolation.query("current_centering_noy", current_centering_noy); - pp_interpolation.query("current_centering_noz", current_centering_noz); + queryWithParser(pp_interpolation, "current_centering_nox", current_centering_nox); + queryWithParser(pp_interpolation, "current_centering_noy", current_centering_noy); + queryWithParser(pp_interpolation, "current_centering_noz", current_centering_noz); } if (maxLevel() > 0) @@ -964,20 +964,20 @@ WarpX::ReadParameters () pp_psatd.query("noy", noy_str); pp_psatd.query("noz", noz_str); - if(nox_str == "inf"){ + if(nox_str == "inf") { nox_fft = -1; - } else{ - pp_psatd.query("nox", nox_fft); + } else { + queryWithParser(pp_psatd, "nox", nox_fft); } - if(noy_str == "inf"){ + if(noy_str == "inf") { noy_fft = -1; - } else{ - pp_psatd.query("noy", noy_fft); + } else { + queryWithParser(pp_psatd, "noy", noy_fft); } - if(noz_str == "inf"){ + if(noz_str == "inf") { noz_fft = -1; - } else{ - pp_psatd.query("noz", noz_fft); + } else { + queryWithParser(pp_psatd, "noz", noz_fft); } @@ -1112,8 +1112,8 @@ WarpX::ReadParameters () } queryArrWithParser(pp_slice, "dom_lo", slice_lo, 0, AMREX_SPACEDIM); queryArrWithParser(pp_slice, "dom_hi", slice_hi, 0, AMREX_SPACEDIM); - pp_slice.queryarr("coarsening_ratio",slice_crse_ratio,0,AMREX_SPACEDIM); - pp_slice.query("plot_int",slice_plot_int); + queryArrWithParser(pp_slice, "coarsening_ratio",slice_crse_ratio,0,AMREX_SPACEDIM); + queryWithParser(pp_slice, "plot_int",slice_plot_int); slice_realbox.setLo(slice_lo); slice_realbox.setHi(slice_hi); slice_cr_ratio = IntVect(AMREX_D_DECL(1,1,1)); @@ -1127,7 +1127,7 @@ WarpX::ReadParameters () if (do_back_transformed_diagnostics) { AMREX_ALWAYS_ASSERT_WITH_MESSAGE(gamma_boost > 1.0, "gamma_boost must be > 1 to use the boost frame diagnostic"); - pp_slice.query("num_slice_snapshots_lab", num_slice_snapshots_lab); + queryWithParser(pp_slice, "num_slice_snapshots_lab", num_slice_snapshots_lab); if (num_slice_snapshots_lab > 0) { getWithParser(pp_slice, "dt_slice_snapshots_lab", dt_slice_snapshots_lab ); getWithParser(pp_slice, "particle_slice_width_lab",particle_slice_width_lab); |