{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Config.py Reference\n", "\n", "Every JAX-ALFA simulation is controlled by a single file: **`Config.py`**, located in the run directory. \n", "The file is plain Python — assign values to the variables listed below, and JAX-ALFA picks them up automatically.\n", "\n", "```\n", "export JAXALFA_RUNDIR=/path/to/run_directory\n", "python -m src.Main\n", "```\n", "\n", "Parameters are grouped below in the same order they appear in `Config.py`." ], "id": "5f1ed3ef012c7c0e" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 1. Platform\n", "\n", "| Parameter | Values | Default | Description |\n", "|---|---|---|---|\n", "| `use_double_precision` | `True` / `False` | `False` | Enable 64-bit (double) floating-point arithmetic throughout |\n", "| `optGPU` | `0` / `1` | — | `0` = CPU only; `1` = use GPU |\n", "| `GPU_ID` | integer ≥ 0 | `0` | Which GPU to use on a multi-GPU machine (0-indexed) |\n", "\n", "**Recommendations**\n", "- Use `use_double_precision = True` for production runs and benchmarking. \n", " Single precision (`False`) can be used for exploratory runs and is ~2× faster on consumer GPUs,\n", " but may accumulate rounding error in long integrations or fine grids.\n", "- On a SLURM cluster, `CUDA_VISIBLE_DEVICES` is set by the scheduler; `GPU_ID` is only used for interactive/local runs.\n", "\n", "```python\n", "# Recommended production settings\n", "use_double_precision = True\n", "optGPU = 1\n", "GPU_ID = 0\n", "```" ], "id": "2cc5122672ba575e" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 2. Domain\n", "\n", "| Parameter | Unit | Description |\n", "|---|---|---|\n", "| `l_x` | m | Domain length in x (streamwise) |\n", "| `l_y` | m | Domain length in y (spanwise) |\n", "| `l_z` | m | Domain height in z |\n", "| `nx` | — | Number of grid points in x |\n", "| `ny` | — | Number of grid points in y |\n", "| `nz` | — | Number of grid points in z |\n", "\n", "**Recommendations**\n", "- Keep `nx = ny` and use powers of 2 (64, 128, 256, 384, 512) for maximum FFT efficiency. \n", " Non-powers-of-2 work but are slower.\n", "- The horizontal grid spacing is `dx = l_x / nx`. \n", " For standard ABL simulations, aim for `dx ≈ dy ≈ dz` (isotropic grid).\n", "- `l_z` should comfortably contain the full boundary-layer depth plus a damping layer above.\n", "\n", "```python\n", "# Example: 5 km × 5 km × 2 km domain at 128³\n", "l_x, l_y, l_z = 5000, 5000, 2000\n", "nx, ny, nz = 128, 128, 128\n", "```" ], "id": "3f735dbefc5dc959" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 3. Time Integration\n", "\n", "| Parameter | Unit | Default | Description |\n", "|---|---|---|-----------------------------------------------------------------------------------|\n", "| `istep` | — | `1` | Starting step number; set > 1 only for restart runs (not yet implemented) |\n", "| `dt` | s | — | Time-step size |\n", "| `SimTime` | s | — | Total physical simulation time |\n", "| `Ugal` | m/s | — | Galilean transformation velocity (subtracted from the mean wind before advancing) |\n", "\n", "**Recommendations**\n", "- Choose `dt` so the CFL number `U_max * dt / dx < 0.2 (conservative).\n", "- Set `Ugal` to the mean wind speed (e.g., `Ug2`) to reduce the advective CFL and allow a larger `dt`.\n", "- For a restart run, set `istep` to the last saved step number from the previous run.\n", "\n", "```python\n", "istep = 1 # fresh start\n", "dt = 0.5 # s — adjust for your CFL\n", "SimTime = 36000 # s (10 hours)\n", "Ugal = 8 # m/s — match approximate mean wind\n", "```" ], "id": "c7ce7c067b95d32d" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 4. Surface Boundary Conditions\n", "\n", "| Parameter | Values / Unit | Default | Description |\n", "|---|---|---|---------------------------------------------------------------------------------------------------------|\n", "| `optSurfFlux` | `0` / `1` | — | `0` = horizontally homogeneous boundary condition; `1` = heterogeneous (spatially varying) |\n", "| `optSurfBC` | `0` / `1` / `2` | `0` | `0` = constant heat flux; `1` = time-varying flux (file); `2` = time-varying surface temperature (file) |\n", "| `z0m` | m | — | Aerodynamic roughness length for momentum |\n", "| `z0T` | m | — | Scalar (thermal) roughness length |\n", "| `zTemperature` | m | `0.0` | Screen-height for heat-flux denominator; `0` = use `z0T` |\n", "| `SensibleHeatFlux` | K m/s | — | Constant surface heat flux; used only when `optSurfBC = 0` |\n", "| `SurfaceBCFile` | path | `'input/SurfaceBC.npz'` | Path to time-varying surface BC file (relative to run directory) |\n", "\n", "**Recommendations**\n", "- For most idealized cases, `optSurfFlux = 0` and `optSurfBC = 0` (constant, homogeneous flux).\n", "- For real-case simulations (e.g., GABLS3, Wangara), use `optSurfBC = 2` with prescribed surface temperatures.\n", "- `zTemperature > 0` is needed when the observational temperature is at a screen height (e.g., 1.2 m for Wangara, 0.25 m for GABLS3) rather than at `z0T`.\n", "- Positive `SensibleHeatFlux` = upward heat flux (unstable/convective); negative = downward (stable).\n", "\n", "```python\n", "# Idealized stable BL (constant cooling)\n", "optSurfFlux = 0\n", "optSurfBC = 0\n", "z0m, z0T = 0.1, 0.1\n", "SensibleHeatFlux = -0.03 # K m/s downward\n", "\n", "# Real-case with observed surface temperatures (GABLS3-style)\n", "optSurfBC = 2\n", "zTemperature = 0.25 # m\n", "SurfaceBCFile = 'input/SurfaceBC.npz'\n", "```" ], "id": "7f5e70c2e712c491" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 5. Forcing\n", "\n", "| Parameter | Values / Unit | Default | Description |\n", "|---|---|---|---|\n", "| `optGeoWind` | `0` / `1` | `0` | `0` = constant `Ug2`, `Vg2`; `1` = time + height varying (from file) |\n", "| `Ug2` | m/s | — | Geostrophic wind component in x |\n", "| `Vg2` | m/s | — | Geostrophic wind component in y |\n", "| `GeoWindFile` | path | `'input/GeoWind.npz'` | Path to time/height-varying geostrophic wind file |\n", "| `f_coriolis` | 1/s | — | Coriolis parameter (typically `1e-4` at mid-latitudes) |\n", "| `inversion` | K/m | — | Potential temperature lapse rate above domain top (free-atmosphere stratification) |\n", "| `optBuoyancy` | `0` / `1` | — | `0` = buoyancy uses fixed reference temperature `T_0`; `1` = uses local virtual potential temperature |\n", "| `T_0` | K | — | Reference temperature for buoyancy (used when `optBuoyancy = 0`, and always for non-dimensionalisation) |\n", "\n", "**Recommendations**\n", "- Use `optBuoyancy = 1` for all simulations. `optBuoyancy = 0` is rarely used.\n", "- Set `inversion > 0` to cap convective boundary layers.\n", "\n", "```python\n", "optGeoWind = 0\n", "Ug2, Vg2 = 8.0, 0.0 # m/s\n", "f_coriolis = 1.0e-4 # 1/s\n", "inversion = 3.0 / 1000 # 3 K/km\n", "optBuoyancy = 1\n", "T_0 = 300.0 # K\n", "```" ], "id": "af972ee5e199442c" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n## 6. Subgrid-Scale (SGS) Model\n\n| Parameter | Values | Default | Description |\n|---|---|---|---|\n| `optSgs` | `1` – `4` | — | SGS model selection (see table below) |\n| `dynamicSGS_call_time` | integer ≥ 1 | — | Recompute dynamic SGS coefficients every N steps |\n| `FGR` | `1` or integer ≥ 2 | — | Filter-to-grid ratio: `1` = implicit filtering + dealiasing (standard); `≥ 2` = explicit filtering, no dealiasing |\n| `Cs2` | float | — | Initial `Cs²` for SM models (used before first dynamic update) |\n| `Cwl` | float | — | Initial `C_WL` for WL models (used before first dynamic update) |\n| `Cs2PrRatio` | float | — | Initial `Cs² / Prt` for SM models |\n| `CwlPrRatio` | float | — | Initial `C_WL / Prt` for WL models |\n\n### SGS model options\n\n| `optSgs` | Model | Best for |\n|---|---|---|\n| `1` | LASDD-SM (Locally-Averaged Scale-Dependent Dynamic Smagorinsky) | General ABL; most thoroughly validated |\n| `2` | LASDD-WL (Wong–Lilly variant) | Alternative to LASDD-SM |\n| `3` | LAD-SM (Locally-Averaged Dynamic Smagorinsky) | Simpler dynamic procedure; faster per step |\n| `4` | LAD-WL | Wong–Lilly variant of LAD |\n\n**Recommendations**\n- `optSgs = 1` (LASDD-SM) is the recommended default for all stable and neutral BL simulations.\n- `FGR = 1` (implicit filtering) is standard. Dealiasing is activated automatically.\n Use `FGR = 2` only if you need explicit filtering (dealiasing is not needed).\n- `dynamicSGS_call_time = 1` (every step) is standard. Increase to 5–10 for faster runs where the SGS field evolves slowly.\n- The initial values `Cs2 = 0.01` and `Cwl = 0.01` (`0.1²`) are reasonable warm-start guesses; they are replaced after the first dynamic update.\n\n```python\noptSgs = 1 # LASDD-SM\ndynamicSGS_call_time = 1\nFGR = 1\nCs2 = 0.1 ** 2\nCwl = 0.1 ** 2\nCs2PrRatio = Cs2 / 1.0\nCwlPrRatio = Cwl / 1.0\n```" ], "id": "74a168de9b60880b" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 7. Rayleigh Damping Layer\n", "\n", "| Parameter | Values / Unit | Default | Description |\n", "|---|---|---|---|\n", "| `optDamping` | `0` / `1` | — | `1` = activate Rayleigh damping above `z_damping` |\n", "| `z_damping` | m | — | Height above which damping starts |\n", "| `RelaxTime` | s | — | Damping relaxation time scale (larger = weaker damping) |\n", "\n", "**Recommendations**\n", "- Always enable the damping layer (`optDamping = 1`) to absorb upward-propagating disturbances and prevent artificial reflections from the rigid lid.\n", "- Set `z_damping` to roughly the top of the boundary layer (or ~60–70% of `l_z`), leaving at least 20–30% of the domain depth as the absorbing sponge.\n", "\n", "```python\n", "optDamping = 1\n", "z_damping = 1500 # m — top of the ABL\n", "RelaxTime = 300 # s\n", "```" ], "id": "4b0f7bf4e91b7063" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 8. Statistics and Output\n", "\n", "| Parameter | Unit | Description |\n", "|---|---|---|\n", "| `SampleInterval_sec` | s | Collect one instantaneous horizontal-average sample every N seconds |\n", "| `OutputInterval_sec` | s | Write time-averaged statistics to disk every N seconds |\n", "| `Output3DInterval_sec` | s | Write full 3-D field snapshots every N seconds |\n", "\n", "**Recommendations**\n", "- `OutputInterval_sec` should be a multiple of `SampleInterval_sec`; averages accumulate from individual samples.\n", "- 3-D field output is expensive in both compute and storage. For long runs, set `Output3DInterval_sec = SimTime` to write only at the end, or to a multiple of the boundary-layer turnover time (~`l_z / u_star`).\n", "- Typical values for a 10-hour ABL run: `SampleInterval_sec = 15`, `OutputInterval_sec = 300`.\n", "\n", "```python\n", "SampleInterval_sec = 15.0 # s\n", "OutputInterval_sec = 300.0 # s\n", "Output3DInterval_sec = SimTime # write once at end\n", "```" ], "id": "f8e33b443a773541" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 9. Large-Scale Advection Forcing\n", "\n", "| Parameter | Values | Default | Description |\n", "|---|---|---|---|\n", "| `optAdvection` | `0` / `1` | `0` | `0` = no mesoscale advection; `1` = time + height varying (from file) |\n", "| `AdvectionFile` | path | `'input/AdvForcing.npz'` | Path to advection forcing file |\n", "\n", "**Recommendations**\n", "- Most idealized cases need no advection forcing (`optAdvection = 0`).\n", "- Enable for real-case simulations where mesoscale horizontal advection of temperature or moisture is significant (e.g., GABLS3, Wangara diurnal cycle).\n", "\n", "```python\n", "optAdvection = 0 # most idealized cases\n", "\n", "optAdvection = 1 # real-case with advection\n", "AdvectionFile = 'input/AdvForcing.npz'\n", "```" ], "id": "96aab796b3af2b5d" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 10. Moisture\n", "\n", "| Parameter | Values / Unit | Default | Description |\n", "|---|---|---|---|\n", "| `optMoisture` | `0` / `1` | `0` | `0` = dry run; `1` = prognostic specific humidity Q |\n", "| `zMoisture` | m | `0.0` | Screen height for moisture-flux denominator; `0` = use `z0T` |\n", "| `MoistureFlux` | kg/kg m/s | `0.0` | Constant surface moisture flux; used when `optMoistureSurfBC = 0` |\n", "| `optMoistureSurfBC` | `0` / `1` / `2` | `0` | `0` = constant flux; `1` = time-varying flux (file); `2` = time-varying surface Q (file) |\n", "| `MoistureSurfaceBCFile` | path | `'input/MoistureSurfaceBC.npz'` | Path to time-varying moisture BC file |\n", "| `q_inversion` | kg/kg/m | `0.0` | Specific humidity lapse rate above domain top; `0` = zero gradient |\n", "\n", "**Recommendations**\n", "- Most ABL benchmarks (GABLS1, GABLS2, NBL_A94) are dry; leave `optMoisture = 0`.\n", "- Enable moisture for the diurnal cycle (Wangara) or when dew formation matters (GABLS3).\n", "- `zMoisture` follows the same logic as `zTemperature`: set to the screen height of the moisture observation when `optMoistureSurfBC = 2`.\n", "\n", "```python\n", "# Dry run (default for most idealized cases)\n", "optMoisture = 0\n", "\n", "# Moist real-case\n", "optMoisture = 1\n", "zMoisture = 0.25\n", "optMoistureSurfBC = 2\n", "MoistureSurfaceBCFile = 'input/MoistureSurfaceBC.npz'\n", "```" ], "id": "49225e801318e30" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## 11. Pressure Solver\n", "\n", "| Parameter | Values | Default | Description |\n", "|---|---|---|---|\n", "| `optPressureSolver` | `0` / `1` | `0` | `0` = LU (dense matrix); `1` = Thomas tridiagonal algorithm (recommended) |\n", "\n", "**Recommendations**\n", "- Always use `optPressureSolver = 1` (Thomas algorithm). It is ~2× faster overall on a 128³ double-precision run because it exploits the tridiagonal structure of the pressure Poisson system instead of applying a dense O(N³) LU solve per horizontal wavenumber pair.\n", "- The Thomas solver produces bit-for-bit identical results to the LU solver for all non-singular modes.\n", "- `optPressureSolver = 0` is retained only for regression testing and backward compatibility.\n", "\n", "```python\n", "optPressureSolver = 1 # Thomas — use this in all production runs\n", "```" ], "id": "b9d244b9dec164b" }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Quick-Reference Summary\n", "\n", "The table below shows the recommended values for a typical production run.\n", "\n", "| Parameter | Recommended | Note |\n", "|---|---|---|\n", "| `use_double_precision` | `True` | Higher accuracy; slower on consumer GPUs |\n", "| `optGPU` | `1` | Use GPU |\n", "| `optSurfFlux` | `0` | Homogeneous surface for idealized runs |\n", "| `optSurfBC` | `0` or `2` | `0` for constant flux; `2` for observed surface temperature |\n", "| `optBuoyancy` | `1` | Virtual potential temperature buoyancy |\n", "| `optSgs` | `1` | LASDD-SM — best validated SGS model |\n", "| `FGR` | `1` | Implicit filtering |\n", "| `dynamicSGS_call_time` | `1` | Every step for accuracy |\n", "| `optDamping` | `1` | Always enable the sponge layer |\n", "| `optAdvection` | `0` | Unless real-case forcing is needed |\n", "| `optMoisture` | `0` | Dry unless moisture is a key variable |\n", "| `optPressureSolver` | `1` | Thomas algorithm — 2× faster |\n", "\n", "---\n", "*Generated for JAX-ALFA — see the [GitHub repository](https://github.com/Sukantabasu/jax-alfa) for source code and issue tracking.*" ], "id": "b1727fc2fd63d560" } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.10.0" } }, "nbformat": 4, "nbformat_minor": 5 }