Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions docs/source/run/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1191,3 +1191,29 @@ or beam in-situ diagnostic as ``[sx], [sx^2], [sy], [sy^2], [sz], [sz^2]``.

* ``<beam name> or beams.spin_anom`` (`bool`) optional (default `0.00115965218128`)
The anomalous magnetic moment. The default value is the moment for electrons.


Parser
------

* ``parser.debug_print`` (list of `strings`) optional
Print an evaluated parser expression for debugging. The fist `string` from the input is the
expression to evaluate and all following `strings` can be used to define constants or variables
that are used in the expression. Constants are defined by ``"<constant name>=<value>"`` and
variables by ``"<variable name>=[<range begin>,<range end>,<num values>]"``, where the expression
will be evaluated at ``<num values>`` equally spaced points between ``<range begin>`` and
``<range end>``. These are the same points as
``numpy.linspace(<range begin>,<range end>,<num values>)`` gives. Up to four variables are
supported. Note that constant and variable definitions have to be enclosed in double-quotes and
if provided through command-line parameters in bash, the full list of strings needs to be
enclosed in single-quotes. Example:

.. code-block:: bash

parser.debug_print = "10*x + y" "x=[0,9,10]" "y=2"

Output:

.. code-block:: bash

Parser Debug Print "10*x + y" = [2, 12, 22, 32, 42, 52, 62, 72, 82, 92]
1 change: 1 addition & 0 deletions src/Hipace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Hipace_early_init::Hipace_early_init (Hipace* instance)
m_phys_const = make_constants_SI();
}
Parser::replaceAmrexParamsWithParser();
Parser::DebugPrint();

queryWithParser(pph, "do_device_synchronize", DO_DEVICE_SYNCHRONIZE);
queryWithParser(pph, "depos_order_xy", m_depos_order_xy);
Expand Down
1 change: 1 addition & 0 deletions src/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ target_sources(HiPACE
IOUtil.cpp
GridCurrent.cpp
MultiBuffer.cpp
Parser.cpp
)
24 changes: 20 additions & 4 deletions src/utils/Parser.H
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,11 @@ namespace Parser
amrex::ParmParse pp_my_constants("my_constants");
if (pos_count_trim == 0) {
loc_str.replace(pos, pos_end-pos+1, "");
} else if (pp_my_constants.contains(parse_string.c_str())) {
} else if (amrex::ParmParse{}.contains(parse_string.c_str()) ||
pp.contains(parse_string.c_str()) ||
pp_my_constants.contains(parse_string.c_str())) {
// use my_constants directly (with recursive string parsing) if available
// also check in local and global namespaces, same as the amrex parser
if (recursive_symbols.count(parse_string) != 0) {
amrex::ErrorStream() << "Expression '"
<< str
Expand All @@ -181,7 +184,13 @@ namespace Parser
AMREX_ALWAYS_ASSERT(recursive_symbols.count(parse_string) == 0);
}
std::string replacer;
pp_my_constants.get(parse_string.c_str(), replacer);
if (amrex::ParmParse{}.contains(parse_string.c_str())) {
amrex::ParmParse{}.get(parse_string.c_str(), replacer);
} else if (pp.contains(parse_string.c_str())) {
pp.get(parse_string.c_str(), replacer);
} else {
pp_my_constants.get(parse_string.c_str(), replacer);
}
std::string parse_val;
recursive_symbols.insert(parse_string);
// for proper escape handling
Expand Down Expand Up @@ -305,6 +314,11 @@ namespace Parser
fillWithParser(pp, str_arr[i], val_arr[i]);
}
}

/** \brief print the value of a user provided function for the purposes of debugging
*/
void
DebugPrint ();
}

/** \brief fill val with the evaluated expression from the input file
Expand Down Expand Up @@ -377,18 +391,20 @@ getWithParserAlt (const amrex::ParmParse& pp, char const * const str, T& val,
* \param[in] func_str string that gets Parsed to a function
* \param[out] parser Parser which owns the data of the returned function
* \param[in] varnames names of the N arguments used in the parsed function
* \param[in] pp ParmParse that is searched for user constants
*/
template<int N>
inline auto
makeFunctionWithParser (std::string const& func_str,
amrex::Parser& parser,
amrex::Vector<std::string> const& varnames)
amrex::Vector<std::string> const& varnames,
const amrex::ParmParse& pp = amrex::ParmParse{})
{
std::string clean_str = func_str;
for (char& c : clean_str) {
if (c=='\n' || c=='\r' || c=='\t') c = ' ';
}
parser = amrex::ParmParse{}.makeParser(clean_str, varnames);
parser = pp.makeParser(clean_str, varnames);
return parser.compile<N>();
}

Expand Down
201 changes: 201 additions & 0 deletions src/utils/Parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/* Copyright 2025
*
* This file is part of HiPACE++.
*
* Authors: AlexanderSinn
* License: BSD-3-Clause-LBNL
*/
#include "Parser.H"

