Skip to content
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
46 changes: 38 additions & 8 deletions dnora/executer/executer.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def _write(
msg.info("No InputFileWriter defined. Won't do anything.")
return

msg.header(input_file_writer, "Writing model input file...")
msg.header(input_file_writer, f"Writing model input file for '{self.model.grid().name}'...")

# Controls generation of file names using the proper defaults etc.
format = format or self._get_default_format()
Expand Down Expand Up @@ -178,8 +178,8 @@ def _write(
)
if not isinstance(output_files, list):
output_files = [output_files]

msg.to_multifile(output_files)
if any(fn for fn in output_files):
msg.to_multifile(output_files)
self.model._input_file_exported_to[file_type] = output_files
self.model._input_file_export_format[file_type] = self._get_default_format()

Expand All @@ -196,6 +196,8 @@ def run_model(
"""Run the main model. Set post_process=False to disable any post-processing that might be defined."""

# Use the method generated by the decorateor, since that will automatically go through all nested grids if present


self.run_input(
model_runner=model_runner,
model_folder=model_folder,
Expand All @@ -214,16 +216,22 @@ def _run(
dateformat: Optional[str] = None,
post_process: bool = True,
post_processors: Optional[list[PostProcessor]] = None,
parent_folder: Optional[str] = None,
dry_run: bool = False,
**kwargs,
) -> None:
"""Run the model."""

if self.model.parent() is not None:
parent_folder = parent_folder or str(Path(self.model.parent().input_file_exported_to(DnoraFileType.INPUT)[0]).parent)
else:
parent_folder = ''
self._dry_run = dry_run
file_type = file_type_from_string(file_type)
model_runner = model_runner or self._model_runners.get(file_type)
if model_runner is None:
raise Exception("Define a ModelRunner!")

msg.header(model_runner, f"Running model '{self.model.grid().name}'...")
# Find location of model executable
# E.g. For writing GRID and a preferred format of WW3 search for DNORA_GRID_WW3_PATH and DNORA_WW3_PATH
model_folder = model_folder or read_environment_variable(
Expand All @@ -246,12 +254,13 @@ def _run(
edge_object=DnoraDataType.GRID,
)

msg.header(model_runner, "Running model...")

msg.plain(f"Using input file: {file_object.get_filepath()}")
if not self.dry_run():
outfile = model_runner(
file_object=file_object,
model_folder=model_folder,
parent_folder=parent_folder,
**kwargs,
)
if outfile is not None:
Expand All @@ -264,22 +273,43 @@ def _run(
post_processors = post_processors or model_runner.post_processors()

if post_processors and post_process:
self.post_process(post_processors, file_object, model_folder, **kwargs)
self.post_process(post_processors, file_object, model_folder, parent_folder,file_type, **kwargs)

def post_process(
self,
post_processors: list[PostProcessor],
file_object: FileNames,
model_folder,
parent_folder: str,
file_type,
**kwargs,
) -> None:
"""Post processes model run output, e.g. convert to netcdf or move files"""
for post_processor in post_processors:
msg.header(post_processor, "Post processing...")
if post_processor.for_nest is not None:
model = self.model.nest(get_dict=True)[post_processor.for_nest]
else:
model = self.model
file_objects = []
for fn in model.input_file_exported_to(post_processor.for_file_type or file_type):

exported_path = Path(fn)
primary_file = exported_path.stem
primary_folder = str(exported_path.parent)
file_objects.append(FileNames(
model=model,
filename=primary_file,
folder=primary_folder,
obj_type=post_processor.for_file_type or file_type,
format=self._get_default_format(),
edge_object=DnoraDataType.GRID,
))

post_processor(
model=self.model,
file_object=file_object,
file_object=file_objects,
model_folder=model_folder,
parent_folder=parent_folder,
**kwargs,
)

Expand Down
82 changes: 57 additions & 25 deletions dnora/executer/inputfile/inputfile_writers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import os
from pathlib import Path
import json

from dnora.grid.mask import LonLat
# Import objects
from typing import TYPE_CHECKING, Union, Optional

Expand Down Expand Up @@ -993,9 +993,9 @@ def __call__(
)
# else:
# grid_exported_to = exported_files["grid"]

ww3_grid(
grid,
model,
filename,
grid_exported_to,
freq1,
Expand Down Expand Up @@ -1031,26 +1031,34 @@ def __call__(
else:
filename = file_object.get_filepath()

wind_exported_to = apply_folder_on_server(
exported_files[self.file_type().name.lower()], folder_on_server
)
__, forcing_filename = recuresively_find_parent_object_and_filename(model,self.file_type().name.lower())
forcing_exported_to = [forcing_filename]

if folder_on_server or model.parent() is None:
forcing_exported_to = apply_folder_on_server(
forcing_exported_to, folder_on_server)
elif model.parent() is not None:
parent_folder = Path('../')/Path(model.parent().input_file_exported_to('grid')[0]).parent
forcing_exported_to = [ parent_folder / Path(forcing_filename).name]


if self.file_type() == DnoraFileType.ICE:
if model[self.file_type().name].get("sic", strict=True) is not None:
ww3_prnc(
f"{filename}.sic",
wind_exported_to,
forcing_exported_to,
forcing_type=self.file_type(),
subtype="sic",
)
if model[self.file_type().name].get("sit", strict=True) is not None:
ww3_prnc(
f"{filename}.sit",
wind_exported_to,
forcing_exported_to,
forcing_type=self.file_type(),
subtype="sit",
)
else:
ww3_prnc(filename, wind_exported_to, forcing_type=self.file_type())
ww3_prnc(filename, forcing_exported_to, forcing_type=self.file_type())

return filename

Expand All @@ -1070,10 +1078,16 @@ def __call__(
folder_on_server: str = "",
**kwargs,
) -> str:
if model.parent() is not None:
msg.info(f"Assuming spectra will be available from the parent run '{model.parent().grid().name}'")
parent_folder = Path('../')/Path(model.parent().input_file_exported_to('grid')[0]).parent
spectra_exported_to = [ parent_folder / Path(model.parent().start_time().strftime('ww3.%Y%m_spec.nc'))]
else:
spectra_exported_to = apply_folder_on_server(
exported_files["spectra"], folder_on_server
)
msg.to_file(file_object.get_folder() + "/spectral_boundary_files.list")
spectra_exported_to = apply_folder_on_server(
exported_files["spectra"], folder_on_server
)

ww3_specfile_list(
file_object.get_folder() + "/spectral_boundary_files.list",
spectra_exported_to,
Expand All @@ -1097,6 +1111,22 @@ def __call__(

return filename

def create_forcing_output_bool_dict(model)-> dict[str, bool]:
"""Determines what forcing data will be available for the model, taking to account that a nested model can have used data loaded for the parent model"""
forcing = {}
for ftype in [DnoraDataType.WIND, DnoraDataType.WATERLEVEL, DnoraDataType.CURRENT, DnoraDataType.ICE]:

obj, __ = recuresively_find_parent_object_and_filename(model,ftype)
forcing[ftype.name.lower()] = obj is not None

if ftype == DnoraDataType.ICE:
forcing["sit"] = (
obj is not None and obj.get("sit", strict=True) is not None
)
forcing["sic"] = (
obj is not None and obj.get("sic", strict=True) is not None
)
return forcing

class WW3(InputFileWriter):
def __call__(
Expand All @@ -1112,6 +1142,11 @@ def __call__(
"""To use homogeneous input, set all the variables in order as: homog = {'wind': [1,4]}"""
if homog is None:
homog = {}
if model.nest() is not None:
for __, nest in model.nest(get_dict=True).items():
blon, blat = nest.grid().boundary_points()
model.grid().set_output_points(LonLat(lon=blon, lat=blat), append=True)

lons, lats = model.grid().output_points()

spectral_output = len(lons) > 0
Expand All @@ -1123,29 +1158,26 @@ def __call__(

start_time = model.start_time(crop_with="all").strftime("%Y%m%d %H0000")
end_time = model.end_time(crop_with="all").strftime("%Y%m%d %H0000")

if file_object.get_filename() == "":
filename = file_object.get_folder() + "/ww3_shel.nml"
else:
filename = file_object.get_filepath()

forcing = {}
forcing["wind"] = model.wind() is not None
forcing["waterlevel"] = model.waterlevel() is not None
forcing["current"] = model.current() is not None
forcing["sit"] = (
model.ice() is not None and model.ice().get("sit", strict=True) is not None
)
forcing["sic"] = (
model.ice() is not None and model.ice().get("sic", strict=True) is not None
)
forcing = create_forcing_output_bool_dict(model)

#output_nest = model.nest() is not None
ww3_shel(
filename, start_time, end_time, stride, forcing, homog, spectral_output, output_vars
filename, start_time, end_time, stride, forcing, homog, spectral_output, output_vars#, output_nest
)
# Make inputfiles for the post-processing
ounf_filename = file_object.get_folder() + "/ww3_ounf.nml"
ounp_filename = file_object.get_folder() + "/ww3_ounp.nml"
ww3_ounf(ounf_filename, start_time, len(model.time()), 3600, output_vars)
ww3_ounp(ounp_filename, start_time, len(model.time()), 3600)

return [filename, ounf_filename, ounp_filename]
if spectral_output > 0:
ounp_filename = file_object.get_folder() + "/ww3_ounp.nml"
ww3_ounp(ounp_filename, start_time, len(model.time()), 3600)

return [filename, ounf_filename, ounp_filename]
else:
return [filename, ounf_filename]
49 changes: 46 additions & 3 deletions dnora/executer/inputfile/ww3_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def write_block(folder: str, fn: str, fout):

def ww3_grid(
grid,
model,
filename: str,
grid_exported_to: str,
freq1: float,
Expand Down Expand Up @@ -167,6 +168,38 @@ def write_inbnd():
fout.write(f" INBND_POINT({n+1:.0f}) = {block:.0f} 1 {flag}\n")
fout.write("/\n\n")

# def write_nest_output(nested_grid, first_nest):
# fout.write('&OUTBND_COUNT_NML\n')
# fout.write(' OUTBND_COUNT%N_LINE = 4\n')
# fout.write('/\n')
# fout.write('&OUTBND_LINE_NML\n')

# # North
# fout.write(f'OUTBND_LINE(1)%X0 = {nested_grid.edges("lon")[0]} ! x index start point\n')
# fout.write(f'OUTBND_LINE(1)%Y0 = {nested_grid.edges("lat")[1]} ! y index start point\n')
# fout.write(f'OUTBND_LINE(1)%DX = {nested_grid.dlon()} ! x-along increment\n')
# fout.write(f'OUTBND_LINE(1)%DY = 0. ! y-along increment\n')
# fout.write(f'OUTBND_LINE(1)%NP = -{nested_grid.nx()} ! number of points\n')
# # West
# fout.write(f'OUTBND_LINE(2)%X0 = {nested_grid.edges("lon")[0]} ! x index start point\n')
# fout.write(f'OUTBND_LINE(2)%Y0 = {nested_grid.edges("lat")[0]} ! y index start point\n')
# fout.write(f'OUTBND_LINE(2)%DX = 0. ! x-along increment\n')
# fout.write(f'OUTBND_LINE(2)%DY = {nested_grid.dlat()} ! y-along increment\n')
# fout.write(f'OUTBND_LINE(2)%NP = {nested_grid.ny()-1} ! number of points\n')
# # South
# fout.write(f'OUTBND_LINE(3)%X0 = {nested_grid.edges("lon")[0]} ! x index start point\n')
# fout.write(f'OUTBND_LINE(3)%Y0 = {nested_grid.edges("lat")[0]} ! y index start point\n')
# fout.write(f'OUTBND_LINE(3)%DX = {nested_grid.dlon()} ! x-along increment\n')
# fout.write(f'OUTBND_LINE(3)%DY = 0. ! y-along increment\n')
# fout.write(f'OUTBND_LINE(3)%NP = {nested_grid.nx()-1} ! number of points\n')
# # East
# fout.write(f'OUTBND_LINE(4)%X0 = {nested_grid.edges("lon")[1]} ! x index start point\n')
# fout.write(f'OUTBND_LINE(4)%Y0 = {nested_grid.edges("lat")[0]} ! y index start point\n')
# fout.write(f'OUTBND_LINE(4)%DX = 0. ! x-along increment\n')
# fout.write(f'OUTBND_LINE(4)%DY = {nested_grid.dlat()} ! y-along increment\n')
# fout.write(f'OUTBND_LINE(4)%NP = {nested_grid.ny()-1} ! number of points\n')
fout.write('/\n')

folder = __file__[:-17] + "/metadata/ww3_grid/"

with open(filename, "w") as fout:
Expand Down Expand Up @@ -197,6 +230,14 @@ def write_inbnd():
write_unst()
write_block("inbnd.txt")
write_inbnd()



# if model.nest():
# first_nest = True
# for __, nest in model.nest(get_dict=True).items():
# write_nest_output(nest.grid(), first_nest)
# first_nest = False
write_block("footer.txt")


Expand Down Expand Up @@ -372,11 +413,13 @@ def write_date():
stride_str = f"{3600*stride:.0f}"
restart_start = (pd.to_datetime(start_time)+pd.Timedelta(stride, 'h')).strftime('%Y%m%d %H%M00')

start_times = {"FIELD": start_time, "POINT": start_time, "RESTART": restart_start}
end_times = {"FIELD": end_time, "POINT": end_time, "RESTART": end_time}
start_times = {"FIELD": start_time, "POINT": start_time, "RESTART": restart_start, "BOUNDARY": start_time}
end_times = {"FIELD": end_time, "POINT": end_time, "RESTART": end_time, "BOUNDARY": end_time}

dt = {"FIELD": "3600", "POINT": "3600", "RESTART": stride_str}
dt = {"FIELD": "3600", "POINT": "3600", "RESTART": stride_str, "BOUNDARY": 3600}
output_types = ["FIELD", "RESTART"]
# if output_nest:
# output_types.append('BOUNDARY')
if spectral_output:
output_types.append("POINT")
for output_type in output_types:
Expand Down
Loading
Loading