Skip to content

Comments

Coupled evaluator with prediction loader #856

Merged
elynnwu merged 14 commits intomainfrom
feature/cpl-pred-loader
Feb 23, 2026
Merged

Coupled evaluator with prediction loader #856
elynnwu merged 14 commits intomainfrom
feature/cpl-pred-loader

Conversation

@elynnwu
Copy link
Contributor

@elynnwu elynnwu commented Feb 19, 2026

prediction_loader is an already supported feature in ace evaluator, we add this feature for coupled evaluator so that we can easily compare with target data on wandb.

Resolves #805

Comment on lines 389 to 392
restrict_to_output_names=(
stepper.ocean.out_names,
stepper.atmosphere.out_names,
),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did not have to do this in ace evaluator because there was no merge operation, we need this here because we can have overlap in atmosphere and ocean in_names (e.g., land_fraction)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the fme.ace version we log all variables including input-only forcings. I think this can be useful for examining the forcings and for post-hoc analyses.

See my other comment. I think we can instead add an @property called all_names to CoupledStepperConfig which returns a CoupledNames where:

  • atmosphere has its out names + atmosphere_forcing_exogenous_names + shared_forcing_exogenous_names
  • ocean has its out names + ocean_forcing_exogenous_names

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, added

@elynnwu
Copy link
Contributor Author

elynnwu commented Feb 20, 2026

Job here
wandb here

Copy link
Member

@jpdunc23 jpdunc23 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! I have some suggestions for handling the names.

deriver: CoupledDeriverABC,
writer: CoupledPairedDataWriter | NullDataWriter | None = None,
record_logs: Callable[[InferenceLogs], None] | None = None,
restrict_to_output_names: tuple[list[str], list[str]] | None = None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a new dataclass to replace tuple[list[str], list[str]] in fme/coupled/typing_.py:

@dataclasses.dataclass
class CoupledNames:
    ocean: list[str]
    atmosphere: list[str]

You could also add an @property called out_names to CoupledStepperConfig which gets the names from the component steppers and returns a CoupledNames object. See my other comment where I suggest instead adding all_names to CoupledStepperConfig.

assert not os.path.exists(tmp_path / "atmosphere/restart.nc")
assert not os.path.exists(tmp_path / "atmosphere/initial_condition.nc")
assert not os.path.exists(tmp_path / "ocean/restart.nc")
assert not os.path.exists(tmp_path / "ocean/initial_condition.nc")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to add a check similar to the following in the fme.ace test:

                # if these are off by something like 90% then probably the stepper
                # is being used instead of the prediction_data
                assert log[f"inference/mean/weighted_rmse/{var}"] == 0.0
                assert log[f"inference/mean/weighted_bias/{var}"] == 0.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment on lines 71 to 80
initial_condition=CoupledPairedData(
ocean_data=PairedData.from_batch_data(
prediction=pred_ic.ocean_data,
reference=target_ic.ocean_data,
),
atmosphere_data=PairedData.from_batch_data(
prediction=pred_ic.atmosphere_data,
reference=target_ic.atmosphere_data,
),
),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use CoupledPairedData.from_coupled_batch_data here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, updated

from fme.coupled.inference.data_writer import CoupledPairedDataWriter


class CoupledDeriverABC(Protocol):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using Protocol rather than abc.ABC as in fme.ace is good, but we should call it CoupledDeriverProtocol or simply CoupledDeriver.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to CoupledDeriver

Comment on lines 389 to 392
restrict_to_output_names=(
stepper.ocean.out_names,
stepper.atmosphere.out_names,
),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the fme.ace version we log all variables including input-only forcings. I think this can be useful for examining the forcings and for post-hoc analyses.

See my other comment. I think we can instead add an @property called all_names to CoupledStepperConfig which returns a CoupledNames where:

  • atmosphere has its out names + atmosphere_forcing_exogenous_names + shared_forcing_exogenous_names
  • ocean has its out names + ocean_forcing_exogenous_names

Copy link
Member

@jpdunc23 jpdunc23 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of nits and a question, but LGTM.

timestep_size=1,
timestep_start=0,
nz=3,
masked_fill_value: float = float("nan"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know why this is needed for prediction_loader inference but not evaluator inference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay this is because we didn't write mask_2d so variables like o_prog doesn't have the right mask, I reverted back to using nans as masked fill values and added the proper mask.

Comment on lines 389 to 393
atmosphere_names = (
self.atmosphere.stepper.output_names
+ self._atmosphere_forcing_exogenous_names
+ self._shared_forcing_exogenous_names
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't matter in practice, but agent review flagged that _shared_forcing_exogenous_names is a subset of _atmosphere_forcing_exogenous_names, so probably best to remove _shared_forcing_exogenous_names here.

deriver: CoupledDeriver,
writer: CoupledPairedDataWriter | NullDataWriter | None = None,
record_logs: Callable[[InferenceLogs], None] | None = None,
restrict_to_output_names: CoupledNames | None = None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Maybe call this all_names since it is no longer restricted to just output names.

@elynnwu elynnwu enabled auto-merge (squash) February 23, 2026 22:29
@elynnwu elynnwu merged commit a40e75c into main Feb 23, 2026
7 checks passed
@elynnwu elynnwu deleted the feature/cpl-pred-loader branch February 23, 2026 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

prediction_loader for coupled eval

3 participants