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

Kynema-SGF API: /home/runner/work/kynema-sgf/kynema-sgf/src/wind_energy/actuator/turbine/external/turbine_external_ops.H Source File
Kynema-SGF API v0.1.0
CFD solver for wind plant simulations
Loading...
Searching...
No Matches
turbine_external_ops.H
Go to the documentation of this file.
1#ifndef TURBINE_EXTERNAL_OPS_H
2#define TURBINE_EXTERNAL_OPS_H
3
10
11using namespace kynema_sgf::actuator::external;
12
14
15template <typename datatype>
16void read_ops(datatype& data, const utils::ActParser& pp)
17{
18 // Tell reading utility the name of the solver
19 data.meta().solver_name = data.meta().ext_ptr->identifier();
20 // Data common to any turbine actuator simulation
21 utils::read_inputs(data.meta(), data.info(), pp);
22
23 auto& tdata = data.meta();
24
25 // Get density value for normalization
26 pp.get("density", tdata.density);
27
28 // Copy data to external data holder
29 const auto& tinfo = data.info();
30 auto& tf = data.meta().ext_data;
31 for (int i = 0; i < AMREX_SPACEDIM; ++i) {
32 tf.base_pos[i] = static_cast<float>(tinfo.base_pos[i]);
33 }
34
35 tf.tlabel = tinfo.label;
36 tf.tid_global = tinfo.id;
37 tf.num_blades = tdata.num_blades;
38 tf.num_pts_blade = tdata.num_pts_blade;
39 tf.num_pts_tower = tdata.num_pts_tower;
40 const auto& time = data.sim().time();
41 tf.dt_cfd = time.delta_t();
42 tf.chkpt_interval = time.chkpt_interval();
43}
44
45template <typename datatype>
47{
48 auto& info = data.info();
49 info.procs =
50 utils::determine_influenced_procs(data.sim().mesh(), info.bound_box);
51
52 AMREX_ALWAYS_ASSERT(info.root_proc > -1);
53 // During regrid, the influenced processes might have changed and might
54 // no longer include the root proc. We insert it back to ensure that it
55 // is always present on the list.
56 info.procs.insert(info.root_proc);
57
58 const int iproc = amrex::ParallelDescriptor::MyProc();
59 auto in_proc = info.procs.find(iproc);
60 info.actuator_in_proc = (in_proc != info.procs.end());
61 info.sample_vel_in_proc = info.is_root_proc;
62}
63
64template <typename datatype, typename SolverTurbine, typename SolverData>
66 datatype& data, amrex::Vector<int>& act_proc_count)
67{
69 auto& info = data.info();
70 info.procs =
71 utils::determine_influenced_procs(data.sim().mesh(), info.bound_box);
72
73 utils::determine_root_proc(info, act_proc_count);
74
75 // TODO: This function is doing a lot more than advertised by the name.
76 // Should figure out a better way to perform the extra work.
77
78 // For OpenFAST we only need velocities sampled in root process
79 info.sample_vel_in_proc = info.is_root_proc;
80
81 // Initialize the OpenFAST object and register this turbine in the root
82 // process
83 if (info.is_root_proc) {
84 auto& tdata = data.meta();
85 auto& ext_mgr = data.sim().ext_solver_manager();
86 ext_mgr.create(::ext_turb::ext_id<SolverData>(), data.sim());
87 tdata.ext_ptr =
88 &(ext_mgr.template get<
90 tdata.ext_ptr->register_turbine(tdata.ext_data);
91 }
92}
93
94template <typename datatype>
95void init_data_op(datatype& data)
96{
97
98 const auto& info = data.info();
99 auto& tdata = data.meta();
100
101 // Initialize our communicator for broadcasting data
102 amrex::ParallelDescriptor::Comm_dup(
103 amrex::ParallelDescriptor::Communicator(), tdata.tcomm);
104
105 amrex::Array<int, 6> sz_info = {0, 0, 0, 0, 0, 0};
106 if (info.is_root_proc) {
107 tdata.ext_ptr->init_turbine(tdata.ext_data.tid_local);
108
109 const auto& tf = tdata.ext_data;
110 sz_info[0] = tf.num_blades;
111 sz_info[1] = tf.length_force(0);
112 sz_info[2] = tf.length_fluid_velocity(0);
113 sz_info[3] = tf.num_pts_tower;
114 sz_info[4] = tf.num_vel_pts_blade();
115 sz_info[5] = tdata.ext_ptr->offset_velocity_points();
116 }
117
118 // Broadcast data to everyone
119 amrex::ParallelDescriptor::Bcast(
120 sz_info.begin(), sz_info.size(), info.root_proc, tdata.tcomm);
121
122 {
123 tdata.num_blades = sz_info[0];
124 // back calculate what the value per blade for number of points in
125 // the openfast data structure
126 tdata.num_vel_pts_blade = sz_info[4];
127 data.grid().resize(sz_info[1], sz_info[2]);
128 tdata.chord.resize(sz_info[1]);
129 tdata.num_pts_tower = sz_info[3];
130 tdata.velocity_points_offset = sz_info[5];
131 }
132
133 tdata.vel_rel.assign(sz_info[1], vs::Vector::zero());
134
135 if (info.is_root_proc) {
136 // copy chord data
137 int npts = sz_info[1];
138 for (int i = 0; i < npts; ++i) {
139 tdata.chord[i] =
140 static_cast<amrex::Real>(tdata.ext_data.chord_at_force()[i]);
141 }
142 }
143
144 amrex::ParallelDescriptor::Bcast(
145 tdata.chord.data(), tdata.chord.size(), info.root_proc, tdata.tcomm);
146
149}
150
151template <typename datatype>
152void update_pos_op(datatype& data)
153{
154 // Return early if this is not the root process for this turbine
155 //
156 // This is handled in Actuator class, but we add a check here just as a
157 // safeguard
158 if (!data.info().is_root_proc) {
159 return;
160 }
161
162 const auto& tdata = data.meta();
163 const auto& bp = data.info().base_pos;
164 const auto& pxvel = tdata.ext_data.position_at_vel(0);
165 const auto& pyvel = tdata.ext_data.position_at_vel(1);
166 const auto& pzvel = tdata.ext_data.position_at_vel(2);
167 auto& vel_pos = data.grid().vel_pos;
168 for (int i = 0; i < vel_pos.size(); ++i) {
169 vel_pos[i].x() = static_cast<amrex::Real>(pxvel[i]) + bp.x();
170 vel_pos[i].y() = static_cast<amrex::Real>(pyvel[i]) + bp.y();
171 vel_pos[i].z() = static_cast<amrex::Real>(pzvel[i]) + bp.z();
172 }
173}
174
175template <typename datatype>
176void update_vel_op(datatype& data)
177{
178 // Return early if this is not the root process for this turbine
179 //
180 // This is handled in Actuator class, but we add a check here just as a
181 // safeguard
182 if (!data.info().is_root_proc) {
183 return;
184 }
185 auto& tdata = data.meta();
186
187 const auto& uvel = tdata.ext_data.fluid_velocity(0);
188 const auto& vvel = tdata.ext_data.fluid_velocity(1);
189 const auto& wvel = tdata.ext_data.fluid_velocity(2);
190 const auto& vel = data.grid().vel;
191
192 if (!tdata.fllc.empty()) {
193 // Compute the relative velocity needed for the FLLC
194 const auto& xdot = tdata.ext_data.solid_velocity(0);
195 const auto& ydot = tdata.ext_data.solid_velocity(1);
196 const auto& zdot = tdata.ext_data.solid_velocity(2);
197 for (int i = 0; i < tdata.vel_rel.size(); ++i) {
198 tdata.vel_rel[i][0] = uvel[i] - static_cast<amrex::Real>(xdot[i]);
199 tdata.vel_rel[i][1] = vvel[i] - static_cast<amrex::Real>(ydot[i]);
200 tdata.vel_rel[i][2] = wvel[i] - static_cast<amrex::Real>(zdot[i]);
201 }
202 // Loop through each blade and apply the FLLC
203 for (int i = 0; i < tdata.num_blades; ++i) {
204 FLLCOp()(tdata.blades[i], tdata.fllc[i]);
205 }
206 }
207
208 for (int i = 0; i < tdata.ext_data.length_fluid_velocity(0); ++i) {
209 uvel[i] = static_cast<float>(vel[i].x());
210 vvel[i] = static_cast<float>(vel[i].y());
211 wvel[i] = static_cast<float>(vel[i].z());
212 }
213}
214
215template <typename datatype>
216void compute_force_op(datatype& data)
217{
218 // Advance external solver by specified number of sub-steps
219 ext_step<datatype>(data);
220 // Broadcast data to all the processes that contain patches influenced
221 // by this turbine
223
224 const auto& time = data.sim().time();
225
226 auto& tdata = data.meta();
227 if (!tdata.fllc.empty()) {
228 for (int i = 0; i < tdata.num_blades; ++i) {
229 if (!(tdata.fllc[i].initialized) &&
230 (time.current_time() > tdata.fllc[i].fllc_start_time)) {
231 fllc_init(tdata.fllc[i], tdata.blades[i], tdata.eps_chord[0]);
232 }
233 }
234 }
235}
236
237} // namespace kynema_sgf::actuator::ops
238
239#endif /* TURBINE_EXTERNAL_OPS_H */
Definition ExtTurbIface.H:26
void get(const std::string &name, vs::Vector &value) const
Definition MultiParser.H:44
std::string ext_id()
Definition turbine_external_utils.H:15
void ext_step(datatype &data)
Definition turbine_external_utils.H:173
void make_component_views(datatype &data)
Definition turbine_external_utils.H:27
void scatter_data(datatype &data)
Definition turbine_external_utils.H:196
void init_epsilon(datatype &data)
Definition turbine_external_utils.H:89
Definition ActSrcLineOp.H:12
void external_determine_root_proc(datatype &data, amrex::Vector< int > &act_proc_count)
Definition turbine_external_ops.H:65
void read_ops(datatype &data, const utils::ActParser &pp)
Definition turbine_external_ops.H:16
void update_pos_op(datatype &data)
Definition turbine_external_ops.H:152
void update_vel_op(datatype &data)
Definition turbine_external_ops.H:176
void external_determine_influenced_procs(datatype &data)
Definition turbine_external_ops.H:46
void init_data_op(datatype &data)
Definition turbine_external_ops.H:95
void compute_force_op(datatype &data)
Definition turbine_external_ops.H:216
Definition ActParser.H:6
::kynema_sgf::utils::MultiParser ActParser
Definition ActParser.H:8
std::set< int > determine_influenced_procs(const amrex::AmrCore &mesh, const amrex::RealBox &rbx)
Definition actuator_utils.cpp:8
void read_inputs(TurbineBaseData &tdata, TurbineInfo &tinfo, const utils::ActParser &pp)
Definition turbine_utils.cpp:11
void determine_root_proc(ActInfo &info, amrex::Vector< int > &act_proc_count)
Definition actuator_utils.cpp:36
void fllc_init(FLLCData &data, const ComponentView &view, const amrex::Real eps_chord)
Initialize FLLC data structure. This should be called at the end of the first ComputeForceOp to ensur...
Definition FLLC.cpp:9
This struct will operate on a blade/wing. The velocity from the simulation is corrected using the Fil...
Definition FLLCOp.H:21
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE constexpr VectorT< amrex::Real > zero()
Definition vector.H:45