/home/runner/work/amr-wind/amr-wind/amr-wind/wind_energy/actuator/wing/wing_ops.H Source File

AMR-Wind API: /home/runner/work/amr-wind/amr-wind/amr-wind/wind_energy/actuator/wing/wing_ops.H Source File
AMR-Wind API v0.1.0
CFD solver for wind plant simulations
Loading...
Searching...
No Matches
wing_ops.H
Go to the documentation of this file.
1#ifndef WING_OPS_H
2#define WING_OPS_H
3
12#include "AMReX_REAL.H"
13
14using namespace amrex::literals;
15
16namespace amr_wind::actuator {
17namespace wing {
18
19// Initialize core data structures when modeling fixed wings
20void init_data_structures(WingBaseData& /*wdata*/, ActGrid& /*grid*/);
21
23 const std::string& /*ncfile*/,
24 const WingBaseData& /*meta*/,
25 const ActInfo& /*info*/,
26 const ActGrid& /*grid*/);
27
28void write_netcdf(
29 const std::string& /*ncfile*/,
30 const WingBaseData& /*meta*/,
31 const ActInfo& /*info*/,
32 const ActGrid& /*grid*/,
33 const amrex::Real /*time*/);
34
35void refresh_wing_position(VecList& vpoints, VecList fpoints, const int npts);
36
38 VecList& points,
39 vs::Vector& vtr,
40 const int npts,
41 const amrex::Real tn,
42 const amrex::Real tnp1,
43 const std::string& motion,
44 const amrex::Real period,
45 const vs::Vector svec);
46
47template <typename T>
48ComponentView make_component_view(typename T::DataType& data)
49{
50 auto& grid = data.grid();
51 auto& meta = data.meta();
52 ComponentView view;
53 view.pos = ::amr_wind::utils::slice(grid.pos, 0, meta.num_pts);
54 view.vel_pos = ::amr_wind::utils::slice(grid.vel_pos, 0, meta.num_pts);
55 view.force = ::amr_wind::utils::slice(grid.force, 0, meta.num_pts);
56 view.epsilon = ::amr_wind::utils::slice(grid.epsilon, 0, meta.num_pts);
57 view.orientation =
58 ::amr_wind::utils::slice(grid.orientation, 0, meta.num_pts);
59 view.chord = ::amr_wind::utils::slice(meta.chord, 0, meta.num_pts);
60 view.vel_rel = ::amr_wind::utils::slice(meta.vel_rel, 0, meta.num_pts);
61 view.vel = ::amr_wind::utils::slice(grid.vel, 0, meta.num_pts);
62
63 return view;
64}
65
66} // namespace wing
67
68namespace ops {
69
70template <typename T>
72airfoil_lookup(typename T::DataType& data);
73
74template <typename ActTrait, typename SrcTrait>
76{
77 static constexpr bool update_pos = true;
78 static constexpr bool update_vel = true;
79 static constexpr bool compute_force = true;
80 static constexpr bool process_outputs = true;
81};
82
83template <typename ActTrait>
85 ActTrait,
87 typename std::enable_if_t<
88 std::is_base_of_v<WingType, ActTrait> &&
89 UseDefaultOp<ActTrait, ActSrcLine>::update_pos>>
90{
91 void operator()(typename ActTrait::DataType& data)
92 {
93 // Put wing at current (time n) position from force points
94 auto& grid = data.grid();
95 const int npts = data.meta().num_pts;
96 actuator::wing::refresh_wing_position(grid.vel_pos, grid.pos, npts);
97 }
98};
99
100template <typename ActTrait>
102 ActTrait,
104 typename std::enable_if_t<
105 std::is_base_of_v<WingType, ActTrait> &&
106 UseDefaultOp<ActTrait, ActSrcLine>::update_vel>>
107{
108
109 void operator()(typename ActTrait::DataType& data)
110 {
111 auto& meta = data.meta();
112 if (meta.fllc) {
113 FLLCOp()(meta.component_view, *(meta.fllc));
114 }
115 }
116};
117
118template <typename ActTrait>
120 ActTrait,
122 typename std::enable_if_t<
123 std::is_base_of_v<WingType, ActTrait> &&
124 UseDefaultOp<ActTrait, ActSrcLine>::compute_force>>
125{
126 void operator()(typename ActTrait::DataType& data)
127 {
128 auto& grid = data.grid();
129 auto& wdata = data.meta();
130 const int npts = wdata.num_pts;
131 const auto& dx = wdata.dx;
132 const auto& chord = wdata.chord;
133 const auto& aflookup = airfoil_lookup<ActTrait>(data);
134 const auto& time = data.sim().time();
135
136 // Move force points to location at n+1
137 // Also, get velocity of actuator from n to n+1
138 // (will be unchanged for "none" and "linear" motion)
140 grid.pos, wdata.vel_tr, npts, time.current_time(), time.new_time(),
141 wdata.motion_type, wdata.s_period, wdata.s_vector);
142
143 // Build the local reference frame
144 const vs::Vector wspan = wdata.end - wdata.start;
145
146 // Use the global coord to orient the blade
147 // The default is for inflow in the x direction
148 const auto blade_y = wspan.unit();
149 const auto blade_z = (wdata.blade_x.unit() ^ blade_y).unit();
150 // Ensure orthogonality for new reference frame
151 const auto blade_x = (blade_y ^ blade_z).unit();
152
153 // Calculate the aoa based on the pitch actuation table if supplied
154 // (interpolate pitch angle at step n+1/2) or the initial pitch angle
155 if (!wdata.pitch_timetable_file.empty()) {
156 const auto time_interp =
157 (time.current_time() + time.new_time()) / 2.0_rt;
158 wdata.pitch = amr_wind::interp::linear_angle(
159 wdata.time_table, wdata.pitch_table, time_interp, 360.0_rt);
160 amrex::Print() << "Wing Ops: Current wing pitch (at time "
161 << time_interp << " s) is " << wdata.pitch
162 << " degrees.\n";
163 // Recalculate transformation matrix and update on grid struct
164 auto tmat = vs::quaternion(wspan, wdata.pitch);
165 grid.orientation.assign(npts, tmat);
166 }
167
168 // Get flags for each coordinate of force and put in vs::Vector
169 const vs::Vector force_coord_flags_vec = {
170 (amrex::Real)wdata.force_coord_flags[0],
171 (amrex::Real)wdata.force_coord_flags[1],
172 (amrex::Real)wdata.force_coord_flags[2]};
173
174 // Calculate the local force using sampled velocity (at n)
175 amrex::Real total_lift = 0.0_rt;
176 amrex::Real total_drag = 0.0_rt;
177 for (int ip = 0; ip < npts; ++ip) {
178
179 // Wind vector is relative to actuator motion
180 vs::Vector windvector;
181 windvector[0] = (grid.vel[ip] - wdata.vel_tr) & blade_x;
182 windvector[1] = 0;
183 windvector[2] = (grid.vel[ip] - wdata.vel_tr) & blade_z;
184
185 const auto vmag = vs::mag(windvector);
186 const auto aoa = std::atan2(windvector[2], windvector[0]) +
187 amr_wind::utils::radians(wdata.pitch);
188
189 // Get Cl, Cd values
190 amrex::Real cl, cd;
191 aflookup(aoa, cl, cd);
192
193 // Calculate factor for qval: 0.5_rt * Uinf * Uinf * dx
194 // but replace velocity magnitude if specified
195 auto qfac =
196 (wdata.prescribed_uinf < 0.0_rt)
197 ? 0.5_rt * vmag * vmag
198 : 0.5_rt * wdata.prescribed_uinf * wdata.prescribed_uinf;
199 // Length scale in spanwise direction
200 if (wdata.gauss_2D && wdata.normalize_2D_spanwise) {
201 // Do not multiply by a length scale, but divide by number of
202 // points because the Gaussians of each point all overlap
203 qfac /= (amrex::Real)npts;
204 // Convert 3D Gaussian factor to 2D factor
205 constexpr amrex::Real G2D_from_3D =
206 0.31830988618379067_rt / 0.17958712212516656_rt;
207 qfac *= G2D_from_3D;
208 // Get rid of epsilon in spanwise direction
209 const amrex::Real eps_span = grid.epsilon[ip][1];
210 qfac *= eps_span;
211 } else {
212 // 3D implementation: multiply by spanwise dx
213 qfac *= dx[ip];
214 }
215
216 const auto qval = qfac * chord[ip];
217 const auto lift = qval * cl;
218 const auto drag = qval * cd;
219
220 // Determine unit vector parallel and perpendicular to velocity
221 const auto drag_dir =
222 (blade_x * windvector.x() + blade_z * windvector.z()).unit();
223 const auto lift_dir = (drag_dir ^ blade_y).unit();
224
225 // Compute force on fluid from this section of wing
226 grid.force[ip] = -(lift_dir * lift + drag * drag_dir);
227
228 // In global coords, zero disabled force components
229 grid.force[ip] *= force_coord_flags_vec;
230
231 // Assign values for output
232 wdata.vel_rel[ip] = windvector;
233 wdata.aoa[ip] = amr_wind::utils::degrees(aoa);
234 wdata.cl[ip] = cl;
235 wdata.cd[ip] = cd;
236
237 total_lift += lift;
238 total_drag += drag;
239 }
240
241 wdata.lift = total_lift;
242 wdata.drag = total_drag;
243
244 if (wdata.fllc) {
245 if (!(wdata.fllc->initialized) &&
246 (time.current_time() > wdata.fllc->fllc_start_time)) {
247 wdata.component_view =
249 data);
250 fllc_init(
251 *(wdata.fllc.get()), wdata.component_view,
252 wdata.epsilon_chord[0]);
253 }
254 }
255 }
256};
257
258template <typename ActTrait, typename SrcTrait>
260 ActTrait,
261 SrcTrait,
262 typename std::enable_if_t<
263 std::is_base_of_v<WingType, ActTrait> &&
264 UseDefaultOp<ActTrait, ActSrcLine>::process_outputs>>
265{
266private:
267 typename ActTrait::DataType& m_data;
268
269 std::string m_out_dir;
270 std::string m_nc_filename;
271 int m_out_freq{10};
272
273public:
274 explicit ProcessOutputsOp(typename ActTrait::DataType& data) : m_data(data)
275 {}
276
278 {
279 pp.query("output_frequency", m_out_freq);
280 }
281
282 void prepare_outputs(const std::string& out_dir)
283 {
284 m_nc_filename = out_dir + "/" + m_data.info().label + ".nc";
286 m_nc_filename, m_data.meta(), m_data.info(), m_data.grid());
287 }
288
290 {
291 const auto& time = m_data.sim().time();
292 const int tidx = time.time_index();
293 if (tidx % m_out_freq != 0) {
294 return;
295 }
296
298 m_nc_filename, m_data.meta(), m_data.info(), m_data.grid(),
299 time.new_time());
300 }
301};
302
303} // namespace ops
304} // namespace amr_wind::actuator
305
306#endif /* WING_OPS_H */
void query(const std::string &name, vs::Vector &value) const
Definition MultiParser.H:56
const AirfoilTraits< T >::AirfoilLookup & airfoil_lookup(typename T::DataType &data)
::amr_wind::utils::MultiParser ActParser
Definition ActParser.H:8
Definition wing_ops.cpp:10
void new_wing_position_velocity(VecList &points, vs::Vector &vtr, const int npts, const amrex::Real tn, const amrex::Real tnp1, const std::string &motion, const amrex::Real period, const vs::Vector svec)
Definition wing_ops.cpp:163
void refresh_wing_position(VecList &vpoints, VecList fpoints, const int npts)
Definition wing_ops.cpp:153
ComponentView make_component_view(typename T::DataType &data)
Definition wing_ops.H:48
void init_data_structures(WingBaseData &wdata, ActGrid &grid)
Definition wing_ops.cpp:12
void prepare_netcdf_file(const std::string &ncfile, const WingBaseData &meta, const ActInfo &info, const ActGrid &grid)
Definition wing_ops.cpp:51
void write_netcdf(const std::string &ncfile, const WingBaseData &meta, const ActInfo &info, const ActGrid &grid, const amrex::Real time)
Definition wing_ops.cpp:113
Definition ActParser.H:6
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
amrex::Vector< amr_wind::vs::Vector > VecList
Definition actuator_types.H:65
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE std::iterator_traits< C2 >::value_type linear_angle(const C1 xbegin, const C1 xend, const C2 yinp, const typename std::iterator_traits< C1 >::value_type &xout, const typename std::iterator_traits< C1 >::value_type &upper_bound)
Definition linear_interpolation.H:218
Slice< T > slice(std::vector< T > &vec, const size_t start, const size_t count)
Definition Slice.H:66
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real degrees(const amrex::Real rad_val)
Convert from radians to degrees.
Definition trig_ops.H:44
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real radians(const amrex::Real deg_val)
Convert from degrees to radians.
Definition trig_ops.H:37
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Tensor quaternion(const Vector &axis, const amrex::Real angle)
Definition tensorI.H:218
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T mag(const TensorT< T > &t)
Definition tensorI.H:182
VectorT< amrex::Real > Vector
Definition vector.H:148
Definition actuator_types.H:41
AirfoilTable AirfoilLookup
Definition AirfoilTable.H:83
Definition actuator_types.H:129
VecSlice vel
Definition actuator_types.H:136
VecSlice epsilon
Definition actuator_types.H:132
VecSlice vel_rel
Definition actuator_types.H:137
VecSlice force
Definition actuator_types.H:131
TensorSlice orientation
Definition actuator_types.H:133
RealSlice chord
Definition actuator_types.H:139
VecSlice pos
Definition actuator_types.H:130
VecSlice vel_pos
Definition actuator_types.H:135
This struct will operate on a blade/wing. The velocity from the simulation is corrected using the Fil...
Definition FLLCOp.H:20
Definition actuator_ops.H:61
Definition actuator_ops.H:43
Definition actuator_ops.H:54
static constexpr bool update_vel
Definition wing_ops.H:78
static constexpr bool compute_force
Definition wing_ops.H:79
static constexpr bool process_outputs
Definition wing_ops.H:80
static constexpr bool update_pos
Definition wing_ops.H:77
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T & z() &noexcept
Definition vector.H:99
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE T & x() &noexcept
Definition vector.H:97
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE VectorT< T > unit() const
Return the unit vector parallel to this vector.
Definition vector.H:92