ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
TurbulentPerturbation Struct Reference

#include <ERF_TurbPertStruct.H>

Collaboration diagram for TurbulentPerturbation:

Public Member Functions

 ~TurbulentPerturbation ()
 
void init_tpi (const int lev, const amrex::IntVect &valid_box_lo, const amrex::IntVect &valid_box_hi, 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)
 
void calc_tpi_update (const int lev, const amrex::Real dt, amrex::MultiFab &mf_xvel, amrex::MultiFab &mf_yvel, amrex::MultiFab &mf_cons)
 
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)
 
void calc_tpi_amp (const int &lev, const int &boxIdx, const amrex::Real &interval)
 
void pseudoRandomPert (const int &boxIdx, const int &lev, const amrex::IndexType &m_ixtype)
 
void netZeroBuoyantAdd (const int &boxIdx, const int &lev)
 
void netZeroBuoyantAdjust (const int &boxIdx, const int &lev)
 
void calc_tpi_meanMag_perBox (const int &boxIdx, const int &lev, amrex::MultiFab &mf_cons, amrex::MultiFab &mf_xvel, amrex::MultiFab &mf_yvel)
 
void debug (amrex::Real)
 

Public Attributes

int pt_type
 
amrex::Vector< amrex::BoxArray > pb_ba
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_mag
 
amrex::Vector< amrex::MultiFab > pb_cell
 

Private Member Functions

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

Private Attributes

int tpi_layers
 
int tpi_offset
 
amrex::Vector< int > tpi_boxDim
 
amrex::Vector< int > tpi_direction
 
amrex::Real tpi_nonDim
 
amrex::Real tpi_Ti
 
amrex::Real tpi_Tinf
 
amrex::Real tpi_Hpb
 
amrex::Real tpi_Lpb
 
amrex::Real tpi_Wpb
 
amrex::Real tpi_lref
 
amrex::Real tpi_net_buoyant
 
amrex::Real tpi_pert_adjust
 
amrex::Vector< amrex::IntVect > ref_ratio
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_interval
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_local_etime
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_amp
 
amrex::Vector< amrex::Vector< amrex::Real > > pb_netZero
 

Detailed Description

Container holding quantities related to turbulent perturbation parameters

Constructor & Destructor Documentation

◆ ~TurbulentPerturbation()

TurbulentPerturbation::~TurbulentPerturbation ( )
inline
22 {}

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
268  {
269  for (int boxIdx = 0; boxIdx < pb_ba[lev].size(); boxIdx++) {
270  amrex::Box pbx = amrex::convert(pb_ba[lev][boxIdx], m_ixtype);
271  amrex::Box ubx = pbx & vbx;
272  if (ubx.ok()) {
273  ParallelFor(ubx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
274  src_arr(i,j,k,comp) += pert_cell(i,j,k);
275 
276  // For box region debug only
277  #ifdef INDEX_PERTURB
278  src_arr(i,j,k,comp) = (amrex::Real) (boxIdx + 5.);
279  #endif
280  });
281  }
282  }
283  }
amrex::Vector< amrex::BoxArray > pb_ba
Definition: ERF_TurbPertStruct.H:549

Referenced by make_sources().

Here is the caller graph for this function:

◆ calc_tpi_amp()

