pycontrails 0.54.2__cp312-cp312-macosx_11_0_arm64.whl → 0.54.4__cp312-cp312-macosx_11_0_arm64.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.

Files changed (68) hide show
  1. pycontrails/__init__.py +2 -2
  2. pycontrails/_version.py +2 -2
  3. pycontrails/core/__init__.py +1 -1
  4. pycontrails/core/aircraft_performance.py +75 -61
  5. pycontrails/core/cache.py +7 -7
  6. pycontrails/core/fleet.py +25 -21
  7. pycontrails/core/flight.py +215 -301
  8. pycontrails/core/interpolation.py +56 -56
  9. pycontrails/core/met.py +48 -39
  10. pycontrails/core/models.py +25 -11
  11. pycontrails/core/polygon.py +15 -15
  12. pycontrails/core/rgi_cython.cpython-312-darwin.so +0 -0
  13. pycontrails/core/vector.py +22 -22
  14. pycontrails/datalib/_met_utils/metsource.py +8 -5
  15. pycontrails/datalib/ecmwf/__init__.py +14 -14
  16. pycontrails/datalib/ecmwf/common.py +1 -1
  17. pycontrails/datalib/ecmwf/era5.py +7 -7
  18. pycontrails/datalib/ecmwf/hres.py +3 -3
  19. pycontrails/datalib/ecmwf/ifs.py +1 -1
  20. pycontrails/datalib/ecmwf/variables.py +1 -0
  21. pycontrails/datalib/gfs/__init__.py +6 -6
  22. pycontrails/datalib/gfs/gfs.py +2 -2
  23. pycontrails/datalib/goes.py +5 -5
  24. pycontrails/datalib/landsat.py +5 -8
  25. pycontrails/datalib/sentinel.py +7 -11
  26. pycontrails/ext/bada.py +3 -2
  27. pycontrails/ext/empirical_grid.py +1 -1
  28. pycontrails/ext/synthetic_flight.py +3 -2
  29. pycontrails/models/accf.py +40 -19
  30. pycontrails/models/apcemm/apcemm.py +5 -4
  31. pycontrails/models/cocip/__init__.py +2 -2
  32. pycontrails/models/cocip/cocip.py +16 -17
  33. pycontrails/models/cocip/cocip_params.py +2 -11
  34. pycontrails/models/cocip/cocip_uncertainty.py +24 -18
  35. pycontrails/models/cocip/contrail_properties.py +331 -316
  36. pycontrails/models/cocip/output_formats.py +53 -53
  37. pycontrails/models/cocip/radiative_forcing.py +135 -131
  38. pycontrails/models/cocip/radiative_heating.py +135 -135
  39. pycontrails/models/cocip/unterstrasser_wake_vortex.py +90 -87
  40. pycontrails/models/cocip/wake_vortex.py +92 -92
  41. pycontrails/models/cocip/wind_shear.py +8 -8
  42. pycontrails/models/cocipgrid/cocip_grid.py +118 -107
  43. pycontrails/models/dry_advection.py +59 -58
  44. pycontrails/models/emissions/__init__.py +2 -2
  45. pycontrails/models/emissions/black_carbon.py +108 -108
  46. pycontrails/models/emissions/emissions.py +85 -85
  47. pycontrails/models/emissions/ffm2.py +35 -35
  48. pycontrails/models/humidity_scaling/humidity_scaling.py +23 -23
  49. pycontrails/models/ps_model/__init__.py +3 -2
  50. pycontrails/models/ps_model/ps_aircraft_params.py +11 -6
  51. pycontrails/models/ps_model/ps_grid.py +256 -60
  52. pycontrails/models/ps_model/ps_model.py +18 -21
  53. pycontrails/models/ps_model/ps_operational_limits.py +58 -69
  54. pycontrails/models/tau_cirrus.py +8 -1
  55. pycontrails/physics/geo.py +216 -67
  56. pycontrails/physics/jet.py +220 -90
  57. pycontrails/physics/static/iata-cargo-load-factors-20241115.csv +71 -0
  58. pycontrails/physics/static/iata-passenger-load-factors-20241115.csv +71 -0
  59. pycontrails/physics/units.py +14 -14
  60. pycontrails/utils/json.py +1 -2
  61. pycontrails/utils/types.py +12 -7
  62. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/METADATA +10 -10
  63. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/NOTICE +1 -1
  64. pycontrails-0.54.4.dist-info/RECORD +111 -0
  65. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/WHEEL +1 -1
  66. pycontrails-0.54.2.dist-info/RECORD +0 -109
  67. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/LICENSE +0 -0
  68. {pycontrails-0.54.2.dist-info → pycontrails-0.54.4.dist-info}/top_level.txt +0 -0
