ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SAMUtils.H
Go to the documentation of this file.
1 #ifndef ERF_SAM_UTILS_H_
2 #define ERF_SAM_UTILS_H_
3 
4 #include <cmath>
5 #include <limits>
6 
7 #include <AMReX_Array4.H>
8 #include <AMReX_GpuQualifiers.H>
9 
10 #include "ERF_Constants.H"
11 #include "ERF_DataStruct.H"
12 #include "ERF_EOS.H"
13 #include "ERF_IndexDefines.H"
14 #include "ERF_MicrophysicsUtils.H"
15 
20 };
21 
33 };
34 
49 };
50 
65 };
66 
68 
71  bool enable_precip{true};
84 };
85 
96 };
97 
111 };
112 
122 };
123 
130 };
131 
132 struct SAMFaceState {
137 };
138 
143 };
144 
149 };
150 
151 // SAM local source updates are treated as constant-pressure microphysics
152 // updates. Copy-in reconstructs tabs and pres_mbar from the conserved state;
153 // source helpers hold pres_mbar fixed while latent heating/cooling changes
154 // tabs; theta is then refreshed from T and the held pressure. Pressure is
155 // stored in mbar on this path, EOS/theta helpers expect Pa, and the saturation
156 // helpers below consume mbar where SAM currently calls them that way.
157 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
158 amrex::Real sam_mbar_to_pa (const amrex::Real& pres_mbar) noexcept
159 {
160  // SAM stores pressure in mbar. EOS and theta helpers expect Pa.
161  return amrex::Real(100.0) * pres_mbar;
162 }
163 
164 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
165 amrex::Real sam_pa_to_mbar (const amrex::Real& pres_pa) noexcept
166 {
167  return amrex::Real(0.01) * pres_pa;
168 }
169 
170 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
172  const amrex::Real& pres_mbar,
173  const amrex::Real rdOcp) noexcept
174 {
175  // Do not replace this with getThgivenRandT(rho,T,qv): that would enforce a
176  // fixed-density EOS projection rather than the SAM source-step
177  // thermodynamic contract.
178  return getThgivenTandP(tabs, sam_mbar_to_pa(pres_mbar), rdOcp);
179 }
180 
181 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
183  const amrex::Real& rho_theta,
184  const amrex::Real& rho_qv,
185  const amrex::Real& rho_qcl,
186  const amrex::Real& rho_qci,
187  const amrex::Real& rho_qpr,
188  const amrex::Real& rho_qps,
189  const amrex::Real& rho_qpg) noexcept
190 {
191  // Copy-in reconstructs the SAM primitive cell state from the conserved ERF
192  // state, clips negative moisture defensively, and diagnoses tabs and
193  // pres_mbar from the incoming rho*theta/rho*q state. That diagnosed mbar
194  // pressure is the held pressure for the following source updates.
195  SAMPrimitiveCell result{};
196  result.rho = rho;
197  result.theta = rho_theta / rho;
198  result.qv = amrex::max(amrex::Real(0.0), rho_qv / rho);
199  result.qcl = amrex::max(amrex::Real(0.0), rho_qcl / rho);
200  result.qci = amrex::max(amrex::Real(0.0), rho_qci / rho);
201  result.qn = result.qcl + result.qci;
202  result.qt = result.qv + result.qn;
203  result.qpr = amrex::max(amrex::Real(0.0), rho_qpr / rho);
204  result.qps = amrex::max(amrex::Real(0.0), rho_qps / rho);
205  result.qpg = amrex::max(amrex::Real(0.0), rho_qpg / rho);
206  result.qp = result.qpr + result.qps + result.qpg;
207  result.tabs = getTgivenRandRTh(rho, rho_theta, result.qv);
208  result.pres_mbar = sam_pa_to_mbar(getPgivenRTh(rho_theta, result.qv));
209  return result;
210 }
211 
212 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
214  const amrex::Array4<amrex::Real>& states_arr,
215  const int& i,
216  const int& j,
217  const int& k) noexcept
218 {
219  // Copy-out writes rho*theta and clipped moisture species back to the
220  // conserved state. Pressure is not stored here; it is diagnosed again on
221  // the next copy-in.
222  states_arr(i,j,k,RhoTheta_comp) = primitive.rho * primitive.theta;
223  states_arr(i,j,k,RhoQ1_comp) = primitive.rho * amrex::max(amrex::Real(0.0), primitive.qv);
224  states_arr(i,j,k,RhoQ2_comp) = primitive.rho * amrex::max(amrex::Real(0.0), primitive.qcl);
225  states_arr(i,j,k,RhoQ3_comp) = primitive.rho * amrex::max(amrex::Real(0.0), primitive.qci);
226  states_arr(i,j,k,RhoQ4_comp) = primitive.rho * amrex::max(amrex::Real(0.0), primitive.qpr);
227  states_arr(i,j,k,RhoQ5_comp) = primitive.rho * amrex::max(amrex::Real(0.0), primitive.qps);
228  states_arr(i,j,k,RhoQ6_comp) = primitive.rho * amrex::max(amrex::Real(0.0), primitive.qpg);
229 }
230 
231 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
232 bool sam_is_no_ice (const MoistureType& moisture_type) noexcept
233 {
234  return moisture_type == MoistureType::SAM_NoIce ||
235  moisture_type == MoistureType::SAM_NoPrecip_NoIce;
236 }
237 
238 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
239 bool sam_is_no_precip (const MoistureType& moisture_type) noexcept
240 {
241  return moisture_type == MoistureType::SAM_NoPrecip_NoIce;
242 }
243 
244 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
245 amrex::Real sam_cloud_liquid_fraction (const int& SAM_moisture_type,
246  const amrex::Real& tabs,
247  const amrex::Real an,
248  const amrex::Real bn) noexcept
249 {
250  // Empirical cloud phase-fraction closure for omega_n. No-ice mode forces
251  // liquid fraction to one; the warm branch is all liquid, the cold branch
252  // is all ice, and the mixed branch varies linearly with temperature.
253  if (SAM_moisture_type == 2) {
254  return one;
255  }
256  if (tabs >= tbgmax) {
257  return one;
258  }
259  if (tabs <= tbgmin) {
260  return zero;
261  }
262  return an * tabs - bn;
263 }
264 
265 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
266 amrex::Real sam_precip_rain_fraction (const int& SAM_moisture_type,
267  const amrex::Real& tabs) noexcept
268 {
269  // Empirical precipitating rain fraction omega_p. No-ice mode forces rain
270  // fraction to one, and the result is clipped to [0, 1].
271  if (SAM_moisture_type == 2) {
272  return one;
273  }
274  return amrex::max(amrex::Real(0.0), amrex::min(amrex::Real(1.0), (tabs - tprmin) * a_pr));
275 }
276 
277 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
278 amrex::Real sam_graupel_fraction (const int& SAM_moisture_type,
279  const amrex::Real& tabs) noexcept
280 {
281  // Empirical graupel fraction omega_g. No-ice mode forces graupel fraction
282  // to zero, and the result is clipped to [0, 1].
283  if (SAM_moisture_type == 2) {
284  return zero;
285  }
286  return amrex::max(amrex::Real(0.0), amrex::min(amrex::Real(1.0), (tabs - tgrmin) * a_gr));
287 }
288 
289 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
290 SAMCloudPhaseChange sam_partition_cloud_phase (const int& SAM_moisture_type,
291  const amrex::Real& tabs,
292  const amrex::Real& qn,
293  const amrex::Real& qcl,
294  const amrex::Real& qci,
295  const amrex::Real fac_cond,
296  const amrex::Real fac_fus,
297  const amrex::Real an,
298  const amrex::Real bn) noexcept
299 {
300  // Repartition cloud condensate between liquid and ice using omega_n while
301  // preserving total cloud condensate qn. The temperature increment accounts
302  // for fusion heating/cooling under the held-pressure source-step
303  // convention; no-ice mode collapses condensate into liquid.
304  SAMCloudPhaseChange result{};
305  result.qcl = qcl;
306  result.qci = qci;
307  result.tabs = tabs;
308  result.omn = sam_cloud_liquid_fraction(SAM_moisture_type, tabs, an, bn);
309 
310  if (SAM_moisture_type == 1) {
311  if (tabs >= tbgmax) {
312  result.omn = one;
313  result.delta_qi = qci;
314  result.qci = zero;
315  result.qcl += result.delta_qi;
316  result.tabs -= fac_fus * result.delta_qi;
317  } else if (tabs <= tbgmin) {
318  result.omn = zero;
319  result.delta_qc = qcl;
320  result.qcl = zero;
321  result.qci += result.delta_qc;
322  result.tabs += fac_fus * result.delta_qc;
323  } else {
324  result.delta_qc = qcl - qn * result.omn;
325  result.delta_qi = qci - qn * (one - result.omn);
326  result.qcl = qn * result.omn;
327  result.qci = qn * (one - result.omn);
328  result.tabs += fac_fus * result.delta_qc;
329  result.omn = sam_cloud_liquid_fraction(SAM_moisture_type, result.tabs, an, bn);
330  }
331  } else {
332  result.omn = one;
333  result.delta_qc = qcl - qn;
334  result.qcl = qn;
335  result.qci = zero;
336  result.tabs += fac_cond * result.delta_qc;
337  }
338 
339  result.qn = result.qcl + result.qci;
340  return result;
341 }
342 
343 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
345  const amrex::Real& qsatw,
346  const amrex::Real& qsati) noexcept
347 {
348  // Mixed liquid/ice saturation relation used by the SAM cloud adjustment.
349  return omn * qsatw + (one - omn) * qsati;
350 }
351 
352 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
354  const amrex::Real& domn,
355  const amrex::Real& qsatw,
356  const amrex::Real& qsati,
357  const amrex::Real& dqsatw,
358  const amrex::Real& dqsati) noexcept
359 {
360  // Temperature derivative of mixed saturation, including the mixed-branch
361  // temperature derivative of the liquid/ice phase fraction.
362  return omn * dqsatw + (one - omn) * dqsati + domn * qsatw - domn * qsati;
363 }
364 
365 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
367  const amrex::Real& domn,
368  const amrex::Real& qn,
369  const amrex::Real& dqsatm) noexcept
370 {
371  // Temperature derivative of the final ice fraction
372  return -domn * qn - (one - omn) * dqsatm;
373 }
374 
375 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
377  const amrex::Real& tabs_old,
378  const amrex::Real fcond,
379  const amrex::Real& qv,
380  const amrex::Real& qsatm,
381  const amrex::Real ffus,
382  const amrex::Real& qi,
383  const amrex::Real& qif) noexcept
384 {
385  // Residual for the local constant-pressure saturation adjustment solve.
386  return -tabs_new + tabs_old + fcond * (qv - qsatm) - ffus * (qi - qif);
387 }
388 
389 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
391  const amrex::Real ffus,
392  const amrex::Real& dqsatm,
393  const amrex::Real& dqif) noexcept
394 {
395  // Derivative for the local constant-pressure saturation adjustment solve.
396  return -one - fcond * dqsatm + ffus * dqif;
397 }
398 
399 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
401  const amrex::Real& qcc,
402  const amrex::Real& qii,
403  const amrex::Real& coefice_k) noexcept
404 {
405  SAMPrecipSources result{};
406  // Thresholded cloud-liquid and cloud-ice autoconversion increments over
407  // the microphysics time step dtn. The strict qcw0/qci0 thresholds are
408  // intentional: equality leaves the source inactive.
409  const amrex::Real auto_r = (qcc > qcw0) ? alphaelq : zero;
410  const amrex::Real autos = (qii > qci0) ? betaelq * coefice_k : zero;
411  result.dqca = dtn * auto_r * (qcc - qcw0);
412  result.dqia = dtn * autos * (qii - qci0);
413  return result;
414 }
415 
416 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
418  const amrex::Real& qcc,
419  const amrex::Real& qii,
420  const amrex::Real& qpr,
421  const amrex::Real& qps,
422  const amrex::Real& qpg,
423  const amrex::Real& powr1,
424  const amrex::Real& pows1,
425  const amrex::Real& powg1,
426  const amrex::Real& omp,
427  const amrex::Real& omg,
428  const amrex::Real& accrrc_k,
429  const amrex::Real& accrsc_k,
430  const amrex::Real& accrsi_k,
431  const amrex::Real& accrgc_k,
432  const amrex::Real& accrgi_k) noexcept
433 {
434  SAMPrecipSources result{};
435  amrex::Real accrcr = zero;
436  amrex::Real accrcs = zero;
437  amrex::Real accris = zero;
438  amrex::Real accrcg = zero;
439  amrex::Real accrig = zero;
440 
441  // Accretion increments over dtn. Liquid-origin sinks feed rain, snow, and
442  // graupel; ice-origin sinks feed snow and graupel. These strict empirical
443  // selector thresholds are implementation rules, not fundamental laws:
444  // rain requires omp > 0.001, snow requires omp < 0.999 and omg < 0.999,
445  // and graupel requires omp < 0.999 and omg > 0.001. Equality is inactive.
446  if (omp > amrex::Real(0.001)) {
447  accrcr = accrrc_k;
448  }
449  if (omp < amrex::Real(0.999) && omg < amrex::Real(0.999)) {
450  accrcs = accrsc_k;
451  accris = accrsi_k;
452  }
453  if (omp < amrex::Real(0.999) && omg > amrex::Real(0.001)) {
454  accrcg = accrgc_k;
455  accrig = accrgi_k;
456  }
457 
458  result.dprc = dtn * accrcr * qcc * std::pow(qpr, powr1);
459  result.dpsc = dtn * accrcs * qcc * std::pow(qps, pows1);
460  result.dpgc = dtn * accrcg * qcc * std::pow(qpg, powg1);
461  result.dpsi = dtn * accris * qii * std::pow(qps, pows1);
462  result.dpgi = dtn * accrig * qii * std::pow(qpg, powg1);
463  return result;
464 }
465 
466 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
468  const amrex::Real& qci,
469  const amrex::Real& eps,
470  SAMPrecipSources result) noexcept
471 {
472  // Proportional donor limiter. If requested liquid or ice sinks exceed
473  // available qcl/qci, all competing sinks from the same donor phase share
474  // one scale factor. This preserves source ratios while preventing negative
475  // qcl or qci. The eps denominator intentionally leaves only an epsilon-
476  // scale undershoot.
477  result.dqc = result.dqca + result.dprc + result.dpsc + result.dpgc;
478  result.dqi = result.dqia + result.dpsi + result.dpgi;
479 
480  const amrex::Real scalec = amrex::min(qcl, result.dqc) / (result.dqc + eps);
481  const amrex::Real scalei = amrex::min(qci, result.dqi) / (result.dqi + eps);
482 
483  result.dqca *= scalec;
484  result.dprc *= scalec;
485  result.dpsc *= scalec;
486  result.dpgc *= scalec;
487  result.dqia *= scalei;
488  result.dpsi *= scalei;
489  result.dpgi *= scalei;
490  result.dqc = result.dqca + result.dprc + result.dpsc + result.dpgc;
491  result.dqi = result.dqia + result.dpsi + result.dpgi;
492 
493  return result;
494 }
495 
496 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
498  const amrex::Real& omp,
499  const amrex::Real& omg) noexcept
500 {
501  // Partitions limited autoconversion sources into rain/snow/graupel using
502  // the precipitating phase fractions and adds direct accretion
503  // contributions. dqpr + dqps + dqpg equals the limited cloud sink total.
504  result.dqpr = (result.dqca + result.dqia) * omp + result.dprc;
505  result.dqps = (result.dqca + result.dqia) * (one - omp) * (one - omg) + result.dpsc + result.dpsi;
506  result.dqpg = (result.dqca + result.dqia) * (one - omp) * omg + result.dpgc + result.dpgi;
507  return result;
508 }
509 
510 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
512  const amrex::Real& qps,
513  const amrex::Real& qpg,
514  const amrex::Real& powr2,
515  const amrex::Real& pows2,
516  const amrex::Real& powg2,
517  const amrex::Real& evapr1_k,
518  const amrex::Real& evapr2_k,
519  const amrex::Real& evaps1_k,
520  const amrex::Real& evaps2_k,
521  const amrex::Real& evapg1_k,
522  const amrex::Real& evapg2_k) noexcept
523 {
524  // Positive-domain evaporation/sublimation rate form for precipitating
525  // species: C1*sqrt(q_m) + C2*q_m^p. The derivative is singular at q_m = 0,
526  // so derivative checks only make sense away from zero.
527  SAMPrecipSources result{};
528  result.dqpr = evapr1_k * std::sqrt(qpr) + evapr2_k * std::pow(qpr, powr2);
529  result.dqps = evaps1_k * std::sqrt(qps) + evaps2_k * std::pow(qps, pows2);
530  result.dqpg = evapg1_k * std::sqrt(qpg) + evapg2_k * std::pow(qpg, powg2);
531  return result;
532 }
533 
534 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
536  const amrex::Real& qps,
537  const amrex::Real& qpg,
538  SAMPrecipSources result) noexcept
539 {
540  // Limits rain evaporation and snow/graupel sublimation by available
541  // qpr/qps/qpg so the source update cannot make precipitating species
542  // negative.
543  result.dqpr = amrex::min(qpr, result.dqpr);
544  result.dqps = amrex::min(qps, result.dqps);
545  result.dqpg = amrex::min(qpg, result.dqpg);
546  result.dqp = result.dqpr + result.dqps + result.dqpg;
547  return result;
548 }
549 
550 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
552  const SAMCoefficientRow& coeffs,
553  const SAMPrecipConfig& config,
554  SAMPrecipCellDiagnostics* diagnostics = nullptr) noexcept
555 {
556  // Local SAM precipitation source update. This is a cell-local,
557  // held-pressure microphysics update; sedimentation and surface
558  // accumulation are handled in PrecipFall. Before sedimentation, the source
559  // terms exchange water among qv/qcl/qci/qpr/qps/qpg, conserve total water,
560  // and conserve the constant-pressure latent proxy
561  // tabs + fac_cond*qv - fac_fus*(qci + qps + qpg)
562  // up to limiter and roundoff effects.
563  if (diagnostics != nullptr) {
564  *diagnostics = {};
565  }
566 
567  state.qn = state.qcl + state.qci;
568  state.qt = state.qv + state.qn;
569  state.qp = state.qpr + state.qps + state.qpg;
570 
571  if (!config.enable_precip || state.qn + state.qp <= zero) {
572  return state;
573  }
574 
575  amrex::Real omn;
576  amrex::Real omp;
577  amrex::Real omg;
578  if (config.sam_moisture_type == 2) {
579  omn = one;
580  omp = one;
581  omg = zero;
582  } else {
584  state.tabs, a_bg, tbgmin * a_bg);
586  state.tabs);
588  state.tabs);
589  }
590 
591  if (diagnostics != nullptr) {
592  diagnostics->omn = omn;
593  diagnostics->omp = omp;
594  diagnostics->omg = omg;
595  }
596 
597  if (state.qn > zero) {
598  SAMPrecipSources source_terms =
599  sam_autoconversion_rates(config.dtn, state.qcl, state.qci, coeffs.coefice);
600  const SAMPrecipSources accretion_terms =
601  sam_accretion_rates(config.dtn, state.qcl, state.qci, state.qpr, state.qps, state.qpg,
602  config.powr1, config.pows1, config.powg1,
603  omp, omg,
604  coeffs.accrrc, coeffs.accrsc, coeffs.accrsi,
605  coeffs.accrgc, coeffs.accrgi);
606  if (diagnostics != nullptr) {
607  diagnostics->autoconversion = source_terms;
608  diagnostics->accretion = accretion_terms;
609  }
610 
611  source_terms.dprc = accretion_terms.dprc;
612  source_terms.dpsc = accretion_terms.dpsc;
613  source_terms.dpgc = accretion_terms.dpgc;
614  source_terms.dpsi = accretion_terms.dpsi;
615  source_terms.dpgi = accretion_terms.dpgi;
616  source_terms = sam_rescale_cloud_sinks(state.qcl, state.qci,
617  config.eps, source_terms);
618  if (diagnostics != nullptr) {
619  diagnostics->limited_sources = source_terms;
620  }
621 
622  source_terms = sam_partition_autoconverted_precip(source_terms, omp, omg);
623  if (diagnostics != nullptr) {
624  diagnostics->partitioned_sources = source_terms;
625  }
626 
627  const amrex::Real dqca = source_terms.dqca;
628  const amrex::Real dqia = source_terms.dqia;
629 
630  state.qcl -= source_terms.dqc;
631  state.qci -= source_terms.dqi;
632  state.qpr += source_terms.dqpr;
633  state.qps += source_terms.dqps;
634  state.qpg += source_terms.dqpg;
635 
636  state.qn = state.qcl + state.qci;
637  state.qt = state.qv + state.qn;
638  state.qp = state.qpr + state.qps + state.qpg;
639 
640  // Cloud-liquid accretion onto snow and graupel increases frozen mass
641  // and must contribute the same fusion-heating term to the local latent
642  // proxy as the autoconverted frozen branch.
643  state.tabs += config.fac_fus * (dqca * (one - omp) - dqia * omp
644  + source_terms.dpsc + source_terms.dpgc);
646  state.pres_mbar,
647  config.rdOcp);
648  }
649 
652  erf_qsatw(state.tabs, state.pres_mbar, qsatw);
653  erf_qsati(state.tabs, state.pres_mbar, qsati);
654  const amrex::Real qsat = sam_mixed_qsat(omn, qsatw, qsati);
655  if (diagnostics != nullptr) {
656  diagnostics->qsat = qsat;
657  }
658 
659  if (state.qp > zero && state.qv < qsat) {
660  SAMPrecipSources evaporation_terms =
661  sam_precip_evaporation_rates(state.qpr, state.qps, state.qpg,
662  config.powr2, config.pows2, config.powg2,
663  coeffs.evapr1, coeffs.evapr2,
664  coeffs.evaps1, coeffs.evaps2,
665  coeffs.evapg1, coeffs.evapg2);
666 
667  const amrex::Real supersat_factor = config.dtn * (one - state.qv / qsat);
668  evaporation_terms.dqpr *= supersat_factor;
669  evaporation_terms.dqps *= supersat_factor;
670  evaporation_terms.dqpg *= supersat_factor;
671  evaporation_terms = sam_apply_precip_evaporation_limiter(state.qpr,
672  state.qps,
673  state.qpg,
674  evaporation_terms);
675  if (diagnostics != nullptr) {
676  diagnostics->evaporation = evaporation_terms;
677  }
678 
679  state.qv += evaporation_terms.dqp;
680  state.qpr -= evaporation_terms.dqpr;
681  state.qps -= evaporation_terms.dqps;
682  state.qpg -= evaporation_terms.dqpg;
683 
684  state.qt = state.qv + state.qn;
685  state.qp = state.qpr + state.qps + state.qpg;
686 
687  // Rain evaporation cools with Lv/cp; snow and graupel sublimation cool
688  // with Ls/cp, preserving the same local latent proxy.
689  state.tabs -= config.fac_cond * evaporation_terms.dqpr
690  + config.fac_sub * (evaporation_terms.dqps + evaporation_terms.dqpg);
692  state.pres_mbar,
693  config.rdOcp);
694  }
695 
696  return state;
697 }
698 
699 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
700 // Closure coefficients for the SAM source parameterizations at one vertical
701 // level. The formula ordering is kept close to the SAM baseline to avoid
702 // unintended numerical drift.
704  const amrex::Real& tabs,
705  const amrex::Real& gamr1,
706  const amrex::Real& gamr2,
707  const amrex::Real& gams1,
708  const amrex::Real& gams2,
709  const amrex::Real& gamg1,
710  const amrex::Real& gamg2) noexcept
711 {
712  // Preserve the SAM baseline formula ordering in these closure rows.
713  SAMCoefficientRow row{};
714  amrex::Real prefactor;
715  amrex::Real pratio = std::sqrt(amrex::Real(1.29) / rho);
716  amrex::Real estw = amrex::Real(100.0) * erf_esatw(tabs);
717  amrex::Real esti = amrex::Real(100.0) * erf_esati(tabs);
718 
719  amrex::Real coef1 = fourth * PI * nzeros * a_snow * gams1 * pratio
720  / std::pow((PI * rhos * nzeros / rho), ((three + b_snow) / amrex::Real(4.0)));
721  amrex::Real coef2 = std::exp(amrex::Real(0.025) * (tabs - amrex::Real(273.15)));
722  row.accrsi = coef1 * coef2 * esicoef;
723  row.accrsc = coef1 * esccoef;
724  row.coefice = coef2;
725 
726  coef1 = (lsub / (tabs * R_v) - one) * lsub / (therco * tabs);
727  coef2 = R_v * R_d / (diffelq * esti);
728  prefactor = two * PI * nzeros / (rho * (coef1 + coef2));
729  prefactor *= (two / PI);
730  row.evaps1 = prefactor * amrex::Real(0.65) * std::sqrt(rho / (PI * rhos * nzeros));
731  row.evaps2 = prefactor * amrex::Real(0.44) * std::sqrt(a_snow * rho / muelq) * gams2
732  * std::sqrt(pratio) * std::pow(rho / (PI * rhos * nzeros), ((amrex::Real(5.0) + b_snow) / amrex::Real(8.0)));
733 
734  coef1 = fourth * PI * nzerog * a_grau * gamg1 * pratio
735  / std::pow((PI * rhog * nzerog / rho), ((three + b_grau) / amrex::Real(4.0)));
736  coef2 = std::exp(amrex::Real(0.025) * (tabs - amrex::Real(273.15)));
737  row.accrgi = coef1 * coef2 * egicoef;
738  row.accrgc = coef1 * egccoef;
739 
740  coef1 = (lsub / (tabs * R_v) - one) * lsub / (therco * tabs);
741  coef2 = R_v * R_d / (diffelq * esti);
742  prefactor = two * PI * nzerog / (rho * (coef1 + coef2));
743  row.evapg1 = prefactor * amrex::Real(0.78) * std::sqrt(rho / (PI * rhog * nzerog));
744  row.evapg2 = prefactor * amrex::Real(0.31) * std::sqrt(a_grau * rho / muelq) * gamg2
745  * std::sqrt(pratio) * std::pow(rho / (PI * rhog * nzerog), ((amrex::Real(5.0) + b_grau) / amrex::Real(8.0)));
746 
747  row.accrrc = fourth * PI * nzeror * a_rain * gamr1 * pratio
748  / std::pow((PI * rhor * nzeror / rho), ((three + b_rain) / amrex::Real(4.0))) * erccoef;
749 
750  coef1 = (lcond / (tabs * R_v) - one) * lcond / (therco * tabs);
751  coef2 = R_v * R_d / (diffelq * estw);
752  prefactor = two * PI * nzeror / (rho * (coef1 + coef2));
753  row.evapr1 = prefactor * amrex::Real(0.78) * std::sqrt(rho / (PI * rhor * nzeror));
754  row.evapr2 = prefactor * amrex::Real(0.31) * std::sqrt(a_rain * rho / muelq) * gamr2
755  * std::sqrt(pratio) * std::pow(rho / (PI * rhor * nzeror), ((amrex::Real(5.0) + b_rain) / amrex::Real(8.0)));
756  return row;
757 }
758 
759 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
761 {
762  // MUST MATCH: SAM cloud-ice terminal-velocity coefficient and exponent.
763  return amrex::min(amrex::Real(0.4),
764  amrex::Real(8.66) * std::pow((amrex::max(amrex::Real(0.0), qci_avg) + amrex::Real(1.e-10)), amrex::Real(0.24)));
765 }
766 
767 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
769  const int& k_lo,
770  const int& k_hi,
771  const amrex::Real& rho_km1,
772  const amrex::Real& rho_k,
773  const amrex::Real tabs_km1,
774  const amrex::Real tabs_k,
775  const amrex::Real& qci_km1,
776  const amrex::Real& qci_k,
777  const amrex::Real qp_km1,
778  const amrex::Real qp_k) noexcept
779 {
780  SAMFaceState result{};
781  if (k == k_lo) {
782  result.rho_avg = rho_k;
783  result.tabs_avg = tabs_k;
784  result.qci_avg = qci_k;
785  result.qp_avg = qp_k;
786  } else if (k == k_hi + 1) {
787  result.rho_avg = rho_km1;
788  result.tabs_avg = tabs_km1;
789  result.qci_avg = qci_km1;
790  result.qp_avg = qp_km1;
791  } else {
792  result.rho_avg = myhalf * (rho_km1 + rho_k);
793  result.tabs_avg = myhalf * (tabs_km1 + tabs_k);
794  result.qci_avg = myhalf * (qci_km1 + qci_k);
795  result.qp_avg = myhalf * (qp_km1 + qp_k);
796  }
797  return result;
798 }
799 
800 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
801 int sam_precip_face_donor_k (const int& face_k,
802  const int& k_lo,
803  const int& k_hi) noexcept
804 {
805  if (face_k <= k_lo) {
806  return k_lo;
807  }
808  if (face_k >= k_hi + 1) {
809  return k_hi;
810  }
811  return face_k;
812 }
813 
814 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
816  const amrex::Real& dt,
817  const amrex::Real& dz) noexcept
818 {
819  // Substeps follow the legacy reduced-flux rule based on the maximum
820  // density-corrected precip flux, not directly on a terminal fall speed.
821  // Property tests characterize this behavior before any intended change.
822  // MUST MATCH: SAM::CFL_MAX.
823  return static_cast<int>(std::ceil(reduced_flux * (dt / dz) / myhalf));
824 }
825 
826 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
827 SAMPrecipFaceState sam_precip_face_state (const int& SAM_moisture_type,
828  const amrex::Array4<const amrex::Real>& rho_array,
829  const amrex::Array4<const amrex::Real>& tabs_array,
830  const amrex::Array4<const amrex::Real>& qp_array,
831  const int& i,
832  const int& j,
833  const int& k,
834  const int& k_lo,
835  const int& k_hi) noexcept
836 {
837  // MUST MATCH: SAM PrecipFall bottom/interior/top face rules.
838  SAMPrecipFaceState result{};
839  if (k == k_lo) {
840  result.rho_avg = rho_array(i,j,k);
841  result.tabs_avg = tabs_array(i,j,k);
842  result.qp_avg = qp_array(i,j,k);
843  } else if (k == k_hi + 1) {
844  result.rho_avg = rho_array(i,j,k-1);
845  result.tabs_avg = tabs_array(i,j,k-1);
846  result.qp_avg = qp_array(i,j,k-1);
847  } else {
848  result.rho_avg = myhalf * (rho_array(i,j,k-1) + rho_array(i,j,k));
849  result.tabs_avg = myhalf * (tabs_array(i,j,k-1) + tabs_array(i,j,k));
850  result.qp_avg = myhalf * (qp_array(i,j,k-1) + qp_array(i,j,k));
851  }
852  result.omp = sam_precip_rain_fraction(SAM_moisture_type, result.tabs_avg);
853  result.omg = sam_graupel_fraction(SAM_moisture_type, result.tabs_avg);
854  result.qrr = result.omp * result.qp_avg;
855  result.qss = (one - result.omp) * (one - result.omg) * result.qp_avg;
856  result.qgg = (one - result.omp) * result.omg * result.qp_avg;
857  return result;
858 }
859 
860 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
861 // Component PrecipFall face state. Uses the same bottom/interior/top face
862 // selection rules, but reads qpr/qps/qpg directly so each precipitating
863 // species can be sedimented and limited conservatively.
864 SAMPrecipComponentFaceState sam_precip_component_face_state (const amrex::Array4<const amrex::Real>& rho_array,
865  const amrex::Array4<const amrex::Real>& tabs_array,
866  const amrex::Array4<const amrex::Real>& qpr_array,
867  const amrex::Array4<const amrex::Real>& qps_array,
868  const amrex::Array4<const amrex::Real>& qpg_array,
869  const int& i,
870  const int& j,
871  const int& k,
872  const int& k_lo,
873  const int& k_hi) noexcept
874 {
875  // MUST MATCH: SAM PrecipFall bottom/interior/top face rules.
877  if (k == k_lo) {
878  result.rho_avg = rho_array(i,j,k);
879  result.tabs_avg = tabs_array(i,j,k);
880  result.qpr_avg = qpr_array(i,j,k);
881  result.qps_avg = qps_array(i,j,k);
882  result.qpg_avg = qpg_array(i,j,k);
883  } else if (k == k_hi + 1) {
884  result.rho_avg = rho_array(i,j,k-1);
885  result.tabs_avg = tabs_array(i,j,k-1);
886  result.qpr_avg = qpr_array(i,j,k-1);
887  result.qps_avg = qps_array(i,j,k-1);
888  result.qpg_avg = qpg_array(i,j,k-1);
889  } else {
890  result.rho_avg = myhalf * (rho_array(i,j,k-1) + rho_array(i,j,k));
891  result.tabs_avg = myhalf * (tabs_array(i,j,k-1) + tabs_array(i,j,k));
892  result.qpr_avg = myhalf * (qpr_array(i,j,k-1) + qpr_array(i,j,k));
893  result.qps_avg = myhalf * (qps_array(i,j,k-1) + qps_array(i,j,k));
894  result.qpg_avg = myhalf * (qpg_array(i,j,k-1) + qpg_array(i,j,k));
895  }
896  return result;
897 }
898 
899 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
900 // Legacy total-qp precip flux helper. It partitions a total qp into rain/
901 // snow/graupel by temperature phase fractions and applies the qp_threshold
902 // branch. The conservative production PrecipFall path uses the component
903 // helper below.
905  const amrex::Real& vrain,
906  const amrex::Real& vsnow,
907  const amrex::Real& vgrau) noexcept
908 {
909  if (face_state.qp_avg <= qp_threshold) {
910  return zero;
911  }
912  return face_state.omp * vrain * std::pow(face_state.rho_avg * face_state.qrr, one + crain)
913  + (one - face_state.omp)
914  * ((one - face_state.omg) * vsnow * std::pow(face_state.rho_avg * face_state.qss, one + csnow)
915  + face_state.omg * vgrau * std::pow(face_state.rho_avg * face_state.qgg, one + cgrau));
916 }
917 
918 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
919 // Legacy total-qp companion returning the partitioned rain/snow/graupel face
920 // fluxes. The conservative production PrecipFall path uses the component
921 // helper below instead of repartitioning total qp.
923  const amrex::Real& vrain,
924  const amrex::Real& vsnow,
925  const amrex::Real& vgrau) noexcept
926 {
927  SAMPrecipFluxComponents result{};
928  if (face_state.qp_avg <= qp_threshold) {
929  return result;
930  }
931 
932  result.rain = face_state.omp * vrain * std::pow(face_state.rho_avg * face_state.qrr, one + crain);
933  result.snow = (one - face_state.omp) * (one - face_state.omg)
934  * vsnow * std::pow(face_state.rho_avg * face_state.qss, one + csnow);
935  result.graupel = (one - face_state.omp) * face_state.omg
936  * vgrau * std::pow(face_state.rho_avg * face_state.qgg, one + cgrau);
937  return result;
938 }
939 
940 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
941 // Component PrecipFall fluxes. Unlike the legacy total-qp helper, these
942 // fluxes are zero only when the corresponding component mass is nonpositive;
943 // tiny positive qpr/qps/qpg produce tiny positive fluxes and are donor-limited
944 // later.
946  const amrex::Real& vrain,
947  const amrex::Real& vsnow,
948  const amrex::Real& vgrau) noexcept
949 {
950  SAMPrecipFluxComponents result{};
951  if (face_state.qpr_avg > zero) {
952  result.rain = vrain * std::pow(face_state.rho_avg * face_state.qpr_avg, one + crain);
953  }
954  if (face_state.qps_avg > zero) {
955  result.snow = vsnow * std::pow(face_state.rho_avg * face_state.qps_avg, one + csnow);
956  }
957  if (face_state.qpg_avg > zero) {
958  result.graupel = vgrau * std::pow(face_state.rho_avg * face_state.qpg_avg, one + cgrau);
959  }
960  return result;
961 }
962 
963 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
965  const amrex::Real& rho_0,
966  const amrex::Real& rho_avg) noexcept
967 {
968  return precip_flux * std::sqrt(rho_0 / rho_avg);
969 }
970 
971 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
973  const amrex::Real& rho_0,
974  const amrex::Real& rho_avg) noexcept
975 {
976  const amrex::Real density_correction = std::sqrt(rho_0 / rho_avg);
977  return {
978  precip_fluxes.rain * density_correction,
979  precip_fluxes.snow * density_correction,
980  precip_fluxes.graupel * density_correction};
981 }
982 
983 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
984 // Donor-cap limiter for conservative component sedimentation. The limited flux
985 // cannot export more component mass over one substep than the donor cell
986 // contains, including detJ for terrain-following cell mass.
988  const amrex::Real& rho_donor,
989  const amrex::Real& q_donor,
990  const amrex::Real& detJ_donor,
991  const amrex::Real& coef) noexcept
992 {
993  const amrex::Real available_flux =
994  rho_donor * amrex::max(amrex::Real(0.0), q_donor) * detJ_donor / coef;
995  return amrex::min(raw_flux, available_flux);
996 }
997 
998 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
999 // Converts face-flux divergence into a mixing-ratio tendency. With the same
1000 // limited face fluxes used for accumulation, column component budgets
1001 // telescope.
1003  const amrex::Real& fz_lo,
1004  const amrex::Real& rho,
1005  const amrex::Real& dJinv,
1006  const amrex::Real& coef) noexcept
1007 {
1008  return dJinv * (one / rho) * (fz_hi - fz_lo) * coef;
1009 }
1010 
1011 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
1012 // Converts the already-limited bottom component fluxes to accumulated surface
1013 // depths. These are the same fluxes used in the in-column sedimentation
1014 // update.
1016  const SAMPrecipFluxComponents& component_fluxes,
1017  const amrex::Real& dtn) noexcept
1018 {
1019  SAMSurfaceAccumulation result{};
1020  result.rain = component_fluxes.rain * dtn / rhor * amrex::Real(1000.0);
1021  result.snow = component_fluxes.snow * dtn / rhos * amrex::Real(1000.0);
1022  result.graupel = component_fluxes.graupel * dtn / rhog * amrex::Real(1000.0);
1023  return result;
1024 }
1025 
1026 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
1028  const amrex::Real& rho_0,
1029  const amrex::Real& vrain,
1030  const amrex::Real& vsnow,
1031  const amrex::Real& vgrau,
1032  const amrex::Real& dtn) noexcept
1033 {
1034  const SAMPrecipFluxComponents face_fluxes =
1035  sam_precip_flux_components_from_face_state(face_state, vrain, vsnow, vgrau);
1036 
1038  sam_precip_flux_components_density_corrected(face_fluxes, rho_0, face_state.rho_avg),
1039  dtn);
1040 }
1041 
1042 #endif
constexpr amrex::Real csnow
Definition: ERF_Constants.H:125
constexpr amrex::Real rhog
Definition: ERF_Constants.H:73
constexpr amrex::Real a_bg
Definition: ERF_Constants.H:120
constexpr amrex::Real R_v
Definition: ERF_Constants.H:48
constexpr amrex::Real three
Definition: ERF_Constants.H:11
constexpr amrex::Real muelq
Definition: ERF_Constants.H:118
constexpr amrex::Real a_gr
Definition: ERF_Constants.H:122
constexpr amrex::Real qci0
Definition: ERF_Constants.H:90
constexpr amrex::Real nzerog
Definition: ERF_Constants.H:102
constexpr amrex::Real cgrau
Definition: ERF_Constants.H:126
constexpr amrex::Real tbgmax
Definition: ERF_Constants.H:75
constexpr amrex::Real betaelq
Definition: ERF_Constants.H:92
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real a_grau
Definition: ERF_Constants.H:85
constexpr amrex::Real lsub
Definition: ERF_Constants.H:111
constexpr amrex::Real alphaelq
Definition: ERF_Constants.H:91
constexpr amrex::Real esicoef
Definition: ERF_Constants.H:96
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real diffelq
Definition: ERF_Constants.H:116
constexpr amrex::Real fourth
Definition: ERF_Constants.H:14
constexpr amrex::Real therco
Definition: ERF_Constants.H:117
constexpr amrex::Real b_grau
Definition: ERF_Constants.H:86
constexpr amrex::Real egccoef
Definition: ERF_Constants.H:97
constexpr amrex::Real egicoef
Definition: ERF_Constants.H:98
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real b_rain
Definition: ERF_Constants.H:82
constexpr amrex::Real lcond
Definition: ERF_Constants.H:109
constexpr amrex::Real myhalf
Definition: ERF_Constants.H:13
constexpr amrex::Real qcw0
Definition: ERF_Constants.H:89
constexpr amrex::Real tprmin
Definition: ERF_Constants.H:76
constexpr amrex::Real qp_threshold
Definition: ERF_Constants.H:103
constexpr amrex::Real PI
Definition: ERF_Constants.H:42
constexpr amrex::Real nzeror
Definition: ERF_Constants.H:100
constexpr amrex::Real tbgmin
Definition: ERF_Constants.H:74
constexpr amrex::Real rhos
Definition: ERF_Constants.H:72
constexpr amrex::Real esccoef
Definition: ERF_Constants.H:95
constexpr amrex::Real rhor
Definition: ERF_Constants.H:71
constexpr amrex::Real a_rain
Definition: ERF_Constants.H:81
constexpr amrex::Real nzeros
Definition: ERF_Constants.H:101
constexpr amrex::Real R_d
Definition: ERF_Constants.H:47
constexpr amrex::Real a_snow
Definition: ERF_Constants.H:83
constexpr amrex::Real crain
Definition: ERF_Constants.H:124
constexpr amrex::Real b_snow
Definition: ERF_Constants.H:84
constexpr amrex::Real erccoef
Definition: ERF_Constants.H:94
constexpr amrex::Real tgrmin
Definition: ERF_Constants.H:78
constexpr amrex::Real a_pr
Definition: ERF_Constants.H:121
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getTgivenRandRTh(const amrex::Real rho, const amrex::Real rhotheta, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:46
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
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 RhoQ4_comp
Definition: ERF_IndexDefines.H:45
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:43
#define RhoQ3_comp
Definition: ERF_IndexDefines.H:44
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
#define RhoQ6_comp
Definition: ERF_IndexDefines.H:47
#define RhoQ5_comp
Definition: ERF_IndexDefines.H:46
Real rho_0
Definition: ERF_InitCustomPert_ABL.H:4
const Real rdOcp
Definition: ERF_InitCustomPert_Bomex.H:16
rho
Definition: ERF_InitCustomPert_Bubble.H:107
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esati(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:31
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:228
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsati(amrex::Real t, amrex::Real p, amrex::Real &qsati)
Definition: ERF_MicrophysicsUtils.H:218
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t, bool use_empirical=false)
Definition: ERF_MicrophysicsUtils.H:123
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipSources sam_accretion_rates(const amrex::Real &dtn, const amrex::Real &qcc, const amrex::Real &qii, const amrex::Real &qpr, const amrex::Real &qps, const amrex::Real &qpg, const amrex::Real &powr1, const amrex::Real &pows1, const amrex::Real &powg1, const amrex::Real &omp, const amrex::Real &omg, const amrex::Real &accrrc_k, const amrex::Real &accrsc_k, const amrex::Real &accrsi_k, const amrex::Real &accrgc_k, const amrex::Real &accrgi_k) noexcept
Definition: ERF_SAMUtils.H:417
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipFaceState sam_precip_face_state(const int &SAM_moisture_type, const amrex::Array4< const amrex::Real > &rho_array, const amrex::Array4< const amrex::Real > &tabs_array, const amrex::Array4< const amrex::Real > &qp_array, const int &i, const int &j, const int &k, const int &k_lo, const int &k_hi) noexcept
Definition: ERF_SAMUtils.H:827
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMCloudPhaseChange sam_partition_cloud_phase(const int &SAM_moisture_type, const amrex::Real &tabs, const amrex::Real &qn, const amrex::Real &qcl, const amrex::Real &qci, const amrex::Real fac_cond, const amrex::Real fac_fus, const amrex::Real an, const amrex::Real bn) noexcept
Definition: ERF_SAMUtils.H:290
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_graupel_fraction(const int &SAM_moisture_type, const amrex::Real &tabs) noexcept
Definition: ERF_SAMUtils.H:278
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipFluxComponents sam_precip_flux_components_from_face_state(const SAMPrecipFaceState &face_state, const amrex::Real &vrain, const amrex::Real &vsnow, const amrex::Real &vgrau) noexcept
Definition: ERF_SAMUtils.H:922
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_mbar_to_pa(const amrex::Real &pres_mbar) noexcept
Definition: ERF_SAMUtils.H:158
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int sam_substep_count_from_reduced_flux(const amrex::Real &reduced_flux, const amrex::Real &dt, const amrex::Real &dz) noexcept
Definition: ERF_SAMUtils.H:815
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipFluxComponents sam_precip_component_fluxes_from_face_state(const SAMPrecipComponentFaceState &face_state, const amrex::Real &vrain, const amrex::Real &vsnow, const amrex::Real &vgrau) noexcept
Definition: ERF_SAMUtils.H:945
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_precip_rain_fraction(const int &SAM_moisture_type, const amrex::Real &tabs) noexcept
Definition: ERF_SAMUtils.H:266
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_newton_residual(const amrex::Real &tabs_new, const amrex::Real &tabs_old, const amrex::Real fcond, const amrex::Real &qv, const amrex::Real &qsatm, const amrex::Real ffus, const amrex::Real &qi, const amrex::Real &qif) noexcept
Definition: ERF_SAMUtils.H:376
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMSurfaceAccumulation sam_surface_accumulation_from_component_fluxes(const SAMPrecipFluxComponents &component_fluxes, const amrex::Real &dtn) noexcept
Definition: ERF_SAMUtils.H:1015
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_mixed_dqif_dT(const amrex::Real &omn, const amrex::Real &domn, const amrex::Real &qn, const amrex::Real &dqsatm) noexcept
Definition: ERF_SAMUtils.H:366
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMFaceState sam_face_average_state(const int &k, const int &k_lo, const int &k_hi, const amrex::Real &rho_km1, const amrex::Real &rho_k, const amrex::Real tabs_km1, const amrex::Real tabs_k, const amrex::Real &qci_km1, const amrex::Real &qci_k, const amrex::Real qp_km1, const amrex::Real qp_k) noexcept
Definition: ERF_SAMUtils.H:768
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_pa_to_mbar(const amrex::Real &pres_pa) noexcept
Definition: ERF_SAMUtils.H:165
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipSources sam_autoconversion_rates(const amrex::Real &dtn, const amrex::Real &qcc, const amrex::Real &qii, const amrex::Real &coefice_k) noexcept
Definition: ERF_SAMUtils.H:400
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipSources sam_rescale_cloud_sinks(const amrex::Real &qcl, const amrex::Real &qci, const amrex::Real &eps, SAMPrecipSources result) noexcept
Definition: ERF_SAMUtils.H:467
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMCellState sam_precip_cell_update(SAMCellState state, const SAMCoefficientRow &coeffs, const SAMPrecipConfig &config, SAMPrecipCellDiagnostics *diagnostics=nullptr) noexcept
Definition: ERF_SAMUtils.H:551
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_precip_flux_density_corrected(const amrex::Real &precip_flux, const amrex::Real &rho_0, const amrex::Real &rho_avg) noexcept
Definition: ERF_SAMUtils.H:964
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool sam_is_no_ice(const MoistureType &moisture_type) noexcept
Definition: ERF_SAMUtils.H:232
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool sam_is_no_precip(const MoistureType &moisture_type) noexcept
Definition: ERF_SAMUtils.H:239
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void sam_primitive_to_cons(const SAMPrimitiveCell &primitive, const amrex::Array4< amrex::Real > &states_arr, const int &i, const int &j, const int &k) noexcept
Definition: ERF_SAMUtils.H:213
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMCoefficientRow sam_compute_coefficient_row(const amrex::Real &rho, const amrex::Real &tabs, const amrex::Real &gamr1, const amrex::Real &gamr2, const amrex::Real &gams1, const amrex::Real &gams2, const amrex::Real &gamg1, const amrex::Real &gamg2) noexcept
Definition: ERF_SAMUtils.H:703
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_limit_precip_component_flux(const amrex::Real &raw_flux, const amrex::Real &rho_donor, const amrex::Real &q_donor, const amrex::Real &detJ_donor, const amrex::Real &coef) noexcept
Definition: ERF_SAMUtils.H:987
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_sedimentation_tendency(const amrex::Real &fz_hi, const amrex::Real &fz_lo, const amrex::Real &rho, const amrex::Real &dJinv, const amrex::Real &coef) noexcept
Definition: ERF_SAMUtils.H:1002
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_cloud_ice_terminal_velocity(const amrex::Real &qci_avg) noexcept
Definition: ERF_SAMUtils.H:760
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMSurfaceAccumulation sam_surface_accumulation(const SAMPrecipFaceState &face_state, const amrex::Real &rho_0, const amrex::Real &vrain, const amrex::Real &vsnow, const amrex::Real &vgrau, const amrex::Real &dtn) noexcept
Definition: ERF_SAMUtils.H:1027
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipSources sam_apply_precip_evaporation_limiter(const amrex::Real &qpr, const amrex::Real &qps, const amrex::Real &qpg, SAMPrecipSources result) noexcept
Definition: ERF_SAMUtils.H:535
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_precip_flux_from_face_state(const SAMPrecipFaceState &face_state, const amrex::Real &vrain, const amrex::Real &vsnow, const amrex::Real &vgrau) noexcept
Definition: ERF_SAMUtils.H:904
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipComponentFaceState sam_precip_component_face_state(const amrex::Array4< const amrex::Real > &rho_array, const amrex::Array4< const amrex::Real > &tabs_array, const amrex::Array4< const amrex::Real > &qpr_array, const amrex::Array4< const amrex::Real > &qps_array, const amrex::Array4< const amrex::Real > &qpg_array, const int &i, const int &j, const int &k, const int &k_lo, const int &k_hi) noexcept
Definition: ERF_SAMUtils.H:864
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_theta_from_stored_mbar_converted_to_pa(const amrex::Real &tabs, const amrex::Real &pres_mbar, const amrex::Real rdOcp) noexcept
Definition: ERF_SAMUtils.H:171
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipSources sam_partition_autoconverted_precip(SAMPrecipSources result, const amrex::Real &omp, const amrex::Real &omg) noexcept
Definition: ERF_SAMUtils.H:497
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_newton_residual_derivative(const amrex::Real fcond, const amrex::Real ffus, const amrex::Real &dqsatm, const amrex::Real &dqif) noexcept
Definition: ERF_SAMUtils.H:390
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrimitiveCell sam_cons_to_primitive(const amrex::Real &rho, const amrex::Real &rho_theta, const amrex::Real &rho_qv, const amrex::Real &rho_qcl, const amrex::Real &rho_qci, const amrex::Real &rho_qpr, const amrex::Real &rho_qps, const amrex::Real &rho_qpg) noexcept
Definition: ERF_SAMUtils.H:182
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int sam_precip_face_donor_k(const int &face_k, const int &k_lo, const int &k_hi) noexcept
Definition: ERF_SAMUtils.H:801
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_cloud_liquid_fraction(const int &SAM_moisture_type, const amrex::Real &tabs, const amrex::Real an, const amrex::Real bn) noexcept
Definition: ERF_SAMUtils.H:245
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipFluxComponents sam_precip_flux_components_density_corrected(const SAMPrecipFluxComponents &precip_fluxes, const amrex::Real &rho_0, const amrex::Real &rho_avg) noexcept
Definition: ERF_SAMUtils.H:972
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_mixed_qsat(const amrex::Real &omn, const amrex::Real &qsatw, const amrex::Real &qsati) noexcept
Definition: ERF_SAMUtils.H:344
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE SAMPrecipSources sam_precip_evaporation_rates(const amrex::Real &qpr, const amrex::Real &qps, const amrex::Real &qpg, const amrex::Real &powr2, const amrex::Real &pows2, const amrex::Real &powg2, const amrex::Real &evapr1_k, const amrex::Real &evapr2_k, const amrex::Real &evaps1_k, const amrex::Real &evaps2_k, const amrex::Real &evapg1_k, const amrex::Real &evapg2_k) noexcept
Definition: ERF_SAMUtils.H:511
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real sam_mixed_dqsat_dT(const amrex::Real &omn, const amrex::Real &domn, const amrex::Real &qsatw, const amrex::Real &qsati, const amrex::Real &dqsatw, const amrex::Real &dqsati) noexcept
Definition: ERF_SAMUtils.H:353
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ qcl
Definition: ERF_Kessler.H:31
@ tabs
Definition: ERF_Kessler.H:26
@ qv
Definition: ERF_Kessler.H:30
@ qpg
Definition: ERF_Morrison.H:42
@ qps
Definition: ERF_Morrison.H:41
@ qn
Definition: ERF_Morrison.H:34
@ qpr
Definition: ERF_Morrison.H:40
@ qci
Definition: ERF_Morrison.H:37
@ qi
Definition: ERF_WSM6.H:27
@ qsatw
Definition: ERF_WSM6.H:249
@ qsati
Definition: ERF_WSM6.H:249
@ dz
Definition: ERF_AdvanceWSM6.cpp:104
Definition: ERF_SAMUtils.H:22
amrex::Real delta_qi
Definition: ERF_SAMUtils.H:26
amrex::Real qcl
Definition: ERF_SAMUtils.H:28
amrex::Real qn
Definition: ERF_SAMUtils.H:30
amrex::Real tabs
Definition: ERF_SAMUtils.H:32
amrex::Real qt
Definition: ERF_SAMUtils.H:31
amrex::Real qv
Definition: ERF_SAMUtils.H:27
amrex::Real delta_qv
Definition: ERF_SAMUtils.H:24
amrex::Real delta_qc
Definition: ERF_SAMUtils.H:25
amrex::Real omn
Definition: ERF_SAMUtils.H:23
amrex::Real qci
Definition: ERF_SAMUtils.H:29
Definition: ERF_SAMUtils.H:98
amrex::Real coefice
Definition: ERF_SAMUtils.H:102
amrex::Real evaps2
Definition: ERF_SAMUtils.H:104
amrex::Real accrsi
Definition: ERF_SAMUtils.H:100
amrex::Real accrgc
Definition: ERF_SAMUtils.H:106
amrex::Real accrgi
Definition: ERF_SAMUtils.H:105
amrex::Real accrsc
Definition: ERF_SAMUtils.H:101
amrex::Real evapg1
Definition: ERF_SAMUtils.H:107
amrex::Real evapr1
Definition: ERF_SAMUtils.H:109
amrex::Real evapg2
Definition: ERF_SAMUtils.H:108
amrex::Real accrrc
Definition: ERF_SAMUtils.H:99
amrex::Real evapr2
Definition: ERF_SAMUtils.H:110
amrex::Real evaps1
Definition: ERF_SAMUtils.H:103
Definition: ERF_SAMUtils.H:132
amrex::Real qp_avg
Definition: ERF_SAMUtils.H:136
amrex::Real qci_avg
Definition: ERF_SAMUtils.H:135
amrex::Real tabs_avg
Definition: ERF_SAMUtils.H:134
amrex::Real rho_avg
Definition: ERF_SAMUtils.H:133
Definition: ERF_SAMUtils.H:16
amrex::Real omg
Definition: ERF_SAMUtils.H:19
amrex::Real omp
Definition: ERF_SAMUtils.H:18
amrex::Real omn
Definition: ERF_SAMUtils.H:17
Definition: ERF_SAMUtils.H:86
SAMPrecipSources limited_sources
Definition: ERF_SAMUtils.H:89
amrex::Real omg
Definition: ERF_SAMUtils.H:95
amrex::Real omp
Definition: ERF_SAMUtils.H:94
SAMPrecipSources partitioned_sources
Definition: ERF_SAMUtils.H:90
amrex::Real qsat
Definition: ERF_SAMUtils.H:92
SAMPrecipSources evaporation
Definition: ERF_SAMUtils.H:91
amrex::Real omn
Definition: ERF_SAMUtils.H:93
SAMPrecipSources autoconversion
Definition: ERF_SAMUtils.H:87
SAMPrecipSources accretion
Definition: ERF_SAMUtils.H:88
Definition: ERF_SAMUtils.H:124
amrex::Real qpr_avg
Definition: ERF_SAMUtils.H:127
amrex::Real qpg_avg
Definition: ERF_SAMUtils.H:129
amrex::Real qps_avg
Definition: ERF_SAMUtils.H:128
amrex::Real tabs_avg
Definition: ERF_SAMUtils.H:126
amrex::Real rho_avg
Definition: ERF_SAMUtils.H:125
Definition: ERF_SAMUtils.H:69
bool enable_precip
Definition: ERF_SAMUtils.H:71
amrex::Real fac_cond
Definition: ERF_SAMUtils.H:74
amrex::Real rdOcp
Definition: ERF_SAMUtils.H:73
amrex::Real dtn
Definition: ERF_SAMUtils.H:72
amrex::Real eps
Definition: ERF_SAMUtils.H:77
amrex::Real powr2
Definition: ERF_SAMUtils.H:81
amrex::Real fac_sub
Definition: ERF_SAMUtils.H:76
amrex::Real pows2
Definition: ERF_SAMUtils.H:82
amrex::Real pows1
Definition: ERF_SAMUtils.H:79
amrex::Real fac_fus
Definition: ERF_SAMUtils.H:75
amrex::Real powg2
Definition: ERF_SAMUtils.H:83
amrex::Real powg1
Definition: ERF_SAMUtils.H:80
int sam_moisture_type
Definition: ERF_SAMUtils.H:70
amrex::Real powr1
Definition: ERF_SAMUtils.H:78
Definition: ERF_SAMUtils.H:113
amrex::Real omg
Definition: ERF_SAMUtils.H:118
amrex::Real qss
Definition: ERF_SAMUtils.H:120
amrex::Real qrr
Definition: ERF_SAMUtils.H:119
amrex::Real qp_avg
Definition: ERF_SAMUtils.H:116
amrex::Real rho_avg
Definition: ERF_SAMUtils.H:114
amrex::Real qgg
Definition: ERF_SAMUtils.H:121
amrex::Real tabs_avg
Definition: ERF_SAMUtils.H:115
amrex::Real omp
Definition: ERF_SAMUtils.H:117
Definition: ERF_SAMUtils.H:145
amrex::Real snow
Definition: ERF_SAMUtils.H:147
amrex::Real rain
Definition: ERF_SAMUtils.H:146
amrex::Real graupel
Definition: ERF_SAMUtils.H:148
Definition: ERF_SAMUtils.H:35
amrex::Real dqpg
Definition: ERF_SAMUtils.H:47
amrex::Real dpgc
Definition: ERF_SAMUtils.H:39
amrex::Real dqca
Definition: ERF_SAMUtils.H:36
amrex::Real dqps
Definition: ERF_SAMUtils.H:46
amrex::Real dqp
Definition: ERF_SAMUtils.H:48
amrex::Real dqc
Definition: ERF_SAMUtils.H:43
amrex::Real dpsc
Definition: ERF_SAMUtils.H:38
amrex::Real dpgi
Definition: ERF_SAMUtils.H:42
amrex::Real dprc
Definition: ERF_SAMUtils.H:37
amrex::Real dqia
Definition: ERF_SAMUtils.H:40
amrex::Real dqpr
Definition: ERF_SAMUtils.H:45
amrex::Real dpsi
Definition: ERF_SAMUtils.H:41
amrex::Real dqi
Definition: ERF_SAMUtils.H:44
Definition: ERF_SAMUtils.H:51
amrex::Real theta
Definition: ERF_SAMUtils.H:53
amrex::Real qpr
Definition: ERF_SAMUtils.H:61
amrex::Real qn
Definition: ERF_SAMUtils.H:59
amrex::Real qps
Definition: ERF_SAMUtils.H:62
amrex::Real qci
Definition: ERF_SAMUtils.H:58
amrex::Real qv
Definition: ERF_SAMUtils.H:56
amrex::Real tabs
Definition: ERF_SAMUtils.H:54
amrex::Real qpg
Definition: ERF_SAMUtils.H:63
amrex::Real qt
Definition: ERF_SAMUtils.H:60
amrex::Real qcl
Definition: ERF_SAMUtils.H:57
amrex::Real rho
Definition: ERF_SAMUtils.H:52
amrex::Real pres_mbar
Definition: ERF_SAMUtils.H:55
amrex::Real qp
Definition: ERF_SAMUtils.H:64
Definition: ERF_SAMUtils.H:139
amrex::Real rain
Definition: ERF_SAMUtils.H:140
amrex::Real snow
Definition: ERF_SAMUtils.H:141
amrex::Real graupel
Definition: ERF_SAMUtils.H:142