void TurbulentPerturbation::calc_tpi_amp ( const int &  lev,
const int &  boxIdx,
const amrex::Real &  interval 
)
inline
289  {
290  amrex::Real Um = pb_mag[lev][boxIdx];
291  pb_amp[lev][boxIdx] = 0.; // Safety step
292 
293  amrex::Real beta = 1./tpi_Tinf; // Thermal expansion coefficient
294 
295  // Pseudo Random temperature the ignores scale when mechanically tripping turbulence
296  amrex::Real g = CONST_GRAV;
297  // get total refinement ratio on each level
298  int total_ref_ratio = 1;
299  for (int level = lev; level >= 1; level--) {
300  total_ref_ratio *= ref_ratio[level-1][2];
301  }
302  // calculation needs to be scale-aware since the formulation relies on the physical size of the box
303  if (tpi_Ti > 0.) g = (tpi_nonDim * Um * Um) / (tpi_Ti * tpi_Hpb) * 1 / total_ref_ratio;
304 
305  // Ma and Senocak (2023) Eq. 8, solving for delta phi
306  pb_amp[lev][boxIdx] = (tpi_nonDim * Um * Um) / (g * beta * tpi_Hpb) * 1 / total_ref_ratio;
307 
308  if (pt_type == 0) {
309  // Performing this step converts the perturbation proportionality into
310  // the forcing term
311  // Ma & Senocak (2023) Eq. 7
312  pb_amp[lev][boxIdx] /= interval;
313  }
314  }
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:21
amrex::Real tpi_Tinf
Definition: ERF_TurbPertStruct.H:568
amrex::Vector< amrex::IntVect > ref_ratio
Definition: ERF_TurbPertStruct.H:579
amrex::Vector< amrex::Vector< amrex::Real > > pb_mag
Definition: ERF_TurbPertStruct.H:550
amrex::Real tpi_Ti
Definition: ERF_TurbPertStruct.H:567
amrex::Real tpi_nonDim
Definition: ERF_TurbPertStruct.H:566
int pt_type
Definition: ERF_TurbPertStruct.H:546
amrex::Real tpi_Hpb
Definition: ERF_TurbPertStruct.H:571
amrex::Vector< amrex::Vector< amrex::Real > > pb_amp
Definition: ERF_TurbPertStruct.H:584

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
410  {
411  // Creating local copy of PB box array and magnitude
412  const amrex::BoxArray m_pb_ba = pb_ba[lev];
413  amrex::Real* m_pb_mag = pb_mag[lev].data();
414  m_pb_mag[boxIdx] = 0.; // Safety step
415 
416  // Storage of averages per PB
417  // Index: 0=u (vol/slab_lo), 1=v (vol/slab_lo)
418  // 2=u (slab_hi), 3=v (slab_hi)
419  int n_avg = 4;
420  amrex::Vector<amrex::Real> avg_h(n_avg,0.);
421  amrex::Gpu::DeviceVector<amrex::Real> avg_d(n_avg,0.);
422  amrex::Real* avg = avg_d.data();
423 
424  // Averaging u & v components in single MFIter
425  for (amrex::MFIter mfi(mf_cons, TileNoZ()); mfi.isValid(); ++mfi) {
426 
427  // CC valid box (inherited from mf_cons)
428  const amrex::Box& vbx = mfi.validbox();
429 
430  // Box logic for u velocity
431  auto ixtype_u = mf_xvel.boxArray().ixType();
432  amrex::Box vbx_u = amrex::convert(vbx,ixtype_u);
433  amrex::Box pbx_u = amrex::convert(m_pb_ba[boxIdx], ixtype_u);
434  amrex::Box ubx_u = pbx_u & vbx_u;
435 
436  // Box logic for v velocity
437  auto ixtype_v = mf_yvel.boxArray().ixType();
438  amrex::Box vbx_v = amrex::convert(vbx,ixtype_v);
439  amrex::Box pbx_v = amrex::convert(m_pb_ba[boxIdx], ixtype_v);
440  amrex::Box ubx_v = pbx_v & vbx_v;
441 
442  // Operation over box union (U)
443  if (ubx_u.ok()) {
444  const amrex::Array4<const amrex::Real>& xvel_arry = mf_xvel.const_array(mfi);
445 
446  #ifdef USE_VOLUME_AVERAGE
447  int npts = ubx_u.numPts();
448  amrex::Real norm = 1.0 / (amrex::Real) npts;
449  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubx_u, [=]
450  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
451  amrex::Gpu::deviceReduceSum(&avg[0], xvel_arry(i,j,k)*norm, handler);
452  });
453  #endif // USE_VOLUME_AVERAGE
454 
455  #ifdef USE_SLAB_AVERAGE
456  amrex::Box ubxSlab_lo = makeSlab(ubx_u,2,ubx_u.smallEnd(2));
457  amrex::Box ubxSlab_hi = makeSlab(ubx_u,2,ubx_u.bigEnd(2));
458  int npts_lo = ubxSlab_lo.numPts();
459  int npts_hi = ubxSlab_hi.numPts();
460  amrex::Real norm_lo = 1.0 / (amrex::Real) npts_lo;
461  amrex::Real norm_hi = 1.0 / (amrex::Real) npts_hi;
462 
463  // Average u in the low slab
464  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubxSlab_lo, [=]
465  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
466  amrex::Gpu::deviceReduceSum(&avg[0], xvel_arry(i,j,k)*norm_lo, handler);
467  });
468 
469  // Average u in the high slab
470  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubxSlab_hi, [=]
471  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
472  amrex::Gpu::deviceReduceSum(&avg[2], xvel_arry(i,j,k)*norm_hi, handler);
473  });
474  #endif // USE_SLAB_AVERAGE
475  } // if
476 
477  // Operation over box union (V)
478  if (ubx_v.ok()) {
479  const amrex::Array4<const amrex::Real>& yvel_arry = mf_yvel.const_array(mfi);
480 
481  #ifdef USE_VOLUME_AVERAGE
482  int npts = ubx_v.numPts();
483  amrex::Real norm = 1.0 / (amrex::Real) npts;
484  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubx_v, [=]
485  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
486  amrex::Gpu::deviceReduceSum(&avg[1], yvel_arry(i,j,k)*norm, handler);
487  });
488  #endif // USE_VOLUME_AVERAGE
489 
490  #ifdef USE_SLAB_AVERAGE
491  amrex::Box ubxSlab_lo = makeSlab(ubx_v,2,ubx_v.smallEnd(2));
492  amrex::Box ubxSlab_hi = makeSlab(ubx_v,2,ubx_v.bigEnd(2));
493  int npts_lo = ubxSlab_lo.numPts();
494  int npts_hi = ubxSlab_hi.numPts();
495  amrex::Real norm_lo = 1.0 / (amrex::Real) npts_lo;
496  amrex::Real norm_hi = 1.0 / (amrex::Real) npts_hi;
497 
498  // Average v in the low slab
499  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubxSlab_lo, [=]
500  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
501  amrex::Gpu::deviceReduceSum(&avg[1], yvel_arry(i,j,k)*norm_lo, handler);
502  });
503 
504  // Average v in the high slab
505  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubxSlab_hi, [=]
506  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
507  amrex::Gpu::deviceReduceSum(&avg[3], yvel_arry(i,j,k)*norm_hi, handler);
508  });
509  #endif // USE_SLAB_AVERAGE
510  } // if
511  } // MFIter
512 
513  // Copy from device back to host
514  amrex::Gpu::copy(amrex::Gpu::deviceToHost, avg_d.begin(), avg_d.end(), avg_h.begin());
515 
516  // Computing the average magnitude within PB
517  #ifdef USE_VOLUME_AVERAGE
518  m_pb_mag[boxIdx] = sqrt(avg_h[0]*avg_h[0] + avg_h[1]*avg_h[1]);
519  #endif
520 
521  #ifdef USE_SLAB_AVERAGE
522  m_pb_mag[boxIdx] = 0.5*( sqrt(avg_h[0]*avg_h[0] + avg_h[1]*avg_h[1])
523  + sqrt(avg_h[2]*avg_h[2] + avg_h[3]*avg_h[3]));
524  #endif
525  }
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real avg_h(amrex::Real XXXm, amrex::Real XXXp)
Definition: ERF_EBUtils.H:10

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 amrex::Real  dt,
amrex::MultiFab &  mf_xvel,
amrex::MultiFab &  mf_yvel,
amrex::MultiFab &  mf_cons 
)
inline
206  {
207  // Resettubg the net buoyant force value
208  tpi_net_buoyant = 0.;
209 
210  // Setting random number generator for update interval
211  srand( (unsigned) time(NULL) );
212 
213  auto m_ixtype = mf_cons.boxArray().ixType(); // safety step
214 
215  for (int boxIdx = 0; boxIdx < pb_ba[lev].size(); boxIdx++) {
216 
217  // Check if the local elapsed time is greater than the update interval
218  if ( pb_interval[lev][boxIdx] <= pb_local_etime[lev][boxIdx] ) {
219 
220  // Compute mean velocity of each perturbation box
221  calc_tpi_meanMag_perBox(boxIdx, lev, mf_cons, mf_xvel, mf_yvel);
222 
223  // Only the rank owning the box will be able to access the storage location
224  // Done for parallelism to avoid Inf being stored in array
225  if (pb_mag[lev][boxIdx] !=0.) {
226  amrex::Real interval = tpi_lref / pb_mag[lev][boxIdx];
227  pb_interval[lev][boxIdx] = RandomReal(0.9*interval,1.1*interval); // 10% variation
228  }
229 
230  // Trigger amplitude calculation per perturbation box
231  calc_tpi_amp(lev, boxIdx, pb_interval[lev][boxIdx]);
232 
233  // Trigger random amplitude storage per cell within perturbation box
234  pseudoRandomPert(boxIdx, lev, m_ixtype);
235 
236  // Reset local elapsed time
237  pb_local_etime[lev][boxIdx] = 0.;
238  } else {
239  // Increase by timestep of level 0
240  pb_local_etime[lev][boxIdx] += dt;
241  } // if
242 
243  // Per iteration operation of net-zero buoyant force check
244  if (pb_mag[lev][boxIdx] !=0.) netZeroBuoyantAdd(boxIdx, lev);
245  tpi_net_buoyant += pb_netZero[lev][boxIdx];
246  } // for
247 
248  // Normalizing the adjustment based on how many boxes there are
249  // the values within the array is already normalized by the number
250  // of cells within each box
251  tpi_pert_adjust = tpi_net_buoyant / (amrex::Real) pb_ba[lev].size();
252 
253  // Per iteration operation of net-zero buoyant force adjustment
254  for (int boxIdx = 0; boxIdx < pb_ba[lev].size(); boxIdx++) {
255  if (pb_mag[lev][boxIdx] !=0.) netZeroBuoyantAdjust(boxIdx, lev);
256  }
257  }
void pseudoRandomPert(const int &boxIdx, const int &lev, const amrex::IndexType &m_ixtype)
Definition: ERF_TurbPertStruct.H:319
amrex::Vector< amrex::Vector< amrex::Real > > pb_local_etime
Definition: ERF_TurbPertStruct.H:583
void calc_tpi_amp(const int &lev, const int &boxIdx, const amrex::Real &interval)
Definition: ERF_TurbPertStruct.H:286
void netZeroBuoyantAdjust(const int &boxIdx, const int &lev)
Definition: ERF_TurbPertStruct.H:381
amrex::Vector< amrex::Vector< amrex::Real > > pb_netZero
Definition: ERF_TurbPertStruct.H:585
amrex::Real tpi_pert_adjust
Definition: ERF_TurbPertStruct.H:577
amrex::Vector< amrex::Vector< amrex::Real > > pb_interval
Definition: ERF_TurbPertStruct.H:582
amrex::Real tpi_lref
Definition: ERF_TurbPertStruct.H:574
void calc_tpi_meanMag_perBox(const int &boxIdx, const int &lev, amrex::MultiFab &mf_cons, amrex::MultiFab &mf_xvel, amrex::MultiFab &mf_yvel)
Definition: ERF_TurbPertStruct.H:404
void netZeroBuoyantAdd(const int &boxIdx, const int &lev)
Definition: ERF_TurbPertStruct.H:346
amrex::Real RandomReal(const amrex::Real min, const amrex::Real max)
Definition: ERF_TurbPertStruct.H:588
amrex::Real tpi_net_buoyant
Definition: ERF_TurbPertStruct.H:576
Here is the call graph for this function:

◆ debug()

void TurbulentPerturbation::debug ( amrex::Real  )
inline
529  {
530  /*
531  amrex::PrintToFile("BoxPerturbationOutput") << "#################### PB output at time = "
532  << time << " ####################\n";
533  amrex::PrintToFile("BoxPerturbationOutput") << " Using type: " << pt_type << "\n";
534  amrex::PrintToFile("BoxPerturbationOutput") << " Net: " << tpi_net_buoyant << " Adjust : " << tpi_pert_adjust << "\n";
535  for (int i = 0; i < pb_mag.size(); i++) {
536  amrex::PrintToFile("BoxPerturbationOutput") << "[" << i
537  << "] pb_Umag=" << pb_mag[i]
538  << " | pb_interval=" << pb_interval[i]
539  << " (" << pb_local_etime[i]
540  << ") | pb_amp=" << pb_amp[i] << "\n";
541  }
542  amrex::PrintToFile("BoxPerturbationOutput") << "\n";
543  */
544  }

◆ init_tpi()

void TurbulentPerturbation::init_tpi ( const int  lev,
const amrex::IntVect &  valid_box_lo,
const amrex::IntVect &  valid_box_hi,
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
40  {
41  // Initialization for some 0 dependent terms
42  tpi_Ti = 0.;
43  tpi_Tinf = 300.;
44 
45  ref_ratio = refRatio;
46 
47  amrex::ParmParse pp(pp_prefix);
48 
49  // Reading inputs, and placing assertion for the perturbation inflow to work
50  pp.queryarr("perturbation_box_dims",tpi_boxDim);
51  pp.queryarr("perturbation_direction",tpi_direction);
52  pp.query("perturbation_layers",tpi_layers);
53  pp.query("perturbation_offset",tpi_offset);
54 
55  pp.query("perturbation_nondimensional",tpi_nonDim);
56  pp.query("perturbation_T_infinity",tpi_Tinf);
57  pp.query("perturbation_T_intensity",tpi_Ti);
58 
59  // Check variables message
60  if (tpi_layers < 0) { amrex::Abort("Please provide a valid perturbation layer value (ie. 3-5)"); }
61  if (tpi_offset < 0) { amrex::Abort("Please provide a valid inflow cell offset value for perturbation region (ie. 0-5)"); }
62  for (int i = 0; i < tpi_boxDim.size(); i++) {
63  if (tpi_boxDim[i] == 0) { amrex::Abort("Please provide valid dimensions for perturbation boxes."); }
64  }
65  if (tpi_nonDim < 0.) { amrex::Abort("Please provide a valid nondimensional number (ie. Ri = 0.042)"); }
66  if (tpi_Tinf < 0.) { amrex::Abort("Please provide a valid ambient temperature value (ie. T_0 = T_infty)"); }
67  if (tpi_Ti < 0.) { amrex::Abort("Please provide a valid temperature intensity value (ie. 0-1.0)"); }
68 
69  // Creating perturbation regions and initializing with generic size. Temporary size for now
70  amrex::Box lo_x_bx(amrex::IntVect(0), amrex::IntVect(1), amrex::IntVect(0));
71  amrex::Box hi_x_bx(amrex::IntVect(0), amrex::IntVect(1), amrex::IntVect(0));
72  amrex::Box lo_y_bx(amrex::IntVect(0), amrex::IntVect(1), amrex::IntVect(0));
73  amrex::Box hi_y_bx(amrex::IntVect(0), amrex::IntVect(1), amrex::IntVect(0));
74 
75  // Create a temporary box list to accumulate all the perturbation regions after box modification
76  amrex::BoxList tmp_bl;
77 
78  // boxSize for individual boxes
79  amrex::IntVect boxSize(tpi_boxDim[0],tpi_boxDim[1],tpi_boxDim[2]);
80 
81  // Starting logic to set the size of the perturbation region(s)
82  //amrex::PrintToFile("BoxPerturbationOutput") << "Setting perturbation region in:";
83  // ***** X-direction perturbation *****
84  if (tpi_direction[0]) { // West
85  lo_x_bx.setSmall(amrex::IntVect(valid_box_lo[0]+tpi_offset, valid_box_lo[1]+tpi_direction[1]*tpi_offset, valid_box_lo[2]));
86  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), valid_box_hi[2]));
87  //amrex::PrintToFile("BoxPerturbationOutput") << " West face";
88  }
89 
90  if (tpi_direction[3]) { // East
91  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, valid_box_lo[2]));
92  hi_x_bx.setBig(amrex::IntVect(valid_box_hi[0]-tpi_offset, valid_box_hi[1]-(tpi_direction[4]*tpi_offset), valid_box_hi[2]));
93  //amrex::PrintToFile("BoxPerturbationOutput") << " East face";
94  }
95 
96  // ***** Y-direction Perturbation *****
97  if (tpi_direction[1]) { // North
98  lo_y_bx.setSmall(amrex::IntVect(valid_box_lo[0]+tpi_direction[0]*tpi_offset, valid_box_lo[1]+tpi_offset, valid_box_lo[2]));
99  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, valid_box_hi[2]));
100  //amrex::PrintToFile("BoxPerturbationOutput") << " North face";
101  }
102 
103  if (tpi_direction[4]) { // South
104  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), valid_box_lo[2]));
105  hi_y_bx.setBig(amrex::IntVect(valid_box_hi[0]-tpi_direction[3]*tpi_offset, valid_box_hi[1]-tpi_offset, valid_box_hi[2]));
106  //amrex::PrintToFile("BoxPerturbationOutput") << " South face";
107  }
108 
109  if (tpi_direction[2] || tpi_direction[5]) { amrex::Abort("Currently not supporting z-direction flow perturbation"); }
110 
111  // Performing box union for intersecting perturbation regions to avoid overlapping sections (double counting at corners)
112  if (tpi_direction[0] && tpi_direction[1]) { // Reshaping South smallEnd
113  amrex::Box lo_x_lo_y_u = lo_x_bx & lo_y_bx;
114  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)));
115  }
116 
117  if (tpi_direction[3] && tpi_direction[1]) { // Reshaping South bigEnd
118  amrex::Box hi_x_lo_y_u = hi_x_bx & lo_y_bx;
119  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)));
120  }
121 
122  if (tpi_direction[0] && tpi_direction[4]) { // Reshaping North smallEnd
123  amrex::Box lo_x_hi_y_u = lo_x_bx & hi_y_bx;
124  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)));
125  }
126 
127  if (tpi_direction[3] && tpi_direction[4]) { // Reshaping North bigEnd
128  amrex::Box hi_x_hi_y_u = hi_x_bx & hi_y_bx;
129  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)));
130  }
131 
132  // Creating structure box array for conserved quantity
133  if (tpi_direction[0]) { tmp_bl.push_back(lo_x_bx); }
134  if (tpi_direction[1]) { tmp_bl.push_back(lo_y_bx); }
135  if (tpi_direction[3]) { tmp_bl.push_back(hi_x_bx); }
136  if (tpi_direction[4]) { tmp_bl.push_back(hi_y_bx); }
137  //amrex::PrintToFile("BoxPerturbationOutput") << "\nBoxList: " << tmp_bl << "\n";
138  amrex::BoxArray tmp_ba(tmp_bl);
139  tmp_ba.maxSize(boxSize);
140  pb_ba.push_back(tmp_ba);
141 
142  if (lev == 0) {
143  pb_mag.resize(max_level+1);
144  pb_netZero.resize(max_level+1);
145  pb_interval.resize(max_level+1);
146  pb_local_etime.resize(max_level+1);
147  pb_amp.resize(max_level+1);
148  pb_cell.resize(max_level+1);
149  }
150 
151  // Initializing mean magnitude vector
152  pb_mag[lev].resize(pb_ba[lev].size(), 0.);
153  pb_netZero[lev].resize(pb_ba[lev].size(), 0.);
154 
155  // Set size of vector and initialize
156  pb_interval[lev].resize(pb_ba[lev].size(), -1.0);
157  pb_local_etime[lev].resize(pb_ba[lev].size(), 0.0);
158  pb_amp[lev].resize(pb_ba[lev].size(), 0.0);
159 
160  // Creating data array for perturbation amplitude storage
161  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...
162  pb_cell[lev].setVal(0.);
163 
164  // Computing perturbation reference length
165  tpi_Lpb = tpi_boxDim[0]*dx[0];
166  tpi_Wpb = tpi_boxDim[1]*dx[1];
167  tpi_Hpb = tpi_boxDim[2]*dx[2];
168  if (lev == 0) { // only need to define reference length scale for coarses level
170  }
171 
172  tpi_pert_adjust = 0.;
173  tpi_net_buoyant = 0.;
174 
175  /*
176  // Function check point message
177  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_box_dims: "
178  << tpi_boxDim[0] << " "
179  << tpi_boxDim[1] << " "
180  << tpi_boxDim[2] << "\n";
181  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_direction: "
182  << tpi_direction[0] << " "
183  << tpi_direction[1] << " "
184  << tpi_direction[2] << "\n\n";
185  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_layers: " << tpi_layers << "\n";
186  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_offset: " << tpi_offset << "\n\n";
187  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_nondimensional: " << tpi_nonDim << "\n";
188  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_T_infinity: " << tpi_Tinf << "\n";
189  amrex::PrintToFile("BoxPerturbationOutput") << "perturbation_T_intensity: " << tpi_Ti << "\n";
190  amrex::PrintToFile("BoxPerturbationOutput") << "Reference length per box = " << tpi_lref << "\n\n";
191  amrex::PrintToFile("BoxPerturbationOutput") << "Turbulent perturbation BoxArray:\n" << pb_ba[lev] << "\n";
192  */
193  }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:219
amrex::Vector< amrex::MultiFab > pb_cell
Definition: ERF_TurbPertStruct.H:554
int tpi_layers
Definition: ERF_TurbPertStruct.H:559
amrex::Real tpi_Wpb
Definition: ERF_TurbPertStruct.H:573
amrex::Real tpi_Lpb
Definition: ERF_TurbPertStruct.H:572
int tpi_offset
Definition: ERF_TurbPertStruct.H:560
amrex::Vector< int > tpi_boxDim
Definition: ERF_TurbPertStruct.H:562
amrex::Vector< int > tpi_direction
Definition: ERF_TurbPertStruct.H:563
Here is the call graph for this function:

