Skip to content

refactor hazard retrieval logic - #617

Draft
jroman-ak wants to merge 5 commits into
os-climate:mainfrom
arfima:refactor-hazard
Draft

jroman-ak wants to merge 5 commits into
os-climate:mainfrom
arfima:refactor-hazard

Conversation

@jroman-ak

Copy link
Copy Markdown
Contributor

Main contribution:

  • We implement an alternative HazardDataProvider: HierarchicalHazardDataProvider. This new provider combines the cascading logic of the existing provider with a new logic for resolving an available scenario and year to fulfill every incoming request. The provider is agnostic to the criterion used to sort the resources. Cascading is strictly geographical, the first resource having geographic coverage to fulfill a requested latitude-longitude will be used. The requested scenario-year is assigned an available scenario-year in the selected resource by a ScenarioYearResolver.
  • We implement resolve_nearest_scenario_year as an instance of the ScenarioYearResolver. Given a requested scenario-year and a resource, it assigns the closest available scenario by radiative forcing value and the closest year. In the historical case it assigns the latest available year if the historical scenario is available. If the historical scenario is not available it assigns the lowest year from the scenario with lowest radiative forcing. In the case of a tie it assigns the scenario with the largest radiative forcing and the largest year (giving a worst case estimate). In the case of an unrecognized requested scenario it assigns the last available scenario (again trying to give a worst case estimate under the assumption that scenarios are sorted in the inventory from most optimistic to most pessimistic).

A notable limitation of the current implementation is that the resolution is one-to-one, this is in contrast with the existing CascadingHazardDataProvider that can do one-to-many resolution at the level of years. It could be generalized to support resolution from linear combinations of available scenario years but we have intentionally kept it simple until a satisfying generalization is established.

Other contributions:

To support the implementation of the new provider, we have reviewed and updated the full HazardModel logical chain, from the PregeneratedHazardModel to the ZarrReader. The main changes are:

  • HazardDataProvider was previously defined as an ABC, we have redefined it as a Protocol. Also, the method it must implement is now called just get_data, as opposed to the previous get_data_cascading, as the cascading nature is an implementation detail that can vary and not part of the interface. Consequently we have renamed the existing HazardDataProvider as CascadingHazardDataProvider.
  • We have moved interpolate_years to be an argument of the __init__ of CascadingHazardDataProvider, since an arbitrary HazardDataProvider might not have year interpolation as a toggleable option.
  • We have refactored the logic of PregeneratedHazardModel. Most importantly we have cleaned up the handling of the event loop to stop using the low level threading.Thread that lead to brittle error propagation and replaced it with higher level asyncio and concurrent directives. We have split the previously monolithic _get_cascading_hazard_data_batches containing the closures all_requests and single_indicator into _get_hazard_data_in_batches and _get_batch_data, and replaced closures and mutation of outer state with pure methods and a merge of the different batch results.
  • We have refactored ImageCreator to extract common functionality and implement a ResolvingImageCreator that uses the same ScenarioYearResolver as the hazard model.
  • We have refactored the logic of ZarrReader to avoid duplicate and diverging checking of "in boundness". Previously this was done separately in the in_bounds method and inside the get_curves method. There was an inconsistency in the checking of bounds in the case of "floor" interpolation that could lead to a resource being selected to fulfill a latitude-longitude after a positive in_bounds check and then get_curves failing to provide a curve, this is because in_bounds previously always applied pixel center offsets regardless of the selected interpolation method.

…azard_data_provider.py

Signed-off-by: Juan Roman <jroman@arfimaconsulting.com>
Signed-off-by: Juan Roman <jroman@arfimaconsulting.com>
Signed-off-by: Juan Roman <jroman@arfimaconsulting.com>
Signed-off-by: Juan Roman <jroman@arfimaconsulting.com>
Signed-off-by: Juan Roman <jroman@arfimaconsulting.com>
@jroman-ak

jroman-ak commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

This is work in progress. I opened this PR to spark discussion.

For now, I have only implemented the new protocols that are supposed to replace SourcePaths: HazardResourceProvider and ScenarioYearResolver. To illustrate their use, I have implemented a new hazard model and a new image creator.

I still haven't refactored the existing CascadingHazardDataProvider in terms of the new protocols. This is challenging because it requires generalizing the ScenarioYearResolver protocol to return linear combinations of ScenarioYear, and wire both HazardDataProviders to it.

My intention is that the HazardResourceProvider and the ScenarioYearResolver should be injectable dependencies of a single/unified CascadingHazardDataProvider. The cascading provider's only job would be to handle the cascade based on geographical availability of the ordered list of resources provided by the HazardResourceProvider. For each resource, in would check "in boundness" of every lat-lon, and if positive, it would call the ScenarioYearResolver to obtain a linear combination of the resource's scenario-years with which to fulfill the requester scenario-year.

Furthermore, the HazardModelFactory should pass the same ScenarioYearResolver to both the HazardModel and the ImageCreator, for consistent fetching of map data and map images. The HierarchicalZarrHazardModel is an example of this philosophy.

In contrast, the current CascadingHazardDataProvider delegates some scenario resolution to CoreInventorySourcePaths, while resolving years internally to perform the linear combination.

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.

1 participant