Source code for environmentaltools.processes.write

import numpy as np
from environmentaltools.common import utils, save
from scipy.io import loadmat as ldm
import os


[docs] def write_cshore(properties: dict, folder: str): """Write CSHORE model input file (infile). Creates the main input file for CSHORE (Coastal Storm Modeling System) with all necessary parameters for beach profile evolution, sediment transport, wave transformation, and coastal structure simulation. Parameters ---------- properties : dict Dictionary containing CSHORE model parameters: - header : str Project description header - iline : int Line number option (1: single line, 2: multiple lines) - iprofl : int Profile option (0: initial, 1: recorded) - isedav : int Sediment availability (0: unlimited, 1: limited) - iperm : int Permeable layer option (0: no, 1: yes) - iover : int Overtopping and overflow option - iwtran : int Wave transmission option - ipond : int Ponding option for runup zone - infilt : int Infiltration option - iwcint : int Wave-current interaction option - iroll : int Roller model option - iwind : int Wind effects option (0: no wind, 1: with wind) - itide : int Tidal variation option - iveg : int Vegetation option - dx : float Node spacing (m) - gamma : float Breaking parameter - d50 : float Median sediment grain size (m) - wf : float Sediment fall velocity (m/s) - sg : float Sediment specific gravity - effb : float Suspended load efficiency factor - efff : float Bed load efficiency factor - slp : float Suspended load parameter - slpot : float Suspended load parameter (offshore transport) - tanphi : float Tangent of internal friction angle - blp : float Bed load parameter - rwh : float Roller parameter - ilab : int Laboratory or field scale - nwave : int Number of wave conditions - nsurg : int Number of surge conditions - timebc_wave : float Time for boundary condition (s) - Tp : float Peak wave period (s) - Hrms : float Root-mean-square wave height (m) - Wsetup : float Wave setup (m) - swlbc : float Still water level boundary condition (m) - angle : float Wave angle (degrees) - x : np.ndarray Cross-shore coordinates (m) - zb : np.ndarray Beach elevation (m) - fw : np.ndarray Bottom friction factor - VelV : float, optional Wind velocity (m/s), required if iwind=1 - DirV : float, optional Wind direction (degrees), required if iwind=1 - slgradient : float, optional Sea level gradient, required if itide=1 folder : str Directory path where the input file will be created Returns ------- None Creates 'infile' in the specified folder Notes ----- The function creates a formatted text file following CSHORE input specifications: - Model control parameters (lines, profile, sediment options) - Physical parameters (grid spacing, breaking, sediment properties) - Boundary conditions (waves, wind, tide) - Bathymetric profile data Wind and tide data are conditionally written based on iwind and itide flags. Examples -------- >>> props = { ... 'header': 'Beach Profile Simulation', ... 'iline': 1, 'iprofl': 0, 'isedav': 1, ... 'dx': 1.0, 'gamma': 0.4, 'd50': 0.0003, ... 'Hrms': 2.5, 'Tp': 8.0, 'angle': 0.0, ... 'x': np.arange(0, 500, 1.0), ... 'zb': np.linspace(-5, 3, 500), ... # ... more parameters ... } >>> write_cshore(props, './cshore_run') """ fid = open(folder + "/infile", "w") fid.write("3 \n") fid.write("{} \n".format(str(properties["header"]))) fid.write( "{} ->ILINE\n".format( str(properties["iline"]) ) ) fid.write( "{} ->IPROFL\n".format( str(properties["iprofl"]) ) ) fid.write( "{} ->ISEDAV\n".format( str(properties["isedav"]) ) ) fid.write( "{} ->IPERM\n".format( str(properties["iperm"]) ) ) fid.write( "{} ->IOVER\n".format( str(properties["iover"]) ) ) fid.write( "{} ->IWTRAN\n".format( str(properties["iwtran"]) ) ) fid.write( "{} ->IPOND\n".format( str(properties["ipond"]) ) ) fid.write( "{} ->INFILT\n".format( str(properties["infilt"]) ) ) fid.write( "{} ->IWCINT\n".format( str(properties["iwcint"]) ) ) fid.write( "{} ->IROLL \n".format( str(properties["iroll"]) ) ) fid.write( "{} ->IWIND \n".format( str(properties["iwind"]) ) ) fid.write( "{} ->ITIDE \n".format( str(properties["itide"]) ) ) fid.write( "{} ->IVEG \n".format( str(properties["iveg"]) ) ) # fid.write('{} ->ICLAY \n'.format(str(properties['iclay']))) fid.write( "{:11.4f} ->DX\n".format(properties["dx"]) ) fid.write( "{:11.4f} ->GAMMA \n".format( properties["gamma"] ) ) fid.write( "{:11.4f}{:11.4f}{:11.4f} ->D50 WF SG\n".format( properties["d50"], properties["wf"], properties["sg"] ) ) fid.write( "{:11.4f}{:11.4f}{:11.4f}{:11.4f} ->EFFB EFFF SLP\n".format( properties["effb"], properties["efff"], properties["slp"], properties["slpot"], ) ) fid.write( "{:11.4f}{:11.4f} ->TANPHI BLP\n".format( properties["tanphi"], properties["blp"] ) ) fid.write( "{:11.4f} ->RWH \n".format( properties["rwh"] ) ) fid.write( "{} ->ILAB\n".format( str(properties["ilab"]) ) ) fid.write( "{} ->NWAVE \n".format( str(properties["nwave"]) ) ) fid.write( "{} ->NSURGE \n".format( str(properties["nsurg"]) ) ) fid.write( "{:11.2f}{:11.4f}{:11.4f}{:11.4f}{:11.4f}{:11.4f}\n".format( properties["timebc_wave"], properties["Tp"], properties["Hrms"], properties["Wsetup"], properties["swlbc"], properties["angle"], ) ) fid.write( "{} ->NBINP \n".format(str(len(properties["x"]))) ) # if properties.iperm==1|properties.isedav >= 1: # fid.write('{} ->NPINP \n',length(properties.x_p)) fid.close() fid = open(folder + "/infile", "a") dum = np.vstack([properties["x"], properties["zb"], properties["fw"]]) for line in range(dum.shape[1]): fid.write("{:11.4f}{:11.4f}{:11.4f}\n".format(*dum[:, line])) # if properties.iperm == 1 | properties.isedav >= 1: # dum = [properties.x_p(:) properties.zb_p(:)] # fid.write('#11.4f#11.4f\n', dum) if properties["iwind"]: fid.write("1 \n") fid.write( "{:11.1f}{:11.4f}{:11.4f}\n".format( 0, properties["VelV"], properties["DirV"] ) ) fid.write( "{:11.1f}{:11.4f}{:11.4f}\n".format( properties["timebc_wave"], properties["VelV"], properties["DirV"] ) ) if properties["itide"]: fid.write("1 \n") fid.write("{:11.1f}{:13.8f}\n".format(0, properties["slgradient"])) fid.write( "{:11.1f}{:13.8f}\n".format( properties["timebc_wave"], properties["slgradient"] ) ) fid.close() return
[docs] def write_swan(i, index_, case_id, data, params, mesh="global", local=False, nested=False): """Write SWAN model input files (swaninit and input file). Creates initialization and input files for SWAN (Simulating WAves Nearshore) spectral wave model, including grid definition, boundary conditions, physical processes, and output specifications. Parameters ---------- i : int Time step counter (0-indexed) index_ : pd.Timestamp or datetime-like Timestamp for current simulation time case_id : str Case identifier (e.g., '0001', '0002') data : pd.DataFrame Time series with boundary condition data containing columns: - eta : float Water level (m) - Hs : float Significant wave height (m) - Tp : float Peak wave period (s) - DirM : float Mean wave direction (degrees, nautical convention) - Vv : float Wind velocity (m/s) - DirV : float Wind direction (degrees) params : dict Model configuration parameters: - directory : str Working directory path - project_name : str Project identifier - {mesh}_coords_x : float Grid origin x-coordinate (m) - {mesh}_coords_y : float Grid origin y-coordinate (m) - {mesh}_angle : float Grid rotation angle (degrees) - {mesh}_length_x : float Grid extent in x-direction (m) - {mesh}_length_y : float Grid extent in y-direction (m) - {mesh}_nodes_x : int Number of grid nodes in x-direction - {mesh}_nodes_y : int Number of grid nodes in y-direction - {mesh}_inc_x : float Grid spacing in x-direction (m) - {mesh}_inc_y : float Grid spacing in y-direction (m) mesh : str, optional Mesh identifier ('global' or 'local'). Default: 'global' local : bool, optional Flag for local mesh (deprecated, not used). Default: False nested : bool, optional If True, creates nested grid output for downscaling. Default: False Returns ------- None Creates two files in params['directory']/case_id/: - swaninit: Initialization file - input_{mesh}_{case_id}.swn: SWAN command file Notes ----- The function generates SWAN input files with: **Grid Configuration:** - Regular Cartesian grid with specified origin, extent, and resolution - Directional discretization: 36 bins (10° resolution) - Frequency range: 0.05-0.50 Hz **Boundary Conditions:** - Global mesh: JONSWAP spectrum with constant parameters - Local mesh: Nested boundary from parent grid - Two-sided boundaries (North/South and East/West) **Physical Processes:** - Wave generation (GEN3 with exponential growth) - Triad and quadruplet wave-wave interactions - Depth-induced breaking and whitecapping - Wave setup and diffraction **Output:** - Nested mode: Boundary conditions for nested grid - Standard mode: Wave parameters on computational grid (Hs, Tp, Dir, etc.) Direction convention: SWAN uses nautical convention (waves coming from), automatically converted from PdE convention (270 - angle). Examples -------- >>> import pandas as pd >>> data = pd.DataFrame({ ... 'eta': [0.5], 'Hs': [2.0], 'Tp': [8.0], ... 'DirM': [45.0], 'Vv': [10.0], 'DirV': [90.0] ... }) >>> params = { ... 'directory': './swan_run', ... 'project_name': 'Beach_Wave_Modeling', ... 'global_coords_x': 0, 'global_coords_y': 0, ... 'global_angle': 0, 'global_length_x': 1000, ... 'global_length_y': 500, 'global_nodes_x': 101, ... 'global_nodes_y': 51, # ... more parameters ... } >>> write_swan(0, data.index[0], '0001', data, params, mesh='global') """ swfile = open(params["directory"] + "/" + case_id + "/swaninit", "w") swfile.write("4 version of initialisation file\n") swfile.write("GDFA name of institute\n") swfile.write("3 command file ref. number\n") swfile.write("input_" + mesh + "_" + case_id + ".swn\n") swfile.write("4 print file ref. number\n") swfile.write("print_" + mesh + "_" + case_id + ".prt\n") swfile.write("4 test file ref. number\n") swfile.write(" test file name\n") swfile.write("6 screen ref. number\n") swfile.write("99 highest file ref. number\n") swfile.write("$ comment identifier\n") swfile.write(" TAB character\n") swfile.write("/ dir sep char in input file\n") swfile.write( "/ dir sep char replacing previous one\n" ) swfile.write("1 default time coding option\n") swfile.close() imswfile = open( params["directory"] + "/" + case_id + "/input_" + mesh + "_" + case_id + ".swn", "w" ) imswfile.write( "$*******************************HEADING******************************************\n" ) imswfile.write("$\n") imswfile.write("PROJ '" + params["project_name"] + "' '" + case_id + "' \n") imswfile.write("$Caso " + mesh + "_" + case_id + "\n") imswfile.write( "$***************************** MODEL INPUT ****************************************\n" ) imswfile.write( "SET LEVEL " + str(np.round(data.loc[index_, "eta"], decimals=2)) + "\n" ) imswfile.write("$ xpc ypc alpc xlenc ylenc mxc myc \n") imswfile.write("$\n") imswfile.write( "CGRID REGULAR " + str(params[mesh + "_coords_x"]) + " " + str(params[mesh + "_coords_y"]) + " " + str(np.round(np.remainder(params[mesh + "_angle"], 360), decimals=2)) + " " + str(params[mesh + "_length_x"]) + " " + str(params[mesh + "_length_y"]) + " " + str(params[mesh + "_nodes_x"] - 1) + " " + str(params[mesh + "_nodes_y"] - 1) + " CIRCLE 36 0.05 0.50\n" ) imswfile.write("$\n") imswfile.write("$xpinp ypinp alpinp mxinp myinp dxinp dyinp\n") imswfile.write( "INPGRID BOTTOM " + str(params[mesh + "_coords_x"]) + " " + str(params[mesh + "_coords_y"]) + " " + str(np.round(np.remainder(params[mesh + "_angle"], 360), decimals=2)) + " " + str(params[mesh + "_nodes_x"] - 1) + " " + str(params[mesh + "_nodes_y"] - 1) + " " + str(params[mesh + "_inc_x"]) + " " + str(params[mesh + "_inc_y"]) + "\n" ) imswfile.write("$\n") imswfile.write( "$ fac fname idla nhedf formato ((mxinp+1)FN.d)\n" ) imswfile.write("$\n") imswfile.write( "READINP BOTTOM -1. '" + case_id + "_" + mesh + ".dat' 3 0 FORMAT '(" + str(params[mesh + "_nodes_x"]) + "F9.3)'\n" ) imswfile.write("$\n") imswfile.write( "WIND " + str(np.round(data.loc[index_, "Vv"], decimals=2)) + " " + str(np.round(np.remainder(270 - data.loc[index_, "DirV"], 360), decimals=2)) + "\n" ) imswfile.write("$\n") if mesh == "global": # Here, direction has PdE convention (waves coming from N: 0º, E: 90º) if data.loc[index_, "DirM"] < 90: side = ["N", "E"] elif (data.loc[index_, "DirM"] < 180) & (data.loc[index_, "DirM"] >= 90): side = ["S", "E"] elif (data.loc[index_, "DirM"] < 270) & (data.loc[index_, "DirM"] >= 180): side = ["S", "W"] else: side = ["N", "W"] imswfile.write("BOUN SHAPESPEC JONSWAP PEAK DSPR POWER\n") imswfile.write("$ Hs Tp Dir dd(spreading power)\n") imswfile.write( "BOUN SIDE " + side[0] + " CONSTANT PAR " + str(np.round(data.loc[index_, "Hs"], decimals=2)) + " " + str(np.round(data.loc[index_, "Tp"], decimals=2)) + " " + str( np.round(np.remainder(270 - data.loc[index_, "DirM"], 360), decimals=2) ) + " 2.00\n" ) imswfile.write( "BOUN SIDE " + side[1] + " VARIABLE PAR 200 " + str(np.round(data.loc[index_, "Hs"], decimals=2)) + " " + str(np.round(data.loc[index_, "Tp"], decimals=2)) + " " + str( np.round(np.remainder(270 - data.loc[index_, "DirM"], 360), decimals=2) ) + " 2.00\n" ) else: imswfile.write("BOUNdnest1 NEST '" + case_id + ".bnd' CLOSED\n") imswfile.write("$*************************WIND GROWTH**************************\n") imswfile.write("GEN3 AGROW\n") imswfile.write( "$*************************WAVE-WAVE INTERACTION**************************\n" ) imswfile.write("TRIAD\n") imswfile.write("QUAD\n") imswfile.write("$*************************DISSIPATION**************************\n") imswfile.write("BREAKING\n") imswfile.write("WCAP\n") imswfile.write("$*************************************************************\n") imswfile.write("SETUP\n") imswfile.write("DIFFRACTION\n") imswfile.write("NUM ACCUR 0.005 0.01 0.005 99.5 STAT 50 0.1\n") if nested: imswfile.write( "$*************************OUPUT LOCATIONS**************************\n" ) imswfile.write( "NGRID '" + case_id + ".dat" + "' " + str(params["local_coords_x"]) + " " + str(params["local_coords_y"]) + " " + str(np.round(np.remainder(params["local_angle"], 360), decimals=2)) + " " + str(params["local_length_x"]) + " " + str(params["local_length_y"]) + " " + str(params["local_nodes_x"] - 1) + " " + str(params["local_nodes_y"] - 1) + " \n" ) imswfile.write( "$***************************** MODEL OUTPUT LOCATIONS***************************************\n" ) imswfile.write("NESTOUT '" + case_id + ".dat" + "' '" + case_id + ".bnd' \n") else: imswfile.write( "$***************************** MODEL COMPUTACIONAL GRID OUTPUT ***************************************\n" ) imswfile.write( "BLOCK 'COMPGRID' NOHEAD '" + case_id + ".mat' LAY 3 XP YP HSIGN TPS DIR QB WLEN DEPTH SETUP\n" ) imswfile.write( "$***************************** COMPUTATIONS ***************************************\n" ) imswfile.write("COMPUTE\n") imswfile.write("STOP\n") imswfile.close() return
[docs] def write_copla(i, index_, case_id, data, params, mesh="local"): """Write COPLA model input files for nearshore profile evolution. Creates input files for COPLA (Coupled Profile and Area) model, which simulates beach profile evolution and morphodynamics. Reads SWAN wave output and formats it for COPLA computation. Parameters ---------- i : int Time step counter (0-indexed) index_ : pd.Timestamp or datetime-like Timestamp for current simulation time case_id : str Case identifier (e.g., '0001', '0002') data : pd.DataFrame Time series with boundary condition data containing: - Hs : float Significant wave height (m) - Tp : float Peak wave period (s) - DirM : float Mean wave direction (degrees) - eta : float Water level / tidal elevation (m) params : dict Model configuration parameters: - directory : str Working directory path - {mesh}_nodes_x : int Number of cross-shore nodes - {mesh}_nodes_y : int Number of longshore nodes - {mesh}_inc_x : float Grid spacing in x-direction (m) - {mesh}_inc_y : float Grid spacing in y-direction (m) mesh : str, optional Mesh identifier, typically 'local'. Default: 'local' Returns ------- None Creates three files in params['directory']/case_id/: - {case_id}out.dat: Output configuration with wave field from SWAN - CLAVE.DAT: Key file with case identifier - {case_id}in.dat: Input parameters file - {case_id}dat: Calibration and solver parameters Notes ----- The function performs coordinate system transformation: - SWAN uses standard coordinates (X: east, Y: north) - COPLA uses rotated coordinates: Xc = -Ys, Yc = Xs - Wave direction adjusted: Dir_copla = Dir_swan - 90° **File Structure:** {case_id}out.dat contains: - Grid dimensions and coordinates - Bathymetry from SWAN depth output - Wave height field (Hs/2 for amplitude) - Wave direction field {case_id}in.dat specifies: - Computational grid parameters - Boundary condition type - Wave period and tidal level - Incident wave amplitude and direction {case_id}dat contains solver settings: - Time step and roughness (Manning coefficient) - Eddy viscosity and Coriolis parameter - Nonlinear terms and flooding options NaN values are replaced with 1e-6 for numerical stability. Examples -------- >>> import pandas as pd >>> data = pd.DataFrame({ ... 'Hs': [2.0], 'Tp': [8.0], ... 'DirM': [45.0], 'eta': [0.5] ... }) >>> params = { ... 'directory': './copla_run', ... 'local_nodes_x': 50, 'local_nodes_y': 100, ... 'local_inc_x': 5.0, 'local_inc_y': 10.0 ... } >>> write_copla(0, data.index[0], '0001', data, params) """ fSwan = ldm(params["directory"] + "/" + case_id + "/" + case_id + ".mat") Hsig, h_CoPla = fSwan["Hsig"], fSwan["Depth"] Dir = ( fSwan["Dir"] - 90 ) # lo giro para adapatarlo al eje de Copla, los ejes de copla son Xc = -Ys, Yc = Xs (c: copla, s:swan) nr, mr = params[mesh + "_nodes_x"], params[mesh + "_nodes_y"] xp, yp = ( np.arange(0, mr) * params["local_inc_x"], np.arange(0, nr) * params["local_inc_y"], ) # Confirmar que es correcto Hsig[np.isnan(Hsig)], Dir[np.isnan(Dir)], h_CoPla[np.isnan(h_CoPla)] = ( 1e-6, 1e-6, 1e-6, ) fp = open(params["directory"] + "/" + case_id + "/" + case_id + "out.dat", "w") fp.write(str(nr) + " " + str(mr) + " 1\n") for col in range(0, nr - 1): fp.write(str(yp[col]) + " ") fp.write(str(yp[-1]) + "\n") for row in range(0, mr): fp.write(str(xp[row]) + "\n") for col in range(0, nr - 1): fp.write("%8.3f" % h_CoPla[row, col] + " ") fp.write("%8.3f" % h_CoPla[row, -1] + "\n") for col in range(0, nr - 1): fp.write("%8.3f" % (Hsig[row, col] / 2) + " ") fp.write("%8.3f" % (Hsig[row, -1] / 2) + "\n") if row != 0: for col in range(0, nr - 1): fp.write("%8.3f" % (Dir[row, col]) + " ") fp.write("%8.3f" % (Dir[row, -1]) + "\n") fp.close() fp = open(params["directory"] + "/" + case_id + "/CLAVE.DAT", "w") fp.write(case_id + "\n") fp.close() # Escritura de fichero clavein fp = open(params["directory"] + "/" + case_id + "/" + case_id + "in.dat", "w") htol, nd = 50, 1 fp.write("nx ny\n") fp.write(str(nr) + " " + str(mr) + " 1\n") fp.write("iu ntype icur ibc\n") fp.write(" 1 1 0 1\n") fp.write("dx dy htol\n") fp.write( str(params["local_inc_y"]) + " " + str(params["local_inc_x"]) + " " + str(htol) + "\n" ) fp.write("nd\n") fp.write(str(nd) + "\n") fp.write("if1 if2 if3\n") fp.write("1 0 0\n") fp.write("iinput ioutput\n") fp.write("1 1\n") fp.write("T marea\n") fp.write(str(data.loc[index_, "Tp"]) + " " + str(data.loc[index_, "eta"]) + "\n") fp.write("amp dir(grados)\n") fp.write( str(data.loc[index_, "Hs"] / 2) + " " + str(180 - data.loc[index_, "DirM"]) + " \n" ) fp.close() fp = open(params["directory"] + "/" + case_id + "/" + case_id + "dat", "w") fp.write("*\n") fp.write("*\n") fp.write("* FICHERO DE DATOS PARA CALIBRACION\n") fp.write("*\n") fp.write("F(2F10.3,3I5)\n") fp.write("* IT = INTERVALO DE TIEMPO\n") fp.write("* ROZA = RUGOSIDAD DE CHEZY --> 1/Mannig\n") fp.write("* NT = NUMERO DE ESCRITURAS EN FICHERO\n") fp.write("* REPE = NUMERO DE ITERACIONES ENTRE LAS ESCRITURAS\n") fp.write("* IESDAO = NUMERO DE REPEs HASTA LA PRIMERA ESCRITURA\n") fp.write("*\n") fp.write("* EN TOTAL LAS ITERACIONES SON --> ((NT-1)*REPE + IESDAO*REPE)\n") fp.write( "* HAY QUE CUMPLIR LA CONDICION --> (NN >= (NT-1)*REPE + IESDAO*REPE)\n" ) fp.write("*\n") fp.write("* IT ROZA NT REPE IESDAO\n") fp.write("******.***######.###*****#####*****\n") fp.write(" 0.500 15.000 1 1000 1\n") fp.write("*\n") fp.write("* EDDY = FACTOR EDDY VISCOSITY\n") fp.write("* CORI = FACTOR DE CORIOLIS\n") fp.write("* NINTER= NUMERO ITERACIONES EN TERMINOS NO LINEALES\n") fp.write("F(2F10.3,I5)\n") fp.write("* EDDY CORI NINTER\n") fp.write(" 30.000 0.000 3\n") fp.write("* \n") fp.write("* IANL = TERMINOS NO LINEALES (SI = 1)\n") fp.write("* IAGUA = INUNDACION DE CELDAS (SI = 1)\n") fp.write("* ISLIP = CONTORNOS SIN FRICCION (SI = 1)\n") fp.write("F(3I5)\n") fp.write("* IANL IAGUA ISLIP\n") fp.write(" 1 0 0\n") fp.write("*\n") fp.write("*\n") fp.write( "* COORDENADAS DE PUNTOS DONDE SE DESEE TENER UN FICHERO EN EL TIEMPO \n" ) fp.write("* DE SUPERFICIE LIBRE (ETA), VELOCIDAD (U), VELOCIDAD (V). \n") fp.write("F(I5)\n") fp.write("*NUMERO DE PUNTOS (MAXIMO 30 PUNTOS)\n") fp.write(" 0\n") return
[docs] def directory(params, data, global_db, local_db): """Create project directory structure with initialized SWAN model files. Sets up the complete directory tree for a SWAN modeling project, creating folders for each simulation case and initializing bathymetry and input files for nested grid computations. Parameters ---------- params : dict Model configuration parameters containing: - directory : str Root directory path for the project data : pd.DataFrame Time series with boundary conditions, indexed by timestamps. Each row represents one simulation case. global_db : xr.Dataset Global (coarse) grid dataset containing: - depth : xr.DataArray Bathymetry on global grid (m) local_db : xr.Dataset Local (fine) grid dataset containing: - depth : xr.DataArray Bathymetry on local nested grid (m) Returns ------- None Creates directory structure: - params['directory']/: Root project folder - params['directory']/####/: Case folders (0001, 0002, ...) Each case folder contains: - ####_global.dat: Global grid bathymetry - ####_local.dat: Local grid bathymetry - swaninit: SWAN initialization file - input_global_####.swn: SWAN input file Notes ----- The function performs the following operations: 1. Creates root project directory (if it doesn't exist) 2. Loops through all time steps in data 3. For each case: - Creates numbered subdirectory (####) - Writes global and local bathymetry files - Generates SWAN input files for nested run Case numbering is 1-indexed with zero-padding to 4 digits (0001-9999). The nested flag in write_swan ensures boundary condition files are generated for downscaling from global to local grid. Examples -------- >>> import pandas as pd >>> import xarray as xr >>> import numpy as np >>> >>> # Create sample datasets >>> data = pd.DataFrame({ ... 'Hs': [2.0, 2.5, 3.0], ... 'Tp': [8.0, 9.0, 10.0], ... 'DirM': [45, 60, 75] ... }, index=pd.date_range('2024-01-01', periods=3, freq='6h')) >>> >>> global_db = xr.Dataset({ ... 'depth': (['y', 'x'], np.random.rand(50, 100) * 10) ... }) >>> local_db = xr.Dataset({ ... 'depth': (['y', 'x'], np.random.rand(100, 200) * 10) ... }) >>> >>> params = {'directory': './swan_project'} >>> directory(params, data, global_db, local_db) >>> # Creates: ./swan_project/0001/, ./swan_project/0002/, ./swan_project/0003/ """ os.makedirs(params["directory"], exist_ok=True) for ind_, time in enumerate(data.index): case_id = str(ind_ + 1).zfill(4) os.makedirs(params["directory"] + "/" + case_id, exist_ok=True) save.to_txt( params["directory"] + "/" + case_id + "/" + case_id + "_global.dat", global_db["depth"].data[:, :], format="%9.3f", ) save.to_txt( params["directory"] + "/" + case_id + "/" + case_id + "_local.dat", local_db["depth"].data[:, :], format="%9.3f", ) write_swan(ind_, time, case_id, data, params, mesh="global", nested=True) return