◆ netZeroBuoyantAdd()

void TurbulentPerturbation::netZeroBuoyantAdd ( const int &  boxIdx,
const int &  lev 
)
inline
348  {
349  // Creating local copy of PB box array and magnitude
350  const amrex::BoxArray m_pb_ba = pb_ba[lev];
351  amrex::Real* m_pb_netZero = pb_netZero[lev].data();
352 
353  // Create device array for summation
354  amrex::Vector<amrex::Real> avg_h(1,0.);
355  amrex::Gpu::DeviceVector<amrex::Real> avg_d(1,0.);
356  amrex::Real* avg = avg_d.data();
357 
358  // Iterates through the cells of each box and sum the white noise perturbation
359  for (amrex::MFIter mfi(pb_cell[lev], TileNoZ()) ; mfi.isValid(); ++mfi) {
360  const amrex::Box& vbx = mfi.validbox();
361  amrex::Box pbx = amrex::convert(m_pb_ba[boxIdx], vbx.ixType());
362  amrex::Box ubx = pbx & vbx;
363  if (ubx.ok()) {
364  const amrex::Array4<const amrex::Real>& pert_cell = pb_cell[lev].const_array(mfi);
365  int npts = ubx.numPts();
366  amrex::Real norm = 1.0 / (amrex::Real) npts;
367  ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), ubx, [=]
368  AMREX_GPU_DEVICE(int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept {
369  amrex::Gpu::deviceReduceSum(&avg[0], pert_cell(i,j,k)*norm, handler);
370  });
371  amrex::Gpu::copy(amrex::Gpu::deviceToHost, avg_d.begin(), avg_d.end(), avg_h.begin());
372 
373  // Assigning onto storage array
374  m_pb_netZero[boxIdx] = avg_h[0];
375  }
376  }
377  }

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
383  {
384  // Creating local copy of PB box array and magnitude
385  const amrex::BoxArray m_pb_ba = pb_ba[lev];
386  for (amrex::MFIter mfi(pb_cell[lev], TileNoZ()) ; mfi.isValid(); ++mfi) {
387  const amrex::Box& vbx = mfi.validbox();
388  amrex::Box pbx = amrex::convert(m_pb_ba[boxIdx], vbx.ixType());
389  amrex::Box ubx = pbx & vbx;
390  if (ubx.ok()) {
391  const amrex::Real adjust = tpi_pert_adjust;
392  const amrex::Array4<amrex::Real>& pert_cell = pb_cell[lev].array(mfi);
393  ParallelFor(ubx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
394  pert_cell(i,j,k) -= adjust;
395  });
396  }
397  }
398  }

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
322  {
323  // Seed the random generator at 1024UL for regression testing
324  int fix_random_seed = 0;
325  amrex::ParmParse pp("erf"); pp.query("fix_random_seed", fix_random_seed);
326  if (fix_random_seed) {
327  amrex::InitRandom(1024UL);
328  }
329 
330  for (amrex::MFIter mfi(pb_cell[lev],TileNoZ()); mfi.isValid(); ++mfi) {
331  amrex::Box vbx = mfi.validbox();
332  amrex::Box pbx = amrex::convert(pb_ba[lev][boxIdx], m_ixtype);
333  amrex::Box ubx = pbx & vbx;
334  if (ubx.ok()) {
335  amrex::Real amp_copy = pb_amp[lev][boxIdx];
336  const amrex::Array4<amrex::Real>& pert_cell = pb_cell[lev].array(mfi);
337  ParallelForRNG(ubx, [=] AMREX_GPU_DEVICE(int i, int j, int k, const amrex::RandomEngine& engine) noexcept {
338  amrex::Real rand_double = amrex::Random(engine);
339  pert_cell(i,j,k) = (rand_double*2.0 - 1.0) * amp_copy;
340  });
341  }
342  }
343  }

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
589  {
590  amrex::Real r = (amrex::Real) rand() / (amrex::Real) RAND_MAX;
591  return min + r * (max - min);
592  }

