ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_FireUtils.H File Reference

Utility functions for fire model atmospheric state extraction. More...

#include <AMReX_MultiFab.H>
#include <AMReX_Geometry.H>
#include <AMReX_MFIter.H>
#include <ERF_MicrophysicsUtils.H>
#include <ERF_EOS.H>
#include <ERF_IndexDefines.H>
#include <ERF_Constants.H>
Include dependency graph for ERF_FireUtils.H:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void compute_rh_from_conservative (amrex::MultiFab &RH_out, const amrex::MultiFab &S_atm, const amrex::Geometry &)
 Compute relative humidity from conserved atmospheric variables at k=0. More...
 
void compute_t_from_conservative (amrex::MultiFab &T_out, const amrex::MultiFab &S_atm)
 Air temperature [K] at k = 0 from the conserved state. More...
 
void fire_copy_k0_plane (amrex::MultiFab &dst_2d, const amrex::MultiFab &src_3d)
 
void fire_host_copy (amrex::MultiFab &dst, const amrex::MultiFab &src, int ncomp=1, int nghost=0)
 Copy a MultiFab between device and host-accessible memory, for an engine whose fire physics runs on the host. More...
 

Detailed Description

Utility functions for fire model atmospheric state extraction.

Function Documentation

◆ compute_rh_from_conservative()

void compute_rh_from_conservative ( amrex::MultiFab &  RH_out,
const amrex::MultiFab &  S_atm,
const amrex::Geometry &   
)
inline

Compute relative humidity from conserved atmospheric variables at k=0.

Computes RH from pressure, temperature, and water vapor mixing ratio at the first atmospheric level (k=0). Uses the ERF microphysics saturation vapor pressure functions.

Parameters
[out]RH_outOutput relative humidity MultiFab [fraction 0-1] Must be allocated with ncomp=1 on same grid as inputs
[in]S_atmConservative state at k=0 Contains RhoTheta (comp 1) and RhoQ1 (comp 4)
[in]geomGeometry at level 0
Note
  • Output is clamped to [0, 1] range
  • Assumes S_atm contains standard conserved variables (Rho, RhoTheta, RhoQ1)
  • Temperature extracted from RhoTheta using standard EOS
  • Pressure computed from RhoTheta and qv using getPgivenRTh
40 {
41  using namespace amrex;
42 
43  // Precompute rdOcp = R_d / Cp_d for use in Exner function
44  // Cp_d = 1004.5 J/(kg-K), R_d = 287.0 J/(kg-K)
45  constexpr Real rdOcp = R_d / Cp_d;
46 
47  // Iterate over all boxes
48  for (MFIter mfi(RH_out); mfi.isValid(); ++mfi) {
49  const Box& bx = mfi.tilebox();
50  Array4<Real> rh_arr = RH_out.array(mfi);
51  Array4<const Real> S_arr = S_atm.const_array(mfi);
52 
53  // Kernel to compute RH at k=0
54  ParallelFor(bx, [=] AMREX_GPU_DEVICE(const IntVect& iv) {
55  int i = iv[0];
56  int j = iv[1];
57  int k = 0; // First atmospheric level
58 
59  // Extract conserved variables at k=0
60  Real rho = S_arr(i, j, k, Rho_comp); // Density
61  Real rho_th = S_arr(i, j, k, RhoTheta_comp); // RhoTheta
62 
63  // Compute mixing ratios (guard against moisture not being present)
64  Real qv = 0.0_rt; // Water vapor mixing ratio [kg/kg]
65  if (RhoQ1_comp < S_arr.nComp()) {
66  Real rho_qv = S_arr(i, j, k, RhoQ1_comp); // RhoQ1 (water vapor)
67  qv = rho_qv / rho;
68  }
69 
70  // Compute potential temperature
71  Real theta = rho_th / rho; // Potential temperature [K]
72 
73  // Compute pressure from RhoTheta and qv using standard EOS
74  Real p = getPgivenRTh(rho_th, qv); // Pressure [Pa]
75 
76  // Convert pressure to mbar for saturation vapor pressure functions
77  Real p_mbar = p * 0.01_rt; // Pa to mbar (1 mbar = 100 Pa)
78 
79  // Compute temperature from potential temperature
80  // T = theta * (p / p_0)^(R_d / c_p)
81  // Use Exner function: pi = (p / p_0)^(R_d / c_p)
82  Real exner = getExnergivenP(p, rdOcp);
83  Real T_K = theta * exner;
84 
85  // Compute saturation vapor pressure [mbar]
86  Real e_sat = erf_esatw(T_K, false); // Use Flatau polynomial
87 
88  // Compute saturation mixing ratio [kg/kg]
89  Real q_sat = erf_qsat_from_esat(e_sat, p_mbar);
90 
91  // Compute relative humidity as RH = qv / qsat
92  Real RH = 0.0_rt;
93  if (q_sat > 1.0e-10_rt) {
94  RH = qv / q_sat;
95  }
96 
97  // Clamp RH to valid range [0, 1]
98  RH = amrex::min(1.0_rt, amrex::max(0.0_rt, RH));
99 
100  rh_arr(i, j, k) = RH;
101  });
102  }
103 }
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:51
constexpr amrex::Real R_d
Definition: ERF_Constants.H:49
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getExnergivenP(const amrex::Real P, const amrex::Real rdOcp)
Definition: ERF_EOS.H:141
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:81
#define Rho_comp
Definition: ERF_IndexDefines.H:53
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:54
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:66
const Real rdOcp
Definition: ERF_InitCustomPert_ABL.H:72
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_qsat_from_esat(amrex::Real esat, amrex::Real p)
Definition: ERF_MicrophysicsUtils.H:233
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t, bool use_empirical=false)
Definition: ERF_MicrophysicsUtils.H:159
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
@ rho
Definition: ERF_Kessler.H:25
@ theta
Definition: ERF_Kessler.H:26
@ qv
Definition: ERF_Kessler.H:31
@ p
Definition: ERF_WSM6.H:301
Definition: ERF_ConsoleIO.cpp:17

