Skip to content

Commit e3595fa

Browse files
authored
User specified tagging criteria (#1673)
1 parent c1c4bf0 commit e3595fa

File tree

7 files changed

+223
-10
lines changed

7 files changed

+223
-10
lines changed

amr-wind/utilities/tagging/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ target_sources(${amr_wind_lib_name} PRIVATE
1313
# Geometry based refinement options
1414
BoxRefiner.cpp
1515
CylinderRefiner.cpp
16+
UDFRefiner.cpp
1617
)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#ifndef UDFREFINER_H
2+
#define UDFREFINER_H
3+
4+
#include "amr-wind/CFDSim.H"
5+
#include "amr-wind/utilities/tagging/GeometryRefinement.H"
6+
#include "AMReX_Parser.H"
7+
8+
namespace amr_wind::tagging {
9+
10+
/** AMR refinement using a user defined expression
11+
* \ingroup amr_utils
12+
*
13+
*/
14+
class UDFRefiner : public GeometryType::Register<UDFRefiner>
15+
{
16+
public:
17+
static std::string identifier() { return "udf"; }
18+
19+
explicit UDFRefiner(const CFDSim& sim, const std::string& key);
20+
21+
~UDFRefiner() override = default;
22+
23+
void operator()(
24+
const amrex::Box& /*bx*/,
25+
const amrex::Geometry& geom,
26+
const amrex::Array4<amrex::TagBox::TagType>& tags) const override;
27+
28+
const amrex::RealBox& bound_box() const override { return m_bound_box; };
29+
30+
private:
31+
const CFDSim& m_sim;
32+
amrex::RealBox m_bound_box;
33+
amrex::Parser m_parser;
34+
};
35+
36+
} // namespace amr_wind::tagging
37+
38+
#endif /* UDFREFINER_H */
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include "amr-wind/utilities/tagging/UDFRefiner.H"
2+
#include "AMReX_ParmParse.H"
3+
4+
namespace amr_wind::tagging {
5+
6+
UDFRefiner::UDFRefiner(const CFDSim& sim, const std::string& key)
7+
: m_sim(sim), m_bound_box(m_sim.repo().mesh().Geom(0).ProbDomain())
8+
{
9+
amrex::ParmParse pp(key);
10+
std::string udf_str;
11+
pp.get("udf", udf_str);
12+
13+
amrex::Vector<amrex::Real> box_lo(AMREX_SPACEDIM, 0);
14+
amrex::Vector<amrex::Real> box_hi(AMREX_SPACEDIM, 0);
15+
if (pp.queryarr("box_lo", box_lo, 0, static_cast<int>(box_lo.size())) ==
16+
1) {
17+
m_bound_box.setLo(box_lo);
18+
}
19+
if (pp.queryarr("box_hi", box_hi, 0, static_cast<int>(box_hi.size())) ==
20+
1) {
21+
m_bound_box.setHi(box_hi);
22+
}
23+
m_parser.define(udf_str);
24+
m_parser.registerVariables({"t", "x", "y", "z"});
25+
}
26+
27+
void UDFRefiner::operator()(
28+
const amrex::Box& bx,
29+
const amrex::Geometry& geom,
30+
const amrex::Array4<amrex::TagBox::TagType>& tag) const
31+
{
32+
const auto& problo = geom.ProbLoArray();
33+
const auto& dx = geom.CellSizeArray();
34+
const auto time = m_sim.time().current_time();
35+
auto udf_func = m_parser.compile<AMREX_SPACEDIM + 1>();
36+
37+
amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
38+
const amrex::Real x = problo[0] + (i + 0.5) * dx[0];
39+
const amrex::Real y = problo[1] + (j + 0.5) * dx[1];
40+
const amrex::Real z = problo[2] + (k + 0.5) * dx[2];
41+
const auto val = udf_func(time, x, y, z);
42+
if (static_cast<bool>(val)) {
43+
tag(i, j, k) = amrex::TagBox::SET;
44+
}
45+
});
46+
}
47+
48+
} // namespace amr_wind::tagging

amr-wind/wind_energy/MOData.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,6 @@ void MOData::update_fluxes(int max_iters)
8888
++iter;
8989
} while ((std::abs(utau_iter - utau) > 1e-5) && iter <= max_iters);
9090

91-
amrex::Print() << "MOData::update_fluxes: output\n"
92-
<< " utau = " << utau << "\n"
93-
<< " q = " << surf_temp_flux << "\n"
94-
<< " L = " << obukhov_len << std::endl;
95-
9691
if (iter >= max_iters) {
9792
amrex::Print()
9893
<< "MOData::update_fluxes: Convergence criteria not met after "

docs/sphinx/user/inputs_tagging.rst

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ Refinement using geometry
122122

123123
This section controls refinement using pre-defined geometric shapes. Currently,
124124
two options are supported: 1. ``box`` -- refines the region inside a hexahedral
125-
block, and 2. ``cylinder`` -- refines the region inside a cylindrical block.
125+
block, 2. ``cylinder`` -- refines the region inside a cylindrical block, and
126+
3. ``udf`` -- refines along an analytical function depending on time and spatial coordinate.
126127

127128
.. input_param:: tagging.GeometryRefinement.shapes
128129

@@ -181,11 +182,21 @@ Example::
181182
tagging.g2.c1.outer_radius = 300.0
182183
tagging.g2.c1.inner_radius = 275.0
183184

185+
tagging.g3.type = GeometryRefinement
186+
tagging.g3.shapes = udf0
187+
tagging.g3.level = 0
188+
tagging.g3.udf0.type = udf
189+
tagging.g3.udf0.udf = "if(x > 500, 1.0, 0.0)"
190+
tagging.g3.udf0.box_lo = 0.0 0.0 0.0
191+
tagging.g3.udf0.box_hi = 1000.0 1000.0 500.0
184192

185-
This example defines two different refinement definitions acting on level 0 and
186-
1 respectively. The refinement at level 0 (``g1``) contains two box regions,
187-
whereas the refinement at level 1 (``g2``) only contains one cylinder
188-
definition.
193+
194+
This example defines three different refinement definitions acting on
195+
levels 0, 1 and 0 respectively. The first refinement at level 0
196+
(``g1``) contains two box regions, whereas the refinement at level 1
197+
(``g2``) only contains one cylinder definition. The second refinement
198+
at level 0 (``g3``) uses a user defined function (UDF) to specify a
199+
geometrical refinement region.
189200

190201
**Refinement using hexahedral block definitions**
191202

@@ -212,6 +223,41 @@ The axis and the extents along the axis are defined by two position vectors
212223
optional ``inner_radius`` can be specified to restrict tagging to an annulus
213224
between the inner and outer radii.
214225

226+
**Refinement using a user specified function**
227+
228+
The UDF uses AMReX's Parser class to parse a string in the input file,
229+
``udf`` key in the input file. For more information on the AMReX
230+
Parser and supported functions, consult the `AMReX Parser
231+
documentation
232+
<https://amrex-codes.github.io/amrex/docs_html/Basics.html#parser>`_.
233+
The UDF can be (almost) arbitrarily complex, leveraging standard
234+
functions, boolean operators, local variables, etc. The following
235+
assumptions are imposed on the UDF: 1. it must evaluate to 0 (tagging
236+
off) or 1 (tagging on) (the return value of the UDF is cast to a
237+
boolean and that is used to set the tags), 2. the allowed variables
238+
are ``t``, ``x``, ``y``, and ``z``.
239+
240+
.. input_param:: tagging.GeometryRefinement.UDFRefiner.udf
241+
242+
**type:** String, required
243+
244+
String specifying the user defined function.
245+
246+
.. input_param:: tagging.GeometryRefinement.UDFRefiner.box_lo
247+
248+
**type:** Vector<Real>, optional
249+
250+
List of the low corner values for a bounding box where the tagging
251+
will be active. By default the bounding box will span the entire domain.
252+
253+
.. input_param:: tagging.GeometryRefinement.UDFRefiner.box_hi
254+
255+
**type:** Vector<Real>, optional
256+
257+
List of the high corner values for a bounding box where the tagging
258+
will be active. By default the bounding box will span the entire domain.
259+
260+
215261
Refinement using Q-Criterion
216262
`````````````````````````````````````
217263

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ add_test_re(ctv_mol_mesh_map_explicit)
287287
add_test_re(abl_specifiedmol_neutral)
288288
add_test_re(abl_specifiedmol_stable)
289289
add_test_re(abl_specifiedmol_unstable)
290+
add_test_re(udf_refinement)
290291

291292
if(AMR_WIND_ENABLE_NETCDF)
292293
add_test_re(abl_bndry_output)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨#
2+
# SIMULATION STOP #
3+
#.......................................#
4+
time.stop_time = 22000.0 # Max (simulated) time to evolve
5+
time.max_step = 10 # Max number of time steps
6+
7+
#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨#
8+
# TIME STEP COMPUTATION #
9+
#.......................................#
10+
time.fixed_dt = 0.5 # Use this constant dt if > 0
11+
time.cfl = 0.95 # CFL factor
12+
13+
#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨#
14+
# INPUT AND OUTPUT #
15+
#.......................................#
16+
time.plot_interval = 10 # Steps between plot files
17+
time.checkpoint_interval = 5 # Steps between checkpoint files
18+
19+
#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨#
20+
# PHYSICS #
21+
#.......................................#
22+
incflo.gravity = 0. 0. -9.81 # Gravitational force (3D)
23+
incflo.density = 1.0 # Reference density
24+
25+
incflo.use_godunov = 1
26+
# default godunov_type is weno_z
27+
incflo.diffusion_type = 1
28+
transport.viscosity = 1.0e-5
29+
transport.laminar_prandtl = 0.7
30+
transport.turbulent_prandtl = 0.3333
31+
transport.reference_temperature = 300.0
32+
turbulence.model = Smagorinsky
33+
Smagorinsky_coeffs.Cs = 0.135
34+
35+
36+
incflo.physics = ABL
37+
ICNS.source_terms = BoussinesqBuoyancy CoriolisForcing ABLForcing
38+
CoriolisForcing.latitude = 41.3
39+
ABLForcing.abl_forcing_height = 90
40+
41+
incflo.velocity = 6.128355544951824 5.142300877492314 0.0
42+
43+
ABL.temperature_heights = 650.0 750.0 1000.0
44+
ABL.temperature_values = 300.0 308.0 308.75
45+
46+
ABL.kappa = .41
47+
ABL.surface_roughness_z0 = 0.15
48+
49+
#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨#
50+
# ADAPTIVE MESH REFINEMENT #
51+
#.......................................#
52+
# amr.n_cell = 48 48 48 # Grid cells at coarsest AMRlevel
53+
amr.n_cell = 128 128 128 # Grid cells at coarsest AMRlevel
54+
amr.max_level = 1 # Max AMR level in hierarchy
55+
amr.max_grid_size = 8
56+
amr.n_error_buf = 0
57+
58+
#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨#
59+
# GEOMETRY #
60+
#.......................................#
61+
geometry.prob_lo = 0. 0. 0. # Lo corner coordinates
62+
geometry.prob_hi = 1000. 1000. 1000. # Hi corner coordinates
63+
geometry.is_periodic = 1 1 0 # Periodicity x y z (0/1)
64+
65+
# Boundary conditions
66+
zlo.type = "wall_model"
67+
68+
zhi.type = "slip_wall"
69+
zhi.temperature_type = "fixed_gradient"
70+
zhi.temperature = 0.003 # tracer is used to specify potential temperature gradient
71+
72+
#¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨#
73+
# VERBOSITY #
74+
#.......................................#
75+
incflo.verbose = 0 # incflo_level
76+
77+
tagging.labels = udf
78+
tagging.udf.type = GeometryRefinement
79+
tagging.udf.shapes = udf0
80+
tagging.udf.level = 0
81+
tagging.udf.udf0.type = udf
82+
tagging.udf.udf0.udf = "x0 = 500.0; y0 = 500.0; z0 = 500.0; r1 = 200.0; r2 = 250.0; xp = x - x0; yp = y - y0; zp = z - z0; d2 = (xp^2 + yp^2 + zp^2); if((r1**2 <= d2) and (d2 <= r2^2), 1.0, 0.0)"
83+
tagging.udf.udf0.box_lo = 0.0 0.0 0.0
84+
tagging.udf.udf0.box_hi = 1000.0 1000.0 500.0

0 commit comments

Comments
 (0)