Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

link mesh if it is the same #121

Merged
15 commits merged into from
Sep 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 60 additions & 54 deletions coupledmodeldriver/generate/adcirc/base.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from datetime import datetime, timedelta
import os
from os import PathLike
from pathlib import Path
import sys
from typing import Any, Union

from adcircpy import AdcircMesh, AdcircRun, Tides
from adcircpy.forcing import BestTrackForcing
from adcircpy.forcing.base import Forcing
from adcircpy.mesh.fort13 import NodalAttributes
from adcircpy.mesh.mesh import ModelForcings
from adcircpy.server import SlurmConfig
from nemspy.model import ADCIRCEntry

Expand Down Expand Up @@ -217,6 +217,7 @@ def __init__(
:param attributes: attributes to set in `adcircpy.AdcircRun` object
"""

self.__mesh = None
self.__base_mesh = None

if tidal_spinup_timestep is None:
Expand Down Expand Up @@ -309,70 +310,72 @@ def adcircpy_forcings(self) -> [Forcing]:

@property
def adcircpy_mesh(self) -> AdcircMesh:
if self.__base_mesh is None:
self.__base_mesh = self['fort_14_path']

if not isinstance(self.__base_mesh, AdcircMesh):
LOGGER.info(f'opening mesh "{self.__base_mesh}"')
self.__base_mesh = AdcircMesh.open(self.__base_mesh, crs=4326)

mesh = self.__base_mesh.copy()

if self['fort_13_path'] is not None:
LOGGER.info(
f'reading attributes from "{os.path.relpath(self["fort_13_path"].resolve(), Path.cwd())}"'
)
if self['fort_13_path'].exists():
mesh.import_nodal_attributes(self['fort_13_path'])
for attribute_name in mesh.get_nodal_attribute_names():
mesh.set_nodal_attribute_state(
attribute_name, coldstart=True, hotstart=True
if self.__mesh is None:
mesh = self.base_mesh.copy()

# reconstruct mesh from base
mesh.forcings = ModelForcings(mesh)
mesh.nodal_attributes = NodalAttributes(mesh)

if self['fort_13_path'] is not None:
if self['fort_13_path'].exists():
LOGGER.info(f'reading attributes from "{self["fort_13_path"]}"')
mesh.import_nodal_attributes(self['fort_13_path'])
for attribute_name in mesh.get_nodal_attribute_names():
mesh.set_nodal_attribute_state(
attribute_name, coldstart=True, hotstart=True
)
else:
LOGGER.warning(
f'mesh values (nodal attributes) not found at "{self["fort_13_path"]}"'
)
else:
LOGGER.warning(
f'mesh values (nodal attributes) not found at "{os.path.relpath(self["fort_13_path"].resolve(), Path.cwd())}"'
)

LOGGER.debug(f'adding {len(self.forcings)} forcing(s) to mesh')
for adcircpy_forcing in self.adcircpy_forcings:
if isinstance(adcircpy_forcing, (Tides, BestTrackForcing)):
adcircpy_forcing.start_date = self['modeled_start_time']
adcircpy_forcing.end_date = self['modeled_end_time']
LOGGER.debug(f'adding {len(self.forcings)} forcing(s) to mesh')
for adcircpy_forcing in self.adcircpy_forcings:
if isinstance(adcircpy_forcing, (Tides, BestTrackForcing)):
adcircpy_forcing.start_date = self['modeled_start_time']
adcircpy_forcing.end_date = self['modeled_end_time']

if (
isinstance(adcircpy_forcing, Tides)
and self['tidal_spinup_duration'] is not None
):
adcircpy_forcing.spinup_time = self['tidal_spinup_duration']
adcircpy_forcing.start_date -= self['tidal_spinup_duration']
# elif isinstance(adcircpy_forcing, BestTrackForcing):
# adcircpy_forcing.clip_to_bbox(mesh.get_bbox(output_type='bbox'), mesh.crs)
if (
isinstance(adcircpy_forcing, Tides)
and self['tidal_spinup_duration'] is not None
):
adcircpy_forcing.spinup_time = self['tidal_spinup_duration']
adcircpy_forcing.start_date -= self['tidal_spinup_duration']
# elif isinstance(adcircpy_forcing, BestTrackForcing):
# adcircpy_forcing.clip_to_bbox(mesh.get_bbox(output_type='bbox'), mesh.crs)

mesh.add_forcing(adcircpy_forcing)
mesh.add_forcing(adcircpy_forcing)

if not mesh.has_nodal_attribute('primitive_weighting_in_continuity_equation'):
LOGGER.debug(f'generating tau0 in mesh')
mesh.generate_tau0()
if not mesh.has_nodal_attribute('primitive_weighting_in_continuity_equation'):
LOGGER.debug(f'generating tau0 in mesh')
mesh.generate_tau0()

return mesh
self.__mesh = mesh

return self.__mesh

@adcircpy_mesh.setter
def adcircpy_mesh(self, adcircpy_mesh: Union[AdcircMesh, PathLike]):
if isinstance(adcircpy_mesh, AdcircMesh):
try:
adcircpy_mesh = adcircpy_mesh.copy()
LOGGER.debug(f'copying mesh object ({sys.getsizeof(adcircpy_mesh)} bytes)')
except Exception as error:
LOGGER.warning(f'unable to copy mesh object: {error}')

self.__base_mesh = adcircpy_mesh
self.__mesh = adcircpy_mesh

@property
def base_mesh(self) -> AdcircMesh:
if self.__base_mesh is None:
if self.__mesh is not None:
self.__base_mesh = self.__mesh
else:
self.__base_mesh = self['fort_14_path']
if not isinstance(self.__base_mesh, AdcircMesh):
LOGGER.info(f'opening mesh "{self.__base_mesh}"')
self.__base_mesh = AdcircMesh.open(self.__base_mesh, crs=4326)
# deconstruct mesh into a base mesh that can be pickled
self.__base_mesh.forcings = None
self.__base_mesh.nodal_attributes = None
return self.__base_mesh

@base_mesh.setter
def base_mesh(self, base_mesh: AdcircMesh):
def base_mesh(self, base_mesh: Union[AdcircMesh, PathLike]):
self.__base_mesh = base_mesh

@property
Expand All @@ -389,9 +392,7 @@ def adcircpy_driver(self) -> AdcircRun:
)

if self['stations_file_path'] is not None:
LOGGER.info(
f'importing stations from "{os.path.relpath(self["stations_file_path"].resolve(), Path.cwd())}"'
)
LOGGER.info(f'importing stations from "{self["stations_file_path"]}"')
driver.import_stations(self['stations_file_path'])

if self['modeled_timestep'] is not None:
Expand Down Expand Up @@ -501,7 +502,12 @@ def adcircpy_driver(self) -> AdcircRun:
def nemspy_entry(self) -> ADCIRCEntry:
return ADCIRCEntry(processors=self['processors'], **self['nems_parameters'])

def __setitem__(self, key: str, value: Any):
super().__setitem__(key, value)
self.__mesh = None

def __copy__(self) -> 'ADCIRCJSON':
instance = super().__copy__()
instance.base_mesh = self.base_mesh
instance.forcings = self.forcings
return instance
13 changes: 8 additions & 5 deletions coupledmodeldriver/generate/adcirc/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,18 @@ def forcings(self) -> [ForcingJSON]:
def adcircpy_mesh(self) -> AdcircMesh:
return self['adcirc'].adcircpy_mesh

@adcircpy_mesh.setter
def adcircpy_mesh(self, adcircpy_mesh: AdcircMesh):
self['adcirc'].adcircpy_mesh = adcircpy_mesh

@property
def adcircpy_driver(self) -> AdcircRun:
return self['adcirc'].adcircpy_driver

@adcircpy_driver.setter
def adcircpy_driver(self, adcircpy_driver: AdcircRun):
self['adcirc'].adcircpy_driver = adcircpy_driver

def __copy__(self) -> 'ADCIRCRunConfiguration':
return self.__class__.from_configurations(
[copy(configuration) for configuration in self.configurations]
Expand Down Expand Up @@ -305,11 +313,6 @@ def add_forcing(self, forcing: ForcingJSON):
forcing = self[self.add(forcing)]
self['adcirc'].add_forcing(forcing)

def __copy__(self) -> 'NEMSADCIRCRunConfiguration':
return self.__class__.from_configurations(
[copy(configuration) for configuration in self.configurations]
)

@classmethod
def from_configurations(
cls, configurations: [ConfigurationJSON]
Expand Down
51 changes: 30 additions & 21 deletions coupledmodeldriver/generate/adcirc/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,15 +173,17 @@ def generate_adcirc_configuration(
if do_spinup:
spinup_directory = output_directory / 'spinup'

spinup_configuration = copy(base_configuration)

spinup_kwargs = {
'directory': spinup_directory,
'configuration': copy(base_configuration),
'configuration': spinup_configuration,
'duration': spinup_duration,
'relative_paths': relative_paths,
'overwrite': overwrite,
'use_original_mesh': use_original_mesh,
'local_fort13_filename': local_fort13_filename,
'local_fort14_filename': local_fort14_filename,
'link_mesh': True,
'relative_paths': relative_paths,
'overwrite': overwrite,
'platform': platform,
'adcirc_processors': adcirc_processors,
'slurm_account': slurm_account,
Expand All @@ -202,16 +204,21 @@ def generate_adcirc_configuration(
for run_name, run_configuration in perturbations.items():
run_directory = runs_directory / run_name

link_mesh = (
use_original_mesh
or run_configuration.adcircpy_mesh == base_configuration.adcircpy_mesh
)

run_kwargs = {
'directory': run_directory,
'name': run_name,
'phase': run_phase,
'configuration': run_configuration,
'relative_paths': relative_paths,
'overwrite': overwrite,
'use_original_mesh': use_original_mesh,
'local_fort13_filename': local_fort13_filename,
'local_fort14_filename': local_fort14_filename,
'link_mesh': link_mesh,
'relative_paths': relative_paths,
'overwrite': overwrite,
'platform': platform,
'adcirc_processors': adcirc_processors,
'slurm_account': slurm_account,
Expand All @@ -224,6 +231,8 @@ def generate_adcirc_configuration(
}

if parallel:
# destroy stored copy of adcircpy mesh, because it cannot be pickled across processes
run_configuration.adcircpy_mesh = None
futures.append(process_pool.submit(write_run_directory, **run_kwargs))
else:
write_run_directory(**run_kwargs)
Expand Down Expand Up @@ -264,9 +273,9 @@ def write_spinup_directory(
duration: timedelta,
local_fort14_filename: PathLike,
local_fort13_filename: PathLike = None,
link_mesh: bool = False,
relative_paths: bool = False,
overwrite: bool = False,
use_original_mesh: bool = False,
platform: Platform = None,
adcirc_processors: int = None,
slurm_account: str = None,
Expand All @@ -277,7 +286,7 @@ def write_spinup_directory(
) -> Path:
if not isinstance(directory, Path):
directory = Path(directory)
if not isinstance(local_fort13_filename, Path):
if local_fort13_filename is not None and not isinstance(local_fort13_filename, Path):
local_fort13_filename = Path(local_fort13_filename)

if not directory.exists():
Expand Down Expand Up @@ -404,17 +413,17 @@ def write_spinup_directory(
adcircpy_driver.write(
directory,
overwrite=overwrite,
fort13=None if use_original_mesh else 'fort.13',
fort14=None,
fort13=None if link_mesh else 'fort.13',
fort14=None if link_mesh else 'fort.14',
fort22='fort.22' if 'besttrack' in configuration else None,
coldstart='fort.15',
hotstart=None,
driver=None,
)
if use_original_mesh:
if local_fort13_filename.exists():
if link_mesh:
if local_fort13_filename is not None and local_fort13_filename.exists():
create_symlink(local_fort13_filename, directory / 'fort.13', relative=True)
create_symlink(local_fort14_filename, directory / 'fort.14', relative=True)
create_symlink(local_fort14_filename, directory / 'fort.14', relative=True)

return directory

Expand All @@ -426,9 +435,9 @@ def write_run_directory(
configuration: Union[ADCIRCRunConfiguration, NEMSADCIRCRunConfiguration],
local_fort14_filename: PathLike,
local_fort13_filename: PathLike = None,
link_mesh: bool = False,
relative_paths: bool = False,
overwrite: bool = False,
use_original_mesh: bool = False,
platform: Platform = None,
adcirc_processors: int = None,
slurm_account: str = None,
Expand All @@ -443,7 +452,7 @@ def write_run_directory(
directory = Path(directory)
if spinup_directory is not None and not isinstance(spinup_directory, Path):
spinup_directory = Path(spinup_directory)
if not isinstance(local_fort13_filename, Path):
if local_fort13_filename is not None and not isinstance(local_fort13_filename, Path):
local_fort13_filename = Path(local_fort13_filename)

if not directory.exists():
Expand Down Expand Up @@ -564,17 +573,17 @@ def write_run_directory(
adcircpy_driver.write(
directory,
overwrite=overwrite,
fort13=None if use_original_mesh else 'fort.13',
fort14=None,
fort13=None if link_mesh else 'fort.13',
fort14=None if link_mesh else 'fort.14',
fort22='fort.22' if 'besttrack' in configuration else None,
coldstart=None,
hotstart='fort.15',
driver=None,
)
if use_original_mesh:
if local_fort13_filename.exists():
if link_mesh:
if local_fort13_filename is not None and local_fort13_filename.exists():
create_symlink(local_fort13_filename, directory / 'fort.13', relative=True)
create_symlink(local_fort14_filename, directory / 'fort.14', relative=True)
create_symlink(local_fort14_filename, directory / 'fort.14', relative=True)

if do_spinup:
for hotstart_filename in ['fort.67.nc', 'fort.68.nc']:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from setuptools import config, find_packages, setup

DEPENDENCIES = {
'adcircpy>=1.0.39': ['gdal', 'fiona'],
'adcircpy>=1.0.41': ['gdal', 'fiona'],
'filelock': [],
'file-read-backwards': [],
'nemspy>=1.0.3': [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
created on 2021-09-07 10:26 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
created on 2021-09-07 14:16 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
Shinacock Inlet Coarse Grid ! RUNID - 24 CHARACTER ALPANUMERIC RUN IDENTIFICATION
1 ! NFOVER - NONFATAL ERROR OVERRIDE OPTION
1 ! NABOUT - ABREVIATED OUTPUT OPTION PARAMETER
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
created on 2021-09-07 10:26 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
created on 2021-09-07 14:16 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
Shinacock Inlet Coarse Grid ! RUNID - 24 CHARACTER ALPANUMERIC RUN IDENTIFICATION
1 ! NFOVER - NONFATAL ERROR OVERRIDE OPTION
1 ! NABOUT - ABREVIATED OUTPUT OPTION PARAMETER
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
created on 2021-09-07 10:26 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
created on 2021-09-07 14:16 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
Shinacock Inlet Coarse Grid ! RUNID - 24 CHARACTER ALPANUMERIC RUN IDENTIFICATION
1 ! NFOVER - NONFATAL ERROR OVERRIDE OPTION
1 ! NABOUT - ABREVIATED OUTPUT OPTION PARAMETER
Expand Down
2 changes: 1 addition & 1 deletion tests/data/reference/test_hera_adcirc_tidal/spinup/fort.15
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
created on 2021-09-07 10:26 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
created on 2021-09-07 14:16 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
Shinacock Inlet Coarse Grid ! RUNID - 24 CHARACTER ALPANUMERIC RUN IDENTIFICATION
1 ! NFOVER - NONFATAL ERROR OVERRIDE OPTION
1 ! NABOUT - ABREVIATED OUTPUT OPTION PARAMETER
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
created on 2021-09-07 10:26 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
created on 2021-09-07 14:17 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
Shinacock Inlet Coarse Grid ! RUNID - 24 CHARACTER ALPANUMERIC RUN IDENTIFICATION
1 ! NFOVER - NONFATAL ERROR OVERRIDE OPTION
1 ! NABOUT - ABREVIATED OUTPUT OPTION PARAMETER
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
created on 2021-09-07 10:26 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
created on 2021-09-07 14:17 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
Shinacock Inlet Coarse Grid ! RUNID - 24 CHARACTER ALPANUMERIC RUN IDENTIFICATION
1 ! NFOVER - NONFATAL ERROR OVERRIDE OPTION
1 ! NABOUT - ABREVIATED OUTPUT OPTION PARAMETER
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
created on 2021-09-07 10:27 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
created on 2021-09-07 14:17 ! RUNDES - 32 CHARACTER ALPHANUMERIC RUN DESCRIPTION
Shinacock Inlet Coarse Grid ! RUNID - 24 CHARACTER ALPANUMERIC RUN IDENTIFICATION
1 ! NFOVER - NONFATAL ERROR OVERRIDE OPTION
1 ! NABOUT - ABREVIATED OUTPUT OPTION PARAMETER
Expand Down
Loading