Skip to content

Commit 7d2d85f

Browse files
Merge pull request #163 from noaa-ocs-modeling/feature/sflux_file
Add sflux forcing from existing file functionality for SCHISM setup
2 parents 6a97a9a + f97983c commit 7d2d85f

File tree

4 files changed

+108
-6
lines changed

4 files changed

+108
-6
lines changed

coupledmodeldriver/client/initialize_schism.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
TimestepForcingJSON,
2626
WaveForcingJSON,
2727
WindForcingJSON,
28+
SfluxFileForcingJSON,
2829
)
2930
from coupledmodeldriver.generate import (
3031
SCHISMRunConfiguration,
@@ -38,6 +39,7 @@ class ForcingConfigurations(Enum):
3839
tidal = TidalForcingJSON
3940
besttrack = BestTrackForcingJSON
4041
nwm = NationalWaterModelFocringJSON
42+
sfluxfiles = SfluxFileForcingJSON
4143

4244

4345
FORCING_NAMES = list(entry.name for entry in ForcingConfigurations)

coupledmodeldriver/configure/forcings/base.py

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from pyschism.forcing.bctides.tpxo import TPXO_VELOCITY as PySCHISMTPXO_VEL
2525
from pyschism.forcing.bctides.tides import TidalDatabase as PySCHISMTidalDatabase
2626
from pyschism.forcing.nws import BestTrackForcing as PySCHISMBestTrackForcing
27+
from pyschism.forcing.nws.nws2 import NWS2 as PySCHISMSfluxForcing
2728
from pyschism.forcing.base import ModelForcing as PySCHISMForcing
2829
from pyschism.forcing import NWM as PySCHISMNWM
2930
from pyschism.forcing.source_sink.nwm import NWMElementPairings
@@ -50,13 +51,11 @@
5051
PYSCHISM_FORCINGS = {
5152
'Tides': 'TidalForcingJSON',
5253
'BestTrackForcing': 'BestTrackForcingJSON',
53-
'NationalWaterModel': 'NationalWaterModelFocringJSON'
54-
# 'NWM : ,
55-
# 'GFS, etc.': 'ATMESHForcingJSON',
56-
# 'AtmosphericMeshForcing': 'ATMESHForcingJSON',
54+
'NationalWaterModel': 'NationalWaterModelFocringJSON',
55+
'NWS2': 'SfluxFileForcingJSON',
5756
}
5857

59-
PYSCHISM_FORCING_CLASSES = (PySCHISMTides, PySCHISMForcing, PySCHISMNWM)
58+
PYSCHISM_FORCING_CLASSES = (PySCHISMTides, PySCHISMForcing, PySCHISMNWM, PySCHISMSfluxForcing)
6059

6160

6261
class TidalSource(IntEnum):
@@ -845,7 +844,7 @@ def __init__(
845844
kwargs['fields'].update(NationalWaterModelFocringJSON.field_types)
846845

847846
HydrologyForcingJSON.__init__(self, **kwargs)
848-
FileForcingJSON.__init__(self, resource=resource, **kwargs)
847+
FileGenForcingJSON.__init__(self, resource=resource, **kwargs)
849848

850849
@property
851850
def adcircpy_forcing(self) -> None:
@@ -894,3 +893,99 @@ def from_pyschism(cls, forcing: PySCHISMNWM) -> 'ForcingJSON':
894893
# sink_json=sink_json_path,
895894
# pairing_hgrid=pairing_hgrid_path
896895
)
896+
897+
898+
class SfluxFileForcingJSON(WindForcingJSON, FileForcingJSON):
899+
900+
name = 'Sflux'
901+
default_filename = f'configure_sfluxfiles.json'
902+
default_nws = 2 # SCHISM NWS
903+
default_sflux_1_glob = '*_1.*'
904+
default_sflux_2_glob = '*_2.*'
905+
field_types = {
906+
'sflux_1_glob': str,
907+
'sflux_2_glob': str,
908+
}
909+
910+
def __init__(
911+
self, resource: PathLike, sflux_1_glob: str = None, sflux_2_glob: str = None, **kwargs,
912+
):
913+
914+
# TODO: Add windrot?
915+
if sflux_1_glob is None:
916+
sflux_1_glob = self.default_sflux_1_glob
917+
if sflux_2_glob is None:
918+
sflux_2_glob = self.default_sflux_2_glob
919+
920+
if 'fields' not in kwargs:
921+
kwargs['fields'] = {}
922+
kwargs['fields'].update(SfluxFileForcingJSON.field_types)
923+
924+
WindForcingJSON.__init__(self, **kwargs)
925+
FileForcingJSON.__init__(self, resource=resource, **kwargs)
926+
927+
self['sflux_1_glob'] = sflux_1_glob
928+
self['sflux_2_glob'] = sflux_2_glob
929+
930+
@property
931+
def adcircpy_forcing(self) -> None:
932+
raise NotImplementedError('ADCIRC does NOT support Sflux forcing!')
933+
934+
@classmethod
935+
def from_adcircpy(cls, forcing: None) -> 'None':
936+
raise NotImplementedError('ADCIRC does NOT support Sflux forcing!')
937+
938+
@property
939+
def pyschism_forcing(self) -> PySCHISMSfluxForcing:
940+
941+
return PySCHISMSfluxForcing.read(
942+
path=self['resource'],
943+
sflux_1_glob=self['sflux_1_glob'],
944+
sflux_2_glob=self['sflux_2_glob'],
945+
)
946+
947+
@classmethod
948+
def from_pyschism(cls, forcing: PySCHISMSfluxForcing) -> 'ForcingJSON':
949+
sf1_paths = forcing.sflux_1.resource
950+
if isinstance(sf1_paths, (str, Path)):
951+
sf1_paths = [sf1_paths]
952+
sf2_paths = forcing.sflux_2.resource
953+
if isinstance(sf2_paths, (str, Path)):
954+
sf2_paths = [sf2_paths]
955+
956+
path = cls._find_shared_root(*sf1_paths, *sf2_paths)
957+
sf1_pat = cls._find_simple_pattern(sf1_paths, path)
958+
sf2_pat = cls._find_simple_pattern(sf2_paths, path)
959+
960+
return cls(resource=path, sflux_1_glob=sf1_pat, sflux_2_glob=sf2_pat,)
961+
962+
def _find_shared_root(*paths):
963+
roots = {Path(i).parent for i in paths}
964+
while len(roots) != 0:
965+
roots = {Path(i).parent for i in roots}
966+
967+
return roots.pop()
968+
969+
def _find_simple_pattern(paths, root):
970+
# Note: CANNOT match complicated patterns, depth MUST be the same
971+
972+
if len(paths) == 0:
973+
return ''
974+
975+
relpaths = [Path(p).relative_to(root) for p in paths]
976+
if len(relpaths) == 1:
977+
return relpaths[0]
978+
979+
exts = {rp.suffix for rp in relpaths}
980+
ext = '.*'
981+
if len(exts) == 1:
982+
ext = exts.pop()
983+
984+
ns_parts = {len(rp.parts) - 1 for rp in relpaths}
985+
if len(ns_parts) > 1:
986+
raise ValueError('Cannot deduce pattern for different directory depths!')
987+
n_parts = ns_parts.pop()
988+
989+
pat = ('*/' * n_parts) + '*' + ext
990+
991+
return pat

coupledmodeldriver/generate/schism/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ def pyschism_driver(self) -> ModelDriver:
429429
nws=meteo,
430430
source_sink=hydrology,
431431
)
432+
# To avoid excessive memory use, especially when writing ensembles
433+
self.base_mesh = self['hgrid_path']
434+
self.pyschism_mesh = self['hgrid_path']
432435
# Hacky way to set the resource for tide
433436
if tides is not None:
434437
config.bctides.tides = tides

coupledmodeldriver/generate/schism/configure.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
TidalForcingJSON,
2323
BestTrackForcingJSON,
2424
NationalWaterModelFocringJSON,
25+
SfluxFileForcingJSON,
2526
)
2627
from coupledmodeldriver.generate.schism.base import SCHISMJSON
2728
from coupledmodeldriver.platforms import Platform
@@ -42,6 +43,7 @@ class SCHISMRunConfiguration(RunConfiguration):
4243
TidalForcingJSON,
4344
BestTrackForcingJSON,
4445
NationalWaterModelFocringJSON,
46+
SfluxFileForcingJSON,
4547
}
4648

4749
def __init__(

0 commit comments

Comments
 (0)