Referenced by calc_tpi_update().

Here is the caller graph for this function:

Member Data Documentation

◆ pb_amp

amrex::Vector<amrex::Vector<amrex::Real> > TurbulentPerturbation::pb_amp
private

◆ pb_ba

amrex::Vector<amrex::BoxArray> TurbulentPerturbation::pb_ba

◆ pb_cell

amrex::Vector<amrex::MultiFab> TurbulentPerturbation::pb_cell

◆ pb_interval

amrex::Vector<amrex::Vector<amrex::Real> > TurbulentPerturbation::pb_interval
private

Referenced by calc_tpi_update(), and init_tpi().

◆ pb_local_etime

amrex::Vector<amrex::Vector<amrex::Real> > TurbulentPerturbation::pb_local_etime
private

Referenced by calc_tpi_update(), and init_tpi().

◆ pb_mag

amrex::Vector<amrex::Vector<amrex::Real> > TurbulentPerturbation::pb_mag

◆ pb_netZero

amrex::Vector<amrex::Vector<amrex::Real> > TurbulentPerturbation::pb_netZero
private

◆ pt_type

int TurbulentPerturbation::pt_type

Referenced by calc_tpi_amp().

◆ ref_ratio

amrex::Vector<amrex::IntVect> TurbulentPerturbation::ref_ratio
private

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_boxDim

