/home/runner/work/kynema-sgf/kynema-sgf/src/wind_energy/actuator/turbine/ActSrcDiskOp_Turbine.H Source File

Kynema-SGF API: /home/runner/work/kynema-sgf/kynema-sgf/src/wind_energy/actuator/turbine/ActSrcDiskOp_Turbine.H Source File
Kynema-SGF API v0.1.0
CFD solver for wind plant simulations
Loading...
Searching...
No Matches
ActSrcDiskOp_Turbine.H
Go to the documentation of this file.
1#ifndef ACTSRCDISKOP_TURBINE_H
2#define ACTSRCDISKOP_TURBINE_H
3
4#include <numbers>
5#include "AMReX_REAL.H"
10
11using namespace amrex::literals;
12
14
15template <typename ActTrait>
17 ActTrait,
19 std::enable_if_t<std::is_base_of_v<TurbineType, ActTrait>>>
20{
21private:
22 typename ActTrait::DataType& m_data;
24
25 // Device copies of the actuator grid data. The component views in the
26 // turbine meta data hold host pointers and cannot be used in kernels.
31
36
37 void copy_to_device();
38
39public:
40 explicit ActSrcOp(typename ActTrait::DataType& data)
41 : m_data(data)
42 , m_act_src(m_data.sim().repo().get_field("actuator_src_term"))
43 {}
44
45 void initialize();
46
48
49 void
50 operator()(int lev, const amrex::MFIter& mfi, const amrex::Geometry& geom);
51};
52
53template <typename ActTrait>
54void ActSrcOp<
55 ActTrait,
57 std::enable_if_t<std::is_base_of_v<TurbineType, ActTrait>>>::initialize()
58{
59 const auto& grid = m_data.grid();
60 const auto& meta = m_data.meta();
61 m_pos.resize(grid.pos.size());
62 m_force.resize(grid.force.size());
63 m_epsilon.resize(grid.epsilon.size());
64 m_orientation.resize(grid.orientation.size());
65
66 // Locate the components within the actuator grid arrays
67 const auto* gpos = grid.pos.data();
68 m_hub_start = static_cast<int>(meta.hub.pos.data() - gpos);
69 m_blade_start = static_cast<int>(meta.blades[0].pos.data() - gpos);
70 for (int ib = 0; ib < meta.num_blades; ++ib) {
71 AMREX_ALWAYS_ASSERT(
72 meta.blades[ib].pos.data() ==
73 gpos + m_blade_start + (ib * meta.num_pts_blade));
74 }
75 if (meta.num_pts_tower > 0) {
76 m_tower_start = static_cast<int>(meta.tower.pos.data() - gpos);
77 }
78}
79
80template <typename ActTrait>
81void ActSrcOp<
82 ActTrait,
84 std::enable_if_t<std::is_base_of_v<TurbineType, ActTrait>>>::
85 copy_to_device()
86{
87 const auto& grid = m_data.grid();
88 amrex::Gpu::copy(
89 amrex::Gpu::hostToDevice, grid.pos.begin(), grid.pos.end(),
90 m_pos.begin());
91 amrex::Gpu::copy(
92 amrex::Gpu::hostToDevice, grid.force.begin(), grid.force.end(),
93 m_force.begin());
94 amrex::Gpu::copy(
95 amrex::Gpu::hostToDevice, grid.epsilon.begin(), grid.epsilon.end(),
96 m_epsilon.begin());
97 amrex::Gpu::copy(
98 amrex::Gpu::hostToDevice, grid.orientation.begin(),
99 grid.orientation.end(), m_orientation.begin());
100}
101
102template <typename ActTrait>
103void ActSrcOp<
104 ActTrait,
106 std::enable_if_t<std::is_base_of_v<TurbineType, ActTrait>>>::
107operator()(const int lev, const amrex::MFIter& mfi, const amrex::Geometry& geom)
108{
109 BL_PROFILE(
110 "kynema-sgf::ActSrcOp<" + ActTrait::identifier() +
111 ActSrcDisk::identifier() + ">");
112
113 const auto& bx = mfi.tilebox();
114
115 const auto bxa =
116 kynema_sgf::utils::realbox_to_box(m_data.info().bound_box, geom);
117 const auto& bxi = bx & bxa;
118 if (bxi.isEmpty()) {
119 return;
120 }
121
122 const auto& sarr = m_act_src(lev).array(mfi);
123 const auto& problo = geom.ProbLoArray();
124 const auto& dx = geom.CellSizeArray();
125
126 auto& tdata = m_data.meta();
127 const int nBlades = tdata.num_blades;
128 const int nPB = tdata.num_pts_blade;
129 const int nPT = tdata.num_pts_tower;
130 const auto* pos = m_pos.data();
131 const auto* force = m_force.data();
132 const auto* eps = m_epsilon.data();
133 const auto* tmat = m_orientation.data();
134 const int hub_start = m_hub_start;
135 const int blade_start = m_blade_start;
136 const int tower_start = m_tower_start;
137 // assume constant dr same for all blades
138 const auto* host_pos = tdata.blades[0].pos.data();
139 const amrex::Real dR = vs::mag(host_pos[0] - host_pos[1]);
140 const amrex::Real dT =
141 2.0_rt * std::numbers::pi_v<amrex::Real> / tdata.num_blades;
142 // assume these will be copied to device by the lambda capture...
143 const vs::Vector m_normal(tdata.rotor_frame.x());
144 const vs::Vector m_origin(tdata.rot_center);
145
146 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
147 const vs::Vector cc{
148 problo[0] + ((i + 0.5_rt) * dx[0]),
149 problo[1] + ((j + 0.5_rt) * dx[1]),
150 problo[2] + ((k + 0.5_rt) * dx[2]),
151 };
152
153 amrex::RealArray src_force = {0.0_rt};
154 // blade/disk contribution
155 for (int ib = 0; ib < nBlades; ++ib) {
156 const int ioff = blade_start + (ib * nPB);
157 for (int ip = ioff; ip < ioff + nPB; ++ip) {
158 const auto R =
159 utils::delta_pnts_cyl(m_origin, m_normal, m_origin, pos[ip])
160 .x();
161 const auto dist_on_disk =
162 utils::delta_pnts_cyl(m_origin, m_normal, cc, pos[ip]);
163 const auto& pforce = force[ip];
164
165 const amrex::Real weight_R =
166 utils::linear_basis_1d(dist_on_disk.x(), dR);
167 const amrex::Real weight_T =
168 utils::linear_basis_1d(R * dist_on_disk.y(), dT * R);
169 const amrex::Real weight_N =
170 utils::gaussian1d(dist_on_disk.z(), eps[ip].x());
171 const auto projection_weight = weight_R * weight_T * weight_N;
172
173 src_force[0] += projection_weight * pforce.x();
174 src_force[1] += projection_weight * pforce.y();
175 src_force[2] += projection_weight * pforce.z();
176 }
177 }
178 // tower contribution
179 for (int ip = tower_start; ip < tower_start + nPT; ++ip) {
180 const auto dist = cc - pos[ip];
181 const auto dist_local = tmat[ip] & dist;
182 const auto gauss_fac = utils::gaussian3d(dist_local, eps[ip]);
183 const auto& pforce = force[ip];
184
185 src_force[0] += gauss_fac * pforce.x();
186 src_force[1] += gauss_fac * pforce.y();
187 src_force[2] += gauss_fac * pforce.z();
188 }
189 // hub
190 {
191 const auto dist = cc - pos[hub_start];
192 const auto dist_local = tmat[hub_start] & dist;
193 const auto gauss_fac =
194 utils::gaussian3d(dist_local, eps[hub_start]);
195 const auto& pforce = force[hub_start];
196 src_force[0] += gauss_fac * pforce.x();
197 src_force[1] += gauss_fac * pforce.y();
198 src_force[2] += gauss_fac * pforce.z();
199 }
200
201 sarr(i, j, k, 0) += src_force[0];
202 sarr(i, j, k, 1) += src_force[1];
203 sarr(i, j, k, 2) += src_force[2];
204 });
205}
206} // namespace kynema_sgf::actuator::ops
207
208#endif /* ACTSRCDISKOP_TURBINE_H */
Definition Field.H:115
int m_hub_start
Index of the first point of each component in the actuator grid.
Definition ActSrcDiskOp_Turbine.H:33
Definition actuator_ops.H:71
Definition ActSrcLineOp.H:12
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real linear_basis_1d(const amrex::Real distance, const amrex::Real dX)
Definition actuator_utils.H:127
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real gaussian3d(const vs::Vector &dist, const vs::Vector &eps)
Definition actuator_utils.H:45
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real gaussian1d(const amrex::Real &dist, const amrex::Real &eps)
Definition actuator_utils.H:71
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE vs::Vector delta_pnts_cyl(const vs::Vector &origin, const vs::Vector &normal, const vs::Vector &point1, const vs::Vector &point2)
Definition actuator_utils.H:89
amrex::Gpu::DeviceVector< kynema_sgf::vs::Tensor > DeviceTensorList
Definition actuator_types.H:98
amrex::Gpu::DeviceVector< kynema_sgf::vs::Vector > DeviceVecList
Definition actuator_types.H:97
Definition bluff_body_ops.cpp:18
amrex::Box realbox_to_box(const amrex::RealBox &rbx, const amrex::Geometry &geom)
Definition index_operations.cpp:5
VectorT< amrex::Real > Vector
Definition vector.H:145
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T mag(const TensorT< T > &t)
Definition tensorI.H:181
Definition actuator_types.H:59
static std::string identifier()
Definition actuator_types.H:60
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T & x() &
Definition vector.H:97