Source code for geophires_monte_carlo

import json
import os
from enum import Enum
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Optional

from geophires_monte_carlo import MC_GeoPHIRES3
from geophires_monte_carlo.common import _get_logger


[docs] class SimulationProgram(str, Enum): GEOPHIRES = 'GEOPHIRES', 'geophires_x/GEOPHIRESv3.py' HIP_RA = 'HIP-RA', 'hip_ra/HIP_RA.py' HIP_RA_X = 'HIP-RA-X', 'hip_ra_x/hip_ra_x.py' def __new__(cls, *args, **kwds): obj = str.__new__(cls) obj._value_ = args[0] return obj # ignore the first param since it's already set by __new__ def __init__(self, _: str, code_file_path: str): self._code_file_path: Path = Path(Path(os.path.abspath(__file__)).parent.parent, code_file_path) # this makes sure that the description is read-only @property def code_file_path(self) -> Path: return self._code_file_path
class MonteCarloRequest: def __init__( self, simulation_program: SimulationProgram, input_file: Path, monte_carlo_settings_file: Path, output_file: Optional[Path] = None, ): self._simulation_program: SimulationProgram = simulation_program if not input_file.is_absolute(): raise ValueError(f'Input file path ({input_file}) must be absolute') self.input_file = input_file if not monte_carlo_settings_file.is_absolute(): raise ValueError(f'Monte Carlo settings file path ({monte_carlo_settings_file}) must be absolute') self.monte_carlo_settings_file = monte_carlo_settings_file if output_file is not None: self.output_file: Path = output_file else: self._temp_output_dir: TemporaryDirectory = TemporaryDirectory(prefix='geophires_monte_carlo-') self.output_file: Path = Path( self._temp_output_dir.name, f'MC_{self._simulation_program.name}_Result.txt' ).absolute() if not self.output_file.is_absolute(): raise ValueError(f'Output file path ({output_file}) must be absolute') @property def code_file_path(self) -> Path: return self._simulation_program.code_file_path def __del__(self): if hasattr(self, '_temp_output_dir'): self._temp_output_dir.cleanup() class MonteCarloResult: def __init__(self, request: MonteCarloRequest): self._request: MonteCarloRequest = request with open(self._request.input_file) as request_input_file, open( self._request.monte_carlo_settings_file ) as mc_settings_file, open(self.json_output_file_path) as json_file: self._result: dict = { 'input': { 'input_file_content': request_input_file.read(), 'monte_carlo_settings_file_content': mc_settings_file.read(), }, 'output': json.loads(json_file.read()), } @property def output_file_path(self) -> Path: return self._request.output_file @property def json_output_file_path(self) -> Path: return self.output_file_path.with_suffix('.json') @property def result(self) -> dict: """TODO define properties in result (instead of unspecified JSON schema)""" return self._result class GeophiresMonteCarloClient: def __init__(self): self._logger = _get_logger() def get_monte_carlo_result(self, request: MonteCarloRequest) -> MonteCarloResult: stash_cwd = Path.cwd() args = [str(request.code_file_path), str(request.input_file), str(request.monte_carlo_settings_file)] if request.output_file is not None: args.append(str(request.output_file)) try: MC_GeoPHIRES3.main(command_line_args=args) except Exception as e: raise RuntimeError(f'Monte Carlo encountered an exception: {e!s}') from e except SystemExit: raise RuntimeError('Monte Carlo exited without giving a reason') from None finally: # Undo MC internal global settings changes os.chdir(stash_cwd) return MonteCarloResult(request)