ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
TurbulentPerturbation Struct Reference

Runtime state and operations for turbulent perturbation forcing. More...

#include <ERF_TurbPertStruct.H>

Collaboration diagram for TurbulentPerturbation:

Public Member Functions

 ~TurbulentPerturbation ()
 Destroy turbulent perturbation state. More...
 
void init_tpi_type (const int lev, const PerturbationType &pert_type, const int max_level)
 Store the integer perturbation-type selector for one AMR level. More...
 
void init_tpi (const int lev, const amrex::Vector< amrex::BoxArray > &subdomains_lev, const amrex::GpuArray< amrex::Real, 3 > dx, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm, const int ngrow_state, std::string pp_prefix, const amrex::Vector< amrex::IntVect > refRatio, const int max_level)
 Initialize turbulent perturbation regions and per-box storage. More...
 
void calc_tpi_update (const int lev, const double dt, amrex::MultiFab &mf_xvel, amrex::MultiFab &mf_yvel, amrex::MultiFab &mf_cons)
 Update perturbation amplitudes and intervals when each box is ready. More...
 
void apply_tpi (const int &lev, const amrex::Box &vbx, const int &comp, const amrex::IndexType &m_ixtype, const amrex::Array4< amrex::Real > &src_arr, const amrex::Array4< amrex::Real const > &pert_cell)
 Apply stored turbulent perturbations to a source or state array. More...
 
void calc_tpi_amp (const int &lev, const int &boxIdx, const double &interval)
 Compute the perturbation amplitude for one perturbation box. More...
 
void pseudoRandomPert (const int &boxIdx, const int &lev, const amrex::IndexType &m_ixtype)
 Assign pseudo-random perturbations to cells in one perturbation box. More...
 
void zero_amp (const int &boxIdx, const int &lev, const amrex::IndexType &m_ixtype)
 Reset CPM perturbation amplitudes in one perturbation box to zero. More...
 
void netZeroBuoyantAdd (const int &boxIdx, const int &lev)
 Accumulate the mean perturbation contribution for net-zero buoyancy enforcement. More...
 
void netZeroBuoyantAdjust (const int &boxIdx, const int &lev)
 Adjust perturbation cells so the net buoyant forcing is zero. More...
 
void calc_tpi_meanMag_perBox (const int &boxIdx, const int &lev, amrex::MultiFab &mf_cons, amrex::MultiFab &mf_xvel, amrex::MultiFab &mf_yvel)
 Compute mean horizontal velocity magnitude and direction for one perturbation box. More...
 
void debug (double)
 Write perturbation debug information when debug output is enabled. More...
 

Public Attributes

amrex::Vector< int > pt_type
 Integer perturbation type for each AMR level. More...
 
amrex::Vector< amrex::BoxArray > pb_ba
 Perturbation-box BoxArray for each AMR level. More...
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_mag
 Mean velocity magnitude for each perturbation box [m/s]. More...
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_dir
 Mean velocity direction for each perturbation box. More...
 
amrex::Vector< amrex::MultiFab > pb_cell
 Per-cell perturbation amplitude storage. More...
 

Private Member Functions

amrex::Real RandomReal (const amrex::Real min, const amrex::Real max)
 Return a pseudo-random real value in a closed interval. More...
 

Private Attributes

int tpi_layers
 Number of layers of perturbation boxes. More...
 
int tpi_offset
 Cell offset for the start of the perturbation region. More...
 
amrex::Vector< int > tpi_boxDim
 Dimensions of each perturbation box. More...
 
amrex::Vector< int > tpi_direction
 Boundary directions where perturbations are applied. More...
 
amrex::Real tpi_nonDim
 Nondimensional number used by the perturbation formulation. More...
 
amrex::Real tpi_Ti
 Temperature intensity used by the perturbation formulation. More...
 
amrex::Real tpi_Tinf
 Reference temperature used by the perturbation formulation [K]. More...
 
amrex::Vector< amrex::Realtpi_Hpb
 Perturbation-box height for each AMR level [m]. More...
 
amrex::Vector< amrex::Realtpi_Lpb
 Perturbation-box length for each AMR level [m]. More...
 
amrex::Vector< amrex::Realtpi_Wpb
 Perturbation-box width for each AMR level [m]. More...
 
amrex::Vector< amrex::Realtpi_lref
 Perturbation-box reference length for each AMR level [m]. More...
 
amrex::Real tpi_net_buoyant
 Accumulated net buoyant perturbation used for correction. More...
 
amrex::Real tpi_pert_adjust
 Per-cell perturbation adjustment used for net-zero buoyancy. More...
 
amrex::Vector< amrex::IntVect > ref_ratio
 Refinement ratios used by multilevel perturbation scaling. More...
 
amrex::Real input_Ug
 Input geostrophic wind speed used to scale CPM perturbations. More...
 
amrex::Real input_w_amp
 Input vertical velocity perturbation amplitude. More...
 
int perturbation_klo
 Lower vertical index bound for perturbations. More...
 
int perturbation_khi
 Upper vertical index bound for perturbations. More...
 
amrex::Vector< amrex::Vector< double > > pb_interval
 Perturbation update interval for each box [s]. More...
 
amrex::Vector< amrex::Vector< double > > pb_local_etime
 Local elapsed time for each perturbation box [s]. More...
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_amp
 Perturbation amplitude for each perturbation box. More...
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_netZero
 Per-box storage used for net-zero buoyancy calculation. More...
 

Detailed Description

Runtime state and operations for turbulent perturbation forcing.

Constructor & Destructor Documentation

◆ ~TurbulentPerturbation()

TurbulentPerturbation::~TurbulentPerturbation ( )
inline

Destroy turbulent perturbation state.

32 {}

Member Function Documentation

◆ apply_tpi()

void TurbulentPerturbation::apply_tpi ( const int &  lev,
const amrex::Box &  vbx,
const int &  comp,
const amrex::IndexType &  m_ixtype,
const amrex::Array4< amrex::Real > &  src_arr,
const amrex::Array4< amrex::Real const > &  pert_cell 
)
inline

Apply stored turbulent perturbations to a source or state array.

Parameters
levAMR level index.
vbxValid box over which perturbations may be applied.
compComponent to modify, or -1 for vertical velocity perturbations.
m_ixtypeIndex type of the destination array.
src_arrDestination array receiving perturbation increments.
pert_cellStored perturbation amplitudes.
407  {
408  for (int boxIdx = 0; boxIdx < pb_ba[lev].size(); boxIdx++) {
409  amrex::Box pbx = amrex::convert(pb_ba[lev][boxIdx], m_ixtype);
410  if (pt_type[lev] == 3) { pbx.setBig(2, pbx.bigEnd(2) - 1); } // prevent double counting after converting to k-faces
411  amrex::Box ubx = pbx & vbx;
412  if (ubx.ok()) {
413  if (comp == -1) { // vertical velocity perturbations
414  ParallelFor(ubx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
415  src_arr(i,j,k) += pert_cell(i,j,k);
416  });
417  } else {
418  ParallelFor(ubx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept {
419  src_arr(i,j,k,comp) += pert_cell(i,j,k);
420 
421  // For box region debug only
422  #ifdef INDEX_PERTURB
423  src_arr(i,j,k,comp) = (amrex::Real) (boxIdx + 5.);
424  #endif
425  });
426  }
427  }
428  }
429  }
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::BoxArray > pb_ba
Perturbation-box BoxArray for each AMR level.
Definition: ERF_TurbPertStruct.H:749
amrex::Vector< int > pt_type
Integer perturbation type for each AMR level.
Definition: ERF_TurbPertStruct.H:746

Referenced by make_sources().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calc_tpi_amp()

void TurbulentPerturbation::calc_tpi_amp ( const int &  lev,
const int &  boxIdx,
const double &  interval 
)
inline

Compute the perturbation amplitude for one perturbation box.

Parameters
levAMR level index.
boxIdxPerturbation-box index on the level.
intervalCurrent perturbation update interval [s].
440  {
441  pb_amp[lev][boxIdx] = zero; // Safety step
442  if (pt_type[lev] == 2) { // CPM
443  amrex::Real cp = 1004; // specific heat of air [J/(kg K)]
444  amrex::Real Ec = amrex::Real(0.2); // Eckert number
445  pb_amp[lev][boxIdx] = (input_Ug * input_Ug) / (Ec * cp);
446  } else if (pt_type[lev] == 3) {
447  pb_amp[lev][boxIdx] = input_w_amp;
448  } else { // box perturbation
449  amrex::Real Um = pb_mag[lev][boxIdx];
450  amrex::Real beta = one/tpi_Tinf; // Thermal expansion coefficient
451 
452  // Pseudo Random temperature the ignores scale when mechanically tripping turbulence
454  // get total refinement ratio on each level
455  int total_ref_ratio = 1;
456  for (int level = lev; level >= 1; level--) {
457  total_ref_ratio *= ref_ratio[level-1][2];
458  }
459  // calculation needs to be scale-aware since the formulation relies on the physical size of the box
460  if (tpi_Ti > zero) g = (tpi_nonDim * Um * Um) / (tpi_Ti * tpi_Hpb[lev]) * 1 / total_ref_ratio;
461 
462  // Ma and Senocak (2023) Eq. 8, solving for delta phi
463  pb_amp[lev][boxIdx] = (tpi_nonDim * Um * Um) / (g * beta * tpi_Hpb[lev]) * 1 / total_ref_ratio;
464 
465  if (pt_type[lev] == 0) {
466  // Performing this step converts the perturbation proportionality into
467  // the forcing term
468  // Ma & Senocak (2023) Eq. 7
469  pb_amp[lev][boxIdx] /= static_cast<amrex::Real>(interval);
470  }
471  }
472  }
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:64
amrex::Real beta
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:10
real(c_double), parameter g
Definition: ERF_module_model_constants.F90:19
real(c_double), parameter cp
Definition: ERF_module_model_constants.F90:22
amrex::Real tpi_Tinf
Reference temperature used by the perturbation formulation [K].
Definition: ERF_TurbPertStruct.H:769
amrex::Real input_w_amp
Input vertical velocity perturbation amplitude.
Definition: ERF_TurbPertStruct.H:782
amrex::Vector< amrex::Vector< amrex::Real > > pb_mag
Mean velocity magnitude for each perturbation box [m/s].
Definition: ERF_TurbPertStruct.H:750
amrex::Real input_Ug
Input geostrophic wind speed used to scale CPM perturbations.
Definition: ERF_TurbPertStruct.H:781
amrex::Vector< amrex::IntVect > ref_ratio
Refinement ratios used by multilevel perturbation scaling.
Definition: ERF_TurbPertStruct.H:780
amrex::Real tpi_Ti
Temperature intensity used by the perturbation formulation.
Definition: ERF_TurbPertStruct.H:768
amrex::Vector< amrex::Vector< amrex::Real > > pb_amp
Perturbation amplitude for each perturbation box.
Definition: ERF_TurbPertStruct.H:789
amrex::Real tpi_nonDim
Nondimensional number used by the perturbation formulation.
Definition: ERF_TurbPertStruct.H:767
amrex::Vector< amrex::Real > tpi_Hpb
Perturbation-box height for each AMR level [m].
Definition: ERF_TurbPertStruct.H:772

Referenced by calc_tpi_update().

Here is the caller graph for this function:

◆ calc_tpi_meanMag_perBox()

void TurbulentPerturbation::calc_tpi_meanMag_perBox ( const int &  boxIdx,
const int &  lev,
amrex::MultiFab &  mf_cons,
amrex::MultiFab &  mf_xvel,
amrex::MultiFab &  mf_yvel 
)
inline

Compute mean horizontal velocity magnitude and direction for one perturbation box.

