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 
42 namespace IC
43 {
44 class Expression : public IC
45 {
46 private:
48  std::vector<amrex::Parser> parser;
49  std::vector<amrex::ParserExecutor<4>> f;
50  Expression::CoordSys coord = Expression::CoordSys::Cartesian;
51 public:
52  static constexpr const char* name = "expression";
53  Expression(amrex::Vector<amrex::Geometry>& _geom) : IC(_geom) {}
54  Expression(amrex::Vector<amrex::Geometry>& _geom, IO::ParmParse& pp, std::string name) : IC(_geom)
55  {
56  pp_queryclass(name, *this);
57  }
58  void Add(const int& lev, Set::Field<Set::Scalar>& a_field, Set::Scalar a_time = 0.0)
59  {
60  Util::Assert(INFO, TEST(a_field[lev]->nComp() == (int)f.size()));
61  for (amrex::MFIter mfi(*a_field[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
62  {
63  amrex::Box bx;// = mfi.tilebox();
64  //bx.grow(a_field[lev]->nGrow());
65  amrex::IndexType type = a_field[lev]->ixType();
66  if (type == amrex::IndexType::TheCellType()) bx = mfi.growntilebox();
67  else if (type == amrex::IndexType::TheNodeType()) bx = mfi.grownnodaltilebox();
68  else Util::Abort(INFO, "Unkonwn index type");
69 
70  amrex::Array4<Set::Scalar> const& field = a_field[lev]->array(mfi);
71  for (unsigned int n = 0; n < f.size(); n++)
72  {
73  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
74  {
75  Set::Vector x = Set::Position(i, j, k, geom[lev], type);
76  if (coord == Expression::CoordSys::Cartesian)
77  {
78 #if AMREX_SPACEDIM == 1
79  field(i, j, k, n) = f[n](x(0), 0.0, 0.0, a_time);
80 #elif AMREX_SPACEDIM == 2
81  field(i, j, k, n) = f[n](x(0), x(1), 0.0, a_time);
82 #elif AMREX_SPACEDIM == 3
83  field(i, j, k, n) = f[n](x(0), x(1), x(2), a_time);
84 #endif
85  }
86 #if AMREX_SPACEDIM>1
87  else if (coord == Expression::CoordSys::Polar)
88  {
89  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);
90  }
91 #endif
92  });
93  }
94  }
95  a_field[lev]->FillBoundary();
96  };
97 
98  void Add(const int& lev, Set::Field<Set::Vector>& a_field, Set::Scalar a_time = 0.0)
99  {
100  Util::Assert(INFO, TEST(a_field[lev]->nComp() == 1));
101  Util::Assert(INFO, TEST(f.size() >= AMREX_SPACEDIM));
102  for (amrex::MFIter mfi(*a_field[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
103  {
104  amrex::Box bx;
105  amrex::IndexType type = a_field[lev]->ixType();
106  if (type == amrex::IndexType::TheCellType()) bx = mfi.growntilebox();
107  else if (type == amrex::IndexType::TheNodeType()) bx = mfi.grownnodaltilebox();
108  else Util::Abort(INFO, "Unkonwn index type");
109 
110  Set::Patch<Set::Vector> field = a_field.Patch(lev,mfi);
111  for (unsigned int n = 0; n < AMREX_SPACEDIM; n++)
112  {
113  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
114  {
115  Set::Vector x = Set::Position(i, j, k, geom[lev], type);
116  if (coord == Expression::CoordSys::Cartesian)
117  {
118 #if AMREX_SPACEDIM == 1
119  field(i, j, k)(n) = f[n](x(0), 0.0, 0.0, a_time);
120 #elif AMREX_SPACEDIM == 2
121  field(i, j, k)(n) = f[n](x(0), x(1), 0.0, a_time);
122 #elif AMREX_SPACEDIM == 3
123  field(i, j, k)(n) = f[n](x(0), x(1), x(2), a_time);
124 #endif
125  }
126 #if AMREX_SPACEDIM>1
127  else if (coord == Expression::CoordSys::Polar)
128  {
129  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);
130  }
131 #endif
132  });
133  }
134  }
135  a_field[lev]->FillBoundary();
136  };
137 
138  static void Parse(Expression& value, IO::ParmParse& pp)
139  {
140  for (int i = 0; true; i++)
141  {
142  std::string coordstr = "cartesian";
143  // coordinate system to use: "cartesian" (for x,y,z,t) and
144  // "polar" (for r, theta, z, t)
145  pp_query("coord", coordstr);
146  if (coordstr == "cartesian") value.coord = Expression::CoordSys::Cartesian;
147  else if (coordstr == "polar") value.coord = Expression::CoordSys::Polar;
148  else Util::Abort(INFO, "unsupported coordinates ", coordstr);
149 
150  std::string func = "0.0";
151  std::string name = "region" + std::to_string(i);
152 
153  if (!pp.contains(name.data())) break;
154  pp_query(name.data(), func);
155 
156  value.parser.push_back(amrex::Parser(func));
157 
158  //
159  // Read in user-defined constants and add them to the parser
160  //
161  std::string prefix = pp.getPrefix();
162  std::set<std::string> entries = pp.getEntries(prefix + ".constant");//"constant");
163  std::set<std::string>::iterator entry;
164  for (entry = entries.begin(); entry != entries.end(); entry++)
165  {
166  IO::ParmParse pp;
167  std::string fullname = *entry;
168  Set::Scalar val = NAN;
169  pp_query(fullname.data(),val);
170  std::string name = Util::String::Split(fullname,'.').back();
171  value.parser.back().setConstant(name,val);
172  }
173 
174  if (value.coord == Expression::CoordSys::Cartesian)
175  {
176  value.parser.back().registerVariables({ "x","y","z","t" });
177  value.f.push_back(value.parser.back().compile<4>());
178  }
179  else if (value.coord == Expression::CoordSys::Polar)
180  {
181  value.parser.back().registerVariables({ "r","theta","z","t" });
182  value.f.push_back(value.parser.back().compile<4>());
183  }
184  }
185 
186  };
187 };
188 }
189 
190 #endif
IC::Expression::parser
std::vector< amrex::Parser > parser
Definition: Expression.H:48
IC::IC::geom
amrex::Vector< amrex::Geometry > & geom
Definition: IC.H:54
Set::Position
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:121
Util.H
TEST
#define TEST(x)
Definition: Util.H:21
Util::String::Split
std::vector< std::string > Split(std::string &str, const char delim)
Definition: Util.cpp:292
IC::Expression::Polar
@ Polar
Definition: Expression.H:47
IC::Expression::Expression
Expression(amrex::Vector< amrex::Geometry > &_geom)
Definition: Expression.H:53
Set::Field< Set::Scalar >
Definition: Set.H:236
Set::Field::Patch
amrex::Array4< T > Patch(int lev, amrex::MFIter &mfi) const &
Definition: Set.H:76
Set::Vector
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition: Base.H:20
ParmParse.H
pp_query
#define pp_query(...)
Definition: ParmParse.H:105
Set::Scalar
amrex::Real Scalar
Definition: Base.H:19
IC::Expression::coord
Expression::CoordSys coord
Definition: Expression.H:50
pp_queryclass
#define pp_queryclass(...)
Definition: ParmParse.H:106
IC::Expression::Expression
Expression(amrex::Vector< amrex::Geometry > &_geom, IO::ParmParse &pp, std::string name)
Definition: Expression.H:54
IC::Expression::f
std::vector< amrex::ParserExecutor< 4 > > f
Definition: Expression.H:49
IC::Expression::Add
void Add(const int &lev, Set::Field< Set::Vector > &a_field, Set::Scalar a_time=0.0)
Definition: Expression.H:98
IC::Expression::name
static constexpr const char * name
Definition: Expression.H:52
IO::ParmParse::contains
bool contains(std::string name)
Definition: ParmParse.H:153
Util::Assert
AMREX_FORCE_INLINE void Assert(std::string file, std::string func, int line, std::string smt, bool pass, Args const &... args)
Definition: Util.H:67
Util::Abort
void Abort(const char *msg)
Definition: Util.cpp:166
IC::Expression::Add
void Add(const int &lev, Set::Field< Set::Scalar > &a_field, Set::Scalar a_time=0.0)
Definition: Expression.H:58
IC::Expression
Definition: Expression.H:44
IC::Expression::Spherical
@ Spherical
Definition: Expression.H:47
IC::Expression::Cartesian
@ Cartesian
Definition: Expression.H:47
IC
Definition: BMP.H:18
IO::ParmParse::getPrefix
std::string getPrefix() const
Definition: ParmParse.H:133
IO::ParmParse
Definition: ParmParse.H:112
Set::Patch
amrex::Array4< T > const & Patch
Definition: Set.H:88
IC::Expression::Parse
static void Parse(Expression &value, IO::ParmParse &pp)
Definition: Expression.H:138
INFO
#define INFO
Definition: Util.H:20
IC.H
Set::Field< Set::Vector >
IC::Expression::CoordSys
CoordSys
Definition: Expression.H:47