Source code for src.spyice.parameters.user_input

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum

from omegaconf import DictConfig
from .constants import Constants
from .real_constants import RealConstants
from .debug_constants import DebugConstants
from .algae_constants import nutrient_cn_dsi_ice, nutrient_cn_dsi_water, carbon_cc_ice_initial, carbon_cc_water_initial
from spyice.utils.config_sort import read_omegaconfig
from spyice.utils.create_directory import create_output_directory
from spyice.utils.initial_userinput import (
    calculate_initial_melt_temperature,)

# TODO: Add docstrings to the functions and classes
# TODO: DEBUG this script for new enum classes.
# TODO: const parameters and varied parameters difference show
# TODO: liquidus relationship status is always "normal" in script update physical values in function calculate_melting_temperature_from_salinity

def _dt_stability_validator(dz: float, dt: float) -> None:
    """Validates the time-step (dt) based on the Fourier stability criteria.

    Args:
        dz (float): The spatial step size.
        dt (float): The time-step to be validated.
    Raises:
        ValueError: If the time-step does not follow the Fourier stability criteria.
    Returns:
        None
    """

    fourier_criteria = int(121 * (dz / 0.01) ** 2)
    if dt > fourier_criteria:
        raise ValueError(
            "Time-step not following Fourier stability criteria, choose dt < "
            + str(fourier_criteria)
        )


[docs] def fourier_number_timestep(constants): """Calculates the Fourier number for the given timestep. Args: constants (object): An object containing the required constants. Returns: float: The calculated Fourier number. """ return 0.5 * constants.rho_br * constants.c_br * constants.dz**2 / constants.k_br
[docs] class LiquidusRelation(str, Enum): """Represents the liquidus relation type. Attributes: NORMAL (str): Normal liquidus relation. FREZCHEM (str): Frezchem liquidus relation. """ NORMAL = "Normal" FREZCHEM = "Frezchem"
[docs] class BoundaryConditionType(str, Enum): """Represents the type of boundary condition. Attributes: NEUMANN (str): Neumann boundary condition. DIRICHLET (str): Dirichlet boundary condition. """ NEUMANN = "Neumann" DIRICHLET = "Dirichlet"
[docs] class InitialSalinity(str, Enum): """Represents the type of initial salinity. User can add more salinity option SX where X is a number. The salinity is in parts per thousand (ppt). Attributes: S34 (str): Initial salinity of 34 ppt. S0 (str): Initial salinity of 0 ppt. S1 (str): Initial salinity of 1 ppt. S2 (str): Initial salinity of 2 ppt. S3 (str): Initial salinity of 3 ppt. S_LINEAR (str): Linear initial salinity. """ S34 = "S34" S0 = "S0" S1 = "S1" S2 = "S2" S3 = "S3" S_LINEAR = "S_linear"
[docs] class InitialTemperature(str, Enum): """Represents the type of initial temperature. Attributes: T_Stefan (str): Initial temperature based on Stefan condition. T271p25 (str): Initial temperature of 271.25 K. T250 (str): Initial temperature of 250 K. T_MELT (str): Initial temperature at which the material melts. T_S (str): Initial temperature based on salinity. """ T_STEFAN = "T_Stefan" T271p25 = "T271.25" T250 = "T250" T_MELT = "Tm_w" T_S = "T(S)"
[docs] class InitialMeltTemperature(str, Enum): """Represents the type of initial melt temperature. Attributes: T_MELT (str): Initial melt temperature. T_S (str): Initial temperature based on salinity. """ ONEPHASE = "onephase" FREZCHEM = "Frezchem" TWOPHASE = "twophase"
[docs] class InitialLiquidFraction(str, Enum): """Represents the type of initial liquid fraction. Attributes: P0 (str): Initial liquid fraction of 0. P1 (str): Initial liquid fraction of 1. P_Stefan (str): Initial liquid fraction based on Stefan condition. PX (str): Initial liquid fraction based on a custom profile. """ P0 = "P0" P1 = "P1" P_Stefan = "P_Stefan" PX = "PX" # where X is a number
[docs] class FileNameSuffix(str, Enum): """Represents the suffix for the output file name. Attributes: NON_CONST_DENS_MUSHFIX (str): Non-constant density mush-fix. NON_CONST_DENS (str): Non-constant density. CONST_DENS (str): Constant density. """ NON_CONST_DENS_MUSHFIX = "nonconst_dens-mushfix" NON_CONST_DENS = "nonconst_dens" CONST_DENS = "const_dens"
[docs] class TopTemperatureType(str, Enum): """Represents the type of top temperature condition. Attributes: STEFAN (str): Stefan condition. DIRICHLET (str): Dirichlet condition. """ STEFAN = "Stefan" DIRICHLET = "Dirichlet"
[docs] @dataclass class UserInput: """Represents the user input parameters for the model. Attributes: constants (RealConstants | DebugConstants): The type of constants to use. max_iterations (int): The maximum number of iterations. is_stefan (bool): Flag indicating whether Stefan condition is applied. is_buffo (bool): Flag indicating whether Buffo condition is applied. liquidus_relation_type (str): The type of liquidus relation to use. grid_resolution_dz (float): The grid resolution in the z-direction. boundary_condition_type (str): The type of boundary condition to use. temperature_tolerance (float): The temperature tolerance. salinity_tolerance (float): The salinity tolerance. liquid_fraction_tolerance (float): The liquid fraction tolerance. initial_temperature (str): The initial temperature profile. initial_salinity (str): The initial salinity profile. initial_liquid_fraction (str): The initial liquid fraction profile. output_suffix (str): The suffix to be added to the output files. temperature_top_type (str): The type of temperature condition at the top boundary. phase_type (int): The type of phase to consider. grid_timestep_dt (float): The grid timestep. dir_output_name (str): The name of the output directory. critical_liquid_fraction (float): The critical liquid fraction. boundary_salinity (float): The boundary salinity (automatically calculated). temperature_melt (float): The temperature at which the material melts (automatically calculated). boundary_top_temperature (float): The temperature at the top boundary (automatically calculated). geometry_type (int): The type of geometry. counter_limit (int): The counter limit. Methods: __post_init__(): Performs post-initialization tasks. """ # grid_timestep_dt=config_data.time_step, # initial_salinity=config_data.initial_salinity, # dir_output_name=output_dir, # max_iterations=config_data.max_iterations # self.constants_type = self.read_omegaconfig("constants") # self.time_step = self.read_omegaconfig("dt") # self.initial_salinity = self.read_omegaconfig("S_IC") # self.max_iterations = self.read_omegaconfig("iter_max") # self.is_salinity_equation = self.read_omegaconfig("salinity") ... # --- Constants and Config --- constants: RealConstants | DebugConstants = Constants.REAL.value config_data: DictConfig = field(default_factory=dict) # --- Model Switches --- is_stefan: bool = True is_buffo: bool = False is_voller: bool = False is_salinity_equation: bool = False is_diffusiononly_equation: bool = True is_algae_equation: bool = False is_radiation_equation: bool = False algae_model_BAL_type: str = "all" # or "all" or "single" # --- Iteration and Limits --- max_iterations: int = 1500 counter_limit: int = 100000 # --- Grid and Time Step --- grid_resolution_dz: float = 0.01 grid_timestep_dt: float = 47 # in seconds # --- Boundary and Geometry --- boundary_condition_type: BoundaryConditionType = BoundaryConditionType.DIRICHLET.value geometry_type: int = field(init=False) boundary_salinity: float = 34.0 boundary_top_temperature: float = 265.0 temperature_top_type: TopTemperatureType = TopTemperatureType.STEFAN.value # --- Tolerances --- temperature_tolerance: float = 0.01 salinity_tolerance: float = 0.01 liquid_fraction_tolerance: float = 0.01 # --- Initial Conditions --- initial_temperature: InitialTemperature = InitialTemperature.T_S.value initial_salinity: InitialSalinity = InitialSalinity.S34.value initial_liquid_fraction: InitialLiquidFraction = InitialLiquidFraction.P1.value critical_liquid_fraction: float = 0.1 temperature_melt: float = field(init=False) # --- Phase and Liquidus --- phase_type: int = 1 liquidus_relation_type: LiquidusRelation = LiquidusRelation.NORMAL.value # --- Output and Directory --- output_suffix: FileNameSuffix = FileNameSuffix.NON_CONST_DENS_MUSHFIX.value dir_output_name_hydra: str = ( "Temperature_{S_IC}_{bc_condition}_{dz}_{dt}_{iter_max}_{cap_dens}" ) dir_output_name: str = ( "Temperature_{S_IC}_{bc_condition}_{dz}_{dt}_{iter_max}_{cap_dens}" ) # --- Algae Model Parameters --- nutrient_cn_dsi_water: float = nutrient_cn_dsi_water nutrient_cn_dsi_ice: float = nutrient_cn_dsi_ice carbon_cc_ice_initial: float = carbon_cc_ice_initial carbon_cc_water_initial: float = carbon_cc_water_initial
[docs] def __post_init__(self): _dt_stability_validator(self.grid_resolution_dz, self.grid_timestep_dt) if isinstance(self.constants, RealConstants): # melt temperature affects the liquid relation: Frezchem or Normal in src/update_physical_values.py script method = InitialMeltTemperature.ONEPHASE.value self.temperature_melt = calculate_initial_melt_temperature(self.boundary_salinity, method) self.geometry_type = 2 if self.config_data: self.grid_timestep_dt = read_omegaconfig(self.config_data, "dt") # self.initial_salinity = read_omegaconfig(self.config_data, "S_IC") self.max_iterations = read_omegaconfig(self.config_data, "iter_max") self.grid_resolution_dz = read_omegaconfig(self.config_data, "dz") self.initial_salinity = self.config_data.get("ICBC", {}).get("S_IC", "default") self.boundary_top_temperature = self.config_data.get("ICBC", {}).get("T_BC", "default") self.is_diffusiononly_equation = self.config_data.get("model", {}).get("is_diffusiononly_equation", "default") self.is_salinity_equation= self.config_data.get("model", {}).get("is_salinity_equation", "default") self.is_algae_equation = self.config_data.get("model", {}).get("is_algae_equation", "default") self.is_radiation_equation = self.config_data.get("model", {}).get("is_radiation_equation", "default") self.algae_model_BAL_type = self.config_data.get("model", {}).get("algae_model_BAL_type", "default") self.dir_output_name = create_output_directory( self.dir_output_name_hydra, self.initial_salinity, self.boundary_condition_type, self.grid_resolution_dz, self.grid_timestep_dt, self.max_iterations, self.output_suffix, ) elif isinstance(self.constants, DebugConstants): self.boundary_salinity = 1.0 self.boundary_top_temperature = -1.0 self.temperature_melt = 0.0 self.geometry_type = 1