pycontrails 0.54.12__cp311-cp311-macosx_11_0_arm64.whl → 0.55.0__cp311-cp311-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.

pycontrails/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.54.12'
32
- __version_tuple__ = version_tuple = (0, 54, 12)
31
+ __version__ = version = '0.55.0'
32
+ __version_tuple__ = version_tuple = (0, 55, 0)
33
33
 
34
- __commit_id__ = commit_id = 'g5920a0c98'
34
+ __commit_id__ = commit_id = 'g113bce45e'
@@ -27,7 +27,7 @@ from pycontrails.core.met_var import MetVariable
27
27
  from pycontrails.core.models import Model, interpolate_met
28
28
  from pycontrails.core.vector import GeoVectorDataset, VectorDataDict
29
29
  from pycontrails.datalib import ecmwf, gfs
30
- from pycontrails.models import sac, tau_cirrus
30
+ from pycontrails.models import extended_k15, sac, tau_cirrus
31
31
  from pycontrails.models.cocip import (
32
32
  contrail_properties,
33
33
  radiative_forcing,
@@ -58,7 +58,7 @@ class Cocip(Model):
58
58
  rad : MetDataset
59
59
  Single level dataset containing top of atmosphere radiation fluxes.
60
60
  See *Notes* for variable names by data source.
61
- params : dict[str, Any], optional
61
+ params : dict[str, Any] | None, optional
62
62
  Override Cocip model parameters with dictionary.
63
63
  See :class:`CocipFlightParams` for model parameters.
64
64
  **params_kwargs : Any
@@ -411,7 +411,7 @@ class Cocip(Model):
411
411
 
412
412
  Returns
413
413
  -------
414
- Flight | list[Flight] | NoReturn
414
+ Flight | list[Flight]
415
415
  Flight(s) with updated Contrail data. The model parameter "verbose_outputs"
416
416
  determines the variables on the return flight object.
417
417
 
@@ -489,7 +489,7 @@ class Cocip(Model):
489
489
 
490
490
  Returns
491
491
  -------
492
- tuple[MetVariable]
492
+ tuple[MetVariable, ...]
493
493
  List of model-agnostic variants of required variables
494
494
  """
495
495
  available = set(met_var.MET_VARIABLES)
@@ -501,7 +501,7 @@ class Cocip(Model):
501
501
 
502
502
  Returns
503
503
  -------
504
- tuple[MetVariable]
504
+ tuple[MetVariable, ...]
505
505
  List of ECMWF-specific variants of required variables
506
506
  """
507
507
  available = set(ecmwf.ECMWF_VARIABLES)
@@ -513,7 +513,7 @@ class Cocip(Model):
513
513
 
514
514
  Returns
515
515
  -------
516
- tuple[MetVariable]
516
+ tuple[MetVariable, ...]
517
517
  List of GFS-specific variants of required variables
518
518
  """
519
519
  available = set(gfs.GFS_VARIABLES)
@@ -981,6 +981,30 @@ class Cocip(Model):
981
981
  )
982
982
  iwc_1 = contrail_properties.iwc_post_wake_vortex(iwc, iwc_ad)
983
983
 
984
+ if self.params["vpm_activation"]:
985
+ # We can add a Cocip parameter for T_exhaust, vpm_ei_n, and particles
986
+ aei = extended_k15.droplet_apparent_emission_index(
987
+ specific_humidity=specific_humidity,
988
+ T_ambient=air_temperature,
989
+ T_exhaust=self.source.attrs.get("T_exhaust", extended_k15.DEFAULT_EXHAUST_T),
990
+ air_pressure=air_pressure,
991
+ nvpm_ei_n=nvpm_ei_n,
992
+ vpm_ei_n=self.source.attrs.get("vpm_ei_n", extended_k15.DEFAULT_VPM_EI_N),
993
+ G=self._sac_flight["G"],
994
+ )
995
+ min_aei = None # don't clip
996
+
997
+ else:
998
+ f_activation = contrail_properties.ice_particle_activation_rate(
999
+ air_temperature, T_critical_sac
1000
+ )
1001
+ aei = nvpm_ei_n * f_activation
1002
+ min_aei = self.params["min_ice_particle_number_nvpm_ei_n"]
1003
+
1004
+ n_ice_per_m_0 = contrail_properties.initial_ice_particle_number(
1005
+ aei=aei, fuel_dist=fuel_dist, min_aei=min_aei
1006
+ )
1007
+
984
1008
  if self.params["unterstrasser_ice_survival_fraction"]:
985
1009
  wingspan = self._sac_flight.get_data_or_attr("wingspan")
986
1010
  rhi_0 = thermo.rhi(specific_humidity, air_temperature, air_pressure)
@@ -997,13 +1021,6 @@ class Cocip(Model):
997
1021
  else:
998
1022
  f_surv = contrail_properties.ice_particle_survival_fraction(iwc, iwc_1)
999
1023
 
1000
- n_ice_per_m_0 = contrail_properties.initial_ice_particle_number(
1001
- nvpm_ei_n=nvpm_ei_n,
1002
- fuel_dist=fuel_dist,
1003
- air_temperature=air_temperature,
1004
- T_crit_sac=T_critical_sac,
1005
- min_ice_particle_number_nvpm_ei_n=self.params["min_ice_particle_number_nvpm_ei_n"],
1006
- )
1007
1024
  n_ice_per_m_1 = n_ice_per_m_0 * f_surv
1008
1025
 
1009
1026
  # Check for persistent initial_contrails
@@ -195,8 +195,8 @@ class CocipParams(AdvectionBuffers):
195
195
  nvpm_ei_n_enhancement_factor: float = 1.0
196
196
 
197
197
  #: Lower bound for ``nvpm_ei_n`` to account for ambient aerosol
198
- #: particles for newer engines, [:math:`kg^{-1}`]
199
- min_ice_particle_number_nvpm_ei_n: float = 1e13
198
+ #: particles for newer engines, [:math:`kg^{-1}`]. Set to None to disable.
199
+ min_ice_particle_number_nvpm_ei_n: float | None = 1e13
200
200
 
201
201
  #: Upper bound for contrail plume depth, constraining it to realistic values.
202
202
  #: CoCiP only uses the ambient conditions at the mid-point of the Gaussian plume,
@@ -223,11 +223,17 @@ class CocipParams(AdvectionBuffers):
223
223
  #: .. versionadded:: 0.28.9
224
224
  radiative_heating_effects: bool = False
225
225
 
226
+ #: Experimental. Apply the extended K15 model to account for vPM activation.
227
+ #: See the preprint `<https://doi.org/10.5194/egusphere-2025-1717>`_ for details.
228
+ #:
229
+ #: .. versionadded:: 0.55.0
230
+ vpm_activation: bool = False
231
+
226
232
  #: Experimental. Radiative effects due to contrail-contrail overlapping
227
233
  #: Account for change in local contrail shortwave and longwave radiative forcing
228
234
  #: due to contrail-contrail overlapping.
229
235
  #:
230
- #: .. versionadded:: 0.45
236
+ #: .. versionadded:: 0.45.0
231
237
  contrail_contrail_overlapping: bool = False
232
238
 
233
239
  #: Experimental. Contrail-contrail overlapping altitude interval
@@ -40,9 +40,9 @@ class habit_dirichlet(rv_frozen):
40
40
 
41
41
  Parameters
42
42
  ----------
43
- *args
43
+ *args : Any
44
44
  Used to create a number of habit distributions
45
- **kwds
45
+ **kwds : Any
46
46
  Passed through to :func:`scipy.stats.dirichlet.rvs()`
47
47
 
48
48
  Returns
@@ -190,7 +190,7 @@ class CocipUncertaintyParams(CocipParams):
190
190
 
191
191
  Returns
192
192
  -------
193
- dict[str, dict[str, Any]]
193
+ dict[str, rv_frozen]
194
194
  Uncertainty parameters and values
195
195
  """
196
196
  # handle these differently starting in version 0.27.0
@@ -230,7 +230,7 @@ class CocipUncertaintyParams(CocipParams):
230
230
 
231
231
  Returns
232
232
  -------
233
- dict[str, float | npt.NDArray[np.floating]]
233
+ dict[str, np.float64 | npt.NDArray[np.floating]]
234
234
  Dictionary of random parameters. Dictionary keys consists of names of parameters in
235
235
  `CocipParams` to be overridden by random value.
236
236
 
@@ -202,32 +202,32 @@ def iwc_post_wake_vortex(
202
202
 
203
203
 
204
204
  def initial_ice_particle_number(
205
- nvpm_ei_n: npt.NDArray[np.floating],
205
+ aei: npt.NDArray[np.floating],
206
206
  fuel_dist: npt.NDArray[np.floating],
207
- air_temperature: npt.NDArray[np.floating],
208
- T_crit_sac: npt.NDArray[np.floating],
209
- min_ice_particle_number_nvpm_ei_n: float,
207
+ min_aei: float | None,
210
208
  ) -> npt.NDArray[np.floating]:
211
209
  """Calculate the initial number of ice particles per distance after the wake vortex phase.
212
210
 
213
- The initial number of ice particle per distance is calculated from the black
214
- carbon number emissions index ``nvpm_ei_n`` and fuel burn per distance ``fuel_dist``.
215
- Note that a lower bound for ``nvpm_ei_n`` is set at ``1e13`` :math:`kg^{-1}` to account
211
+ The initial number of ice particle per distance is calculated from the activated apparent
212
+ emissions index ``aei`` and fuel burn per distance ``fuel_dist``.
213
+ Note that a lower bound for ``aei`` is set at ``1e13`` :math:`kg^{-1}` to account
216
214
  for the activation of ambient aerosol particles and organic volatile particles.
217
215
 
216
+ .. versionchanged:: 0.55
217
+
218
+ The signature of this function has changed. The parameter ``aei`` is now
219
+ expected to be the previous ``npvm_ei_n`` multiplied by the activation
220
+ fraction ``f_activation``.
221
+
218
222
  Parameters
219
223
  ----------
220
- nvpm_ei_n : npt.NDArray[np.floating]
221
- black carbon number emissions index, [:math:`kg^{-1}`]
224
+ aei : npt.NDArray[np.floating]
225
+ Apparent contrail emissions index, [:math:`kg^{-1}`]
222
226
  fuel_dist : npt.NDArray[np.floating]
223
- fuel consumption of the flight segment per distance traveled, [:math:`kg m^{-1}`]
224
- air_temperature : npt.NDArray[np.floating]
225
- ambient temperature for each waypoint, [:math:`K`]
226
- T_crit_sac : npt.NDArray[np.floating]
227
- estimated Schmidt-Appleman temperature threshold for contrail formation, [:math:`K`]
228
- min_ice_particle_number_nvpm_ei_n : float
229
- lower bound for nvpm_ei_n to account for ambient aerosol particles for
230
- newer engines [:math:`kg^{-1}`]
227
+ Fuel consumption of the flight segment per distance traveled, [:math:`kg m^{-1}`]
228
+ min_aei : float | None
229
+ Lower bound for ``aei`` to account for ambient aerosol particles for
230
+ newer engines [:math:`kg^{-1}`]. If None, no clipping is applied.
231
231
 
232
232
  Returns
233
233
  -------
@@ -235,9 +235,9 @@ def initial_ice_particle_number(
235
235
  The initial number of ice particles per distance before the wake vortex
236
236
  phase, [:math:`# m^{-1}`]
237
237
  """
238
- f_activation = ice_particle_activation_rate(air_temperature, T_crit_sac)
239
- nvpm_ei_n_activated = nvpm_ei_n * f_activation
240
- return fuel_dist * np.maximum(nvpm_ei_n_activated, min_ice_particle_number_nvpm_ei_n)
238
+ if min_aei is not None:
239
+ aei = np.clip(aei, min=min_aei) # type: ignore[arg-type,call-overload]
240
+ return fuel_dist * aei
241
241
 
242
242
 
243
243
  def ice_particle_activation_rate(
@@ -462,9 +462,9 @@ def _within_range(
462
462
  ----------
463
463
  val : np.ndarray
464
464
  value of selected contrail property
465
- max : np.ndarray | float | np.timedelta64 | None, optional
465
+ max : float | np.timedelta64 | None, optional
466
466
  Upper bound. If None, no upper bound is imposed. None by default.
467
- min : np.ndarray | float | np.timedelta64 | None, optional
467
+ min : float | np.timedelta64 | None, optional
468
468
  Lower bound. If None, no lower bound is imposed. None by default.
469
469
 
470
470
  Returns
@@ -585,9 +585,9 @@ def contrail_vertices(
585
585
 
586
586
  Returns
587
587
  -------
588
- tuple[npt.NDArray[np.floating], npt.NDArray[np.floating], npt.NDArray[np.floating], npt.NDArray[np.floating]]
588
+ tuple
589
589
  (lon_1, lat_1, lon_2, lat_2, lon_3, lat_3, lon_4, lat_4) degrees
590
- """ # noqa: E501
590
+ """
591
591
  dlon_width = units.m_to_longitude_distance(width * sin_a * 0.5, lat)
592
592
  dlat_width = units.m_to_latitude_distance(width * cos_a * 0.5)
593
593
 
@@ -888,9 +888,9 @@ def vertical_diffusivity(
888
888
  Temperature gradient with respect to altitude (dz), [:math:`K m^{-1}`]
889
889
  depth_eff : npt.NDArray[np.floating]
890
890
  Effective depth of the contrail plume, [:math:`m`]
891
- terminal_fall_speed : npt.NDArray[np.floating]
891
+ terminal_fall_speed : npt.NDArray[np.floating] | float
892
892
  Terminal fall speed of contrail ice particles, [:math:`m s^{-1}`]
893
- sedimentation_impact_factor : float
893
+ sedimentation_impact_factor : npt.NDArray[np.floating] | float
894
894
  Enhancement parameter denoted by `f_T` in eq. (35) Schumann (2012).
895
895
  eff_heat_rate: npt.NDArray[np.floating] | None
896
896
  Effective heating rate, i.e., rate of which the contrail plume
@@ -1506,7 +1506,7 @@ def mean_energy_flux_per_m(
1506
1506
  rad_flux_per_m : npt.NDArray[np.floating]
1507
1507
  Mean radiative flux between time steps for waypoint, [:math:`W m^{-1}`].
1508
1508
  See :func:`mean_radiative_flux_per_m`.
1509
- dt : npt.NDArray[np.timedelta64]
1509
+ dt : npt.NDArray[np.timedelta64] | np.timedelta64
1510
1510
  timedelta of integration timestep for each waypoint.
1511
1511
 
1512
1512
  Returns
@@ -241,7 +241,7 @@ def habit_weight_regime_idx(
241
241
 
242
242
  def effective_radius_by_habit(
243
243
  r_vol_um: npt.NDArray[np.floating], habit_idx: npt.NDArray[np.intp]
244
- ) -> np.ndarray:
244
+ ) -> npt.NDArray[np.floating]:
245
245
  r"""Calculate the effective radius ``r_eff_um`` via the mean ice particle radius and habit type.
246
246
 
247
247
  The ``habit_idx`` corresponds to the habit types in ``rf_const.habits``.
@@ -479,7 +479,7 @@ def longwave_radiative_forcing(
479
479
  habit_weights_ : npt.NDArray[np.floating]
480
480
  Weights to different ice particle habits for each waypoint,
481
481
  ``n_waypoints x 8`` (habit) columns, [:math:`[0 - 1]`]
482
- r_eff_um : npt.NDArray[np.floating], optional
482
+ r_eff_um : npt.NDArray[np.floating] | None, optional
483
483
  Provide effective radius corresponding to elements in ``r_vol_um``, [:math:`\mu m`].
484
484
  Defaults to None, which means the effective radius will be calculated using ``r_vol_um``
485
485
  and habit types in :func:`effective_radius_by_habit`.
@@ -583,7 +583,7 @@ def shortwave_radiative_forcing(
583
583
  habit_weights_ : npt.NDArray[np.floating]
584
584
  Weights to different ice particle habits for each waypoint,
585
585
  ``n_waypoints x 8`` (habit) columns, [:math:`[0 - 1]`]
586
- r_eff_um : npt.NDArray[np.floating], optional
586
+ r_eff_um : npt.NDArray[np.floating] | None, optional
587
587
  Provide effective radius corresponding to elements in ``r_vol_um``, [:math:`\mu m`].
588
588
  Defaults to None, which means the effective radius will be calculated using ``r_vol_um``
589
589
  and habit types in :func:`effective_radius_by_habit`.
@@ -923,7 +923,7 @@ def contrail_contrail_overlap_radiative_effects(
923
923
  min_altitude_m : float
924
924
  Minimum altitude domain in simulation, [:math:`m`]
925
925
  See :attr:`CocipParams.min_altitude_m`
926
- max_altitude_m
926
+ max_altitude_m : float
927
927
  Maximum altitude domain in simulation, [:math:`m`]
928
928
  See :attr:`CocipParams.min_altitude_m`
929
929
  dz_overlap_m : float
@@ -284,7 +284,7 @@ def z_emit_length_scale_analytical(
284
284
 
285
285
  Parameters
286
286
  ----------
287
- rho_emit : npt.NDArray[np.floating] | float
287
+ rho_emit : npt.NDArray[np.floating]
288
288
  Aircraft-emitted water vapour concentration in the plume, [:math:`kg m^{-3}`]
289
289
  air_temperature : npt.NDArray[np.floating]
290
290
  ambient temperature for each waypoint, [:math:`K`]
@@ -317,7 +317,7 @@ def z_emit_length_scale_numerical(
317
317
 
318
318
  Parameters
319
319
  ----------
320
- rho_emit : npt.NDArray[np.floating] | float
320
+ rho_emit : npt.NDArray[np.floating]
321
321
  Aircraft-emitted water vapour concentration in the plume, [:math:`kg m^{-3}`]
322
322
  air_temperature : npt.NDArray[np.floating]
323
323
  ambient temperature for each waypoint, [:math:`K`]
@@ -365,7 +365,7 @@ def plume_area(wingspan: npt.NDArray[np.floating] | float) -> npt.NDArray[np.flo
365
365
 
366
366
  Returns
367
367
  -------
368
- float
368
+ npt.NDArray[np.floating] | float
369
369
  Area of two wake-vortex plumes, [:math:`m^{2}`]
370
370
 
371
371
  Notes
@@ -396,7 +396,7 @@ def z_desc_length_scale(
396
396
  pressure altitude at each waypoint, [:math:`Pa`]
397
397
  true_airspeed : npt.NDArray[np.floating]
398
398
  true airspeed for each waypoint, [:math:`m s^{-1}`]
399
- aircraft_mass : npt.NDArray[np.floating] | float
399
+ aircraft_mass : npt.NDArray[np.floating]
400
400
  aircraft mass for each waypoint, [:math:`kg`]
401
401
  dT_dz : npt.NDArray[np.floating]
402
402
  potential temperature gradient, [:math:`K m^{-1}`]
@@ -436,7 +436,7 @@ def _initial_wake_vortex_circulation(
436
436
  pressure altitude at each waypoint, [:math:`Pa`]
437
437
  true_airspeed : npt.NDArray[np.floating]
438
438
  true airspeed for each waypoint, [:math:`m s^{-1}`]
439
- aircraft_mass : npt.NDArray[np.floating] | float
439
+ aircraft_mass : npt.NDArray[np.floating]
440
440
  aircraft mass for each waypoint, [:math:`kg`]
441
441
 
442
442
  Returns
@@ -39,7 +39,7 @@ def max_downward_displacement(
39
39
  ds_dz: npt.NDArray[np.floating],
40
40
  air_pressure: npt.NDArray[np.floating],
41
41
  effective_vertical_resolution: float,
42
- wind_shear_enhancement_exponent: float | npt.NDArray[np.floating],
42
+ wind_shear_enhancement_exponent: npt.NDArray[np.floating] | float,
43
43
  ) -> npt.NDArray[np.floating]:
44
44
  """
45
45
  Calculate the maximum contrail downward displacement after the wake vortex phase.
@@ -117,11 +117,11 @@ def effective_time_scale(
117
117
 
118
118
  Parameters
119
119
  ----------
120
- wingspan : npt.NDArray[np.floating]
120
+ wingspan : npt.NDArray[np.floating] | float
121
121
  aircraft wingspan, [:math:`m`]
122
122
  true_airspeed : npt.NDArray[np.floating]
123
123
  true airspeed for each waypoint, [:math:`m \ s^{-1}`]
124
- aircraft_mass : npt.NDArray[np.floating]
124
+ aircraft_mass : npt.NDArray[np.floating] | float
125
125
  aircraft mass for each waypoint, [:math:`kg`]
126
126
  rho_air : npt.NDArray[np.floating]
127
127
  density of air for each waypoint, [:math:`kg \ m^{-3}`]
@@ -260,7 +260,7 @@ def wake_vortex_separation(
260
260
 
261
261
  Returns
262
262
  -------
263
- npt.NDArray[np.floating]
263
+ npt.NDArray[np.floating] | float
264
264
  wake vortex separation, [:math:`m`]
265
265
  """
266
266
  return (np.pi * wingspan) / 4.0
@@ -320,9 +320,9 @@ def normalized_dissipation_rate(
320
320
  aircraft wingspan, [:math:`m`]
321
321
  true_airspeed : npt.NDArray[np.floating]
322
322
  true airspeed for each waypoint, [:math:`m s^{-1}`]
323
- aircraft_mass : npt.NDArray[np.floating]
323
+ aircraft_mass : npt.NDArray[np.floating] | float
324
324
  aircraft mass for each waypoint, [:math:`kg`]
325
- rho_air : npt.NDArray[np.floating]
325
+ rho_air : npt.NDArray[np.floating] | float
326
326
  density of air for each waypoint, [:math:`kg m^{-3}`]
327
327
 
328
328
  Returns
@@ -16,7 +16,7 @@ import pycontrails
16
16
  from pycontrails.core import models
17
17
  from pycontrails.core.met import MetDataset, maybe_downselect_mds
18
18
  from pycontrails.core.vector import GeoVectorDataset, VectorDataset
19
- from pycontrails.models import humidity_scaling, sac
19
+ from pycontrails.models import extended_k15, humidity_scaling, sac
20
20
  from pycontrails.models.cocip import cocip, contrail_properties, wake_vortex, wind_shear
21
21
  from pycontrails.models.cocipgrid.cocip_grid_params import CocipGridParams
22
22
  from pycontrails.models.emissions import Emissions
@@ -36,13 +36,15 @@ class CocipGrid(models.Model):
36
36
 
37
37
  Parameters
38
38
  ----------
39
- met, rad : MetDataset
39
+ met : MetDataset
40
40
  CoCiP-specific met data to interpolate against
41
- params : dict[str, Any], optional
41
+ rad : MetDataset
42
+ CoCiP-specific radiation data to interpolate against
43
+ params : dict[str, Any] | None, optional
42
44
  Override :class:`CocipGridParams` defaults. Most notably, the model is highly
43
45
  dependent on the parameter ``dt_integration``. Memory usage is also affected by
44
46
  parameters ``met_slice_dt`` and ``target_split_size``.
45
- param_kwargs : Any
47
+ **params_kwargs : Any
46
48
  Override CocipGridParams defaults with arbitrary keyword arguments.
47
49
 
48
50
  Notes
@@ -126,10 +128,7 @@ class CocipGrid(models.Model):
126
128
  raise NotImplementedError(msg)
127
129
 
128
130
  if self.params["unterstrasser_ice_survival_fraction"]:
129
- msg = (
130
- "Parameter 'unterstrasser_ice_survival_fraction' is not "
131
- "yet implemented in CocipGrid"
132
- )
131
+ msg = "Parameter 'unterstrasser_ice_survival_fraction' is not implemented in CocipGrid"
133
132
  raise NotImplementedError(msg)
134
133
 
135
134
  self._target_dtype = np.result_type(*self.met.data.values())
@@ -767,20 +766,26 @@ class CocipGrid(models.Model):
767
766
 
768
767
  Parameters
769
768
  ----------
770
- level : level: npt.NDArray[np.floating] | list[float] | float
769
+ level : npt.NDArray[np.floating] | list[float] | float
771
770
  Pressure levels for gridded cocip.
772
771
  To avoid interpolating outside of the passed ``met`` and ``rad`` data, this
773
772
  parameter should avoid the extreme values of the ``met`` and `rad` levels.
774
773
  If ``met`` is already defined, a good choice for ``level`` is
775
774
  ``met.data['level'].values[1: -1]``.
776
- time: npt.NDArray[np.datetime64 | list[np.datetime64] | np.datetime64,
775
+ time : npt.NDArray[np.datetime64] | list[np.datetime64] | np.datetime64
777
776
  One or more time values for gridded cocip.
778
- longitude, latitude : npt.NDArray[np.floating] | list[float], optional
779
- Longitude and latitude arrays, by default None. If not specified, values of
777
+ longitude : npt.NDArray[np.floating] | list[float] | None, optional
778
+ Longitude array, by default None. If not specified, values of
779
+ ``lon_step`` and ``lat_step`` are used to define ``longitude`` and ``latitude``.
780
+ latitude : npt.NDArray[np.floating] | list[float] | None, optional
781
+ Latitude array, by default None. If not specified, values of
780
782
  ``lon_step`` and ``lat_step`` are used to define ``longitude`` and ``latitude``.
781
- lon_step, lat_step : float, optional
782
- Longitude and latitude resolution, by default 1.0.
783
- Only used if parameter ``longitude`` (respective ``latitude``) not specified.
783
+ lon_step : float, optional
784
+ Longitude resolution, by default 1.0.
785
+ Only used if parameter ``longitude`` not specified.
786
+ lat_step : float, optional
787
+ Latitude resolution, by default 1.0.
788
+ Only used if parameter ``latitude`` not specified.
784
789
 
785
790
  Returns
786
791
  -------
@@ -899,14 +904,16 @@ def run_interpolators(
899
904
  ----------
900
905
  vector : GeoVectorDataset
901
906
  Grid points.
902
- met, rad : MetDataset
903
- CoCiP met and rad slices. See :class:`CocipGrid`.
907
+ met : MetDataset
908
+ CoCiP met slices. See :class:`CocipGrid`.
909
+ rad : MetDataset | None, optional
910
+ CoCiP rad slices. If ``keys`` is not None, this parameter must be None.
904
911
  dz_m : float | None, optional
905
912
  Difference in altitude between top and bottom layer for stratification calculations (m).
906
913
  Must be specified if ``keys`` is None.
907
914
  humidity_scaling : humidity_scaling.HumidityScaling | None, optional
908
915
  Specific humidity scaling scheme. Must be specified if ``keys`` is None.
909
- keys : list[str]
916
+ keys : Sequence[str] | None, optional
910
917
  Only run interpolators for select keys from ``met``
911
918
  **interp_kwargs : Any
912
919
  Interpolation keyword arguments
@@ -1067,8 +1074,10 @@ def _evolve_vector(
1067
1074
  ----------
1068
1075
  vector : GeoVectorDataset
1069
1076
  Contrail points that have been initialized and are ready for evolution.
1070
- met, rad : MetDataset
1071
- CoCiP met and rad slices. See :class:`CocipGrid`.
1077
+ met : MetDataset
1078
+ CoCiP met slices. See :class:`CocipGrid`.
1079
+ rad : MetDataset
1080
+ CoCiP rad slices. See :class:`CocipGrid`.
1072
1081
  params : dict[str, Any]
1073
1082
  CoCiP model parameters. See :class:`CocipGrid`.
1074
1083
  t : np.datetime64
@@ -1124,8 +1133,10 @@ def _run_downwash(
1124
1133
  ----------
1125
1134
  vector : GeoVectorDataset
1126
1135
  Grid values
1127
- met, rad : MetDataset
1128
- CoCiP met and rad slices. See :class:`CocipGrid`.
1136
+ met : MetDataset
1137
+ CoCiP met slices. See :class:`CocipGrid`.
1138
+ rad : MetDataset
1139
+ CoCiP rad slices. See :class:`CocipGrid`.
1129
1140
  params : dict[str, Any]
1130
1141
  CoCiP model parameters. See :class:`CocipGrid`.
1131
1142
 
@@ -1297,6 +1308,8 @@ def find_initial_contrail_regions(
1297
1308
  # which is why we compute it here
1298
1309
  T_crit_sac = sac.T_critical_sac(t_sat_liq[filt], rh[filt], G[filt])
1299
1310
  filtered_vector["T_crit_sac"] = T_crit_sac
1311
+ if params["vpm_activation"]:
1312
+ filtered_vector["G"] = G[filt] # only used in vpm_activation
1300
1313
  return filtered_vector, pd.Series(data=sac_, index=vector["index"])
1301
1314
 
1302
1315
 
@@ -1487,14 +1500,29 @@ def find_initial_persistent_contrails(
1487
1500
  air_pressure_1=air_pressure_1,
1488
1501
  )
1489
1502
  iwc_1 = contrail_properties.iwc_post_wake_vortex(iwc, iwc_ad)
1490
- f_surv = contrail_properties.ice_particle_survival_fraction(iwc, iwc_1)
1503
+
1504
+ if params["vpm_activation"]:
1505
+ # We can add a Cocip parameter for T_exhaust, vpm_ei_n, and particles
1506
+ aei = extended_k15.droplet_apparent_emission_index(
1507
+ specific_humidity=specific_humidity,
1508
+ T_ambient=air_temperature,
1509
+ T_exhaust=vector.attrs.get("T_exhaust", extended_k15.DEFAULT_EXHAUST_T),
1510
+ air_pressure=air_pressure,
1511
+ nvpm_ei_n=nvpm_ei_n,
1512
+ vpm_ei_n=vector.attrs.get("vpm_ei_n", extended_k15.DEFAULT_VPM_EI_N),
1513
+ G=vector["G"],
1514
+ )
1515
+ min_aei = None
1516
+ else:
1517
+ f_activ = contrail_properties.ice_particle_activation_rate(air_temperature, T_crit_sac)
1518
+ aei = nvpm_ei_n * f_activ
1519
+ min_aei = params["min_ice_particle_number_nvpm_ei_n"]
1520
+
1491
1521
  n_ice_per_m_0 = contrail_properties.initial_ice_particle_number(
1492
- nvpm_ei_n=nvpm_ei_n,
1493
- fuel_dist=fuel_dist,
1494
- air_temperature=air_temperature,
1495
- T_crit_sac=T_crit_sac,
1496
- min_ice_particle_number_nvpm_ei_n=params["min_ice_particle_number_nvpm_ei_n"],
1522
+ aei=aei, fuel_dist=fuel_dist, min_aei=min_aei
1497
1523
  )
1524
+
1525
+ f_surv = contrail_properties.ice_particle_survival_fraction(iwc, iwc_1)
1498
1526
  n_ice_per_m_1 = n_ice_per_m_0 * f_surv
1499
1527
 
1500
1528
  # The logic below corresponds to Cocip._create_downwash_contrail (roughly)
@@ -2131,7 +2159,7 @@ def result_to_metdataset(
2131
2159
  result : VectorDataset | None
2132
2160
  Aggregated data arising from contrail evolution. Expected to contain keys:
2133
2161
  ``index``, ``age``, ``ef``.
2134
- verbose_dict : dict[str, npt.NDArray[np.floating]]:
2162
+ verbose_dict : dict[str, npt.NDArray[np.floating]]
2135
2163
  Verbose outputs to attach to results.
2136
2164
  source : MetDataset
2137
2165
  :attr:`CocipGrid.`source` data on which to attach results.
@@ -2366,11 +2394,11 @@ def _check_coverage(
2366
2394
 
2367
2395
  Parameters
2368
2396
  ----------
2369
- met_array : np.ndarray
2397
+ met_array : npt.NDArray[_T]
2370
2398
  Coordinate on met data
2371
- grid_array : np.ndarray
2399
+ grid_array : npt.NDArray[_T]
2372
2400
  Coordinate on grid data
2373
- coord : {"longitude", "latitude", "level", "time"}
2401
+ coord : str
2374
2402
  Name of coordinate. Only used for warning message.
2375
2403
  name : str
2376
2404
  Name of met dataset. Only used for warning message.
@@ -137,14 +137,14 @@ class DryAdvection(models.Model):
137
137
 
138
138
  Parameters
139
139
  ----------
140
- source : GeoVectorDataset
140
+ source : GeoVectorDataset | None
141
141
  Arbitrary points to advect. A :class:`Flight` instance is not treated any
142
142
  differently than a :class:`GeoVectorDataset`. In particular, the user must
143
143
  explicitly set ``flight["azimuth"] = flight.segment_azimuth()`` if they
144
144
  want to use wind shear effects for a flight.
145
145
  In the current implementation, any existing meteorological variables in the ``source``
146
146
  are ignored. The ``source`` will be interpolated against the :attr:`met` dataset.
147
- params : Any
147
+ **params : Any
148
148
  Overwrite model parameters defined in ``__init__``.
149
149
 
150
150
  Returns