/home/runner/work/kynema-sgf/kynema-sgf/src/physics/ForestDrag.H Source File

Kynema-SGF API: /home/runner/work/kynema-sgf/kynema-sgf/src/physics/ForestDrag.H Source File
Kynema-SGF API v0.1.0
CFD solver for wind plant simulations
Loading...
Searching...
No Matches
ForestDrag.H
Go to the documentation of this file.
1#ifndef FORESTDRAG_H
2#define FORESTDRAG_H
3
4#include "src/core/Physics.H"
5#include "src/core/Field.H"
6#include "src/CFDSim.H"
10#include "AMReX_REAL.H"
11
12using namespace amrex::literals;
13
14namespace kynema_sgf::forestdrag {
15
16// One precomputed inward-facing half-space edge for convex hull tests.
18{
19 amrex::Real m_nx;
20 amrex::Real m_ny;
21 amrex::Real m_d;
22 amrex::Real m_tol_scale;
23};
24
25// Per-forest descriptor consumed by host logic and device kernels.
26struct Forest
27{
28 // Forest identifier written to forest_id field.
29 int m_id{-1};
30 // 0 = legacy cylindrical forest, 1 = point-cloud forest.
32
33 // Point-cloud storage slice [offset, offset + count) in flattened point
34 // array.
37
38 // Convex hull half-space storage slice in flattened edge array.
41
42 // Legacy cylindrical/model parameters.
43 amrex::Real m_type_forest;
44 amrex::Real m_x_forest;
45 amrex::Real m_y_forest;
46 amrex::Real m_height_forest;
47 amrex::Real m_diameter_forest;
48 amrex::Real m_cd_forest;
49 amrex::Real m_lai_forest;
50 amrex::Real m_laimax_forest;
51
52 // Axis-aligned bounding box used for coarse spatial pruning.
53 amrex::Real m_bbox_xlo{0.0_rt};
54 amrex::Real m_bbox_ylo{0.0_rt};
55 amrex::Real m_bbox_zlo{0.0_rt};
56 amrex::Real m_bbox_xhi{0.0_rt};
57 amrex::Real m_bbox_yhi{0.0_rt};
58 amrex::Real m_bbox_zhi{0.0_rt};
59
60 // Compute the type-2 peak LAD scaling factor from integrated LAI.
61 AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real lm() const
62 {
63 amrex::Real treelaimax = 0.0_rt;
64 if (m_type_forest == 2) {
65 const amrex::Real captured_height_forest = m_height_forest;
66 const amrex::Real treeZm = m_laimax_forest * captured_height_forest;
67 const int n = 100;
68 const amrex::Real int_0_fh = kynema_sgf::utils::trapz(
69 0, captured_height_forest - constants::TIGHT_TOL, n,
70 [=](const amrex::Real x) {
71 const amrex::Real ratio =
72 (captured_height_forest - treeZm) /
73 (captured_height_forest - x);
74 const auto exponent = (x < treeZm) ? 6.0_rt : 0.5_rt;
75 return std::pow(ratio, exponent) *
76 std::exp(exponent * (1 - ratio));
77 });
78 treelaimax = m_lai_forest / int_0_fh;
79 }
80 return treelaimax;
81 }
82
83 // Vertical LAD profile used by legacy cylindrical forests.
84 AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real
85 area_fraction(const amrex::Real z, const amrex::Real treelaimax) const
86 {
87 amrex::Real af = 0.0_rt;
88 if (m_type_forest == 1) {
90 } else if (m_type_forest == 2) {
91 const auto treeZm = m_laimax_forest * m_height_forest;
92 const auto ratio =
93 (m_height_forest - treeZm) / (m_height_forest - z);
94 const auto exponent = (z < treeZm) ? 6.0_rt : 0.5_rt;
95 af = treelaimax * std::pow(ratio, exponent) *
96 std::exp(exponent * (1 - ratio));
97 }
98 return af;
99 }
100
101 // Convex-hull half-space test (boundary-inclusive) using precomputed
102 // inward edge normals.
103 AMREX_GPU_DEVICE AMREX_FORCE_INLINE bool point_in_on_hull(
104 const amrex::Real px,
105 const amrex::Real py,
106 const ForestHullEdge* hull_edges) const
107 {
108 if (m_hull_edge_count <= 0) {
109 return true;
110 }
111 for (int i = 0; i < m_hull_edge_count; ++i) {
112 const auto& e = hull_edges[m_hull_edge_offset + i];
113 const amrex::Real signed_dist =
114 (e.m_nx * px) + (e.m_ny * py) - e.m_d;
115 if (signed_dist < -constants::TIGHT_TOL * e.m_tol_scale) {
116 return false;
117 }
118 }
119 return true;
120 }
121
122 // Return real-space bounds for either point-cloud or cylindrical mode.
123 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::RealBox real_bounding_box(
124 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& prob_lo) const
125 {
126 if (m_drag_mode == 1) {
129 }
130
131 const amrex::Real search_tol = 1.1_rt;
132 const amrex::Real search_radius =
133 0.5_rt * search_tol * m_diameter_forest;
134 const auto x0 = m_x_forest - search_radius;
135 const auto y0 = m_y_forest - search_radius;
136 const auto z0 = prob_lo[2];
137 const auto x1 = m_x_forest + search_radius;
138 const auto y1 = m_y_forest + search_radius;
139 const auto z1 = m_height_forest;
140 return {x0, y0, z0, x1, y1, z1};
141 }
142
143 // Integer box used for tile intersection tests before launching kernels.
144 [[nodiscard]] amrex::Box bounding_box(const amrex::Geometry& geom) const
145 {
147 real_bounding_box(geom.ProbLoArray()), geom);
148 }
149};
150
151// A single LAD sample for point-cloud forests.
153{
154 amrex::Real m_x;
155 amrex::Real m_y;
156 amrex::Real m_z;
157 amrex::Real m_lad;
158};
159
163
164class ForestDrag : public Physics::Register<ForestDrag>
165{
166public:
167 static std::string identifier() { return "ForestDrag"; }
168
169 explicit ForestDrag(CFDSim& sim);
170
171 ~ForestDrag() override = default;
172
173 void
174 initialize_fields(int /*level*/, const amrex::Geometry& /*geom*/) override;
175
176 void pre_init_actions() override {}
177
178 void post_init_actions() override {}
179
180 void post_regrid_actions() override;
181
182 void pre_advance_work() override {}
183
184 void post_advance_work() override {}
185
186 // Parse legacy cylindrical forest file for a specific AMR level.
187 [[nodiscard]] amrex::Vector<Forest> read_cylinder_forests(int level) const;
188
189 // Parse point-cloud forests, flatten points/hull-edges, and build forest
190 // descriptors.
191 [[nodiscard]] amrex::Vector<Forest> read_point_cloud_forests(
192 int level,
193 amrex::Vector<ForestPoint>& points,
194 amrex::Vector<ForestHullEdge>& hull_edges) const;
195
196private:
198 // Output fields populated by this physics source.
201
202 // Input configuration for legacy and point-cloud modes.
203 std::string m_forest_file{"forest.amrwind"};
204 amrex::Vector<std::string> m_point_cloud_files;
205 amrex::Vector<amrex::Real> m_forest_cd;
206
207 // Point-cloud interpolation controls.
210};
211} // namespace kynema_sgf::forestdrag
212
213#endif
Definition CFDSim.H:55
Definition Field.H:112
Field & m_forest_drag
Definition ForestDrag.H:199
void pre_advance_work() override
Definition ForestDrag.H:182
CFDSim & m_sim
Definition ForestDrag.H:197
int m_point_neighbors
Definition ForestDrag.H:208
amrex::Vector< amrex::Real > m_forest_cd
Definition ForestDrag.H:205
void post_regrid_actions() override
Definition ForestDrag.cpp:307
void initialize_fields(int, const amrex::Geometry &) override
Definition ForestDrag.cpp:131
ForestDrag(CFDSim &sim)
Definition ForestDrag.cpp:90
void post_advance_work() override
Definition ForestDrag.H:184
std::string m_forest_file
Definition ForestDrag.H:203
Field & m_forest_id
Definition ForestDrag.H:200
amrex::Vector< std::string > m_point_cloud_files
Definition ForestDrag.H:204
amrex::Real m_point_interp_eps
Definition ForestDrag.H:209
void pre_init_actions() override
Definition ForestDrag.H:176
static std::string identifier()
Definition ForestDrag.H:167
void post_init_actions() override
Definition ForestDrag.H:178
amrex::Vector< Forest > read_cylinder_forests(int level) const
Definition ForestDrag.cpp:316
amrex::Vector< Forest > read_point_cloud_forests(int level, amrex::Vector< ForestPoint > &points, amrex::Vector< ForestHullEdge > &hull_edges) const
Definition ForestDrag.cpp:356
static constexpr amrex::Real TIGHT_TOL
A tight tolerance.
Definition constants.H:17
Definition ForestDrag.cpp:20
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real trapz(const amrex::Real xa, const amrex::Real xb, const int n, const Function &f)
Definition integrals.H:14
amrex::Box realbox_to_box(const amrex::RealBox &rbx, const amrex::Geometry &geom)
Definition index_operations.cpp:5
Definition ForestDrag.H:27
amrex::Box bounding_box(const amrex::Geometry &geom) const
Definition ForestDrag.H:144
AMREX_GPU_DEVICE AMREX_FORCE_INLINE bool point_in_on_hull(const amrex::Real px, const amrex::Real py, const ForestHullEdge *hull_edges) const
Definition ForestDrag.H:103
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real lm() const
Definition ForestDrag.H:61
amrex::Real m_bbox_zhi
Definition ForestDrag.H:58
int m_drag_mode
Definition ForestDrag.H:31
amrex::Real m_height_forest
Definition ForestDrag.H:46
amrex::Real m_bbox_yhi
Definition ForestDrag.H:57
amrex::Real m_lai_forest
Definition ForestDrag.H:49
amrex::Real m_bbox_xhi
Definition ForestDrag.H:56
amrex::Real m_type_forest
Definition ForestDrag.H:43
int m_hull_edge_count
Definition ForestDrag.H:40
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real area_fraction(const amrex::Real z, const amrex::Real treelaimax) const
Definition ForestDrag.H:85
int m_cloud_point_count
Definition ForestDrag.H:36
amrex::Real m_bbox_zlo
Definition ForestDrag.H:55
amrex::Real m_laimax_forest
Definition ForestDrag.H:50
amrex::Real m_diameter_forest
Definition ForestDrag.H:47
amrex::Real m_y_forest
Definition ForestDrag.H:45
amrex::Real m_cd_forest
Definition ForestDrag.H:48
amrex::Real m_x_forest
Definition ForestDrag.H:44
amrex::Real m_bbox_xlo
Definition ForestDrag.H:53
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::RealBox real_bounding_box(const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &prob_lo) const
Definition ForestDrag.H:123
int m_id
Definition ForestDrag.H:29
int m_hull_edge_offset
Definition ForestDrag.H:39
int m_cloud_point_offset
Definition ForestDrag.H:35
amrex::Real m_bbox_ylo
Definition ForestDrag.H:54
Definition ForestDrag.H:18
amrex::Real m_nx
Definition ForestDrag.H:19
amrex::Real m_tol_scale
Definition ForestDrag.H:22
amrex::Real m_d
Definition ForestDrag.H:21
amrex::Real m_ny
Definition ForestDrag.H:20
Definition ForestDrag.H:153
amrex::Real m_lad
Definition ForestDrag.H:157
amrex::Real m_z
Definition ForestDrag.H:156
amrex::Real m_x
Definition ForestDrag.H:154
amrex::Real m_y
Definition ForestDrag.H:155