Referenced by FireCoupler::advance().

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

◆ compute_t_from_conservative()

void compute_t_from_conservative ( amrex::MultiFab &  T_out,
const amrex::MultiFab &  S_atm 
)
inline

Air temperature [K] at k = 0 from the conserved state.

T = theta * (p / p_0)^(R_d / c_p), with p from RhoTheta and qv as in compute_rh_from_conservative. Fuel-moisture curves and ignition criteria take an air temperature, not the potential temperature of the first cell, which at 840 hPa is 14-16 K above it.

Parameters
[out]T_out2D MultiFab (one cell in z) on the level's boxes
[in]S_atmConserved state (Rho, RhoTheta, RhoQ1 when moist)
119 {
120  using namespace amrex;
121  constexpr Real rdOcp = R_d / Cp_d;
122  for (MFIter mfi(T_out); mfi.isValid(); ++mfi) {
123  const Box& bx = mfi.tilebox();
124  Array4<Real> t_arr = T_out.array(mfi);
125  Array4<const Real> S_arr = S_atm.const_array(mfi);
126  ParallelFor(bx, [=] AMREX_GPU_DEVICE(const IntVect& iv) {
127  const int i = iv[0];
128  const int j = iv[1];
129  const int k = 0;
130  const Real rho = S_arr(i, j, k, Rho_comp);
131  const Real rho_th = S_arr(i, j, k, RhoTheta_comp);
132  Real qv = 0.0_rt;
133  if (RhoQ1_comp < S_arr.nComp()) {
134  qv = S_arr(i, j, k, RhoQ1_comp) / rho;
135  }
136  const Real p = getPgivenRTh(rho_th, qv);
137  const Real exner = getExnergivenP(p, rdOcp);
138  t_arr(i, j, k) = (rho_th / rho) * exner;
139  });
140  }
141 }

Referenced by FireCoupler::advance().

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

◆ fire_copy_k0_plane()

void fire_copy_k0_plane ( amrex::MultiFab &  dst_2d,
const amrex::MultiFab &  src_3d 
)
inline

Copy the k = 0 plane of a cell-centred atmospheric field into a MultiFab on the same boxes coarsened to one cell in z. A namespace-scope function because nvcc rejects a device kernel inside a private member such as ERF::Advance.

150 {
151  for (amrex::MFIter mfi(dst_2d); mfi.isValid(); ++mfi) {
152  amrex::Array4<amrex::Real> d = dst_2d.array(mfi);
153  amrex::Array4<const amrex::Real> s = src_3d.const_array(mfi);
154  amrex::ParallelFor(mfi.tilebox(), [=] AMREX_GPU_DEVICE (const amrex::IntVect& iv) {
155  d(iv[0], iv[1], 0) = s(iv[0], iv[1], 0);
156  });
157  }
158 }
Here is the call graph for this function:

◆ fire_host_copy()

void fire_host_copy ( amrex::MultiFab &  dst,
const amrex::MultiFab &  src,
int  ncomp = 1,
int  nghost = 0 
)
inline

Copy a MultiFab between device and host-accessible memory, for an engine whose fire physics runs on the host.

The memory contract of ERF_FireEngine.H: the coupling's fields are in the default arena (device memory on a GPU build) and are only valid during the call that hands them over; an engine's returned fields must be readable there too. dst and src have the same BoxArray and DistributionMapping; ncomp components and nghost ghost cells are copied from component 0. dst belongs to the caller (allocate a host copy once with amrex::MFInfo().SetArena(amrex::The_Pinned_Arena()), or The_Managed_Arena(), and reuse it). The copy completes before the call returns: the GPU stream is synchronised, so the host may read dst, or the device read it, right away. On a CPU build it is a plain copy.

177 {
178  AMREX_ALWAYS_ASSERT(dst.boxArray() == src.boxArray() && dst.DistributionMap() == src.DistributionMap());
179  amrex::MultiFab::Copy(dst, src, 0, 0, ncomp, nghost);
180  amrex::Gpu::streamSynchronize();
181 }
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
Here is the call graph for this function: