Source code for rompy.swan.components.startup

"""Model start up components."""
import logging
from typing import Literal, Optional
from pydantic import field_validator, Field

from rompy.swan.components.base import BaseComponent
from rompy.swan.subcomponents.startup import CARTESIAN, SPHERICAL


logger = logging.getLogger(__name__)


[docs] class PROJECT(BaseComponent): """SWAN Project. .. code-block:: text PROJECT 'name' 'nr' 'title' 'title2 'title3' With this required command the user defines a number of strings to identify the SWAN run (project name e.g., an engineering project) in the print and plot file. Examples -------- .. ipython:: python :okwarning: from rompy.swan.components.startup import PROJECT proj = PROJECT(nr="01") print(proj.render()) proj = PROJECT( name="waus", nr="001", title1="Western Australia", title2="Perth Nest" ) print(proj.render()) """ model_type: Literal["project", "PROJECT"] = Field( default="project", description="Model type discriminator", ) name: Optional[str] = Field( default=None, description="Is the name of the project, at most 16 characters long", max_length=16, ) nr: str = Field( description=( "Is the run identification (to be provided as a character string; e.g. " "the run number) to distinguish this run among other runs for the same " "project; it is at most 4 characters long. It is the only required " "information in this command." ), max_length=4, ) title1: Optional[str] = Field( default=None, description=( "A string of at most 72 characters provided by the user to appear in the " "output of the program for the user's convenience (SWAN default: blanks)" ), max_length=72, ) title2: Optional[str] = Field( default=None, description="Same as 'title1'", max_length=72 ) title3: Optional[str] = Field( default=None, description="Same as 'title1'", max_length=72 )
[docs] def cmd(self) -> str: repr = "PROJECT" if self.name is not None: repr += f" name='{self.name}'" repr += f" nr='{self.nr}'" if self.title1 is not None: repr += f" title1='{self.title1}'" if self.title2 is not None: repr += f" title2='{self.title2}'" if self.title3 is not None: repr += f" title3='{self.title3}'" return repr
[docs] class SET(BaseComponent): """SWAN setting commands. .. code-block:: text SET [level] [nor] [depmin] [maxmes] [maxerr] [grav] [rho] [cdcap] & [inrhog] [hsrerr] NAUTICAL|->CARTESIAN [pwtail] [froudmax] [icewind] With this optional command the user assigns values to various general parameters. Notes ----- The error level `maxerr` is coded as follows: * 1: warnings * 2: errors (possibly automatically repaired or repairable by SWAN) * 3: severe errors Default values for `pwtail` depend on formulations of physics: * command GEN1: `pwtail = 5` * command GEN2: `pwtail = 5` * command GEN3 KOMEN: `pwtail = 4` * command GEN3 WESTH: `pwtail = 4` * command GEN3 JANSSEN: `pwtail = 5` Examples -------- .. ipython:: python :okwarning: from rompy.swan.components.startup import SET set = SET(level=0.5, direction_convention="nautical") print(set.render()) set = SET( level=-1.0, nor=90, depmin=0.01, maxerr=3, grav=9.81, rho=1025, cdcap=2.5e-3, inrhog=0, hsrerr=0.1, direction_convention="nautical", ) print(set.render()) """ model_type: Literal["set", "SET"] = Field( default="set", description="Model type discriminator" ) level: Optional[float] = Field( default=None, description=( "Increase in water level that is constant in space and time can be given " "with this option, `level` is the value of this increase (in m). For a " "variable water level reference is made to the commands " "INPGRID and READINP (SWAN default: 0)" ), ) nor: Optional[float] = Field( default=None, description=( "Direction of North with respect to the x-axis (measured " "counterclockwise); default `nor = 90`, i.e. x-axis of the problem " "coordinate system points East. When spherical coordinates are used " "(see command COORD) the value of `nor` may not be modified" ), ge=-360.0, le=360.0, ) depmin: Optional[float] = Field( default=None, description=( "Threshold depth (in m). In the computation any positive depth smaller " "than `depmin` is made equal to `depmin` (SWAN default: 0.05)" ), ge=0.0, ) maxmes: Optional[int] = Field( default=None, description=( "Maximum number of error messages during the computation at which the " "computation is terminated. During the computational process messages are " "written to the print file (SWAN default: 200)" ), ge=0, ) maxerr: Optional[Literal[1, 2, 3]] = Field( default=None, description=( "During pre-processing SWAN checks input data. Depending on the severity " "of the errors encountered during this pre-processing, SWAN does not " "start computations. The user can influence the error level above which " "SWAN will not start computations (at the level indicated the " "computations will continue) (SWAN default: 1)" ), ) grav: Optional[float] = Field( default=None, description="The gravitational acceleration (in m/s2) (SWAN default: 9.81)", ge=0.0, ) rho: Optional[float] = Field( default=None, description="The water density (in kg/m3) (SWAN default: 1025)", ge=0.0, ) cdcap: Optional[float] = Field( default=None, description=( "The maximum value for the wind drag coefficient. A value of 99999 means" "no cutting off the drag coefficient. A suggestion for this parameter is " "`cdcap = 2.5x 10-3` (SWAN default: 99999) " ), ge=0.0, ) inrhog: Optional[Literal[0, 1]] = Field( default=None, description=( "To indicate whether the user requires output based on variance or based " "on true energy (see Section 2.5). `inrhog` = 0: output based on variance, " "`inrhog` = 1: output based on true energy (SWAN default: 0)" ), ) hsrerr: Optional[float] = Field( default=None, description=( "The relative difference between the user imposed significant wave height " "and the significant wave height computed by SWAN (anywhere along the " "computational grid boundary) above which a warning will be given. This " "relative difference is the difference normalized with the user provided " "significant wave height. This warning will be given for each boundary " "grid point where the problem occurs (with its x- and y-index number of " "the computational grid). The cause of the difference is explained in " "Section 2.6.3. To suppress these warnings (in particular for " "nonstationary computations), set `hsrerr` at a very high value or use " "command OFF BNDCHK (SWAN default: 0.10) (ONLY MEANT FOR STRUCTURED GRIDS)" ), ge=0.0, ) direction_convention: Literal["nautical", "cartesian"] = Field( description=( "Direction convention: `nautical` indicates that the Nautical convention " "for wind and wave direction (SWAN input and output) will be used, " "`cartesian` indicates that the Cartesian convention for wind and wave " "direction will be used. For definition, see Section 2.5 or Appendix A " "(SWAN default: `cartesian`)" ), ) pwtail: Optional[int] = Field( default=None, description=( "Power of high frequency tail; defines the shape of the spectral tail " "above the highest prognostic frequency `fhigh` (see command CGRID). " "The energy density is assumed to be proportional to frequency to the " "power `pwtail`. If the user wishes to use another value, then this SET " "command should be located in the command file after GEN1, GEN2 or GEN3 " "command (these will override the SET command with respect to `pwtail`)" ), ge=0, ) froudmax: Optional[float] = Field( default=None, description=( "Is the maximum Froude number (`U/√gd` with `U` the current and `d` the " "water depth). The currents taken from a circulation model may mismatch " "with given water depth `d` in the sense that the Froude number becomes " "larger than 1. For this, the current velocities will be maximized by " "Froude number times `sqrt(gh)` (SWAN default: 0.8)" ), ge=0.0, ) icewind: Optional[Literal[0, 1]] = Field( default=None, description=( "Controls the scaling of wind input by open water fraction. Default value " "of zero corresponds to the case where wind input is scaled by the open " "water fraction. If `icewind = 1` then sea ice does not affect wind input " "directly. (Though there is still indirect effect via the sea ice sink " "term; see command SICE) (SWAN default: 0)" ), )
[docs] @field_validator("pwtail") @classmethod def pwtail_after_gen(cls, v): if v is not None: logger.warning("pwtail only has effect if set after GEN command") return v
[docs] def cmd(self) -> str: repr = "SET" if self.level is not None: repr += f" level={self.level}" if self.nor is not None: repr += f" nor={self.nor}" if self.depmin is not None: repr += f" depmin={self.depmin}" if self.maxmes is not None: repr += f" maxmes={self.maxmes}" if self.maxerr is not None: repr += f" maxerr={self.maxerr}" if self.grav is not None: repr += f" grav={self.grav}" if self.rho is not None: repr += f" rho={self.rho}" if self.cdcap is not None: repr += f" cdcap={self.cdcap}" if self.inrhog is not None: repr += f" inrhog={self.inrhog}" if self.hsrerr is not None: repr += f" hsrerr={self.hsrerr}" if self.direction_convention is not None: repr += f" {self.direction_convention.upper()}" if self.pwtail is not None: repr += f" pwtail={self.pwtail}" if self.froudmax is not None: repr += f" froudmax={self.froudmax}" if self.icewind is not None: repr += f" icewind={self.icewind}" return repr
[docs] class MODE(BaseComponent): """SWAN Mode. .. code-block:: text MODE ->STATIONARY|NONSTATIONARY ->TWODIMENSIONAL|ONEDIMENSIONAL With this optional command the user indicates that the run will be either stationary or nonstationary and one-dimensional (1D-mode) or two-dimensional (2D-mode). Nonstationary means either (see command COMPUTE): * (a) one nonstationary computations or * (b) a sequence of stationary computations or * (c) a mix of (a) and (b) Examples -------- .. ipython:: python :okwarning: from rompy.swan.components.startup import MODE mode = MODE() print(mode.render()) mode = MODE(kind="nonstationary", dim="twodimensional") print(mode.render()) """ model_type: Literal["mode", "MODE"] = Field( default="mode", description="Model type discriminator." ) kind: Literal["stationary", "nonstationary"] = Field( default="stationary", description="Indicates if run will be stationary or nonstationary", ) dim: Literal["onedimensional", "twodimensional"] = Field( default="twodimensional", description=( "Indicates that the run will be either one-dimensional (1D-mode) or " "two-dimensional (2D-mode)" ), )
[docs] def cmd(self) -> str: return f"MODE {self.kind.upper()} {self.dim.upper()}"
[docs] class COORDINATES(BaseComponent): """SWAN Coordinates. .. code-block:: text COORDINATES ->CARTESIAN|SPHERICAL REPEATING Command to choose between Cartesian and spherical coordinates (see Section 2.5). A nested SWAN run must use the same coordinate system as the coarse grid SWAN run. Examples -------- .. ipython:: python :okwarning: from rompy.swan.components.startup import COORDINATES coords = COORDINATES() print(coords.render()) coords = COORDINATES( kind=dict(model_type="spherical", projection="ccm"), reapeating=True, ) print(coords.render()) """ model_type: Literal["coordinates", "COORDINATES"] = Field( default="coordinates", description="Model type discriminator", ) kind: CARTESIAN | SPHERICAL = Field( default_factory=CARTESIAN, description="Coordinates kind", ) reapeating: bool = Field( default=False, description=( "This option is only for academic cases. It means that wave energy " "leaving at one end of the domain (in computational x-direction) enter at " "the other side; it is as if the wave field repeats itself in x-direction " "with the length of the domain in x-direction. This option cannot be used " "in combination with computation of set-up (see command SETUP). This " "option is available only with regular grids" ), )
[docs] def cmd(self) -> str: repr = f"COORDINATES {self.kind.render()}" if self.reapeating: repr += " REPEATING" return repr