Parameters
boxIdxPerturbation-box index on the level.
levAMR level index.
mf_consConserved state used for iteration layout.
mf_xvelX-velocity field.
mf_yvelY-velocity field.
610  {
611  // Creating local copy of PB box array and magnitude
612  const amrex::BoxArray m_pb_ba = pb_ba[lev];
613  amrex::Real* m_pb_mag = pb_mag[lev].data();
614  amrex::Real* m_pb_dir = pb_dir[lev].data();
615  m_pb_mag[boxIdx] = zero; // Safety step
616  m_pb_dir[boxIdx] = zero; // Safety step
617 
618  // Storage of averages per PB
619  // Index: 0=u (vol/slab_lo), 1=v (vol/slab_lo)
620  // 2=u (slab_hi), 3=v (slab_hi)
621  int n_avg = 4;
622  amrex::Vector<amrex::Real> avg_h(n_avg,zero);
623  amrex::Gpu::DeviceVector<amrex::Real> avg_d(n_avg,zero);
624  amrex::Real* avg = avg_d.data();
625 
626  // Averaging u & v components in single MFIter
627  for (amrex::MFIter mfi(mf_cons, TileNoZ()); mfi.isValid(); ++mfi) {
628 
629  // CC valid box (inherited from mf_cons)
630  const amrex::Box& vbx = mfi.validbox();
631 
632  // Box logic for u velocity
633  auto ixtype_u = mf_xvel.boxArray().ixType();
634  amrex::Box vbx_u = amrex::convert(vbx,ixtype_u);
635  amrex::Box pbx_u = amrex::convert(m_pb_ba[boxIdx], ixtype_u);
636  amrex::Box ubx_u = pbx_u & vbx_u;
637 
638  // Box logic for v velocity
639  auto ixtype_v = mf_yvel.boxArray().ixType();
640  amrex::Box vbx_v = amrex::convert(vbx,ixtype_v);
641  amrex::Box pbx_v = amrex::convert(m_pb_ba[boxIdx], ixtype_v);
642  amrex::Box ubx_v = pbx_v & vbx_v;
643 
644  // Operation over box union (U)
645  if (ubx_u.ok()) {
646  const amrex::Array4<const amrex::Real>& xvel_arry = mf_xvel.const_array(mfi);
647 
648  #ifdef USE_VOLUME_AVERAGE
649  amrex::Real norm = one / static_cast<amrex::Real>(ubx_u.numPts());
650  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubx_u, [=]
651  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
652  amrex::Gpu::deviceReduceSum(&avg[0], xvel_arry(i,j,k)*norm, handler);
653  });
654  #endif // USE_VOLUME_AVERAGE
655 
656  #ifdef USE_SLAB_AVERAGE
657  amrex::Box ubxSlab_lo = makeSlab(ubx_u,2,ubx_u.smallEnd(2));
658  amrex::Box ubxSlab_hi = makeSlab(ubx_u,2,ubx_u.bigEnd(2));
659  amrex::Real norm_lo = one / static_cast<amrex::Real>(ubxSlab_lo.numPts());
660  amrex::Real norm_hi = one / static_cast<amrex::Real>(ubxSlab_hi.numPts());
661 
662  // Average u in the low slab
663  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubxSlab_lo, [=]
664  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
665  amrex::Gpu::deviceReduceSum(&avg[0], xvel_arry(i,j,k)*norm_lo, handler);
666  });
667 
668  // Average u in the high slab
669  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubxSlab_hi, [=]
670  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
671  amrex::Gpu::deviceReduceSum(&avg[2], xvel_arry(i,j,k)*norm_hi, handler);
672  });
673  #endif // USE_SLAB_AVERAGE
674  } // if
675 
676  // Operation over box union (V)
677  if (ubx_v.ok()) {
678  const amrex::Array4<const amrex::Real>& yvel_arry = mf_yvel.const_array(mfi);
679 
680  #ifdef USE_VOLUME_AVERAGE
681  amrex::Real norm = one / static_cast<amrex::Real>(ubx_v.numPts());
682  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubx_v, [=]
683  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
684  amrex::Gpu::deviceReduceSum(&avg[1], yvel_arry(i,j,k)*norm, handler);
685  });
686  #endif // USE_VOLUME_AVERAGE
687 
688  #ifdef USE_SLAB_AVERAGE
689  amrex::Box ubxSlab_lo = makeSlab(ubx_v,2,ubx_v.smallEnd(2));
690  amrex::Box ubxSlab_hi = makeSlab(ubx_v,2,ubx_v.bigEnd(2));
691  amrex::Real norm_lo = one / static_cast<amrex::Real>(ubxSlab_lo.numPts());
692  amrex::Real norm_hi = one / static_cast<amrex::Real>(ubxSlab_hi.numPts());
693 
694  // Average v in the low slab
695  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubxSlab_lo, [=]
696  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
697  amrex::Gpu::deviceReduceSum(&avg[1], yvel_arry(i,j,k)*norm_lo, handler);
698  });
699 
700  // Average v in the high slab
701  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubxSlab_hi, [=]
702  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
703  amrex::Gpu::deviceReduceSum(&avg[3], yvel_arry(i,j,k)*norm_hi, handler);
704  });
705  #endif // USE_SLAB_AVERAGE
706  } // if
707  } // MFIter
708 
709  // Copy from device back to host
710  amrex::Gpu::copy(amrex::Gpu::deviceToHost, avg_d.begin(), avg_d.end(), avg_h.begin());
711 
712  // Computing the average magnitude within PB
713  #ifdef USE_VOLUME_AVERAGE
714  m_pb_mag[boxIdx] = std::sqrt(avg_h[0]*avg_h[0] + avg_h[1]*avg_h[1]);
715  m_pb_dir[boxIdx] = std::atan(std::abs(avg_h[0]) / std::abs(avg_h[1]+std::numeric_limits<amrex::Real>::epsilon()));
716  #endif
717 
718  #ifdef USE_SLAB_AVERAGE
719  m_pb_mag[boxIdx] = myhalf*( std::sqrt(avg_h[0]*avg_h[0] + avg_h[1]*avg_h[1])
720  + std::sqrt(avg_h[2]*avg_h[2] + avg_h[3]*avg_h[3]));
721  m_pb_dir[boxIdx] = std::atan(std::abs(myhalf*(avg_h[0]+avg_h[2])) / std::abs(myhalf*(avg_h[1]+avg_h[3])+std::numeric_limits<amrex::Real>::epsilon()));
722  #endif
723  }
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
amrex::Vector< amrex::Vector< amrex::Real > > pb_dir
Mean velocity direction for each perturbation box.
Definition: ERF_TurbPertStruct.H:751

Referenced by calc_tpi_update().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calc_tpi_update()

void TurbulentPerturbation::calc_tpi_update ( const int  lev,
const double  dt,
amrex::MultiFab &  mf_xvel,
amrex::MultiFab &  mf_yvel,
amrex::MultiFab &  mf_cons 
)
inline

Update perturbation amplitudes and intervals when each box is ready.

