ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
WindFarm Class Reference

Manage a collection of wind turbine models. More...

#include <ERF_WindFarm.H>

Inheritance diagram for WindFarm:
Collaboration diagram for WindFarm:

Public Member Functions

 WindFarm ()
 
virtual ~WindFarm ()=default
 
 WindFarm (int nlev, const WindFarmType &a_windfarm_type)
 
void read_tables (std::string windfarm_loc_table, std::string windfarm_spec_table, bool x_y, bool lat_lon, const amrex::Real windfarm_x_shift=zero, const amrex::Real windfarm_y_shift=zero)
 Read turbine location and specification tables. More...
 
void init_windfarm_lat_lon (const std::string windfarm_loc_table, const amrex::Real windfarm_x_shift, const amrex::Real windfarm_y_shift)
 Initialize wind farm using latitude and longitude coordinates. More...
 
void init_windfarm_x_y (const std::string windfarm_loc_table)
 Initialize wind farm using Cartesian coordinates. More...
 
void read_windfarm_locations_table (const std::string windfarm_loc_table, bool x_y, bool lat_lon, const amrex::Real windfarm_x_shift=zero, const amrex::Real windfarm_y_shift=zero)
 Read the turbine location table. More...
 
void read_windfarm_spec_table (const std::string windfarm_spec_table)
 Read the turbine specification table. More...
 
void read_windfarm_blade_table (const std::string windfarm_blade_table)
 Read the turbine blade table. More...
 
void read_windfarm_airfoil_tables (const std::string windfarm_airfoil_tables, const std::string windfarm_blade_table)
 Read the airfoil tables. More...
 
void read_windfarm_spec_table_extra (const std::string windfarm_spec_table_extra)
 Read extra turbine specifications. More...
 
void fill_Nturb_multifab (const amrex::Geometry &geom, amrex::MultiFab &mf_Nturb, std::unique_ptr< amrex::MultiFab > &z_phys_nd)
 Fill the turbine count MultiFab. More...
 
void fill_SMark_multifab (const amrex::Geometry &geom, amrex::MultiFab &mf_SMark, const amrex::Real &sampling_distance_by_D, const amrex::Real &turb_disk_angle, std::unique_ptr< amrex::MultiFab > &z_phys_cc)
 Fill the SMark MultiFab. More...
 
void fill_SMark_multifab_mesoscale_models (const amrex::Geometry &geom, amrex::MultiFab &mf_SMark, const amrex::MultiFab &mf_Nturb, std::unique_ptr< amrex::MultiFab > &z_phys_cc)
 Fill the SMark MultiFab for mesoscale models. More...
 
void write_turbine_locations_vtk ()
 Write turbine locations to a VTK file. More...
 
void write_actuator_disks_vtk (const amrex::Geometry &geom, const amrex::Real &sampling_distance_by_D)
 Write actuator disks to a VTK file. More...
 
void advance (const amrex::Geometry &a_geom, const double &dt_advance, amrex::MultiFab &cons_in, amrex::MultiFab &mf_vars_windfarm, amrex::MultiFab &U_old, amrex::MultiFab &V_old, amrex::MultiFab &W_old, const amrex::MultiFab &mf_Nturb, const amrex::MultiFab &mf_SMark, const double &time) override
 Advance the wind farm model in time. More...
 
void set_turb_spec (const amrex::Real &a_rotor_rad, const amrex::Real &a_hub_height, const amrex::Real &a_thrust_coeff_standing, const amrex::Vector< amrex::Real > &a_wind_speed, const amrex::Vector< amrex::Real > &a_thrust_coeff, const amrex::Vector< amrex::Real > &a_power) override
 Set general turbine specifications. More...
 
void set_turb_loc (const amrex::Vector< amrex::Real > &a_xloc, const amrex::Vector< amrex::Real > &a_yloc) override
 Set turbine locations. More...
 
void set_turb_disk_angle (const amrex::Real &a_turb_disk_angle) override
 Set the turbine disk angle. More...
 
void set_blade_spec (const amrex::Vector< amrex::Real > &a_bld_rad_loc, const amrex::Vector< amrex::Real > &a_bld_twist, const amrex::Vector< amrex::Real > &a_bld_chord) override
 Set blade specifications. More...
 
void set_blade_airfoil_spec (const amrex::Vector< amrex::Vector< amrex::Real >> &a_bld_airfoil_aoa, const amrex::Vector< amrex::Vector< amrex::Real >> &a_bld_airfoil_Cl, const amrex::Vector< amrex::Vector< amrex::Real >> &a_bld_airfoil_Cd) override
 Set blade airfoil specifications. More...
 
void set_turb_spec_extra (const amrex::Vector< amrex::Real > &a_velocity, const amrex::Vector< amrex::Real > &a_C_P, const amrex::Vector< amrex::Real > &a_C_T, const amrex::Vector< amrex::Real > &a_rotor_RPM, const amrex::Vector< amrex::Real > &a_blade_pitch) override
 Set extra turbine specifications. More...
 
- Public Member Functions inherited from NullWindFarm
 NullWindFarm ()
 
virtual ~NullWindFarm ()=default
 
void get_turb_spec (amrex::Real &rotor_rad, amrex::Real &hub_height, amrex::Real &thrust_coeff_standing, amrex::Vector< amrex::Real > &wind_speed, amrex::Vector< amrex::Real > &thrust_coeff, amrex::Vector< amrex::Real > &power)
 
void get_turb_loc (amrex::Vector< amrex::Real > &xloc, amrex::Vector< amrex::Real > &yloc)
 
void get_turb_disk_angle (amrex::Real &turb_disk_angle)
 
void get_blade_spec (amrex::Vector< amrex::Real > &bld_rad_loc, amrex::Vector< amrex::Real > &bld_twist, amrex::Vector< amrex::Real > &bld_chord)
 
void get_blade_airfoil_spec (amrex::Vector< amrex::Vector< amrex::Real >> &bld_airfoil_aoa, amrex::Vector< amrex::Vector< amrex::Real >> &bld_airfoil_Cl, amrex::Vector< amrex::Vector< amrex::Real >> &bld_airfoil_Cd)
 
void get_turb_spec_extra (amrex::Vector< amrex::Real > &velocity, amrex::Vector< amrex::Real > &C_P, amrex::Vector< amrex::Real > &C_T, amrex::Vector< amrex::Real > &rotor_RPM, amrex::Vector< amrex::Real > &blade_pitch)
 

Protected Member Functions

template<class NewWindFarmModel >
void SetModel ()
 Create and set the specified windfarm model. More...
 

Protected Attributes

amrex::Vector< amrex::Realxloc
 
amrex::Vector< amrex::Realyloc
 
amrex::Vector< amrex::Realzloc
 
amrex::Real my_turb_disk_angle
 
amrex::Real hub_height
 
amrex::Real rotor_rad
 
amrex::Real thrust_coeff_standing
 
amrex::Real nominal_power
 
amrex::Vector< amrex::Realwind_speed
 
amrex::Vector< amrex::Realthrust_coeff
 
amrex::Vector< amrex::Realpower
 
amrex::Vector< amrex::Realbld_rad_loc
 
amrex::Vector< amrex::Realbld_twist
 
amrex::Vector< amrex::Realbld_chord
 
amrex::Vector< amrex::Vector< amrex::Real > > bld_airfoil_aoa
 
amrex::Vector< amrex::Vector< amrex::Real > > bld_airfoil_Cl
 
amrex::Vector< amrex::Vector< amrex::Real > > bld_airfoil_Cd
 
int n_bld_sections
 
amrex::Vector< amrex::Realvelocity
 
amrex::Vector< amrex::RealC_P
 
amrex::Vector< amrex::RealC_T
 
amrex::Vector< amrex::Realrotor_RPM
 
amrex::Vector< amrex::Realblade_pitch
 
- Protected Attributes inherited from NullWindFarm
amrex::Vector< amrex::Realm_xloc
 
amrex::Vector< amrex::Realm_yloc
 
amrex::Real m_turb_disk_angle
 
amrex::Real m_hub_height
 
amrex::Real m_rotor_rad
 
amrex::Real m_thrust_coeff_standing
 
amrex::Real m_nominal_power
 
amrex::Vector< amrex::Realm_wind_speed
 
amrex::Vector< amrex::Realm_thrust_coeff
 
amrex::Vector< amrex::Realm_power
 
amrex::Vector< amrex::Realm_bld_rad_loc
 
amrex::Vector< amrex::Realm_bld_twist
 
amrex::Vector< amrex::Realm_bld_chord
 