amrex::Vector<int> TurbulentPerturbation::tpi_boxDim
private

Referenced by init_tpi().

◆ tpi_direction

amrex::Vector<int> TurbulentPerturbation::tpi_direction
private

Referenced by init_tpi().

◆ tpi_Hpb

amrex::Real TurbulentPerturbation::tpi_Hpb
private

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_layers

int TurbulentPerturbation::tpi_layers
private

Referenced by init_tpi().

◆ tpi_Lpb

amrex::Real TurbulentPerturbation::tpi_Lpb
private

Referenced by init_tpi().

◆ tpi_lref

amrex::Real TurbulentPerturbation::tpi_lref
private

Referenced by calc_tpi_update(), and init_tpi().

◆ tpi_net_buoyant

amrex::Real TurbulentPerturbation::tpi_net_buoyant
private

Referenced by calc_tpi_update(), and init_tpi().

◆ tpi_nonDim

amrex::Real TurbulentPerturbation::tpi_nonDim
private

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_offset

int TurbulentPerturbation::tpi_offset
private

Referenced by init_tpi().

◆ tpi_pert_adjust

amrex::Real TurbulentPerturbation::tpi_pert_adjust
private

◆ tpi_Ti

amrex::Real TurbulentPerturbation::tpi_Ti
private

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_Tinf

amrex::Real TurbulentPerturbation::tpi_Tinf
private

Referenced by calc_tpi_amp(), and init_tpi().

◆ tpi_Wpb

amrex::Real TurbulentPerturbation::tpi_Wpb
private

Referenced by init_tpi().


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