24 auto& grid = data.grid();
25 auto& tdata = data.meta();
26 const int num_blades = tdata.num_blades;
27 const int num_pts_blade = tdata.num_pts_blade;
28 const int num_vel_pts_blade = tdata.num_vel_pts_blade;
30 for (
int ib = 0;
ib < num_blades; ++
ib) {
35 const auto start =
ib * num_pts_blade + 1;
36 const auto start_vel =
ib * num_vel_pts_blade;
39 grid.pos, start, num_pts_blade);
41 grid.force, start, num_pts_blade);
43 grid.epsilon, start, num_pts_blade);
45 grid.orientation, start, num_pts_blade);
47 tdata.chord, start, num_pts_blade);
49 tdata.vel_rel, start, num_pts_blade);
51 grid.vel, start_vel, num_vel_pts_blade);
53 grid.vel_pos, start_vel, num_vel_pts_blade);
56 tdata.blades.emplace_back(cv);
58 if (tdata.num_pts_tower > 0) {
59 const int num_pts_tower = tdata.num_pts_tower;
60 const int ntwr_start = num_blades * num_pts_blade + 1;
61 auto& cv = tdata.tower;
69 grid.orientation, ntwr_start, num_pts_tower);
86 auto& tdata = data.meta();
100 const auto& cd = tdata.nacelle_cd;
101 const auto& area = tdata.nacelle_area;
104 auto& nac_eps = data.grid().epsilon[0];
105 nac_eps.x() = amrex::max(eps, tdata.eps_min.x());
106 nac_eps.y() = amrex::max(eps, tdata.eps_min.y());
107 nac_eps.z() = amrex::max(eps, tdata.eps_min.z());
110 for (
int ib = 0;
ib < tdata.num_blades; ++
ib) {
111 auto& cv = tdata.blades[
ib];
113 for (
int i = 0; i < tdata.num_pts_blade; ++i) {
114 const auto eps_crd = tdata.eps_chord * cv.chord[i];
116 for (
int n = 0; n < AMREX_SPACEDIM; ++n) {
118 amrex::max(tdata.eps_min[n], tdata.eps_inp[n], eps_crd[n]);
123 auto& cv = tdata.tower;
124 for (
int i = 0; i < tdata.num_pts_tower; ++i) {
125 for (
int n = 0; n < AMREX_SPACEDIM; ++n) {
126 cv.epsilon[i][n] = amrex::max(
127 tdata.eps_min[n], tdata.eps_inp[n], tdata.eps_tower[n]);
136 if (!data.info().is_root_proc) {
140 const auto& cd = data.meta().nacelle_cd;
141 const auto& area = data.meta().nacelle_area;
142 const auto& cd_area = cd * area;
143 const auto& ext_tdata = data.meta().ext_data;
144 const auto& rho = data.meta().density;
146 const auto& eps = data.grid().epsilon[0].x();
149 ext_tdata.fluid_velocity(0)[0], ext_tdata.fluid_velocity(1)[0],
150 ext_tdata.fluid_velocity(2)[0]};
151 amrex::Real correction = 0.0;
155 correction = 1.0 / fac;
158 0.5 * rho * cd_area *
vs::mag(vel) * correction * correction;
160 for (
int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
161 ext_tdata.force(dir)[0] =
static_cast<float>(coeff * vel[dir]);
191 if (!data.info().actuator_in_proc) {
199 const auto dsize = data.grid().pos.size() * 15;
200 amrex::Vector<float> buf(dsize);
204 if (data.info().is_root_proc) {
205 BL_PROFILE(
"amr-wind::actuator::external::compute_force_op::scatter1");
206 const auto& ext_tdata = data.meta().ext_data;
207 auto it = buf.begin();
208 for (
int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
210 ext_tdata.force(dir),
211 ext_tdata.force(dir) + ext_tdata.length_force(dir), it);
212 std::advance(it, ext_tdata.length_force(dir));
214 for (
int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
216 ext_tdata.position_at_force(dir),
217 ext_tdata.position_at_force(dir) +
218 ext_tdata.length_position_at_force(dir),
220 std::advance(it, ext_tdata.length_position_at_force(dir));
224 std::copy(ext_tdata.orientation(),
225 ext_tdata.orientation() + ext_tdata.length_orientation(), it);
230 const auto& procs = data.info().procs;
231 const int tag = 1001;
232 if (data.info().is_root_proc) {
233 BL_PROFILE(
"amr-wind::actuator::external::compute_force_op::scatter2");
234 for (
const int ip : procs) {
235 if (ip == data.info().root_proc) {
239 amrex::ParallelDescriptor::Send(
240 buf.data(), dsize, ip, tag, data.meta().tcomm);
243 BL_PROFILE(
"amr-wind::actuator::external::compute_force_op::scatter2");
244 amrex::ParallelDescriptor::Recv(
245 buf.data(), dsize, data.info().root_proc, tag, data.meta().tcomm);
251 BL_PROFILE(
"amr-wind::actuator::external::compute_force_op::scatter3");
252 const auto& bp = data.info().base_pos;
253 auto& grid = data.grid();
254 const auto& npts = grid.pos.size();
255 const auto& rho = data.meta().density;
256 const size_t ifx = 0;
257 const size_t ify = ifx + npts;
258 const size_t ifz = ify + npts;
259 const size_t ipx = ifz + npts;
260 const size_t ipy = ipx + npts;
261 const size_t ipz = ipy + npts;
262 const size_t iori = ipz + npts;
264 for (
int i = 0; i < npts; ++i) {
269 grid.force[i].x() = -
static_cast<amrex::Real
>(buf[ifx + i]) / rho;
270 grid.force[i].y() = -
static_cast<amrex::Real
>(buf[ify + i]) / rho;
271 grid.force[i].z() = -
static_cast<amrex::Real
>(buf[ifz + i]) / rho;
275 grid.pos[i].x() =
static_cast<amrex::Real
>(buf[ipx + i]) + bp.x();
276 grid.pos[i].y() =
static_cast<amrex::Real
>(buf[ipy + i]) + bp.y();
277 grid.pos[i].z() =
static_cast<amrex::Real
>(buf[ipz + i]) + bp.z();
286 static_cast<int>(iori) + i * AMREX_SPACEDIM * AMREX_SPACEDIM;
287 for (
int j = 0; j < AMREX_SPACEDIM; ++j) {
288 for (
int k = 0; k < AMREX_SPACEDIM; ++k) {
289 grid.orientation[i][j * AMREX_SPACEDIM + k] =
290 static_cast<amrex::Real
>(
291 buf[off + j + k * AMREX_SPACEDIM]);
297 auto& meta = data.meta();
298 meta.rot_center = grid.pos[0];
301 const auto xvec = grid.orientation[0].x().unit();
303 const auto zvec = xvec ^ yvec;
304 meta.rotor_frame.rows(xvec, yvec.unit(), zvec.unit());