Parameters
levAMR level index.
dtTime step for elapsed-time accumulation.
mf_xvelX-velocity field used to compute box mean velocities.
mf_yvelY-velocity field used to compute box mean velocities.
mf_consConserved state used for iteration layout.
297  {
298  // Resetting the net buoyant force value
300 
301  // Setting random number generator for update interval
302  srand( (unsigned) time(NULL) );
303 
304  auto m_ixtype = mf_cons.boxArray().ixType(); // safety step
305  if (pt_type[lev] == 3) { m_ixtype = amrex::IndexType(amrex::IntVect(0,0,1)); }
306 
307  // Seed the random generator at 1024UL for regression testing
308  int fix_random_seed = 0;
309  amrex::ParmParse pp("erf");
310  pp.query("fix_random_seed", fix_random_seed);
311  if (fix_random_seed) {
312  // We need this one for the ParalleForRNG used in calc_tpi
313  amrex::InitRandom(1024UL, amrex::ParallelDescriptor::NProcs(), 1024UL);
314 
315  // We need this one for the RandomReal below
316  srand(1024UL);
317  }
318 
319  for (int boxIdx = 0; boxIdx < pb_ba[lev].size(); boxIdx++) {
320 
321  bool update_box = true; // initialize flag
322  // Check if the local elapsed time is greater than the update interval and don't go into boxes the rank doesn't own
323  if (pt_type[lev] == 2 || pt_type[lev] == 3) {
324  // for CPM, perturbation boxes/cells refresh after boxes have advected box width/length * num_layers (advective time scale)
325  update_box = ((pb_local_etime[lev][boxIdx] >= pb_interval[lev][boxIdx]*tpi_layers) && pb_local_etime[lev][boxIdx] != -one);
326  } else {
327  update_box = ( pb_local_etime[lev][boxIdx] >= pb_interval[lev][boxIdx] && pb_local_etime[lev][boxIdx] != -one );
328  }
329  if ( update_box ) {
330 
331  // Compute mean velocity of each perturbation box
332  calc_tpi_meanMag_perBox(boxIdx, lev, mf_cons, mf_xvel, mf_yvel);
333 
334  // Only the rank owning the box will be able to access the storage location
335  // Done for parallelism to avoid Inf being stored in array
336  if (pb_mag[lev][boxIdx] !=zero) {
337  double interval = 0.0;
338  if (pt_type[lev] == 2 || pt_type[lev] == 3) {
339  // Wind direction correction for angled wind
340  amrex::Real wind_direction = pb_dir[lev][boxIdx];
341  if (wind_direction > PI / 4) { wind_direction = PI / 2 - wind_direction; }
342  // CPM only cares about the side length of a box, min call maintains flexibility.
343  interval = one / std::cos(wind_direction) * std::min(tpi_Lpb[lev], tpi_Wpb[lev]) / pb_mag[lev][boxIdx];
344  } else {
345  interval = tpi_lref[lev] / pb_mag[lev][boxIdx];
346  }
347  pb_interval[lev][boxIdx] = RandomReal(static_cast<amrex::Real>(0.9*interval),
348  static_cast<amrex::Real>(1.1*interval)); // 10% variation
349 
350  // Reset local elapsed time
351  pb_local_etime[lev][boxIdx] = zero;
352  } else {
353  // this box is not on this rank, we shouldn't enter it again.
354  // Technically, all boxes are looped through on the very first step of a simulation and this is when this is set
355  pb_local_etime[lev][boxIdx] = -one;
356  }
357 
358  // Trigger amplitude calculation per perturbation box
359  calc_tpi_amp(lev, boxIdx, pb_interval[lev][boxIdx]);
360 
361  // Trigger random amplitude storage per cell within perturbation box
362  pseudoRandomPert(boxIdx, lev, m_ixtype);
363 
364  } else {
365  // set perturbation amplitudes to 0 for CPM. A little inefficient but leverages as much as existing code as possible.
366  if (pt_type[lev] == 2 || pt_type[lev] == 3) { zero_amp(boxIdx, lev, m_ixtype); }
367 
368  // Increase by timestep of level 0 (but only if the box is owned by this rank)
369  if (pb_local_etime[lev][boxIdx] != -one) { pb_local_etime[lev][boxIdx] += dt; }
370  } // if
371 
372  if (pt_type[lev] < 2) { // box perturbation method only
373  // Per iteration operation of net-zero buoyant force check
374  if (pb_mag[lev][boxIdx] !=zero) netZeroBuoyantAdd(boxIdx, lev);
375  tpi_net_buoyant += pb_netZero[lev][boxIdx];
376  }
377  } // for
378 
379  if (pt_type[lev] < 2) { // box perturbation method only
380  // Normalizing the adjustment based on how many boxes there are
381  // the values within the array is already normalized by the number
382  // of cells within each box
384 
385  // Per iteration operation of net-zero buoyant force adjustment
386  for (int boxIdx = 0; boxIdx < pb_ba[lev].size(); boxIdx++) {
387  if (pb_mag[lev][boxIdx] !=zero) netZeroBuoyantAdjust(boxIdx, lev);
388  }
389  }
390  }
constexpr amrex::Real PI
Definition: ERF_Constants.H:42
ParmParse pp("prob")
int tpi_layers
Number of layers of perturbation boxes.
Definition: ERF_TurbPertStruct.H:760
amrex::Vector< amrex::Real > tpi_Wpb
Perturbation-box width for each AMR level [m].
Definition: ERF_TurbPertStruct.H:774
void calc_tpi_amp(const int &lev, const int &boxIdx, const double &interval)
Compute the perturbation amplitude for one perturbation box.
Definition: ERF_TurbPertStruct.H:437
void pseudoRandomPert(const int &boxIdx, const int &lev, const amrex::IndexType &m_ixtype)
Assign pseudo-random perturbations to cells in one perturbation box.
Definition: ERF_TurbPertStruct.H:480
amrex::Real tpi_pert_adjust
Per-cell perturbation adjustment used for net-zero buoyancy.
Definition: ERF_TurbPertStruct.H:778
amrex::Vector< amrex::Real > tpi_Lpb
Perturbation-box length for each AMR level [m].
Definition: ERF_TurbPertStruct.H:773
amrex::Vector< amrex::Vector< amrex::Real > > pb_netZero
Per-box storage used for net-zero buoyancy calculation.
Definition: ERF_TurbPertStruct.H:790
void netZeroBuoyantAdjust(const int &boxIdx, const int &lev)
Adjust perturbation cells so the net buoyant forcing is zero.
Definition: ERF_TurbPertStruct.H:575
amrex::Real tpi_net_buoyant
Accumulated net buoyant perturbation used for correction.
Definition: ERF_TurbPertStruct.H:777
amrex::Vector< amrex::Vector< double > > pb_interval
Perturbation update interval for each box [s].
Definition: ERF_TurbPertStruct.H:787
amrex::Vector< amrex::Vector< double > > pb_local_etime
Local elapsed time for each perturbation box [s].
Definition: ERF_TurbPertStruct.H:788
amrex::Vector< amrex::Real > tpi_lref
Perturbation-box reference length for each AMR level [m].
Definition: ERF_TurbPertStruct.H:775
void zero_amp(const int &boxIdx, const int &lev, const amrex::IndexType &m_ixtype)
Reset CPM perturbation amplitudes in one perturbation box to zero.
Definition: ERF_TurbPertStruct.H:514
void calc_tpi_meanMag_perBox(const int &boxIdx, const int &lev, amrex::MultiFab &mf_cons, amrex::MultiFab &mf_xvel, amrex::MultiFab &mf_yvel)
Compute mean horizontal velocity magnitude and direction for one perturbation box.
Definition: ERF_TurbPertStruct.H:604
void netZeroBuoyantAdd(const int &boxIdx, const int &lev)
Accumulate the mean perturbation contribution for net-zero buoyancy enforcement.
Definition: ERF_TurbPertStruct.H:538
amrex::Real RandomReal(const amrex::Real min, const amrex::Real max)
Return a pseudo-random real value in a closed interval.
Definition: ERF_TurbPertStruct.H:798
Here is the call graph for this function:

◆ debug()

void TurbulentPerturbation::debug ( double  )
inline

Write perturbation debug information when debug output is enabled.

729  {
730  /*
731  amrex::PrintToFile("BoxPerturbationOutput") << "#################### PB output at time = "
732  << time << " ####################\n";
733  amrex::PrintToFile("BoxPerturbationOutput") << " Using type: " << pt_type << "\n";
734  amrex::PrintToFile("BoxPerturbationOutput") << " Net: " << tpi_net_buoyant << " Adjust : " << tpi_pert_adjust << "\n";
735  for (int i = 0; i < pb_mag.size(); i++) {
736  amrex::PrintToFile("BoxPerturbationOutput") << "[" << i
737  << "] pb_Umag=" << pb_mag[i]
738  << " | pb_interval=" << pb_interval[i]
739  << " (" << pb_local_etime[i]
740  << ") | pb_amp=" << pb_amp[i] << "\n";
741  }
742  amrex::PrintToFile("BoxPerturbationOutput") << "\n";
743  */
744  }

◆ init_tpi()

