/home/runner/work/amr-wind/amr-wind/amr-wind/wind_energy/actuator/turbine/external/turbine_external_ops.H Source File

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