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

AMR-Wind API: /home/runner/work/amr-wind/amr-wind/amr-wind/wind_energy/actuator/wing/fixed_wing_ops.H Source File
AMR-Wind API v0.1.0
CFD solver for wind plant simulations
Loading...
Searching...
No Matches
fixed_wing_ops.H
Go to the documentation of this file.
1#ifndef FIXED_WING_OPS_H
2#define FIXED_WING_OPS_H
3
8
10
11template <>
13{
15 {
16 auto& wdata = data.meta();
17 auto& info = data.info();
18 pp.get("num_points", wdata.num_pts);
19 pp.get("start", wdata.start);
20 pp.get("end", wdata.end);
21 pp.query_either("epsilon", wdata.eps_inp);
22 pp.query_either("epsilon_chord", wdata.epsilon_chord);
23 if (!pp.contains("pitch_timetable")) {
24 // Constant pitch is required without timetable
25 pp.get("pitch", wdata.pitch);
26 }
27 pp.get("airfoil_table", wdata.airfoil_file);
28 pp.query("airfoil_type", wdata.airfoil_type);
29 pp.queryarr("span_locs", wdata.span_locs);
30 pp.queryarr("chord", wdata.chord_inp);
31 bool use_fllc = false;
32 pp.query("fllc", use_fllc);
33
34 // If spanwise components of Gaussian should be ignored
35 pp.query("disable_spanwise_gaussian", wdata.gauss_2D);
36 // If spanwise components of Gaussian and forces should be normalized
37 // (on by default, not used unless gauss_2D = true)
38 pp.query("normalize_spanwise", wdata.normalize_2D_spanwise);
39 // If certain components of force should be ignored
40 // (check that correct number of components are specified)
41 amrex::Vector<int> force_coord_flags_query_inp;
42 pp.queryarr("active_force_dirs", force_coord_flags_query_inp);
43 if (!force_coord_flags_query_inp.empty()) {
44 AMREX_ALWAYS_ASSERT(
45 force_coord_flags_query_inp.size() == AMREX_SPACEDIM);
46 wdata.force_coord_flags = force_coord_flags_query_inp;
47 }
48
49 // If velocity magnitude for force calculation should be prescribed by
50 // user, not measured from the flow
51 pp.query("prescribed_uinf", wdata.prescribed_uinf);
52
53 // Initialize tables for pitch actuation (in degrees)
54 pp.query("pitch_timetable", wdata.pitch_timetable_file);
55 if (!wdata.pitch_timetable_file.empty()) {
56 std::ifstream ifh(wdata.pitch_timetable_file, std::ios::in);
57 if (!ifh.good()) {
58 amrex::Abort(
59 "Cannot find input file: " + wdata.pitch_timetable_file);
60 }
61 amrex::Real data_time;
62 amrex::Real data_pitch_deg;
63 ifh.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
64 while (ifh >> data_time) {
65 ifh >> data_pitch_deg;
66 wdata.time_table.push_back(data_time);
67 wdata.pitch_table.push_back(data_pitch_deg);
68 }
69 }
70
71 pp.query("motion_type", wdata.motion_type);
72 {
73 // do nothing for default, "none"
74 if (amrex::toLower(wdata.motion_type) == "linear") {
75 // get velocity
76 pp.get("velocity", wdata.vel_tr);
77 } else if (amrex::toLower(wdata.motion_type) == "sine") {
78 // get parameters
79 pp.get("sine_period", wdata.s_period);
80 pp.get("sine_vector", wdata.s_vector);
81 } else if (amrex::toLower(wdata.motion_type) != "none") {
82 amrex::Abort(
83 "Invalid FixedWingLine motion type. Valid options are "
84 "none, linear, and sine.");
85 }
86 }
87 if (use_fllc) {
88 wdata.fllc = std::make_unique<FLLCData>();
89 fllc_parse(pp, *(wdata.fllc));
90 }
91
92 if (!pp.contains("epsilon") && !pp.contains("epsilon_chord")) {
93 amrex::Abort(
94 "Actuator fixed wing requires specification of one or both "
95 "of 'epsilon' or 'epsilon_chord'");
96 }
97
98 AMREX_ALWAYS_ASSERT(wdata.span_locs.size() == wdata.chord_inp.size());
99
100 amrex::Real max_chord =
101 *std::max_element(wdata.chord_inp.begin(), wdata.chord_inp.end());
102 amrex::Real max_eps =
103 *std::max_element(wdata.eps_inp.begin(), wdata.eps_inp.end());
104 amrex::Real max_epsc = *std::max_element(
105 wdata.epsilon_chord.begin(), wdata.epsilon_chord.end());
106 amrex::Real search_radius =
107 amrex::max(max_eps, max_epsc) * max_chord * 3.0;
108 const auto& p1 = wdata.start;
109 const auto& p2 = wdata.end;
110 // Bounding box quantities used for all motion types
111 amrex::Real minpx = amrex::min(p1.x(), p2.x());
112 amrex::Real maxpx = amrex::max(p1.x(), p2.x());
113 amrex::Real minpy = amrex::min(p1.y(), p2.y());
114 amrex::Real maxpy = amrex::max(p1.y(), p2.y());
115 amrex::Real minpz = amrex::min(p1.z(), p2.z());
116 amrex::Real maxpz = amrex::max(p1.z(), p2.z());
117 // Bounding box limits for 2D actuator
118 if (wdata.gauss_2D) {
119 // Assume largest component of span needs entire domain, but the
120 // others do not need the bounding box to grow
121 const auto wspan = wdata.end - wdata.start;
122 // Flag for checking periodicity in spanwise direction
123 bool warn_per{false};
124 std::string sdir;
125 auto per = data.sim().mesh().Geom()[0].periodicity();
126 if (std::abs(wspan.x()) >=
127 std::max(std::abs(wspan.y()), std::abs(wspan.z()))) {
128 minpx = data.sim().mesh().Geom(0).ProbLoArray()[0];
129 maxpx = data.sim().mesh().Geom(0).ProbHiArray()[0];
130 warn_per = !per.isPeriodic(0);
131 sdir = "x";
132 } else if (std::abs(wspan.y()) >= std::abs(wspan.z())) {
133 minpy = data.sim().mesh().Geom(0).ProbLoArray()[1];
134 maxpy = data.sim().mesh().Geom(0).ProbHiArray()[1];
135 warn_per = !per.isPeriodic(1);
136 sdir = "y";
137 } else {
138 minpz = data.sim().mesh().Geom(0).ProbLoArray()[2];
139 maxpz = data.sim().mesh().Geom(0).ProbHiArray()[2];
140 warn_per = !per.isPeriodic(2);
141 sdir = "z";
142 }
143 if (warn_per) {
144 amrex::Print()
145 << "\nWARNING: fixed_wing_ops: Detected spanwise direction "
146 << sdir
147 << " is not periodic, though 2D Gaussian is being "
148 "used.\n\n";
149 }
150 }
151 // Set up bounding box depending on motion type
152 if (amrex::toLower(wdata.motion_type) == "none") {
153 info.bound_box = amrex::RealBox(
154 minpx - search_radius, minpy - search_radius,
155 minpz - search_radius, maxpx + search_radius,
156 maxpy + search_radius, maxpz + search_radius);
157 } else if (amrex::toLower(wdata.motion_type) == "linear") {
158 // Extend bounding box in case of velocity
159 constexpr amrex::Real tiny = 1e-8;
160 // If velocity is present, assume wing can travel entire domain
161 const bool up_ = wdata.vel_tr.x() > tiny;
162 const amrex::Real up_ext =
163 data.sim().mesh().Geom(0).ProbHiArray()[0];
164 const bool um_ = wdata.vel_tr.x() < -tiny;
165 const amrex::Real um_ext =
166 data.sim().mesh().Geom(0).ProbLoArray()[0];
167 const bool vp_ = wdata.vel_tr.y() > tiny;
168 const amrex::Real vp_ext =
169 data.sim().mesh().Geom(0).ProbHiArray()[1];
170 const bool vm_ = wdata.vel_tr.y() < -tiny;
171 const amrex::Real vm_ext =
172 data.sim().mesh().Geom(0).ProbLoArray()[1];
173 const bool wp_ = wdata.vel_tr.z() > tiny;
174 const amrex::Real wp_ext =
175 data.sim().mesh().Geom(0).ProbHiArray()[2];
176 const bool wm_ = wdata.vel_tr.z() < -tiny;
177 const amrex::Real wm_ext =
178 data.sim().mesh().Geom(0).ProbLoArray()[2];
179 info.bound_box = amrex::RealBox(
180 um_ ? um_ext : minpx - search_radius,
181 vm_ ? vm_ext : minpy - search_radius,
182 wm_ ? wm_ext : minpz - search_radius,
183 up_ ? up_ext : maxpx + search_radius,
184 vp_ ? vp_ext : maxpy + search_radius,
185 wp_ ? wp_ext : maxpz + search_radius);
186 } else if (amrex::toLower(wdata.motion_type) == "sine") {
187 info.bound_box = amrex::RealBox(
188 minpx - wdata.s_vector.x() - search_radius,
189 minpy - wdata.s_vector.y() - search_radius,
190 minpz - wdata.s_vector.z() - search_radius,
191 maxpx + wdata.s_vector.x() + search_radius,
192 maxpy + wdata.s_vector.y() + search_radius,
193 maxpz + wdata.s_vector.z() + search_radius);
194 }
195 }
196};
197
198template <>
200{
202 {
203 wing::init_data_structures(data.meta(), data.grid());
204
205 auto& meta = data.meta();
206 {
207 const int npts = data.meta().num_pts;
208 auto& grid = data.grid();
209 // Process chord information
210 const auto wlen = vs::mag(grid.pos.back() - grid.pos.front());
211 RealList wx(npts);
212 for (int i = 0; i < npts; ++i) {
213 wx[i] = vs::mag(grid.pos[i] - grid.pos[0]) / wlen;
214 }
215 meta.chord.resize(npts);
217 meta.span_locs, meta.chord_inp, wx, meta.chord);
218 meta.epsilon_chord = {
219 meta.epsilon_chord.x(), meta.epsilon_chord.z(),
220 meta.epsilon_chord.y()};
221 meta.eps_inp = {
222 meta.eps_inp.x(), meta.eps_inp.z(), meta.eps_inp.y()};
223 for (int i = 0; i < npts; ++i) {
224 for (int n = 0; n < AMREX_SPACEDIM; ++n) {
225 const auto eps = meta.epsilon_chord[n] * meta.chord[i];
226 grid.epsilon[i][n] = amrex::max(meta.eps_inp[n], eps);
227 }
228 }
229 // Copy Gaussian flags to grid struct if 2D
230 if (meta.gauss_2D) {
231 // Local coords are chord, span, thickness internally
232 grid.dcoord_flags = vs::Vector(1.0, 0.0, 1.0);
233 }
234 }
235
236 meta.aflookup =
237 AirfoilLoader::load_airfoil(meta.airfoil_file, meta.airfoil_type);
238 }
239};
240
241template <>
243{
244 return *data.meta().aflookup;
245}
246
247} // namespace amr_wind::actuator::ops
248
249#endif /* FIXED_WING_OPS_H */
amrex::AmrCore & mesh()
Return the AMR mesh hierarchy.
Definition CFDSim.H:54
Definition actuator_types.H:184
CFDSim & sim()
Definition actuator_types.H:211
ActTrait::GridType & grid()
Definition actuator_types.H:217
ActTrait::InfoType & info()
Definition actuator_types.H:214
ActTrait::MetaType & meta()
Definition actuator_types.H:220
static std::unique_ptr< AirfoilTable > load_airfoil(const std::string &af_file, const std::string &type)
Definition AirfoilTable.cpp:74
Definition AirfoilTable.H:13
Definition MultiParser.H:18
void query_either(const std::string &name, vs::Vector &value) const
Definition MultiParser.H:95
void get(const std::string &name, vs::Vector &value) const
Definition MultiParser.H:42
void queryarr(const std::string &name, T &value) const
Definition MultiParser.H:147
bool contains(const std::string &name) const
Check if the keyword is present in either namespace.
Definition MultiParser.H:31
void query(const std::string &name, vs::Vector &value) const
Definition MultiParser.H:57
Definition ActSrcLineOp.H:9
const AirfoilTable & airfoil_lookup< FixedWing >(FixedWing::DataType &data)
Definition fixed_wing_ops.H:242
void init_data_structures(WingBaseData &wdata, ActGrid &grid)
Definition wing_ops.cpp:10
void fllc_parse(const utils::ActParser &pp, FLLCData &data)
Function to capture common parsing requirements for the filtered lifting line correction.
Definition FLLC.cpp:108
amrex::Vector< amrex::Real > RealList
Definition actuator_types.H:60
void linear_monotonic(const C1 &xinp, const C2 &yinp, const C1 &xout, C2 &yout, const int ncomp=1, const int comp=0)
Definition linear_interpolation.H:152
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:38
Definition FixedWing.H:20
void operator()(FixedWing::DataType &data)
Definition fixed_wing_ops.H:201
Definition actuator_ops.H:32
void operator()(FixedWing::DataType &data, const utils::ActParser &pp)
Definition fixed_wing_ops.H:14
Definition actuator_ops.H:19