amrex::Vector< amrex::Vector< amrex::Real > > m_bld_airfoil_aoa
 
amrex::Vector< amrex::Vector< amrex::Real > > m_bld_airfoil_Cl
 
amrex::Vector< amrex::Vector< amrex::Real > > m_bld_airfoil_Cd
 
amrex::Vector< amrex::Realm_velocity
 
amrex::Vector< amrex::Realm_C_P
 
amrex::Vector< amrex::Realm_C_T
 
amrex::Vector< amrex::Realm_rotor_RPM
 
amrex::Vector< amrex::Realm_blade_pitch
 

Private Attributes

amrex::Vector< std::unique_ptr< NullWindFarm > > m_windfarm_model
 

Additional Inherited Members

- Static Public Member Functions inherited from NullWindFarm
static AMREX_GPU_DEVICE bool find_if_marked (amrex::Real x1, amrex::Real x2, amrex::Real y1, amrex::Real y2, amrex::Real x0, amrex::Real y0, amrex::Real nx, amrex::Real ny, amrex::Real d_hub_height, amrex::Real d_rotor_rad, amrex::Real z)
 

Detailed Description

Manage a collection of wind turbine models.

Constructor & Destructor Documentation

◆ WindFarm() [1/2]

WindFarm::WindFarm ( )
inline
21 {}

◆ ~WindFarm()

virtual WindFarm::~WindFarm ( )
virtualdefault

◆ WindFarm() [2/2]

WindFarm::WindFarm ( int  nlev,
const WindFarmType &  a_windfarm_type 
)
inline
27  {
28  m_windfarm_model.resize(nlev);
29  if (a_windfarm_type == WindFarmType::Fitch) {
30  SetModel<Fitch>();
31  amrex::Print() << "Fitch windfarm model!\n";
32  }
33  else if (a_windfarm_type == WindFarmType::EWP) {
34  SetModel<EWP>();
35  amrex::Print() << "EWP windfarm model!\n";
36  }
37  else if (a_windfarm_type == WindFarmType::SimpleAD) {
38  SetModel<SimpleAD>();
39  amrex::Print() << "Simplified actuator disk windfarm model!\n";
40  }
41  else if (a_windfarm_type == WindFarmType::GeneralAD) {
42  SetModel<GeneralAD>();
43  amrex::Print() << "Generalized actuator disk windfarm model!\n";
44  }
45  else {
46  amrex::Abort("WindFarm: Dont know this windfarm_type!") ;
47  }
48  }
amrex::Vector< std::unique_ptr< NullWindFarm > > m_windfarm_model
Definition: ERF_WindFarm.H:299

Member Function Documentation

◆ advance()

void WindFarm::advance ( const amrex::Geometry &  a_geom,
const double &  dt_advance,
amrex::MultiFab &  cons_in,
amrex::MultiFab &  mf_vars_windfarm,
amrex::MultiFab &  U_old,
amrex::MultiFab &  V_old,
amrex::MultiFab &  W_old,
const amrex::MultiFab &  mf_Nturb,
const amrex::MultiFab &  mf_SMark,
const double &  time 
)
inlineoverridevirtual

Advance the wind farm model in time.

Parameters
[in]a_geomGeometry
[in]dt_advanceTimestep.
[in,out]cons_inConservative variables.
[in,out]mf_vars_windfarmWind farm variables MultiFab.
[in,out]U_oldOld x-velocity MultiFab.
[in,out]V_oldOld y-velocity MultiFab.
[in,out]W_oldOld z-velocity MultiFab.
[in]mf_NturbTurbine count MultiFab.
[in]mf_SMarkSMark MultiFab.
[in]timeCurrent simulation time.

Implements NullWindFarm.

192  {
193  m_windfarm_model[0]->advance(a_geom, dt_advance, cons_in, mf_vars_windfarm,
194  U_old, V_old, W_old, mf_Nturb, mf_SMark, time);
195  }

◆ fill_Nturb_multifab()

void WindFarm::fill_Nturb_multifab ( const amrex::Geometry &  geom,
amrex::MultiFab &  mf_Nturb,
std::unique_ptr< amrex::MultiFab > &  z_phys_nd 
)

Fill the turbine count MultiFab.

Parameters
[in]geomGeometry
[out]mf_NturbMultiFab to fill with turbine counts.
[in,out]z_phys_ndPhysical height MultiFab.

Fill a MultiFab with the number of turbines per cell and determine base heights.

Parameters
[in]geomGeometry defining the domain.
[in,out]mf_NturbMultiFab to be filled with turbine counts per cell.
[in]z_phys_ndNode-centered physical height FAB.
435 {
436 
437  zloc.resize(xloc.size(),zero);
438  Vector<int> is_counted;
439  is_counted.resize(xloc.size(),0);
440 
441  amrex::Gpu::DeviceVector<Real> d_xloc(xloc.size());
442  amrex::Gpu::DeviceVector<Real> d_yloc(yloc.size());
443  amrex::Gpu::DeviceVector<Real> d_zloc(xloc.size());
444  amrex::Gpu::DeviceVector<int> d_is_counted(xloc.size());
445  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, xloc.begin(), xloc.end(), d_xloc.begin());
446  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, yloc.begin(), yloc.end(), d_yloc.begin());
447  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, zloc.begin(), zloc.end(), d_zloc.begin());
448  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, is_counted.begin(), is_counted.end(), d_is_counted.begin());
449 
450  Real* d_xloc_ptr = d_xloc.data();
451  Real* d_yloc_ptr = d_yloc.data();
452  Real* d_zloc_ptr = d_zloc.data();
453  int* d_is_counted_ptr = d_is_counted.data();
454 
455  mf_Nturb.setVal(0);
456 
457  int i_lo = geom.Domain().smallEnd(0); int i_hi = geom.Domain().bigEnd(0);
458  int j_lo = geom.Domain().smallEnd(1); int j_hi = geom.Domain().bigEnd(1);
459  auto dx = geom.CellSizeArray();
460  if(dx[0]<= 1e-3 or dx[1]<=1e-3 or dx[2]<= 1e-3) {
461  Abort("The value of grid spacing for wind farm parametrization cannot be less than 1e-3 m. "
462  "It should be usually of order 1 m");
463  }
464  auto ProbLoArr = geom.ProbLoArray();
465  auto ProbHiArr = geom.ProbHiArray();
466  int num_turb = xloc.size();
467 
468  bool is_terrain = z_phys_nd ? true: false;
469 
470  // The ground is at the bottom of the domain, not at the bottom of each box --
471  // these differ for every box that doesn't touch the ground, which happens
472  // whenever the grids are decomposed in the vertical direction
473  const int k0 = geom.Domain().smallEnd(2);
474 
475  // Initialize wind farm
476  for ( MFIter mfi(mf_Nturb,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
477  const Box& bx = mfi.tilebox();
478  auto Nturb_array = mf_Nturb.array(mfi);
479  const Array4<const Real>& z_nd_arr = z_phys_nd->const_array(mfi);
480  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
481  int li = amrex::min(amrex::max(i, i_lo), i_hi);
482  int lj = amrex::min(amrex::max(j, j_lo), j_hi);
483 
484  Real x1 = ProbLoArr[0] + li*dx[0];
485  Real x2 = ProbLoArr[0] + (li+1)*dx[0];
486  Real y1 = ProbLoArr[1] + lj*dx[1];
487  Real y2 = ProbLoArr[1] + (lj+1)*dx[1];
488 
489  for(int it=0; it<num_turb; it++){
490  if( d_xloc_ptr[it]+1e-3 > x1 and d_xloc_ptr[it]+1e-3 < x2 and
491  d_yloc_ptr[it]+1e-3 > y1 and d_yloc_ptr[it]+1e-3 < y2){
492  Nturb_array(i,j,k,0) = Nturb_array(i,j,k,0) + 1;
493  //
494  // Only the cell at the bottom of the domain counts this turbine and
495  // stores its surface elevation. d_is_counted is a per-rank array
496  // which is summed over all ranks below, so if we counted at every k
497  // then a column spread over more than one rank (which happens when
498  // the grids are decomposed in z) would be counted more than once.
499  //
500  if (is_terrain and k == k0) {
501  int expected = 0;
502  int desired = 1;
503  // Atomic Compare-And-Swap: Increment only if d_is_counted_ptr[it] was 0
504  if (Gpu::Atomic::CAS(&d_is_counted_ptr[it], expected, desired) == expected) {
505  // The current thread successfully set d_is_counted_ptr[it] from 0 to 1
506  Gpu::Atomic::Add(&d_zloc_ptr[it], z_nd_arr(i, j, k0));
507  }
508  }
509  }
510  }
511  });
512  }
513 
514  mf_Nturb.FillBoundary(geom.periodicity());
515 
516  Gpu::copy(Gpu::deviceToHost, d_zloc.begin(), d_zloc.end(), zloc.begin());
517  Gpu::copy(Gpu::deviceToHost, d_is_counted.begin(), d_is_counted.end(), is_counted.begin());
518 
519  amrex::ParallelAllReduce::Sum(zloc.data(),
520  zloc.size(),
521  amrex::ParallelContext::CommunicatorAll());
522 
523  amrex::ParallelAllReduce::Sum(is_counted.data(),
524  is_counted.size(),
525  amrex::ParallelContext::CommunicatorAll());
526 
527  for(int it=0;it<num_turb;it++) {
528  if(is_terrain and
529  xloc[it] > ProbLoArr[0] and
530  xloc[it] < ProbHiArr[0] and
531  yloc[it] > ProbLoArr[1] and
532  yloc[it] < ProbHiArr[1] ) {
533  if(is_counted[it] != 1) {
534  Abort("Wind turbine " + std::to_string(it) + "has been counted " + std::to_string(is_counted[it]) + " times" +
535  " It should have been counted only once. Aborting....");
536  }
537  }
538  }
539 
540  // Debugging
541  /*int my_rank = amrex::ParallelDescriptor::MyProc();
542 
543  for(int it=0;it<num_turb;it++) {
544  std::cout << "The value of zloc is " << my_rank << " " << zloc[it] << " " << is_counted[it] << "\n";
545  }*/
546 }
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
amrex::Real Real
Definition: ERF_ShocInterface.H:19
amrex::Vector< amrex::Real > yloc
Definition: ERF_WindFarm.H:280
amrex::Vector< amrex::Real > zloc
Definition: ERF_WindFarm.H:280
amrex::Vector< amrex::Real > xloc
Definition: ERF_WindFarm.H:280
Here is the call graph for this function:

◆ fill_SMark_multifab()

void WindFarm::fill_SMark_multifab ( const amrex::Geometry &  geom,
amrex::MultiFab &  mf_SMark,
const amrex::Real sampling_distance_by_D,
const amrex::Real turb_disk_angle,
std::unique_ptr< amrex::MultiFab > &  z_phys_cc 
)

Fill the SMark MultiFab.

Parameters
[in]geomGeometry
[out]mf_SMarkMultiFab to fill with SMark values.
[in]sampling_distance_by_DSampling distance normalized by rotor diameter.
[in]turb_disk_angleTurbine disk angle.
[in,out]z_phys_ccPhysical height MultiFab.

Fill the SMark MultiFab identifying turbine disks and sampling points.

Parameters
[in]geomGeometry defining the domain.
[in,out]mf_SMarkMultiFab to be filled with turbine markers.
[in]sampling_distance_by_DNormalized sampling distance.
[in]turb_disk_angleAngle of the turbine disk in degrees.
[in]z_phys_ccCell-centered physical height FAB.
623 {
624  // Copy turbine locations to device
625  Gpu::DeviceVector<Real> d_xloc(xloc.size());
626  Gpu::DeviceVector<Real> d_yloc(yloc.size());
627  Gpu::DeviceVector<Real> d_zloc(zloc.size());
628 
629  Gpu::copy(Gpu::hostToDevice, xloc.begin(), xloc.end(), d_xloc.begin());
630 
631  Gpu::copy(Gpu::hostToDevice, yloc.begin(), yloc.end(), d_yloc.begin());
632 
633  Gpu::copy(Gpu::hostToDevice, zloc.begin(), zloc.end(), d_zloc.begin());
634 
635  Real d_rotor_rad = rotor_rad;
636  Real d_hub_height = hub_height;
637  Real d_sampling_distance = sampling_distance_by_D * two * rotor_rad;
638 
639  Real* d_xloc_ptr = d_xloc.data();
640  Real* d_yloc_ptr = d_yloc.data();
641  Real* d_zloc_ptr = d_zloc.data();
642 
643  mf_SMark.setVal(-1.0);
644 
645  const int i_lo = geom.Domain().smallEnd(0);
646  const int i_hi = geom.Domain().bigEnd(0);
647  const int j_lo = geom.Domain().smallEnd(1);
648  const int j_hi = geom.Domain().bigEnd(1);
649  const int k_lo = geom.Domain().smallEnd(2);
650  const int k_hi = geom.Domain().bigEnd(2);
651 
652  auto dx = geom.CellSizeArray();
653  auto ProbLoArr = geom.ProbLoArray();
654 
655  const int num_turb = static_cast<int>(xloc.size());
656 
657  Real theta = turb_disk_angle * M_PI / Real(180.0) - myhalf * M_PI;
658 
661 
662  Real nx = -std::cos(theta);
663  Real ny = -std::sin(theta);
664 
665  // ------------------------------------------------------------
666  // Device-side overlap information
667  //
668  // overlap_info[0] = overlap flag
669  // overlap_info[1] = first turbine index
670  // overlap_info[2] = second turbine index
671  // ------------------------------------------------------------
672 
673  int h_overlap_info[3] = {0, -1, -1};
674 
675  Gpu::DeviceVector<int> d_overlap_info(3);
676 
677  Gpu::copy(Gpu::hostToDevice, h_overlap_info, h_overlap_info + 3, d_overlap_info.begin());
678 
679  int* d_overlap_info_ptr = d_overlap_info.data();
680 
681  // ------------------------------------------------------------
682  // Initialize wind farm
683  // ------------------------------------------------------------
684 
685  for (MFIter mfi(mf_SMark, TilingIfNotGPU()); mfi.isValid(); ++mfi)
686  {
687  const Box& gbx = mfi.growntilebox(1);
688 
689  auto SMark_array = mf_SMark.array(mfi);
690 
691  const Array4<const Real>& z_cc_arr = z_phys_cc->const_array(mfi);
692 
693  ParallelFor(
694  gbx,
695  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
696  {
697  int ii = amrex::min(amrex::max(i, i_lo), i_hi);
698  int jj = amrex::min(amrex::max(j, j_lo), j_hi);
699  int kk = amrex::min(amrex::max(k, k_lo), k_hi);
700 
701  // ------------------------------------------------
702  // Mesh-cell x/y extents
703  // ------------------------------------------------
704 
705  Real x1 = ProbLoArr[0] + ii * dx[0];
706  Real x2 = ProbLoArr[0] + (ii + 1) * dx[0];
707 
708  Real y1 = ProbLoArr[1] + jj * dx[1];
709  Real y2 = ProbLoArr[1] + (jj + 1) * dx[1];
710 
711  // ------------------------------------------------
712  // Cell-centered physical z
713  // ------------------------------------------------
714 
715  Real z = z_cc_arr(ii, jj, kk);
716 
717  int check_int = 0;
718  int first_turb = -1;
719 
720  for (int it = 0; it < num_turb; ++it)
721  {
722  Real z0 = d_zloc_ptr[it];
723 
724  // ------------------------------------------------
725  // Sampling point upstream/downstream of turbine
726  // ------------------------------------------------
727 
728  Real x0 = d_xloc_ptr[it] + d_sampling_distance * nx;
729 
730  Real y0 = d_yloc_ptr[it] + d_sampling_distance * ny;
731 
732  bool is_cell_marked =
734  x1, x2, y1, y2,
735  x0, y0,
736  nx, ny,
737  d_hub_height + z0,
738  d_rotor_rad,
739  z);
740 
741  if (is_cell_marked)
742  {
743  SMark_array(i, j, k, 0) = it;
744  }
745 
746  // ------------------------------------------------
747  // Actual turbine disk
748  // ------------------------------------------------
749 
750  x0 = d_xloc_ptr[it];
751  y0 = d_yloc_ptr[it];
752 
753  is_cell_marked =
755  x1, x2, y1, y2,
756  x0, y0,
757  nx, ny,
758  d_hub_height + z0,
759  d_rotor_rad,
760  z);
761 
762  if (is_cell_marked)
763  {
764  SMark_array(i, j, k, 1) = it;
765 
766  if (check_int == 0)
767  {
768  first_turb = it;
769  }
770 
771  ++check_int;
772 
773  // ------------------------------------------------
774  // More than one turbine disk marks this cell
775  // ------------------------------------------------
776 
777  if (check_int > 1)
778  {
779  // Set overlap flag.
780  amrex::Gpu::Atomic::Exch(&d_overlap_info_ptr[0], 1);
781 
782  // Save the turbine indices. Multiple threads
783  // may write these, so use atomics.
784  amrex::Gpu::Atomic::Exch(&d_overlap_info_ptr[1], first_turb);
785 
786  amrex::Gpu::Atomic::Exch(&d_overlap_info_ptr[2], it);
787  }
788  }
789  }
790  });
791  }
792 
793  // ------------------------------------------------------------
794  // Copy overlap information back to host.
795  // This also synchronizes the GPU work.
796  // ------------------------------------------------------------
797 
798  Gpu::copy(Gpu::deviceToHost, d_overlap_info.begin(), d_overlap_info.end(), h_overlap_info);
799 
800  // ------------------------------------------------------------
801  // Handle overlap on the HOST, not inside the GPU kernel.
802  // ------------------------------------------------------------
803 
804  if (h_overlap_info[0] != 0)
805  {
806  amrex::Error(
807  "Actuator disks with indices " + std::to_string(h_overlap_info[1]) +
808  " and " + std::to_string(h_overlap_info[2]) + " are overlapping. "
809  "Visualize actuator_disks.vtk and check the "
810  "windturbine locations input file. Exiting..");
811  }
812 }
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
#define M_PI
Definition: ERF_HurricaneDiagnostics.cpp:26
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:8
static AMREX_GPU_DEVICE bool find_if_marked(amrex::Real x1, amrex::Real x2, amrex::Real y1, amrex::Real y2, amrex::Real x0, amrex::Real y0, amrex::Real nx, amrex::Real ny, amrex::Real d_hub_height, amrex::Real d_rotor_rad, amrex::Real z)
Definition: ERF_NullWindFarm.H:140
amrex::Real my_turb_disk_angle
Definition: ERF_WindFarm.H:281
amrex::Real hub_height
Definition: ERF_WindFarm.H:282
amrex::Real rotor_rad
Definition: ERF_WindFarm.H:282
void set_turb_disk_angle(const amrex::Real &a_turb_disk_angle) override
Set the turbine disk angle.
Definition: ERF_WindFarm.H:230
@ theta
Definition: ERF_SLM.H:20
Here is the call graph for this function:

◆ fill_SMark_multifab_mesoscale_models()

void WindFarm::fill_SMark_multifab_mesoscale_models ( const amrex::Geometry &  geom,
amrex::MultiFab &  mf_SMark,
const amrex::MultiFab &  mf_Nturb,
std::unique_ptr< amrex::MultiFab > &  z_phys_cc 
)

Fill the SMark MultiFab for mesoscale models.

Parameters
[in]geomGeometry
[out]mf_SMarkMultiFab to fill with SMark values.
[in]mf_NturbMultiFab containing turbine counts.
[in,out]z_phys_ccPhysical height MultiFab.

Fill the SMark MultiFab for mesoscale model parametrization.

Parameters
[in]geomGeometry defining the domain.
[in,out]mf_SMarkMultiFab to be filled with turbine markers.
[in]mf_NturbMultiFab containing turbine counts per cell.
[in]z_phys_ndNode-centered physical height FAB.
561 {
562  mf_SMark.setVal(-1.0);
563 
564  Real d_hub_height = hub_height;
565 
566  amrex::Gpu::DeviceVector<Real> d_xloc(xloc.size());
567  amrex::Gpu::DeviceVector<Real> d_yloc(yloc.size());
568  amrex::Gpu::DeviceVector<Real> d_zloc(xloc.size());
569  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, xloc.begin(), xloc.end(), d_xloc.begin());
570  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, yloc.begin(), yloc.end(), d_yloc.begin());
571  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice, zloc.begin(), zloc.end(), d_zloc.begin());
572 
573  int i_lo = geom.Domain().smallEnd(0); int i_hi = geom.Domain().bigEnd(0);
574  int j_lo = geom.Domain().smallEnd(1); int j_hi = geom.Domain().bigEnd(1);
575  int k_lo = geom.Domain().smallEnd(2); int k_hi = geom.Domain().bigEnd(2);
576 
577  //auto dx = geom.CellSizeArray();
578  //auto ProbLoArr = geom.ProbLoArray();
579 
580  // Initialize wind farm
581  for ( MFIter mfi(mf_SMark,TilingIfNotGPU()); mfi.isValid(); ++mfi) {
582 
583  const Box& gbx = mfi.growntilebox(1);
584  auto SMark_array = mf_SMark.array(mfi);
585  auto Nturb_array = mf_Nturb.array(mfi);
586  const Array4<const Real>& z_nd_arr = z_phys_nd->const_array(mfi);
587  int k0 = std::max(gbx.smallEnd(2), geom.Domain().smallEnd(2));
588 
589  ParallelFor(gbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
590  if(Nturb_array(i,j,k,0) > 0) {
591  int li = amrex::min(amrex::max(i, i_lo), i_hi);
592  int lj = amrex::min(amrex::max(j, j_lo), j_hi);
593  int lk = amrex::min(amrex::max(k, k_lo), k_hi);
594 
595  Real z1 = z_nd_arr(li,lj,lk );
596  Real z2 = z_nd_arr(li,lj,lk+1);
597 
598  Real zturb = z_nd_arr(li,lj,k0) + d_hub_height;
599  if (zturb+1e-3 > z1 and zturb+1e-3 < z2) {
600  SMark_array(i,j,k,0) = one;
601  }
602  }
603  });
604  }
605 }
constexpr amrex::Real one
Definition: ERF_Constants.H:9
Here is the call graph for this function:

◆ init_windfarm_lat_lon()

void WindFarm::init_windfarm_lat_lon ( const std::string  windfarm_loc_table,
const amrex::Real  windfarm_x_shift,
const amrex::Real  windfarm_y_shift 
)

Initialize wind farm using latitude and longitude coordinates.

Parameters
[in]windfarm_loc_tablePath to the location table.
[in]windfarm_x_shiftX-coordinate shift.
[in]windfarm_y_shiftY-coordinate shift.

Initialize turbine locations from latitude and longitude coordinates.

Parameters
[in]windfarm_loc_tablePath to the turbine locations table.
[in]windfarm_x_shiftShift applied to the resulting x coordinates.
[in]windfarm_y_shiftShift applied to the resulting y coordinates.
74 {
75  // Re-reading the file must not append to a previous level's list.
76  xloc.clear();
77  yloc.clear();
78 
79  // Read turbine locations from windturbines.txt
80  std::ifstream file(windfarm_loc_table);
81  if (!file.is_open()) {
82  amrex::Error("Wind turbines location table not found. Either the inputs is missing the"
83  " erf.windfarm_loc_table entry or the file specified in the entry " + windfarm_loc_table + " is missing.");
84  }
85  // Vector of vectors to store the matrix
86  Vector<Real> lat, lon;
87  Real value1, value2, value3;
88 
89  while (file >> value1 >> value2 >> value3) {
90 
91  if(std::fabs(value1) > Real(90.0)) {
92  amrex::Error("The value of latitude for entry " + std::to_string(lat.size() + 1) +
93  " in " + windfarm_loc_table + " should be within -90 and 90");
94  }
95 
96  if(std::fabs(value2) > Real(180.0)) {
97  amrex::Error("The value of longitude for entry " + std::to_string(lat.size() + 1) +
98  " in " + windfarm_loc_table + " should be within -180 and 180");
99  }
100  lat.push_back(value1);
101  lon.push_back(value2);
102  }
103  file.close();
104 
105  Real rad_earth = Real(6371.0e3); // Radius of the earth
106  Real m_per_deg_lat = rad_earth*two*M_PI/(two*Real(180.0));
107 
108  // Find the coordinates of average of min and max of the farm
109  // Rotate about that point
110  ParmParse pp("erf");
111  std::string fname_usgs;
112  auto valid_fname_USGS = pp.queryAdd("terrain_file_name_USGS",fname_usgs);
113  Real lon_ref, lat_ref;
114 
115  if (valid_fname_USGS) {
116  std::ifstream file_usgs(fname_usgs);
117  file_usgs >> lon_ref >> lat_ref;
118  file_usgs.close();
119  lon_ref = lon_ref*M_PI/Real(180.0);
120  lat_ref = lat_ref*M_PI/Real(180.0);
121  } else {
122  Real lat_min = *std::min_element(lat.begin(), lat.end());
123  Real lon_min = *std::min_element(lon.begin(), lon.end());
124 
125  lon_ref = lon_min*M_PI/Real(180.0);
126  lat_ref = lat_min*M_PI/Real(180.0);
127  }
128 
129 
130  for(int it=0;it<lat.size();it++){
131  lat[it] = lat[it]*M_PI/Real(180.0);
132  lon[it] = lon[it]*M_PI/Real(180.0);
133  Real delta_lat = (lat[it] - lat_ref);
134  Real delta_lon = (lon[it] - lon_ref);
135 
136  Real term1 = amrex::Math::powi<2>(sin(delta_lat/two));
137  Real term2 = cos(lat[it])*cos(lat_ref)*amrex::Math::powi<2>(sin(delta_lon/two));
138  Real dist = two*rad_earth*std::asin(std::sqrt(term1 + term2));
139  Real dy_turb = delta_lat * m_per_deg_lat * Real(180.0)/M_PI ;
140 
141  if(dist<dy_turb){
142  if(std::fabs(dist-dy_turb)<1e-8){
143  dist=dy_turb;
144  }
145  else{
146  Abort("The value of dist is less than dy_turb "+ std::to_string(dist) + " " + std::to_string(dy_turb));
147  }
148  }
149  Real tmp = amrex::Math::powi<2>(dist) - amrex::Math::powi<2>(dy_turb);
150 
151  if(std::fabs(tmp)<1e-8){
152  tmp = zero;
153  }
154  Real dx_turb = std::sqrt(tmp);
155 
156 
157  if(delta_lon >= zero) {
158  xloc.push_back(dx_turb);
159  }
160  else {
161  xloc.push_back(-dx_turb);
162  }
163  yloc.push_back(dy_turb);
164  }
165 
166  for(int it = 0;it<xloc.size(); it++){
167  xloc[it] = xloc[it] + windfarm_x_shift;
168  yloc[it] = yloc[it] + windfarm_y_shift;
169  }
170 }
ParmParse pp("prob")
@ tmp
Definition: ERF_AdvanceWSM6.cpp:114
Here is the call graph for this function:

◆ init_windfarm_x_y()

void WindFarm::init_windfarm_x_y ( const std::string  windfarm_loc_table)

Initialize wind farm using Cartesian coordinates.

Parameters
[in]windfarm_loc_tablePath to the location table.

Initialize turbine locations from Cartesian x and y coordinates.

Parameters
[in]windfarm_loc_tablePath to the turbine locations table.
179 {
180  // Read turbine locations from windturbines.txt
181  std::ifstream file(windfarm_loc_table);
182  if (!file.is_open()) {
183  amrex::Error("Wind turbines location table not found. Either the inputs is missing the"
184  " erf.windfarm_loc_table entry or the file specified in the entry " + windfarm_loc_table + " is missing.");
185  }
186  // Vector of vectors to store the matrix
187  Real value1, value2;
188 
189  // Re-reading the file must not append to a previous level's list.
190  xloc.clear();
191  yloc.clear();
192 
193  while (file >> value1 >> value2) {
194  value1 = value1 + 1e-3;
195  value2 = value2 + 1e-3;
196  xloc.push_back(value1);
197  yloc.push_back(value2);
198  }
199  file.close();
200 }

◆ read_tables()

void WindFarm::read_tables ( std::string  windfarm_loc_table,
std::string  windfarm_spec_table,
bool  x_y,
bool  lat_lon,
const amrex::Real  windfarm_x_shift = zero,
const amrex::Real  windfarm_y_shift = zero 
)

Read turbine location and specification tables.

Parameters
[in]windfarm_loc_tablePath to the location table.
[in]windfarm_spec_tablePath to the specification table.
[in]x_yWhether to use Cartesian coordinates.
[in]lat_lonWhether to use latitude and longitude coordinates.
[in]windfarm_x_shiftX-coordinate shift.
[in]windfarm_y_shiftY-coordinate shift.

Read in the turbine locations in latitude-longitude from windturbines.txt and convert it into x and y coordinates in metres

Parameters
levInteger specifying the current level
24 {
25  amrex::Print() << "Reading wind turbine locations table" << "\n";
26  read_windfarm_locations_table(windfarm_loc_table,
27  x_y, lat_lon,
28  windfarm_x_shift, windfarm_y_shift);
29 
30  amrex::Print() << "Reading wind turbine specifications table" << "\n";
31  read_windfarm_spec_table(windfarm_spec_table);
32 }
void read_windfarm_spec_table(const std::string windfarm_spec_table)
Read the turbine specification table.
Definition: ERF_WindFarm.cpp:209
void read_windfarm_locations_table(const std::string windfarm_loc_table, bool x_y, bool lat_lon, const amrex::Real windfarm_x_shift=zero, const amrex::Real windfarm_y_shift=zero)
Read the turbine location table.
Definition: ERF_WindFarm.cpp:44

◆ read_windfarm_airfoil_tables()

void WindFarm::read_windfarm_airfoil_tables ( const std::string  windfarm_airfoil_tables,
const std::string  windfarm_blade_table 
)

Read the airfoil tables.

Parameters
[in]windfarm_airfoil_tablesPath to the airfoil tables.
[in]windfarm_blade_tablePath to the blade table.

Read airfoil data from a directory of tables.

Parameters
[in]windfarm_airfoil_tablesPath to the directory containing airfoil tables.
[in]windfarm_blade_tablePath to the turbine blade properties table.
347 {
348  DIR* dir;
349  struct dirent* entry;
350  std::vector<std::string> files;
351 
352  // Check if directory exists
353  if ((dir = opendir(windfarm_airfoil_tables.c_str())) == nullptr) {
354  Abort("You are using a generalized actuator disk model based on blade element theory. This needs info of airfoil"
355  " cross sections over the span of the blade. There needs to be an entry erf.airfoil_tables which is the directory that"
356  " contains the angle of attack, Cl, Cd data for each airfoil cross-section. Either the entry is missing or the directory specified"
357  " in the entry - " + windfarm_airfoil_tables + " is missing. Exiting...");
358  }
359 
360  // Loop through directory entries and collect filenames
361  while ((entry = readdir(dir)) != nullptr) {
362  // Skip special directory entries "." and ".."
363  if (std::string(entry->d_name) == "." || std::string(entry->d_name) == "..") {
364  continue;
365  }
366  files.emplace_back(windfarm_airfoil_tables + "/" + entry->d_name); // Add file path to vector
367  }
368 
369  // Close the directory
370  closedir(dir);
371 
372  if (files.empty()) {
373  Abort("It seems the directory containing the info of airfoil cross sections of the blades - " + windfarm_airfoil_tables +
374  " is empty. Exiting...");
375  }
376 
377  if(files.size() != static_cast<long double>(n_bld_sections)) {
378  printf("There are %d airfoil sections in the last column of %s. But the number"
379  " of files in %s is only %ld.\n", n_bld_sections, windfarm_blade_table.c_str(),
380  windfarm_airfoil_tables.c_str(), files.size());
381  Abort("The number of blade sections from " + windfarm_blade_table + " should match the number of"
382  " files in " + windfarm_airfoil_tables + ". Exiting...");
383  }
384 
385  // Sort filenames in lexicographical (alphabetical) order
386  std::sort(files.begin(), files.end());
387 
388  // Process each file
389  int count = 0;
393  for (const auto& filePath : files) {
394  std::ifstream filename(filePath.c_str());
395 
396  if (!filename.is_open()) {
397  std::cerr << "Failed to open file: " << filePath << std::endl;
398  continue; // Move on to the next file
399  }
400 
401  std::cout << "Reading file: " << filePath << std::endl;
402 
403  std::string line;
404  for (int i = 0; i < 54; ++i) {
405  if (std::getline(filename, line)) { // Read one line into the array
406  }
407  }
408 
409  Real var1, var2, var3, temp;
410 
411  while(filename >> var1 >> var2 >> var3 >> temp) {
412  bld_airfoil_aoa[count].push_back(var1);
413  bld_airfoil_Cl[count].push_back(var2);
414  bld_airfoil_Cd[count].push_back(var3);
415  //int idx = bld_airfoil_aoa.size()-1;
416  //printf("Values are = %0.15g %0.15g %0.15g\n", bld_airfoil_aoa[idx], bld_airfoil_Cl[idx], bld_airfoil_Cd[idx]);
417  }
418  count++;
419  }
420 
422 }
amrex::Vector< amrex::Vector< amrex::Real > > bld_airfoil_Cl
Definition: ERF_WindFarm.H:285
amrex::Vector< amrex::Vector< amrex::Real > > bld_airfoil_aoa
Definition: ERF_WindFarm.H:285
amrex::Vector< amrex::Vector< amrex::Real > > bld_airfoil_Cd
Definition: ERF_WindFarm.H:285
int n_bld_sections
Definition: ERF_WindFarm.H:286
void set_blade_airfoil_spec(const amrex::Vector< amrex::Vector< amrex::Real >> &a_bld_airfoil_aoa, const amrex::Vector< amrex::Vector< amrex::Real >> &a_bld_airfoil_Cl, const amrex::Vector< amrex::Vector< amrex::Real >> &a_bld_airfoil_Cd) override
Set blade airfoil specifications.
Definition: ERF_WindFarm.H:254

◆ read_windfarm_blade_table()

void WindFarm::read_windfarm_blade_table ( const std::string  windfarm_blade_table)

Read the turbine blade table.

Parameters
[in]windfarm_blade_tablePath to the blade table.

Read turbine blade geometry and properties from a table.

Parameters
[in]windfarm_blade_tablePath to the turbine blade properties table.
263 {
264  std::ifstream filename(windfarm_blade_table);
265  std::string line;
266  Real temp, var1, var2, var3;
267  if (!filename.is_open()) {
268  Error("You are using a generalized actuator disk model based on blade element theory. This needs info of blades."
269  " An entry erf.windfarm_blade_table is needed. Either the entry is missing or the file specified"
270  " in the entry - " + windfarm_blade_table + " is missing.");
271  }
272  else {
273  Print() << "Reading in wind farm blade table: " << windfarm_blade_table << "\n";
274 
275  // First 6 lines are comments
276 
277  for (int i = 0; i < 6; ++i) {
278  if (std::getline(filename, line)) { // Read one line into the array
279  }
280  }
281 
282  while(filename >> var1 >> temp >> temp >> temp >> var2 >> var3 >> temp) {
283  bld_rad_loc.push_back(var1);
284  bld_twist.push_back(var2);
285  bld_chord.push_back(var3);
286  //int idx = bld_rad_loc.size()-1;
287  //printf("Values are = %0.15g %0.15g %0.15g\n", bld_rad_loc[idx], bld_twist[idx], bld_chord[idx]);
288  }
290  n_bld_sections = bld_rad_loc.size();
291  }
292 }
void set_blade_spec(const amrex::Vector< amrex::Real > &a_bld_rad_loc, const amrex::Vector< amrex::Real > &a_bld_twist, const amrex::Vector< amrex::Real > &a_bld_chord) override
Set blade specifications.
Definition: ERF_WindFarm.H:241
amrex::Vector< amrex::Real > bld_twist
Definition: ERF_WindFarm.H:284
amrex::Vector< amrex::Real > bld_chord
Definition: ERF_WindFarm.H:284
amrex::Vector< amrex::Real > bld_rad_loc
Definition: ERF_WindFarm.H:284

◆ read_windfarm_locations_table()

void WindFarm::read_windfarm_locations_table ( const std::string  windfarm_loc_table,
bool  x_y,
bool  lat_lon,
const amrex::Real  windfarm_x_shift = zero,
const amrex::Real  windfarm_y_shift = zero 
)

Read the turbine location table.

Parameters
[in]windfarm_loc_tablePath to the location table.
[in]x_yWhether to use Cartesian coordinates.
[in]lat_lonWhether to use latitude and longitude coordinates.
[in]windfarm_x_shiftX-coordinate shift.
[in]windfarm_y_shiftY-coordinate shift.

Read turbine locations from a table and convert them to Cartesian coordinates.

Parameters
[in]windfarm_loc_tablePath to the turbine locations table.
[in]x_yBoolean indicating if locations are provided as x and y coordinates.
[in]lat_lonBoolean indicating if locations are provided as latitude and longitude.
[in]windfarm_x_shiftShift applied to the resulting x coordinates.
[in]windfarm_y_shiftShift applied to the resulting y coordinates.
48 {
49  if(x_y) {
50  init_windfarm_x_y(windfarm_loc_table);
51  }
52  else if(lat_lon) {
53  init_windfarm_lat_lon(windfarm_loc_table, windfarm_x_shift, windfarm_y_shift);
54  }
55  else {
56  amrex::Abort("Are you using windfarms? For windfarm simulations, the inputs need to have an"
57  " entry erf.windfarm_loc_type which should be either lat_lon or x_y. \n");
58  }
59 
61 }
void set_turb_loc(const amrex::Vector< amrex::Real > &a_xloc, const amrex::Vector< amrex::Real > &a_yloc) override
Set turbine locations.
Definition: ERF_WindFarm.H:220
void init_windfarm_x_y(const std::string windfarm_loc_table)
Initialize wind farm using Cartesian coordinates.
Definition: ERF_WindFarm.cpp:178
void init_windfarm_lat_lon(const std::string windfarm_loc_table, const amrex::Real windfarm_x_shift, const amrex::Real windfarm_y_shift)
Initialize wind farm using latitude and longitude coordinates.
Definition: ERF_WindFarm.cpp:71

◆ read_windfarm_spec_table()

void WindFarm::read_windfarm_spec_table ( const std::string  windfarm_spec_table)

Read the turbine specification table.

Parameters
[in]windfarm_spec_tablePath to the specification table.

Read turbine performance specifications from a table.

Parameters
[in]windfarm_spec_tablePath to the turbine specifications table.
210 {
211  //The first line is the number of pairs entries for the power curve and thrust coefficient.
212  //The second line gives first the height in meters of the turbine hub, second, the diameter in
213  //meters of the rotor, third the standing thrust coefficient, and fourth the nominal power of
214  //the turbine in MW.
215  //The remaining lines contain the three values of: wind speed, thrust coefficient, and power production in kW.
216 
217  // Read turbine data from wind-turbine-1.tbl
218  std::ifstream file_turb_table(windfarm_spec_table);
219  if (!file_turb_table.is_open()) {
220  Error("Wind farm specifications table not found. Either the inputs is missing the "
221  "erf.windfarm_spec_table entry or the file specified in the entry - " + windfarm_spec_table + " is missing.");
222  }
223  else {
224  Print() << "Reading in wind farm specifications table: " << windfarm_spec_table << "\n";
225  }
226 
227  int nlines;
228  file_turb_table >> nlines;
229  wind_speed.resize(nlines);
230  thrust_coeff.resize(nlines);
231  power.resize(nlines);
232 
233  Real rotor_dia;
234  file_turb_table >> hub_height >> rotor_dia >> thrust_coeff_standing >> nominal_power;
235  rotor_rad = rotor_dia*myhalf;
236  if(rotor_rad > hub_height) {
237  Abort("The blade length is more than the hub height. Check the second line in wind-turbine-1.tbl. Aborting.....");
238  }
239  if(thrust_coeff_standing > one) {
240  Abort("The standing thrust coefficient is greater than one. Check the second line in wind-turbine-1.tbl. Aborting.....");
241  }
242 
243  for(int iline=0;iline<nlines;iline++){
244  file_turb_table >> wind_speed[iline] >> thrust_coeff[iline] >> power[iline];
245  if(thrust_coeff[iline] > one) {
246  Abort("The thrust coefficient is greater than one. Check wind-turbine-1.tbl. Aborting.....");
247  }
248  }
249  file_turb_table.close();
250 
253 
254 }
amrex::Vector< amrex::Real > wind_speed
Definition: ERF_WindFarm.H:283
amrex::Vector< amrex::Real > thrust_coeff
Definition: ERF_WindFarm.H:283
amrex::Real nominal_power
Definition: ERF_WindFarm.H:282
void set_turb_spec(const amrex::Real &a_rotor_rad, const amrex::Real &a_hub_height, const amrex::Real &a_thrust_coeff_standing, const amrex::Vector< amrex::Real > &a_wind_speed, const amrex::Vector< amrex::Real > &a_thrust_coeff, const amrex::Vector< amrex::Real > &a_power) override
Set general turbine specifications.
Definition: ERF_WindFarm.H:206
amrex::Real thrust_coeff_standing
Definition: ERF_WindFarm.H:282
amrex::Vector< amrex::Real > power
Definition: ERF_WindFarm.H:283

◆ read_windfarm_spec_table_extra()

void WindFarm::read_windfarm_spec_table_extra ( const std::string  windfarm_spec_table_extra)

Read extra turbine specifications.

Parameters
[in]windfarm_spec_table_extraPath to the extra specification table.

Read extended turbine performance specifications from a table.

