|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +""" |
| 4 | +Class to generate NEMO v4.0 s-coordinates |
| 5 | +""" |
| 6 | + |
| 7 | +from typing import Optional # , Tuple |
| 8 | + |
| 9 | +# import numpy as np |
| 10 | +from xarray import Dataset |
| 11 | + |
| 12 | +from .zgr import Zgr |
| 13 | + |
| 14 | +# from pydomcfg.utils import is_nemo_none |
| 15 | + |
| 16 | + |
| 17 | +class Sco(Zgr): |
| 18 | + """ |
| 19 | + Class to generate terrain-following coordinates dataset objects. |
| 20 | + Currently, four types of terrain-following grids can be genrated: |
| 21 | + *) uniform sigma-coordinates (Phillips 1957) |
| 22 | + *) stretched s-coordinates with Song & Haidvogel 1994 stretching |
| 23 | + *) stretched s-coordinates with Siddorn & Furner 2013 stretching |
| 24 | + *) stretched s-coordinates with Madec et al. 1996 stretching |
| 25 | +
|
| 26 | + Method |
| 27 | + ------ |
| 28 | + *) Model levels' depths depT/W are defined from analytical function. |
| 29 | + *) Model vertical scale factors e3 (i.e., grid cell thickness) can |
| 30 | + be computed as |
| 31 | +
|
| 32 | + 1) analytical derivative of depth function |
| 33 | + (ln_e3_dep=False); for backward compatibility with v3.6. |
| 34 | + 2) discrete derivative (central-difference) of levels' depth |
| 35 | + (ln_e3_dep=True). The only possibility from v4.0. |
| 36 | +
|
| 37 | + References: |
| 38 | + *) NEMO v4.0 domzgr/{zgr_sco,s_sh94,s_sf12,s_tanh} subroutine |
| 39 | + *) Phillips, J. Meteorol., 14, 184-185, 1957. |
| 40 | + *) Song & Haidvogel, J. Comp. Phy., 115, 228-244, 1994. |
| 41 | + *) Siddorn & Furner, Oce. Mod. 66:1-13, 2013. |
| 42 | + *) Madec, Delecluse, Crepon & Lott, JPO 26(8):1393-1408, 1996. |
| 43 | + """ |
| 44 | + |
| 45 | + # -------------------------------------------------------------------------- |
| 46 | + def __call__( |
| 47 | + self, |
| 48 | + bot_min: float, |
| 49 | + bot_max: float, |
| 50 | + hc: float = 0.0, |
| 51 | + rmax: Optional[float] = None, |
| 52 | + stretch: Optional[str] = None, |
| 53 | + psurf: Optional[float] = None, |
| 54 | + pbott: Optional[float] = None, |
| 55 | + alpha: Optional[float] = None, |
| 56 | + efold: Optional[float] = None, |
| 57 | + pbot2: Optional[float] = None, |
| 58 | + ln_e3_dep: bool = True, |
| 59 | + ) -> Dataset: |
| 60 | + """ |
| 61 | + Generate NEMO terrain-following model levels. |
| 62 | +
|
| 63 | + Parameters |
| 64 | + ---------- |
| 65 | + bot_min: float |
| 66 | + Minimum depth of bottom topography surface (>0) (m) |
| 67 | + bot_max: float |
| 68 | + Maximum depth of bottom topography surface (>0) (m) |
| 69 | + hc: float |
| 70 | + critical depth for transition from uniform sigma |
| 71 | + to stretched s-coordinates (>0) (m) |
| 72 | + rmax: float, optional |
| 73 | + maximum slope parameter value allowed |
| 74 | + stretch: str, optional |
| 75 | + Type of stretching applied: |
| 76 | + *) None = no stretching, i.e. uniform sigma-coord. |
| 77 | + *) "sh94" = Song & Haidvogel 1994 stretching |
| 78 | + *) "sf12" = Siddorn & Furner 2013 stretching |
| 79 | + *) "md96" = Madec et al. 1996 stretching |
| 80 | + psurf: float, optional |
| 81 | + sh94: surface control parameter (0<= psurf <=20) |
| 82 | + md96: surface control parameter (0<= psurf <=20) |
| 83 | + sf12: thickness of first model layer (m) |
| 84 | + pbott: float, optional |
| 85 | + sh94: bottom control parameter (0<= pbott <=1) |
| 86 | + md96: bottom control parameter (0<= pbott <=1) |
| 87 | + sf12: scaling factor for computing thickness |
| 88 | + of bottom level Zb |
| 89 | + alpha: float, optional |
| 90 | + sf12: stretching parameter |
| 91 | + efold: float, optional |
| 92 | + sf12: efold length scale for transition from sigma |
| 93 | + to stretched coord |
| 94 | + pbot2: float, optional |
| 95 | + sf12 offset for calculating Zb = H*pbott + pbot2 |
| 96 | + ln_e3_dep: bool |
| 97 | + Logical flag to comp. e3 as fin. diff. (True) or |
| 98 | + analyt. (False) (default = True) |
| 99 | +
|
| 100 | + Returns |
| 101 | + ------- |
| 102 | + Dataset |
| 103 | + Describing the 3D geometry of the model |
| 104 | + """ |
| 105 | + |
| 106 | + self._bot_min = bot_min |
| 107 | + self._bot_max = bot_max |
| 108 | + self._hc = hc |
| 109 | + self.rmax = rmax |
| 110 | + self._stretch = stretch |
| 111 | + self._ln_e3_dep = ln_e3_dep |
| 112 | + |
| 113 | + # set stretching parameters after checking their consistency |
| 114 | + if self._stretch: |
| 115 | + self._set_stretch_par(psurf, pbott, alpha, efold, pbot2) |
| 116 | + |
| 117 | + ds = self._init_ds() |
| 118 | + |
| 119 | + # compute envelope bathymetry |
| 120 | + ds_env = self._compute_env(ds) |
| 121 | + |
| 122 | + # compute sigma-coordinates for z3 computation |
| 123 | + kindx = ds_env["z"] |
| 124 | + sigma = (self._compute_sigma(kk) for kk in kindx) |
| 125 | + self._sigT, self._sigW = sigma |
| 126 | + |
| 127 | + # compute z3 depths of zco vertical levels |
| 128 | + # dsz = self._sco_z3(ds_env) |
| 129 | + |
| 130 | + # compute e3 scale factors |
| 131 | + # dse = self._compute_e3(dsz) if self._ln_e3_dep else self._analyt_e3(dsz) |
| 132 | + |
| 133 | + # return dse |
| 134 | + |
| 135 | + # -------------------------------------------------------------------------- |
| 136 | + def _set_stretch_par(self, psurf, pbott, alpha, efold, pbot2): |
| 137 | + """ |
| 138 | + Set stretching parameters after checking |
| 139 | + consistency of input parameters |
| 140 | + """ |
| 141 | + if not (psurf and pbott): |
| 142 | + if self._stretch == "sh94": |
| 143 | + srf = "rn_theta" |
| 144 | + bot = "rn_bb" |
| 145 | + elif self._stretch == "md96": |
| 146 | + srf = "rn_theta" |
| 147 | + bot = "rn_thetb" |
| 148 | + elif self._stretch == "sf12": |
| 149 | + srf = "rn_zs" |
| 150 | + bot = "rn_zb_a" |
| 151 | + msg = ( |
| 152 | + srf |
| 153 | + + " and " |
| 154 | + + bot |
| 155 | + + "MUST be set when using " |
| 156 | + + self._stretch |
| 157 | + + " stretching." |
| 158 | + ) |
| 159 | + raise ValueError(msg) |
| 160 | + |
| 161 | + if self._stretch == "sf12": |
| 162 | + if not (alpha and efold and pbot2): |
| 163 | + msg = "rn_alpha, rn_efold and rn_zb_b MUST be set when \ |
| 164 | + using sf12 stretching." |
| 165 | + raise ValueError(msg) |
| 166 | + |
| 167 | + # setting stretching parameters |
| 168 | + self._psurf = psurf if psurf else 0.0 |
| 169 | + self._pbott = pbott if pbott else 0.0 |
| 170 | + self._alpha = alpha if alpha else 0.0 |
| 171 | + self._efold = efold if efold else 0.0 |
| 172 | + self._pbot2 = pbot2 if pbot2 else 0.0 |
| 173 | + |
| 174 | + # -------------------------------------------------------------------------- |
| 175 | + def _compute_env(self, ds: Dataset) -> Dataset: |
| 176 | + """ |
| 177 | + Compute the envelope bathymetry surface by applying the |
| 178 | + Martinho & Batteen (2006) smoothing algorithm to the |
| 179 | + actual topography to reduce the maximum value of the slope |
| 180 | + parameter |
| 181 | + r = abs(Hb-Ha) / (Ha+Hb) |
| 182 | +
|
| 183 | + where Ha and Hb are the depths of adjacent grid cells. |
| 184 | + The maximum slope parameter is reduced to be <= rmax. |
| 185 | +
|
| 186 | + Reference: |
| 187 | + *) Martinho & Batteen, Oce. Mod. 13(2):166-175, 2006. |
| 188 | +
|
| 189 | + Parameters |
| 190 | + ---------- |
| 191 | + ds: Dataset |
| 192 | + xarray dataset with the 2D bottom topography DataArray |
| 193 | + Returns |
| 194 | + ------- |
| 195 | + ds: Dataset |
| 196 | + xarray dataset with the 2D envelope bathymetry DataArray |
| 197 | + """ |
| 198 | + |
| 199 | + return ds |
0 commit comments