ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_CoarseFineFaces.cpp File Reference
#include "ERF.H"
#include "ERF_Utils.H"
#include "ERF_TI_slow_headers.H"
#include <AMReX_FillPatchUtil.H>
#include <AMReX_Interpolater.H>
#include <limits>
Include dependency graph for ERF_CoarseFineFaces.cpp:

Functions

static MultiFab weighted_mass_flux (const MultiFab &m, const MultiFab &area, const MultiFab &mf)
 
static void fill_cf_momentum (ERFFillPatcher &patcher, MultiFab &mom, const MultiFab &area, const MultiFab &mapfac, bool mass_flux, double time_d, const Vector< BCRec > &bcs)
 

Detailed Description

A refined level that stops inside the domain in z (a level refined over part of the depth) has coarse/fine faces at its top and bottom. On a terrain-fitted mesh the anelastic projection works with the contravariant flux through each z-face,

Omega = rho0 w - rho0 u dz/dx - rho0 v dz/dy,

which needs the horizontal momenta one face below and above the level and, for the solve to have a solution, fluxes through the level's boundary that add up to the coarse level's.

cf_zface_coarse_data builds both from the coarse level, on thin planes around the level's top and bottom only: the horizontal momenta in the layer just outside the level, and the coarse Omega on its coarse/fine faces in z. project_momenta uses them through set_cf_zghost_projection and set_cf_zface_omega; every fine-level fill uses them through FillSetMomentaCF, right after the coarse/fine faces are set from the coarse level and before any ghost fill, so the time step carries theta and the other scalars with the fluxes the projection balanced.

ERF used to keep the coarse (rho w) that FillSet puts on these faces: the fine level then rebuilt Omega from its own u, v and slopes, the fluxes no longer added up to the coarse ones, and the difference stayed in the level as a uniform divergence (2.8e-6 1/s on the test hill).

Function Documentation

◆ fill_cf_momentum()

static void fill_cf_momentum ( ERFFillPatcher &  patcher,
MultiFab &  mom,
const MultiFab &  area,
const MultiFab &  mapfac,
bool  mass_flux,
double  time_d,
const Vector< BCRec > &  bcs 
)
static

Fill the coarse/fine faces of one horizontal momentum component. Where cf_interp_mass_flux holds, the fill gives the mass flux, which is multiplied by the fine map factor and divided by the fine area on the faces it set; all other faces keep their values exactly.

974 {
975  PhysBCFunctNoOp null_bc;
976  if (!mass_flux) {
977  patcher.FillSet(mom, time_d, null_bc, bcs);
978  return;
979  }
980  constexpr Real not_set = std::numeric_limits<Real>::max();
981  MultiFab flux(mom.boxArray(), mom.DistributionMap(), 1, 0);
982  flux.setVal(not_set);
983  patcher.FillSet(flux, time_d, null_bc, bcs);
984  for (MFIter mfi(flux, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
985  const Box bx = mfi.tilebox();
986  const auto f = flux.const_array(mfi);
987  const auto a = area.const_array(mfi);
988  const auto mf = mapfac.const_array(mfi);
989  const auto m = mom.array(mfi);
990  const Real flag = not_set;
991  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
992  {
993  if (f(i,j,k) != flag) { m(i,j,k) = f(i,j,k) * mf(i,j,0) / a(i,j,k); }
994  });
995  }
996 }
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
void FillSet(amrex::MultiFab &mf, double time, BC &cbc, amrex::Vector< amrex::BCRec > const &bcs)
Definition: ERF_FillPatcher.H:204

Referenced by ERF::FillSetHorizontalMomentaCF().

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

◆ weighted_mass_flux()

static MultiFab weighted_mass_flux ( const MultiFab &  m,
const MultiFab &  area,
const MultiFab &  mf 
)
static

The mass flux a (rho u) / m of a horizontal momentum component, on the faces of its valid region and the ghost faces that the momentum, the area and the map factor all hold.

Parameters
mFace momenta, (rho u) or (rho v)
areaFace areas, ax or ay
mfMap factor on those faces, m_uy or m_vx
543 {
544  IntVect ng = amrex::min(m.nGrowVect(), area.nGrowVect());
545  ng[0] = amrex::min(ng[0], mf.nGrowVect()[0]);
546  ng[1] = amrex::min(ng[1], mf.nGrowVect()[1]);
547  MultiFab w(m.boxArray(), m.DistributionMap(), 1, ng);
548  for (MFIter mfi(w, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
549  const Box bx = mfi.growntilebox(ng);
550  const auto w_arr = w.array(mfi);
551  const auto m_arr = m.const_array(mfi);
552  const auto a_arr = area.const_array(mfi);
553  const auto f_arr = mf.const_array(mfi);
554  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
555  {
556  w_arr(i,j,k) = m_arr(i,j,k) * a_arr(i,j,k) / f_arr(i,j,0);
557  });
558  }
559  return w;
560 }
Real w
Definition: ERF_Plotfile2DInterpolator.cpp:23
@ ng
Definition: ERF_Morrison.H:51

Referenced by ERF::average_down_mass_flux(), ERF::cf_anelastic_stage_registration(), and ERF::RegisterCoarseMomentumCF().

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