Source code for particle_tracking_manager.config_misc

"""Defines ParticleTrackingState and SetupOutputFiles."""

# Standard library imports
import datetime
import logging
import pathlib

from os import PathLike
from typing import Any, Mapping, Self

# Third-party imports
from pydantic import BaseModel, Field, computed_field, field_validator, model_validator

# Local imports
from .config_the_manager import OutputFormatEnum, TheManagerConfig


OUTPUT_FORMAT_SUFFIX: Mapping[OutputFormatEnum, str] = {
    OutputFormatEnum.netcdf: ".nc",
    OutputFormatEnum.parquet: ".parquet",  # can't be read back in by OpenDrift which is necessary for plots in PTM
    OutputFormatEnum.both: ".nc",  # first netcdf, then additionally output parquet at the end
}

logger = logging.getLogger()


[docs] class ParticleTrackingState(BaseModel): """Track simulation state.""" has_run_setup: bool = False # this may not be required for all models has_added_reader: bool = False has_run_seeding: bool = False has_run: bool = False
[docs] def generate_default_output_file() -> str: """Generate a default output file name based on the current date and time.""" return f"output-results_{datetime.datetime.now():%Y-%m-%dT%H%M%SZ}"
[docs] class SetupOutputFiles(BaseModel): """Handle all changes/work on output files. This class runs first thing. Then logger setup. """ output_file: PathLike[str] | None = Field( TheManagerConfig.model_json_schema()["properties"]["output_file"]["default"] ) output_format: OutputFormatEnum = Field( TheManagerConfig.model_json_schema()["properties"]["output_format"]["default"] ) model_config = {"validate_default": True}
[docs] @field_validator("output_file", mode="after") def assign_output_file_if_needed(value: Any) -> str: """Assign a default output file name if not provided.""" if value is None: return generate_default_output_file() return value
[docs] @model_validator(mode="after") def set_output_file_extension(self) -> Self: """Set the appropriate file extension based on the output format.""" assert self.output_file is not None if self.output_format not in OUTPUT_FORMAT_SUFFIX: raise ValueError(f"output_format {self.output_format} not recognized.") self.output_file = pathlib.Path(self.output_file).with_suffix( OUTPUT_FORMAT_SUFFIX[self.output_format] ) return self
@computed_field def logfile_name(self) -> str: """Generate a log file name based on the output file name.""" assert self.output_file is not None return str(pathlib.Path(self.output_file).with_suffix(".log"))