namespace Parser {

void
DebugPrint () {
amrex::ParmParse pp("parser", "parser");

std::vector<std::string> inputs{};

if (!queryWithParser(pp, "debug_print", inputs)) {
return;
}

amrex::Vector<std::string> local_variables_names{};
std::vector<std::tuple<double, double, int>> local_variables_bounds{};

for (auto i=1ul; i!=inputs.size(); ++i) {
const std::string& s = inputs[i];
const std::string abort_str = "DebugPrint(): invalid variable format! Must be "
"\"<var name>=<value>\" or \"<var name>=[<range begin>,<range end>,<num values>]\"."
" Got: \"" + s + "\"";

auto pos = s.find_first_of("=");

if (pos == std::string::npos) {
amrex::Abort(abort_str);
}

std::string varname = s.substr(0, pos);
std::string expr = s.substr(pos + 1u);
std::stringstream expr_ss{expr};

if (expr.size() < 1ul) {
amrex::Abort(abort_str);
}

if (expr_ss.peek() == '[') {
double range_begin = 0., range_end = 0., num_points = 0.;
char bracket_open = '[', first_comma = ',', second_comma = ',', bracked_close = ']';

expr_ss >> bracket_open >> range_begin
>> first_comma >> range_end
>> second_comma >> num_points
>> bracked_close;

if (bracket_open != '[' || first_comma != ',' ||
second_comma != ',' || bracked_close != ']') {
amrex::Abort(abort_str);
}
local_variables_names.emplace_back(varname);
local_variables_bounds.emplace_back(range_begin, range_end,
static_cast<int>(std::round(num_points)));
} else {
double val = 0.;
expr_ss >> val;
pp.add(varname.c_str(), val);
}

if (expr_ss.fail() ||
(static_cast<long>(expr_ss.tellg()) != static_cast<long>(expr.size()) &&
static_cast<long>(expr_ss.tellg()) != -1l)) {
amrex::Abort(abort_str);
}
}

amrex::Parser func_parser{};

if (local_variables_names.size() == 0) {
auto exe = makeFunctionWithParser<0>(inputs[0], func_parser, {}, pp);
std::cout << "\nParser Debug Print \"" << inputs[0] << "\" = "
<< exe() << "\n" << std::endl;
} else if (local_variables_names.size() == 1) {
auto exe = makeFunctionWithParser<1>(inputs[0], func_parser, local_variables_names, pp);
std::cout << "\nParser Debug Print \"" << inputs[0] << "\" = [";
auto [lo, hi, n] = local_variables_bounds[0];
const double dx = (hi-lo)/(n-1);
for (int i=0; i<n; ++i) {
double x = lo + i * dx;
const double val = exe(x);
if (i > 0) {
std::cout << ", ";
}
std::cout << val;
}
std::cout << "]\n" << std::endl;
} else if (local_variables_names.size() == 2) {
auto exe = makeFunctionWithParser<2>(inputs[0], func_parser, local_variables_names, pp);
std::cout << "\nParser Debug Print \"" << inputs[0] << "\" = [";
auto [lox, hix, nx] = local_variables_bounds[0];
auto [loy, hiy, ny] = local_variables_bounds[1];
const double dx = (hix-lox)/(nx-1);
const double dy = (hiy-loy)/(ny-1);
for (int j=0; j<ny; ++j) {
const double y = loy + j * dy;
if (j > 0) {
std::cout << ",\n";
}
std::cout << "[";
for (int i=0; i<nx; ++i) {
const double x = lox + i * dx;
const double val = exe(x, y);
if (i > 0) {
std::cout << ", ";
}
std::cout << val;
}
std::cout << "]";
}
std::cout << "]\n" << std::endl;
} else if (local_variables_names.size() == 3) {
auto exe = makeFunctionWithParser<3>(inputs[0], func_parser, local_variables_names, pp);
std::cout << "\nParser Debug Print \"" << inputs[0] << "\" = [";
auto [lox, hix, nx] = local_variables_bounds[0];
auto [loy, hiy, ny] = local_variables_bounds[1];
auto [loz, hiz, nz] = local_variables_bounds[2];
const double dx = (hix-lox)/(nx-1);
const double dy = (hiy-loy)/(ny-1);
const double dz = (hiz-loz)/(nz-1);
for (int k=0; k<nz; ++k) {
const double z = loz + k * dz;
if (k > 0) {
std::cout << ",\n\n";
}
std::cout << "[";
for (int j=0; j<ny; ++j) {
const double y = loy + j * dy;
if (j > 0) {
std::cout << ",\n";
}
std::cout << "[";
for (int i=0; i<nx; ++i) {
const double x = lox + i * dx;
const double val = exe(x, y, z);
if (i > 0) {
std::cout << ", ";
}
std::cout << val;
}
std::cout << "]";
}
std::cout << "]";
}
std::cout << "]\n" << std::endl;
} else if (local_variables_names.size() == 4) {
auto exe = makeFunctionWithParser<4>(inputs[0], func_parser, local_variables_names, pp);
std::cout << "\nParser Debug Print \"" << inputs[0] << "\" = [";
auto [lox, hix, nx] = local_variables_bounds[0];
auto [loy, hiy, ny] = local_variables_bounds[1];
auto [loz, hiz, nz] = local_variables_bounds[2];
auto [low, hiw, nw] = local_variables_bounds[3];
const double dx = (hix-lox)/(nx-1);
const double dy = (hiy-loy)/(ny-1);
const double dz = (hiz-loz)/(nz-1);
const double dw = (hiw-low)/(nw-1);
for (int l=0; l<nw; ++l) {
const double w = low + l * dw;
if (l > 0) {
std::cout << ",\n\n\n";
}
std::cout << "[";
for (int k=0; k<nz; ++k) {
const double z = loz + k * dz;
if (k > 0) {
std::cout << ",\n\n";
}
std::cout << "[";
for (int j=0; j<ny; ++j) {
const double y = loy + j * dy;
if (j > 0) {
std::cout << ",\n";
}
std::cout << "[";
for (int i=0; i<nx; ++i) {
const double x = lox + i * dx;
const double val = exe(x, y, z, w);
if (i > 0) {
std::cout << ", ";
}
std::cout << val;
}
std::cout << "]";
}
std::cout << "]";
}
std::cout << "]";
}
std::cout << "]\n" << std::endl;
} else {
amrex::Abort("DebugPrint(): Only supports up to 4 variables");
}
}

}
Loading