@@ -371,6 +371,136 @@ function overwrite_initial_conditions!(
371371 )
372372end
373373
374+ """
375+ correct_surface_pressure_for_topography!(
376+ p_sfc,
377+ file_path,
378+ face_space,
379+ Y,
380+ ᶜT,
381+ ᶜq_tot,
382+ thermo_params,
383+ regridder_kwargs,
384+ )
385+
386+ Adjusts the surface pressure field `p_sfc` to account for mismatches between
387+ ERA5 (file) surface altitude and the model orography when specifying pressure.
388+
389+ Δz = z_model_surface - z_sfc
390+
391+ and applies a hydrostatic correction at the surface using the local moist gas
392+ constant and temperature at the surface:
393+
394+ p_sfc .= p_sfc .* exp.(-Δz * g ./ (R_m_sfc .* T_sfc))
395+
396+ where:
397+ - `g` is gravitational acceleration from `thermo_params`
398+ - `R_m_sfc` is the moist-air gas constant evaluated from `ᶜq_tot` at the surface
399+ - `T_sfc` is the air temperature from `ᶜT` at the surface
400+
401+ A small floor is applied to the denominator `R_m_sfc .* T_sfc` to avoid
402+ numerical blow-ups, and non-finite `Δz` entries leave `p_sfc` unchanged.
403+
404+ Returns `true` if the correction is applied. If `z_sfc` is missing in the
405+ provided file, the function logs a warning and returns `false` without
406+ modifying `p_sfc`.
407+
408+ Arguments
409+ - `p_sfc`: face field of surface pressure to be corrected (modified in-place)
410+ - `file_path`: path to the ERA5-derived initialization NetCDF file
411+ - `face_space`: face space of the model grid (for reading/regridding)
412+ - `Y`: prognostic state, used to obtain model surface height
413+ - `ᶜT`: center field of temperature
414+ - `ᶜq_tot`: center field of total specific humidity
415+ - `thermo_params`: thermodynamics parameter set
416+ - `regridder_kwargs`: keyword arguments forwarded to the regridder
417+
418+ Notes
419+ - Expects `z_sfc` units in meters; if the variable is not present, the
420+ correction is skipped.
421+ """
422+ function correct_surface_pressure_for_topography! (
423+ p_sfc,
424+ file_path,
425+ face_space,
426+ Y,
427+ ᶜT,
428+ ᶜq_tot,
429+ thermo_params,
430+ regridder_kwargs,
431+ )
432+ var_name = " z_sfc"
433+ ᶠz_surface = nothing
434+ # Explicitly check if `z_sfc` exists in the input file; skip if not found
435+ has_z_sfc = NC. NCDataset (file_path) do ds
436+ haskey (ds, var_name)
437+ end
438+ if ! has_z_sfc
439+ @warn " Skipping topographic correction because variable `$var_name ` is missing from $(file_path) ."
440+ return false
441+ end
442+ ᶠz_surface = Fields. level (
443+ SpaceVaryingInputs. SpaceVaryingInput (
444+ file_path,
445+ var_name,
446+ face_space,
447+ regridder_kwargs = regridder_kwargs,
448+ ),
449+ Fields. half,
450+ )
451+
452+ if ᶠz_surface === nothing
453+ return false
454+ end
455+
456+ FT = eltype (thermo_params)
457+ grav = thermo_params. grav
458+
459+ # Log initial surface pressure statistics
460+ p_sfc_arr = Array (Fields. field2array (p_sfc))
461+ p_sfc_finite = filter (isfinite, p_sfc_arr)
462+
463+ ᶠz_model_surface = Fields. level (Fields. coordinate_field (Y. f). z, Fields. half)
464+ ᶠΔz = zeros (face_space)
465+ @. ᶠΔz = ᶠz_model_surface - ᶠz_surface
466+
467+ # Log surface height statistics
468+ z_surface_arr = Array (Fields. field2array (ᶠz_surface))
469+ z_model_arr = Array (Fields. field2array (ᶠz_model_surface))
470+ Δz_arr = Array (Fields. field2array (ᶠΔz))
471+
472+ ᶜphase_partition = TD. PhasePartition .(ᶜq_tot)
473+ ᶜR_m = TD. gas_constant_air .(thermo_params, ᶜphase_partition)
474+ ᶠR_m = ᶠinterp .(ᶜR_m)
475+ ᶠR_m_sfc = Fields. level (ᶠR_m, Fields. half)
476+
477+ ᶠT = ᶠinterp .(ᶜT)
478+ ᶠT_sfc = Fields. level (ᶠT, Fields. half)
479+
480+ denom = copy (ᶠR_m_sfc)
481+ @. denom = ᶠR_m_sfc * ᶠT_sfc
482+ denom_floor = FT (10 )
483+ @. denom = ifelse (isfinite (denom) && denom > denom_floor, denom, denom_floor)
484+
485+ correction_factor = similar (ᶠΔz)
486+ @. correction_factor = ifelse (
487+ isfinite (ᶠΔz),
488+ exp (FT (- 1 ) * ᶠΔz * grav / denom),
489+ one (FT),
490+ )
491+
492+ @. p_sfc =
493+ p_sfc *
494+ ifelse (
495+ isfinite (ᶠΔz),
496+ exp (FT (- 1 ) * ᶠΔz * grav / denom),
497+ one (FT),
498+ )
499+
500+ @info " Adjusted surface pressure to account for ERA5/model surface-height differences."
501+ return true
502+ end
503+
374504# WeatherModel function using the shared implementation
375505function overwrite_initial_conditions! (
376506 initial_condition:: WeatherModel ,
@@ -421,6 +551,16 @@ function overwrite_initial_conditions!(
421551 center_space,
422552 regridder_kwargs = regridder_kwargs,
423553 )
554+ correct_surface_pressure_for_topography! (
555+ p_sfc,
556+ file_path,
557+ face_space,
558+ Y,
559+ ᶜT,
560+ ᶜq_tot,
561+ thermo_params,
562+ regridder_kwargs,
563+ )
424564
425565 # With the known temperature (ᶜT) and moisture (ᶜq_tot) profile,
426566 # recompute the pressure levels assuming hydrostatic balance is maintained.
0 commit comments