-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy path__init__.py
209 lines (189 loc) · 5.23 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# -*- mode: python; coding: utf-8 -*-
#
# Copyright (C) 2023 Benjamin Thomas Schwertfeger
# All rights reserved.
# https://github.com/btschwertfeger
#
# pylint: disable=consider-using-f-string,logging-not-lazy
r"""
Module providing the a method named "adjust" to apply different bias
correction techniques to time-series climate data.
Some variables used in this package:
T = Temperatures ($T$)
X = Some climate variable ($X$)
h = historical
p = scenario; future; predicted
obs = observed data ($T_{obs,h}$)
simh = modeled data with same time period as obs ($T_{sim,h}$)
simp = data to correct (predicted simulated data) ($T_{sim,p}$)
F = Cumulative Distribution Function
\mu = mean
\sigma = standard deviation
i = index
_{m} = long-term monthly interval
"""
from __future__ import annotations
import logging
import sys
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from cloup import Context
import cloup
import xarray as xr
from click import echo
from cloup import HelpFormatter, HelpTheme, Path, Style, command, option, option_group
from cloup.constraints import Equal, If, require_all
from cmethods.core import adjust
__all__ = ["adjust"]
def print_version(
ctx: Context,
param: Any, # noqa: ARG001
value: Any,
) -> None:
"""Prints the version of the package"""
if not value or ctx.resilient_parsing:
return
from importlib.metadata import version # noqa: PLC0415
echo(version("python-cmethods"))
ctx.exit()
@command(
context_settings={
"auto_envvar_prefix": "CMETHODS",
"help_option_names": ["-h", "--help"],
},
formatter_settings=HelpFormatter.settings(
theme=HelpTheme(
invoked_command=Style(fg="bright_yellow"),
heading=Style(fg="bright_white", bold=True),
constraint=Style(fg="magenta"),
col1=Style(fg="bright_yellow"),
),
),
)
@option(
"--version",
is_flag=True,
callback=print_version,
expose_value=False,
is_eager=True,
)
@option(
"--obs",
"--observations",
required=True,
type=Path(exists=True),
help="Reference data set (control period)",
)
@option(
"--simh",
"--simulated-historical",
required=True,
type=Path(exists=True),
help="Modeled data set (control period)",
)
@option(
"--simp",
"--simulated-scenario",
required=True,
type=Path(exists=True),
help="Modeled data set (scenario period)",
)
@option(
"--method",
required=True,
type=cloup.Choice(
[
"linear_scaling",
"variance_scaling",
"delta_method",
"quantile_mapping",
"quantile_delta_mapping",
],
case_sensitive=False,
),
help="Bias adjustment method to apply",
)
@option(
"--kind",
required=True,
type=cloup.Choice(["+", "add", "*", "mult"]),
help="Kind of adjustment",
)
@option(
"--variable",
required=True,
type=str,
help="Variable of interest",
)
@option(
"-o",
"--output",
required=True,
type=str,
callback=lambda _, __, value: (value if value.endswith(".nc") else f"{value}.nc"),
help="Output file name",
)
@option_group(
"Scaling-Based Adjustment Options",
option(
"--group",
type=str,
help="Temporal grouping",
),
constraint=If(
Equal("method", "linear_scaling") & Equal("method", "variance_scaling") & Equal("method", "delta_method"),
then=require_all,
),
)
@option_group(
"Distribution-Based Adjustment Options",
option(
"--quantiles",
type=int,
help="Quantiles to respect",
),
constraint=If(
Equal("method", "quantile_mapping") & Equal("method", "quantile_delta_mapping"),
then=require_all,
),
)
def cli(**kwargs) -> None:
"""
Command-line tool to apply bias correction procedures to climate data.
Copyright (C) 2023 Benjamin Thomas Schwertfeger\n
GitHub: https://github.com/btschwertfeger/python-cmethods
"""
logging.basicConfig(
format="%(asctime)s %(levelname)8s | %(message)s",
datefmt="%Y/%m/%d %H:%M:%S",
level=logging.INFO,
)
log = logging.getLogger(__name__)
log.info("Loading data sets ...")
try:
for key, message in zip(
("obs", "simh", "simp"),
(
"observation data set",
"modeled data set of the control period",
"modeled data set of the scenario period",
),
):
kwargs[key] = xr.open_dataset(kwargs[key])
if not isinstance(kwargs[key], xr.Dataset):
raise TypeError("The data sets must be type xarray.Dataset")
if kwargs["variable"] not in kwargs[key]:
raise KeyError(
f"Variable '{kwargs['variable']}' is missing in the {message}",
)
kwargs[key] = kwargs[key][kwargs["variable"]]
except (TypeError, KeyError) as exc:
log.error(exc)
sys.exit(1)
log.info("Data sets loaded ...")
kwargs["n_quantiles"] = kwargs["quantiles"]
del kwargs["quantiles"]
log.info("Applying %s ...", kwargs["method"])
result = adjust(**kwargs)
log.info("Saving result to %s ...", kwargs["output"])
result.to_netcdf(kwargs["output"])