Parameters
[in]windfarm_spec_table_extraPath to the extended turbine specifications table.
301 {
302  // Open the file
303  std::ifstream file(windfarm_spec_table_extra);
304 
305  // Check if file opened successfully
306  if (!file.is_open()) {
307  Abort("Error: You are using generalized wind farms option. This requires an input file erf.windfarm_spec_table_extra."
308  " Either this entry is missing in the inputs or the file specified -" + windfarm_spec_table_extra + " does"
309  " not exist. Exiting...");
310  } else {
311  printf("Reading in windfarm_spec_table_extra %s", windfarm_spec_table_extra.c_str());
312  }
313 
314  // Ignore the first line (header)
315  std::string header;
316  std::getline(file, header);
317 
318  // Variables to hold each row's values
319  double V, Cp, Ct, rpm, pitch, temp;
320 
321  // Read the file row by row
322  while (file >> V) {
323  char comma; // To ignore the commas
324  file >> comma >> Cp >> comma >> Ct >> comma >> temp >> comma >> temp >> comma
325  >> temp >> comma >> rpm >> comma >> pitch >> comma >> temp;
326 
327  velocity.push_back(V);
328  C_P.push_back(Cp);
329  C_T.push_back(Ct);
330  rotor_RPM.push_back(rpm);
331  blade_pitch.push_back(pitch);
332  }
333 
335 }
amrex::Vector< amrex::Real > blade_pitch
Definition: ERF_WindFarm.H:287
void set_turb_spec_extra(const amrex::Vector< amrex::Real > &a_velocity, const amrex::Vector< amrex::Real > &a_C_P, const amrex::Vector< amrex::Real > &a_C_T, const amrex::Vector< amrex::Real > &a_rotor_RPM, const amrex::Vector< amrex::Real > &a_blade_pitch) override
Set extra turbine specifications.
Definition: ERF_WindFarm.H:269
amrex::Vector< amrex::Real > velocity
Definition: ERF_WindFarm.H:287
amrex::Vector< amrex::Real > C_P
Definition: ERF_WindFarm.H:287
amrex::Vector< amrex::Real > C_T
Definition: ERF_WindFarm.H:287
amrex::Vector< amrex::Real > rotor_RPM
Definition: ERF_WindFarm.H:287
@ V
Definition: ERF_IndexDefines.H:127

◆ set_blade_airfoil_spec()

void WindFarm::set_blade_airfoil_spec ( const amrex::Vector< amrex::Vector< amrex::Real >> &  a_bld_airfoil_aoa,
const amrex::Vector< amrex::Vector< amrex::Real >> &  a_bld_airfoil_Cl,
const amrex::Vector< amrex::Vector< amrex::Real >> &  a_bld_airfoil_Cd 
)
inlineoverridevirtual

Set blade airfoil specifications.

Parameters
[in]a_bld_airfoil_aoaAngle of attack.
[in]a_bld_airfoil_ClLift coefficient.
[in]a_bld_airfoil_CdDrag coefficient.

Reimplemented from NullWindFarm.

257  {
258  m_windfarm_model[0]->set_blade_airfoil_spec(a_bld_airfoil_aoa, a_bld_airfoil_Cl, a_bld_airfoil_Cd);
259  }

◆ set_blade_spec()

void WindFarm::set_blade_spec ( const amrex::Vector< amrex::Real > &  a_bld_rad_loc,
const amrex::Vector< amrex::Real > &  a_bld_twist,
const amrex::Vector< amrex::Real > &  a_bld_chord 
)
inlineoverridevirtual

Set blade specifications.

Parameters
[in]a_bld_rad_locBlade radial locations.
[in]a_bld_twistBlade twist.
[in]a_bld_chordBlade chord.

Reimplemented from NullWindFarm.

244  {
245  m_windfarm_model[0]->set_blade_spec(a_bld_rad_loc, a_bld_twist, a_bld_chord);
246  }

◆ set_turb_disk_angle()

void WindFarm::set_turb_disk_angle ( const amrex::Real a_turb_disk_angle)
inlineoverridevirtual

Set the turbine disk angle.

Parameters
[in]a_turb_disk_angleDisk angle.

Reimplemented from NullWindFarm.

231  {
232  m_windfarm_model[0]->set_turb_disk_angle(a_turb_disk_angle);
233  }

◆ set_turb_loc()

void WindFarm::set_turb_loc ( const amrex::Vector< amrex::Real > &  a_xloc,
const amrex::Vector< amrex::Real > &  a_yloc 
)
inlineoverridevirtual

Set turbine locations.

Parameters
[in]a_xlocX locations.
[in]a_ylocY locations.

Reimplemented from NullWindFarm.

222  {
223  m_windfarm_model[0]->set_turb_loc(a_xloc, a_yloc);
224  }

◆ set_turb_spec()

void WindFarm::set_turb_spec ( const amrex::Real a_rotor_rad,
const amrex::Real a_hub_height,
const amrex::Real a_thrust_coeff_standing,
const amrex::Vector< amrex::Real > &  a_wind_speed,
const amrex::Vector< amrex::Real > &  a_thrust_coeff,
const amrex::Vector< amrex::Real > &  a_power 
)
inlineoverridevirtual

Set general turbine specifications.

Parameters
[in]a_rotor_radRotor radius.
[in]a_hub_heightHub height.
[in]a_thrust_coeff_standingStanding thrust coefficient.
[in]a_wind_speedWind speed vector.
[in]a_thrust_coeffThrust coefficient vector.
[in]a_powerPower vector.

Reimplemented from NullWindFarm.

210  {
211  m_windfarm_model[0]->set_turb_spec(a_rotor_rad, a_hub_height, a_thrust_coeff_standing,
212  a_wind_speed, a_thrust_coeff, a_power);
213  }

◆ set_turb_spec_extra()

void WindFarm::set_turb_spec_extra ( const amrex::Vector< amrex::Real > &  a_velocity,
const amrex::Vector< amrex::Real > &  a_C_P,
const amrex::Vector< amrex::Real > &  a_C_T,
const amrex::Vector< amrex::Real > &  a_rotor_RPM,
const amrex::Vector< amrex::Real > &  a_blade_pitch 
)
inlineoverridevirtual

Set extra turbine specifications.

Parameters
[in]a_velocityVelocity.
[in]a_C_PPower coefficient.
[in]a_C_TThrust coefficient.
[in]a_rotor_RPMRotor RPM.
[in]a_blade_pitchBlade pitch.

Reimplemented from NullWindFarm.

274  {
275  m_windfarm_model[0]->set_turb_spec_extra(a_velocity, a_C_P, a_C_T, a_rotor_RPM, a_blade_pitch);
276  }

◆ SetModel()

template<class NewWindFarmModel >
void WindFarm::SetModel ( )
inlineprotected

Create and set the specified windfarm model.

292  {
293  for (int lev(0); lev<m_windfarm_model.size(); ++lev) {
294  m_windfarm_model[lev] = std::make_unique<NewWindFarmModel>();
295  }
296  }

◆ write_actuator_disks_vtk()

void WindFarm::write_actuator_disks_vtk ( const amrex::Geometry &  geom,
const amrex::Real sampling_distance_by_D 
)

Write actuator disks to a VTK file.

Parameters
[in]geomGeometry
[in]sampling_distance_by_DSampling distance normalized by rotor diameter.

Write the actuator disks and sampling disks to VTK files.