void TurbulentPerturbation::init_tpi ( const int  lev,
const amrex::Vector< amrex::BoxArray > &  subdomains_lev,
const amrex::GpuArray< amrex::Real, 3 >  dx,
const amrex::BoxArray &  ba,
const amrex::DistributionMapping &  dm,
const int  ngrow_state,
std::string  pp_prefix,
const amrex::Vector< amrex::IntVect >  refRatio,
const int  max_level 
)
inline

Initialize turbulent perturbation regions and per-box storage.

Parameters
levAMR level index.
subdomains_levRectangular level subdomains used to define perturbation regions.
dxCell spacing for this level.
baState BoxArray used for perturbation-cell storage.
dmDistributionMapping for perturbation-cell storage.
ngrow_stateNumber of ghost cells for perturbation-cell storage.
pp_prefixParmParse prefix for the ERF input namespace.
refRatioRefinement ratios between AMR levels.
max_levelMaximum AMR level configured for the run.
83  {
84  ref_ratio = refRatio;
85 
86  amrex::ParmParse pp(pp_prefix);
87 
88  // Reading inputs, and placing assertion for the perturbation inflow to work
89  pp.getarr("perturbation_box_dims",tpi_boxDim);
90  pp.getarr("perturbation_direction",tpi_direction);
91  pp.get("perturbation_layers",tpi_layers);
92  pp.get("perturbation_offset",tpi_offset);
93 
94  tpi_nonDim = zero;
95  pp.query("perturbation_nondimensional",tpi_nonDim);
96 
97  tpi_Tinf = amrex::Real(300.);
98  pp.query("perturbation_T_infinity",tpi_Tinf);
99 
100  tpi_Ti = zero;
101  pp.query("perturbation_T_intensity",tpi_Ti);
102 
103  input_Ug = zero;
104  pp.query("perturbation_Ug",input_Ug);
105 
106  input_w_amp = zero;
107  pp.query("perturbation_w_amp",input_w_amp);
108 
109  perturbation_klo = 0;
110  bool have_klo = pp.query("perturbation_klo", perturbation_klo);
111 
112  perturbation_khi = 0;
113  bool have_khi = pp.query("perturbation_khi", perturbation_khi);
114 
115  // Check variables message
116  if (tpi_offset < 0) { amrex::Abort("Please provide a valid inflow cell offset value for perturbation region (ie. 0-5)"); }
117  if (tpi_layers < 0) { amrex::Abort("Please provide a valid perturbation layer value (ie. 3-5)"); }
118  if (tpi_nonDim < zero) { amrex::Abort("Please provide a valid nondimensional number (ie. Ri = amrex::Real(0.042))"); }
119  for (int i = 0; i < tpi_boxDim.size(); i++) {
120  if (tpi_boxDim[i] < 3) { amrex::Abort("Please provide valid dimensions for perturbation boxes."); }
121  }
122  if (input_Ug < zero) { amrex::Abort("Please provide a valid geostrophic wind speed (ie. Ug = amrex::Real(10.0) m/s)"); }
123  if (tpi_Tinf < zero) { amrex::Abort("Please provide a valid ambient temperature value (ie. T_0 = T_infty)"); }
124  if (tpi_Ti < zero) { amrex::Abort("Please provide a valid temperature intensity value (ie. 0-one)"); }
125 
126  // Create a temporary box list to accumulate all the perturbation regions after box modification
127  amrex::BoxList tmp_bl;
128 
129  // boxSize for individual boxes
130  amrex::IntVect boxSize(tpi_boxDim[0],tpi_boxDim[1],tpi_boxDim[2]);
131 
132  if (tpi_direction[2] || tpi_direction[5]) { amrex::Abort("Currently not supporting z-direction flow perturbation"); }
133 
134  for (int isub = 0; isub < subdomains_lev.size(); ++isub) {
135  const amrex::BoxArray& subdomain = subdomains_lev[isub];
136  amrex::Box subdomain_box(subdomain.minimalBox());
137 
138  if (subdomain_box.numPts() != subdomain.numPts()) {
139  amrex::Abort("Turbulent perturbations require rectangular subdomains. "
140  "Level " + std::to_string(lev) +
141  ", subdomain " + std::to_string(isub) +
142  " is not a rectangular region fully covered by grids.");
143  }
144 
145  const amrex::IntVect& valid_box_lo = subdomain_box.smallEnd();
146  const amrex::IntVect& valid_box_hi = subdomain_box.bigEnd();
147 
148  // default perturbation region to be the entire z extent if the user does not specify bounds
149  if (!have_klo) { perturbation_klo = valid_box_lo[2]; }
150  if (!have_khi) { perturbation_khi = valid_box_hi[2]; }
151 
152  // Creating perturbation regions and initializing with generic size.
153  amrex::Box lo_x_bx(amrex::IntVect(0), amrex::IntVect(1), amrex::IntVect(0));
154  amrex::Box hi_x_bx(amrex::IntVect(0), amrex::IntVect(1), amrex::IntVect(0));
155  amrex::Box lo_y_bx(amrex::IntVect(0), amrex::IntVect(1), amrex::IntVect(0));
156  amrex::Box hi_y_bx(amrex::IntVect(0), amrex::IntVect(1), amrex::IntVect(0));
157 
158  // Starting logic to set the size of the perturbation region(s)
159  //amrex::PrintToFile("BoxPerturbationOutput") << "Setting perturbation region in:";
160  // ***** X-direction perturbation *****
161  if (tpi_direction[0]) { // West
162  lo_x_bx.setSmall(amrex::IntVect(valid_box_lo[0]+tpi_offset, valid_box_lo[1]+tpi_direction[1]*tpi_offset, perturbation_klo));
163  lo_x_bx.setBig (amrex::IntVect(valid_box_lo[0]+(tpi_layers*tpi_boxDim[0]-1)+tpi_offset, valid_box_hi[1]-(tpi_direction[4]*tpi_offset), perturbation_khi));
164  amrex::PrintToFile("BoxPerturbationOutput") << " West face";
165  }
166 
167  if (tpi_direction[3]) { // East
168  hi_x_bx.setSmall(amrex::IntVect(valid_box_hi[0]-((tpi_layers*tpi_boxDim[0]-1)+tpi_offset), valid_box_lo[1]+tpi_direction[1]*tpi_offset, perturbation_klo));
169  hi_x_bx.setBig(amrex::IntVect(valid_box_hi[0]-tpi_offset, valid_box_hi[1]-(tpi_direction[4]*tpi_offset), perturbation_khi));
170  amrex::PrintToFile("BoxPerturbationOutput") << " East face";
171  }
172 
173  // ***** Y-direction Perturbation *****
174  if (tpi_direction[1]) { // North
175  lo_y_bx.setSmall(amrex::IntVect(valid_box_lo[0]+tpi_direction[0]*tpi_offset, valid_box_lo[1]+tpi_offset, perturbation_klo));
176  lo_y_bx.setBig(amrex::IntVect(valid_box_hi[0]-tpi_direction[3]*tpi_offset, valid_box_lo[1]+((tpi_layers*tpi_boxDim[1])-1)+tpi_offset, perturbation_khi));
177  amrex::PrintToFile("BoxPerturbationOutput") << " North face";
178  }
179 
180  if (tpi_direction[4]) { // South
181  hi_y_bx.setSmall(amrex::IntVect(valid_box_lo[0]+tpi_direction[0]*tpi_offset, valid_box_hi[1]-((tpi_layers*tpi_boxDim[1]-1)+tpi_offset), perturbation_klo));
182  hi_y_bx.setBig(amrex::IntVect(valid_box_hi[0]-tpi_direction[3]*tpi_offset, valid_box_hi[1]-tpi_offset, perturbation_khi));
183  amrex::PrintToFile("BoxPerturbationOutput") << " South face";
184  }
185 
186  // Performing box union for intersecting perturbation regions to avoid overlapping sections (double counting at corners)
187  if (tpi_direction[0] && tpi_direction[1]) { // Reshaping South smallEnd
188  amrex::Box lo_x_lo_y_u = lo_x_bx & lo_y_bx;
189  lo_y_bx.setSmall(amrex::IntVect(lo_x_lo_y_u.bigEnd(0)+1, lo_x_lo_y_u.smallEnd(1), lo_x_lo_y_u.smallEnd(2)));
190  }
191 
192  if (tpi_direction[3] && tpi_direction[1]) { // Reshaping South bigEnd
193  amrex::Box hi_x_lo_y_u = hi_x_bx & lo_y_bx;
194  lo_y_bx.setBig(amrex::IntVect(hi_x_lo_y_u.smallEnd(0)-1, hi_x_lo_y_u.bigEnd(1), hi_x_lo_y_u.bigEnd(2)));
195  }
196 
197  if (tpi_direction[0] && tpi_direction[4]) { // Reshaping North smallEnd
198  amrex::Box lo_x_hi_y_u = lo_x_bx & hi_y_bx;
199  hi_y_bx.setSmall(amrex::IntVect(lo_x_hi_y_u.bigEnd(0)+1, lo_x_hi_y_u.smallEnd(1), lo_x_hi_y_u.smallEnd(2)));
200  }
201 
202  if (tpi_direction[3] && tpi_direction[4]) { // Reshaping North bigEnd
203  amrex::Box hi_x_hi_y_u = hi_x_bx & hi_y_bx;
204  hi_y_bx.setBig(amrex::IntVect(hi_x_hi_y_u.smallEnd(0)-1, hi_x_hi_y_u.bigEnd(1), hi_x_hi_y_u.bigEnd(2)));
205  }
206 
207  // Creating structure box array for conserved quantity
208  if (tpi_direction[0]) { tmp_bl.push_back(lo_x_bx); }
209  if (tpi_direction[1]) { tmp_bl.push_back(lo_y_bx); }
210  if (tpi_direction[3]) { tmp_bl.push_back(hi_x_bx); }
211  if (tpi_direction[4]) { tmp_bl.push_back(hi_y_bx); }
212  }
213 
214  //amrex::PrintToFile("BoxPerturbationOutput") << "\nBoxList: " << tmp_bl << "\n";
215  amrex::BoxArray tmp_ba(tmp_bl);
216  tmp_ba.maxSize(boxSize);
217 
218  const int num_levels = max_level + 1;
219  if (pb_ba.size() < num_levels) {
220  pb_ba.resize(num_levels);
221  pb_mag.resize(num_levels);
222  pb_dir.resize(num_levels);
223  pb_netZero.resize(num_levels);
224  pb_interval.resize(num_levels);
225  pb_local_etime.resize(num_levels);
226  pb_amp.resize(num_levels);
227  pb_cell.resize(num_levels);
228  tpi_Lpb.resize(num_levels);
229  tpi_Wpb.resize(num_levels);
230  tpi_Hpb.resize(num_levels);
231  tpi_lref.resize(num_levels);
232  }
233 
234  pb_ba[lev] = tmp_ba;
235 
236  // Initializing mean magnitude and direction vectors
237  pb_mag[lev].resize(pb_ba[lev].size(), zero);
238  pb_dir[lev].resize(pb_ba[lev].size(), zero);
239  pb_netZero[lev].resize(pb_ba[lev].size(), zero);
240 
241  // Set size of vector and initialize
242  pb_interval[lev].resize(pb_ba[lev].size(), -one);
243  pb_local_etime[lev].resize(pb_ba[lev].size(), zero);
244  pb_amp[lev].resize(pb_ba[lev].size(), zero);
245 
246  // Creating data array for perturbation amplitude storage
247  if (pt_type[lev] == 3) { // CPM_W converts to the k-face ba.
248  pb_cell[lev].define(convert(ba, amrex::IntVect(0,0,1)), dm, 1, ngrow_state);
249  } else {
250  pb_cell[lev].define(ba, dm, 1, ngrow_state); // this is the only place ba is used. Maybe we can print here to determine what's valid...
251  }
252  pb_cell[lev].setVal(0.);
253 
254  // Computing perturbation reference length
255  tpi_Lpb[lev] = tpi_boxDim[0]*dx[0];
256  tpi_Wpb[lev] = tpi_boxDim[1]*dx[1];
257  tpi_Hpb[lev] = tpi_boxDim[2]*dx[2];
258  tpi_lref[lev] = std::sqrt(tpi_Lpb[lev]*tpi_Lpb[lev] + tpi_Wpb[lev]*tpi_Wpb[lev]);
259 
262 
263  /*
264  // Function check point message
265  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_box_dims: "
266  << tpi_boxDim[0] << " "
267  << tpi_boxDim[1] << " "
268  << tpi_boxDim[2] << "\n";
269  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_direction: "
270  << tpi_direction[0] << " "
271  << tpi_direction[1] << " "
272  << tpi_direction[2] << "\n\n";
273  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_layers: " << tpi_layers << "\n";
274  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_offset: " << tpi_offset << "\n\n";
275  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_nondimensional: " << tpi_nonDim << "\n";
276  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_T_infinity: " << tpi_Tinf << "\n";
277  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_T_intensity: " << tpi_Ti << "\n";
278  amrex::PrintToFile("BoxPerturbationOutput") << "Reference length per box = " << tpi_lref[lev] << "\n\n";
279  amrex::PrintToFile("BoxPerturbationOutput") << "Turbulent perturbation BoxArray:\n" << pb_ba[lev] << "\n";
280  */
281  }
const Real dx
Definition: ERF_InitCustomPert_ABL.H:23
integer, private isub
Definition: ERF_module_mp_morr_two_moment.F90:164
amrex::Vector< int > tpi_direction
Boundary directions where perturbations are applied.
Definition: ERF_TurbPertStruct.H:764
int perturbation_klo
Lower vertical index bound for perturbations.
Definition: ERF_TurbPertStruct.H:783
int tpi_offset
Cell offset for the start of the perturbation region.
Definition: ERF_TurbPertStruct.H:761
amrex::Vector< int > tpi_boxDim
Dimensions of each perturbation box.
Definition: ERF_TurbPertStruct.H:763
amrex::Vector< amrex::MultiFab > pb_cell
Per-cell perturbation amplitude storage.
Definition: ERF_TurbPertStruct.H:755
int perturbation_khi
Upper vertical index bound for perturbations.
Definition: ERF_TurbPertStruct.H:784
Here is the call graph for this function:

◆ init_tpi_type()

void TurbulentPerturbation::init_tpi_type ( const int  lev,
const PerturbationType &  pert_type,
const int  max_level 
)
inline

Store the integer perturbation-type selector for one AMR level.

Parameters
levAMR level index.
pert_typePerturbation type selected for this level.
max_levelMaximum AMR level configured for the run.
43  {
44  if (pt_type.size() < max_level + 1) {
45  pt_type.resize(max_level + 1, -1);
46  }
47 
48  if (pert_type == PerturbationType::Source) {
49  pt_type[lev] = 0;
50  } else if (pert_type == PerturbationType::Direct) {
51  pt_type[lev] = 1;
52  } else if (pert_type == PerturbationType::CPM) {
53  pt_type[lev] = 2;
54  } else if (pert_type == PerturbationType::CPM_W) {
55  pt_type[lev] = 3;
56  } else {
57  pt_type[lev] = -1;
58  }
59  }

◆ netZeroBuoyantAdd()

void TurbulentPerturbation::netZeroBuoyantAdd ( const int &  boxIdx,
const int &  lev 
)
inline

Accumulate the mean perturbation contribution for net-zero buoyancy enforcement.

Parameters
boxIdxPerturbation-box index on the level.
levAMR level index.
540  {
541  // Creating local copy of PB box array and magnitude
542  const amrex::BoxArray m_pb_ba = pb_ba[lev];
543  amrex::Real* m_pb_netZero = pb_netZero[lev].data();
544 
545  // Create device array for summation
546  amrex::Vector<amrex::Real> avg_h(1,zero);
547  amrex::Gpu::DeviceVector<amrex::Real> avg_d(1,zero);
548  amrex::Real* avg = avg_d.data();
549 
550  // Iterates through the cells of each box and sum the white noise perturbation
551  for (amrex::MFIter mfi(pb_cell[lev], TileNoZ()) ; mfi.isValid(); ++mfi) {
552  const amrex::Box& vbx = mfi.validbox();
553  amrex::Box pbx = amrex::convert(m_pb_ba[boxIdx], vbx.ixType());
554  amrex::Box ubx = pbx & vbx;
555  if (ubx.ok()) {
556  const amrex::Array4<const amrex::Real>& pert_cell = pb_cell[lev].const_array(mfi);
557  amrex::Real norm = one / static_cast<amrex::Real>(ubx.numPts());
558  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubx, [=]
559  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
560  amrex::Gpu::deviceReduceSum(&avg[0], pert_cell(i,j,k)*norm, handler);
561  });
562  amrex::Gpu::copy(amrex::Gpu::deviceToHost, avg_d.begin(), avg_d.end(), avg_h.begin());
563 
564  // Assigning onto storage array
565  m_pb_netZero[boxIdx] = avg_h[0];
566  }
567  }
568  }

Referenced by calc_tpi_update().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ netZeroBuoyantAdjust()

void TurbulentPerturbation::netZeroBuoyantAdjust ( const int &  boxIdx,
const int &  lev 
)
inline

Adjust perturbation cells so the net buoyant forcing is zero.

Parameters
boxIdxPerturbation-box index on the level.
levAMR level index.
577  {
578  // Creating local copy of PB box array and magnitude
579  const amrex::BoxArray m_pb_ba = pb_ba[lev];
580  for (amrex::MFIter mfi(pb_cell[lev], TileNoZ()) ; mfi.isValid(); ++mfi) {
581  const amrex::Box& vbx = mfi.validbox();
582  amrex::Box pbx = amrex::convert(m_pb_ba[boxIdx], vbx.ixType());
583  amrex::Box ubx = pbx & vbx;
584  if (ubx.ok()) {
585  const amrex::Real adjust = tpi_pert_adjust;
586  const amrex::Array4<amrex::Real>& pert_cell = pb_cell[lev].array(mfi);
587  ParallelFor(ubx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
588  pert_cell(i,j,k) -= adjust;
589  });
590  }
591  }
592  }

Referenced by calc_tpi_update().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pseudoRandomPert()

void TurbulentPerturbation::pseudoRandomPert ( const int &  boxIdx,
const int &  lev,
const amrex::IndexType &  m_ixtype 
)
inline

Assign pseudo-random perturbations to cells in one perturbation box.

Parameters
boxIdxPerturbation-box index on the level.
levAMR level index.
m_ixtypeIndex type used to align perturbation storage.
483  {
484  for (amrex::MFIter mfi(pb_cell[lev],TileNoZ()); mfi.isValid(); ++mfi) {
485  amrex::Box vbx = mfi.validbox();
486  amrex::Box pbx = amrex::convert(pb_ba[lev][boxIdx], m_ixtype);
487  if (pt_type[lev] == 3) { pbx.setBig(2, pbx.bigEnd(2) - 1); } // prevent double counting after converting to k-faces
488  amrex::Box ubx = pbx & vbx;
489  if (ubx.ok()) {
490  amrex::Real amp_copy = pb_amp[lev][boxIdx];
491  const amrex::Array4<amrex::Real>& pert_cell = pb_cell[lev].array(mfi);
492 
493  if (pt_type[lev] == 2 || pt_type[lev] == 3) { // CPM
494  amrex::Real rand_number_const = RandomReal(-one, one);
495  ParallelFor(ubx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
496  pert_cell(i,j,k) = rand_number_const * amp_copy;
497  });
498  } else {
499  ParallelForRNG(ubx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine& engine) noexcept {
500  amrex::Real rand_double = amrex::Random(engine);
501  pert_cell(i,j,k) = (rand_double*two - one) * amp_copy;
502  });
503  }
504  }
505  }
506  }
constexpr amrex::Real two
Definition: ERF_Constants.H:10
ParallelForRNG(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine &engine) noexcept { const Real x=prob_lo_x+(i+myhalf) *dx;const Real y=prob_lo_y+(j+myhalf) *dy;const Real z=z_cc(i, j, k);const Real r=std::sqrt((x-xc) *(x-xc)+(y-yc) *(y-yc)+(z-zc) *(z-zc));if((z<=pert_ref_height) &&(T_0_Pert_Mag !=amrex::Real(0))) { Real rand_double=amrex::Random(engine);state_pert(i, j, k, RhoTheta_comp)=(rand_double *amrex::Real(2) - amrex::Real(1)) *T_0_Pert_Mag;if(!pert_rhotheta) { state_pert(i, j, k, RhoTheta_comp) *=r_hse(i, j, k);} } state_pert(i, j, k, RhoScalar_comp)=A_0 *std::exp(-amrex::Real(10.) *r *r);if(state_pert.nComp() > RhoKE_comp) { if(rhoKE_0 > 0) { state_pert(i, j, k, RhoKE_comp)=rhoKE_0;} else { state_pert(i, j, k, RhoKE_comp)=r_hse(i, j, k) *KE_0;} if(KE_decay_height > 0) { state_pert(i, j, k, RhoKE_comp) *=amrex::max(std::pow(1 - amrex::min(z/KE_decay_height, amrex::Real(1)), KE_decay_order), Real(1e-12));} } })

Referenced by calc_tpi_update().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ RandomReal()

amrex::Real TurbulentPerturbation::RandomReal ( const amrex::Real  min,
const amrex::Real  max 
)
inlineprivate

Return a pseudo-random real value in a closed interval.

Parameters
minLower bound of the interval.
maxUpper bound of the interval.
Returns
Pseudo-random value between min and max.
799  {
800  amrex::Real r = (amrex::Real) rand() / (amrex::Real) RAND_MAX;
801  return min + r * (max - min);
802  }

Referenced by calc_tpi_update(), and pseudoRandomPert().

Here is the caller graph for this function:

◆ zero_amp()

void TurbulentPerturbation::zero_amp ( const int &  boxIdx,
const int &  lev,
const amrex::IndexType &  m_ixtype 
)
inline

Reset CPM perturbation amplitudes in one perturbation box to zero.

Parameters
boxIdxPerturbation-box index on the level.
levAMR level index.
m_ixtypeIndex type used to align perturbation storage.
517  {
518 
519  for (amrex::MFIter mfi(pb_cell[lev],TileNoZ()); mfi.isValid(); ++mfi) {
520  amrex::Box vbx = mfi.validbox();
521  amrex::Box pbx = amrex::convert(pb_ba[lev][boxIdx], m_ixtype);
522  if (pt_type[lev] == 3) { pbx.setBig(2, pbx.bigEnd(2) - 1); } // prevent double counting after converting to k-faces
523  amrex::Box ubx = pbx & vbx;
524  if (ubx.ok()) {
525  const amrex::Array4<amrex::Real>& pert_cell = pb_cell[lev].array(mfi);
526  ParallelFor(ubx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
527  pert_cell(i,j,k) = zero;
528  });
529  }
530  }
531  }

Referenced by calc_tpi_update().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ input_Ug

TurbulentPerturbation::input_Ug
private

Input geostrophic wind speed used to scale CPM perturbations.

Referenced by calc_tpi_amp(), and init_tpi().

◆ input_w_amp

TurbulentPerturbation::input_w_amp
private

Input vertical velocity perturbation amplitude.

Referenced by calc_tpi_amp(), and init_tpi().

◆ pb_amp

TurbulentPerturbation::pb_amp
private

Perturbation amplitude for each perturbation box.

Referenced by calc_tpi_amp(), init_tpi(), and pseudoRandomPert().

◆ pb_ba

TurbulentPerturbation::pb_ba

◆ pb_cell

TurbulentPerturbation::pb_cell

Per-cell perturbation amplitude storage.

Referenced by init_tpi(), make_sources(), netZeroBuoyantAdd(), netZeroBuoyantAdjust(), pseudoRandomPert(), and zero_amp().

◆ pb_dir

TurbulentPerturbation::pb_dir

Mean velocity direction for each perturbation box.

Referenced by calc_tpi_meanMag_perBox(), calc_tpi_update(), and init_tpi().

◆ pb_interval

TurbulentPerturbation::pb_interval
private

Perturbation update interval for each box [s].

Referenced by calc_tpi_update(), and init_tpi().

◆ pb_local_etime

TurbulentPerturbation::pb_local_etime
private

Local elapsed time for each perturbation box [s].

Referenced by calc_tpi_update(), and init_tpi().

◆ pb_mag

TurbulentPerturbation::pb_mag

Mean velocity magnitude for each perturbation box [m/s].

Referenced by calc_tpi_amp(), calc_tpi_meanMag_perBox(), calc_tpi_update(), and init_tpi().

◆ pb_netZero

TurbulentPerturbation::pb_netZero
private

Per-box storage used for net-zero buoyancy calculation.

Referenced by calc_tpi_update(), init_tpi(), and netZeroBuoyantAdd().

◆ perturbation_khi

TurbulentPerturbation::perturbation_khi
private

Upper vertical index bound for perturbations.

Referenced by init_tpi().

◆ perturbation_klo

TurbulentPerturbation::perturbation_klo
private

Lower vertical index bound for perturbations.

Referenced by init_tpi().

◆ pt_type

TurbulentPerturbation::pt_type

Integer perturbation type for each AMR level.

Referenced by apply_tpi(), calc_tpi_amp(), calc_tpi_update(), init_tpi(), init_tpi_type(), pseudoRandomPert(), and zero_amp().

◆ ref_ratio

TurbulentPerturbation::ref_ratio
private

Refinement ratios used by multilevel perturbation scaling.

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_boxDim

TurbulentPerturbation::tpi_boxDim
private

Dimensions of each perturbation box.

Referenced by init_tpi().

◆ tpi_direction

TurbulentPerturbation::tpi_direction
private

Boundary directions where perturbations are applied.

Referenced by init_tpi().

◆ tpi_Hpb

TurbulentPerturbation::tpi_Hpb
private

Perturbation-box height for each AMR level [m].

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_layers

TurbulentPerturbation::tpi_layers
private

Number of layers of perturbation boxes.

Referenced by calc_tpi_update(), and init_tpi().

◆ tpi_Lpb

TurbulentPerturbation::tpi_Lpb
private

Perturbation-box length for each AMR level [m].

Referenced by calc_tpi_update(), and init_tpi().

◆ tpi_lref

TurbulentPerturbation::tpi_lref
private

Perturbation-box reference length for each AMR level [m].

Referenced by calc_tpi_update(), and init_tpi().

◆ tpi_net_buoyant

TurbulentPerturbation::tpi_net_buoyant
private

Accumulated net buoyant perturbation used for correction.

Referenced by calc_tpi_update(), and init_tpi().

◆ tpi_nonDim

TurbulentPerturbation::tpi_nonDim
private

Nondimensional number used by the perturbation formulation.

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_offset

TurbulentPerturbation::tpi_offset
private

Cell offset for the start of the perturbation region.

Referenced by init_tpi().

◆ tpi_pert_adjust

TurbulentPerturbation::tpi_pert_adjust
private

Per-cell perturbation adjustment used for net-zero buoyancy.

Referenced by calc_tpi_update(), init_tpi(), and netZeroBuoyantAdjust().

◆ tpi_Ti

TurbulentPerturbation::tpi_Ti
private

Temperature intensity used by the perturbation formulation.

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_Tinf

TurbulentPerturbation::tpi_Tinf
private

Reference temperature used by the perturbation formulation [K].

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_Wpb

TurbulentPerturbation::tpi_Wpb
private

Perturbation-box width for each AMR level [m].

Referenced by calc_tpi_update(), and init_tpi().


The documentation for this struct was generated from the following file: