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

#include <ERF_MOSTAverage.H>

Collaboration diagram for MOSTAverage:

Public Member Functions

 MOSTAverage (amrex::Vector< amrex::Geometry > geom, const bool &has_zphys, std::string a_pp_prefix, const MeshType &m_mesh_type, const TerrainType &m_terrain_type, const amrex::Vector< const eb_ * > &eb_vec={})
 
 ~MOSTAverage ()
 
 MOSTAverage (MOSTAverage &&) noexcept=default
 
MOSTAverageoperator= (MOSTAverage &&other) noexcept=delete
 
 MOSTAverage (const MOSTAverage &other)=delete
 
MOSTAverageoperator= (const MOSTAverage &other)=delete
 
void make_MOSTAverage_at_level (const int &lev, const amrex::Vector< amrex::MultiFab * > &vars_old, std::unique_ptr< amrex::MultiFab > &Theta_prim, std::unique_ptr< amrex::MultiFab > &Qv_prim, std::unique_ptr< amrex::MultiFab > &Qr_prim, std::unique_ptr< amrex::MultiFab > &z_phys_nd)
 
void update_field_ptrs (const int &lev, amrex::Vector< amrex::Vector< amrex::MultiFab >> &vars_old, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Theta_prim, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Qv_prim, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Qr_prim)
 
void set_rotated_fields (const int &lev)
 
void set_plane_normalization (const int &lev)
 
void set_eb_normalization (const int &lev)
 
void set_region_normalization (const int &)
 
void set_k_indices_N (const int &lev)
 
void set_k_indices_T (const int &lev)
 
void set_norm_indices_T (const int &lev)
 
void set_z_positions_T (const int &lev)
 
void set_z_positions_EB (const int &lev)
 
void set_norm_positions_T (const int &lev)
 
void compute_averages (const int &lev)
 
void compute_plane_averages (const int &lev)
 
void compute_region_averages (const int &lev)
 
void compute_eb_averages (const int &lev)
 
void write_k_indices (const int &lev)
 
void write_norm_indices (const int &lev)
 
void write_xz_positions (const int &lev, const int &j)
 
void write_averages (const int &lev)
 
const amrex::MultiFab * get_average (const int &lev, const int &comp) const
 
amrex::MultiFab * get_average (const int &lev, const int &comp)
 
bool do_time_averaging () const
 
int get_navg () const
 
bool time_avg_is_initialized (const int &lev) const
 
void set_time_avg_initialized (const int &lev)
 
amrex::Vector< amrex::Realget_plane_average (const int &lev) const
 
bool set_plane_average (const int &lev, const amrex::Vector< amrex::Real > &pavg)
 
amrex::MultiFab * get_zref (const int &lev) const
 
const amrex::iMultiFab * get_k_indices (const int &lev) const
 

Static Public Member Functions

AMREX_GPU_HOST_DEVICE static AMREX_INLINE void trilinear_interp_T (const amrex::Real &xp, const amrex::Real &yp, const amrex::Real &zp, amrex::Real *interp_vals, amrex::Array4< amrex::Real const > const &interp_array, amrex::Array4< amrex::Real const > const &z_arr, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &plo, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxi, const int interp_comp)
 

Protected Attributes

const amrex::Vector< amrex::Geometry > m_geom
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_fields
 
amrex::Vector< amrex::MultiFab * > m_z_phys_nd
 
std::string m_pp_prefix
 
MeshType m_mesh_type
 
TerrainType m_terrain_type
 
int m_nvar {6}
 
int m_navg {6}
 
int m_maxlev {0}
 
int m_policy {0}
 
bool m_rotate {false}
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_zref
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_x_pos
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_y_pos
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_z_pos
 
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > m_i_indx
 
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > m_j_indx
 
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > m_k_indx
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > m_averages
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > m_rot_fields
 
amrex::Vector< amrex::Vector< int > > m_ncell_plane
 
amrex::Vector< amrex::Vector< amrex::Real > > m_plane_average
 
int m_radius {0}
 
int m_ncell_region {1}
 
amrex::Vector< int > m_k_in
 
bool m_interp {false}
 
bool m_norm_vec {false}
 
amrex::Vector< const eb_ * > m_eb_vec
 
amrex::Vector< amrex::Vector< amrex::Real > > m_total_bndry_area
 
bool m_t_avg {false}
 
amrex::Vector< int > m_t_init
 
double m_time_window {1.0e-16}
 
amrex::Real m_fact_new
 
amrex::Real m_fact_old
 
bool include_subgrid_vel = false
 
amrex::Vector< amrex::Realm_Vsg
 
const amrex::Real zref_default = amrex::Real(10.0)
 
const amrex::Real zref_sentinel = amrex::Real(-1.0)
 

Constructor & Destructor Documentation

◆ MOSTAverage() [1/3]

MOSTAverage::MOSTAverage ( amrex::Vector< amrex::Geometry >  geom,
const bool &  has_zphys,
std::string  a_pp_prefix,
const MeshType &  m_mesh_type,
const TerrainType &  m_terrain_type,
const amrex::Vector< const eb_ * > &  eb_vec = {} 
)
explicit

Construct the MOST averaging helper.

Parameters
[in]geomgeometry for all AMR levels
[in]has_zphyswhether nodal physical-height data are available
[in]a_pp_prefixParmParse prefix
[in]m_mesh_typemesh type
[in]m_terrain_typeterrain representation
[in]eb_vecoptional embedded-boundary geometry data

◆ ~MOSTAverage()

MOSTAverage::~MOSTAverage ( )
inline

Destroy the MOST averaging helper.

40  {}

◆ MOSTAverage() [2/3]

MOSTAverage::MOSTAverage ( MOSTAverage &&  )
defaultnoexcept

Default move constructor.

◆ MOSTAverage() [3/3]

MOSTAverage::MOSTAverage ( const MOSTAverage other)
delete

Deleted copy constructor.

Parameters
[in]othersource object

Member Function Documentation

◆ compute_averages()

void MOSTAverage::compute_averages ( const int &  lev)

Driver for the selected average policy.

Parameters
[in]levlevel index

Function to call the type of average computation.

Parameters
[in]levCurrent level
971 {
972  if (m_rotate) set_rotated_fields(lev);
973 
974  switch(m_policy) {
975  case 0: // Standard plane average
977  break;
978  case 1: // Local region/point
980  break;
981  case 2: // EB Terrain average
982  compute_eb_averages(lev);
983  break;
984  default:
985  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(false, "Unknown policy for MOSTAverage!");
986  }
987 
988  // We have initialized the averages
989  if (m_t_avg) m_t_init[lev] = 1;
990 }
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_cloud_chamber_config.active, "Cloud Chamber: initializer reached without a parsed configuration")
bool m_t_avg
Definition: ERF_MOSTAverage.H:452
void compute_plane_averages(const int &lev)
Definition: ERF_MOSTAverage.cpp:999
int m_policy
Definition: ERF_MOSTAverage.H:417
void compute_region_averages(const int &lev)
Definition: ERF_MOSTAverage.cpp:1298
amrex::Vector< int > m_t_init
Definition: ERF_MOSTAverage.H:453
void set_rotated_fields(const int &lev)
Definition: ERF_MOSTAverage.cpp:328
bool m_rotate
Definition: ERF_MOSTAverage.H:418
void compute_eb_averages(const int &lev)
Definition: ERF_MOSTAverage.cpp:1675
Here is the call graph for this function:

◆ compute_eb_averages()

void MOSTAverage::compute_eb_averages ( const int &  lev)

Fill averages for the embedded-boundary policy.

Parameters
[in]levlevel index

Function to compute average over an EB surface.

Parameters
[in]levCurrent level
1676 {
1677  AMREX_ALWAYS_ASSERT(m_eb_vec[lev] != nullptr);
1678 
1679  // Peel back the level
1680  auto& fields = m_fields[lev];
1681  auto& averages = m_averages[lev];
1682  auto& plane_average = m_plane_average[lev];
1683 
1684  // Get EB data
1685  const auto& cc_flags = m_eb_vec[lev]->get_const_factory()->getMultiEBCellFlagFab();
1686  auto cc_afrac = m_eb_vec[lev]->get_const_factory()->getAreaFrac();
1687  const auto& cc_bnorm = m_eb_vec[lev]->get_const_factory()->getBndryNormal();
1688  const auto& u_vfrac = m_eb_vec[lev]->get_u_const_factory()->getVolFrac();
1689  const auto& v_vfrac = m_eb_vec[lev]->get_v_const_factory()->getVolFrac();
1690  const auto& w_vfrac = m_eb_vec[lev]->get_w_const_factory()->getVolFrac();
1691 
1692  // Get geometry for cell sizes
1693  auto const& dx_arr = m_geom[lev].CellSizeArray();
1694  Real dx = dx_arr[0];
1695  Real dy = dx_arr[1];
1696  Real dz = dx_arr[2];
1697 
1698  // Set factors for time averaging
1699  Real d_fact_new, d_fact_old;
1700  if (m_t_avg && m_t_init[lev]) {
1701  d_fact_new = m_fact_new;
1702  d_fact_old = m_fact_old;
1703  } else {
1704  d_fact_new = one;
1705  d_fact_old = zero;
1706  }
1707 
1708  // GPU array to accumulate averages into
1709  Gpu::DeviceVector<Real> pavg(plane_average.size(), zero);
1710  Real* plane_avg = pavg.data();
1711 
1712  // Vectors for normalization and buffer storage
1713  Vector<Real> denom(plane_average.size(),zero);
1714  Vector<Real> val_old(plane_average.size(),zero);
1715 
1716  //
1717  //----------------------------------------------------------
1718  // Averages for U, V, and tangential velocity (in local coordinate)
1719  //----------------------------------------------------------
1720  //
1721  {
1722  denom[0] = one / m_total_bndry_area[lev][0];
1723  val_old[0] = plane_average[0]*d_fact_old;
1724  denom[1] = one / m_total_bndry_area[lev][1];
1725  val_old[1] = plane_average[1]*d_fact_old;
1726 
1727  int iavg = m_navg - 1; // Tangential velocity magnitude
1728  denom[iavg] = one / m_total_bndry_area[lev][iavg];
1729  val_old[iavg] = plane_average[iavg]*d_fact_old;
1730 
1731  const Real Vsg = m_Vsg[lev]; // Subgrid scale velocity
1732 
1733 #ifdef _OPENMP
1734 #pragma omp parallel if (Gpu::notInLaunchRegion())
1735 #endif
1736  for (MFIter mfi(*fields[2], TileNoZ()); mfi.isValid(); ++mfi) {
1737  const auto& flag = cc_flags[mfi];
1738 
1739  // Skip boxes that are not singlevalued (MultiCutFab only has data for singlevalued boxes)
1740  if (flag.getType() != FabType::singlevalued) continue;
1741 
1742  Box bx = mfi.tilebox(); // Full 3D box
1743 
1744  // Get EB arrays
1745  auto const flag_arr = flag.const_array();
1746  auto const afrac_x = cc_afrac[0]->const_array(mfi);
1747  auto const afrac_y = cc_afrac[1]->const_array(mfi);
1748  auto const afrac_z = cc_afrac[2]->const_array(mfi);
1749  auto const bnorm_arr = cc_bnorm.const_array(mfi);
1750  auto const u_vf_arr = u_vfrac.const_array(mfi);
1751  auto const v_vf_arr = v_vfrac.const_array(mfi);
1752  auto const w_vf_arr = w_vfrac.const_array(mfi);
1753 
1754  // Get velocity arrays
1755  auto const u_arr = fields[0]->const_array(mfi);
1756  auto const v_arr = fields[1]->const_array(mfi);
1757  auto const w_arr = fields[5]->const_array(mfi);
1758 
1759  ParallelFor(Gpu::KernelInfo().setReduction(true), bx, [=]
1760  AMREX_GPU_DEVICE(int i, int j, int k, Gpu::Handler const& handler) noexcept
1761  {
1762  // Area-weighted averaging over cut cells at any k
1763  if (flag_arr(i,j,k).isSingleValued()) {
1764  // Compute area from face-centered area fractions
1765  Real axm = afrac_x(i ,j ,k );
1766  Real axp = afrac_x(i+1,j ,k );
1767  Real aym = afrac_y(i ,j ,k );
1768  Real ayp = afrac_y(i ,j+1,k );
1769  Real azm = afrac_z(i ,j ,k );
1770  Real azp = afrac_z(i ,j ,k+1);
1771 
1772  Real adx = (axm - axp) * dy * dz;
1773  Real ady = (aym - ayp) * dx * dz;
1774  Real adz = (azm - azp) * dx * dy;
1775 
1776  Real area = std::sqrt(adx*adx + ady*ady + adz*adz);
1777 
1778  // Volume-weighted interpolation of velocities to cell center
1779  Real vf_u_lo = u_vf_arr(i,j,k);
1780  Real vf_u_hi = u_vf_arr(i+1,j,k);
1781  Real sum_vf_u = vf_u_lo + vf_u_hi;
1782  Real u_cc = (sum_vf_u > zero) ? (u_arr(i,j,k)*vf_u_lo + u_arr(i+1,j,k)*vf_u_hi) / sum_vf_u : zero;
1783 
1784  Real vf_v_lo = v_vf_arr(i,j,k);
1785  Real vf_v_hi = v_vf_arr(i,j+1,k);
1786  Real sum_vf_v = vf_v_lo + vf_v_hi;
1787  Real v_cc = (sum_vf_v > zero) ? (v_arr(i,j,k)*vf_v_lo + v_arr(i,j+1,k)*vf_v_hi) / sum_vf_v : zero;
1788 
1789  Real vf_w_lo = w_vf_arr(i,j,k);
1790  Real vf_w_hi = w_vf_arr(i,j,k+1);
1791  Real sum_vf_w = vf_w_lo + vf_w_hi;
1792  Real w_cc = (sum_vf_w > zero) ? (w_arr(i,j,k)*vf_w_lo + w_arr(i,j,k+1)*vf_w_hi) / sum_vf_w : zero;
1793 
1794  // Get normal vector components
1795  Real nx = bnorm_arr(i,j,k,0);
1796  Real ny = bnorm_arr(i,j,k,1);
1797  Real nz = bnorm_arr(i,j,k,2);
1798 
1799  // Compute tangential velocity components
1800  Real v_dot_n = u_cc*nx + v_cc*ny + w_cc*nz;
1801  Real u_tangent = u_cc - v_dot_n * nx;
1802  Real v_tangent = v_cc - v_dot_n * ny;
1803  Real mag = std::sqrt(u_tangent*u_tangent + v_tangent*v_tangent + Vsg*Vsg);
1804 
1805  // Area-weighted sum
1806  Real val_u = u_tangent * area;
1807  Real val_v = v_tangent * area;
1808  Real val_mag = mag * area;
1809 
1810  Gpu::deviceReduceSum(&plane_avg[0], val_u, handler);
1811  Gpu::deviceReduceSum(&plane_avg[1], val_v, handler);
1812  Gpu::deviceReduceSum(&plane_avg[iavg], val_mag, handler);
1813  }
1814  });
1815  }
1816  }
1817 
1818  //
1819  //----------------------------------------------------------
1820  // Averages for T,Qv (cell-centered scalars)
1821  //----------------------------------------------------------
1822  //
1823  for (int imf(2); imf < 4; ++imf) {
1824 
1825  // Continue if no valid Qv pointer
1826  if (!fields[imf]) continue;
1827 
1828  denom[imf] = one / m_total_bndry_area[lev][imf];
1829  val_old[imf] = plane_average[imf]*d_fact_old;
1830 
1831 #ifdef _OPENMP
1832 #pragma omp parallel if (Gpu::notInLaunchRegion())
1833 #endif
1834  for (MFIter mfi(*fields[imf], TileNoZ()); mfi.isValid(); ++mfi) {
1835  const auto& flag = cc_flags[mfi];
1836 
1837  // Skip boxes that are not singlevalued (MultiCutFab only has data for singlevalued boxes)
1838  if (flag.getType() != FabType::singlevalued) continue;
1839 
1840  Box bx = mfi.tilebox(); // Full 3D box
1841  auto const flag_arr = flag.const_array();
1842  auto const afrac_x = cc_afrac[0]->const_array(mfi);
1843  auto const afrac_y = cc_afrac[1]->const_array(mfi);
1844  auto const afrac_z = cc_afrac[2]->const_array(mfi);
1845  auto const mf_arr = fields[imf]->const_array(mfi);
1846 
1847  ParallelFor(Gpu::KernelInfo().setReduction(true), bx, [=]
1848  AMREX_GPU_DEVICE(int i, int j, int k, Gpu::Handler const& handler) noexcept
1849  {
1850  // Area-weighted averaging over cut cells at any k
1851  if (flag_arr(i,j,k).isSingleValued()) {
1852  // Compute area from face-centered area fractions
1853  Real axm = afrac_x(i ,j ,k );
1854  Real axp = afrac_x(i+1,j ,k );
1855  Real aym = afrac_y(i ,j ,k );
1856  Real ayp = afrac_y(i ,j+1,k );
1857  Real azm = afrac_z(i ,j ,k );
1858  Real azp = afrac_z(i ,j ,k+1);
1859 
1860  Real adx = (axm - axp) * dy * dz;
1861  Real ady = (aym - ayp) * dx * dz;
1862  Real adz = (azm - azp) * dx * dy;
1863 
1864  Real area = std::sqrt(adx*adx + ady*ady + adz*adz);
1865 
1866  Real val = mf_arr(i,j,k) * area;
1867  Gpu::deviceReduceSum(&plane_avg[imf], val, handler);
1868  }
1869  });
1870  }
1871  }
1872 
1873  //
1874  //------------------------------------------------------------------------
1875  // Averages for virtual potential temperature
1876  //------------------------------------------------------------------------
1877  //
1878  if (fields[3]) // We have water vapor
1879  {
1880  int iavg = 4;
1881  denom[iavg] = one / m_total_bndry_area[lev][iavg];
1882  val_old[iavg] = plane_average[iavg]*d_fact_old;
1883 
1884 #ifdef _OPENMP
1885 #pragma omp parallel if (Gpu::notInLaunchRegion())
1886 #endif
1887  for (MFIter mfi(*fields[3], TileNoZ()); mfi.isValid(); ++mfi)
1888  {
1889  const auto& flag = cc_flags[mfi];
1890 
1891  // Skip boxes that are not singlevalued (MultiCutFab only has data for singlevalued boxes)
1892  if (flag.getType() != FabType::singlevalued) continue;
1893 
1894  Box bx = mfi.tilebox(); // Full 3D box
1895  auto const flag_arr = flag.const_array();
1896  auto const afrac_x = cc_afrac[0]->const_array(mfi);
1897  auto const afrac_y = cc_afrac[1]->const_array(mfi);
1898  auto const afrac_z = cc_afrac[2]->const_array(mfi);
1899 
1900  const Array4<Real const> T_mf_arr = fields[2]->const_array(mfi);
1901  const Array4<Real const> qv_mf_arr = fields[3]->const_array(mfi);
1902  const Array4<Real const> qr_mf_arr = (fields[4]) ? fields[4]->const_array(mfi) :
1903  Array4<const Real> {};
1904 
1905  ParallelFor(Gpu::KernelInfo().setReduction(true), bx, [=]
1906  AMREX_GPU_DEVICE(int i, int j, int k, Gpu::Handler const& handler) noexcept
1907  {
1908  if (flag_arr(i,j,k).isSingleValued()) {
1909  // Compute area from face-centered area fractions
1910  Real axm = afrac_x(i ,j ,k );
1911  Real axp = afrac_x(i+1,j ,k );
1912  Real aym = afrac_y(i ,j ,k );
1913  Real ayp = afrac_y(i ,j+1,k );
1914  Real azm = afrac_z(i ,j ,k );
1915  Real azp = afrac_z(i ,j ,k+1);
1916 
1917  Real adx = (axm - axp) * dy * dz;
1918  Real ady = (aym - ayp) * dx * dz;
1919  Real adz = (azm - azp) * dx * dy;
1920 
1921  Real area = std::sqrt(adx*adx + ady*ady + adz*adz);
1922 
1923  Real vfac;
1924  if (qr_mf_arr) {
1925  // We also have liquid water
1926  vfac = one + epsv*qv_mf_arr(i,j,k) - qr_mf_arr(i,j,k);
1927  } else {
1928  vfac = one + epsv*qv_mf_arr(i,j,k);
1929  }
1930  const Real val = T_mf_arr(i,j,k) * vfac * area;
1931  Gpu::deviceReduceSum(&plane_avg[iavg], val, handler);
1932  }
1933  });
1934  }
1935  }
1936  else // copy temperature
1937  {
1938  int iavg = m_navg - 2;
1939  denom[iavg] = one / m_total_bndry_area[lev][iavg];
1940  // plane_avg[iavg] = plane_avg[2]
1941  Gpu::copy(Gpu::deviceToDevice, pavg.begin() + 2, pavg.begin() + 3,
1942  pavg.begin() + iavg);
1943  }
1944 
1945  // Copy to host and sum across procs
1946  Gpu::copy(Gpu::deviceToHost, pavg.begin(), pavg.end(), plane_average.begin());
1947  ParallelDescriptor::ReduceRealSum(plane_average.data(), plane_average.size());
1948 
1949  // Normalize by total area and apply time averaging
1950  for (int iavg(0); iavg < m_navg; ++iavg){
1951  plane_average[iavg] *= denom[iavg]*d_fact_new;
1952  plane_average[iavg] += val_old[iavg];
1953  averages[iavg]->setVal(plane_average[iavg]);
1954  }
1955 }
constexpr amrex::Real epsv
Definition: ERF_Constants.H:53
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
Real vfac
Definition: ERF_InitCustomPertVels_ABL.H:42
const Real dy
Definition: ERF_InitCustomPert_ABL.H:45
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
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_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
int m_navg
Definition: ERF_MOSTAverage.H:415
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > m_averages
Definition: ERF_MOSTAverage.H:426
amrex::Vector< amrex::Vector< amrex::Real > > m_total_bndry_area
Definition: ERF_MOSTAverage.H:448
amrex::Vector< amrex::Real > m_Vsg
Definition: ERF_MOSTAverage.H:460
amrex::Vector< amrex::Vector< amrex::Real > > m_plane_average
Definition: ERF_MOSTAverage.H:432
amrex::Real m_fact_new
Definition: ERF_MOSTAverage.H:455
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_fields
Definition: ERF_MOSTAverage.H:406
amrex::Vector< const eb_ * > m_eb_vec
Definition: ERF_MOSTAverage.H:447
amrex::Real m_fact_old
Definition: ERF_MOSTAverage.H:455
const amrex::Vector< amrex::Geometry > m_geom
Definition: ERF_MOSTAverage.H:405
@ dz
Definition: ERF_AdvanceWDM6.cpp:270

Referenced by compute_averages().

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

◆ compute_plane_averages()

void MOSTAverage::compute_plane_averages ( const int &  lev)

Fill averages for the plane policy.

Parameters
[in]levlevel index

Function to compute average over a plane.

Parameters
[in]levCurrent level
1000 {
1001  // Peel back the level
1002  auto& fields = m_fields[lev];
1003  auto& rot_fields = m_rot_fields[lev];
1004  auto& averages = m_averages[lev];
1005  const auto & geom = m_geom[lev];
1006 
1007  auto& z_phys = m_z_phys_nd[lev];
1008  auto& x_pos = m_x_pos[lev];
1009  auto& y_pos = m_y_pos[lev];
1010  auto& z_pos = m_z_pos[lev];
1011 
1012  auto& i_indx = m_i_indx[lev];
1013  auto& j_indx = m_j_indx[lev];
1014  auto& k_indx = m_k_indx[lev];
1015 
1016  auto& ncell_plane = m_ncell_plane[lev];
1017  auto& plane_average = m_plane_average[lev];
1018 
1019  // Set factors for time averaging
1020  Real d_fact_new, d_fact_old;
1021  if (m_t_avg && m_t_init[lev]) {
1022  d_fact_new = m_fact_new;
1023  d_fact_old = m_fact_old;
1024  } else {
1025  d_fact_new = one;
1026  d_fact_old = zero;
1027  }
1028 
1029  int klo = m_geom[lev].Domain().smallEnd(2);
1030 
1031  // GPU array to accumulate averages into
1032  Gpu::DeviceVector<Real> pavg(plane_average.size(), zero);
1033  Real* plane_avg = pavg.data();
1034 
1035  // Vectors for normalization and buffer storage
1036  Vector<Real> denom(plane_average.size(),zero);
1037  Vector<Real> val_old(plane_average.size(),zero);
1038 
1039  //
1040  //----------------------------------------------------------
1041  // Averages over all the fields
1042  //----------------------------------------------------------
1043  //
1044  Box domain = geom.Domain();
1045 
1046  Array<int,AMREX_SPACEDIM> is_per = {0,0,0};
1047  for (int idim(0); idim < AMREX_SPACEDIM-1; ++idim) {
1048  if (geom.isPeriodic(idim)) is_per[idim] = 1;
1049  }
1050 
1051  // Averages for U,V,T,Qv (not Qc or W)
1052  for (int imf(0); imf < 4; ++imf) {
1053 
1054  // Continue if no valid Qv pointer
1055  if (!fields[imf]) continue;
1056 
1057  denom[imf] = one / (Real)ncell_plane[imf];
1058  val_old[imf] = plane_average[imf]*d_fact_old;
1059 
1060 #ifdef _OPENMP
1061 #pragma omp parallel if (Gpu::notInLaunchRegion())
1062 #endif
1063  for (MFIter mfi(*fields[imf], TileNoZ()); mfi.isValid(); ++mfi) {
1064  Box vbx = mfi.validbox(); // This is the grid (not tile)
1065  Box pbx = mfi.tilebox(); // This is the tile (not grid)
1066 
1067  if (pbx.smallEnd(2) != klo) { continue; }
1068 
1069  // Make planar since mfiter is over fields
1070  pbx.makeSlab(2,klo);
1071 
1072  // Avoid double counting nodal data by changing the high end when we are
1073  // at the high side of the grid (not just of the tile)
1074  IndexType ixt = averages[imf]->boxArray().ixType();
1075  for (int idim(0); idim < AMREX_SPACEDIM-1; ++idim) {
1076  if ( ixt.nodeCentered(idim) && (pbx.bigEnd(idim) == vbx.bigEnd(idim)) ) {
1077  int dom_hi = domain.bigEnd(idim)+1;
1078  if (pbx.bigEnd(idim) < dom_hi || is_per[idim]) {
1079  pbx.growHi(idim,-1);
1080  }
1081  }
1082  }
1083 
1084  auto mf_arr = (m_rotate) ? rot_fields[imf]->const_array(mfi) :
1085  fields[imf]->const_array(mfi);
1086 
1087  if (m_interp) {
1088  const auto plo = geom.ProbLoArray();
1089  const auto dxInv = geom.InvCellSizeArray();
1090  const auto z_phys_arr = z_phys->const_array(mfi);
1091  auto x_pos_arr = x_pos->array(mfi);
1092  auto y_pos_arr = y_pos->array(mfi);
1093  auto z_pos_arr = z_pos->array(mfi);
1094  ParallelFor(Gpu::KernelInfo().setReduction(true), pbx, [=]
1095  AMREX_GPU_DEVICE(int i, int j, int , Gpu::Handler const& handler) noexcept
1096  {
1097  Real interp{0};
1098  trilinear_interp_T(x_pos_arr(i,j,0), y_pos_arr(i,j,0), z_pos_arr(i,j,0),
1099  &interp, mf_arr, z_phys_arr, plo, dxInv, 1);
1100  Real val = interp;
1101  Gpu::deviceReduceSum(&plane_avg[imf], val, handler);
1102  });
1103  } else {
1104  auto k_arr = k_indx->const_array(mfi);
1105  auto j_arr = j_indx ? j_indx->const_array(mfi) : Array4<const int> {};
1106  auto i_arr = i_indx ? i_indx->const_array(mfi) : Array4<const int> {};
1107  ParallelFor(Gpu::KernelInfo().setReduction(true), pbx, [=]
1108  AMREX_GPU_DEVICE(int i, int j, int , Gpu::Handler const& handler) noexcept
1109  {
1110  int mk = k_arr(i,j,0);
1111  int mj = j_arr ? j_arr(i,j,0) : j;
1112  int mi = i_arr ? i_arr(i,j,0) : i;
1113  Real val = mf_arr(mi,mj,mk);
1114  Gpu::deviceReduceSum(&plane_avg[imf], val, handler);
1115  });
1116  }
1117  }
1118  }
1119 
1120  //
1121  //------------------------------------------------------------------------
1122  // Averages for virtual potential temperature
1123  // (This is cell-centered so we don't need to worry about double-counting)
1124  //------------------------------------------------------------------------
1125  //
1126  if (fields[3]) // We have water vapor
1127  {
1128  int iavg = 4;
1129  denom[iavg] = one / (Real)ncell_plane[iavg];
1130  val_old[iavg] = plane_average[iavg]*d_fact_old;
1131 
1132 #ifdef _OPENMP
1133 #pragma omp parallel if (Gpu::notInLaunchRegion())
1134 #endif
1135  for (MFIter mfi(*fields[3], TileNoZ()); mfi.isValid(); ++mfi)
1136  {
1137  Box pbx = mfi.tilebox();
1138 
1139  if (pbx.smallEnd(2) != klo) { continue; }
1140 
1141  pbx.makeSlab(2,klo);
1142 
1143  const Array4<Real const>& T_mf_arr = fields[2]->const_array(mfi);
1144  const Array4<Real const>& qv_mf_arr = fields[3]->const_array(mfi);
1145  const Array4<Real const>& qr_mf_arr = (fields[4]) ? fields[4]->const_array(mfi) :
1146  Array4<const Real> {};
1147 
1148  if (m_interp) {
1149  const auto plo = m_geom[lev].ProbLoArray();
1150  const auto dxInv = m_geom[lev].InvCellSizeArray();
1151  const auto z_phys_arr = z_phys->const_array(mfi);
1152  auto x_pos_arr = x_pos->array(mfi);
1153  auto y_pos_arr = y_pos->array(mfi);
1154  auto z_pos_arr = z_pos->array(mfi);
1155  ParallelFor(Gpu::KernelInfo().setReduction(true), pbx, [=]
1156  AMREX_GPU_DEVICE(int i, int j, int , Gpu::Handler const& handler) noexcept
1157  {
1158  Real T_interp{0};
1159  Real qv_interp{0};
1160  trilinear_interp_T(x_pos_arr(i,j,0), y_pos_arr(i,j,0), z_pos_arr(i,j,0),
1161  &T_interp, T_mf_arr, z_phys_arr, plo, dxInv, 1);
1162  trilinear_interp_T(x_pos_arr(i,j,0), y_pos_arr(i,j,0), z_pos_arr(i,j,0),
1163  &qv_interp, qv_mf_arr, z_phys_arr, plo, dxInv, 1);
1164  Real vfac;
1165  if (qr_mf_arr) {
1166  // We also have liquid water
1167  Real qr_interp{0};
1168  trilinear_interp_T(x_pos_arr(i,j,0), y_pos_arr(i,j,0), z_pos_arr(i,j,0),
1169  &qr_interp, qr_mf_arr, z_phys_arr, plo, dxInv, 1);
1170  vfac = one + epsv*qv_interp - qr_interp;
1171  } else {
1172  vfac = one + epsv*qv_interp;
1173  }
1174  const Real val = T_interp * vfac;
1175  Gpu::deviceReduceSum(&plane_avg[iavg], val, handler);
1176  });
1177  } else {
1178  auto k_arr = k_indx->const_array(mfi);
1179  auto j_arr = j_indx ? j_indx->const_array(mfi) : Array4<const int> {};
1180  auto i_arr = i_indx ? i_indx->const_array(mfi) : Array4<const int> {};
1181  ParallelFor(Gpu::KernelInfo().setReduction(true), pbx, [=]
1182  AMREX_GPU_DEVICE(int i, int j, int , Gpu::Handler const& handler) noexcept
1183  {
1184  int mk = k_arr(i,j,0);
1185  int mj = j_arr ? j_arr(i,j,0) : j;
1186  int mi = i_arr ? i_arr(i,j,0) : i;
1187  Real vfac;
1188  if (qr_mf_arr) {
1189  // We also have liquid water
1190  vfac = one + epsv*qv_mf_arr(mi,mj,mk) - qr_mf_arr(mi,mj,mk);
1191  } else {
1192  vfac = one + epsv*qv_mf_arr(mi,mj,mk);
1193  }
1194  const Real val = T_mf_arr(mi,mj,mk) * vfac;
1195  Gpu::deviceReduceSum(&plane_avg[iavg], val, handler);
1196  });
1197  }
1198  }
1199  }
1200  else // copy temperature
1201  {
1202  int iavg = m_navg - 2;
1203  denom[iavg] = one / (Real)ncell_plane[iavg];
1204  // plane_avg[iavg] = plane_avg[2]
1205  Gpu::copy(Gpu::deviceToDevice, pavg.begin() + 2, pavg.begin() + 3,
1206  pavg.begin() + iavg);
1207  }
1208 
1209  //
1210  //------------------------------------------------------------------------
1211  // Averages for the tangential velocity magnitude
1212  // (This is cell-centered so we don't need to worry about double-counting)
1213  //------------------------------------------------------------------------
1214  //
1215  {
1216  int imf_cc = 2;
1217  int imf = 0;
1218  int iavg = m_navg - 1;
1219  denom[iavg] = one / (Real)ncell_plane[iavg];
1220  val_old[iavg] = plane_average[iavg]*d_fact_old;
1221 
1222  const Real Vsg = m_Vsg[lev];
1223 
1224 #ifdef _OPENMP
1225 #pragma omp parallel if (Gpu::notInLaunchRegion())
1226 #endif
1227  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi)
1228  {
1229  Box pbx = mfi.tilebox();
1230 
1231  if (pbx.smallEnd(2) != klo) { continue; }
1232 
1233  pbx.makeSlab(2,klo);
1234 
1235  // Last element is Umag and always cell centered
1236  auto u_mf_arr = (m_rotate) ? rot_fields[imf ]->const_array(mfi) :
1237  fields[imf ]->const_array(mfi);
1238  auto v_mf_arr = (m_rotate) ? rot_fields[imf+1]->const_array(mfi) :
1239  fields[imf+1]->const_array(mfi);
1240 
1241  if (m_interp) {
1242  const auto plo = m_geom[lev].ProbLoArray();
1243  const auto dxInv = m_geom[lev].InvCellSizeArray();
1244  const auto z_phys_arr = z_phys->const_array(mfi);
1245  auto x_pos_arr = x_pos->array(mfi);
1246  auto y_pos_arr = y_pos->array(mfi);
1247  auto z_pos_arr = z_pos->array(mfi);
1248  ParallelFor(Gpu::KernelInfo().setReduction(true), pbx, [=]
1249  AMREX_GPU_DEVICE(int i, int j, int , Gpu::Handler const& handler) noexcept
1250  {
1251  Real u_interp{0};
1252  Real v_interp{0};
1253  trilinear_interp_T(x_pos_arr(i,j,0), y_pos_arr(i,j,0), z_pos_arr(i,j,0),
1254  &u_interp, u_mf_arr, z_phys_arr, plo, dxInv, 1);
1255  trilinear_interp_T(x_pos_arr(i,j,0), y_pos_arr(i,j,0), z_pos_arr(i,j,0),
1256  &v_interp, v_mf_arr, z_phys_arr, plo, dxInv, 1);
1257  const Real val = std::sqrt(u_interp*u_interp + v_interp*v_interp + Vsg*Vsg);
1258  Gpu::deviceReduceSum(&plane_avg[iavg], val, handler);
1259  });
1260  } else {
1261  auto k_arr = k_indx->const_array(mfi);
1262  auto j_arr = j_indx ? j_indx->const_array(mfi) : Array4<const int> {};
1263  auto i_arr = i_indx ? i_indx->const_array(mfi) : Array4<const int> {};
1264  ParallelFor(Gpu::KernelInfo().setReduction(true), pbx, [=]
1265  AMREX_GPU_DEVICE(int i, int j, int , Gpu::Handler const& handler) noexcept
1266  {
1267  int mk = k_arr(i,j,0);
1268  int mj = j_arr ? j_arr(i,j,0) : j;
1269  int mi = i_arr ? i_arr(i,j,0) : i;
1270  const Real u_val = myhalf * (u_mf_arr(mi,mj,mk) + u_mf_arr(mi+1,mj ,mk));
1271  const Real v_val = myhalf * (v_mf_arr(mi,mj,mk) + v_mf_arr(mi ,mj+1,mk));
1272  const Real val = std::sqrt(u_val*u_val + v_val*v_val + Vsg*Vsg);
1273  Gpu::deviceReduceSum(&plane_avg[iavg], val, handler);
1274  });
1275  }
1276  }
1277  }
1278 
1279  // Copy to host and sum across procs
1280  Gpu::copy(Gpu::deviceToHost, pavg.begin(), pavg.end(), plane_average.begin());
1281  ParallelDescriptor::ReduceRealSum(plane_average.data(), static_cast<int>(plane_average.size()));
1282 
1283  // No spatial variation with plane averages
1284  for (int iavg(0); iavg < m_navg; ++iavg){
1285  plane_average[iavg] *= denom[iavg]*d_fact_new;
1286  plane_average[iavg] += val_old[iavg];
1287  averages[iavg]->setVal(plane_average[iavg]);
1288  }
1289 }
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
amrex::GpuArray< Real, AMREX_SPACEDIM > dxInv
Definition: ERF_InitCustomPertVels_ParticleTests.H:17
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_y_pos
Definition: ERF_MOSTAverage.H:421
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > m_i_indx
Definition: ERF_MOSTAverage.H:423
amrex::Vector< amrex::MultiFab * > m_z_phys_nd
Definition: ERF_MOSTAverage.H:407
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_x_pos
Definition: ERF_MOSTAverage.H:420
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > m_rot_fields
Definition: ERF_MOSTAverage.H:427
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_z_pos
Definition: ERF_MOSTAverage.H:422
amrex::Vector< amrex::Vector< int > > m_ncell_plane
Definition: ERF_MOSTAverage.H:431
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > m_j_indx
Definition: ERF_MOSTAverage.H:424
bool m_interp
Definition: ERF_MOSTAverage.H:442
AMREX_GPU_HOST_DEVICE static AMREX_INLINE void trilinear_interp_T(const amrex::Real &xp, const amrex::Real &yp, const amrex::Real &zp, amrex::Real *interp_vals, amrex::Array4< amrex::Real const > const &interp_array, amrex::Array4< amrex::Real const > const &z_arr, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &plo, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxi, const int interp_comp)
Definition: ERF_MOSTAverage.H:336
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > m_k_indx
Definition: ERF_MOSTAverage.H:425

Referenced by compute_averages().

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

◆ compute_region_averages()

void MOSTAverage::compute_region_averages ( const int &  lev)

Fill averages for the point or region policy.

Parameters
[in]levlevel index

Function to compute average over local region.

Parameters
[in]levCurrent level
1299 {
1300  // Peel back the level
1301  auto& fields = m_fields[lev];
1302  auto& rot_fields = m_rot_fields[lev];
1303  auto& averages = m_averages[lev];
1304  const auto & geom = m_geom[lev];
1305 
1306  auto& z_phys = m_z_phys_nd[lev];
1307  auto& x_pos = m_x_pos[lev];
1308  auto& y_pos = m_y_pos[lev];
1309  auto& z_pos = m_z_pos[lev];
1310 
1311  auto& i_indx = m_i_indx[lev];
1312  auto& j_indx = m_j_indx[lev];
1313  auto& k_indx = m_k_indx[lev];
1314 
1315  int klo = m_geom[lev].Domain().smallEnd(2);
1316 
1317  // Set factors for time averaging
1318  Real d_fact_new, d_fact_old;
1319  if (m_t_avg && m_t_init[lev]) {
1320  d_fact_new = m_fact_new;
1321  d_fact_old = m_fact_old;
1322  } else {
1323  d_fact_new = one;
1324  d_fact_old = zero;
1325  }
1326 
1327  // Number of cells contained in the local average
1328  const Real denom = one / (Real) m_ncell_region;
1329 
1330  // Capture radius for device
1331  int d_radius = m_radius;
1332 
1333  //
1334  //----------------------------------------------------------
1335  // Averages for U,V,T,Qv
1336  //----------------------------------------------------------
1337  //
1338  for (int imf(0); imf < 4; ++imf) {
1339 
1340  // Continue if no valid Qv pointer
1341  if (!fields[imf]) continue;
1342 
1343 #ifdef _OPENMP
1344 #pragma omp parallel if (Gpu::notInLaunchRegion())
1345 #endif
1346  for (MFIter mfi(*fields[imf], TileNoZ()); mfi.isValid(); ++mfi) {
1347  Box pbx = mfi.tilebox();
1348 
1349  if (pbx.smallEnd(2) != klo) { continue; }
1350 
1351  // Make planar since mfiter is over fields
1352  pbx.makeSlab(2,klo);
1353 
1354  auto mf_arr = (m_rotate) ? rot_fields[imf]->const_array(mfi) :
1355  fields[imf]->const_array(mfi);
1356  auto ma_arr = averages[imf]->array(mfi);
1357 
1358  if (m_interp) {
1359  const auto plo = geom.ProbLoArray();
1360  const auto dx = geom.CellSizeArray();
1361  const auto dxInv = geom.InvCellSizeArray();
1362  const auto z_phys_arr = z_phys->const_array(mfi);
1363  auto x_pos_arr = x_pos->array(mfi);
1364  auto y_pos_arr = y_pos->array(mfi);
1365  auto z_pos_arr = z_pos->array(mfi);
1366  ParallelFor(pbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1367  {
1368  ma_arr(i,j,0) *= d_fact_old;
1369 
1370  Real met_h_zeta = Compute_h_zeta_AtCellCenter(i,j,k,dxInv,z_phys_arr);
1371  for (int lk(-d_radius); lk <= (d_radius); ++lk) {
1372  for (int lj(-d_radius); lj <= (d_radius); ++lj) {
1373  for (int li(-d_radius); li <= (d_radius); ++li) {
1374  Real interp{0};
1375  Real xp = x_pos_arr(i+li,j+lj,0);
1376  Real yp = y_pos_arr(i+li,j+lj,0);
1377  Real zp = z_pos_arr(i+li,j+lj,0) + met_h_zeta*lk*dx[2];
1378  trilinear_interp_T(xp, yp, zp, &interp, mf_arr, z_phys_arr, plo, dxInv, 1);
1379  Real val = denom * interp * d_fact_new;
1380  ma_arr(i,j,0) += val;
1381  }
1382  }
1383  }
1384  });
1385  } else {
1386  auto k_arr = k_indx->const_array(mfi);
1387  auto j_arr = j_indx ? j_indx->const_array(mfi) : Array4<const int> {};
1388  auto i_arr = i_indx ? i_indx->const_array(mfi) : Array4<const int> {};
1389  ParallelFor(pbx, [=] AMREX_GPU_DEVICE(int i, int j, int ) noexcept
1390  {
1391  ma_arr(i,j,0) *= d_fact_old;
1392 
1393  int mk = k_arr(i,j,0);
1394  int mj = j_arr ? j_arr(i,j,0) : j;
1395  int mi = i_arr ? i_arr(i,j,0) : i;
1396  for (int lk(mk-d_radius); lk <= (mk+d_radius); ++lk) {
1397  for (int lj(mj-d_radius); lj <= (mj+d_radius); ++lj) {
1398  for (int li(mi-d_radius); li <= (mi+d_radius); ++li) {
1399  Real val = denom * mf_arr(li, lj, lk) * d_fact_new;
1400  ma_arr(i,j,0) += val;
1401  }
1402  }
1403  }
1404  });
1405  }
1406  } // MFiter
1407 
1408  // Fill interior ghost cells and any ghost cells outside a periodic domain
1409  //***********************************************************************************
1410  averages[imf]->FillBoundary(geom.periodicity());
1411 
1412  } // imf
1413 
1414  //
1415  //----------------------------------------------------------
1416  // Averages for virtual potential temperature
1417  //----------------------------------------------------------
1418  //
1419  if (fields[3]) // We have water vapor
1420  {
1421  int iavg = 4;
1422 
1423 #ifdef _OPENMP
1424 #pragma omp parallel if (Gpu::notInLaunchRegion())
1425 #endif
1426  for (MFIter mfi(*fields[3], TileNoZ()); mfi.isValid(); ++mfi) {
1427  Box pbx = mfi.tilebox();
1428 
1429  if (pbx.smallEnd(2) != klo) { continue; }
1430 
1431  pbx.makeSlab(2,klo);
1432 
1433  const Array4<Real const>& T_mf_arr = fields[2]->const_array(mfi);
1434  const Array4<Real const>& qv_mf_arr = fields[3]->const_array(mfi);
1435  const Array4<Real const>& qr_mf_arr = (fields[4]) ? fields[4]->const_array(mfi) :
1436  Array4<const Real> {};
1437  auto ma_arr = averages[iavg]->array(mfi);
1438 
1439  if (m_interp) {
1440  const auto plo = geom.ProbLoArray();
1441  const auto dx = geom.CellSizeArray();
1442  const auto dxInv = geom.InvCellSizeArray();
1443  const auto z_phys_arr = z_phys->const_array(mfi);
1444  auto x_pos_arr = x_pos->array(mfi);
1445  auto y_pos_arr = y_pos->array(mfi);
1446  auto z_pos_arr = z_pos->array(mfi);
1447  ParallelFor(pbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1448  {
1449  ma_arr(i,j,0) *= d_fact_old;
1450 
1451  Real met_h_zeta = Compute_h_zeta_AtCellCenter(i,j,k,dxInv,z_phys_arr);
1452  for (int lk(-d_radius); lk <= (d_radius); ++lk) {
1453  for (int lj(-d_radius); lj <= (d_radius); ++lj) {
1454  for (int li(-d_radius); li <= (d_radius); ++li) {
1455  Real T_interp{0};
1456  Real qv_interp{0};
1457  Real xp = x_pos_arr(i+li,j+lj,0);
1458  Real yp = y_pos_arr(i+li,j+lj,0);
1459  Real zp = z_pos_arr(i+li,j+lj,0) + met_h_zeta*lk*dx[2];
1460  trilinear_interp_T(xp, yp, zp, &T_interp, T_mf_arr, z_phys_arr, plo, dxInv, 1);
1461  trilinear_interp_T(xp, yp, zp, &qv_interp, qv_mf_arr, z_phys_arr, plo, dxInv, 1);
1462  Real vfac;
1463  if (qr_mf_arr) {
1464  // We also have liquid water
1465  Real qr_interp{0};
1466  trilinear_interp_T(x_pos_arr(i,j,0), y_pos_arr(i,j,0), z_pos_arr(i,j,0),
1467  &qr_interp, qr_mf_arr, z_phys_arr, plo, dxInv, 1);
1468  vfac = one + epsv*qv_interp - qr_interp;
1469  } else {
1470  vfac = one + epsv*qv_interp;
1471  }
1472  const Real mag = T_interp * vfac;
1473  const Real val = denom * mag * d_fact_new;
1474  ma_arr(i,j,0) += val;
1475  }
1476  }
1477  }
1478  });
1479  } else {
1480  auto k_arr = k_indx->const_array(mfi);
1481  auto j_arr = j_indx ? j_indx->const_array(mfi) : Array4<const int> {};
1482  auto i_arr = i_indx ? i_indx->const_array(mfi) : Array4<const int> {};
1483  ParallelFor(pbx, [=] AMREX_GPU_DEVICE(int i, int j, int ) noexcept
1484  {
1485  ma_arr(i,j,0) *= d_fact_old;
1486 
1487  int mk = k_arr(i,j,0);
1488  int mj = j_arr ? j_arr(i,j,0) : j;
1489  int mi = i_arr ? i_arr(i,j,0) : i;
1490  for (int lk(mk-d_radius); lk <= (mk+d_radius); ++lk) {
1491  for (int lj(mj-d_radius); lj <= (mj+d_radius); ++lj) {
1492  for (int li(mi-d_radius); li <= (mi+d_radius); ++li) {
1493  Real vfac;
1494  if (qr_mf_arr) {
1495  // We also have liquid water
1496  vfac = one + epsv*qv_mf_arr(li,lj,lk) - qr_mf_arr(li,lj,lk);
1497  } else {
1498  vfac = one + epsv*qv_mf_arr(li,lj,lk);
1499  }
1500  const Real mag = T_mf_arr(li,lj,lk) * vfac;
1501  const Real val = denom * mag * d_fact_new;
1502  ma_arr(i,j,0) += val;
1503  }
1504  }
1505  }
1506  });
1507  }
1508  } // MFiter
1509 
1510  // Fill interior ghost cells and any ghost cells outside a periodic domain
1511  //***********************************************************************************
1512  averages[iavg]->FillBoundary(geom.periodicity());
1513 
1514  }
1515  else // copy temperature
1516  {
1517  int iavg = m_navg - 2;
1518  IntVect ng = averages[iavg]->nGrowVect();
1519  MultiFab::Copy(*(averages[iavg]),*(averages[2]),0,0,1,ng);
1520  }
1521 
1522  //
1523  //----------------------------------------------------------
1524  // Averages for the tangential velocity magnitude
1525  //----------------------------------------------------------
1526  //
1527  {
1528  int imf_cc = 2;
1529  int imf = 0;
1530  int iavg = m_navg - 1;
1531 
1532  const Real Vsg = m_Vsg[lev];
1533 
1534 #ifdef _OPENMP
1535 #pragma omp parallel if (Gpu::notInLaunchRegion())
1536 #endif
1537  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
1538  Box pbx = mfi.tilebox();
1539 
1540  if (pbx.smallEnd(2) != klo) { continue; }
1541 
1542  pbx.makeSlab(2,klo);
1543 
1544  auto u_mf_arr = (m_rotate) ? rot_fields[imf ]->const_array(mfi) :
1545  fields[imf ]->const_array(mfi);
1546  auto v_mf_arr = (m_rotate) ? rot_fields[imf+1]->const_array(mfi) :
1547  fields[imf+1]->const_array(mfi);
1548  auto ma_arr = averages[iavg]->array(mfi);
1549 
1550  if (m_interp) {
1551  const auto plo = geom.ProbLoArray();
1552  const auto dx = geom.CellSizeArray();
1553  const auto dxInv = geom.InvCellSizeArray();
1554  const auto z_phys_arr = z_phys->const_array(mfi);
1555  auto x_pos_arr = x_pos->array(mfi);
1556  auto y_pos_arr = y_pos->array(mfi);
1557  auto z_pos_arr = z_pos->array(mfi);
1558  ParallelFor(pbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
1559  {
1560  ma_arr(i,j,0) *= d_fact_old;
1561 
1562  Real met_h_zeta = Compute_h_zeta_AtCellCenter(i,j,k,dxInv,z_phys_arr);
1563  for (int lk(-d_radius); lk <= (d_radius); ++lk) {
1564  for (int lj(-d_radius); lj <= (d_radius); ++lj) {
1565  for (int li(-d_radius); li <= (d_radius); ++li) {
1566  Real u_interp{0};
1567  Real v_interp{0};
1568  Real xp = x_pos_arr(i+li,j+lj,0);
1569  Real yp = y_pos_arr(i+li,j+lj,0);
1570  Real zp = z_pos_arr(i+li,j+lj,0) + met_h_zeta*lk*dx[2];
1571  trilinear_interp_T(xp, yp, zp, &u_interp, u_mf_arr, z_phys_arr, plo, dxInv, 1);
1572  trilinear_interp_T(xp, yp, zp, &v_interp, v_mf_arr, z_phys_arr, plo, dxInv, 1);
1573  const Real mag = std::sqrt(u_interp*u_interp + v_interp*v_interp + Vsg*Vsg);
1574  Real val = denom * mag * d_fact_new;
1575  ma_arr(i,j,0) += val;
1576  }
1577  }
1578  }
1579  });
1580  } else {
1581  auto k_arr = k_indx->const_array(mfi);
1582  auto j_arr = j_indx ? j_indx->const_array(mfi) : Array4<const int> {};
1583  auto i_arr = i_indx ? i_indx->const_array(mfi) : Array4<const int> {};
1584  ParallelFor(pbx, [=] AMREX_GPU_DEVICE(int i, int j, int ) noexcept
1585  {
1586  ma_arr(i,j,0) *= d_fact_old;
1587 
1588  int mk = k_arr(i,j,0);
1589  int mj = j_arr ? j_arr(i,j,0) : j;
1590  int mi = i_arr ? i_arr(i,j,0) : i;
1591  for (int lk(mk-d_radius); lk <= (mk+d_radius); ++lk) {
1592  for (int lj(mj-d_radius); lj <= (mj+d_radius); ++lj) {
1593  for (int li(mi-d_radius); li <= (mi+d_radius); ++li) {
1594  const Real u_val = myhalf * (u_mf_arr(li,lj,lk) + u_mf_arr(li+1,lj ,lk));
1595  const Real v_val = myhalf * (v_mf_arr(li,lj,lk) + v_mf_arr(li ,lj+1,lk));
1596  const Real mag = std::sqrt(u_val*u_val + v_val*v_val + Vsg*Vsg);
1597  Real val = denom * mag * d_fact_new;
1598  ma_arr(i,j,0) += val;
1599  }
1600  }
1601  }
1602  });
1603  }
1604  } // MFiter
1605 
1606  // Fill interior ghost cells and any ghost cells outside a periodic domain
1607  //***********************************************************************************
1608  averages[iavg]->FillBoundary(geom.periodicity());
1609 
1610  }
1611 
1612  // NOTE: Checking periodicity with the geom structure is not
1613  // sufficient at higher levels. The BA may be contained
1614  // within the domain and it's exterior ghost cells filled
1615  // from interpolation; yet the domain BCs are periodic.
1616 
1617  // Need to fill ghost cells outside the domain if not periodic
1618  bool not_per_x = !(geom.periodicity().isPeriodic(0));
1619  bool not_per_y = !(geom.periodicity().isPeriodic(1));
1620  Box cc_bnd_bx = (m_fields[lev][2]->boxArray()).minimalBox();
1621  Box domain = geom.Domain();
1622  if (domain.contains(cc_bnd_bx) || (not_per_x || not_per_y)) {
1623  for (int iavg(0); iavg < m_navg; ++iavg) {
1624  IntVect ng = averages[iavg]->nGrowVect(); ng[2]=0;
1625 
1626  // NOTE: Level 0 spans the whole domain, but finer
1627  // levels do not have such a restriction.
1628  // For now, use the bounding box of the boxArray.
1629 
1630  // NOTE2: The fields and averages have different indexing.
1631  // The averages are: U/V/T/Qv/Tv/Umag
1632  // The fields are: U/V/T/Qv/Qr/W
1633  // We clip iavg at 2 since all the remaining data is CC
1634 
1635  // Bounded box of CC data used for normalization
1636  int imf = min(iavg,2);
1637  Box bnd_bx = (fields[imf]->boxArray()).minimalBox();
1638 #ifdef _OPENMP
1639 #pragma omp parallel if (Gpu::notInLaunchRegion())
1640 #endif
1641  for (MFIter mfi(*fields[imf], TileNoZ()); mfi.isValid(); ++mfi) {
1642  Box gpbx = mfi.growntilebox(ng);
1643 
1644  if (gpbx.smallEnd(2) != klo) { continue; }
1645 
1646  gpbx.makeSlab(2,klo);
1647 
1648  if (bnd_bx.contains(gpbx)) continue;
1649 
1650  auto ma_arr = averages[iavg]->array(mfi);
1651 
1652  int i_lo = bnd_bx.smallEnd(0); int i_hi = bnd_bx.bigEnd(0);
1653  int j_lo = bnd_bx.smallEnd(1); int j_hi = bnd_bx.bigEnd(1);
1654  ParallelFor(gpbx, [=] AMREX_GPU_DEVICE(int i, int j, int ) noexcept
1655  {
1656  int li, lj;
1657  li = i < i_lo ? i_lo : i;
1658  li = li > i_hi ? i_hi : li;
1659  lj = j < j_lo ? j_lo : j;
1660  lj = lj > j_hi ? j_hi : lj;
1661 
1662  ma_arr(i,j,0) = ma_arr(li,lj,0);
1663  });
1664  } // MFiter
1665  } // iavg
1666  } // Not periodic
1667 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_zeta_AtCellCenter(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:179
int m_radius
Definition: ERF_MOSTAverage.H:436
int m_ncell_region
Definition: ERF_MOSTAverage.H:437
@ ng
Definition: ERF_Morrison.H:49

Referenced by compute_averages().

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

◆ do_time_averaging()

bool MOSTAverage::do_time_averaging ( ) const
inline

Return whether the averages are filtered in time (erf.most.time_average).

249 { return m_t_avg; }

Referenced by SurfaceLayer::mac_avg_is_time_averaged().

Here is the caller graph for this function:

◆ get_average() [1/2]

amrex::MultiFab* MOSTAverage::get_average ( const int &  lev,
const int &  comp 
)
inline

Return one 2D average MultiFab for modification (used to restore the exponential filter state from a checkpoint).

Parameters
[in]levlevel index
[in]compaverage component index
244 { return m_averages[lev][comp].get(); }

◆ get_average() [2/2]

const amrex::MultiFab* MOSTAverage::get_average ( const int &  lev,
const int &  comp 
) const
inline

Return one 2D average MultiFab.

Parameters
[in]levlevel index
[in]compaverage component index
235 { return m_averages[lev][comp].get(); }

Referenced by SurfaceLayer::get_mac_avg(), and SurfaceLayer::get_mac_avg_ptr().

Here is the caller graph for this function:

◆ get_k_indices()

const amrex::iMultiFab* MOSTAverage::get_k_indices ( const int &  lev) const
inline

Return the k-index iMultiFab.

Parameters
[in]levlevel index
320 { return m_k_indx[lev].get(); }

◆ get_navg()

int MOSTAverage::get_navg ( ) const
inline

Return the number of average components.

254 { return m_navg; }

Referenced by SurfaceLayer::get_num_mac_avg().

Here is the caller graph for this function:

◆ get_plane_average()

amrex::Vector<amrex::Real> MOSTAverage::get_plane_average ( const int &  lev) const
inline

Return the filtered plane averages, which hold the filter state for the plane and EB policies. The region policy holds its state in m_averages instead and never allocates these, in which case this is empty.

Parameters
[in]levlevel index
286  {
287  if (lev < static_cast<int>(m_plane_average.size())) { return m_plane_average[lev]; }
288  return amrex::Vector<amrex::Real>{};
289  }

Referenced by SurfaceLayer::get_mac_plane_avg().

Here is the caller graph for this function:

◆ get_zref()

amrex::MultiFab* MOSTAverage::get_zref ( const int &  lev) const
inline

Return z_ref, which may be computed from a specified k-index.

Parameters
[in]levlevel index
313 { return m_zref[lev].get(); }
amrex::Vector< std::unique_ptr< amrex::MultiFab > > m_zref
Definition: ERF_MOSTAverage.H:419

Referenced by SurfaceLayer::get_zref().

Here is the caller graph for this function:

◆ make_MOSTAverage_at_level()

void MOSTAverage::make_MOSTAverage_at_level ( const int &  lev,
const amrex::Vector< amrex::MultiFab * > &  vars_old,
std::unique_ptr< amrex::MultiFab > &  Theta_prim,
std::unique_ptr< amrex::MultiFab > &  Qv_prim,
std::unique_ptr< amrex::MultiFab > &  Qr_prim,
std::unique_ptr< amrex::MultiFab > &  z_phys_nd 
)

Make MOST-average data structures at one level.

Parameters
[in]levlevel index
[in]vars_oldold-time state and velocity fields
[in]Theta_primprimitive potential-temperature field
[in]Qv_primprimitive water-vapor field
[in]Qr_primprimitive rain-water field
[in]z_phys_ndnodal physical-height field

Make MOSTAverage data structures at one level.

Parameters
[in]levCurrent level
[in]vars_oldState data used by the average calculator
[in]Theta_primPrimitive theta component at this level
[in]Qv_primPrimitive water-vapor component at this level
[in]Qr_primPrimitive rain-water component at this level
[in]z_phys_ndNodal physical height at this level
117 {
118  m_fields[lev].resize(m_nvar);
119  m_rot_fields[lev].resize(m_nvar-1);
120  m_averages[lev].resize(m_navg);
121  m_z_phys_nd[lev] = z_phys_nd.get();
122 
123  bool use_terrain_fitted_coords = ( (m_terrain_type == TerrainType::StaticFittedMesh) ||
124  (m_terrain_type == TerrainType::MovingFittedMesh) );
125 
126  bool use_eb = (m_terrain_type == TerrainType::EB);
127 
128  { // Nodal in x
129  auto& mf = *vars_old[Vars::xvel];
130  // Create a 2D ba, dm, & ghost cells
131  const BoxArray& ba = mf.boxArray();
132  BoxList bl2d = ba.boxList();
133  for (auto& b : bl2d) { b.setRange(2,0); }
134  BoxArray ba2d(std::move(bl2d));
135  const DistributionMapping& dm = mf.DistributionMap();
136  const int ncomp = 1;
137  IntVect ng = mf.nGrowVect(); ng[2]=0;
138 
139  m_fields[lev][0] = vars_old[Vars::xvel];
140  m_averages[lev][0] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
141  m_averages[lev][0]->setVal(bogus_large_value);
142  if (m_rotate) {
143  m_rot_fields[lev][0] = std::make_unique<MultiFab>(ba,dm,ncomp,ng);
144  MultiFab::Copy(*m_rot_fields[lev][0],mf,0,0,1,ng);
145  } else {
146  m_rot_fields[lev][0] = nullptr;
147  }
148  }
149  { // Nodal in y
150  auto& mf = *vars_old[Vars::yvel];
151  // Create a 2D ba, dm, & ghost cells
152  const BoxArray& ba = mf.boxArray();
153  BoxList bl2d = ba.boxList();
154  for (auto& b : bl2d) { b.setRange(2,0); }
155  BoxArray ba2d(std::move(bl2d));
156  const DistributionMapping& dm = mf.DistributionMap();
157  const int ncomp = 1;
158  IntVect ng = mf.nGrowVect(); ng[2]=0;
159 
160  m_fields[lev][1] = vars_old[Vars::yvel];
161  m_averages[lev][1] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
162  m_averages[lev][1]->setVal(bogus_large_value);
163  if (m_rotate) {
164  m_rot_fields[lev][1] = std::make_unique<MultiFab>(ba,dm,ncomp,ng);
165  MultiFab::Copy(*m_rot_fields[lev][1],mf,0,0,1,ng);
166  } else {
167  m_rot_fields[lev][1] = nullptr;
168  }
169  }
170  { // CC vars
171  auto& mf = *Theta_prim;
172  // Create a 2D ba, dm, & ghost cells
173  const BoxArray& ba = mf.boxArray();
174  BoxList bl2d = ba.boxList();
175  for (auto& b : bl2d) { b.setRange(2,0); }
176  BoxArray ba2d(std::move(bl2d));
177  const DistributionMapping& dm = mf.DistributionMap();
178  const int ncomp = 1;
179  const int incomp = 1;
180  IntVect ng = mf.nGrowVect(); ng[2]=0;
181 
182  // Get field pointers
183  m_fields[lev][2] = Theta_prim.get();
184  m_fields[lev][3] = Qv_prim.get();
185  m_fields[lev][4] = Qr_prim.get();
186 
187  // Initialize remaining multifabs
188  for (int iavg(2); iavg < m_navg; ++iavg) {
189  m_averages[lev][iavg] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
190  m_averages[lev][iavg]->setVal(bogus_large_value);
191  }
192 
193  // Default to dry
194  m_averages[lev][3]->setVal(0.0);
195 
196  if (m_rotate) {
197  m_rot_fields[lev][2] = std::make_unique<MultiFab>(ba,dm,ncomp,ng);
198  m_rot_fields[lev][3] = std::make_unique<MultiFab>(ba,dm,ncomp,ng);
199  MultiFab::Copy(*m_rot_fields[lev][2],*Theta_prim,0,0,1,ng);
200  if (Qv_prim) MultiFab::Copy(*m_rot_fields[lev][3],*Qv_prim,0,0,1,ng);
201  } else {
202  m_rot_fields[lev][2] = nullptr;
203  m_rot_fields[lev][3] = nullptr;
204  }
205 
206  // Default zref to 10 and fill will true values later
207  m_zref[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ng);
208  m_zref[lev]->setVal(zref_default);
209 
210  if (use_terrain_fitted_coords && m_norm_vec && m_interp) {
211  m_x_pos[lev] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
212  m_y_pos[lev] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
213  m_z_pos[lev] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
214  } else if (use_terrain_fitted_coords && m_interp) {
215  m_x_pos[lev] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
216  m_y_pos[lev] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
217  m_z_pos[lev] = std::make_unique<MultiFab>(ba2d,dm,ncomp,ng);
218  } else if (use_terrain_fitted_coords && m_norm_vec) {
219  m_i_indx[lev] = std::make_unique<iMultiFab>(ba2d,dm,incomp,ng);
220  m_j_indx[lev] = std::make_unique<iMultiFab>(ba2d,dm,incomp,ng);
221  m_k_indx[lev] = std::make_unique<iMultiFab>(ba2d,dm,incomp,ng);
222  } else {
223  if (!use_eb) {
224  m_k_indx[lev] = std::make_unique<iMultiFab>(ba2d,dm,incomp,ng);
225  }
226  }
227  }
228  // Nodal in z (only used with terrain stress rotations)
229  m_fields[lev][5] = vars_old[Vars::zvel];
230 
231  // Setup auxiliary data for spatial configuration & policy
232  //--------------------------------------------------------
233  if (use_terrain_fitted_coords && m_norm_vec && m_interp) { // Terrain w/ norm & w/ interpolation
235  } else if (use_terrain_fitted_coords && m_interp) { // Terrain w/ interpolation
236  set_z_positions_T(lev);
237  } else if (use_terrain_fitted_coords && m_norm_vec) { // Terrain w/ norm & w/o interpolation
238  set_norm_indices_T(lev);
239  } else if (use_terrain_fitted_coords) { // Terrain
240  set_k_indices_T(lev);
241  } else if (use_eb) { // EB
242  set_z_positions_EB(lev);
243  } else { // No Terrain
244  set_k_indices_N(lev);
245  }
246 
247  // Setup normalization data for the chosen policy
248  //--------------------------------------------------------
249  switch(m_policy) {
250  case 0: // Plane average
252  break;
253  case 1: // Local region/point
255  break;
256  case 2: // EB
258  break;
259  default:
260  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(false, "Unknown policy for MOSTAverage!");
261  }
262 
263  // Set up the exponential time filtering
264  //--------------------------------------------------------
265  if (m_t_avg) {
266  // Exponential filter function
267  m_fact_old = static_cast<amrex::Real>(std::exp(-1.0 / m_time_window));
268 
269  // Enforce discrete normalization: (mfn*val_new + mfo*val_old)
271 
272  // None of the averages are initialized
273  m_t_init.resize(m_maxlev,0);
274 
275  // We have just (re)built the average containers at this level, so whatever
276  // filter history this level held is gone: m_averages holds bogus_large_value
277  // and set_plane_normalization has zeroed m_plane_average. Note that resize
278  // above does not touch existing entries, so this must be set explicitly or a
279  // regrid would blend the bogus values into the filtered average. On restart
280  // ReadCheckpointFileSurfaceLayer restores the state and sets this back to 1.
281  m_t_init[lev] = 0;
282  }
283 
284  // Correction to the mean surface velocity at this level
285  m_Vsg[lev] = zero;
286  if (include_subgrid_vel) {
287  Print() << "Subgrid velocity scale correction at level : " << lev << ' ';
288  const auto dxArr = m_geom[lev].CellSizeArray();
289  Real dx = std::sqrt(dxArr[0]*dxArr[1]);
290  if (dx > Real(5000.)) {
291  m_Vsg[lev] = Real(0.32) * std::pow(dx/Real(5000.)-1, Real(0.33));
292  }
293  Print() << m_Vsg[lev] << std::endl;
294  }
295 }
constexpr amrex::Real bogus_large_value
Definition: ERF_Constants.H:26
double m_time_window
Definition: ERF_MOSTAverage.H:454
void set_z_positions_EB(const int &lev)
Definition: ERF_MOSTAverage.cpp:597
void set_region_normalization(const int &)
Definition: ERF_MOSTAverage.H:126
void set_z_positions_T(const int &lev)
Definition: ERF_MOSTAverage.cpp:805
void set_norm_positions_T(const int &lev)
Definition: ERF_MOSTAverage.cpp:875
void set_k_indices_T(const int &lev)
Definition: ERF_MOSTAverage.cpp:625
void set_plane_normalization(const int &lev)
Definition: ERF_MOSTAverage.cpp:388
TerrainType m_terrain_type
Definition: ERF_MOSTAverage.H:410
bool m_norm_vec
Definition: ERF_MOSTAverage.H:443
int m_nvar
Definition: ERF_MOSTAverage.H:414
void set_norm_indices_T(const int &lev)
Definition: ERF_MOSTAverage.cpp:711
int m_maxlev
Definition: ERF_MOSTAverage.H:416
void set_eb_normalization(const int &lev)
Definition: ERF_MOSTAverage.cpp:446
bool include_subgrid_vel
Definition: ERF_MOSTAverage.H:459
void set_k_indices_N(const int &lev)
Definition: ERF_MOSTAverage.cpp:535
const amrex::Real zref_default
Definition: ERF_MOSTAverage.H:464
@ xvel
Definition: ERF_IndexDefines.H:215
@ zvel
Definition: ERF_IndexDefines.H:217
@ yvel
Definition: ERF_IndexDefines.H:216

Referenced by SurfaceLayer::make_SurfaceLayer_at_level().

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

◆ operator=() [1/2]

MOSTAverage& MOSTAverage::operator= ( const MOSTAverage other)
delete

Deleted copy-assignment operator.

Parameters
[in]othersource object

◆ operator=() [2/2]

MOSTAverage& MOSTAverage::operator= ( MOSTAverage &&  other)
deletenoexcept

Deleted move-assignment operator.

Parameters
[in]othersource object

◆ set_eb_normalization()

void MOSTAverage::set_eb_normalization ( const int &  lev)

Compute total embedded-boundary surface area.

Parameters
[in]levlevel index

Function to compute normalization for average over EB.

Parameters
[in]levCurrent level
447 {
448  AMREX_ALWAYS_ASSERT(m_eb_vec[lev] != nullptr);
449 
450  // Get EB data - need both cell-centered and face-centered flags
451  const auto& cc_flags = m_eb_vec[lev]->get_const_factory()->getMultiEBCellFlagFab();
452 
453  // Get area fractions for different centerings
454  auto cc_afrac = m_eb_vec[lev]->get_const_factory()->getAreaFrac(); // Cell-centered area fractions (Array of 3 MultiCutFab*)
455 
456  // Initialize storage
458  m_total_bndry_area[lev].resize(m_navg, zero);
459  m_plane_average.resize(m_maxlev);
460  m_plane_average[lev].resize(m_navg, zero);
461 
462  // Compute total area for each field type based on its centering
463  // iavg: 0=U(xface), 1=V(yface), 2=T(cc), 3=Qv(cc), 4=Tv(cc), 5=Umag(cc)
464 
465  // Get geometry for cell sizes
466  auto const& dx_arr = m_geom[lev].CellSizeArray();
467  Real dx = dx_arr[0];
468  Real dy = dx_arr[1];
469  Real dz = dx_arr[2];
470 
471  // GPU array to accumulate areas
472  Gpu::DeviceVector<Real> area_vec(m_navg, zero);
473  Real* area_device = area_vec.data();
474 
475  // All fields are now averaged on cell-centered grid
476  // Compute total area once on cell-centered grid and use for all iavg
477  Real total_area = zero;
478 #ifdef _OPENMP
479 #pragma omp parallel if (Gpu::notInLaunchRegion())
480 #endif
481  for (MFIter mfi(cc_flags, TileNoZ()); mfi.isValid(); ++mfi) {
482  const auto& flag = cc_flags[mfi];
483 
484  // Skip boxes that are not singlevalued (MultiCutFab only has data for singlevalued boxes)
485  if (flag.getType() != FabType::singlevalued) continue;
486 
487  Box bx = mfi.tilebox();
488  auto const flag_arr = flag.const_array();
489  auto const afrac_x = cc_afrac[0]->const_array(mfi);
490  auto const afrac_y = cc_afrac[1]->const_array(mfi);
491  auto const afrac_z = cc_afrac[2]->const_array(mfi);
492 
493  // Sum area only for cut cells using atomic reduction
494  ParallelFor(Gpu::KernelInfo().setReduction(true), bx, [=]
495  AMREX_GPU_DEVICE(int i, int j, int k, Gpu::Handler const& handler) noexcept
496  {
497  if (flag_arr(i,j,k).isSingleValued()) {
498  // Compute area from face-centered area fractions
499  Real axm = afrac_x(i ,j ,k );
500  Real axp = afrac_x(i+1,j ,k );
501  Real aym = afrac_y(i ,j ,k );
502  Real ayp = afrac_y(i ,j+1,k );
503  Real azm = afrac_z(i ,j ,k );
504  Real azp = afrac_z(i ,j ,k+1);
505 
506  Real adx = (axm - axp) * dy * dz;
507  Real ady = (aym - ayp) * dx * dz;
508  Real adz = (azm - azp) * dx * dy;
509 
510  Real area = std::sqrt(adx*adx + ady*ady + adz*adz);
511 
512  Gpu::deviceReduceSum(&area_device[0], area, handler);
513  }
514  });
515  }
516 
517  // Copy to host and sum across MPI ranks
518  Gpu::copy(Gpu::deviceToHost, area_vec.begin(), area_vec.begin() + 1, &total_area);
519  ParallelDescriptor::ReduceRealSum(&total_area, 1);
520 
521  // Set the same total area for all iavg
522  for (int iavg = 0; iavg < m_navg; ++iavg) {
523  m_total_bndry_area[lev][iavg] = total_area;
524  }
525 
526  Print() << "EB surface area on cell-centerd grid at level " << lev << ": " << total_area << std::endl;
527 }

Referenced by make_MOSTAverage_at_level().

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

◆ set_k_indices_N()

void MOSTAverage::set_k_indices_N ( const int &  lev)

Populate the 2D k-index iMultiFab without terrain.

Parameters
[in]levlevel index

Function to set K indices without terrain.

Parameters
[in]levCurrent level
536 {
537  ParmParse pp(m_pp_prefix);
538  // See zref_sentinel in ERF_MOSTAverage.H: probe with the sentinel and test the
539  // value, since queryAdd's return value stops meaning "user specified" after the
540  // first parse of the key and this routine runs once per level.
541  Real zref_tmp = zref_sentinel;
542  pp.queryAdd("most.zref",zref_tmp);
543  bool read_z = (zref_tmp > Real(0));
544  if (!read_z) { zref_tmp = zref_default; }
545  auto read_k = pp.queryarr("most.k_arr_in",m_k_in);
546 
547  // Default behavior is to use the first cell center
548  if (!read_z && !read_k) {
549  Real m_zlo = m_geom[0].ProbLo(2);
550  Real m_dz = m_geom[0].CellSize(2);
551  zref_tmp = m_zlo + myhalf * m_dz;
552  m_zref[lev]->setVal( zref_tmp );
553  Print() << "Reference height for MOST set to " << zref_tmp << std::endl;
554  read_z = true;
555  }
556 
557  // Specify z_ref & compute k_indx (z_ref takes precedence)
558  if (read_z) {
559  Real m_zlo = m_geom[lev].ProbLo(2);
560  Real m_zhi = m_geom[lev].ProbHi(2);
561  Real m_dz = m_geom[lev].CellSize(2);
562 
563  amrex::ignore_unused(m_zhi);
564 
565  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(zref_tmp >= m_zlo + myhalf * m_dz,
566  "Query point must be past first z-cell!");
567 
568  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(zref_tmp <= m_zhi - myhalf * m_dz,
569  "Query point must be below the last z-cell!");
570 
571  int lk = static_cast<int>(floor((zref_tmp - m_zlo) / m_dz - myhalf));
572 
573  m_zref[lev]->setVal( (lk + myhalf) * m_dz + m_zlo );
574 
576 
577  m_k_indx[lev]->setVal(lk);
578  // Specified k_indx & compute z_ref
579  } else if (read_k) {
581  "K index must be larger than averaging radius!");
582  m_k_indx[lev]->setVal(m_k_in[lev]);
583 
584  // TODO: check that z_ref is constant across levels
585  Real m_zlo = m_geom[0].ProbLo(2);
586  Real m_dz = m_geom[0].CellSize(2);
587  m_zref[lev]->setVal( ((Real)m_k_in[0] + myhalf) * m_dz + m_zlo );
588  }
589 }
ParmParse pp("prob")
const amrex::Real zref_sentinel
Definition: ERF_MOSTAverage.H:473
std::string m_pp_prefix
Definition: ERF_MOSTAverage.H:408
amrex::Vector< int > m_k_in
Definition: ERF_MOSTAverage.H:438

Referenced by make_MOSTAverage_at_level().

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

◆ set_k_indices_T()

void MOSTAverage::set_k_indices_T ( const int &  lev)

Populate the 2D k-index iMultiFab with terrain.

Parameters
[in]levlevel index

Function to set K indices with terrain (w/o terrain normals or interpolation).

Parameters
[in]levCurrent level
626 {
627  // Peel back the level
628  auto& fields = m_fields[lev];
629 
630  // MFIter over CC data
631  int imf_cc = 2;
632 
633  ParmParse pp(m_pp_prefix);
634  // See zref_sentinel in ERF_MOSTAverage.H: probe with the sentinel and test the
635  // value, since queryAdd's return value stops meaning "user specified" after the
636  // first parse of the key and this routine runs once per level.
637  Real zref_tmp = zref_sentinel;
638  pp.queryAdd("most.zref",zref_tmp);
639  bool read_z = (zref_tmp > Real(0));
640  auto read_k = pp.queryarr("most.k_arr_in",m_k_in);
641  int klo = m_geom[lev].Domain().smallEnd(2);
642 
643  // Allow default zref
644  if (!read_z) {
645  zref_tmp = zref_default;
646  Print() << "most.zref not specified, query distance default is " << zref_tmp << std::endl;
647  read_z = true;
648  }
649 
650  // No default behavior with terrain (we can't tell the difference between
651  // vertical grid stretching and true terrain)
652  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(read_z != read_k,
653  "Need to specify zref or k_arr_in for MOST");
654 
655  // Capture for device
656  Real d_zref = zref_tmp;
657  Real d_radius = static_cast<Real>(m_radius);
658  amrex::ignore_unused(d_radius);
659 
660  // Specify z_ref & compute k_indx (z_ref takes precedence)
661  if (read_z) {
662  int kmax = m_geom[lev].Domain().bigEnd(2);
663  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
664  Box npbx = mfi.tilebox(IntVect(1,1,0),IntVect(1,1,0));
665 
666  if (npbx.smallEnd(2) != klo) { continue; }
667 
668  npbx.makeSlab(2,klo);
669 
670  const auto z_phys_arr = m_z_phys_nd[lev]->const_array(mfi);
671  auto k_arr = m_k_indx[lev]->array(mfi);
672  auto zref_arr = m_zref[lev]->array(mfi);
673  ParallelFor(npbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
674  {
675  k_arr(i,j,k) = klo;
676  bool found = false;
677  Real z_bot_face = fourth * ( z_phys_arr(i ,j ,k) + z_phys_arr(i+1,j ,k)
678  + z_phys_arr(i ,j+1,k) + z_phys_arr(i+1,j+1,k) );
679  Real z_target = z_bot_face + d_zref;
680  for (int lk(klo); lk<=kmax; ++lk) {
681  Real z_lo = fourth * ( z_phys_arr(i,j ,lk ) + z_phys_arr(i+1,j ,lk )
682  + z_phys_arr(i,j+1,lk ) + z_phys_arr(i+1,j+1,lk ) );
683  Real z_hi = fourth * ( z_phys_arr(i,j ,lk+1) + z_phys_arr(i+1,j ,lk+1)
684  + z_phys_arr(i,j+1,lk+1) + z_phys_arr(i+1,j+1,lk+1) );
685  if (z_target > z_lo && z_target < z_hi){
686  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(lk >= d_radius,
687  "K index must be larger than averaging radius!");
688  k_arr(i,j,0) = lk;
689  zref_arr(i,j,0) = myhalf * (z_hi + z_lo) - z_bot_face;
690  found = true;
691  break;
692  }
693  }
695  "zref not found with terrain!");
696  });
697  }
698  // Specified k_indx & compute z_ref
699  } else if (read_k) {
700  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(false, "Specified k-indx with terrain not implemented!");
701  }
702 }
constexpr amrex::Real fourth
Definition: ERF_Constants.H:14

Referenced by make_MOSTAverage_at_level().

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

◆ set_norm_indices_T()

void MOSTAverage::set_norm_indices_T ( const int &  lev)

Populate all 2D normal-index iMultiFabs with terrain.

Parameters
[in]levlevel index

Function to set I,J,K indices with terrain normals (w/o interpolation).

Parameters
[in]levCurrent level
712 {
713  // Peel back the level
714  auto& fields = m_fields[lev];
715 
716  // MFIter over CC data
717  int imf_cc = 2;
718 
719  ParmParse pp(m_pp_prefix);
720  // See zref_sentinel in ERF_MOSTAverage.H: probe with the sentinel and test the
721  // value, since queryAdd's return value stops meaning "user specified" after the
722  // first parse of the key and this routine runs once per level.
723  Real zref_tmp = zref_sentinel;
724  pp.queryAdd("most.zref",zref_tmp);
725  bool read_zref = (zref_tmp > Real(0));
726  if (!read_zref) {
727  zref_tmp = zref_default;
728  Print() << "most.zref not specified, query distance default is " << zref_tmp << std::endl;
729  }
730  int klo = m_geom[lev].Domain().smallEnd(2);
731 
732  // Capture for device
733  Real d_zref = zref_tmp;
734  Real d_radius = static_cast<Real>(m_radius);
735 
736  const auto dxInv = m_geom[lev].InvCellSizeArray();
737  IntVect ng = m_k_indx[lev]->nGrowVect(); ng[2]=0;
738  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
739  Box npbx = mfi.tilebox(IntVect(1,1,0),IntVect(1,1,0));
740 
741  if (npbx.smallEnd(2) != klo) { continue; }
742 
743  int kmax = npbx.bigEnd(2);
744 
745  npbx.makeSlab(2,klo);
746 
747  const auto z_phys_arr = m_z_phys_nd[lev]->const_array(mfi);
748  auto i_arr = m_i_indx[lev]->array(mfi);
749  auto j_arr = m_j_indx[lev]->array(mfi);
750  auto k_arr = m_k_indx[lev]->array(mfi);
751  auto zref_arr = m_zref[lev]->array(mfi);
752  ParallelFor(npbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
753  {
754  // Elements of normal vector
755  Real met_h_xi = Compute_h_xi_AtCellCenter (i,j,k,dxInv,z_phys_arr);
756  Real met_h_eta = Compute_h_eta_AtCellCenter(i,j,k,dxInv,z_phys_arr);
757  Real mag = std::sqrt(met_h_xi*met_h_xi + met_h_eta*met_h_eta + one);
758 
759  // Unit-normal vector scaled by z_ref
760  Real delta_x = -met_h_xi/mag * d_zref;
761  Real delta_y = -met_h_eta/mag * d_zref;
762  Real delta_z = one/mag * d_zref;
763 
764  // Compute i & j as displacements (no grid stretching)
765  int delta_i = static_cast<int>(std::round(delta_x*dxInv[0]));
766  int delta_j = static_cast<int>(std::round(delta_y*dxInv[1]));
767  int i_new = i + delta_i;
768  int j_new = j + delta_j;
769  i_arr(i,j,0) = i_new;
770  j_arr(i,j,0) = j_new;
771 
772  // Search for k (grid is stretched in z)
773  Real z_bot_face = fourth * ( z_phys_arr(i ,j ,k) + z_phys_arr(i+1,j ,k)
774  + z_phys_arr(i ,j+1,k) + z_phys_arr(i+1,j+1,k) );
775  Real z_target = z_bot_face + delta_z;
776  k_arr(i,j,0) = klo;
777  zref_arr(i,j,0) = myhalf * z_bot_face +
778  Real(0.125) * ( z_phys_arr(i ,j ,k+1) + z_phys_arr(i+1,j ,k+1)
779  + z_phys_arr(i ,j+1,k+1) + z_phys_arr(i+1,j+1,k+1) );
780  for (int lk(klo); lk<=kmax; ++lk) {
781  Real z_lo = fourth * ( z_phys_arr(i_new,j_new ,lk ) + z_phys_arr(i_new+1,j_new ,lk )
782  + z_phys_arr(i_new,j_new+1,lk ) + z_phys_arr(i_new+1,j_new+1,lk ) );
783  Real z_hi = fourth * ( z_phys_arr(i_new,j_new ,lk+1) + z_phys_arr(i_new+1,j_new ,lk+1)
784  + z_phys_arr(i_new,j_new+1,lk+1) + z_phys_arr(i_new+1,j_new+1,lk+1) );
785  if (z_target > z_lo && z_target < z_hi){
786  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(lk >= d_radius,
787  "K index must be larger than averaging radius!");
788  amrex::ignore_unused(d_radius);
789  k_arr(i,j,0) = lk;
790  zref_arr(i,j,0) = myhalf * (z_hi + z_lo) - z_bot_face;
791  break;
792  }
793  }
794  });
795  }
796 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_xi_AtCellCenter(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:204
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_eta_AtCellCenter(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:229

Referenced by make_MOSTAverage_at_level().

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

◆ set_norm_positions_T()

void MOSTAverage::set_norm_positions_T ( const int &  lev)

Populate terrain-aware normal positions.

Parameters
[in]levlevel index

Function to set positions with terrain and normal vector (with interpolation).

Parameters
[in]levCurrent level
876 {
877  // Peel back the level
878  auto& fields = m_fields[lev];
879 
880  // MFIter over CC data
881  int imf_cc = 2;
882 
883  ParmParse pp(m_pp_prefix);
884  // See zref_sentinel in ERF_MOSTAverage.H: probe with the sentinel and test the
885  // value, since queryAdd's return value stops meaning "user specified" after the
886  // first parse of the key and this routine runs once per level.
887  Real zref_tmp = zref_sentinel;
888  pp.queryAdd("most.zref",zref_tmp);
889  bool read_zref = (zref_tmp > Real(0));
890  if (!read_zref) {
891  zref_tmp = zref_default;
892  Print() << "most.zref not specified, query distance default is " << zref_tmp << std::endl;
893  }
894  int klo = m_geom[lev].Domain().smallEnd(2);
895 
896  // Capture for device
897  Real d_zref = zref_tmp;
898  const auto plo = m_geom[lev].ProbLoArray();
899 
900  RealVect base;
901  const auto dx = m_geom[lev].CellSizeArray();
902  const auto dxInv = m_geom[lev].InvCellSizeArray();
903  IntVect ng = m_x_pos[lev]->nGrowVect(); ng[2]=0;
904  const int position_ng = (m_radius > 1) ? m_radius : 1;
905  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
906  Box npbx = mfi.tilebox(IntVect(1,1,0),IntVect(position_ng,position_ng,0));
907  Box gtbx = mfi.growntilebox(ng);
908  RealBox grb{gtbx,dx.data(),base.dataPtr()};
909 
910  if (npbx.smallEnd(2) != klo) { continue; }
911 
912  npbx.makeSlab(2,klo);
913 
914  const auto z_phys_arr = m_z_phys_nd[lev]->const_array(mfi);
915  auto x_pos_arr = m_x_pos[lev]->array(mfi);
916  auto y_pos_arr = m_y_pos[lev]->array(mfi);
917  auto z_pos_arr = m_z_pos[lev]->array(mfi);
918  auto zref_arr = m_zref[lev]->array(mfi);
919  ParallelFor(npbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
920  {
921  // Elements of normal vector
922  Real met_h_xi = Compute_h_xi_AtCellCenter (i,j,k,dxInv,z_phys_arr);
923  Real met_h_eta = Compute_h_eta_AtCellCenter(i,j,k,dxInv,z_phys_arr);
924  Real imag = one / std::sqrt(met_h_xi*met_h_xi + met_h_eta*met_h_eta + one);
925 
926  // Unit-normal vector scaled by z_ref
927  Real delta_x = -met_h_xi * imag * d_zref;
928  Real delta_y = -met_h_eta * imag * d_zref;
929  Real delta_z = imag * d_zref;
930 
931  // Position of the current node (indx:0,0,1)
932  Real x0 = plo[0] + ((Real) i + myhalf) * dx[0];
933  Real y0 = plo[1] + ((Real) j + myhalf) * dx[1];
934 
935  // Final position at end of vector
936  x_pos_arr(i,j,0) = x0 + delta_x;
937  y_pos_arr(i,j,0) = y0 + delta_y;
938  Real z_bot_face = fourth * ( z_phys_arr(i ,j ,k) + z_phys_arr(i+1,j ,k)
939  + z_phys_arr(i ,j+1,k) + z_phys_arr(i+1,j+1,k) );
940  z_pos_arr(i,j,0) = z_bot_face + delta_z;
941 
942  // NOTE: Normal vector end point can be below the surface for concave regions.
943  // Here we protect against that by augmenting the normal if needed.
944  int i_new = (int) ((x_pos_arr(i,j,0) - plo[0]) / dx[0] - myhalf);
945  int j_new = (int) ((y_pos_arr(i,j,0) - plo[1]) / dx[1] - myhalf);
946  Real z_new_bot_face = fourth * ( z_phys_arr(i_new,j_new ,k) + z_phys_arr(i_new+1,j_new ,k)
947  + z_phys_arr(i_new,j_new+1,k) + z_phys_arr(i_new+1,j_new+1,k) );
948  if (z_pos_arr(i,j,0) < z_new_bot_face) {
949  z_pos_arr(i,j,0) = z_new_bot_face + delta_z;
950  }
951 
952  zref_arr(i,j,0) = delta_z;
953 
954  // Destination position must be contained on the current process!
955  Real pos[] = {x_pos_arr(i,j,0)-plo[0],y_pos_arr(i,j,0)-plo[1],myhalf*dx[2]};
956  amrex::ignore_unused(pos);
957  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(grb.contains(&pos[0]),
958  "Query point outside of proc domain!");
959  });
960  }
961 }

Referenced by make_MOSTAverage_at_level().

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

◆ set_plane_average()

bool MOSTAverage::set_plane_average ( const int &  lev,
const amrex::Vector< amrex::Real > &  pavg 
)
inline

Restore the filtered plane averages from a checkpoint. Returns false if the checkpoint does not hold what this run expects, e.g. because the averaging policy changed, in which case nothing is restored.

Parameters
[in]levlevel index
[in]pavgfiltered plane averages, one per average component
300  {
301  const int n_have = (lev < static_cast<int>(m_plane_average.size())) ?
302  static_cast<int>(m_plane_average[lev].size()) : 0;
303  if (n_have != static_cast<int>(pavg.size())) { return false; }
304  if (n_have > 0) { m_plane_average[lev] = pavg; }
305  return true;
306  }

Referenced by SurfaceLayer::set_mac_plane_avg().

Here is the caller graph for this function:

◆ set_plane_normalization()

void MOSTAverage::set_plane_normalization ( const int &  lev)

Compute number of cells per averaging plane.

Parameters
[in]levlevel index

Function to compute normalization for plane average.

Parameters
[in]levCurrent level
389 {
390  // Cells per plane and temp avg storage
391  m_ncell_plane.resize(m_maxlev);
392  m_plane_average.resize(m_maxlev);
393 
394  // True domain not used for normalization
395  Box domain = m_geom[lev].Domain();
396 
397  // NOTE: Level 0 spans the whole domain, but finer
398  // levels do not have such a restriction.
399  // For now, use the bounding box of the boxArray
400  // for normalization, consistent with avg routine.
401 
402  // Bounded box of CC data used for normalization
403  Box bnd_bx = (m_fields[lev][2]->boxArray()).minimalBox();
404 
405  // NOTE: Bounding box must lie on the periodic boundaries
406  // in order to trip the is_per flag
407 
408  // Num components, plane avg, cells per plane
409  Array<int,AMREX_SPACEDIM> is_per = {0,0,0};
410  for (int idim(0); idim < AMREX_SPACEDIM-1; ++idim) {
411  if ( m_geom[lev].isPeriodic(idim) &&
412  bnd_bx.bigEnd(idim)==domain.bigEnd(idim) &&
413  bnd_bx.smallEnd(idim)==domain.smallEnd(idim) ) { is_per[idim] = 1; }
414  }
415 
416  m_ncell_plane[lev].resize(m_navg);
417  m_plane_average[lev].resize(m_navg);
418  for (int iavg(0); iavg < m_navg; ++iavg) {
419  // Convert bnd_bx to current index type
420  IndexType ixt = m_averages[lev][iavg]->boxArray().ixType();
421  bnd_bx.convert(ixt);
422  IntVect bnd_bx_lo(bnd_bx.loVect());
423  IntVect bnd_bx_hi(bnd_bx.hiVect());
424 
425  m_plane_average[lev][iavg] = zero;
426 
427  m_ncell_plane[lev][iavg] = 1;
428  for (int idim(0); idim < AMREX_SPACEDIM; ++idim) {
429  if (idim != 2) {
430  if (ixt.nodeCentered(idim) && is_per[idim]) {
431  m_ncell_plane[lev][iavg] *= (bnd_bx_hi[idim] - bnd_bx_lo[idim]);
432  } else {
433  m_ncell_plane[lev][iavg] *= (bnd_bx_hi[idim] - bnd_bx_lo[idim] + 1);
434  }
435  }
436  } // idim
437  } // iavg
438 }

Referenced by make_MOSTAverage_at_level().

Here is the caller graph for this function:

◆ set_region_normalization()

void MOSTAverage::set_region_normalization ( const int &  )
inline

Compute number of cells in the region average.

Parameters
[in]levlevel index
127  {m_ncell_region = (2 * m_radius + 1) * (2 * m_radius + 1) * (2 * m_radius + 1);}

Referenced by make_MOSTAverage_at_level().

Here is the caller graph for this function:

◆ set_rotated_fields()

void MOSTAverage::set_rotated_fields ( const int &  lev)

Update the rotated fields.

Parameters
[in]levlevel index

Function to set the rotated velocities.

Parameters
[in]levCurrent level
329 {
330  // Peel back the level
331  auto& fields = m_fields[lev];
332  auto& rot_fields = m_rot_fields[lev];
333  auto z_phys_nd = m_z_phys_nd[lev];
334 
335  // Inverse grid size
336  const auto dxInv = m_geom[lev].InvCellSizeArray();
337 
338  // Single MFIter over CC data
339  int imf_cc = 2;
340 
341  // Populate rotated U & V for terrain
342 #ifdef _OPENMP
343 #pragma omp parallel if (Gpu::notInLaunchRegion())
344 #endif
345  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
346  Box ubx = mfi.tilebox(IntVect(1,0,0));
347  Box vbx = mfi.tilebox(IntVect(0,1,0));
348 
349  const Array4<const Real>& z_phys_arr = z_phys_nd->const_array(mfi);
350 
351  const Array4<const Real>& u_arr = fields[0]->const_array(mfi);
352  const Array4<const Real>& v_arr = fields[1]->const_array(mfi);
353  const Array4<const Real>& w_arr = fields[5]->const_array(mfi);
354 
355  const Array4<Real>& u_rot_arr = rot_fields[0]->array(mfi);
356  const Array4<Real>& v_rot_arr = rot_fields[1]->array(mfi);
357 
358  // U rotated magnitude
359  ParallelFor(ubx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
360  {
361  // Elements of first tangent vector
362  Real met_h_xi = Compute_h_xi_AtIface(i,j,k,dxInv,z_phys_arr);
363  u_rot_arr(i,j,k) = (u_arr(i,j,k) + met_h_xi*w_arr(i,j,k))
364  / std::sqrt(met_h_xi*met_h_xi + one);
365  });
366 
367  // V rotated magnitude
368  ParallelFor(vbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
369  {
370  // Elements of second tangent vector
371  Real met_h_eta = Compute_h_eta_AtJface(i,j,k,dxInv,z_phys_arr);
372  v_rot_arr(i,j,k) = (v_arr(i,j,k) + met_h_eta*w_arr(i,j,k))
373  / std::sqrt(met_h_eta*met_h_eta + one);
374  });
375  }
376 
377  // Direct copy of other scalar variables
378  MultiFab::Copy(*rot_fields[2],*fields[2],0,0,1,rot_fields[2]->nGrowVect());
379  if (fields[3]) MultiFab::Copy(*rot_fields[3],*fields[3],0,0,1,rot_fields[3]->nGrowVect());
380 }
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_xi_AtIface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:281
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_eta_AtJface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:374

Referenced by compute_averages().

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

◆ set_time_avg_initialized()

void MOSTAverage::set_time_avg_initialized ( const int &  lev)
inline

Declare the time filter at this level to hold meaningful history. This is used on restart, once the filter state has been read back in.

Parameters
[in]levlevel index
274  {
275  if (m_t_avg) { m_t_init[lev] = 1; }
276  }

Referenced by SurfaceLayer::set_mac_avg_initialized().

Here is the caller graph for this function:

◆ set_z_positions_EB()

void MOSTAverage::set_z_positions_EB ( const int &  lev)

Populate embedded-boundary z positions.

Parameters
[in]levlevel index

Function to set K indices for EB.

Parameters
[in]levCurrent level
598 {
599  // See zref_sentinel in ERF_MOSTAverage.H: probe with the sentinel and test the
600  // value, since queryAdd's return value stops meaning "user specified" after the
601  // first parse of the key and this routine runs once per level.
602  Real zref_tmp = zref_sentinel;
603  ParmParse pp(m_pp_prefix);
604  pp.queryAdd("most.zref",zref_tmp);
605  bool read_z = (zref_tmp > Real(0));
606  if (!read_z) { zref_tmp = zref_default; }
607 
608  if (read_z) {
609  m_zref[lev]->setVal( zref_tmp );
610  // Default behavior is to use the first cell center
611  } else {
612  Real m_dz = m_geom[0].CellSize(2);
613  zref_tmp = myhalf * m_dz;
614  m_zref[lev]->setVal( zref_tmp );
615  Print() << "Reference height for MOST set to " << zref_tmp << std::endl;
616  }
617 }

Referenced by make_MOSTAverage_at_level().

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

◆ set_z_positions_T()

void MOSTAverage::set_z_positions_T ( const int &  lev)

Populate terrain-aware z positions.

Parameters
[in]levlevel index

Function to set positions with terrain and e_z vector (with interpolation but no terrain normals)

Parameters
[in]levCurrent level
806 {
807  // Peel back the level
808  auto& fields = m_fields[lev];
809 
810  // MFIter over CC data
811  int imf_cc = 2;
812 
813  ParmParse pp(m_pp_prefix);
814  // See zref_sentinel in ERF_MOSTAverage.H: probe with the sentinel and test the
815  // value, since queryAdd's return value stops meaning "user specified" after the
816  // first parse of the key and this routine runs once per level.
817  Real zref_tmp = zref_sentinel;
818  pp.queryAdd("most.zref",zref_tmp);
819  bool read_zref = (zref_tmp > Real(0));
820  if (!read_zref) {
821  zref_tmp = zref_default;
822  Print() << "most.zref not specified, query distance default is " << zref_tmp << std::endl;
823  } else {
824  m_zref[lev]->setVal(zref_tmp);
825  }
826  int klo = m_geom[lev].Domain().smallEnd(2);
827 
828  // Capture for device
829  Real d_zref = zref_tmp;
830  const auto plo = m_geom[lev].ProbLoArray();
831 
832  RealVect base;
833  const auto dx = m_geom[lev].CellSizeArray();
834  IntVect ng = m_x_pos[lev]->nGrowVect(); ng[2]=0;
835  const int position_ng = (m_radius > 1) ? m_radius : 1;
836  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
837  Box npbx = mfi.tilebox(IntVect(1,1,0),IntVect(position_ng,position_ng,0));
838  Box gtbx = mfi.growntilebox(ng);
839 
840  if (npbx.smallEnd(2) != klo) { continue; }
841 
842  npbx.makeSlab(2,klo);
843 
844  RealBox grb{gtbx,dx.data(),base.dataPtr()};
845 
846  const auto z_phys_arr = m_z_phys_nd[lev]->const_array(mfi);
847  auto x_pos_arr = m_x_pos[lev]->array(mfi);
848  auto y_pos_arr = m_y_pos[lev]->array(mfi);
849  auto z_pos_arr = m_z_pos[lev]->array(mfi);
850  ParallelFor(npbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
851  {
852  // Final position at end of vector
853  x_pos_arr(i,j,0) = plo[0] + ((Real) i + myhalf) * dx[0];
854  y_pos_arr(i,j,0) = plo[1] + ((Real) j + myhalf) * dx[1];
855  Real z_bot_face = fourth * ( z_phys_arr(i ,j ,k) + z_phys_arr(i+1,j ,k)
856  + z_phys_arr(i ,j+1,k) + z_phys_arr(i+1,j+1,k) );
857  z_pos_arr(i,j,0) = z_bot_face + d_zref;
858 
859  // Destination position must be contained on the current process!
860  Real pos[] = {x_pos_arr(i,j,0)-plo[0],y_pos_arr(i,j,0)-plo[1],myhalf*dx[2]};
861  amrex::ignore_unused(pos);
862  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(grb.contains(&pos[0]),
863  "Query point outside of proc domain!");
864  });
865  }
866 }

Referenced by make_MOSTAverage_at_level().

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

◆ time_avg_is_initialized()

bool MOSTAverage::time_avg_is_initialized ( const int &  lev) const
inline

Return whether the time filter at this level holds meaningful history. Until it does, the next average is taken to be the instantaneous one.

Parameters
[in]levlevel index
263  {
264  return ( m_t_avg && (lev < static_cast<int>(m_t_init.size())) && (m_t_init[lev] == 1) );
265  }

Referenced by SurfaceLayer::mac_avg_is_initialized().

Here is the caller graph for this function:

◆ trilinear_interp_T()

AMREX_GPU_HOST_DEVICE static AMREX_INLINE void MOSTAverage::trilinear_interp_T ( const amrex::Real xp,
const amrex::Real yp,
const amrex::Real zp,
amrex::Real interp_vals,
amrex::Array4< amrex::Real const > const &  interp_array,
amrex::Array4< amrex::Real const > const &  z_arr,
const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &  plo,
const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &  dxi,
const int  interp_comp 
)
inlinestatic

Function to compute trilinear interpolation with terrain.

