-
Notifications
You must be signed in to change notification settings - Fork 3
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
Runfile timeloop prephysics computations and configuration #1081
Conversation
class Prescriber: | ||
"""A pre-physics stepper which obtains prescribed values from an external source | ||
|
||
TODO: Implement methods |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a stub which does nothing, for the follow-on PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you remove it then? I think this should be unit tested before merging to master.
@@ -14,4 +14,6 @@ | |||
- fcc46bebe36ea131688f8e15700e18d4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These checksums were preserved but the test name was not
Would also be nice to get the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my reading this looks like a pretty clean approach to solving the multiple stepper issue. I just have a couple comments / suggestions, but I'll let @nbren12 give the final approval.
I agree it would be good if the fv3gfs-wrapper PR was merged; the changes there are pretty trivial but there seems to be an issue with the CI (I recall I was able to get the tests to pass locally).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for putting this together. I have a fair number of comments, and am happy to chat over zoom to explain any that don't have clear motivations. Some overall thoughts:
- we should wait until fv3gfs-wrapper is merged until master
- Revert changes to
machine_learning.py
and refactor unique "MLStateStepper" logic to either MLStepper or Loop. - Remove Prescriber class and related configs until that feature is functional.
- Simplify coupled fixture hierarchy in tests.
class Prescriber: | ||
"""A pre-physics stepper which obtains prescribed values from an external source | ||
|
||
TODO: Implement methods |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you remove it then? I think this should be unit tested before merging to master.
|
||
|
||
@dataclasses.dataclass | ||
class PrephysicsConfig: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why make a new object for this? You can use Union
directly in UserConfig
. It's odd to have a config object with one attribute named "config".
|
||
Attributes: | ||
variables: list variable names to prescribe | ||
data_source: path to the source of the data to prescribe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you mention what kind of data must be at this path? Zarr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moot since reverting
prephysics: Optional[PrephysicsConfig] | ||
if "prephysics" in config_dict: | ||
prephysics = dacite.from_dict( | ||
PrephysicsConfig, {"config": config_dict["prephysics"]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This renaming breaks down the 1-1 correspondence between the UserConfig attribute names and the yaml representation. This makes the documentation less useful. Again, PrephysicsConfig doesn't seem like it should be a class.
@@ -109,6 +109,22 @@ It can be used multiple times to specify multiple models. For example:: | |||
--model_url path/to_another/model | |||
> fv3config.yaml | |||
|
|||
Prephysics |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can document the prephysics config in the docstring of the UserConfig class.
@@ -60,6 +80,33 @@ def get_mock_sklearn_model() -> fv3fit.Predictor: | |||
return model | |||
|
|||
|
|||
def get_mock_rad_flux_model() -> fv3fit.Predictor: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a lot of copy paste here. Can we add some parameters to get_mock_sklearn_model?
@@ -191,30 +218,64 @@ def _get_states_to_output(self, config: UserConfig) -> Sequence[str]: | |||
states_to_output = diagnostic.variables # type: ignore | |||
return states_to_output | |||
|
|||
def _get_stepper(self, config: UserConfig) -> Optional[Stepper]: | |||
def _get_steppers(self, config: UserConfig) -> Mapping[str, Optional[Stepper]]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We heavily rely on mypy to detect errors in this un-testable Loop
class, and the old design was more amenable to static analysis . The Mapping[str, Optional[Stepper]]
return type will prevent mypy from detecting errors statically (e.g. if "_compute_physics" is not inside this dict). It will also add more indirection for the reader.
Can you revert these changes, and put the prephysics specific code into _get_prephysics_stepper
method and store the stepper in self._prephysics_stepper
?
@@ -177,7 +204,7 @@ def __init__( | |||
|
|||
self._states_to_output: Sequence[str] = self._get_states_to_output(config) | |||
self._log_debug(f"States to output: {self._states_to_output}") | |||
self.stepper = self._get_stepper(config) | |||
self.steppers = self._get_steppers(config) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.steppers = self._get_steppers(config) | |
self.post_physics_stepper = self._get_stepper(config) | |
self.pre_physics_stepper = self._get_pre_physics_stepper(config) |
@@ -27,6 +27,26 @@ def _model_dataset() -> xr.Dataset: | |||
return data | |||
|
|||
|
|||
def _rad_model_dataset() -> xr.Dataset: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copy paste here. Can you add these new variables to _model_dataset
and delete this function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good. Thanks. There was one place below I briefly got confused.
self._log_info("Downloading ML Model") | ||
if self.rank == 0: | ||
local_model_paths = download_model( | ||
ml_config, os.path.join(step, "ml_model") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got a little worried seeing this path logic. At first glance it looks like it could be a backwards incompatible change to how the user configuration is interpreted, but really it is just a temporary local cache. Can you note this in a comment or better yet...modify download_model
to use tempfile.NamedTemporaryDirectory
?
self._compute_prephysics, | ||
self._apply_prephysics, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these functions occur in sequence would it be simpler to group them in one function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates @brianhenn! It seems like we should be able to merge the wrapper PR today too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ai2cm/fv3gfs-wrapper#244 has now been merged, so we should be able to merge this PR soon, with a few more minor updates.
"total_sky_downward_shortwave_flux_at_surface_override", | ||
"total_sky_net_shortwave_flux_at_surface_override", | ||
"total_sky_downward_longwave_flux_at_surface_override", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These have been renamed in the merged version of ai2cm/fv3gfs-wrapper#244:
"total_sky_downward_shortwave_flux_at_surface_override", | |
"total_sky_net_shortwave_flux_at_surface_override", | |
"total_sky_downward_longwave_flux_at_surface_override", | |
"override_for_time_adjusted_total_sky_downward_shortwave_flux_at_surface", | |
"override_for_time_adjusted_total_sky_net_shortwave_flux_at_surface", | |
"override_for_time_adjusted_total_sky_downward_longwave_flux_at_surface", |
"total_sky_downward_shortwave_flux_at_surface_override", | ||
"total_sky_net_shortwave_flux_at_surface_override", | ||
"total_sky_downward_longwave_flux_at_surface_override", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"total_sky_downward_shortwave_flux_at_surface_override", | |
"total_sky_net_shortwave_flux_at_surface_override", | |
"total_sky_downward_longwave_flux_at_surface_override", | |
"override_for_time_adjusted_total_sky_downward_shortwave_flux_at_surface", | |
"override_for_time_adjusted_total_sky_net_shortwave_flux_at_surface", | |
"override_for_time_adjusted_total_sky_downward_longwave_flux_at_surface", |
In order to override the coarse model radiative fluxes with predicted values prior to the land surface model call during a prognostic run, this PR implement a
prephysics
steps in the sklearn_runfile's loop, after dynamics. It allows for configuring this optional prephysics computation by specifying a machine learning model, in the style of aMachineLearningConfig
used by the existing python computations after the physics routine (renamed as thepostphysics
step by this PR.Added public API:
PrephysicsConfig
specification for prognostic runs, an optionalMachineLearningConfig
specificationSignificant internal changes:
added an MLStateStepper object to
runtime.steppers.machine_learning
which returns ML-predicted states (as opposed to tendencies)runtime.loop
adds a_prephysics
steps to the loopruntime.loop
supports having twoStepper
objects, one for theprephysics
and one for the previous python computations after physics, now calledpostphysics
Tests added