Parameters
[in]geomGeometry defining the domain.
[in]sampling_distance_by_DNormalized sampling distance.
845 {
846 
847  Real sampling_distance = sampling_distance_by_D*two*rotor_rad;
848 
849  if (ParallelDescriptor::IOProcessor()){
850  FILE *file_actuator_disks_all, *file_actuator_disks_in_dom, *file_averaging_disks_in_dom;
851  file_actuator_disks_all = fopen("actuator_disks_all.vtk","w");
852  fprintf(file_actuator_disks_all, "%s\n","# vtk DataFile Version 3.0");
853  fprintf(file_actuator_disks_all, "%s\n","Actuator Disks");
854  fprintf(file_actuator_disks_all, "%s\n","ASCII");
855  fprintf(file_actuator_disks_all, "%s\n","DATASET POLYDATA");
856 
857  file_actuator_disks_in_dom = fopen("actuator_disks_in_dom.vtk","w");
858  fprintf(file_actuator_disks_in_dom, "%s\n","# vtk DataFile Version 3.0");
859  fprintf(file_actuator_disks_in_dom, "%s\n","Actuator Disks");
860  fprintf(file_actuator_disks_in_dom, "%s\n","ASCII");
861  fprintf(file_actuator_disks_in_dom, "%s\n","DATASET POLYDATA");
862 
863  file_averaging_disks_in_dom = fopen("averaging_disks_in_dom.vtk","w");
864  fprintf(file_averaging_disks_in_dom, "%s\n","# vtk DataFile Version 3.0");
865  fprintf(file_averaging_disks_in_dom, "%s\n","Actuator Disks");
866  fprintf(file_averaging_disks_in_dom, "%s\n","ASCII");
867  fprintf(file_averaging_disks_in_dom, "%s\n","DATASET POLYDATA");
868 
869 
870  int npts = 100;
871  fprintf(file_actuator_disks_all, "%s %ld %s\n", "POINTS", xloc.size()*npts, "float");
872  auto ProbLoArr = geom.ProbLoArray();
873  auto ProbHiArr = geom.ProbHiArray();
874  int num_turb_in_dom = 0;
875 
876  // Find the number of turbines inside the specified computational domain
877 
878  for(int it=0; it<xloc.size(); it++){
879  Real x = xloc[it];
880  Real y = yloc[it];
881  if(x > ProbLoArr[0] and x < ProbHiArr[0] and y > ProbLoArr[1] and y < ProbHiArr[1]) {
882  num_turb_in_dom++;
883  }
884  }
885  fprintf(file_actuator_disks_in_dom, "%s %ld %s\n", "POINTS", static_cast<long int>(num_turb_in_dom*npts), "float");
886  fprintf(file_averaging_disks_in_dom, "%s %ld %s\n", "POINTS", static_cast<long int>(num_turb_in_dom*npts), "float");
887 
888  Real nx = std::cos(my_turb_disk_angle+myhalf*M_PI);
889  Real ny = std::sin(my_turb_disk_angle+myhalf*M_PI);
890 
891  Real nx1 = -std::cos(my_turb_disk_angle);
892  Real ny1 = -std::sin(my_turb_disk_angle);
893 
894  for(int it=0; it<xloc.size(); it++){
895  for(int pt=0;pt<100;pt++){
896  Real x, y, z, xavg, yavg;
897  Real theta = two*M_PI/npts*pt;
898  x = xloc[it] + rotor_rad*cos(theta)*nx;
899  y = yloc[it] + rotor_rad*cos(theta)*ny;
900  z = hub_height + zloc[it] + rotor_rad*sin(theta);
901 
902  xavg = xloc[it] + sampling_distance*nx1 + rotor_rad*cos(theta)*nx;
903  yavg = yloc[it] + sampling_distance*ny1 + rotor_rad*cos(theta)*ny;
904 
905  fprintf(file_actuator_disks_all, "%0.15g %0.15g %0.15g\n", x, y, z);
906  if(xloc[it] > ProbLoArr[0] and xloc[it] < ProbHiArr[0] and yloc[it] > ProbLoArr[1] and yloc[it] < ProbHiArr[1]) {
907  fprintf(file_actuator_disks_in_dom, "%0.15g %0.15g %0.15g\n", x, y, z);
908  fprintf(file_averaging_disks_in_dom, "%0.15g %0.15g %0.15g\n", xavg, yavg, z);
909  }
910  }
911  }
912  fprintf(file_actuator_disks_all, "%s %ld %ld\n", "LINES", xloc.size()*(npts-1), static_cast<long int>(xloc.size()*(npts-1)*3));
913  fprintf(file_actuator_disks_in_dom, "%s %ld %ld\n", "LINES", static_cast<long int>(num_turb_in_dom*(npts-1)), static_cast<long int>(num_turb_in_dom*(npts-1)*3));
914  fprintf(file_averaging_disks_in_dom, "%s %ld %ld\n", "LINES", static_cast<long int>(num_turb_in_dom*(npts-1)), static_cast<long int>(num_turb_in_dom*(npts-1)*3));
915  for(int it=0; it<xloc.size(); it++){
916  for(int pt=0;pt<99;pt++){
917  fprintf(file_actuator_disks_all, "%ld %ld %ld\n",
918  static_cast<long int>(2),
919  static_cast<long int>(it*npts+pt),
920  static_cast<long int>(it*npts+pt+1));
921  }
922  }
923  for(int it=0; it<num_turb_in_dom; it++){
924  for(int pt=0;pt<99;pt++){
925  fprintf(file_actuator_disks_in_dom, "%ld %ld %ld\n",
926  static_cast<long int>(2),
927  static_cast<long int>(it*npts+pt),
928  static_cast<long int>(it*npts+pt+1));
929  }
930  }
931 
932  for(int it=0; it<num_turb_in_dom; it++){
933  for(int pt=0;pt<99;pt++){
934  fprintf(file_averaging_disks_in_dom, "%ld %ld %ld\n",
935  static_cast<long int>(2),
936  static_cast<long int>(it*npts+pt),
937  static_cast<long int>(it*npts+pt+1));
938  }
939  }
940 
941  fclose(file_actuator_disks_all);
942  fclose(file_actuator_disks_in_dom);
943  fclose(file_averaging_disks_in_dom);
944  }
945 }

◆ write_turbine_locations_vtk()

void WindFarm::write_turbine_locations_vtk ( )

Write turbine locations to a VTK file.

Write the turbine hub locations to a VTK file.

819 {
820  if (ParallelDescriptor::IOProcessor()){
821  FILE* file_turbloc_vtk;
822  file_turbloc_vtk = fopen("turbine_locations.vtk","w");
823  fprintf(file_turbloc_vtk, "%s\n","# vtk DataFile Version 3.0");
824  fprintf(file_turbloc_vtk, "%s\n","Wind turbine locations");
825  fprintf(file_turbloc_vtk, "%s\n","ASCII");
826  fprintf(file_turbloc_vtk, "%s\n","DATASET POLYDATA");
827  fprintf(file_turbloc_vtk, "%s %ld %s\n", "POINTS", xloc.size(), "float");
828  for(int it=0; it<xloc.size(); it++){
829  fprintf(file_turbloc_vtk, "%0.15g %0.15g %0.15g\n", xloc[it], yloc[it], hub_height);
830  }
831  fclose(file_turbloc_vtk);
832  }
833 }

Member Data Documentation

◆ blade_pitch

amrex::Vector<amrex::Real> WindFarm::blade_pitch
protected

◆ bld_airfoil_aoa

amrex::Vector<amrex::Vector<amrex::Real> > WindFarm::bld_airfoil_aoa
protected

◆ bld_airfoil_Cd

amrex::Vector<amrex::Vector<amrex::Real> > WindFarm::bld_airfoil_Cd
protected

◆ bld_airfoil_Cl

amrex::Vector<amrex::Vector<amrex::Real> > WindFarm::bld_airfoil_Cl
protected

◆ bld_chord

amrex::Vector<amrex::Real> WindFarm::bld_chord
protected

◆ bld_rad_loc

amrex::Vector<amrex::Real> WindFarm::bld_rad_loc
protected

◆ bld_twist

amrex::Vector<amrex::Real> WindFarm::bld_twist
protected

◆ C_P

amrex::Vector<amrex::Real> WindFarm::C_P
protected

◆ C_T

amrex::Vector<amrex::Real> WindFarm::C_T
protected

◆ hub_height

amrex::Real WindFarm::hub_height
protected

◆ m_windfarm_model

amrex::Vector<std::unique_ptr<NullWindFarm> > WindFarm::m_windfarm_model
private

◆ my_turb_disk_angle

amrex::Real WindFarm::my_turb_disk_angle
protected

◆ n_bld_sections

int WindFarm::n_bld_sections
protected

◆ nominal_power

amrex::Real WindFarm::nominal_power
protected

◆ power

amrex::Vector<amrex::Real> WindFarm::power
protected

◆ rotor_rad

amrex::Real WindFarm::rotor_rad
protected

◆ rotor_RPM

amrex::Vector<amrex::Real> WindFarm::rotor_RPM
protected

◆ thrust_coeff

amrex::Vector<amrex::Real> WindFarm::thrust_coeff
protected

◆ thrust_coeff_standing

amrex::Real WindFarm::thrust_coeff_standing
protected

◆ velocity

amrex::Vector<amrex::Real> WindFarm::velocity
protected

◆ wind_speed

amrex::Vector<amrex::Real> WindFarm::wind_speed
protected

◆ xloc

amrex::Vector<amrex::Real> WindFarm::xloc
protected

◆ yloc

amrex::Vector<amrex::Real> WindFarm::yloc
protected

◆ zloc

amrex::Vector<amrex::Real> WindFarm::zloc
protected

The documentation for this class was generated from the following files: