Alamo
Expression.H
Go to the documentation of this file.
1//
2// Initialize a field using a mathematical expression.
3// Expressions are imported as strings and are compiled real-time using the
4// `AMReX Parser <https://amrex-codes.github.io/amrex/docs_html/Basics.html#parser>`_.
5//
6// Works for single or multiple-component fields.
7// Use the :code:`regionN` (N=0,1,2, etc. up to number of components) to pass expression.
8// For example:
9//
10// .. code-block:: bash
11//
12// ic.region0 = "sin(x*y*z)"
13// ic.region1 = "3.0*(x > 0.5 and y > 0.5)"
14//
15// for a two-component field. It is up to you to make sure your expressions are parsed
16// correctly; otherwise you will get undefined behavior.
17//
18// :bdg-primary-line:`Constants`
19// You can add constants to your expressions using the :code:`constant` directive.
20// For instance, in the following code
21//
22// .. code-block:: bash
23//
24// psi.ic.type=expression
25// psi.ic.expression.constant.eps = 0.05
26// psi.ic.expression.constant.R = 0.25
27// psi.ic.expression.region0 = "0.5 + 0.5*tanh((x^2 + y^2 - R)/eps)"
28//
29// the constants :code:`eps` and :code:`R` are defined by the user and then used
30// in the subsequent expression.
31// The variables can have any name made up of characters that is not reserved.
32// However, if multiple ICs are used, they must be defined each time for each IC.
33//
34
35#ifndef IC_EXPRESSION_H_
36#define IC_EXPRESSION_H_
37#include "IC/IC.H"
38#include "Util/Util.H"
39#include "IO/ParmParse.H"
40#include "AMReX_Parser.H"
41#include <stdexcept>
42
43namespace IC
44{
45class Expression : public IC<Set::Scalar>, public IC<Set::Vector>
46{
47private:
49 std::vector<amrex::Parser> parser;
50 std::vector<amrex::ParserExecutor<4>> f;
52public:
53 static constexpr const char* name = "expression";
54 Expression(amrex::Vector<amrex::Geometry>& _geom) :
55 IC<Set::Scalar>(_geom), IC<Set::Vector>(_geom) {}
56 Expression(amrex::Vector<amrex::Geometry>& _geom, IO::ParmParse& pp, std::string name) :
57 IC<Set::Scalar>(_geom), IC<Set::Vector>(_geom)
58 {
59 pp_queryclass(name, *this);
60 }
61 Expression(amrex::Vector<amrex::Geometry>& _geom, Unit a_unit, IO::ParmParse& pp, std::string name) :
62 IC<Set::Scalar>(_geom), IC<Set::Vector>(_geom), unit(a_unit)
63 {
64 pp_queryclass(name, *this);
65 }
66 virtual void Add(const int& lev, Set::Field<Set::Scalar>& a_field, Set::Scalar a_time = 0.0) override
67 {
68 Util::Assert(INFO, TEST(a_field[lev]->nComp() == (int)f.size()));
69 for (amrex::MFIter mfi(*a_field[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
70 {
71 const auto prob_lo = IC<Set::Scalar>::geom[lev].ProbLoArray();
72 const auto cell_size = IC<Set::Scalar>::geom[lev].CellSizeArray();
73 const int coord = static_cast<int>(this->coord);
74 const auto unitfactor = this->unitfactor;
75 amrex::Box bx;// = mfi.tilebox();
76 //bx.grow(a_field[lev]->nGrow());
77 amrex::IndexType type = a_field[lev]->ixType();
78 if (type == amrex::IndexType::TheCellType()) bx = mfi.growntilebox();
79 else if (type == amrex::IndexType::TheNodeType()) bx = mfi.grownnodaltilebox();
80 else Util::Abort(INFO, "Unkonwn index type");
81
82 amrex::Array4<Set::Scalar> const& field = a_field[lev]->array(mfi);
83 for (unsigned int n = 0; n < f.size(); n++)
84 {
85 const auto f_n = f[n];
86 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
87 {
88 Set::Vector x =
89 Set::Position(i, j, k, prob_lo, cell_size, type);
90 if (coord == static_cast<int>(Expression::CoordSys::Cartesian))
91 {
92#if AMREX_SPACEDIM == 1
93 field(i, j, k, n) = f_n(x(0), 0.0, 0.0, a_time) * unitfactor;
94#elif AMREX_SPACEDIM == 2
95 field(i, j, k, n) = f_n(x(0), x(1), 0.0, a_time) * unitfactor;
96#elif AMREX_SPACEDIM == 3
97 field(i, j, k, n) = f_n(x(0), x(1), x(2), a_time) * unitfactor;
98#endif
99 }
100#if AMREX_SPACEDIM>1
101 else if (coord == static_cast<int>(Expression::CoordSys::Polar))
102 {
103 field(i, j, k, n) = f_n(
104 sqrt(x(0)*x(0) + x(1)*x(1)),
105 std::atan2(x(1), x(0)),
106#if AMREX_SPACEDIM > 2
107 x(2),
108#else
109 0.0,
110#endif
111 a_time) * unitfactor;
112 }
113#endif
114 });
115 }
116 }
117 a_field[lev]->FillBoundary();
118 };
119
120 virtual void Add(const int& lev, Set::Field<Set::Vector>& a_field, Set::Scalar a_time = 0.0) override
121 {
122 Util::Assert(INFO, TEST(a_field[lev]->nComp() == 1));
123 Util::Assert(INFO, TEST(f.size() >= AMREX_SPACEDIM));
124 for (amrex::MFIter mfi(*a_field[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
125 {
126 const auto prob_lo = IC<Set::Vector>::geom[lev].ProbLoArray();
127 const auto cell_size = IC<Set::Vector>::geom[lev].CellSizeArray();
128 const int coord = static_cast<int>(this->coord);
129 const auto unitfactor = this->unitfactor;
130 amrex::Box bx;
131 amrex::IndexType type = a_field[lev]->ixType();
132 if (type == amrex::IndexType::TheCellType()) bx = mfi.growntilebox();
133 else if (type == amrex::IndexType::TheNodeType()) bx = mfi.grownnodaltilebox();
134 else Util::Abort(INFO, "Unkonwn index type");
135
136 Set::Patch<Set::Vector> field = a_field.Patch(lev,mfi);
137 for (unsigned int n = 0; n < AMREX_SPACEDIM; n++)
138 {
139 const auto f_n = f[n];
140 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
141 {
142 Set::Vector x =
143 Set::Position(i, j, k, prob_lo, cell_size, type);
144 if (coord == static_cast<int>(Expression::CoordSys::Cartesian))
145 {
146#if AMREX_SPACEDIM == 1
147 field(i, j, k)(n) = f_n(x(0), 0.0, 0.0, a_time) * unitfactor;
148#elif AMREX_SPACEDIM == 2
149 field(i, j, k)(n) = f_n(x(0), x(1), 0.0, a_time) * unitfactor;
150#elif AMREX_SPACEDIM == 3
151 field(i, j, k)(n) = f_n(x(0), x(1), x(2), a_time) * unitfactor;
152#endif
153 }
154#if AMREX_SPACEDIM>1
155 else if (coord == static_cast<int>(Expression::CoordSys::Polar))
156 {
157 field(i, j, k)(n) = f_n(
158 sqrt(x(0)*x(0) + x(1)*x(1)),
159 std::atan2(x(1), x(0)),
160#if AMREX_SPACEDIM > 2
161 x(2),
162#else
163 0.0,
164#endif
165 a_time) * unitfactor;
166 }
167#endif
168 });
169 }
170 }
171 a_field[lev]->FillBoundary();
172 };
173
174 static void Parse(Expression& value, IO::ParmParse& pp)
175 {
176 std::string coordstr = "";
177 // coordinate system to use
178 pp_query_validate("coord", coordstr, {"cartesian","polar"});
179 if (coordstr == "cartesian") value.coord = Expression::CoordSys::Cartesian;
180 else if (coordstr == "polar") value.coord = Expression::CoordSys::Polar;
181 else Util::Exception(INFO, "unsupported coordinates ", coordstr);
182
183 std::string unitstr;
184 // Units of the value that is returned by the expression
185 pp.query_default("unit",unitstr,"");
186 try
187 {
188 Unit unit_spec = Unit::Parse(unitstr);
189 if (!unit_spec.isType(value.unit) && !unit_spec.isType(Unit::Less()))
190 Util::Exception(INFO, "Incompatible unit specified: ", unitstr);
191 value.unitfactor = unit_spec.normalized_value();
192 }
193 catch (std::runtime_error &e)
194 {
195 Util::Exception(INFO,e.what());
196 }
197
198 std::vector<std::string> expression_strs;
199 // Mathematical expression in terms of x,y,z,t (if coord=cartesian)
200 // or r,theta,z,t (if coord=polar) and any defined constants.
201 pp.query_enumerate("region", expression_strs);
202
203 for (unsigned int i = 0; i < expression_strs.size(); i++)
204 {
205 value.parser.push_back(amrex::Parser(expression_strs[i]));
206
207 //
208 // Read in user-defined constants and add them to the parser
209 //
210 std::string prefix = pp.getPrefix();
211 std::set<std::string> entries = pp.getEntries(prefix + ".constant");//"constant");
212 std::set<std::string>::iterator entry;
213 for (entry = entries.begin(); entry != entries.end(); entry++)
214 {
215 IO::ParmParse pp;
216 std::string fullname = *entry;
217 Unit val;
218 pp.queryunit(fullname.data(),val);
219 std::string name = Util::String::Split(fullname,'.').back();
220 value.parser.back().setConstant(name,val.normalized_value());
221 }
222
224 {
225 value.parser.back().registerVariables({ "x","y","z","t" });
226 value.f.push_back(value.parser.back().compile<4>());
227 }
228 else if (value.coord == Expression::CoordSys::Polar)
229 {
230 value.parser.back().registerVariables({ "r","theta","z","t" });
231 value.f.push_back(value.parser.back().compile<4>());
232 }
233 }
234 };
235private:
238};
239}
240
241#endif
#define pp_query_validate(...)
Definition ParmParse.H:121
#define pp_queryclass(...)
Definition ParmParse.H:130
#define TEST(x)
Definition Util.H:25
#define INFO
Definition Util.H:24
static constexpr const char * name
Definition Expression.H:53
virtual void Add(const int &lev, Set::Field< Set::Vector > &a_field, Set::Scalar a_time=0.0) override
Definition Expression.H:120
virtual void Add(const int &lev, Set::Field< Set::Scalar > &a_field, Set::Scalar a_time=0.0) override
Definition Expression.H:66
Expression(amrex::Vector< amrex::Geometry > &_geom, Unit a_unit, IO::ParmParse &pp, std::string name)
Definition Expression.H:61
Set::Scalar unitfactor
Definition Expression.H:237
Expression::CoordSys coord
Definition Expression.H:51
Expression(amrex::Vector< amrex::Geometry > &_geom, IO::ParmParse &pp, std::string name)
Definition Expression.H:56
std::vector< amrex::ParserExecutor< 4 > > f
Definition Expression.H:50
std::vector< amrex::Parser > parser
Definition Expression.H:49
Expression(amrex::Vector< amrex::Geometry > &_geom)
Definition Expression.H:54
static void Parse(Expression &value, IO::ParmParse &pp)
Definition Expression.H:174
Pure abstract IC object from which all other IC objects inherit.
Definition IC.H:23
std::string getPrefix() const
Definition ParmParse.H:275
int query_default(std::string name, T &value, T defaultvalue, const std::source_location &location=std::source_location::current())
Definition ParmParse.H:492
int queryunit(std::string name, Unit &value, const std::source_location &location=std::source_location::current())
Definition ParmParse.H:351
int query_enumerate(std::string a_name, std::vector< T > &value, int number=1, const std::source_location &location=std::source_location::current())
Definition ParmParse.H:1582
amrex::Array4< T > Patch(int lev, amrex::MFIter &mfi) const &
Definition Set.H:76
Initialize a spherical inclusion.
Definition BMP.H:20
A collection of data types and symmetry-reduced data structures.
Definition Base.H:18
amrex::Real Scalar
Definition Base.H:19
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition Base.H:21
AMREX_FORCE_INLINE Vector Position(const int &i, const int &j, const int &k, const amrex::Geometry &geom, const amrex::IndexType &ixType)
Definition Base.H:122
AMREX_FORCE_INLINE std::vector< std::string > Split(std::string &str, const char delim=' ')
Definition String.H:138
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE void Assert(const char *file, const char *func, int line, const char *smt, bool pass, Args const &... args)
Definition Util.H:60
AMREX_GPU_HOST_DEVICE void Abort(const char *msg)
Definition Util.cpp:406
void Exception(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:237
Definition Unit.H:21
bool isType(const Unit &test) const
Definition Unit.H:425
static Unit Parse(double val, std::string unitstring, bool verbose=false)
Definition Unit.H:270
double normalized_value() const
Definition Unit.H:506
static Unit Less()
Definition Unit.H:197