Skip to content

Commit 50f3fd9

Browse files
committed
Add some documentation
1 parent 23cae6c commit 50f3fd9

File tree

1 file changed

+109
-11
lines changed

1 file changed

+109
-11
lines changed

climada/util/calibrate/impact_func.py

Lines changed: 109 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def impf_step_generator(threshold: Number, paa: Number) -> ImpactFuncSet:
4545
class Input:
4646
"""Define the static input for a calibration task
4747
48-
Parameters
48+
Attributes
4949
----------
5050
hazard : climada.Hazard
5151
Hazard object to compute impacts from
@@ -108,7 +108,21 @@ def __post_init__(self, align):
108108

109109
@dataclass
110110
class Output:
111-
"""Define the output of a calibration task"""
111+
"""Generic output of a calibration task
112+
113+
Attributes
114+
----------
115+
params : Mapping (str, Number)
116+
The optimal parameters
117+
target : Number
118+
The target function value for the optimal parameters
119+
success : bool
120+
If the calibration succeeded. The definition depends on the actual optimization
121+
algorithm used.
122+
result
123+
A result object specific to the optimization algorithm used. See the optimizer
124+
documentation for details.
125+
"""
112126

113127
params: Mapping[str, Number]
114128
target: Number
@@ -118,19 +132,77 @@ class Output:
118132

119133
@dataclass
120134
class Optimizer(ABC):
121-
"""Define the basic interface for an optimization"""
135+
"""Abstract base class (interface) for an optimization
136+
137+
This defines the interface for optimizers in CLIMADA. New optimizers can be created
138+
by deriving from this class and overriding at least the :py:meth:`run` method.
139+
140+
Attributes
141+
----------
142+
input : Input
143+
The input object for the optimization task. See :py:class:`Input`.
144+
"""
122145

123146
input: Input
124147

125-
def _target_func(self, impact: Impact, data: pd.DataFrame):
148+
def _target_func(self, impact: Impact, data: pd.DataFrame) -> Number:
149+
"""Target function for the optimizer
150+
151+
The default version of this function simply returns the value of the cost
152+
function evaluated on the arguments.
153+
154+
Paramters
155+
---------
156+
impact : climada.engine.Impact
157+
The impact object returned by the impact calculation.
158+
data : pandas.DataFrame
159+
The data used for calibration. See :py:attr:`Input.data`.
160+
161+
Returns
162+
-------
163+
The value of the target function for the optimizer.
164+
"""
126165
return self.input.cost_func(impact, data)
127166

128167
def _kwargs_to_impact_func_gen(self, *_, **kwargs) -> Dict[str, Any]:
129-
"""Define how the parameters to 'opt_func' must be transformed"""
168+
"""Define how the parameters to 'opt_func' must be transformed
169+
170+
Optimizers may implement different ways of representing the parameters (e.g.,
171+
key-value pairs, arrays, etc.). Depending on this representation, the parameters
172+
must be transformed to match the syntax of the impact function generator used,
173+
see :py:attr:`Input.impact_func_gen`.
174+
175+
In this default version, the method simply returns its keyword arguments as
176+
mapping. Override this method if the optimizer used *does not* represent
177+
parameters as key-value pairs.
178+
179+
Parameters
180+
----------
181+
kwargs
182+
The parameters as key-value pairs.
183+
184+
Returns
185+
-------
186+
The parameters as key-value pairs.
187+
"""
130188
return kwargs
131189

132-
def _opt_func(self, *args, **kwargs):
133-
"""The optimization function that is iterated"""
190+
def _opt_func(self, *args, **kwargs) -> Number:
191+
"""The optimization function iterated by the optimizer
192+
193+
This function takes arbitrary arguments from the optimizer, generates a new set
194+
of impact functions from it, computes the impact, and finally calculates the
195+
target function value and returns it.
196+
197+
Parameters
198+
----------
199+
args, kwargs
200+
Arbitrary arguments from the optimizer, including parameters
201+
202+
Returns
203+
-------
204+
Target function value for the given arguments
205+
"""
134206
params = self._kwargs_to_impact_func_gen(*args, **kwargs)
135207
impf_set = self.input.impact_func_gen(**params)
136208
impact = ImpactCalc(
@@ -143,7 +215,6 @@ def _opt_func(self, *args, **kwargs):
143215
@abstractmethod
144216
def run(self, **opt_kwargs) -> Output:
145217
"""Execute the optimization"""
146-
pass
147218

148219

149220
@dataclass
@@ -155,14 +226,33 @@ def __post_init__(self):
155226
self._param_names: List[str] = list()
156227

157228
def _kwargs_to_impact_func_gen(self, *args, **_) -> Dict[str, Any]:
229+
"""Transform the array of parameters into key-value pairs"""
158230
return dict(zip(self._param_names, args[0].flat))
159231

160232
def _select_by_param_names(self, mapping: Mapping[str, Any]) -> List[Any]:
161233
"""Return a list of entries from a map with matching keys or ``None``"""
162234
return [mapping.get(key) for key in self._param_names]
163235

164-
def run(self, **opt_kwargs):
165-
"""Execute the optimization"""
236+
def run(self, **opt_kwargs) -> Output:
237+
"""Execute the optimization
238+
239+
Parameters
240+
----------
241+
params_init : Mapping (str, Number)
242+
The initial guess for all parameters as key-value pairs.
243+
method : str, optional
244+
The minimization method applied. Defaults to ``"trust-constr"``.
245+
See https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html
246+
for details.
247+
kwargs
248+
Additional keyword arguments passed to ``scipy.optimize.minimize``.
249+
250+
Returns
251+
-------
252+
output : Output
253+
The output of the optimization. The :py:attr:`Output.result` attribute
254+
stores the associated ``scipy.optimize.OptimizeResult`` instance.
255+
"""
166256
# Parse kwargs
167257
params_init = opt_kwargs.pop("params_init")
168258
method = opt_kwargs.pop("method", "trust-constr")
@@ -213,9 +303,17 @@ def __post_init__(
213303
**bayes_opt_kwds,
214304
)
215305

216-
def run(self, init_points: int = 100, n_iter: int = 200, **opt_kwargs):
306+
def run(self, **opt_kwargs):
217307
"""Execute the optimization"""
308+
# Retrieve parameters
309+
num_params = len(self.input.bounds)
310+
init_points = opt_kwargs.pop("init_points", 10**num_params)
311+
n_iter = opt_kwargs.pop("n_iter", 10**num_params)
312+
313+
# Run optimizer
218314
self.optimizer.maximize(init_points=init_points, n_iter=n_iter, **opt_kwargs)
315+
316+
# Return output
219317
opt = self.optimizer.max
220318
return Output(
221319
params=opt["params"],

0 commit comments

Comments
 (0)