@@ -88,13 +88,16 @@ class ACCFParams(ModelParams):
88
88
  h2o_scaling: float = 1.0
89
89
  o3_scaling: float = 1.0
90
90
 
91
- forecast_step: float = 6.0
91
+ forecast_step: float | None = None
92
92
 
93
93
  sep_ri_rw: bool = False
94
94
 
95
95
  climate_indicator: str = "ATR"
96
96
 
97
- horizontal_resolution: float = 0.5
97
+ #: The horizontal resolution of the meteorological data in degrees.
98
+ #: If None, it will be inferred from the ``met`` dataset for :class:`MetDataset`
99
+ #: source, otherwise it will be set to 0.5.
100
+ horizontal_resolution: float | None = None
98
101
 
99
102
  emission_scenario: str = "pulse"
100
103
 
@@ -116,6 +119,8 @@ class ACCFParams(ModelParams):
116
119
 
117
120
  PMO: bool = False
118
121
 
122
+ unit_K_per_kg_fuel: bool = False
123
+
119
124
 
120
125
  class ACCF(Model):
121
126
  """Compute Algorithmic Climate Change Functions (ACCF).
@@ -146,16 +151,13 @@ class ACCF(Model):
146
151
  SpecificHumidity,
147
152
  ecmwf.PotentialVorticity,
148
153
  Geopotential,
149
- RelativeHumidity,
154
+ (RelativeHumidity, ecmwf.RelativeHumidity),
150
155
  NorthwardWind,
151
156
  EastwardWind,
152
- ecmwf.PotentialVorticity,
153
157
  )
154
158
  sur_variables = (ecmwf.SurfaceSolarDownwardRadiation, ecmwf.TopNetThermalRadiation)
155
159
  default_params = ACCFParams
156
160
 
157
- short_vars = frozenset(v.short_name for v in (*met_variables, *sur_variables))
158
-
159
161
  # This variable won't get used since we are not writing the output
160
162
  # anywhere, but the library will complain if it's not defined
161
163
  path_lib = "./"
@@ -168,7 +170,13 @@ class ACCF(Model):
168
170
  **params_kwargs: Any,
169
171
  ) -> None:
170
172
  # Normalize ECMWF variables
171
- met = standardize_variables(met, self.met_variables)
173
+ variables = (v[0] if isinstance(v, tuple) else v for v in self.met_variables)
174
+ met = standardize_variables(met, variables)
175
+
176
+ # If relative humidity is in percentage, convert to a proportion
177
+ if met["relative_humidity"].attrs.get("units") == "%":
178
+ met.data["relative_humidity"] /= 100.0
179
+ met.data["relative_humidity"].attrs["units"] = "1"
172
180
 
173
181
  # Ignore humidity scaling warning
174
182
  with warnings.catch_warnings():
@@ -231,18 +239,21 @@ class ACCF(Model):
231
239
  if hasattr(self, "surface"):
232
240
  self.surface = self.source.downselect_met(self.surface)
233
241
 
234
- if isinstance(self.source, MetDataset):
235
- # Overwrite horizontal resolution to match met
236
- longitude = self.source.data["longitude"].values
237
- if longitude.size > 1:
238
- hres = abs(longitude[1] - longitude[0])
239
- self.params["horizontal_resolution"] = float(hres)
240
-
241
- else:
242
+ if self.params["horizontal_resolution"] is None:
243
+ if isinstance(self.source, MetDataset):
244
+ # Overwrite horizontal resolution to match met
245
+ longitude = self.source.data["longitude"].values
242
246
  latitude = self.source.data["latitude"].values
243
- if latitude.size > 1:
247
+ if longitude.size > 1:
248
+ hres = abs(longitude[1] - longitude[0])
249
+ self.params["horizontal_resolution"] = float(hres)
250
+ elif latitude.size > 1:
244
251
  hres = abs(latitude[1] - latitude[0])
245
252
  self.params["horizontal_resolution"] = float(hres)
253
+ else:
254
+ self.params["horizontal_resolution"] = 0.5
255
+ else:
256
+ self.params["horizontal_resolution"] = 0.5
246
257
 
247
258
  p_settings = _get_accf_config(self.params)
248
259
 
@@ -267,10 +278,14 @@ class ACCF(Model):
267
278
  aCCFs, _ = clim_imp.get_xarray()
268
279
 
269
280
  # assign ACCF outputs to source
281
+ skip = {
282
+ v[0].short_name if isinstance(v, tuple) else v.short_name
283
+ for v in (*self.met_variables, *self.sur_variables)
284
+ }
270
285
  maCCFs = MetDataset(aCCFs)
271
286
  for key, arr in maCCFs.data.items():
272
287
  # skip met variables
273
- if key in self.short_vars:
288
+ if key in skip:
274
289
  continue
275
290
 
276
291
  assert isinstance(key, str)
@@ -292,7 +307,12 @@ class ACCF(Model):
292
307
  # It also needs variables to have the ECMWF short name
293
308
  if isinstance(self.met, MetDataset):
294
309
  ds_met = self.met.data.transpose("time", "level", "latitude", "longitude")
295
- name_dict = {v.standard_name: v.short_name for v in self.met_variables}
310
+ name_dict = {
311
+ v[0].standard_name if isinstance(v, tuple) else v.standard_name: v[0].short_name
312
+ if isinstance(v, tuple)
313
+ else v.short_name
314
+ for v in self.met_variables
315
+ }
296
316
  ds_met = ds_met.rename(name_dict)
297
317
  else:
298
318
  ds_met = None
@@ -340,7 +360,7 @@ def _get_accf_config(params: dict[str, Any]) -> dict[str, Any]:
340
360
  "horizontal_resolution": params["horizontal_resolution"],
341
361
  "forecast_step": params["forecast_step"],
342
362
  "NOx_aCCF": True,
343
- "NOx&inverse_EIs": params["nox_ei"],
363
+ "NOx_EI&F_km": params["nox_ei"],
344
364
  "output_format": "netCDF",
345
365
  "mean": False,
346
366
  "std": False,
@@ -361,6 +381,7 @@ def _get_accf_config(params: dict[str, Any]) -> dict[str, Any]:
361
381
  "H2O": params["h2o_scaling"],
362
382
  "O3": params["o3_scaling"],
363
383
  },
384
+ "unit_K/kg(fuel)": params["unit_K_per_kg_fuel"],
364
385
  "PCFA": params["pfca"],
365
386
  "PCFA-ISSR": {
366
387
  "rhi_threshold": params["issr_rhi_threshold"],
@@ -28,6 +28,7 @@ from pycontrails.core.met_var import (
28
28
  SpecificHumidity,
29
29
  VerticalVelocity,
30
30
  )
31
+ from pycontrails.core.vector import GeoVectorDataset
31
32
  from pycontrails.models.apcemm import utils
32
33
  from pycontrails.models.apcemm.inputs import APCEMMInput
33
34
  from pycontrails.models.dry_advection import DryAdvection
@@ -276,13 +277,13 @@ class APCEMM(models.Model):
276
277
  """
277
278
 
278
279
  __slots__ = (
279
- "apcemm_path",
280
+ "_trajectory_downsampling",
280
281
  "apcemm_input_params",
282
+ "apcemm_path",
281
283
  "cachestore",
284
+ "contrail",
282
285
  "trajectories",
283
286
  "vortex",
284
- "contrail",
285
- "_trajectory_downsampling",
286
287
  )
287
288
 
288
289
  name = "apcemm"
@@ -314,7 +315,7 @@ class APCEMM(models.Model):
314
315
  source: Flight
315
316
 
316
317
  #: Output from trajectory calculation
317
- trajectories: Flight | None
318
+ trajectories: GeoVectorDataset | None
318
319
 
319
320
  #: Time series output from the APCEMM early plume model
320
321
  vortex: pd.DataFrame | None
@@ -15,9 +15,10 @@ from pycontrails.models.cocip.output_formats import (
15
15
 
16
16
  __all__ = [
17
17
  "Cocip",
18
+ "CocipFlightParams",
18
19
  "CocipParams",
19
20
  "CocipUncertaintyParams",
20
- "CocipFlightParams",
21
+ "compare_cocip_with_goes",
21
22
  "contrail_flight_summary_statistics",
22
23
  "contrails_to_hi_res_grid",
23
24
  "flight_waypoint_summary_statistics",
@@ -25,5 +26,4 @@ __all__ = [
25
26
  "longitude_latitude_grid",
26
27
  "natural_cirrus_properties_to_hi_res_grid",
27
28
  "time_slice_statistics",
28
- "compare_cocip_with_goes",
29
29
  ]
@@ -195,14 +195,14 @@ class Cocip(Model):
195
195
  """
196
196
 
197
197
  __slots__ = (
198
- "rad",
198
+ "_downwash_contrail",
199
+ "_downwash_flight",
200
+ "_sac_flight",
199
201
  "contrail",
200
202
  "contrail_dataset",
201
203
  "contrail_list",
204
+ "rad",
202
205
  "timesteps",
203
- "_sac_flight",
204
- "_downwash_flight",
205
- "_downwash_contrail",
206
206
  )
207
207
 
208
208
  name = "cocip"
@@ -660,7 +660,7 @@ class Cocip(Model):
660
660
  attrs = self.source.attrs
661
661
  attrs.pop("fl_attrs", None)
662
662
  attrs.pop("data_keys", None)
663
- self.source = Fleet.from_seq(fls, broadcast_numeric=False, copy=False, attrs=attrs)
663
+ self.source = Fleet.from_seq(fls, broadcast_numeric=False, attrs=attrs)
664
664
 
665
665
  # Single flight
666
666
  else:
@@ -2055,9 +2055,9 @@ def calc_radiative_properties(contrail: GeoVectorDataset, params: dict[str, Any]
2055
2055
 
2056
2056
  def calc_contrail_properties(
2057
2057
  contrail: GeoVectorDataset,
2058
- effective_vertical_resolution: float | npt.NDArray[np.float64],
2059
- wind_shear_enhancement_exponent: float | npt.NDArray[np.float64],
2060
- sedimentation_impact_factor: float | npt.NDArray[np.float64],
2058
+ effective_vertical_resolution: float | npt.NDArray[np.floating],
2059
+ wind_shear_enhancement_exponent: float | npt.NDArray[np.floating],
2060
+ sedimentation_impact_factor: float | npt.NDArray[np.floating],
2061
2061
  radiative_heating_effects: bool,
2062
2062
  ) -> None:
2063
2063
  """Calculate geometric and ice-related properties of contrail.
@@ -2084,11 +2084,11 @@ def calc_contrail_properties(
2084
2084
  ----------
2085
2085
  contrail : GeoVectorDataset
2086
2086
  Grid points with many precomputed keys.
2087
- effective_vertical_resolution : float | npt.NDArray[np.float64]
2087
+ effective_vertical_resolution : float | npt.NDArray[np.floating]
2088
2088
  Passed into :func:`wind_shear.wind_shear_enhancement_factor`.
2089
- wind_shear_enhancement_exponent : float | npt.NDArray[np.float64]
2089
+ wind_shear_enhancement_exponent : float | npt.NDArray[np.floating]
2090
2090
  Passed into :func:`wind_shear.wind_shear_enhancement_factor`.
2091
- sedimentation_impact_factor: float | npt.NDArray[np.float64]
2091
+ sedimentation_impact_factor: float | npt.NDArray[np.floating]
2092
2092
  Passed into `contrail_properties.vertical_diffusivity`.
2093
2093
  radiative_heating_effects: bool
2094
2094
  Include radiative heating effects on contrail cirrus properties.
@@ -2296,8 +2296,7 @@ def calc_timestep_contrail_evolution(
2296
2296
  dt = time_2_array - time_1
2297
2297
 
2298
2298
  # get new contrail location & segment properties after t_step
2299
- longitude_2 = geo.advect_longitude(longitude_1, latitude_1, u_wind_1, dt)
2300
- latitude_2 = geo.advect_latitude(latitude_1, v_wind_1, dt)
2299
+ longitude_2, latitude_2 = geo.advect_horizontal(longitude_1, latitude_1, u_wind_1, v_wind_1, dt)
2301
2300
  level_2 = geo.advect_level(level_1, vertical_velocity_1, rho_air_1, terminal_fall_speed_1, dt)
2302
2301
  altitude_2 = units.pl_to_m(level_2)
2303
2302
 
@@ -2526,8 +2525,8 @@ def calc_timestep_contrail_evolution(
2526
2525
  def _rad_accumulation_to_average_instantaneous(
2527
2526
  rad: MetDataset,
2528
2527
  name: str,
2529
- arr: npt.NDArray[np.float64],
2530
- ) -> npt.NDArray[np.float64]:
2528
+ arr: npt.NDArray[np.floating],
2529
+ ) -> npt.NDArray[np.floating]:
2531
2530
  """Convert from radiation accumulation to average instantaneous values.
2532
2531
 
2533
2532
  .. versionadded:: 0.48.0
@@ -2538,12 +2537,12 @@ def _rad_accumulation_to_average_instantaneous(
2538
2537
  Radiation data
2539
2538
  name : str
2540
2539
  Variable name
2541
- arr : npt.NDArray[np.float64]
2540
+ arr : npt.NDArray[np.floating]
2542
2541
  Array of values already interpolated from ``rad``
2543
2542
 
2544
2543
  Returns
2545
2544
  -------
2546
- npt.NDArray[np.float64]
2545
+ npt.NDArray[np.floating]
2547
2546
  Array of values converted from accumulation to average instantaneous values
2548
2547
 
2549
2548
  Raises
@@ -11,7 +11,7 @@ import numpy as np
11
11
  import numpy.typing as npt
12
12
 
13
13
  from pycontrails.core.aircraft_performance import AircraftPerformance
14
- from pycontrails.core.models import ModelParams
14
+ from pycontrails.core.models import AdvectionBuffers
15
15
  from pycontrails.models.emissions.emissions import EmissionsParams
16
16
  from pycontrails.models.humidity_scaling import HumidityScaling
17
17
 
@@ -50,7 +50,7 @@ def _habits() -> npt.NDArray[np.str_]:
50
50
 
51
51
 
52
52
  @dataclasses.dataclass
53
- class CocipParams(ModelParams):
53
+ class CocipParams(AdvectionBuffers):
54
54
  """Model parameters required by the CoCiP models."""
55
55
 
56
56
  # -------------------------
@@ -116,15 +116,6 @@ class CocipParams(ModelParams):
116
116
  #: evaluation after the met data is downselected.
117
117
  compute_tau_cirrus_in_model_init: bool | str = "auto"
118
118
 
119
- #: Met longitude [WGS84] buffer for Cocip evolution.
120
- met_longitude_buffer: tuple[float, float] = (10.0, 10.0)
121
-
122
- #: Met latitude buffer [WGS84] for Cocip evolution.
123
- met_latitude_buffer: tuple[float, float] = (10.0, 10.0)
124
-
125
- #: Met level buffer [:math:`hPa`] for Cocip initialization and evolution.
126
- met_level_buffer: tuple[float, float] = (40.0, 40.0)
127
-
128
119
  # ---------
129
120
  # Filtering
130
121
  # ---------
@@ -2,8 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import dataclasses
5
6
  import logging
6
- from dataclasses import asdict, dataclass
7
7
  from typing import Any, ClassVar
8
8
 
9
9
  import numpy as np
@@ -70,7 +70,7 @@ class habit_dirichlet(rv_frozen):
70
70
  return habit_weights
71
71
 
72
72
 
73
- @dataclass
73
+ @dataclasses.dataclass
74
74
  class CocipUncertaintyParams(CocipParams):
75
75
  """Model parameters for CoCiP epistemic uncertainty.
76
76
 
@@ -117,26 +117,30 @@ class CocipUncertaintyParams(CocipParams):
117
117
  #: Schumann takes ``wind_shear_enhancement_exponent`` = 0.5 and discusses the case of 0 and 2/3
118
118
  #: as possibilities.
119
119
  #: With a value of 0, wind shear is not enhanced.
120
- wind_shear_enhancement_exponent_uncertainty: rv_frozen | None = stats.triang(
121
- loc=0.0, c=CocipParams.wind_shear_enhancement_exponent, scale=1.0
120
+ wind_shear_enhancement_exponent_uncertainty: rv_frozen | None = dataclasses.field(
121
+ default_factory=lambda: stats.triang(
122
+ loc=0.0, c=CocipParams.wind_shear_enhancement_exponent, scale=1.0
123
+ )
122
124
  )
123
125
 
124
126
  #: Schumann takes ``initial_wake_vortex_depth`` = 0.5 and discusses some
125
127
  #: uncertainty in this value. This parameter should be non-negative.
126
- initial_wake_vortex_depth_uncertainty: rv_frozen | None = stats.triang(
127
- loc=0.3, c=CocipParams.initial_wake_vortex_depth, scale=0.4
128
+ initial_wake_vortex_depth_uncertainty: rv_frozen | None = dataclasses.field(
129
+ default_factory=lambda: stats.triang(
130
+ loc=0.3, c=CocipParams.initial_wake_vortex_depth, scale=0.4
131
+ )
128
132
  )
129
133
 
130
134
  #: Schumann takes a default value of 0.1 and describes it as an "important adjustable parameter"
131
135
  #: Currently, `CocipParams` uses a default value of 0.5
132
- sedimentation_impact_factor_uncertainty: rv_frozen | None = stats.norm(
133
- loc=CocipParams.sedimentation_impact_factor, scale=0.1
136
+ sedimentation_impact_factor_uncertainty: rv_frozen | None = dataclasses.field(
137
+ default_factory=lambda: stats.norm(loc=CocipParams.sedimentation_impact_factor, scale=0.1)
134
138
  )
135
139
 
136
140
  #: Teoh 2022 (to appear) takes values between 70% decrease and 100% increase.
137
141
  #: This coincides with the log normal distribution defined below.
138
- nvpm_ei_n_enhancement_factor_uncertainty: rv_frozen | None = stats.lognorm(
139
- s=0.15, scale=1 / stats.lognorm(s=0.15).mean()
142
+ nvpm_ei_n_enhancement_factor_uncertainty: rv_frozen | None = dataclasses.field(
143
+ default_factory=lambda: stats.lognorm(s=0.15, scale=1 / stats.lognorm(s=0.15).mean())
140
144
  )
141
145
 
142
146
  #: Scale shortwave radiative forcing.
@@ -145,8 +149,8 @@ class CocipUncertaintyParams(CocipParams):
145
149
  #: by `libRadTran <http://www.libradtran.org/doku.php>`_.
146
150
  #: We use the average RMS error across all habit types (pg 1397) as the standard deviation
147
151
  #: of a normally distributed scaling factor for SW forcing
148
- rf_sw_enhancement_factor_uncertainty: rv_frozen | None = stats.norm(
149
- loc=CocipParams.rf_sw_enhancement_factor, scale=0.106
152
+ rf_sw_enhancement_factor_uncertainty: rv_frozen | None = dataclasses.field(
153
+ default_factory=lambda: stats.norm(loc=CocipParams.rf_sw_enhancement_factor, scale=0.106)
150
154
  )
151
155
 
152
156
  #: Scale longwave radiative forcing.
@@ -154,8 +158,8 @@ class CocipUncertaintyParams(CocipParams):
154
158
  #: fit to the data generated by `libRadTran <http://www.libradtran.org/doku.php>`_.
155
159
  #: We use the average RMS error across all habit types (pg 1397) as the standard deviation
156
160
  #: of a normally distributed scaling factor for LW forcing.
157
- rf_lw_enhancement_factor_uncertainty: rv_frozen | None = stats.norm(
158
- loc=CocipParams.rf_lw_enhancement_factor, scale=0.071
161
+ rf_lw_enhancement_factor_uncertainty: rv_frozen | None = dataclasses.field(
162
+ default_factory=lambda: stats.norm(loc=CocipParams.rf_lw_enhancement_factor, scale=0.071)
159
163
  )
160
164
 
161
165
  #: Scale the habit distributions by a dirichlet distribution
@@ -163,7 +167,9 @@ class CocipUncertaintyParams(CocipParams):
163
167
  #: where :math:`\text{G}_{i}` is the approximate habit weight distributions
164
168
  #: defined in :attr:`CocipParams().habit_distributions`.
165
169
  #: Higher values of :math:`\text{C}` correspond to higher confidence in initial estimates.
166
- habit_distributions_uncertainty: rv_frozen | None = habit_dirichlet(C=96.0)
170
+ habit_distributions_uncertainty: rv_frozen | None = dataclasses.field(
171
+ default_factory=habit_dirichlet
172
+ )
167
173
 
168
174
  def __post_init__(self) -> None:
169
175
  """Override values of model parameters according to ranges."""
@@ -192,7 +198,7 @@ class CocipUncertaintyParams(CocipParams):
192
198
 
193
199
  out = {}
194
200
 
195
- param_dict = asdict(self)
201
+ param_dict = dataclasses.asdict(self)
196
202
  for uncertainty_param, dist in param_dict.items():
197
203
  if uncertainty_param.endswith("_uncertainty") and dist is not None:
198
204
  param = uncertainty_param.split("_uncertainty")[0]
@@ -212,7 +218,7 @@ class CocipUncertaintyParams(CocipParams):
212
218
 
213
219
  return out
214
220
 
215
- def rvs(self, size: None | int = None) -> dict[str, np.float64 | npt.NDArray[np.float64]]:
221
+ def rvs(self, size: None | int = None) -> dict[str, np.float64 | npt.NDArray[np.floating]]:
216
222
  """Call each distribution's `rvs` method to generate random parameters.
217
223
 
218
224
  Seed calls to `rvs` with class variable `rng`.
@@ -224,7 +230,7 @@ class CocipUncertaintyParams(CocipParams):
224
230
 
225
231
  Returns
226
232
  -------
227
- dict[str, float | npt.NDArray[np.float64]]
233
+ dict[str, float | npt.NDArray[np.floating]]
228
234
  Dictionary of random parameters. Dictionary keys consists of names of parameters in
229
235
  `CocipParams` to be overridden by random value.
230
236