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

Classes

struct  ConversionFailure
 

Enumerations

enum class  ConversionError : int {
  none = 0 , bad_density , no_moisture_comp , bad_rho_qv ,
  bad_qv , bad_theta_to_temperature , bad_temperature_to_theta , bad_pressure ,
  bad_skin_temperature , bad_q_air , bad_q_surf
}
 

Functions

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pressure_at_boundary_from_cell (const amrex::Real rho, const amrex::Real rho_theta, const amrex::Real qv, const amrex::Real delta_z)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pressure_at_surface (const amrex::Real rho, const amrex::Real rho_theta, const amrex::Real qv, const amrex::Real delta_z)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool valid_pressure (const amrex::Real pressure)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool valid_temperature (const amrex::Real temperature)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool theta_to_temperature (const amrex::Real theta, const amrex::Real pressure, const amrex::Real rdOcp, amrex::Real &temperature)
 
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool temperature_to_theta (const amrex::Real temperature, const amrex::Real pressure, const amrex::Real rdOcp, amrex::Real &theta)
 
AMREX_GPU_DEVICE AMREX_FORCE_INLINE void record_conversion_failure (ConversionFailure *fail, const bool fatal, const ConversionError code, const int i, const int j, const int k, const amrex::Real rho=amrex::Real(0.0), const amrex::Real rho_theta=amrex::Real(0.0), const amrex::Real rho_qv=amrex::Real(0.0), const amrex::Real t_surf=amrex::Real(0.0), const amrex::Real pressure=amrex::Real(0.0), const amrex::Real delta_z=amrex::Real(0.0), const amrex::Real q_air=amrex::Real(0.0))
 
AMREX_FORCE_INLINE const char * conversion_error_text (const ConversionError code)
 
void abort_on_conversion_failure (const char *who, const int lev, ConversionFailure const &fail)
 

Enumeration Type Documentation

◆ ConversionError

Why a surface conversion could not be made, in the order the kernels test for it.

Every kernel that converts between the atmospheric state and a surface temperature or humidity guards the same sequence of ways that state can be unusable. Which guard tripped is the difference between "the surface layer gave up" and knowing that the state handed to it was already bad – so the guards are named rather than merged into a single flag.

Enumerator
none 
bad_density 
no_moisture_comp 
bad_rho_qv 
bad_qv 
bad_theta_to_temperature 
bad_temperature_to_theta 
bad_pressure 
bad_skin_temperature 
bad_q_air 
bad_q_surf 

Function Documentation

◆ abort_on_conversion_failure()

void erf_surface_temperature::abort_on_conversion_failure ( const char *  who,
const int  lev,
ConversionFailure const &  fail 
)
inline

Describe what this rank recorded, then abort if any rank recorded anything.

Collective: every rank must call this. Each rank that failed describes its own first failure before the abort, so a failure confined to one rank still names the cell and the numbers rather than only the check that tripped.

Parameters
[in]whoName of the fill, used to open the message
[in]levLevel being filled
[in]failThis rank's record
239 {
240  int any_failed = (fail.code != static_cast<int>(ConversionError::none)) ? 1 : 0;
241  amrex::ParallelDescriptor::ReduceIntMax(any_failed);
242  if (any_failed == 0) { return; }
243 
244  if (fail.code != static_cast<int>(ConversionError::none)) {
245  const auto code = static_cast<ConversionError>(fail.code);
246 
247  const bool is_conversion = (code == ConversionError::bad_theta_to_temperature ||
248  code == ConversionError::bad_temperature_to_theta);
249  const bool has_state = (code != ConversionError::no_moisture_comp);
250  const bool has_vapor = (is_conversion ||
251  code == ConversionError::bad_rho_qv ||
252  code == ConversionError::bad_qv ||
253  code == ConversionError::bad_q_air ||
254  code == ConversionError::bad_q_surf);
255  const bool has_surface = (is_conversion ||
256  code == ConversionError::bad_pressure ||
257  code == ConversionError::bad_skin_temperature ||
258  code == ConversionError::bad_q_surf);
259  const bool has_q_air = (code == ConversionError::bad_q_air ||
260  code == ConversionError::bad_q_surf);
261 
262  // Assemble the whole report before writing it, so that ranks that failed do not
263  // interleave their lines with one another
264  std::ostringstream msg;
265  msg << who << ": surface conversion failed at level " << lev
266  << " [rank " << amrex::ParallelDescriptor::MyProc() << "]\n"
267  << " " << fail.count << " of the cells this fill owns failed";
268  if (fail.halo_count > 0) {
269  msg << " (and " << fail.halo_count << " halo cells, which are not fatal)";
270  }
271  msg << "\n first failure at (" << fail.i << "," << fail.j << "," << fail.k << "): "
272  << conversion_error_text(code) << "\n";
273 
274  if (has_state) {
275  msg << std::setprecision(10) << " rho = " << fail.rho
276  << " (rho theta) = " << fail.rho_theta;
277  if (has_vapor) { msg << " (rho qv) = " << fail.rho_qv; }
278  if (has_q_air) { msg << " q_air = " << fail.q_air; }
279  if (has_surface) {
280  msg << "\n surface temperature = " << fail.t_surf
281  << " pressure = " << fail.pressure
282  << " delta_z = " << fail.delta_z;
283  }
284  msg << "\n";
285  }
286 
287  amrex::AllPrint() << msg.str() << std::flush;
288  }
289 
290  // Let every rank finish writing before one of them tears the job down
291  amrex::ParallelDescriptor::Barrier();
292  amrex::Abort(std::string(who) + ": could not convert the surface state (see above)");
293 }
AMREX_FORCE_INLINE const char * conversion_error_text(const ConversionError code)
Definition: ERF_SurfaceTemperature.H:196
ConversionError
Definition: ERF_SurfaceTemperature.H:105

Referenced by SurfaceLayer::fill_qsurf_with_qsat(), SurfaceLayer::fill_qsurf_with_skin_moisture(), SurfaceLayer::fill_tsurf_with_coupled_sst(), SurfaceLayer::fill_tsurf_with_sfc_sst(), and SurfaceLayer::fill_tsurf_with_skin_temperature().

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

◆ conversion_error_text()

AMREX_FORCE_INLINE const char* erf_surface_temperature::conversion_error_text ( const ConversionError  code)
197 {
198  switch (code) {
199  case ConversionError::bad_density:
200  return "the density or (rho theta) of the state cell is not usable";
201  case ConversionError::no_moisture_comp:
202  return "the state carries no water vapor component to convert";
203  case ConversionError::bad_rho_qv:
204  return "the (rho qv) of the state cell is not usable";
205  case ConversionError::bad_qv:
206  return "the water vapor mixing ratio derived from the state cell is not usable";
207  case ConversionError::bad_theta_to_temperature:
208  return "the surface potential temperature could not be converted to absolute temperature";
209  case ConversionError::bad_temperature_to_theta:
210  return "the surface temperature could not be converted to potential temperature";
211  case ConversionError::bad_pressure:
212  return "the surface pressure derived from the state cell is not usable";
213  case ConversionError::bad_skin_temperature:
214  return "the skin temperature is not usable";
215  case ConversionError::bad_q_air:
216  return "the reference-height water vapor mixing ratio is not usable";
217  case ConversionError::bad_q_surf:
218  return "the surface mixing ratio came out non-finite";
219  default:
220  return "the conversion failed for a reason that was not recorded";
221  }
222 }

Referenced by abort_on_conversion_failure().

Here is the caller graph for this function:

◆ pressure_at_boundary_from_cell()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_surface_temperature::pressure_at_boundary_from_cell ( const amrex::Real  rho,
const amrex::Real  rho_theta,
const amrex::Real  qv,
const amrex::Real  delta_z 
)

Pressure at a boundary face from the adjacent atmospheric cell state.

The state pressure is diagnosed at the cell centre. Adding rho*g*delta_z gives the pressure at the boundary face, where delta_z is the signed distance from the face to the cell centre.

30 {
31  return getPgivenRTh(rho_theta, qv) + rho * CONST_GRAV * delta_z;
32 }
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:68
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
@ rho
Definition: ERF_Kessler.H:25
@ qv
Definition: ERF_Kessler.H:31

Referenced by SurfaceLayer::fill_qsurf_with_qsat(), SurfaceLayer::fill_qsurf_with_skin_moisture(), SurfaceLayer::fill_tsurf_with_coupled_sst(), SurfaceLayer::fill_tsurf_with_sfc_sst(), SurfaceLayer::fill_tsurf_with_skin_temperature(), and pressure_at_surface().

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

◆ pressure_at_surface()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_surface_temperature::pressure_at_surface ( const amrex::Real  rho,
const amrex::Real  rho_theta,
const amrex::Real  qv,
const amrex::Real  delta_z 
)
40 {
41  return pressure_at_boundary_from_cell(rho, rho_theta, qv, delta_z);
42 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pressure_at_boundary_from_cell(const amrex::Real rho, const amrex::Real rho_theta, const amrex::Real qv, const amrex::Real delta_z)
Definition: ERF_SurfaceTemperature.H:26

Referenced by Radiation::mf_to_kokkos_buffers(), and vertical_two_stream_sweep().

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

◆ record_conversion_failure()

AMREX_GPU_DEVICE AMREX_FORCE_INLINE void erf_surface_temperature::record_conversion_failure ( ConversionFailure *  fail,
const bool  fatal,
const ConversionError  code,
const int  i,
const int  j,
const int  k,
const amrex::Real  rho = amrex::Real(0.0),
const amrex::Real  rho_theta = amrex::Real(0.0),
const amrex::Real  rho_qv = amrex::Real(0.0),
const amrex::Real  t_surf = amrex::Real(0.0),
const amrex::Real  pressure = amrex::Real(0.0),
const amrex::Real  delta_z = amrex::Real(0.0),
const amrex::Real  q_air = amrex::Real(0.0) 
)

Record one cell's failure.

Every failing cell adds to a count; the first authoritative one to arrive also claims the description, so what gets reported is a failure that matters rather than whichever thread happened to finish last. Pass the values the caller has reached by this point: the report prints the ones that mean something for the code it is given.

Parameters
[in,out]failThis rank's record
[in]fatalWhether this is a cell the fill is authoritative for
[in]codeWhich guard tripped
[in]i,j,kThe cell whose state was read
170 {
171  if (!fatal) {
172  amrex::Gpu::Atomic::Add(&fail->halo_count, 1);
173  return;
174  }
175 
176  amrex::Gpu::Atomic::Add(&fail->count, 1);
177 
178  // The first failure to arrive owns the description; the rest only add to the count.
179  constexpr int unclaimed = static_cast<int>(ConversionError::none);
180  if (amrex::Gpu::Atomic::CAS(&fail->code, unclaimed, static_cast<int>(code)) != unclaimed) {
181  return;
182  }
183 
184  fail->i = i; fail->j = j; fail->k = k;
185  fail->rho = rho;
186  fail->rho_theta = rho_theta;
187  fail->rho_qv = rho_qv;
188  fail->t_surf = t_surf;
189  fail->pressure = pressure;
190  fail->delta_z = delta_z;
191  fail->q_air = q_air;
192 }

Referenced by SurfaceLayer::fill_qsurf_with_qsat(), SurfaceLayer::fill_qsurf_with_skin_moisture(), SurfaceLayer::fill_tsurf_with_coupled_sst(), SurfaceLayer::fill_tsurf_with_sfc_sst(), and SurfaceLayer::fill_tsurf_with_skin_temperature().

Here is the caller graph for this function:

◆ temperature_to_theta()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool erf_surface_temperature::temperature_to_theta ( const amrex::Real  temperature,
const amrex::Real  pressure,
const amrex::Real  rdOcp,
amrex::Real &  theta 
)
83 {
84  if (!valid_pressure(pressure) || !valid_temperature(temperature) ||
85  !amrex::Math::isfinite(rdOcp) || rdOcp <= amrex::Real(0.0)) {
86  return false;
87  }
88  const amrex::Real result = getThgivenTandP(temperature, pressure, rdOcp);
89  if (!valid_temperature(result)) {
90  return false;
91  }
92  theta = result;
93  return true;
94 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getThgivenTandP(const amrex::Real T, const amrex::Real P, const amrex::Real rdOcp)
Definition: ERF_EOS.H:18
const Real rdOcp
Definition: ERF_InitCustomPert_ABL.H:72
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ theta
Definition: ERF_Kessler.H:26
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool valid_pressure(const amrex::Real pressure)
Definition: ERF_SurfaceTemperature.H:46
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool valid_temperature(const amrex::Real temperature)
Definition: ERF_SurfaceTemperature.H:53

Referenced by SurfaceLayer::fill_tsurf_with_coupled_sst(), SurfaceLayer::fill_tsurf_with_sfc_sst(), SurfaceLayer::fill_tsurf_with_skin_temperature(), and metgrid_surface_theta().

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

◆ theta_to_temperature()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool erf_surface_temperature::theta_to_temperature ( const amrex::Real  theta,
const amrex::Real  pressure,
const amrex::Real  rdOcp,
amrex::Real &  temperature 
)
64 {
65  if (!valid_pressure(pressure) || !valid_temperature(theta) ||
66  !amrex::Math::isfinite(rdOcp) || rdOcp <= amrex::Real(0.0)) {
67  return false;
68  }
69  const amrex::Real result = getTgivenPandTh(pressure, theta, rdOcp);
70  if (!valid_temperature(result)) {
71  return false;
72  }
73  temperature = result;
74  return true;
75 }
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

Referenced by SurfaceLayer::fill_qsurf_with_qsat(), rrtmgp::resolve_surface_temperature(), and vertical_two_stream_sweep().

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

◆ valid_pressure()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool erf_surface_temperature::valid_pressure ( const amrex::Real  pressure)
47 {
48  return amrex::Math::isfinite(pressure) && pressure > amrex::Real(0.0);
49 }

Referenced by SurfaceLayer::fill_qsurf_with_skin_moisture(), temperature_to_theta(), and theta_to_temperature().

Here is the caller graph for this function:

◆ valid_temperature()

AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool erf_surface_temperature::valid_temperature ( const amrex::Real  temperature)
54 {
55  return amrex::Math::isfinite(temperature) && temperature > amrex::Real(0.0);
56 }

Referenced by SurfaceLayer::fill_qsurf_with_skin_moisture(), temperature_to_theta(), and theta_to_temperature().

Here is the caller graph for this function: