Skip to content

Commit e3ece5c

Browse files
authored
Merge pull request #57 from NGWPC/maxkipp-fix-cli-hindcast-pw
Mirror for PW: Fix CLI Hindcast by Consuming Generator
2 parents 93a5896 + 5fdc7e3 commit e3ece5c

2 files changed

Lines changed: 25 additions & 14 deletions

File tree

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,16 @@ python -m nwm_fcst_mgr run_hindcast \
133133
```python
134134
from nwm_fcst_mgr.forecast import run_hindcast
135135

136-
run_hindcast(
136+
for _ in run_hindcast(
137137
valid_yaml='/path/to/valid.yaml',
138138
config='/path/to/input.config',
139139
fcst_run_name='my_hindcast_run',
140140
cycle_interval=3,
141141
num_iterations=10,
142142
cold_start_state='/path/to/cold_start_state/',
143143
yield_realizations=False,
144-
)
144+
):
145+
pass
145146
```
146147

147148
#### Arguments
@@ -151,7 +152,9 @@ run_hindcast(
151152
- `cycle_interval` - Cycle interval in hours (spacing between hindcast cycles)
152153
- `num_iterations` - Number of hindcast cycles to perform
153154
- `cold_start_state` - (Optional) Path to cold start state to initialize hindcasting workflow
154-
- `yield_realizations` - (Optional) Default False. If True, then this function will act as a generator and will yield each RealizationBuilder instance after constructing it and calling its build_fcst_realization() method. If False, this function itself will execute each ngen realization of the hindcast sequence as they become built.
155+
- `yield_realizations` - (Optional) Default False. If True, then this generator will yield each RealizationBuilder instance after constructing it
156+
and calling its build_fcst_realization() method, so the caller can execute the realization.
157+
If False, then this generator will yield None, and consuming it will instead execute each RealizationBuilder instance itself.
155158

156159

157160
#### Hindcast Example

python/nwm_fcst_mgr/forecast.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -779,17 +779,22 @@ def run_hindcast(
779779
num_iterations,
780780
cold_start_state=None,
781781
yield_realizations: bool = False,
782-
) -> None | Generator[RealizationBuilder, None, None]:
782+
) -> Generator[RealizationBuilder | None, None, None]:
783783
"""
784+
WARNING: this is a generator so it should be fully consumed (iterated over) regardless of the provided
785+
value for `yield_realizations`.
786+
784787
Run hindcast workflow with warm start runs, initial cold start should be run separately
785788
Accepts cycle interval and number of intervals for repeated hindcasts.
786789
787-
If yield_realizations is True, then this function acts as a generator of (built) RealizationBuilder
788-
instances, with the assumption that the caller will execute each realization as it is generated,
789-
before the next one is generated.
790+
When `yield_realizations` is True, the realizations are built and yielded without being executed.
791+
They are yielded on the fly for the caller to execute them, e.g. in the nwm-rte use case.
790792
791-
If yield_realizations is False, then this function builds and runs the realizations sequence itself
792-
(which takes significant time to return).
793+
When `yield_realizations` is False, the realizations are built and then executed in sequence as the
794+
generator is consumed, i.e. the caller does not need to manually execute the realizations. In this mode,
795+
None is yielded instead of the built realizations being yielded.
796+
Note that in this mode, the caller must still consume (iterate over) the generator,
797+
otherwise the realizations will not execute.
793798
794799
Parameters
795800
---------
@@ -808,8 +813,9 @@ def run_hindcast(
808813
If provided, will be used for first hindcast cycle (hind_cycle=0)
809814
Subsequent cycles will use warm start states
810815
yield_realizations: bool
811-
If True, then this function will act as a generator and will yield each RealizationBuilder
812-
instance after constructing it and calling its build_fcst_realization() method.
816+
If True, then this generator will yield each RealizationBuilder instance after constructing it
817+
and calling its build_fcst_realization() method, so the caller can execute the realization.
818+
If False, then this generator will yield None, and consuming it will instead execute each RealizationBuilder instance itself.
813819
"""
814820
# Set up hindcast orchestration logger, initialized once the hindcast root directory is known
815821
hindcast_logger = None
@@ -968,9 +974,11 @@ def main():
968974
if args.command == "run_forecast":
969975
run_forecast(real_path=args.real_path, valid_yaml=args.valid_yaml, no_valid=args.no_valid, partition_file=args.partition_file)
970976
elif args.command == "run_hindcast":
971-
run_hindcast(valid_yaml=args.valid_yaml, config=args.input_path,
972-
fcst_run_name=args.fcst_run_name, cycle_interval=args.cycle_interval,
973-
num_iterations=args.num_iterations, cold_start_state=args.cold_start_state)
977+
# run_hindcast is a generator, it must be consumed whether yield_realizations is True or False.
978+
for _ in run_hindcast(valid_yaml=args.valid_yaml, config=args.input_path,
979+
fcst_run_name=args.fcst_run_name, cycle_interval=args.cycle_interval,
980+
num_iterations=args.num_iterations, cold_start_state=args.cold_start_state):
981+
pass
974982
else:
975983
raise ValueError(f"Unexpected command: {args.command}. Use either 'run_forecast', o r'run_hindcast'")
976984

0 commit comments

Comments
 (0)