Parameters
[in]xpX-position
[in]ypY-position
[in]zpZ-position
[out]interp_valsValues interpolated
[in]interp_arrayArray to interpolate on
[in]z_arrPhysical heights
[in]ploProblem lower bounds
[in]dxiInverse cell size array
[in]interp_compNumber of components to interpolate
345  {
346  // Search to get z/k
347  bool found = false;
348  int kmax = ubound(z_arr).z;
349  amrex::Real zval = zero;
350  amrex::Real z_target = zp;
351 
352  // Map position to i,j (must be same mapping in cpp file)
353  amrex::Real ireal = (xp - plo[0]) * dxi[0];
354  amrex::Real jreal = (yp - plo[1]) * dxi[1];
355  int i_new = (int) (ireal - myhalf);
356  int j_new = (int) (jreal - myhalf);
357 
358  for (int lk(0); lk<kmax; ++lk) {
359  amrex::Real z_lo = fourth * ( z_arr(i_new,j_new ,lk ) + z_arr(i_new+1,j_new ,lk )
360  + z_arr(i_new,j_new+1,lk ) + z_arr(i_new+1,j_new+1,lk ) );
361  amrex::Real z_hi = fourth * ( z_arr(i_new,j_new ,lk+1) + z_arr(i_new+1,j_new ,lk+1)
362  + z_arr(i_new,j_new+1,lk+1) + z_arr(i_new+1,j_new+1,lk+1) );
363  if (z_target > z_lo && z_target < z_hi){
364  found = true;
365  zval = (amrex::Real) lk + ((z_target - z_lo) / (z_hi - z_lo)) + myhalf;
366  break;
367  }
368  }
369 
370  amrex::ignore_unused(found);
371  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(found, "MOSTAverage: Height above terrain not found, try increasing z_ref!");
372 
373  // NOTE: This is the point ahead of the current i,j (e.g. i/j_new + 1)
374  const amrex::RealVect lx(ireal + myhalf, jreal + myhalf, zval);
375 
376  const amrex::IntVect ijk = lx.floor();
377 
378  int i = ijk[0]; int j = ijk[1]; int k = ijk[2];
379 
380  // Convert ijk (IntVect) to a RealVect explicitly
381  amrex::RealVect ijk_r(static_cast<amrex::Real>(ijk[0]),
382  static_cast<amrex::Real>(ijk[1]),
383  static_cast<amrex::Real>(ijk[2]));
384 
385  // Weights
386  const amrex::RealVect sx_hi = lx - ijk_r;
387  const amrex::RealVect sx_lo = one - sx_hi;
388 
389  for (int n = 0; n < interp_comp; n++) {
390  interp_vals[n] = sx_lo[0]*sx_lo[1]*sx_lo[2]*interp_array(i-1, j-1, k-1,n) +
391  sx_lo[0]*sx_lo[1]*sx_hi[2]*interp_array(i-1, j-1, k ,n) +
392  sx_lo[0]*sx_hi[1]*sx_lo[2]*interp_array(i-1, j , k-1,n) +
393  sx_lo[0]*sx_hi[1]*sx_hi[2]*interp_array(i-1, j , k ,n) +
394  sx_hi[0]*sx_lo[1]*sx_lo[2]*interp_array(i , j-1, k-1,n) +
395  sx_hi[0]*sx_lo[1]*sx_hi[2]*interp_array(i , j-1, k ,n) +
396  sx_hi[0]*sx_hi[1]*sx_lo[2]*interp_array(i , j , k-1,n) +
397  sx_hi[0]*sx_hi[1]*sx_hi[2]*interp_array(i , j , k ,n);
398  }
399  }

Referenced by compute_plane_averages(), and compute_region_averages().

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

◆ update_field_ptrs()

void MOSTAverage::update_field_ptrs ( const int &  lev,
amrex::Vector< amrex::Vector< amrex::MultiFab >> &  vars_old,
amrex::Vector< std::unique_ptr< amrex::MultiFab >> &  Theta_prim,
amrex::Vector< std::unique_ptr< amrex::MultiFab >> &  Qv_prim,
amrex::Vector< std::unique_ptr< amrex::MultiFab >> &  Qr_prim 
)

Reset pointers to field MultiFabs.

Parameters
[in]levlevel index
[in]vars_oldold-time state and velocity fields
[in]Theta_primprimitive potential-temperature fields by level
[in]Qv_primprimitive water-vapor fields by level
[in]Qr_primprimitive rain-water fields by level

Function to reset the pointers to field variables.

Parameters
[in]levCurrent level
[in]vars_oldConserved variables at each level
[in]Theta_primPrimitive theta component at each level
[in]Qv_primPrimitive water-vapor component at each level
[in]Qr_primPrimitive rain-water component at each level
313 {
314  m_fields[lev][0] = &vars_old[lev][Vars::xvel];
315  m_fields[lev][1] = &vars_old[lev][Vars::yvel];
316  m_fields[lev][2] = Theta_prim[lev].get();
317  m_fields[lev][3] = Qv_prim[lev].get();
318  m_fields[lev][4] = Qr_prim[lev].get();
319  m_fields[lev][5] = &vars_old[lev][Vars::zvel];
320 }

Referenced by SurfaceLayer::update_mac_ptrs().

Here is the caller graph for this function:

◆ write_averages()

void MOSTAverage::write_averages ( const int &  lev)

Write averages on the 2D MultiFab.

Parameters
[in]levlevel index

Function to write averages to text file.

Parameters
[in]levCurrent level
2110 {
2111  // Peel back the level
2112  auto& fields = m_fields[lev];
2113  auto& averages = m_averages[lev];
2114 
2115  // MFIter on CC
2116  int imf_cc = 2;
2117 
2118  int klo = m_geom[lev].Domain().smallEnd(2);
2119 
2120  int navg = m_navg - 1;
2121 
2122  std::ofstream ofile;
2123  ofile.open ("MOST_averages.txt");
2124  ofile << "Averages computed via MOSTAverages class:\n";
2125 
2126  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
2127  Box pbx = mfi.tilebox();
2128 
2129  if(pbx.smallEnd(2) != klo) { continue; }
2130 
2131  pbx.makeSlab(2,klo);
2132 
2133  int il = pbx.smallEnd(0); int iu = pbx.bigEnd(0);
2134  int jl = pbx.smallEnd(1); int ju = pbx.bigEnd(1);
2135 
2136  for (int j(jl); j <= ju; ++j) {
2137  for (int i(il); i <= iu; ++i) {
2138  ofile << "(I,J): " << "(" << i << "," << j << ")" << "\n";
2139  int k = 0;
2140  for (int iavg(0); iavg <= navg; ++iavg) {
2141  auto mf_arr = averages[iavg]->array(mfi);
2142  ofile << "iavg val: "
2143  << iavg << ' '
2144  << mf_arr(i,j,k) << "\n";
2145  }
2146  ofile << "\n";
2147  }
2148  }
2149  }
2150  ofile.close();
2151 }
Here is the call graph for this function:

◆ write_k_indices()

void MOSTAverage::write_k_indices ( const int &  lev)

Write k-index data.

Parameters
[in]levlevel index

Function to write the K indices to text file.

Parameters
[in]levCurrent level
1964 {
1965  // Peel back the level
1966  auto& fields = m_fields[lev];
1967  auto& k_indx = m_k_indx[lev];
1968 
1969  // MFIter on CC
1970  int imf_cc = 2;
1971 
1972  int klo = m_geom[lev].Domain().smallEnd(2);
1973 
1974  std::ofstream ofile;
1975  ofile.open ("MOST_k_indices.txt");
1976  ofile << "K indices used to compute averages via MOSTAverages class:\n";
1977 
1978  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
1979  Box pbx = mfi.tilebox();
1980 
1981  if(pbx.smallEnd(2) != klo) { continue; }
1982 
1983  pbx.makeSlab(2,klo);
1984 
1985  int il = pbx.smallEnd(0); int iu = pbx.bigEnd(0);
1986  int jl = pbx.smallEnd(1); int ju = pbx.bigEnd(1);
1987 
1988  auto k_arr = k_indx->array(mfi);
1989 
1990  for (int j(jl); j <= ju; ++j) {
1991  for (int i(il); i <= iu; ++i) {
1992  ofile << "(I,J): " << "(" << i << "," << j << ")" << "\n";
1993  int k = 0;
1994  ofile << "K_ind: "
1995  << k_arr(i,j,k) << "\n";
1996  ofile << "\n";
1997  }
1998  }
1999  }
2000  ofile.close();
2001 }
Here is the call graph for this function:

◆ write_norm_indices()

void MOSTAverage::write_norm_indices ( const int &  lev)

Write normal-index data.

Parameters
[in]levlevel index

Function to write I,J,K indices to text file.

Parameters
[in]levCurrent level
2011 {
2012  // Peel back the level
2013  auto& fields = m_fields[lev];
2014  auto& k_indx = m_k_indx[lev];
2015  auto& j_indx = m_j_indx[lev];
2016  auto& i_indx = m_i_indx[lev];
2017 
2018  // MFIter on CC
2019  int imf_cc = 2;
2020 
2021  int klo = m_geom[lev].Domain().smallEnd(2);
2022 
2023  std::ofstream ofile;
2024  ofile.open ("MOST_ijk_indices.txt");
2025  ofile << "IJK indices used to compute averages via MOSTAverages class:\n";
2026 
2027  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
2028  Box pbx = mfi.tilebox();
2029 
2030  if(pbx.smallEnd(2) != klo) { continue; }
2031 
2032  pbx.makeSlab(2,klo);
2033 
2034  int il = pbx.smallEnd(0); int iu = pbx.bigEnd(0);
2035  int jl = pbx.smallEnd(1); int ju = pbx.bigEnd(1);
2036 
2037  auto k_arr = k_indx->array(mfi);
2038  auto j_arr = j_indx ? j_indx->array(mfi) : Array4<int> {};
2039  auto i_arr = i_indx ? i_indx->array(mfi) : Array4<int> {};
2040 
2041  for (int j(jl); j <= ju; ++j) {
2042  for (int i(il); i <= iu; ++i) {
2043  ofile << "(I1,J1,K1): " << "(" << i << "," << j << "," << 0 << ")" << "\n";
2044 
2045  int k = 0;
2046  int km = k_arr(i,j,k);
2047  int jm = j_arr ? j_arr(i,j,k) : j;
2048  int im = i_arr ? i_arr(i,j,k) : i;
2049 
2050  ofile << "(I2,J2,K2): "
2051  << "(" << im << "," << jm << "," << km << ")" << "\n";
2052  ofile << "\n";
2053  }
2054  }
2055  }
2056  ofile.close();
2057 }
Here is the call graph for this function:

◆ write_xz_positions()

void MOSTAverage::write_xz_positions ( const int &  lev,
const int &  j 
)

Write XZ planar positions.

Parameters
[in]levlevel index
[in]jy-index of the plane to write

Function to write X & Z positions to text file.

Parameters
[in]levCurrent level
[in]jIndex in y-dir
2069 {
2070  // Peel back the level
2071  auto& fields = m_fields[lev];
2072  auto& x_pos_mf = m_x_pos[lev];
2073  auto& z_pos_mf = m_z_pos[lev];
2074 
2075  // MFIter on CC
2076  int imf_cc = 2;
2077 
2078  int klo = m_geom[lev].Domain().smallEnd(2);
2079 
2080  std::ofstream ofile;
2081  ofile.open ("MOST_xz_positions.txt");
2082 
2083  for (MFIter mfi(*fields[imf_cc], TileNoZ()); mfi.isValid(); ++mfi) {
2084  Box pbx = mfi.tilebox();
2085 
2086  if(pbx.smallEnd(2) != klo) { continue; }
2087 
2088  pbx.makeSlab(2,klo);
2089 
2090  int il = pbx.smallEnd(0); int iu = pbx.bigEnd(0);
2091 
2092  auto x_pos_arr = x_pos_mf->array(mfi);
2093  auto z_pos_arr = z_pos_mf->array(mfi);
2094 
2095  int k = 0;
2096  for (int i(il); i <= iu; ++i)
2097  ofile << x_pos_arr(i,j,k) << ' ' << z_pos_arr(i,j,k) << "\n";
2098  }
2099  ofile.close();
2100 }
Here is the call graph for this function:

Member Data Documentation

◆ include_subgrid_vel

bool MOSTAverage::include_subgrid_vel = false
protected

◆ m_averages

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > MOSTAverage::m_averages
protected

◆ m_eb_vec

amrex::Vector<const eb_*> MOSTAverage::m_eb_vec
protected

◆ m_fact_new

◆ m_fact_old

◆ m_fields

◆ m_geom

◆ m_i_indx

amrex::Vector<std::unique_ptr<amrex::iMultiFab> > MOSTAverage::m_i_indx
protected

◆ m_interp

bool MOSTAverage::m_interp {false}
protected

◆ m_j_indx

amrex::Vector<std::unique_ptr<amrex::iMultiFab> > MOSTAverage::m_j_indx
protected

◆ m_k_in

amrex::Vector<int> MOSTAverage::m_k_in
protected

Referenced by set_k_indices_N(), and set_k_indices_T().

◆ m_k_indx

◆ m_maxlev

int MOSTAverage::m_maxlev {0}
protected

◆ m_mesh_type

MeshType MOSTAverage::m_mesh_type
protected

◆ m_navg

◆ m_ncell_plane

amrex::Vector<amrex::Vector<int> > MOSTAverage::m_ncell_plane
protected

◆ m_ncell_region

int MOSTAverage::m_ncell_region {1}
protected

◆ m_norm_vec

bool MOSTAverage::m_norm_vec {false}
protected

◆ m_nvar

int MOSTAverage::m_nvar {6}
protected

◆ m_plane_average

amrex::Vector<amrex::Vector<amrex::Real> > MOSTAverage::m_plane_average
protected

◆ m_policy

int MOSTAverage::m_policy {0}
protected

◆ m_pp_prefix

std::string MOSTAverage::m_pp_prefix
protected

◆ m_radius

◆ m_rot_fields

amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab> > > MOSTAverage::m_rot_fields
protected

◆ m_rotate

bool MOSTAverage::m_rotate {false}
protected

◆ m_t_avg

◆ m_t_init

◆ m_terrain_type

TerrainType MOSTAverage::m_terrain_type
protected

◆ m_time_window

double MOSTAverage::m_time_window {1.0e-16}
protected

◆ m_total_bndry_area

amrex::Vector<amrex::Vector<amrex::Real> > MOSTAverage::m_total_bndry_area
protected

◆ m_Vsg

amrex::Vector<amrex::Real> MOSTAverage::m_Vsg
protected

◆ m_x_pos

amrex::Vector<std::unique_ptr<amrex::MultiFab> > MOSTAverage::m_x_pos
protected

◆ m_y_pos

amrex::Vector<std::unique_ptr<amrex::MultiFab> > MOSTAverage::m_y_pos
protected

◆ m_z_phys_nd

◆ m_z_pos

amrex::Vector<std::unique_ptr<amrex::MultiFab> > MOSTAverage::m_z_pos
protected

◆ m_zref

amrex::Vector<std::unique_ptr<amrex::MultiFab> > MOSTAverage::m_zref
protected

◆ zref_default

◆ zref_sentinel


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