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