from logging import warning
import os
import datetime
from dataclasses import dataclass
from textwrap import dedent as dtxt
from .utils import (bool_to_str, verify_runpath, verify_mod_def,
verify_ww3_out)
from .ww3 import WW3Base
[docs]@dataclass
class WW3Ounp(WW3Base):
"""This class abstracts the program ww3_ounf. It is an extension of the class
:class:`pyww3.ww3.WW3Base()`.
"""
# withoput these two parameters, everything breaks
runpath: str
mod_def: str
EXE = "ww3_ounp"
DATE_FORMAT = "%Y%m%d %H%M%S"
output: str = "ww3_ounp.nml"
ww3_pnt: str = "out_pnt.ww3"
point_timestart: datetime.datetime = datetime.datetime(1900, 1, 1)
point_timestride: int = 0
point_timecount: int = 1000000000
point_timesplit: int = 6
point_list: str = "all"
point_samefile: bool = True
point_buffer: int = 150
point_type: int = 1
point_dimorder = True
file_prefix: str = "ww3."
file_netcdf: int = 4
spectra_output: int = 3
spectra_scale_fac: int = 1
spectra_output_fac: int = 0
param_output: int = 4
source_output: int = 4
source_scale_fac: int = 0
source_output_fac: int = 0
source_table_fac: int = 0
source_spectrum: bool = True
source_input: bool = True
source_interactions: bool = True
source_dissipation: bool = True
source_bottom: bool = True
source_ice: bool = True
source_total: bool = True
def __post_init__(self):
"""Validates the class initialization"""
# verify if all files are valid
verify_runpath(self.runpath)
verify_mod_def(self.runpath, self.mod_def)
verify_ww3_out(self.runpath, self.ww3_pnt)
# update date to match the simulation date
self.__setattr__("field_timestart", self.point_timestart)
# create the namelist text here
self.__setattr__("text", self.populate_namelist())
# check if file_prefix contais a folder
if "/" in self.file_prefix:
dirname = os.path.join(self.runpath, os.path.dirname(self.file_prefix))
if not os.path.isdir(dirname):
os.makedirs(dirname, exist_ok=True)
error = f"Path \'{dirname}\' does not exist in the runpath. I am creating it for you."
warning(error)
# NOTE: I am doing this this way instead of reading it from a file
# because f-strings in a file allow for arbitrary code execution,
# and are thefore a security issue. Writting everything here at
# least controls what is being executed.
[docs] def populate_namelist(self):
"""Create the namelist text using NOAA's latest template."""
txt = dtxt(f"""\
! -------------------------------------------------------------------- !
! WAVEWATCH III - ww3_ounp.nml - Point output post-processing !
! -------------------------------------------------------------------- !
! -------------------------------------------------------------------- !
! Define the output fields to postprocess via POINT_NML namelist
!
!
! * namelist must be terminated with /
! * definitions & defaults:
! Stop date for the output field
! POINT%TIMESTART = '19000101 000000'
! Time stride for the output field
! POINT%TIMESTRIDE = '0'
! Number of time steps
! POINT%TIMECOUNT = '1000000000'
! [4(yearly),6(monthly),8(daily),10(hourly)]
! POINT%TIMESPLIT = 6
! List of points index ['all'|'1 2 3']
! POINT%LIST = 'all'
! All the points in the same file
! POINT%SAMEFILE = T
! Number of points to process per pass
! POINT%BUFFER = 150
! [0=inventory | 1=spectra | 2=mean param | 3=source terms]
! POINT%TYPE = 1
! [time,station=T | station,time=F]
! POINT%DIMORDER = T
! -------------------------------------------------------------------- !
&POINT_NML
POINT%TIMESTART = '{self.point_timestart.strftime(self.DATE_FORMAT)}'
POINT%TIMESTRIDE = '{self.point_timestride}'
POINT%TIMECOUNT = '{self.point_timecount}'
POINT%TIMESPLIT = {self.point_timesplit}
POINT%LIST = '{self.point_list}'
POINT%SAMEFILE = {bool_to_str(self.point_samefile).upper()}
POINT%BUFFER = {self.point_buffer}
POINT%TYPE = {self.point_type}
POINT%DIMORDER = {bool_to_str(self.point_dimorder).upper()}
/
! -------------------------------------------------------------------- !
! Define the content of the output file via FILE_NML namelist
!
! * namelist must be terminated with /
! * definitions & defaults:
! FILE%PREFIX = 'ww3.' ! Prefix for output file name
! FILE%NETCDF = 3 ! Netcdf version [3|4]
! -------------------------------------------------------------------- !
&FILE_NML
FILE%PREFIX = '{self.file_prefix}'
FILE%NETCDF = {self.file_netcdf}
/
! -------------------------------------------------------------------- !
! Define the type 0, inventory of file
!
! * namelist must be terminated with /
! * definitions & defaults:
! No additional input, the above time range is ignored.
! -------------------------------------------------------------------- !
! -------------------------------------------------------------------- !
! Define the type 1, spectra via SPECTRA_NML namelist
!
! Table of 1-D spectra content :
! - time, station id, station name, longitude, latitude
! - frequency : unit Hz, center band frequency
! linear log scale (XFR factor)
! - ffp, f, th1m, sth1m, alpha : 1D spectral parameters
! - dpt, ust, wnd, wnddir : mean parameters
!
! Transfert file content :
! - time, station id, station name, longitude, latitude
! - frequency : unit Hz, center band frequency
! linear log scale (XFR factor)
! - frequency1 : unit Hz, lower band frequency
! - frequency2 : unit Hz, upper band frequency
! - direction : unit degree, convention to, origin East, trigonometric order
! - efth(time,station,frequency,direction) : 2D spectral density
! - dpt, wnd, wnddir, cur, curdir : mean parameters
!
! Spectral partitioning content :
! - time, station id, station name, longitude, latitude
! - npart : number of partitions
! - hs, tp, lm, th1m, sth1m, ws, tm10, t01, t02 : partitioned parameters
! - dpt, wnd, wnddir, cur, curdir : mean parameters
!
!
! * namelist must be terminated with /
! * definitions & defaults:
! SPECTRA%OUTPUT = 3 ! 1: Print plots
! ! 2: Table of 1-D spectra
! ! 3: Transfer file
! ! 4: Spectral partitioning
! SPECTRA%SCALE_FAC = 1 ! Scale factor (-1=disabled)
! SPECTRA%OUTPUT_FAC = 0 ! Output factor (0=normalized)
! -------------------------------------------------------------------- !
&SPECTRA_NML
SPECTRA%OUTPUT = {self.spectra_output}
SPECTRA%SCALE_FAC = {self.spectra_scale_fac}
SPECTRA%OUTPUT_FAC = {self.spectra_output_fac}
/
! -------------------------------------------------------------------- !
! Define the type 2, mean parameter via PARAM_NML namelist
!
! Forcing parameters content :
! - dpt, wnd, wnddir, cur, curdir
!
! Mean wave parameters content :
! - hs, lm, tr, th1p, sth1p, fp, th1m, sth1m
!
! Nondimensional parameters (U*) content :
! - ust, efst, fpst, cd, alpha
!
! Nondimensional parameters (U10) content :
! - wnd, efst, fpst, cd, alpha
!
! Validation table content :
! - wnd, wnddir, hs, hsst, cpu, cmu, ast
!
! WMO stantdard output content :
! - wnd, wnddir, hs, tp
!
! * namelist must be terminated with /
! * definitions & defaults:
! PARAM%OUTPUT = 4 ! 1: Forcing parameters
! ! 2: Mean wave parameters
! ! 3: Nondimensional pars. (U*)
! ! 4: Nondimensional pars. (U10)
! ! 5: Validation table
! ! 6: WMO standard output
! -------------------------------------------------------------------- !
&PARAM_NML
PARAM%OUTPUT = {self.param_output}
/
! -------------------------------------------------------------------- !
! Define the type 3, source terms via SOURCE_NML namelist
!
! Table of 1-D S(f) content :
! - time, station id, station name, longitude, latitude
! - frequency : unit Hz, center band frequency
! - ef(frequency) : 1D spectral density
! - Sin(frequency) : input source term
! - Snl(frequency) : non linear interactions source term
! - Sds(frequency) : dissipation source term
! - Sbt(frequency) : bottom source term
! - Sice(frequency) : ice source term
! - Stot(frequency) : total source term
! - dpt, ust, wnd : mean parameters
!
! Table of 1-D inverse time scales (1/T = S/F) content :
! - time, station id, station name, longitude, latitude
! - frequency : unit Hz, center band frequency
! - ef(frequency) : 1D spectral density
! - tini(frequency) : input inverse time scales source term
! - tnli(frequency) : non linear interactions inverse time
! scales source term
! - tdsi(frequency) : dissipation inverse time scales source term
! - tbti(frequency) : bottom inverse time scales source term
! - ticei(frequency) : ice inverse time scales source term
! - ttoti(frequency) : total inverse time scales source term
! - dpt, ust, wnd : mean parameters
!
! Transfert file content :
! - time, station id, station name, longitude, latitude
! - frequency : unit Hz, center band frequency
! linear log scale (XFR factor)
! - frequency1 : unit Hz, lower band frequency
! - frequency2 : unit Hz, upper band frequency
! - direction : unit degree, convention to, origin East, trigonometric order
! - efth(frequency,direction) : 2D spectral density
! - Sin(frequency,direction) : input source term
! - Snl(frequency,direction) : non linear interactions source term
! - Sds(frequency,direction) : dissipation source term
! - Sbt(frequency,direction) : bottom source term
! - Sice(frequency,direction) : ice source term
! - Stot(frequency,direction) : total source term
! - dpt, wnd, wnddir, cur, curdir, ust : mean parameters
!
!
! * namelist must be terminated with /
! * definitions & defaults:
! SOURCE%OUTPUT = 4 ! 1: Print plots
! ! 2: Table of 1-D S(f)
! ! 3: Table of 1-D inv. time scales
! (1/T = S/F)
! ! 4: Transfer file
! SOURCE%SCALE_FAC = 0 ! Scale factor (-1=disabled)
! SOURCE%OUTPUT_FAC = 0 ! Output factor (0=normalized)
! SOURCE%TABLE_FAC = 0 ! Table factor
! 0 : Dimensional.
! 1 : N.dim. in terms of U10
! 2 : N.dim. in terms of U*
! 3-5: like 0-2 with f norm by fp.
! SOURCE%SPECTRUM = T ! [T|F]
! SOURCE%INPUT = T ! [T|F]
! SOURCE%INTERACTIONS = T ! [T|F]
! SOURCE%DISSIPATION = T ! [T|F]
! SOURCE%BOTTOM = T ! [T|F]
! SOURCE%ICE = T ! [T|F]
! SOURCE%TOTAL = T ! [T|F]
! -------------------------------------------------------------------- !
&SOURCE_NML
SOURCE%OUTPUT = {self.source_output}
SOURCE%SCALE_FAC = {self.source_scale_fac}
SOURCE%OUTPUT_FAC = {self.source_output_fac}
SOURCE%TABLE_FAC = {self.source_table_fac}
SOURCE%SPECTRUM = {bool_to_str(self.source_spectrum).upper()}
SOURCE%INPUT = {bool_to_str(self.source_input).upper()}
SOURCE%INTERACTIONS = {bool_to_str(self.source_interactions).upper()}
SOURCE%DISSIPATION = {bool_to_str(self.source_dissipation).upper()}
SOURCE%BOTTOM = {bool_to_str(self.source_bottom).upper()}
SOURCE%ICE = {bool_to_str(self.source_ice).upper()}
SOURCE%TOTAL = {bool_to_str(self.source_total).upper()}
/
! -------------------------------------------------------------------- !
! WAVEWATCH III - end of namelist !
! -------------------------------------------------------------------- !""")
return txt