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 amrex::Box bx;// = mfi.tilebox();
72 //bx.grow(a_field[lev]->nGrow());
73 amrex::IndexType type = a_field[lev]->ixType();
74 if (type == amrex::IndexType::TheCellType()) bx = mfi.growntilebox();
75 else if (type == amrex::IndexType::TheNodeType()) bx = mfi.grownnodaltilebox();
76 else Util::Abort(INFO, "Unkonwn index type");
77
78 amrex::Array4<Set::Scalar> const& field = a_field[lev]->array(mfi);
79 for (unsigned int n = 0; n < f.size(); n++)
80 {
81 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
82 {
83 Set::Vector x = Set::Position(i, j, k, IC<Set::Scalar>::geom[lev], type);
85 {
86#if AMREX_SPACEDIM == 1
87 field(i, j, k, n) = f[n](x(0), 0.0, 0.0, a_time) * unitfactor;
88#elif AMREX_SPACEDIM == 2
89 field(i, j, k, n) = f[n](x(0), x(1), 0.0, a_time) * unitfactor;
90#elif AMREX_SPACEDIM == 3
91 field(i, j, k, n) = f[n](x(0), x(1), x(2), a_time) * unitfactor;
92#endif
93 }
94#if AMREX_SPACEDIM>1
96 {
97 field(i, j, k, n) = f[n](sqrt(x(0)* x(0) + x(1) * x(1)), std::atan2(x(1), x(0)), x(2), a_time) * unitfactor;
98 }
99#endif
100 });
101 }
102 }
103 a_field[lev]->FillBoundary();
104 };
105
106 virtual void Add(const int& lev, Set::Field<Set::Vector>& a_field, Set::Scalar a_time = 0.0) override
107 {
108 Util::Assert(INFO, TEST(a_field[lev]->nComp() == 1));
109 Util::Assert(INFO, TEST(f.size() >= AMREX_SPACEDIM));
110 for (amrex::MFIter mfi(*a_field[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
111 {
112 amrex::Box bx;
113 amrex::IndexType type = a_field[lev]->ixType();
114 if (type == amrex::IndexType::TheCellType()) bx = mfi.growntilebox();
115 else if (type == amrex::IndexType::TheNodeType()) bx = mfi.grownnodaltilebox();
116 else Util::Abort(INFO, "Unkonwn index type");
117
118 Set::Patch<Set::Vector> field = a_field.Patch(lev,mfi);
119 for (unsigned int n = 0; n < AMREX_SPACEDIM; n++)
120 {
121 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
122 {
123 Set::Vector x = Set::Position(i, j, k, IC<Set::Vector>::geom[lev], type);
125 {
126#if AMREX_SPACEDIM == 1
127 field(i, j, k)(n) = f[n](x(0), 0.0, 0.0, a_time) * unitfactor;
128#elif AMREX_SPACEDIM == 2
129 field(i, j, k)(n) = f[n](x(0), x(1), 0.0, a_time) * unitfactor;
130#elif AMREX_SPACEDIM == 3
131 field(i, j, k)(n) = f[n](x(0), x(1), x(2), a_time) * unitfactor;
132#endif
133 }
134#if AMREX_SPACEDIM>1
136 {
137 field(i, j, k)(n) = f[n](sqrt(x(0)* x(0) + x(1) * x(1)), std::atan2(x(1), x(0)), x(2), a_time) * unitfactor;
138 }
139#endif
140 });
141 }
142 }
143 a_field[lev]->FillBoundary();
144 };
145
146 static void Parse(Expression& value, IO::ParmParse& pp)
147 {
148 std::string coordstr = "";
149 // coordinate system to use
150 pp_query_validate("coord", coordstr, {"cartesian","polar"});
151 if (coordstr == "cartesian") value.coord = Expression::CoordSys::Cartesian;
152 else if (coordstr == "polar") value.coord = Expression::CoordSys::Polar;
153 else Util::Exception(INFO, "unsupported coordinates ", coordstr);
154
155 std::string unitstr;
156 // Units of the value that is returned by the expression
157 pp.query_default("unit",unitstr,"");
158 try
159 {
160 Unit unit_spec = Unit::Parse(unitstr);
161 if (!unit_spec.isType(value.unit) && !unit_spec.isType(Unit::Less()))
162 Util::Exception(INFO, "Incompatible unit specified: ", unitstr);
163 value.unitfactor = unit_spec.normalized_value();
164 }
165 catch (std::runtime_error &e)
166 {
167 Util::Exception(INFO,e.what());
168 }
169
170 std::vector<std::string> expression_strs;
171 // Mathematical expression in terms of x,y,z,t (if coord=cartesian)
172 // or r,theta,z,t (if coord=polar) and any defined constants.
173 pp.query_enumerate("region", expression_strs);
174
175 for (unsigned int i = 0; i < expression_strs.size(); i++)
176 {
177 value.parser.push_back(amrex::Parser(expression_strs[i]));
178
179 //
180 // Read in user-defined constants and add them to the parser
181 //
182 std::string prefix = pp.getPrefix();
183 std::set<std::string> entries = pp.getEntries(prefix + ".constant");//"constant");
184 std::set<std::string>::iterator entry;
185 for (entry = entries.begin(); entry != entries.end(); entry++)
186 {
187 IO::ParmParse pp;
188 std::string fullname = *entry;
189 Unit val;
190 pp.queryunit(fullname.data(),val);
191 std::string name = Util::String::Split(fullname,'.').back();
192 value.parser.back().setConstant(name,val.normalized_value());
193 }
194
196 {
197 value.parser.back().registerVariables({ "x","y","z","t" });
198 value.f.push_back(value.parser.back().compile<4>());
199 }
200 else if (value.coord == Expression::CoordSys::Polar)
201 {
202 value.parser.back().registerVariables({ "r","theta","z","t" });
203 value.f.push_back(value.parser.back().compile<4>());
204 }
205 }
206 };
207private:
210};
211}
212
213#endif
#define pp_query_validate(...)
Definition ParmParse.H:103
#define pp_queryclass(...)
Definition ParmParse.H:109
#define TEST(x)
Definition Util.H:22
#define INFO
Definition Util.H:21
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:106
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:209
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:146
Pure abstract IC object from which all other IC objects inherit.
Definition IC.H:23
int queryunit(std::string name, Unit &value)
Definition ParmParse.H:192
int query_enumerate(std::string a_name, std::vector< T > &value, int number=1)
Definition ParmParse.H:804
std::string getPrefix() const
Definition ParmParse.H:136
int query_default(std::string name, T &value, T defaultvalue)
Definition ParmParse.H:293
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:17
amrex::Real Scalar
Definition Base.H:18
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition Base.H:19
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:120
AMREX_FORCE_INLINE std::vector< std::string > Split(std::string &str, const char delim=' ')
Definition String.H:138
void Abort(const char *msg)
Definition Util.cpp:225
AMREX_FORCE_INLINE void Assert(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition Util.H:55
void Exception(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:223
Definition Unit.H:20
bool isType(const Unit &test) const
Definition Unit.H:353
double normalized_value() const
Definition Unit.H:401
static Unit Less()
Definition Unit.H:187
static Unit Parse(double val, std::string unitstring)
Definition Unit.H:257