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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ all = { composite = ["lint", "mypy", "pytest"] }
complete = { call = "tasks.complete:main", help = "Create autocomplete files for bash and fish" }

[project.scripts]
os_climate_hazard = "hazard.cli:cli"
os_climate_hazard = "hazard.cli.cli_legacy:cli"
osc_hazard = "hazard.cli:app"

[tool.ruff]
Expand Down
31 changes: 27 additions & 4 deletions src/hazard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@
from hazard.onboard.global_seismic_hazard_v2023_1 import GEMSeismicHazard
from hazard.onboard.indicator_model_onboarder import (
DaysTasAboveIndicator,
DaysTasAboveIndicatorDeprecated,
DaysWBGTAboveIndicator,
DegreeDays,
DroughtIndicator,
HeatingCoolingDegreeDays,
HeatingCoolingDegreeDaysDeprecated,
WaterTemperatureAboveIndicator,
WetBulbGlobeTemperatureAboveIndicator,
WorkLossIndicator,
Expand All @@ -38,13 +41,16 @@
_onboarder_classes: list[Type[Onboarder]] = [
DavydzenkaEtAlLandSubsidence,
DaysTasAboveIndicator,
DaysTasAboveIndicatorDeprecated,
DaysWBGTAboveIndicator,
DegreeDays,
DroughtIndicator,
ETHZurichLitPop,
FireRiskIndicators,
FLOPROSFloodStandardOfProtection,
GEMSeismicHazard,
HeatingCoolingDegreeDays,
HeatingCoolingDegreeDaysDeprecated,
IPCCDrought,
IRISIndicator,
JRCLandslides,
Expand Down Expand Up @@ -73,9 +79,9 @@
DegreeDays,
Jupiter,
WorkLossIndicator,
DaysTasAboveIndicator,
DaysTasAboveIndicatorDeprecated,
IRISIndicator,
HeatingCoolingDegreeDays,
HeatingCoolingDegreeDaysDeprecated,
WaterTemperatureAboveIndicator,
WetBulbGlobeTemperatureAboveIndicator,
WRIAqueductWaterRisk,
Expand All @@ -88,6 +94,14 @@
JRCRiverFlood,
]

# v3 replacements of the v2 chronic heat indicators: used in place of these in the inventory
# when get_inventory_hazards is called with heat_v3=True
_inventory_heat_v3_replacements: Dict[Type[Onboarder], Type[Onboarder]] = {
DaysTasAboveIndicatorDeprecated: DaysTasAboveIndicator,
HeatingCoolingDegreeDaysDeprecated: HeatingCoolingDegreeDays,
WetBulbGlobeTemperatureAboveIndicator: DaysWBGTAboveIndicator,
}

hazard_map: Dict[str, Type[Onboarder]] = {
cls.__name__: cls for cls in _onboarder_classes
}
Expand All @@ -101,8 +115,17 @@ def get_hazards_onboarding() -> Dict[str, Type[Onboarder]]:
return hazard_map


def get_inventory_hazards() -> Dict[str, Type[Onboarder]]:
def get_inventory_hazards(heat_v3: bool = False) -> Dict[str, Type[Onboarder]]:
"""Return the subset of onboardable hazards considered ready to be published in
the inventory/catalog -- see _inventory_classes.

Args:
heat_v3 (bool, optional): If True, the v3 chronic heat indicators replace the v2 ones
(see _inventory_heat_v3_replacements), in the same positions. Defaults to False.
"""
return inventory_hazard_map
if not heat_v3:
return inventory_hazard_map
classes = [
_inventory_heat_v3_replacements.get(cls, cls) for cls in _inventory_classes
]
return {cls.__name__: cls for cls in classes}
138 changes: 0 additions & 138 deletions src/hazard/cli.py

This file was deleted.

9 changes: 9 additions & 0 deletions src/hazard/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Command line interfaces for hazard.

`osc_hazard` (hazard.cli.main) onboards hazards generically; `os_climate_hazard`
(hazard.cli.cli_legacy) supports the legacy per-indicator commands.
"""

from hazard.cli.main import app

__all__ = ["app"]
73 changes: 48 additions & 25 deletions src/hazard/services.py → src/hazard/cli/cli_legacy.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
"""Services Module for Hazard Indicators."""
"""Legacy command line interface for hazard indicators (`os_climate_hazard`).

import logging # noqa: E402
Kept for the CWL application package (hazard_workflow.cwl) and the Docker image,
which call e.g. `os_climate_hazard days_tas_above_indicator --store ...`. Each
command here is a hand-written wrapper around a specific (v2) model, so adding an
indicator means adding another command.

The generic way is to onboard hazards like any other: indicator models are wrapped
as onboarders (see hazard.onboard.indicator_model_onboarder) and run via
`osc_hazard onboard` (hazard.cli.main) or hazard.onboard.general_onboarding.
New indicators should not be added here.
"""

import logging
from enum import Enum
from typing import Any, Dict, Optional, Sequence, Tuple

from dask.distributed import Client, LocalCluster # noqa: E402
import fire
from dask.distributed import Client, LocalCluster

from hazard.docs_store import DocStore # type: ignore
from hazard.models.degree_days import DegreeDays
from hazard.models.deprecated_v2 import DaysTasAboveIndicatorDeprecated
from hazard.sources import get_source_dataset_instance
from hazard.sources.osc_zarr import OscZarr

from hazard.docs_store import DocStore # type: ignore # noqa: E402
from hazard.models.days_tas_above import DaysTasAboveIndicator # noqa: E402
from hazard.models.degree_days import DegreeDays # noqa: E402
from hazard.sources import SourceDataset, get_source_dataset_instance
from hazard.sources.osc_zarr import OscZarr # noqa: E402

logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s",
)
class SourceDataset(str, Enum):
NEX_GDDP_CMIP6 = "NEX-GDDP-CMIP6"
UKCP18 = "UKCP18"


def days_tas_above_indicator(
source_dataset: SourceDataset = "NEX-GDDP-CMIP6",
source_dataset: SourceDataset = SourceDataset.NEX_GDDP_CMIP6,
source_dataset_kwargs: Optional[Dict[str, Any]] = None,
gcm_list: Sequence[str] = ["NorESM2-MM"],
scenario_list: Sequence[str] = ["ssp585"],
Expand All @@ -31,6 +44,7 @@ def days_tas_above_indicator(
store: Optional[str] = None,
store_netcdf_coords: Optional[bool] = False,
dask_cluster_kwargs: Optional[Dict[str, Any]] = None,
**kwargs, # To allow for extra parameters to the cli, due to how CWL will provide all input parameters
):
"""Run the days_tas_above indicator generation for a list of models,scenarios, thresholds, central years and a given size of years window over which to compute the average.

Expand All @@ -42,19 +56,16 @@ def days_tas_above_indicator(
bucket, prefix, store, store_netcdf_coords, dask_cluster_kwargs
)

source_dataset_kwargs = (
{} if source_dataset_kwargs is None else source_dataset_kwargs
)
source = get_source_dataset_instance(source_dataset, source_dataset_kwargs)
source = get_source_dataset_instance(source_dataset, source_dataset_kwargs or {}) # type: ignore

model = DaysTasAboveIndicator(
model = DaysTasAboveIndicatorDeprecated(
threshold_temps_c=threshold_list,
window_years=window_years,
gcms=gcm_list,
scenarios=scenario_list,
central_years=central_year_list,
central_year_historical=central_year_historical,
source_dataset=source_dataset,
source_dataset=source_dataset, # type: ignore
)

docs_store.update_inventory(model.inventory())
Expand All @@ -63,7 +74,7 @@ def days_tas_above_indicator(


def degree_days_indicator(
source_dataset: SourceDataset = "NEX-GDDP-CMIP6",
source_dataset: SourceDataset = SourceDataset.NEX_GDDP_CMIP6,
source_dataset_kwargs: Optional[Dict[str, Any]] = None,
gcm_list: Sequence[str] = ["NorESM2-MM"],
scenario_list: Sequence[str] = ["ssp585"],
Expand All @@ -76,6 +87,7 @@ def degree_days_indicator(
store: Optional[str] = None,
store_netcdf_coords: Optional[bool] = False,
dask_cluster_kwargs: Optional[Dict[str, Any]] = None,
**kwargs, # To allow for extra parameters to the cli, due to how CWL will provide all input parameters
):
"""Run the degree days indicator generation for a list of models,scenarios, a threshold temperature, central years and a given size of years window over which to compute the average.

Expand All @@ -87,10 +99,7 @@ def degree_days_indicator(
bucket, prefix, store, store_netcdf_coords, dask_cluster_kwargs
)

source_dataset_kwargs = (
{} if source_dataset_kwargs is None else source_dataset_kwargs
)
source = get_source_dataset_instance(source_dataset, source_dataset_kwargs)
source = get_source_dataset_instance(source_dataset, source_dataset_kwargs or {}) # type: ignore

model = DegreeDays(
threshold=threshold_temperature,
Expand All @@ -99,7 +108,7 @@ def degree_days_indicator(
scenarios=scenario_list,
central_years=central_year_list,
central_year_historical=central_year_historical,
source_dataset=source_dataset,
source_dataset=source_dataset, # type: ignore
)

docs_store.update_inventory(model.inventory())
Expand Down Expand Up @@ -136,3 +145,17 @@ def setup(
client = Client(cluster)

return docs_store, target, client


class Cli(object):
def __init__(self) -> None:
self.days_tas_above_indicator = days_tas_above_indicator
self.degree_days_indicator = degree_days_indicator


def cli():
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s",
)
fire.Fire(Cli)
Loading
Loading