pycontrails 0.41.0__cp39-cp39-win_amd64.whl → 0.42.2__cp39-cp39-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pycontrails might be problematic. Click here for more details.
- pycontrails/_version.py +2 -2
- pycontrails/core/airports.py +228 -0
- pycontrails/core/cache.py +4 -6
- pycontrails/core/datalib.py +13 -6
- pycontrails/core/fleet.py +72 -20
- pycontrails/core/flight.py +485 -134
- pycontrails/core/flightplan.py +238 -0
- pycontrails/core/interpolation.py +11 -15
- pycontrails/core/met.py +5 -5
- pycontrails/core/models.py +4 -0
- pycontrails/core/rgi_cython.cp39-win_amd64.pyd +0 -0
- pycontrails/core/vector.py +80 -63
- pycontrails/datalib/__init__.py +1 -1
- pycontrails/datalib/ecmwf/common.py +14 -19
- pycontrails/datalib/spire/__init__.py +19 -0
- pycontrails/datalib/spire/spire.py +739 -0
- pycontrails/ext/bada/__init__.py +6 -6
- pycontrails/ext/cirium/__init__.py +2 -2
- pycontrails/models/cocip/cocip.py +37 -39
- pycontrails/models/cocip/cocip_params.py +37 -30
- pycontrails/models/cocip/cocip_uncertainty.py +47 -58
- pycontrails/models/cocip/radiative_forcing.py +220 -193
- pycontrails/models/cocip/wake_vortex.py +96 -91
- pycontrails/models/cocip/wind_shear.py +2 -2
- pycontrails/models/emissions/emissions.py +1 -1
- pycontrails/models/humidity_scaling.py +266 -9
- pycontrails/models/issr.py +2 -2
- pycontrails/models/pcr.py +1 -1
- pycontrails/models/quantiles/era5_ensemble_quantiles.npy +0 -0
- pycontrails/models/quantiles/iagos_quantiles.npy +0 -0
- pycontrails/models/sac.py +7 -5
- pycontrails/physics/geo.py +5 -3
- pycontrails/physics/jet.py +66 -113
- pycontrails/utils/json.py +3 -3
- {pycontrails-0.41.0.dist-info → pycontrails-0.42.2.dist-info}/METADATA +4 -7
- {pycontrails-0.41.0.dist-info → pycontrails-0.42.2.dist-info}/RECORD +40 -34
- {pycontrails-0.41.0.dist-info → pycontrails-0.42.2.dist-info}/LICENSE +0 -0
- {pycontrails-0.41.0.dist-info → pycontrails-0.42.2.dist-info}/NOTICE +0 -0
- {pycontrails-0.41.0.dist-info → pycontrails-0.42.2.dist-info}/WHEEL +0 -0
- {pycontrails-0.41.0.dist-info → pycontrails-0.42.2.dist-info}/top_level.txt +0 -0
pycontrails/ext/bada/__init__.py
CHANGED
|
@@ -20,6 +20,12 @@ try:
|
|
|
20
20
|
BADAParams,
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
+
except ImportError as e:
|
|
24
|
+
raise ImportError(
|
|
25
|
+
'Failed to import `pycontrails-bada` extension. Install with `pip install "pycontrails-bada'
|
|
26
|
+
' @ git+ssh://git@github.com/contrailcirrus/pycontrails-bada.git"`'
|
|
27
|
+
) from e
|
|
28
|
+
else:
|
|
23
29
|
__all__ = [
|
|
24
30
|
"BADA",
|
|
25
31
|
"BADA3",
|
|
@@ -33,9 +39,3 @@ try:
|
|
|
33
39
|
"bada4",
|
|
34
40
|
"bada_model",
|
|
35
41
|
]
|
|
36
|
-
|
|
37
|
-
except ImportError as e:
|
|
38
|
-
raise ImportError(
|
|
39
|
-
'Failed to import `pycontrails-bada` extension. Install with `pip install "pycontrails-bada'
|
|
40
|
-
' @ git+ssh://git@github.com/contrailcirrus/pycontrails-bada.git"`'
|
|
41
|
-
) from e
|
|
@@ -5,10 +5,10 @@ from __future__ import annotations
|
|
|
5
5
|
try:
|
|
6
6
|
from pycontrails_cirium import Cirium
|
|
7
7
|
|
|
8
|
-
__all__ = ["Cirium"]
|
|
9
|
-
|
|
10
8
|
except ImportError as e:
|
|
11
9
|
raise ImportError(
|
|
12
10
|
"Failed to import `pycontrails-cirium` extension. Install with `pip install"
|
|
13
11
|
' "pycontrails-cirium @ git+ssh://git@github.com/contrailcirrus/pycontrails-cirium.git"`'
|
|
14
12
|
) from e
|
|
13
|
+
else:
|
|
14
|
+
__all__ = ["Cirium"]
|
|
@@ -7,6 +7,7 @@ import warnings
|
|
|
7
7
|
from typing import Any, NoReturn, Sequence, overload
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
|
+
import numpy.typing as npt
|
|
10
11
|
import pandas as pd
|
|
11
12
|
import xarray as xr
|
|
12
13
|
from overrides import overrides
|
|
@@ -257,7 +258,7 @@ class Cocip(Model):
|
|
|
257
258
|
contrail_dataset: xr.Dataset | None
|
|
258
259
|
|
|
259
260
|
#: Array of np.datetime64 time steps for contrail evolution
|
|
260
|
-
timesteps: np.
|
|
261
|
+
timesteps: npt.NDArray[np.datetime64]
|
|
261
262
|
|
|
262
263
|
#: Parallel copy of flight waypoints after SAC filter applied
|
|
263
264
|
_sac_flight: Flight
|
|
@@ -376,8 +377,9 @@ class Cocip(Model):
|
|
|
376
377
|
# Save humidity scaling type to output attrs
|
|
377
378
|
# NOTE: Do this after _process_flight because that method automatically
|
|
378
379
|
# broadcasts all numeric source params.
|
|
379
|
-
|
|
380
|
-
|
|
380
|
+
humidity_scaling = self.params["humidity_scaling"]
|
|
381
|
+
if humidity_scaling is not None:
|
|
382
|
+
for k, v in humidity_scaling.description.items():
|
|
381
383
|
self.source.attrs[f"humidity_scaling_{k}"] = v
|
|
382
384
|
|
|
383
385
|
if isinstance(self.source, Fleet):
|
|
@@ -488,7 +490,7 @@ class Cocip(Model):
|
|
|
488
490
|
self.source.setdefault("level", self.source.level)
|
|
489
491
|
self.source.setdefault("air_pressure", self.source.air_pressure)
|
|
490
492
|
|
|
491
|
-
core_columns =
|
|
493
|
+
core_columns = ("longitude", "latitude", "altitude", "time")
|
|
492
494
|
for col in core_columns:
|
|
493
495
|
if np.isnan(self.source[col]).any():
|
|
494
496
|
raise ValueError(
|
|
@@ -532,23 +534,20 @@ class Cocip(Model):
|
|
|
532
534
|
# STEP 4: Begin met interpolation
|
|
533
535
|
# Unfortunately we use both "u_wind" and "eastward_wind" to refer to the
|
|
534
536
|
# same variable, so the logic gets a bit more complex.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
for met_variable, fl_variable in variables.items():
|
|
545
|
-
interpolate_met(met, self.source, met_variable, fl_variable, **self.interp_kwargs)
|
|
537
|
+
humidity_scaling = self.params["humidity_scaling"]
|
|
538
|
+
scale_humidity = humidity_scaling is not None and "specific_humidity" not in self.source
|
|
539
|
+
verbose_outputs = self.params["verbose_outputs"]
|
|
540
|
+
|
|
541
|
+
interpolate_met(met, self.source, "air_temperature", **self.interp_kwargs)
|
|
542
|
+
interpolate_met(met, self.source, "specific_humidity", **self.interp_kwargs)
|
|
543
|
+
interpolate_met(met, self.source, "eastward_wind", "u_wind", **self.interp_kwargs)
|
|
544
|
+
interpolate_met(met, self.source, "northward_wind", "v_wind", **self.interp_kwargs)
|
|
546
545
|
|
|
547
546
|
if scale_humidity:
|
|
548
|
-
|
|
547
|
+
humidity_scaling.eval(self.source, copy_source=False)
|
|
549
548
|
|
|
550
549
|
# if humidity_scaling isn't defined, add rhi to source for verbose_outputs
|
|
551
|
-
elif
|
|
550
|
+
elif verbose_outputs:
|
|
552
551
|
self.source["rhi"] = thermo.rhi(
|
|
553
552
|
self.source["specific_humidity"],
|
|
554
553
|
self.source["air_temperature"],
|
|
@@ -556,7 +555,7 @@ class Cocip(Model):
|
|
|
556
555
|
)
|
|
557
556
|
|
|
558
557
|
# Cache extra met properties for post-analysis
|
|
559
|
-
if
|
|
558
|
+
if verbose_outputs:
|
|
560
559
|
interpolate_met(met, self.source, "tau_cirrus", **self.interp_kwargs)
|
|
561
560
|
|
|
562
561
|
# handle ECMWF/GFS ciwc variables
|
|
@@ -568,6 +567,9 @@ class Cocip(Model):
|
|
|
568
567
|
self.source["rho_air"] = thermo.rho_d(
|
|
569
568
|
self.source["air_temperature"], self.source.air_pressure
|
|
570
569
|
)
|
|
570
|
+
self.source["sdr"] = geo.solar_direct_radiation(
|
|
571
|
+
self.source["longitude"], self.source["latitude"], self.source["time"]
|
|
572
|
+
)
|
|
571
573
|
|
|
572
574
|
# STEP 5: Calculate segment-specific properties if they are not already attached
|
|
573
575
|
if "true_airspeed" not in self.source:
|
|
@@ -579,7 +581,8 @@ class Cocip(Model):
|
|
|
579
581
|
)
|
|
580
582
|
if "segment_length" not in self.source:
|
|
581
583
|
self.source["segment_length"] = self.source.segment_length()
|
|
582
|
-
|
|
584
|
+
|
|
585
|
+
max_ = self.source.max_distance_gap
|
|
583
586
|
lim_ = self.params["max_seg_length_m"]
|
|
584
587
|
if max_ > 0.9 * lim_:
|
|
585
588
|
warnings.warn(
|
|
@@ -867,8 +870,9 @@ class Cocip(Model):
|
|
|
867
870
|
**self.interp_kwargs,
|
|
868
871
|
)
|
|
869
872
|
|
|
870
|
-
|
|
871
|
-
|
|
873
|
+
humidity_scaling = self.params["humidity_scaling"]
|
|
874
|
+
if humidity_scaling is not None:
|
|
875
|
+
humidity_scaling.eval(contrail_1, copy_source=False)
|
|
872
876
|
else:
|
|
873
877
|
contrail_1["air_pressure"] = contrail_1.air_pressure
|
|
874
878
|
contrail_1["rhi"] = thermo.rhi(
|
|
@@ -1274,15 +1278,6 @@ class Cocip(Model):
|
|
|
1274
1278
|
Flight or list of Flight objects with empty variables.
|
|
1275
1279
|
"""
|
|
1276
1280
|
|
|
1277
|
-
empty = np.full(shape=len(self.source), fill_value=np.nan)
|
|
1278
|
-
|
|
1279
|
-
self.source["sdr"] = empty.copy()
|
|
1280
|
-
self.source["rsr"] = empty.copy()
|
|
1281
|
-
self.source["olr"] = empty.copy()
|
|
1282
|
-
self.source["rf_sw"] = empty.copy()
|
|
1283
|
-
self.source["rf_lw"] = empty.copy()
|
|
1284
|
-
self.source["rf_net"] = empty.copy()
|
|
1285
|
-
|
|
1286
1281
|
intersection = self.source.data.pop("_met_intersection")
|
|
1287
1282
|
zeros_and_nans = np.where(intersection, 0.0, np.nan)
|
|
1288
1283
|
self.source["ef"] = zeros_and_nans.copy()
|
|
@@ -1830,9 +1825,9 @@ def calc_radiative_properties(contrail: GeoVectorDataset, params: dict[str, Any]
|
|
|
1830
1825
|
|
|
1831
1826
|
def calc_contrail_properties(
|
|
1832
1827
|
contrail: GeoVectorDataset,
|
|
1833
|
-
effective_vertical_resolution: float | np.
|
|
1834
|
-
wind_shear_enhancement_exponent: float | np.
|
|
1835
|
-
sedimentation_impact_factor: float | np.
|
|
1828
|
+
effective_vertical_resolution: float | npt.NDArray[np.float_],
|
|
1829
|
+
wind_shear_enhancement_exponent: float | npt.NDArray[np.float_],
|
|
1830
|
+
sedimentation_impact_factor: float | npt.NDArray[np.float_],
|
|
1836
1831
|
radiative_heating_effects: bool,
|
|
1837
1832
|
) -> None:
|
|
1838
1833
|
"""Calculate geometric and ice-related properties of contrail.
|
|
@@ -1859,10 +1854,12 @@ def calc_contrail_properties(
|
|
|
1859
1854
|
----------
|
|
1860
1855
|
contrail : GeoVectorDataset
|
|
1861
1856
|
Grid points with many precomputed keys.
|
|
1862
|
-
effective_vertical_resolution
|
|
1863
|
-
Passed into :func:`wind_shear.wind_shear_enhancement_factor
|
|
1864
|
-
|
|
1865
|
-
Passed into
|
|
1857
|
+
effective_vertical_resolution : float | npt.NDArray[np.float_]
|
|
1858
|
+
Passed into :func:`wind_shear.wind_shear_enhancement_factor`.
|
|
1859
|
+
wind_shear_enhancement_exponent : float | npt.NDArray[np.float_]
|
|
1860
|
+
Passed into :func:`wind_shear.wind_shear_enhancement_factor`.
|
|
1861
|
+
sedimentation_impact_factor: float | npt.NDArray[np.float_]
|
|
1862
|
+
Passed into `contrail_properties.vertical_diffusivity`.
|
|
1866
1863
|
radiative_heating_effects: bool
|
|
1867
1864
|
Include radiative heating effects on contrail cirrus properties.
|
|
1868
1865
|
"""
|
|
@@ -2141,8 +2138,9 @@ def calc_timestep_contrail_evolution(
|
|
|
2141
2138
|
|
|
2142
2139
|
interpolate_met(met, contrail_2, "specific_humidity", **interp_kwargs)
|
|
2143
2140
|
|
|
2144
|
-
|
|
2145
|
-
|
|
2141
|
+
humidity_scaling = params["humidity_scaling"]
|
|
2142
|
+
if humidity_scaling is not None:
|
|
2143
|
+
humidity_scaling.eval(contrail_2, copy_source=False)
|
|
2146
2144
|
else:
|
|
2147
2145
|
contrail_2["air_pressure"] = contrail_2.air_pressure
|
|
2148
2146
|
contrail_2["rhi"] = thermo.rhi(
|
|
@@ -8,6 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
import dataclasses
|
|
9
9
|
|
|
10
10
|
import numpy as np
|
|
11
|
+
import numpy.typing as npt
|
|
11
12
|
|
|
12
13
|
from pycontrails.core.models import ModelParams
|
|
13
14
|
from pycontrails.models.aircraft_performance import AircraftPerformance
|
|
@@ -15,6 +16,39 @@ from pycontrails.models.emissions.emissions import EmissionsParams
|
|
|
15
16
|
from pycontrails.models.humidity_scaling import HumidityScaling
|
|
16
17
|
|
|
17
18
|
|
|
19
|
+
def _radius_threshold_um() -> npt.NDArray[np.float32]:
|
|
20
|
+
return np.array([5.0, 9.5, 23.0, 190.0, 310.0], dtype=np.float32)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _habit_distributions() -> npt.NDArray[np.float32]:
|
|
24
|
+
return np.array(
|
|
25
|
+
[
|
|
26
|
+
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
|
|
27
|
+
[0.0, 0.3, 0.0, 0.0, 0.0, 0.0, 0.7, 0.0],
|
|
28
|
+
[0.0, 0.3, 0.0, 0.0, 0.3, 0.0, 0.4, 0.0],
|
|
29
|
+
[0.0, 0.5, 0.0, 0.0, 0.15, 0.35, 0.0, 0.0],
|
|
30
|
+
[0.0, 0.45, 0.45, 0.1, 0.0, 0.0, 0.0, 0.0],
|
|
31
|
+
[0.0, 0.0, 0.0, 0.03, 0.97, 0.0, 0.0, 0.0],
|
|
32
|
+
],
|
|
33
|
+
dtype=np.float32,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _habits() -> npt.NDArray[np.str_]:
|
|
38
|
+
return np.array(
|
|
39
|
+
[
|
|
40
|
+
"Sphere",
|
|
41
|
+
"Solid column",
|
|
42
|
+
"Hollow column",
|
|
43
|
+
"Rough aggregate",
|
|
44
|
+
"Rosette-6",
|
|
45
|
+
"Plate",
|
|
46
|
+
"Droxtal",
|
|
47
|
+
"Myhre",
|
|
48
|
+
]
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
18
52
|
@dataclasses.dataclass
|
|
19
53
|
class CocipParams(ModelParams):
|
|
20
54
|
"""Model parameters required by the CoCiP models."""
|
|
@@ -147,45 +181,18 @@ class CocipParams(ModelParams):
|
|
|
147
181
|
#: Radius threshold for regime bins, [:math:`\mu m`]
|
|
148
182
|
#: This is the row index label for ``habit_distributions``.
|
|
149
183
|
#: See Table 2 in :cite:`schumannEffectiveRadiusIce2011`.
|
|
150
|
-
radius_threshold_um: np.ndarray = dataclasses.field(
|
|
151
|
-
default_factory=lambda: np.array([5.0, 9.5, 23.0, 190.0, 310.0], dtype=np.float32)
|
|
152
|
-
)
|
|
184
|
+
radius_threshold_um: np.ndarray = dataclasses.field(default_factory=_radius_threshold_um)
|
|
153
185
|
|
|
154
186
|
#: Particle habit (shape) types.
|
|
155
187
|
#: This is the column index label for ``habit_distributions``.
|
|
156
188
|
#: See Table 2 in :cite:`schumannEffectiveRadiusIce2011`.
|
|
157
|
-
habits: np.ndarray = dataclasses.field(
|
|
158
|
-
default_factory=lambda: np.array(
|
|
159
|
-
[
|
|
160
|
-
"Sphere",
|
|
161
|
-
"Solid column",
|
|
162
|
-
"Hollow column",
|
|
163
|
-
"Rough aggregate",
|
|
164
|
-
"Rosette-6",
|
|
165
|
-
"Plate",
|
|
166
|
-
"Droxtal",
|
|
167
|
-
"Myhre",
|
|
168
|
-
]
|
|
169
|
-
)
|
|
170
|
-
)
|
|
189
|
+
habits: np.ndarray = dataclasses.field(default_factory=_habits)
|
|
171
190
|
|
|
172
191
|
#: Mix of ice particle habits in each radius regime.
|
|
173
192
|
#: Rows indexes are ``radius_threshold_um`` elements.
|
|
174
193
|
#: Columns indexes are ``habits`` particle habit type.
|
|
175
194
|
#: See Table 2 from :cite:`schumannEffectiveRadiusIce2011`.
|
|
176
|
-
habit_distributions: np.ndarray = dataclasses.field(
|
|
177
|
-
default_factory=lambda: np.array(
|
|
178
|
-
[
|
|
179
|
-
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
|
|
180
|
-
[0.0, 0.3, 0.0, 0.0, 0.0, 0.0, 0.7, 0.0],
|
|
181
|
-
[0.0, 0.3, 0.0, 0.0, 0.3, 0.0, 0.4, 0.0],
|
|
182
|
-
[0.0, 0.5, 0.0, 0.0, 0.15, 0.35, 0.0, 0.0],
|
|
183
|
-
[0.0, 0.45, 0.45, 0.1, 0.0, 0.0, 0.0, 0.0],
|
|
184
|
-
[0.0, 0.0, 0.0, 0.03, 0.97, 0.0, 0.0, 0.0],
|
|
185
|
-
],
|
|
186
|
-
dtype=np.float32,
|
|
187
|
-
)
|
|
188
|
-
)
|
|
195
|
+
habit_distributions: np.ndarray = dataclasses.field(default_factory=_habit_distributions)
|
|
189
196
|
|
|
190
197
|
#: Scale shortwave radiative forcing.
|
|
191
198
|
#: Primarily used to support uncertainty estimation.
|
|
@@ -7,11 +7,12 @@ from dataclasses import asdict, dataclass
|
|
|
7
7
|
from typing import Any, ClassVar
|
|
8
8
|
|
|
9
9
|
import numpy as np
|
|
10
|
+
import numpy.typing as npt
|
|
10
11
|
from scipy import stats
|
|
11
12
|
from scipy.stats.distributions import rv_frozen
|
|
12
13
|
|
|
14
|
+
from pycontrails.models.cocip import cocip_params
|
|
13
15
|
from pycontrails.models.cocip.cocip_params import CocipParams
|
|
14
|
-
from pycontrails.models.humidity_scaling import ExponentialBoostHumidityScaling
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
@@ -32,7 +33,7 @@ class habit_dirichlet(rv_frozen):
|
|
|
32
33
|
def __init__(self, C: float = 96.0):
|
|
33
34
|
self.C = C
|
|
34
35
|
|
|
35
|
-
def rvs(self, *args: Any, **kwds: Any) -> np.
|
|
36
|
+
def rvs(self, *args: Any, **kwds: Any) -> npt.NDArray[np.float32]:
|
|
36
37
|
"""Generate sample set of habit distributions.
|
|
37
38
|
|
|
38
39
|
Sampled using dirichlet distribution.
|
|
@@ -46,20 +47,25 @@ class habit_dirichlet(rv_frozen):
|
|
|
46
47
|
|
|
47
48
|
Returns
|
|
48
49
|
-------
|
|
49
|
-
np.
|
|
50
|
+
npt.NDArray[np.float32]
|
|
50
51
|
Sampled habit weight distribution with the same shape
|
|
51
52
|
as :attr:`CocipParams().habit_distributions`
|
|
52
53
|
"""
|
|
53
|
-
if args or (
|
|
54
|
+
if args or (kwds.get("size") is not None and kwds["size"] > 1):
|
|
54
55
|
raise ValueError("habit_dirichlet distribution only supports creating one rv at a time")
|
|
55
56
|
|
|
56
|
-
default_distributions =
|
|
57
|
-
alpha_i =
|
|
58
|
-
|
|
57
|
+
default_distributions = cocip_params._habit_distributions()
|
|
58
|
+
alpha_i = 0.5 + self.C * default_distributions
|
|
59
|
+
|
|
60
|
+
# In the first distribution, we assume all ice particles are droxtals
|
|
61
|
+
# There is no way to quantify the uncertainty in this assumption
|
|
62
|
+
# Consequently, we leave the first distribution in default_distributions
|
|
63
|
+
# alone, and only perturb the rest
|
|
64
|
+
distr_list = [stats.dirichlet(a) for a in alpha_i[1:]]
|
|
59
65
|
|
|
60
66
|
habit_weights = default_distributions.copy()
|
|
61
|
-
for i in
|
|
62
|
-
habit_weights[i] = distr
|
|
67
|
+
for i, distr in enumerate(distr_list, start=1):
|
|
68
|
+
habit_weights[i] = distr.rvs(**kwds)
|
|
63
69
|
|
|
64
70
|
return habit_weights
|
|
65
71
|
|
|
@@ -81,17 +87,19 @@ class CocipUncertaintyParams(CocipParams):
|
|
|
81
87
|
>>> import scipy.stats
|
|
82
88
|
>>> from pycontrails.models.cocip import CocipUncertaintyParams
|
|
83
89
|
|
|
84
|
-
# Override the
|
|
85
|
-
>>>
|
|
86
|
-
>>>
|
|
87
|
-
>>> params
|
|
88
|
-
|
|
90
|
+
>>> # Override the 'initial_wake_vortex_depth' field from
|
|
91
|
+
>>> # CocipParams with a uniform value in [0.4, 0.6]
|
|
92
|
+
>>> distr = scipy.stats.uniform(loc=0.4, scale=0.2)
|
|
93
|
+
>>> params = CocipUncertaintyParams(seed=123, initial_wake_vortex_depth_uncertainty=distr)
|
|
94
|
+
>>> params.initial_wake_vortex_depth
|
|
95
|
+
0.41076420
|
|
89
96
|
|
|
90
|
-
# Once seeded, calling the class again gives a new value
|
|
91
|
-
>>> params = CocipUncertaintyParams(
|
|
92
|
-
>>> params.
|
|
93
|
-
0.
|
|
97
|
+
>>> # Once seeded, calling the class again gives a new value
|
|
98
|
+
>>> params = CocipUncertaintyParams(initial_wake_vortex_depth=distr)
|
|
99
|
+
>>> params.initial_wake_vortex_depth
|
|
100
|
+
0.43526372
|
|
94
101
|
|
|
102
|
+
>>> # To retain the default value, set the uncertainty to None
|
|
95
103
|
>>> params = CocipUncertaintyParams(rf_lw_enhancement_factor_uncertainty=None)
|
|
96
104
|
>>> params.rf_lw_enhancement_factor
|
|
97
105
|
1.0
|
|
@@ -106,23 +114,6 @@ class CocipUncertaintyParams(CocipParams):
|
|
|
106
114
|
#: Reseed the random generator defined in ``__post_init__``
|
|
107
115
|
seed: int | None = None
|
|
108
116
|
|
|
109
|
-
# This might need fixing!
|
|
110
|
-
# Whenever we overhaul / redo an uncertainty analysis, we may need to change
|
|
111
|
-
# how it interacts with a humidity scaler
|
|
112
|
-
humidity_scaling: ExponentialBoostHumidityScaling = ExponentialBoostHumidityScaling()
|
|
113
|
-
|
|
114
|
-
#: Parameters for specific humidity and RHi enhancement
|
|
115
|
-
#: This assumes Cocip.Params.humidity_scaling is an
|
|
116
|
-
#: :class:`ExponentialBoostHumidityScaling`` instance.
|
|
117
|
-
rhi_adj_uncertainty: rv_frozen | None = stats.norm(
|
|
118
|
-
loc=ExponentialBoostHumidityScaling.default_params.rhi_adj, scale=0.1
|
|
119
|
-
)
|
|
120
|
-
rhi_boost_exponent_uncertainty: rv_frozen = stats.triang(
|
|
121
|
-
loc=1.0,
|
|
122
|
-
c=ExponentialBoostHumidityScaling.default_params.rhi_boost_exponent - 1.0,
|
|
123
|
-
scale=1.0,
|
|
124
|
-
)
|
|
125
|
-
|
|
126
117
|
#: Schumann takes ``wind_shear_enhancement_exponent`` = 0.5 and discusses the case of 0 and 2/3
|
|
127
118
|
#: as possibilities.
|
|
128
119
|
#: With a value of 0, wind shear is not enhanced.
|
|
@@ -172,7 +163,7 @@ class CocipUncertaintyParams(CocipParams):
|
|
|
172
163
|
#: where :math:`\text{G}_{i}` is the approximate habit weight distributions
|
|
173
164
|
#: defined in :attr:`CocipParams().habit_distributions`.
|
|
174
165
|
#: Higher values of :math:`\text{C}` correspond to higher confidence in initial estimates.
|
|
175
|
-
habit_distributions_uncertainty: rv_frozen | None = habit_dirichlet(C=96)
|
|
166
|
+
habit_distributions_uncertainty: rv_frozen | None = habit_dirichlet(C=96.0)
|
|
176
167
|
|
|
177
168
|
def __post_init__(self) -> None:
|
|
178
169
|
"""Override values of model parameters according to ranges."""
|
|
@@ -221,7 +212,7 @@ class CocipUncertaintyParams(CocipParams):
|
|
|
221
212
|
|
|
222
213
|
return out
|
|
223
214
|
|
|
224
|
-
def rvs(self, size: None | int = None) -> dict[str, float | np.
|
|
215
|
+
def rvs(self, size: None | int = None) -> dict[str, float | npt.NDArray[np.float_]]:
|
|
225
216
|
"""Call each distribution's `rvs` method to generate random parameters.
|
|
226
217
|
|
|
227
218
|
Seed calls to `rvs` with class variable `rng`.
|
|
@@ -233,7 +224,7 @@ class CocipUncertaintyParams(CocipParams):
|
|
|
233
224
|
|
|
234
225
|
Returns
|
|
235
226
|
-------
|
|
236
|
-
dict[str, float | np.
|
|
227
|
+
dict[str, float | npt.NDArray[np.float_]]
|
|
237
228
|
Dictionary of random parameters. Dictionary keys consists of names of parameters in
|
|
238
229
|
`CocipParams` to be overridden by random value.
|
|
239
230
|
|
|
@@ -244,26 +235,24 @@ class CocipUncertaintyParams(CocipParams):
|
|
|
244
235
|
>>> params = CocipUncertaintyParams(seed=456)
|
|
245
236
|
>>> pprint(params.rvs())
|
|
246
237
|
{'habit_distributions': array([[0.0000000e+00, 0.0000000e+00, 0.0000000e+00, 0.0000000e+00,
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
'sedimentation_impact_factor': 0.6433086271594898,
|
|
266
|
-
'wind_shear_enhancement_exponent': 0.31735944665388505}
|
|
238
|
+
0.0000000e+00, 0.0000000e+00, 1.0000000e+00, 0.0000000e+00],
|
|
239
|
+
[1.5554131e-02, 2.1363135e-01, 7.7715185e-03, 1.7690966e-02,
|
|
240
|
+
3.1576434e-03, 3.2992734e-06, 7.4009895e-01, 2.0921326e-03],
|
|
241
|
+
[3.8193921e-03, 2.1235342e-01, 3.3554080e-04, 5.2846869e-04,
|
|
242
|
+
3.1945917e-01, 4.8709914e-04, 4.6250960e-01, 5.0730183e-04],
|
|
243
|
+
[5.7327619e-04, 4.7781631e-01, 4.2596990e-03, 6.7235163e-04,
|
|
244
|
+
1.4447135e-01, 3.6184600e-01, 1.0150939e-02, 2.1006212e-04],
|
|
245
|
+
[1.5397545e-02, 4.0522218e-01, 4.2781001e-01, 1.4331797e-01,
|
|
246
|
+
7.1088417e-04, 9.4511814e-04, 3.3900745e-03, 3.2062260e-03],
|
|
247
|
+
[7.9063961e-04, 3.0336906e-03, 7.7571563e-04, 2.0577813e-02,
|
|
248
|
+
9.4205803e-01, 4.3379897e-03, 3.6786550e-03, 2.4747452e-02]],
|
|
249
|
+
dtype=float32),
|
|
250
|
+
'initial_wake_vortex_depth': 0.39805019708566847,
|
|
251
|
+
'nvpm_ei_n_enhancement_factor': 0.9371878437312526,
|
|
252
|
+
'rf_lw_enhancement_factor': 1.1017491252832377,
|
|
253
|
+
'rf_sw_enhancement_factor': 0.99721639115012,
|
|
254
|
+
'sedimentation_impact_factor': 0.5071779847244678,
|
|
255
|
+
'wind_shear_enhancement_exponent': 0.34100931239701004}
|
|
267
256
|
"""
|
|
268
257
|
return {
|
|
269
258
|
param: distr.rvs(size=size, random_state=self.rng)
|