ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
near_surface_diagnostics Namespace Reference

Classes

struct  NativeBundle
 
struct  NativeAggregate
 
struct  MostState
 
struct  MostProfile
 
struct  Sources
 

Functions

void fill (MultiFab &dst, int temperature_comp, int mixing_ratio_comp, int source_comp, const Sources &sources, Real missing_value)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool valid_real (amrex::Real value) noexcept
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool valid_noahmp_component (amrex::Real value) noexcept
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool native_bundle_temperature_is_valid (const NativeBundle &bundle) noexcept
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool native_bundle_mixing_ratio_is_valid (const NativeBundle &bundle) noexcept
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool native_bundle_vegetation_fraction_is_valid (const NativeBundle &bundle) noexcept
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool native_bundle_is_valid (const NativeBundle &bundle) noexcept
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE NativeAggregate aggregate_native_bundle (const NativeBundle &bundle) noexcept
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool evaluate_most_factor (const MostState &state, amrex::Real height, amrex::Real &factor) noexcept
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool evaluate_most_profile (const MostState &state, amrex::Real height, MostProfile &profile) noexcept
 
void fill (amrex::MultiFab &dst, int temperature_comp, int mixing_ratio_comp, int source_comp, const Sources &sources, amrex::Real missing_value=amrex::Real(-999.0))
 

Function Documentation

◆ aggregate_native_bundle()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE NativeAggregate near_surface_diagnostics::aggregate_native_bundle ( const NativeBundle bundle)
noexcept
111 {
112  const amrex::Real f = bundle.vegetation_fraction;
113  return {
114  f * bundle.temperature_vegetated + (amrex::Real(1.0)-f) * bundle.temperature_bare,
115  f * bundle.mixing_ratio_vegetated + (amrex::Real(1.0)-f) * bundle.mixing_ratio_bare
116  };
117 }
amrex::Real Real
Definition: ERF_ShocInterface.H:19

Referenced by fill().

Here is the caller graph for this function:

◆ evaluate_most_factor()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool near_surface_diagnostics::evaluate_most_factor ( const MostState state,
amrex::Real  height,
amrex::Real factor 
)
noexcept
123 {
124  if (!valid_real(state.roughness_height) ||
125  !valid_real(state.obukhov_length) ||
126  state.roughness_height <= amrex::Real(0.0) ||
127  height <= state.roughness_height ||
128  state.obukhov_length == amrex::Real(0.0)) {
129  return false;
130  }
131  const similarity_funs sfuns;
132  factor = std::log(height / state.roughness_height) -
133  sfuns.calc_psi_h(height / state.obukhov_length);
134  return valid_real(factor);
135 }
Real height
Definition: ERF_InitCustomPert_SquallLine.H:33
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool valid_real(amrex::Real value) noexcept
Definition: ERF_NearSurfaceDiagnostics.H:48
Definition: ERF_MOSTStress.H:40
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_h(amrex::Real zeta) const
Definition: ERF_MOSTStress.H:104

Referenced by evaluate_most_profile(), and fill().

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

◆ evaluate_most_profile()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool near_surface_diagnostics::evaluate_most_profile ( const MostState state,
amrex::Real  height,
MostProfile profile 
)
noexcept
143 {
144  if (!valid_real(state.theta_surface) || !valid_real(state.theta_star) ||
145  !valid_real(state.mixing_ratio_surface) || !valid_real(state.mixing_ratio_star)) {
146  return false;
147  }
148 
149  amrex::Real profile_factor = amrex::Real(0.0);
150  if (!evaluate_most_factor(state, height, profile_factor)) {
151  return false;
152  }
153 
154  profile.potential_temperature = state.theta_surface +
155  state.theta_star / KAPPA * profile_factor;
156  profile.mixing_ratio = state.mixing_ratio_surface +
157  state.mixing_ratio_star / KAPPA * profile_factor;
158  return valid_real(profile.potential_temperature) &&
159  valid_real(profile.mixing_ratio) &&
160  profile.potential_temperature > amrex::Real(0.0) &&
161  profile.mixing_ratio >= amrex::Real(0.0);
162 }
constexpr amrex::Real KAPPA
Definition: ERF_Constants.H:63
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool evaluate_most_factor(const MostState &state, amrex::Real height, amrex::Real &factor) noexcept
Definition: ERF_NearSurfaceDiagnostics.H:120
Here is the call graph for this function:

◆ fill() [1/2]

void near_surface_diagnostics::fill ( amrex::MultiFab &  dst,
int  temperature_comp,
int  mixing_ratio_comp,
int  source_comp,
const Sources sources,
amrex::Real  missing_value = amrex::Real(-999.0) 
)

◆ fill() [2/2]

void near_surface_diagnostics::fill ( MultiFab &  dst,
int  temperature_comp,
int  mixing_ratio_comp,
int  source_comp,
const Sources sources,
Real  missing_value 
)
47 {
48 #ifdef _OPENMP
49 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
50 #endif
51  for (MFIter mfi(dst, TilingIfNotGPU()); mfi.isValid(); ++mfi) {
52  const Box& bx = mfi.tilebox();
53  const auto dst_arr = dst.array(mfi);
54 
55  const auto tv = array_or_empty(sources.native_temperature_vegetated, mfi);
56  const auto tb = array_or_empty(sources.native_temperature_bare, mfi);
57  const auto qv = array_or_empty(sources.native_mixing_ratio_vegetated, mfi);
58  const auto qb = array_or_empty(sources.native_mixing_ratio_bare, mfi);
59  const auto fv = array_or_empty(sources.native_vegetation_fraction, mfi);
60  const auto ts = array_or_empty(sources.theta_surface, mfi);
61  const auto tstar = array_or_empty(sources.theta_star, mfi);
62  const auto qs = array_or_empty(sources.mixing_ratio_surface, mfi);
63  const auto qstar = array_or_empty(sources.mixing_ratio_star, mfi);
64  const auto z0 = array_or_empty(sources.roughness_height, mfi);
65  const auto olen = array_or_empty(sources.obukhov_length, mfi);
66  const auto source_mask = array_or_empty(sources.source_mask, mfi);
67  const auto lmask = int_array_or_empty(sources.land_mask, mfi);
68  const auto cons = array_or_empty(sources.cons, mfi);
69  const auto znd = array_or_empty(sources.z_phys_nd, mfi);
70 
71  const bool request_temperature = temperature_comp >= 0;
72  const bool request_mixing_ratio = mixing_ratio_comp >= 0;
73  const bool request_source = source_comp >= 0;
74  // Provenance follows the temperature path only for a source-only
75  // request. When paired with humidity, it describes the humidity
76  // source without adding an unrequested temperature prerequisite.
77  const bool source_only = request_source && !request_temperature &&
78  !request_mixing_ratio;
79  const bool need_temperature = request_temperature || source_only;
80  const bool need_mixing_ratio = request_mixing_ratio;
81  const bool have_native_temperature = sources.native_temperature_vegetated &&
82  sources.native_temperature_bare &&
83  sources.native_vegetation_fraction;
84  const bool have_native_mixing_ratio = sources.native_mixing_ratio_vegetated &&
85  sources.native_mixing_ratio_bare &&
86  sources.native_vegetation_fraction;
87  const bool have_most_temperature = sources.theta_surface && sources.theta_star &&
88  sources.roughness_height && sources.obukhov_length;
89  const bool have_most_mixing_ratio = sources.mixing_ratio_surface &&
90  sources.mixing_ratio_star &&
91  sources.roughness_height && sources.obukhov_length;
92  const bool have_atmosphere = sources.cons != nullptr;
93  const bool have_source_mask = sources.source_mask != nullptr;
94  const bool have_land_mask = sources.land_mask != nullptr;
95  const int klo = sources.klo;
96  const Real dz = sources.dz;
97  const bool moist = sources.moist;
98  const bool has_lsm = sources.has_lsm;
99 
100  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
101  Real temperature = missing_value;
102  Real mixing_ratio = missing_value;
105 
106  const NativeBundle native_bundle{
107  have_native_temperature ? tv(i,j,0) : missing_value,
108  have_native_temperature ? tb(i,j,0) : missing_value,
109  have_native_mixing_ratio ? qv(i,j,0) : missing_value,
110  have_native_mixing_ratio ? qb(i,j,0) : missing_value,
111  (have_native_temperature || have_native_mixing_ratio) ? fv(i,j,0) : missing_value
112  };
113  const bool native_temperature_valid = have_native_temperature &&
114  native_bundle_temperature_is_valid(native_bundle);
115  const bool native_mixing_ratio_valid = moist && have_native_mixing_ratio &&
117  const bool native_selected = (!need_temperature || native_temperature_valid) &&
118  (!need_mixing_ratio || native_mixing_ratio_valid);
119 
120  bool selected = false;
121  if (native_selected && (need_temperature || need_mixing_ratio)) {
122  const NativeAggregate aggregate = aggregate_native_bundle(native_bundle);
123  if (need_temperature) {
124  temperature = aggregate.temperature;
125  }
126  if (need_mixing_ratio) {
127  mixing_ratio = aggregate.mixing_ratio;
128  }
129  source_value = surface_diagnostics::to_plot_value(
131  selected = true;
132  }
133 
134  if (!selected && (need_temperature || need_mixing_ratio)) {
135  const MostState state{
136  have_most_temperature ? ts(i,j,0) : missing_value,
137  have_most_temperature ? tstar(i,j,0) : missing_value,
138  have_most_mixing_ratio ? qs(i,j,0) : missing_value,
139  have_most_mixing_ratio ? qstar(i,j,0) : missing_value,
140  (have_most_temperature || have_most_mixing_ratio) ? z0(i,j,0) : missing_value,
141  (have_most_temperature || have_most_mixing_ratio) ? olen(i,j,0) : missing_value
142  };
143  Real factor = zero;
144  const bool common_most_valid = evaluate_most_factor(state, Real(2.0), factor);
145  bool most_temperature_valid = false;
146  bool most_mixing_ratio_valid = false;
147  Real theta_2m = missing_value;
148  Real q_2m = missing_value;
149  if (common_most_valid && need_temperature && have_most_temperature) {
150  theta_2m = state.theta_surface + state.theta_star / KAPPA * factor;
151  if (valid_real(theta_2m) && theta_2m > zero && have_atmosphere) {
152  const Real rho = cons(i,j,klo,Rho_comp);
153  const Real rhotheta = cons(i,j,klo,RhoTheta_comp);
154  const Real q_cell = moist ? cons(i,j,klo,RhoQ1_comp) / rho : zero;
155  if (valid_real(rho) && rho > zero && valid_real(rhotheta) &&
156  valid_real(q_cell) && q_cell >= zero) {
157  const Real p_cc = getPgivenRTh(rhotheta, q_cell);
158  const Real z_cc_agl = znd ? Compute_Zrel_AtCellCenter(i,j,klo,znd)
159  : Real(0.5) * dz;
160  const Real p_2m = p_cc + rho * CONST_GRAV *
161  (z_cc_agl - Real(2.0));
162  const Real t_2m = (valid_real(p_2m) && p_2m > zero)
163  ? getTgivenPandTh(p_2m, theta_2m, R_d/Cp_d)
164  : missing_value;
165  most_temperature_valid = valid_real(t_2m) && t_2m > zero;
166  if (most_temperature_valid) { temperature = t_2m; }
167  }
168  }
169  }
170  if (common_most_valid && need_mixing_ratio && moist &&
171  have_most_mixing_ratio && valid_real(state.mixing_ratio_surface) &&
172  valid_real(state.mixing_ratio_star)) {
173  q_2m = state.mixing_ratio_surface + state.mixing_ratio_star / KAPPA * factor;
174  most_mixing_ratio_valid = valid_real(q_2m) && q_2m >= zero;
175  if (most_mixing_ratio_valid) {
176  mixing_ratio = q_2m;
177  }
178  }
179  const bool most_selected = (!need_temperature || most_temperature_valid) &&
180  (!need_mixing_ratio || most_mixing_ratio_valid);
181  // Do not expose a valid scalar from an incomplete MOST bundle
182  // when both requested fields must come from one source.
183  if (!most_selected) {
184  temperature = missing_value;
185  mixing_ratio = missing_value;
186  }
187  if (most_selected) {
188  if (have_source_mask && source_value_is_valid(source_mask(i,j,0))) {
189  source_value = source_mask(i,j,0);
190  if (static_cast<int>(source_value) ==
192  source_value = surface_diagnostics::to_plot_value(
194  }
195  } else if (have_land_mask && lmask(i,j,0) == 0) {
196  source_value = surface_diagnostics::to_plot_value(
198  } else {
199  source_value = surface_diagnostics::to_plot_value(
202  }
203  selected = true;
204  }
205  }
206 
207  if (temperature_comp >= 0) {
208  dst_arr(i,j,k,temperature_comp) = temperature;
209  }
210  if (mixing_ratio_comp >= 0) {
211  dst_arr(i,j,k,mixing_ratio_comp) = (selected && moist)
212  ? mixing_ratio : missing_value;
213  }
214  if (source_comp >= 0) {
215  dst_arr(i,j,k,source_comp) = source_value;
216  }
217  });
218  }
219 }
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:49
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:64
constexpr amrex::Real R_d
Definition: ERF_Constants.H:47
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
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenPandTh(const amrex::Real P, const amrex::Real th, const amrex::Real rdOcp)
Definition: ERF_EOS.H:32
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:8
rho
Definition: ERF_InitCustomPert_Bubble.H:107
ParallelFor(grown_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_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_Zrel_AtCellCenter(const int &i, const int &j, const int &k, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:389
@ qv
Definition: ERF_Kessler.H:30
@ qs
Definition: ERF_WSM6.H:29
@ cons
Definition: ERF_IndexDefines.H:175
@ dz
Definition: ERF_AdvanceWSM6.cpp:104
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool native_bundle_temperature_is_valid(const NativeBundle &bundle) noexcept
Definition: ERF_NearSurfaceDiagnostics.H:78
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE NativeAggregate aggregate_native_bundle(const NativeBundle &bundle) noexcept
Definition: ERF_NearSurfaceDiagnostics.H:110
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool native_bundle_mixing_ratio_is_valid(const NativeBundle &bundle) noexcept
Definition: ERF_NearSurfaceDiagnostics.H:90
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real to_plot_value(SurfaceDiagnosticSource source) noexcept
Definition: ERF_SurfaceDiagnosticSource.H:35
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int to_int(SurfaceDiagnosticSource source) noexcept
Definition: ERF_SurfaceDiagnosticSource.H:28

Referenced by PlaneAverage::operator()(), and ERF::Write2DPlotFile().

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

◆ native_bundle_is_valid()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool near_surface_diagnostics::native_bundle_is_valid ( const NativeBundle bundle)
noexcept
71 {
72  return native_bundle_temperature_is_valid(bundle) &&
75 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool native_bundle_vegetation_fraction_is_valid(const NativeBundle &bundle) noexcept
Definition: ERF_NearSurfaceDiagnostics.H:102
Here is the call graph for this function:

◆ native_bundle_mixing_ratio_is_valid()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool near_surface_diagnostics::native_bundle_mixing_ratio_is_valid ( const NativeBundle bundle)
noexcept
91 {
92  return valid_noahmp_component(bundle.mixing_ratio_vegetated) &&
93  valid_noahmp_component(bundle.mixing_ratio_bare) &&
94  valid_noahmp_component(bundle.vegetation_fraction) &&
95  bundle.mixing_ratio_vegetated >= amrex::Real(0.0) &&
96  bundle.mixing_ratio_bare >= amrex::Real(0.0) &&
97  bundle.vegetation_fraction >= amrex::Real(0.0) &&
98  bundle.vegetation_fraction <= amrex::Real(1.0);
99 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool valid_noahmp_component(amrex::Real value) noexcept
Definition: ERF_NearSurfaceDiagnostics.H:54

Referenced by fill(), and native_bundle_is_valid().

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

◆ native_bundle_temperature_is_valid()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool near_surface_diagnostics::native_bundle_temperature_is_valid ( const NativeBundle bundle)
noexcept
79 {
80  return valid_noahmp_component(bundle.temperature_vegetated) &&
81  valid_noahmp_component(bundle.temperature_bare) &&
82  bundle.temperature_vegetated > amrex::Real(0.0) &&
83  bundle.temperature_bare > amrex::Real(0.0) &&
84  valid_noahmp_component(bundle.vegetation_fraction) &&
85  bundle.vegetation_fraction >= amrex::Real(0.0) &&
86  bundle.vegetation_fraction <= amrex::Real(1.0);
87 }

Referenced by fill(), and native_bundle_is_valid().

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

◆ native_bundle_vegetation_fraction_is_valid()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool near_surface_diagnostics::native_bundle_vegetation_fraction_is_valid ( const NativeBundle bundle)
noexcept
103 {
104  return valid_noahmp_component(bundle.vegetation_fraction) &&
105  bundle.vegetation_fraction >= amrex::Real(0.0) &&
106  bundle.vegetation_fraction <= amrex::Real(1.0);
107 }

Referenced by native_bundle_is_valid().

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

◆ valid_noahmp_component()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool near_surface_diagnostics::valid_noahmp_component ( amrex::Real  value)
noexcept
55 {
56  return valid_real(value) && value > amrex::Real(-9990.0) &&
58 }
constexpr amrex::Real lsm_undefined
Definition: ERF_Constants.H:35
Real value
Definition: ERF_HurricaneDiagnostics.cpp:30

Referenced by native_bundle_mixing_ratio_is_valid(), native_bundle_temperature_is_valid(), and native_bundle_vegetation_fraction_is_valid().

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

◆ valid_real()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool near_surface_diagnostics::valid_real ( amrex::Real  value)
noexcept
49 {
50  return std::isfinite(value);
51 }

Referenced by evaluate_most_factor(), evaluate_most_profile(), fill(), and valid_noahmp_component().

Here is the caller graph for this function: