Skip to content

Commit

Permalink
move functions from NEMS ADCIRC into ADCIRC submodule
Browse files Browse the repository at this point in the history
  • Loading branch information
zacharyburnett committed Apr 7, 2021
1 parent 970b842 commit 4421748
Show file tree
Hide file tree
Showing 15 changed files with 652 additions and 674 deletions.
4 changes: 3 additions & 1 deletion coupledmodeldriver/configure/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
from .base import ModelDriverJSON, SlurmJSON
from .base import ModelDriverJSON, NEMSJSON, SlurmJSON
from .forcings import *
from .models import *
79 changes: 78 additions & 1 deletion coupledmodeldriver/configure/base.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from abc import ABC, abstractmethod
from datetime import timedelta
from datetime import datetime, timedelta
import json
from os import PathLike
from pathlib import Path
from typing import Any

from adcircpy.server import SlurmConfig
from nemspy import ModelingSystem
from nemspy.model import ModelEntry

from ..platforms import Platform
Expand Down Expand Up @@ -161,6 +162,82 @@ def to_file(self, filename: PathLike = None, overwrite: bool = False):
LOGGER.debug(f'skipping existing file "{filename}"')


class NEMSJSON(ConfigurationJSON):
name = 'nems'
default_filename = f'configure_nems.json'
field_types = {
'executable_path': Path,
'modeled_start_time': datetime,
'modeled_end_time': datetime,
'interval': timedelta,
'models': [ModelEntry],
'connections': [[str]],
'mediations': [str],
'sequence': [str],
}

def __init__(
self,
executable_path: PathLike,
modeled_start_time: datetime,
modeled_end_time: datetime,
interval: timedelta = None,
models: [ModelEntry] = None,
connections: [[str]] = None,
mediations: [[str]] = None,
sequence: [str] = None,
**kwargs,
):
if 'fields' not in kwargs:
kwargs['fields'] = {}
kwargs['fields'].update(NEMSJSON.field_types)

ConfigurationJSON.__init__(self, **kwargs)

self['executable_path'] = executable_path
self['modeled_start_time'] = modeled_start_time
self['modeled_end_time'] = modeled_end_time
self['interval'] = interval
self['models'] = models
self['connections'] = connections
self['mediations'] = mediations
self['sequence'] = sequence

@property
def nemspy_modeling_system(self) -> ModelingSystem:
modeling_system = ModelingSystem(
start_time=self['modeled_start_time'],
end_time=self['modeled_end_time'],
interval=self['interval'],
**{model.model_type.value.lower(): model for model in self['models']},
)
for connection in self['connections']:
modeling_system.connect(*connection)
for mediation in self['mediations']:
modeling_system.mediate(*mediation)

modeling_system.sequence = self['sequence']

return modeling_system

def to_nemspy(self) -> ModelingSystem:
return self.nemspy_modeling_system

@classmethod
def from_nemspy(cls, modeling_system: ModelingSystem, executable_path: PathLike = None):
if executable_path is None:
executable_path = 'NEMS.x'
return cls(
executable_path=executable_path,
modeled_start_time=modeling_system.start_time,
modeled_end_time=modeling_system.end_time,
interval=modeling_system.interval,
models=modeling_system.models,
connections=modeling_system.connections,
sequence=modeling_system.sequence,
)


class NEMSCapJSON(ConfigurationJSON, ABC):
field_types = {
'processors': int,
Expand Down
1 change: 0 additions & 1 deletion coupledmodeldriver/generate/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from .adcirc import *
from .nems import *
6 changes: 3 additions & 3 deletions coupledmodeldriver/generate/adcirc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .configure import ADCIRCRunConfiguration
from .generate import generate_adcirc_configuration
from .script import ADCIRCGenerationScript
from .configure import ADCIRCRunConfiguration, NEMSADCIRCRunConfiguration
from .generate import generate_adcirc_configuration, generate_nems_adcirc_configuration
from .script import ADCIRCGenerationScript, NEMSADCIRCGenerationScript
144 changes: 144 additions & 0 deletions coupledmodeldriver/generate/adcirc/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
from pathlib import Path

from adcircpy import AdcircMesh, AdcircRun, Tides
from adcircpy.forcing.base import Forcing
from adcircpy.forcing.waves.ww3 import WaveWatch3DataForcing
from adcircpy.forcing.winds.atmesh import AtmosphericMeshForcing
from nemspy import ModelingSystem

from coupledmodeldriver.configure import NEMSJSON
from coupledmodeldriver.configure.base import ModelDriverJSON, SlurmJSON
from coupledmodeldriver.configure.forcings import (
ATMESHForcingJSON,
Expand Down Expand Up @@ -180,3 +183,144 @@ def read_directory(cls, directory: PathLike) -> 'ADCIRCRunConfiguration':
adcirc=configurations[2],
forcings=forcings,
)


class NEMSADCIRCRunConfiguration(ADCIRCRunConfiguration):
required = [
ModelDriverJSON,
NEMSJSON,
SlurmJSON,
ADCIRCJSON,
]

def __init__(
self,
fort13: PathLike,
fort14: PathLike,
modeled_start_time: datetime,
modeled_end_time: datetime,
modeled_timestep: timedelta,
nems_interval: timedelta,
nems_connections: [str],
nems_mediations: [str],
nems_sequence: [str],
tidal_spinup_duration: timedelta = None,
platform: Platform = None,
runs: {str: (float, str)} = None,
forcings: [ForcingJSON] = None,
adcirc_processors: int = None,
slurm_job_duration: timedelta = None,
slurm_partition: str = None,
slurm_email_address: str = None,
nems_executable: PathLike = None,
adcprep_executable: PathLike = None,
source_filename: PathLike = None,
):
self.__nems = None

super().__init__(
fort13=fort13,
fort14=fort14,
modeled_start_time=modeled_start_time,
modeled_end_time=modeled_end_time,
modeled_timestep=modeled_timestep,
tidal_spinup_duration=tidal_spinup_duration,
platform=platform,
runs=runs,
forcings=None,
adcirc_processors=adcirc_processors,
slurm_job_duration=slurm_job_duration,
slurm_partition=slurm_partition,
slurm_email_address=slurm_email_address,
adcprep_executable=adcprep_executable,
source_filename=source_filename,
)

nems = NEMSJSON(
executable_path=nems_executable,
modeled_start_time=modeled_start_time,
modeled_end_time=modeled_end_time,
interval=nems_interval,
models=self.nemspy_entries,
connections=nems_connections,
mediations=nems_mediations,
sequence=nems_sequence,
)

self.configurations[nems.name] = nems

for forcing in forcings:
self.add_forcing(forcing)

self['slurm']['tasks'] = self['nems'].nemspy_modeling_system.processors

@property
def nemspy_modeling_system(self) -> ModelingSystem:
return self['nems'].nemspy_modeling_system

def add_forcing(self, forcing: Forcing):
if not isinstance(forcing, ForcingJSON):
if isinstance(forcing, AtmosphericMeshForcing):
forcing = ATMESHForcingJSON.from_adcircpy(forcing)
self['nems']['models'].append(forcing.nemspy_entry)
elif isinstance(forcing, WaveWatch3DataForcing):
forcing = WW3DATAForcingJSON.from_adcircpy(forcing)
self['nems']['models'].append(forcing.nemspy_entry)
elif isinstance(forcing, Tides):
forcing = TidalForcingJSON.from_adcircpy(forcing)
else:
raise NotImplementedError(f'unable to parse object of type {type(forcing)}')

if forcing not in self:
self[forcing.name] = forcing
self['adcirc'].forcings.append(forcing)

@classmethod
def from_configurations(
cls,
driver: ModelDriverJSON,
nems: NEMSJSON,
slurm: SlurmJSON,
adcirc: ADCIRCJSON,
forcings: [ForcingJSON] = None,
) -> 'NEMSADCIRCRunConfiguration':
instance = super().from_configurations(
driver=driver, slurm=slurm, adcirc=adcirc, forcings=None,
)
instance.__class__ = cls
instance.configurations['nems'] = nems

if forcings is not None:
for forcing in forcings:
instance.add_forcing(forcing)

return instance

@classmethod
def read_directory(cls, directory: PathLike) -> 'NEMSADCIRCRunConfiguration':
if not isinstance(directory, Path):
directory = Path(directory)
if directory.is_file():
directory = directory.parent

configurations = []
for configuration_class in cls.required:
filename = directory / configuration_class.default_filename
if filename.exists():
configurations.append(configuration_class.from_file(filename))
else:
raise FileNotFoundError(f'missing required configuration file "{filename}"')

forcings = []
for configuration_class in cls.forcings:
filename = directory / configuration_class.default_filename
if filename.exists():
forcings.append(configuration_class.from_file(filename))

return cls.from_configurations(
driver=configurations[0],
nems=configurations[1],
slurm=configurations[2],
adcirc=configurations[3],
forcings=forcings,
)
Loading

0 comments on commit 4421748

Please sign in to comment.