ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_InitForEnsemble.cpp File Reference
#include <ERF.H>
#include <ERF_TileNoZ.H>
#include <AMReX_PlotFileUtil.H>
#include <filesystem>
Include dependency graph for ERF_InitForEnsemble.cpp:

Functions

void NormalizeMultiFabRMS_PerComponent (MultiFab &mf_cc_pert)
 
void ApplyNeumannBCs (const Geometry &geom, MultiFab &mf_cc)
 
void ReadCustomDataFile (const std::string &filename_custom, int &nx, int &ny, int &nz, int &ng, int &ncomp, std::array< Real, 3 > &problo_ext, std::array< Real, 3 > &probhi_ext, Vector< Real > &data_rho, Vector< Real > &data_theta, Vector< Real > &data_xvel, Vector< Real > &data_yvel, Vector< Real > &data_zvel, Vector< Real > &data_qv, Vector< Real > &data_qc, Vector< Real > &data_qrain)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx (int i, int j, int k, int nx, int ny)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real interp_trilinear (const Real *f, int i, int j, int k, Real tx, Real ty, Real tz, int nx, int ny, int nz)
 
void InterpolateToFineMF (const Vector< Real > &data_rho, const Vector< Real > &data_theta, const Vector< Real > &data_xvel, const Vector< Real > &data_yvel, const Vector< Real > &data_zvel, const Vector< Real > &data_qv, const Vector< Real > &data_qc, const Vector< Real > &data_qrain, int nx, int ny, int nz, const std::array< Real, 3 > &problo, const std::array< Real, 3 > &probhi, MultiFab &mf_fine, const Geometry &geom_fine)
 
void MakeFinalMultiFabs (const MultiFab &mf_cc_fine, MultiFab &cons_pert, MultiFab &xvel_pert, MultiFab &yvel_pert, MultiFab &zvel_pert, const int n_qstate_moist)
 
void AddPertToBckgnd (MultiFab &mf_cc_fine, const MultiFab &mf_cc_pert, const Real &ens_pert_amplitude)
 

Variables

Vector< Realperturb_scale
 

Function Documentation

◆ AddPertToBckgnd()

void AddPertToBckgnd ( MultiFab &  mf_cc_fine,
const MultiFab &  mf_cc_pert,
const Real ens_pert_amplitude 
)

Add normalized perturbations to the interpolated background state.

Parameters
mf_cc_fineBackground state modified in place
mf_cc_pertPerturbation field to apply
ens_pert_amplitudeRelative perturbation amplitude
693 {
694  const int ncomp = mf_cc_fine.nComp();
695 
696  // Optional safety check (recommended)
697  AMREX_ALWAYS_ASSERT(mf_cc_pert.nComp() == ncomp);
698 
699  // Create a GPU-accessible array and copy the host vector into it
700  GpuArray<Real, 8> scale_gpu; // Use the maximum possible ncomp, e.g., 8
701  for (int n = 0; n < ncomp; ++n) {
702  scale_gpu[n] = perturb_scale[n];
703  }
704 
705  for (MFIter mfi(mf_cc_fine, TilingIfNotGPU()); mfi.isValid(); ++mfi)
706  {
707  const Box& bx = mfi.tilebox();
708 
709  auto const& bg = mf_cc_fine.array(mfi);
710  auto const& pert = mf_cc_pert.const_array(mfi);
711 
712  amrex::ParallelFor(bx, ncomp,
713  [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept
714  {
715  Real ens_amp = ens_pert_amplitude*scale_gpu[n]*std::abs(bg(i,j,k,n));
716  bg(i,j,k,n) += ens_amp*pert(i,j,k,n);
717  });
718  }
719 }
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
Vector< Real > perturb_scale
Definition: ERF_InitForEnsemble.cpp:14
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
real(c_double), private bg
Definition: ERF_module_mp_morr_two_moment.F90:182

Referenced by ERF::create_background_state_for_ensemble().

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

◆ ApplyNeumannBCs()

void ApplyNeumannBCs ( const Geometry &  geom,
MultiFab &  mf_cc 
)

Fill periodic ghost cells and apply first-order extrapolation at boundaries.

Parameters
geomGeometry defining domain bounds and periodicity
mf_ccCell-centered MultiFab whose ghost cells are filled in place
218 {
219 
220  // -------------------------------------------------
221  // 2. Fill interior + periodic ghost cells
222  // -------------------------------------------------
223  mf_cc.FillBoundary(geom.periodicity());
224  // -------------------------------------------------
225  // 3. Apply FOExtrap (Neumann) at domain boundaries
226  // -------------------------------------------------
227  const Box& domain = geom.Domain();
228 
229  const bool periodic_x = geom.isPeriodic(0);
230  const bool periodic_y = geom.isPeriodic(1);
231  const bool periodic_z = geom.isPeriodic(2);
232 
233  for (MFIter mfi(mf_cc, TilingIfNotGPU()); mfi.isValid(); ++mfi)
234  {
235  const Box& gbx = mfi.growntilebox(); // includes ghost cells
236  const Box& vbx = mfi.validbox();
237 
238  auto const& arr = mf_cc.array(mfi);
239  int ncomp = mf_cc.nComp();
240 
241  ParallelFor(gbx, ncomp,
242  [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
243  {
244  if (vbx.contains(i,j,k)) return;
245 
246  int ii = i;
247  int jj = j;
248  int kk = k;
249 
250  if (!periodic_x) {
251  ii = amrex::max(domain.smallEnd(0),
252  amrex::min(i, domain.bigEnd(0)));
253  }
254 
255  if (!periodic_y) {
256  jj = amrex::max(domain.smallEnd(1),
257  amrex::min(j, domain.bigEnd(1)));
258  }
259 
260  if (!periodic_z) {
261  kk = amrex::max(domain.smallEnd(2),
262  amrex::min(k, domain.bigEnd(2)));
263  }
264 
265  arr(i,j,k,n) = arr(ii,jj,kk,n);
266  });
267  }
268 }
if(l_use_mynn &&start_comp<=RhoKE_comp &&end_comp >=RhoKE_comp)
Definition: ERF_AddQKESources.H:2

Referenced by ERF::create_background_state_for_ensemble().

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

◆ idx()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx ( int  i,
int  j,
int  k,
int  nx,
int  ny 
)

Convert a three-dimensional cell index into a flattened array index.

Parameters
ix-index
jy-index
kz-index
nxNumber of cells in the x-direction
nyNumber of cells in the y-direction
Returns
Flattened index into a row-major 3D array
397 {
398  return i + nx * (j + ny * k);
399 }
const int nx
Definition: ERF_InitCustomPertVels_CloudChamber.H:14
const int ny
Definition: ERF_InitCustomPertVels_CloudChamber.H:15

Referenced by br_shift(), ChopGrids2D(), clamp_interp_index(), closest_index(), ERF::FillPlot3DVars(), ERF::FillSurfaceStateMultiFabs(), NOAHMP::Init(), ERF::init_stuff(), ERF::InitData_post(), MRISplitIntegrator< T >::initialize_data(), interp_trilinear(), NOAHMP::Lsm_DataIndex(), NOAHMP::Lsm_FluxIndex(), OpenBCCornerBox(), parse_fixed_width_int(), ERF::read_box_for_refinement(), ReadBndryPlanes::read_file(), ReadBndryPlanes::read_input_files(), ReadCustomBinaryIC(), ReadCustomDataFile(), SatMethods::wv_sat_qsat_ice(), SatMethods::wv_sat_qsat_trans(), SatMethods::wv_sat_qsat_water(), SatMethods::wv_sat_svp_ice(), SatMethods::wv_sat_svp_trans(), and SatMethods::wv_sat_svp_water().

Here is the caller graph for this function:

◆ interp_trilinear()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real interp_trilinear ( const Real f,
int  i,
int  j,
int  k,
Real  tx,
Real  ty,
Real  tz,
int  nx,
int  ny,
int  nz 
)

Trilinearly interpolate one scalar component from a flattened array.

Parameters
fFlattened source data
iLower x-index of the interpolation cell
jLower y-index of the interpolation cell
kLower z-index of the interpolation cell
txFractional x-coordinate within the cell
tyFractional y-coordinate within the cell
tzFractional z-coordinate within the cell
nxNumber of cells in the x-direction
nyNumber of cells in the y-direction
nzNumber of cells in the z-direction
Returns
Interpolated scalar value
423 {
424  int i1 = amrex::min(i+1, nx-1);
425  int j1 = amrex::min(j+1, ny-1);
426  int k1 = amrex::min(k+1, nz-1);
427 
428  Real c000 = f[idx(i ,j ,k ,nx,ny)];
429  Real c100 = f[idx(i1,j ,k ,nx,ny)];
430  Real c010 = f[idx(i ,j1,k ,nx,ny)];
431  Real c110 = f[idx(i1,j1,k ,nx,ny)];
432  Real c001 = f[idx(i ,j ,k1,nx,ny)];
433  Real c101 = f[idx(i1,j ,k1,nx,ny)];
434  Real c011 = f[idx(i ,j1,k1,nx,ny)];
435  Real c111 = f[idx(i1,j1,k1,nx,ny)];
436 
437  Real c00 = c000*(1-tx) + c100*tx;
438  Real c10 = c010*(1-tx) + c110*tx;
439  Real c01 = c001*(1-tx) + c101*tx;
440  Real c11 = c011*(1-tx) + c111*tx;
441 
442  Real c0 = c00*(1-ty) + c10*ty;
443  Real c1 = c01*(1-ty) + c11*ty;
444 
445  return c0*(1-tz) + c1*tz;
446 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx(int i, int j, int k, int nx, int ny)
Definition: ERF_InitForEnsemble.cpp:396
real(c_double), private k1
Definition: ERF_module_mp_morr_two_moment.F90:213
real(c_double), private c1
Definition: ERF_module_mp_morr_two_moment.F90:212

Referenced by InterpolateToFineMF().

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

◆ InterpolateToFineMF()

void InterpolateToFineMF ( const Vector< Real > &  data_rho,
const Vector< Real > &  data_theta,
const Vector< Real > &  data_xvel,
const Vector< Real > &  data_yvel,
const Vector< Real > &  data_zvel,
const Vector< Real > &  data_qv,
const Vector< Real > &  data_qc,
const Vector< Real > &  data_qrain,
int  nx,
int  ny,
int  nz,
const std::array< Real, 3 > &  problo,
const std::array< Real, 3 > &  probhi,
MultiFab &  mf_fine,
const Geometry &  geom_fine 
)

Interpolate coarse custom background data onto the fine cell-centered grid.

Parameters
data_rhoCoarse density values
data_thetaCoarse potential temperature values
data_xvelCoarse x-velocity values
data_yvelCoarse y-velocity values
data_zvelCoarse z-velocity values
data_qvCoarse water vapor values
data_qcCoarse cloud water values
data_qrainCoarse rain water values
nxNumber of coarse cells in the x-direction
nyNumber of coarse cells in the y-direction
nzNumber of coarse cells in the z-direction
probloPhysical lower bounds of the coarse data
probhiPhysical upper bounds of the coarse data
mf_fineFine-grid cell-centered MultiFab to fill
geom_fineGeometry of the fine grid
482 {
483  // coarse spacing
484  Real dx_c[3];
485  dx_c[0] = (probhi[0] - problo[0]) / nx;
486  dx_c[1] = (probhi[1] - problo[1]) / ny;
487  dx_c[2] = (probhi[2] - problo[2]) / nz;
488 
489  const auto problo_f = geom_fine.ProbLoArray();
490  const auto dx_f = geom_fine.CellSizeArray();
491 
492  // Step 1: declare device vectors with correct size
493  amrex::Gpu::DeviceVector<Real> d_rho(data_rho.size());
494  amrex::Gpu::DeviceVector<Real> d_theta(data_theta.size());
495  amrex::Gpu::DeviceVector<Real> d_xvel(data_xvel.size());
496  amrex::Gpu::DeviceVector<Real> d_yvel(data_yvel.size());
497  amrex::Gpu::DeviceVector<Real> d_zvel(data_zvel.size());
498  amrex::Gpu::DeviceVector<Real> d_qv(data_qv.size());
499  amrex::Gpu::DeviceVector<Real> d_qc(data_qc.size());
500  amrex::Gpu::DeviceVector<Real> d_qrain(data_qrain.size());
501 
502  // Step 2: copy data from host to device
503  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice,
504  data_rho.begin(), data_rho.end(),
505  d_rho.begin());
506 
507  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice,
508  data_theta.begin(), data_theta.end(),
509  d_theta.begin());
510 
511  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice,
512  data_xvel.begin(), data_xvel.end(),
513  d_xvel.begin());
514 
515  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice,
516  data_yvel.begin(), data_yvel.end(),
517  d_yvel.begin());
518 
519  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice,
520  data_zvel.begin(), data_zvel.end(),
521  d_zvel.begin());
522 
523  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice,
524  data_qv.begin(), data_qv.end(),
525  d_qv.begin());
526 
527  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice,
528  data_qc.begin(), data_qc.end(),
529  d_qc.begin());
530 
531  amrex::Gpu::copyAsync(amrex::Gpu::hostToDevice,
532  data_qrain.begin(), data_qrain.end(),
533  d_qrain.begin());
534 
535  const Real* rho_ptr = d_rho.data();
536  const Real* theta_ptr = d_theta.data();
537  const Real* xvel_ptr = d_xvel.data();
538  const Real* yvel_ptr = d_yvel.data();
539  const Real* zvel_ptr = d_zvel.data();
540  const Real* qv_ptr = d_qv.data();
541  const Real* qc_ptr = d_qc.data();
542  const Real* qrain_ptr = d_qrain.data();
543 
544  // -------------------------------
545  // GPU kernel over MultiFab
546  // -------------------------------
547  for (MFIter mfi(mf_fine); mfi.isValid(); ++mfi)
548  {
549  const Box& bx = mfi.validbox();
550  auto arr = mf_fine.array(mfi);
551 
553  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
554  {
555  // physical location (fine cell center)
556  Real x = problo_f[0] + (i + myhalf) * dx_f[0];
557  Real y = problo_f[1] + (j + myhalf) * dx_f[1];
558  Real z = problo_f[2] + (k + myhalf) * dx_f[2];
559 
560  // map to coarse index space (cell centers)
561  Real rx = (x - problo[0]) / dx_c[0] - myhalf;
562  Real ry = (y - problo[1]) / dx_c[1] - myhalf;
563  Real rz = (z - problo[2]) / dx_c[2] - myhalf;
564 
565  // clamp coordinates into valid coarse cell-center range
566  rx = amrex::max(Real(0), amrex::min(rx, Real(nx-1)));
567  ry = amrex::max(Real(0), amrex::min(ry, Real(ny-1)));
568  rz = amrex::max(Real(0), amrex::min(rz, Real(nz-1)));
569 
570  int ic = static_cast<int>(amrex::Math::floor(rx));
571  int jc = static_cast<int>(amrex::Math::floor(ry));
572  int kc = static_cast<int>(amrex::Math::floor(rz));
573 
574  Real tx = rx - ic;
575  Real ty = ry - jc;
576  Real tz = rz - kc;
577 
578  // optional: avoid degenerate interpolation at upper edge
579  if (ic == nx-1) tx = Real(0);
580  if (jc == ny-1) ty = Real(0);
581  if (kc == nz-1) tz = Real(0);
582 
583  //printf("The values are x, y, z, rx, ry, rz = %0.15g %0.15g %0.15g %0.15g %0.15g %0.15g\n", x, y, z, rx, ry, rz);
584 
585  // interpolate each component using device trilinear
586  arr(i,j,k,0) = interp_trilinear(rho_ptr, ic,jc,kc, tx,ty,tz, nx,ny,nz);
587  arr(i,j,k,1) = interp_trilinear(theta_ptr, ic,jc,kc, tx,ty,tz, nx,ny,nz);
588  arr(i,j,k,2) = interp_trilinear(xvel_ptr, ic,jc,kc, tx,ty,tz, nx,ny,nz);
589  arr(i,j,k,3) = interp_trilinear(yvel_ptr, ic,jc,kc, tx,ty,tz, nx,ny,nz);
590  arr(i,j,k,4) = interp_trilinear(zvel_ptr, ic,jc,kc, tx,ty,tz, nx,ny,nz);
591  arr(i,j,k,5) = interp_trilinear(qv_ptr, ic,jc,kc, tx,ty,tz, nx,ny,nz);
592  arr(i,j,k,6) = interp_trilinear(qc_ptr, ic,jc,kc, tx,ty,tz, nx,ny,nz);
593  arr(i,j,k,7) = interp_trilinear(qrain_ptr, ic,jc,kc, tx,ty,tz, nx,ny,nz);
594 
595  /*printf("Values are %0.15g %0.15g %0.15g %0.15g %0.15g %0.15g %0.15g %0.15g\n",
596  arr(i,j,k,0), arr(i,j,k,1), arr(i,j,k,2), arr(i,j,k,3),
597  arr(i,j,k,4), arr(i,j,k,5), arr(i,j,k,6), arr(i,j,k,7));*/
598  });
599  }
600 }
auto probhi
Definition: ERF_InitCustomPertVels_ABL.H:37
auto problo
Definition: ERF_InitCustomPertVels_ABL.H:36
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Real interp_trilinear(const Real *f, int i, int j, int k, Real tx, Real ty, Real tz, int nx, int ny, int nz)
Definition: ERF_InitForEnsemble.cpp:418
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:34

Referenced by ERF::create_background_state_for_ensemble().

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

◆ MakeFinalMultiFabs()

void MakeFinalMultiFabs ( const MultiFab &  mf_cc_fine,
MultiFab &  cons_pert,
MultiFab &  xvel_pert,
MultiFab &  yvel_pert,
MultiFab &  zvel_pert,
const int  n_qstate_moist 
)

Split cell-centered interpolated background data into ERF state and face velocities.

Parameters
mf_cc_fineFine-grid cell-centered source data
cons_pertConserved-state perturbation MultiFab to fill
xvel_pertx-face velocity perturbation MultiFab to fill
yvel_perty-face velocity perturbation MultiFab to fill
zvel_pertz-face velocity perturbation MultiFab to fill
618 {
619 
620  for (MFIter mfi(cons_pert, TilingIfNotGPU()); mfi.isValid(); ++mfi)
621  {
622  const Box& bx = mfi.tilebox();
623 
624  auto const& mf_cc_fine_arr = mf_cc_fine.const_array(mfi);
625  auto const& cons_pert_arr = cons_pert.array(mfi);
626 
627  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
628  {
629  Real tmp_rho = mf_cc_fine_arr(i,j,k,0);
630  Real tmp_theta = mf_cc_fine_arr(i,j,k,1);
631  Real tmp_qv = mf_cc_fine_arr(i,j,k,5);
632  Real tmp_qc = mf_cc_fine_arr(i,j,k,6);
633  Real tmp_qrain = mf_cc_fine_arr(i,j,k,7);
634  cons_pert_arr(i,j,k,Rho_comp) = tmp_rho;
635  cons_pert_arr(i,j,k,RhoTheta_comp) = tmp_rho*tmp_theta;
636  if (n_qstate_moist > 0) cons_pert_arr(i,j,k,RhoQ1_comp) = std::max(tmp_rho*tmp_qv,0.0_rt);
637  if (n_qstate_moist > 1) cons_pert_arr(i,j,k,RhoQ2_comp) = std::max(tmp_rho*tmp_qc,0.0_rt);
638  if (n_qstate_moist > 2) cons_pert_arr(i,j,k,RhoQ3_comp) = std::max(tmp_rho*tmp_qrain,0.0_rt);
639  });
640  }
641 
642  // --- X-faces (component 2) ---
643  for (MFIter mfi(xvel_pert, TilingIfNotGPU()); mfi.isValid(); ++mfi)
644  {
645  const Box& bx = mfi.tilebox();
646  auto const& uface = xvel_pert.array(mfi);
647  auto const& cc = mf_cc_fine.const_array(mfi);
648 
649  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
650  {
651  uface(i,j,k) = myhalf * (cc(i-1,j,k,2) + cc(i,j,k,2));
652  });
653  }
654 
655  // --- Y-faces (component 3) ---
656  for (MFIter mfi(yvel_pert, TilingIfNotGPU()); mfi.isValid(); ++mfi)
657  {
658  const Box& bx = mfi.tilebox();
659  auto const& vface = yvel_pert.array(mfi);
660  auto const& cc = mf_cc_fine.const_array(mfi);
661 
662  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
663  {
664  vface(i,j,k) = myhalf * (cc(i,j-1,k,3) + cc(i,j,k,3));
665  });
666  }
667 
668  // --- Z-faces (component 4) ---
669  for (MFIter mfi(zvel_pert, TilingIfNotGPU()); mfi.isValid(); ++mfi)
670  {
671  const Box& bx = mfi.tilebox();
672  auto const& wface = zvel_pert.array(mfi);
673  auto const& cc = mf_cc_fine.const_array(mfi);
674 
675  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
676  {
677  wface(i,j,k) = myhalf * (cc(i,j,k-1,4) + cc(i,j,k,4));
678  });
679  }
680 }
#define Rho_comp
Definition: ERF_IndexDefines.H:39
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:40
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:46
#define RhoQ3_comp
Definition: ERF_IndexDefines.H:47
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:45

Referenced by ERF::create_background_state_for_ensemble().

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

◆ NormalizeMultiFabRMS_PerComponent()

void NormalizeMultiFabRMS_PerComponent ( MultiFab &  mf_cc_pert)

Normalize each component of a perturbation MultiFab by its global RMS value.

Parameters
mf_cc_pertMultiFab whose components are normalized in place
65 {
66  const int ncomp = mf_cc_pert.nComp();
67 
68  for (int n = 0; n < ncomp; ++n)
69  {
70  // 1. Set up AMReX reduction (sum of squares + count)
71  ReduceOps<ReduceOpSum, ReduceOpSum> reduce_op;
72  ReduceData<Real, Long> reduce_data(reduce_op);
73  using ReduceTuple = typename decltype(reduce_data)::Type;
74 
75  // 2. Loop over tiles and accumulate
76  for (MFIter mfi(mf_cc_pert, TilingIfNotGPU()); mfi.isValid(); ++mfi)
77  {
78  const Box& bx = mfi.tilebox();
79  auto const& arr = mf_cc_pert.const_array(mfi);
80 
81  reduce_op.eval(bx, reduce_data,
82  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept -> ReduceTuple
83  {
84  Real v = arr(i, j, k, n);
85  return { v * v, 1L };
86  });
87  }
88 
89  // 3. Retrieve results (includes implicit GPU sync + host copy)
90  auto rv = reduce_data.value(reduce_op);
91  Real h_sumsq = amrex::get<0>(rv);
92  Long h_count = amrex::get<1>(rv);
93 
94  // 4. Sum across MPI ranks
95  ParallelDescriptor::ReduceRealSum(h_sumsq);
96  ParallelDescriptor::ReduceLongSum(h_count);
97 
98  // 5. Compute RMS and normalize
99  if (h_count > 0)
100  {
101  Real rms = std::sqrt(h_sumsq / static_cast<Real>(h_count));
102  if (rms > zero) {
103  mf_cc_pert.mult(one / rms, n, 1);
104  }
105  }
106  }
107 }
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:30
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:29

Referenced by ERF::apply_gaussian_smoothing_to_perturbations().

Here is the caller graph for this function:

◆ ReadCustomDataFile()

void ReadCustomDataFile ( const std::string &  filename_custom,
int &  nx,
int &  ny,
int &  nz,
int &  ng,
int &  ncomp,
std::array< Real, 3 > &  problo_ext,
std::array< Real, 3 > &  probhi_ext,
Vector< Real > &  data_rho,
Vector< Real > &  data_theta,
Vector< Real > &  data_xvel,
Vector< Real > &  data_yvel,
Vector< Real > &  data_zvel,
Vector< Real > &  data_qv,
Vector< Real > &  data_qc,
Vector< Real > &  data_qrain 
)

Read binary custom ensemble background data into host vectors.

Parameters
filename_customPath to the custom binary data file
nxNumber of cells in the x-direction read from the file
nyNumber of cells in the y-direction read from the file
nzNumber of cells in the z-direction read from the file
ngNumber of ghost cells read from the file
ncompNumber of stored components read from the file
problo_extPhysical lower bounds read from the file
probhi_extPhysical upper bounds read from the file
data_rhoDensity values read from the file
data_thetaPotential temperature values read from the file
data_xvelx-velocity values read from the file
data_yvely-velocity values read from the file
data_zvelz-velocity values read from the file
data_qvWater vapor values read from the file
data_qcCloud water values read from the file
data_qrainRain water values read from the file
305 {
306  std::ifstream ifs(filename_custom, std::ios::binary);
307  if (!ifs.is_open()) {
308  Abort("Failed to open file " + filename_custom + " for reading");
309  }
310 
311  // ----------------------------
312  // Read header
313  // ----------------------------
314  ifs.read(reinterpret_cast<char*>(&nx), sizeof(int));
315  ifs.read(reinterpret_cast<char*>(&ny), sizeof(int));
316  ifs.read(reinterpret_cast<char*>(&nz), sizeof(int));
317 
318  ifs.read(reinterpret_cast<char*>(&ng), sizeof(int));
319  ifs.read(reinterpret_cast<char*>(&ncomp), sizeof(int));
320 
321  ifs.read(reinterpret_cast<char*>(&problo_ext[0]), sizeof(Real));
322  ifs.read(reinterpret_cast<char*>(&problo_ext[1]), sizeof(Real));
323  ifs.read(reinterpret_cast<char*>(&problo_ext[2]), sizeof(Real));
324 
325  ifs.read(reinterpret_cast<char*>(&probhi_ext[0]), sizeof(Real));
326  ifs.read(reinterpret_cast<char*>(&probhi_ext[1]), sizeof(Real));
327  ifs.read(reinterpret_cast<char*>(&probhi_ext[2]), sizeof(Real));
328 
329  const std::size_t ncell = static_cast<std::size_t>(nx) * ny * nz;
330 
331  // ----------------------------
332  // Allocate storage
333  // ----------------------------
334  data_rho.resize(ncell);
335  data_theta.resize(ncell);
336  data_xvel.resize(ncell);
337  data_yvel.resize(ncell);
338  data_zvel.resize(ncell);
339  data_qv.resize(ncell);
340  data_qc.resize(ncell);
341  data_qrain.resize(ncell);
342 
343  // ----------------------------
344  // Read data
345  // ----------------------------
346  std::size_t idx = 0;
347 
348  for (int k = 0; k < nz; ++k)
349  {
350  for (int j = 0; j < ny; ++j)
351  {
352  for (int i = 0; i < nx; ++i)
353  {
354  // Skip coordinates
355  Real x, y, z;
356  ifs.read(reinterpret_cast<char*>(&x), sizeof(Real));
357  ifs.read(reinterpret_cast<char*>(&y), sizeof(Real));
358  ifs.read(reinterpret_cast<char*>(&z), sizeof(Real));
359 
360  // Read components (fixed order)
361  ifs.read(reinterpret_cast<char*>(&data_rho[idx]), sizeof(Real));
362  ifs.read(reinterpret_cast<char*>(&data_theta[idx]), sizeof(Real));
363  ifs.read(reinterpret_cast<char*>(&data_xvel[idx]), sizeof(Real));
364  ifs.read(reinterpret_cast<char*>(&data_yvel[idx]), sizeof(Real));
365  ifs.read(reinterpret_cast<char*>(&data_zvel[idx]), sizeof(Real));
366  ifs.read(reinterpret_cast<char*>(&data_qv[idx]), sizeof(Real));
367  ifs.read(reinterpret_cast<char*>(&data_qc[idx]), sizeof(Real));
368  ifs.read(reinterpret_cast<char*>(&data_qrain[idx]), sizeof(Real));
369 
370  /*if(ParallelDescriptor::IOProcessor()) {
371  std::cout << "Values are " << data_rho[idx] << " " << data_theta[idx] << " "
372  << data_xvel[idx] << " " << data_yvel[idx] << " "
373  << data_zvel[idx] << " " << data_qv[idx] << " "
374  << data_qc[idx] << " " << data_qrain[idx] << std::endl;
375  }*/
376  ++idx;
377  }
378  }
379  }
380 
381  ifs.close();
382 }
@ ng
Definition: ERF_Morrison.H:50

Referenced by ERF::create_background_state_for_ensemble().

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

Variable Documentation

◆ perturb_scale

Vector<Real> perturb_scale
Initial value:
=
{
0.01,
1.0,
1.0,
1.0,
0.5,
5.0e-4,
1.0e-4,
1.0e-4
}

Referenced by AddPertToBckgnd().