pycontrails 0.54.7__cp312-cp312-macosx_11_0_arm64.whl → 0.54.9__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.
- pycontrails/_version.py +9 -4
- pycontrails/core/aircraft_performance.py +48 -35
- pycontrails/core/cache.py +4 -0
- pycontrails/core/flightplan.py +10 -2
- pycontrails/core/met.py +12 -7
- pycontrails/core/models.py +54 -9
- pycontrails/core/rgi_cython.cpython-312-darwin.so +0 -0
- pycontrails/core/vector.py +11 -3
- pycontrails/datalib/goes.py +146 -2
- pycontrails/datalib/spire/spire.py +6 -8
- pycontrails/ext/synthetic_flight.py +1 -1
- pycontrails/models/cocip/cocip.py +14 -5
- pycontrails/models/cocip/contrail_properties.py +4 -6
- pycontrails/models/cocip/output_formats.py +12 -4
- pycontrails/models/cocip/radiative_forcing.py +2 -8
- pycontrails/models/cocipgrid/cocip_grid.py +11 -11
- pycontrails/models/humidity_scaling/humidity_scaling.py +49 -4
- pycontrails/models/ps_model/ps_aircraft_params.py +1 -1
- pycontrails/models/ps_model/ps_grid.py +22 -22
- pycontrails/models/ps_model/ps_model.py +7 -13
- pycontrails/models/ps_model/static/{ps-aircraft-params-20240524.csv → ps-aircraft-params-20250328.csv} +58 -57
- pycontrails/models/ps_model/static/{ps-synonym-list-20240524.csv → ps-synonym-list-20250328.csv} +1 -0
- pycontrails/models/tau_cirrus.py +1 -0
- pycontrails/physics/jet.py +5 -4
- pycontrails/physics/static/{iata-cargo-load-factors-20241115.csv → iata-cargo-load-factors-20250221.csv} +3 -0
- pycontrails/physics/static/{iata-passenger-load-factors-20241115.csv → iata-passenger-load-factors-20250221.csv} +3 -0
- {pycontrails-0.54.7.dist-info → pycontrails-0.54.9.dist-info}/METADATA +3 -2
- {pycontrails-0.54.7.dist-info → pycontrails-0.54.9.dist-info}/RECORD +32 -32
- {pycontrails-0.54.7.dist-info → pycontrails-0.54.9.dist-info}/WHEEL +2 -1
- {pycontrails-0.54.7.dist-info → pycontrails-0.54.9.dist-info/licenses}/LICENSE +0 -0
- {pycontrails-0.54.7.dist-info → pycontrails-0.54.9.dist-info/licenses}/NOTICE +0 -0
- {pycontrails-0.54.7.dist-info → pycontrails-0.54.9.dist-info}/top_level.txt +0 -0
|
@@ -997,14 +997,14 @@ class Cocip(Model):
|
|
|
997
997
|
else:
|
|
998
998
|
f_surv = contrail_properties.ice_particle_survival_fraction(iwc, iwc_1)
|
|
999
999
|
|
|
1000
|
-
|
|
1000
|
+
n_ice_per_m_0 = contrail_properties.initial_ice_particle_number(
|
|
1001
1001
|
nvpm_ei_n=nvpm_ei_n,
|
|
1002
1002
|
fuel_dist=fuel_dist,
|
|
1003
|
-
f_surv=f_surv,
|
|
1004
1003
|
air_temperature=air_temperature,
|
|
1005
1004
|
T_crit_sac=T_critical_sac,
|
|
1006
1005
|
min_ice_particle_number_nvpm_ei_n=self.params["min_ice_particle_number_nvpm_ei_n"],
|
|
1007
1006
|
)
|
|
1007
|
+
n_ice_per_m_1 = n_ice_per_m_0 * f_surv
|
|
1008
1008
|
|
|
1009
1009
|
# Check for persistent initial_contrails
|
|
1010
1010
|
persistent_1 = contrail_properties.initial_persistent(iwc_1, rhi_1)
|
|
@@ -1018,6 +1018,8 @@ class Cocip(Model):
|
|
|
1018
1018
|
self._sac_flight["rho_air_1"] = rho_air_1
|
|
1019
1019
|
self._sac_flight["rhi_1"] = rhi_1
|
|
1020
1020
|
self._sac_flight["iwc_1"] = iwc_1
|
|
1021
|
+
self._sac_flight["f_surv"] = f_surv
|
|
1022
|
+
self._sac_flight["n_ice_per_m_0"] = n_ice_per_m_0
|
|
1021
1023
|
self._sac_flight["n_ice_per_m_1"] = n_ice_per_m_1
|
|
1022
1024
|
self._sac_flight["persistent_1"] = persistent_1
|
|
1023
1025
|
|
|
@@ -1384,7 +1386,13 @@ class Cocip(Model):
|
|
|
1384
1386
|
if verbose_outputs:
|
|
1385
1387
|
sac_cols += ["dT_dz", "ds_dz", "dz_max"]
|
|
1386
1388
|
|
|
1387
|
-
downwash_cols = [
|
|
1389
|
+
downwash_cols = [
|
|
1390
|
+
"rho_air_1",
|
|
1391
|
+
"iwc_1",
|
|
1392
|
+
"f_surv",
|
|
1393
|
+
"n_ice_per_m_0",
|
|
1394
|
+
"n_ice_per_m_1",
|
|
1395
|
+
]
|
|
1388
1396
|
df = pd.concat(
|
|
1389
1397
|
[
|
|
1390
1398
|
self.source.dataframe.set_index(col_idx),
|
|
@@ -2211,8 +2219,6 @@ def calc_contrail_properties(
|
|
|
2211
2219
|
air_temperature += contrail["cumul_heat"]
|
|
2212
2220
|
|
|
2213
2221
|
# get required radiation
|
|
2214
|
-
theta_rad = geo.orbital_position(time)
|
|
2215
|
-
sd0 = geo.solar_constant(theta_rad)
|
|
2216
2222
|
sdr = contrail["sdr"]
|
|
2217
2223
|
rsr = contrail["rsr"]
|
|
2218
2224
|
olr = contrail["olr"]
|
|
@@ -2247,6 +2253,9 @@ def calc_contrail_properties(
|
|
|
2247
2253
|
diffuse_h = contrail_properties.horizontal_diffusivity(ds_dz, depth)
|
|
2248
2254
|
|
|
2249
2255
|
if radiative_heating_effects:
|
|
2256
|
+
# theta_rad has float64 dtype, convert back to float32 if needed
|
|
2257
|
+
theta_rad = geo.orbital_position(time).astype(sdr.dtype, copy=False)
|
|
2258
|
+
sd0 = geo.solar_constant(theta_rad)
|
|
2250
2259
|
heat_rate = radiative_heating.heating_rate(
|
|
2251
2260
|
air_temperature=air_temperature,
|
|
2252
2261
|
rhi=rhi,
|
|
@@ -201,10 +201,9 @@ def iwc_post_wake_vortex(
|
|
|
201
201
|
return np.maximum(iwc - iwc_ad, 0.0)
|
|
202
202
|
|
|
203
203
|
|
|
204
|
-
def
|
|
204
|
+
def initial_ice_particle_number(
|
|
205
205
|
nvpm_ei_n: npt.NDArray[np.floating],
|
|
206
206
|
fuel_dist: npt.NDArray[np.floating],
|
|
207
|
-
f_surv: npt.NDArray[np.floating],
|
|
208
207
|
air_temperature: npt.NDArray[np.floating],
|
|
209
208
|
T_crit_sac: npt.NDArray[np.floating],
|
|
210
209
|
min_ice_particle_number_nvpm_ei_n: float,
|
|
@@ -222,8 +221,6 @@ def ice_particle_number(
|
|
|
222
221
|
black carbon number emissions index, [:math:`kg^{-1}`]
|
|
223
222
|
fuel_dist : npt.NDArray[np.floating]
|
|
224
223
|
fuel consumption of the flight segment per distance traveled, [:math:`kg m^{-1}`]
|
|
225
|
-
f_surv : npt.NDArray[np.floating]
|
|
226
|
-
Fraction of contrail ice particle number that survive the wake vortex phase.
|
|
227
224
|
air_temperature : npt.NDArray[np.floating]
|
|
228
225
|
ambient temperature for each waypoint, [:math:`K`]
|
|
229
226
|
T_crit_sac : npt.NDArray[np.floating]
|
|
@@ -235,11 +232,12 @@ def ice_particle_number(
|
|
|
235
232
|
Returns
|
|
236
233
|
-------
|
|
237
234
|
npt.NDArray[np.floating]
|
|
238
|
-
initial number of ice particles per distance
|
|
235
|
+
The initial number of ice particles per distance before the wake vortex
|
|
236
|
+
phase, [:math:`# m^{-1}`]
|
|
239
237
|
"""
|
|
240
238
|
f_activation = ice_particle_activation_rate(air_temperature, T_crit_sac)
|
|
241
239
|
nvpm_ei_n_activated = nvpm_ei_n * f_activation
|
|
242
|
-
return fuel_dist * np.maximum(nvpm_ei_n_activated, min_ice_particle_number_nvpm_ei_n)
|
|
240
|
+
return fuel_dist * np.maximum(nvpm_ei_n_activated, min_ice_particle_number_nvpm_ei_n)
|
|
243
241
|
|
|
244
242
|
|
|
245
243
|
def ice_particle_activation_rate(
|
|
@@ -1188,10 +1188,18 @@ def meteorological_time_slice_statistics(
|
|
|
1188
1188
|
)
|
|
1189
1189
|
|
|
1190
1190
|
# ISSR: Volume of airspace with RHi > 100% between FL300 and FL450
|
|
1191
|
-
|
|
1192
|
-
rhi =
|
|
1193
|
-
|
|
1194
|
-
|
|
1191
|
+
met_cruise = MetDataset(met.data.sel(level=slice(150, 300)))
|
|
1192
|
+
rhi = humidity_scaling.eval(met_cruise)["rhi"].data
|
|
1193
|
+
|
|
1194
|
+
try:
|
|
1195
|
+
# If the given time is already in the dataset, select the time slice
|
|
1196
|
+
i = rhi.get_index("time").get_loc(time)
|
|
1197
|
+
except KeyError:
|
|
1198
|
+
rhi = rhi.interp(time=time)
|
|
1199
|
+
else:
|
|
1200
|
+
rhi = rhi.isel(time=i)
|
|
1201
|
+
|
|
1202
|
+
is_issr = rhi > 1.0
|
|
1195
1203
|
|
|
1196
1204
|
# Cirrus in a longitude-latitude grid
|
|
1197
1205
|
if cirrus_coverage is None:
|
|
@@ -1104,10 +1104,7 @@ def _contrail_optical_depth_above_contrail_layer(
|
|
|
1104
1104
|
|
|
1105
1105
|
da_surface_area = geo.grid_surface_area(da["longitude"].values, da["latitude"].values)
|
|
1106
1106
|
da = da / da_surface_area
|
|
1107
|
-
|
|
1108
|
-
lon_coords = da["longitude"].values
|
|
1109
|
-
wrap_longitude = (lon_coords[-1] + lon_coords[0] + np.diff(lon_coords)[0]) == 0.0
|
|
1110
|
-
mda = MetDataArray(da, wrap_longitude=wrap_longitude, copy=False)
|
|
1107
|
+
mda = MetDataArray(da)
|
|
1111
1108
|
|
|
1112
1109
|
# Interpolate to contrails_level
|
|
1113
1110
|
contrails_level["tau_contrails_above"] = contrails_level.intersect_met(mda)
|
|
@@ -1133,10 +1130,7 @@ def _rsr_and_olr_with_contrail_overlap(
|
|
|
1133
1130
|
Contrail waypoints at the current altitude layer with `rsr_overlap` and
|
|
1134
1131
|
`olr_overlap` attached.
|
|
1135
1132
|
"""
|
|
1136
|
-
|
|
1137
|
-
lon_coords = delta_rad_t["longitude"].values
|
|
1138
|
-
wrap_longitude = (lon_coords[-1] + lon_coords[0] + np.diff(lon_coords)[0]) == 0.0
|
|
1139
|
-
mds = MetDataset(delta_rad_t, wrap_longitude=wrap_longitude, copy=False)
|
|
1133
|
+
mds = MetDataset(delta_rad_t)
|
|
1140
1134
|
|
|
1141
1135
|
# Interpolate radiation fields to obtain `rsr_overlap` and `olr_overlap`
|
|
1142
1136
|
delta_rsr = contrails_level.intersect_met(mds["rsr"])
|
|
@@ -1488,18 +1488,18 @@ def find_initial_persistent_contrails(
|
|
|
1488
1488
|
)
|
|
1489
1489
|
iwc_1 = contrail_properties.iwc_post_wake_vortex(iwc, iwc_ad)
|
|
1490
1490
|
f_surv = contrail_properties.ice_particle_survival_fraction(iwc, iwc_1)
|
|
1491
|
-
|
|
1491
|
+
n_ice_per_m_0 = contrail_properties.initial_ice_particle_number(
|
|
1492
1492
|
nvpm_ei_n=nvpm_ei_n,
|
|
1493
1493
|
fuel_dist=fuel_dist,
|
|
1494
|
-
f_surv=f_surv,
|
|
1495
1494
|
air_temperature=air_temperature,
|
|
1496
1495
|
T_crit_sac=T_crit_sac,
|
|
1497
1496
|
min_ice_particle_number_nvpm_ei_n=params["min_ice_particle_number_nvpm_ei_n"],
|
|
1498
1497
|
)
|
|
1498
|
+
n_ice_per_m_1 = n_ice_per_m_0 * f_surv
|
|
1499
1499
|
|
|
1500
1500
|
# The logic below corresponds to Cocip._create_downwash_contrail (roughly)
|
|
1501
1501
|
contrail["iwc"] = iwc_1
|
|
1502
|
-
contrail["n_ice_per_m"] =
|
|
1502
|
+
contrail["n_ice_per_m"] = n_ice_per_m_1
|
|
1503
1503
|
|
|
1504
1504
|
# Check for persistent initial_contrails
|
|
1505
1505
|
rhi_1 = contrail["rhi"]
|
|
@@ -2152,18 +2152,18 @@ def result_to_metdataset(
|
|
|
2152
2152
|
size = np.prod(shape)
|
|
2153
2153
|
|
|
2154
2154
|
dtype = result["ef"].dtype if result else np.float32
|
|
2155
|
-
|
|
2156
|
-
|
|
2155
|
+
contrail_age_1d = np.zeros(size, dtype=np.float32)
|
|
2156
|
+
ef_per_m_1d = np.zeros(size, dtype=dtype)
|
|
2157
2157
|
|
|
2158
2158
|
if result:
|
|
2159
2159
|
contrail_idx = result["index"]
|
|
2160
2160
|
# Step 1: Contrail age. Convert from timedelta to float
|
|
2161
|
-
|
|
2161
|
+
contrail_age_1d[contrail_idx] = result["age"] / np.timedelta64(1, "h")
|
|
2162
2162
|
# Step 2: EF
|
|
2163
|
-
|
|
2163
|
+
ef_per_m_1d[contrail_idx] = result["ef"] / nominal_segment_length
|
|
2164
2164
|
|
|
2165
|
-
|
|
2166
|
-
|
|
2165
|
+
contrail_age_4d = contrail_age_1d.reshape(shape)
|
|
2166
|
+
ef_per_m_4d = ef_per_m_1d.reshape(shape)
|
|
2167
2167
|
|
|
2168
2168
|
# Step 3: Dataset dims and attrs
|
|
2169
2169
|
dims = tuple(source.coords)
|
|
@@ -2171,8 +2171,8 @@ def result_to_metdataset(
|
|
|
2171
2171
|
|
|
2172
2172
|
# Step 4: Dataset core variables
|
|
2173
2173
|
data_vars = {
|
|
2174
|
-
"contrail_age": (dims,
|
|
2175
|
-
"ef_per_m": (dims,
|
|
2174
|
+
"contrail_age": (dims, contrail_age_4d, local_attrs["contrail_age"]),
|
|
2175
|
+
"ef_per_m": (dims, ef_per_m_4d, local_attrs["ef_per_m"]),
|
|
2176
2176
|
}
|
|
2177
2177
|
|
|
2178
2178
|
# Step 5: Dataset variables from verbose_dicts
|
|
@@ -321,7 +321,27 @@ class _SigmoidCoefficients:
|
|
|
321
321
|
|
|
322
322
|
|
|
323
323
|
@functools.cache
|
|
324
|
-
def _load_sigmoid_coef(q_method: str | None) -> _SigmoidCoefficients:
|
|
324
|
+
def _load_sigmoid_coef(q_method: str | None, level_type: str) -> _SigmoidCoefficients:
|
|
325
|
+
available = ("pressure", "model")
|
|
326
|
+
if level_type not in available:
|
|
327
|
+
msg = f"Invalid 'level_type' value '{level_type}'. Must be one of {available}."
|
|
328
|
+
raise ValueError(msg)
|
|
329
|
+
|
|
330
|
+
if level_type == "model":
|
|
331
|
+
if q_method is not None:
|
|
332
|
+
msg = "Parameter 'q_method' must be None for model-level data."
|
|
333
|
+
raise ValueError(msg)
|
|
334
|
+
return _SigmoidCoefficients(
|
|
335
|
+
a1=0.026302083473778933,
|
|
336
|
+
a2=0.9651041666272301,
|
|
337
|
+
a3=2.250107435038734,
|
|
338
|
+
a4=36.549393263544914,
|
|
339
|
+
b1=0.489062500000000095,
|
|
340
|
+
b2=2.210937499999999,
|
|
341
|
+
b3=4.182743010484767,
|
|
342
|
+
b4=17.53378893219587,
|
|
343
|
+
)
|
|
344
|
+
|
|
325
345
|
if q_method is None:
|
|
326
346
|
return _SigmoidCoefficients(
|
|
327
347
|
a1=0.062621,
|
|
@@ -347,6 +367,14 @@ def _load_sigmoid_coef(q_method: str | None) -> _SigmoidCoefficients:
|
|
|
347
367
|
raise NotImplementedError(f"Unsupported q_method: {q_method}")
|
|
348
368
|
|
|
349
369
|
|
|
370
|
+
@dataclasses.dataclass
|
|
371
|
+
class ExponentialBoostLatitudeCorrectionParams(models.ModelParams):
|
|
372
|
+
"""Parameters for :class:`ExponentialBoostLatitudeCorrectionHumidityScaling`."""
|
|
373
|
+
|
|
374
|
+
#: The ERA5 vertical level type. Must be one of ``"pressure"`` or ``"model"``.
|
|
375
|
+
level_type: str = "pressure"
|
|
376
|
+
|
|
377
|
+
|
|
350
378
|
class ExponentialBoostLatitudeCorrectionHumidityScaling(HumidityScaling):
|
|
351
379
|
"""Correct RHi values derived from ECMWF ERA5 HRES.
|
|
352
380
|
|
|
@@ -406,12 +434,28 @@ class ExponentialBoostLatitudeCorrectionHumidityScaling(HumidityScaling):
|
|
|
406
434
|
name = "exponential_boost_latitude_customization"
|
|
407
435
|
long_name = "Latitude specific humidity scaling composed with exponential boosting"
|
|
408
436
|
formula = "rhi -> (rhi / rhi_adj) ^ rhi_boost_exponent"
|
|
409
|
-
default_params =
|
|
437
|
+
default_params = ExponentialBoostLatitudeCorrectionParams
|
|
410
438
|
scaler_specific_keys = ("latitude",)
|
|
411
439
|
|
|
440
|
+
def __init__(
|
|
441
|
+
self,
|
|
442
|
+
met: MetDataset | None = None,
|
|
443
|
+
params: dict[str, Any] | None = None,
|
|
444
|
+
**params_kwargs: Any,
|
|
445
|
+
):
|
|
446
|
+
if (params is None or "level_type" not in params) and ("level_type" not in params_kwargs):
|
|
447
|
+
msg = (
|
|
448
|
+
"The default level_type will change from 'pressure' to 'model' "
|
|
449
|
+
"in a future release. To silence this warning, provide a 'level_type' "
|
|
450
|
+
"value when instantiating ExponentialBoostLatitudeCorrectionHumidityScaling."
|
|
451
|
+
)
|
|
452
|
+
warnings.warn(msg, DeprecationWarning)
|
|
453
|
+
super().__init__(met, params, **params_kwargs)
|
|
454
|
+
|
|
412
455
|
def _scale_kwargs(self) -> dict[str, Any]:
|
|
413
456
|
q_method = self.params["interpolation_q_method"]
|
|
414
|
-
|
|
457
|
+
level_type = self.params["level_type"]
|
|
458
|
+
return {**super()._scale_kwargs(), "q_method": q_method, "level_type": level_type}
|
|
415
459
|
|
|
416
460
|
@override
|
|
417
461
|
def scale(
|
|
@@ -423,7 +467,8 @@ class ExponentialBoostLatitudeCorrectionHumidityScaling(HumidityScaling):
|
|
|
423
467
|
) -> tuple[ArrayLike, ArrayLike]:
|
|
424
468
|
# Get sigmoid coefficients
|
|
425
469
|
q_method = kwargs["q_method"]
|
|
426
|
-
|
|
470
|
+
level_type = kwargs["level_type"]
|
|
471
|
+
coef = _load_sigmoid_coef(q_method, level_type)
|
|
427
472
|
|
|
428
473
|
# Use the dtype of specific_humidity to determine the precision of the
|
|
429
474
|
# the calculation. If working with gridded data here, latitude will have
|
|
@@ -16,7 +16,7 @@ from pycontrails.physics import constants as c
|
|
|
16
16
|
from pycontrails.utils.types import ArrayOrFloat
|
|
17
17
|
|
|
18
18
|
#: Path to the Poll-Schumann aircraft parameters CSV file.
|
|
19
|
-
PS_FILE_PATH = pathlib.Path(__file__).parent / "static" / "ps-aircraft-params-
|
|
19
|
+
PS_FILE_PATH = pathlib.Path(__file__).parent / "static" / "ps-aircraft-params-20250328.csv"
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
@dataclasses.dataclass(frozen=True)
|
|
@@ -408,35 +408,35 @@ def ps_nominal_grid(
|
|
|
408
408
|
>>> perf.attrs["mach_number"]
|
|
409
409
|
0.753
|
|
410
410
|
|
|
411
|
-
>>> perf.to_dataframe()
|
|
411
|
+
>>> perf.to_dataframe().round({"aircraft_mass": 0, "engine_efficiency": 3, "fuel_flow": 3})
|
|
412
412
|
aircraft_mass engine_efficiency fuel_flow
|
|
413
413
|
level
|
|
414
|
-
200.0
|
|
415
|
-
210.0
|
|
416
|
-
220.0
|
|
417
|
-
230.0
|
|
418
|
-
240.0
|
|
419
|
-
250.0
|
|
420
|
-
260.0
|
|
421
|
-
270.0
|
|
422
|
-
280.0
|
|
423
|
-
290.0
|
|
414
|
+
200.0 58416.0 0.301 0.576
|
|
415
|
+
210.0 61618.0 0.301 0.604
|
|
416
|
+
220.0 64830.0 0.301 0.633
|
|
417
|
+
230.0 68026.0 0.301 0.663
|
|
418
|
+
240.0 71188.0 0.301 0.695
|
|
419
|
+
250.0 71775.0 0.301 0.703
|
|
420
|
+
260.0 71766.0 0.300 0.708
|
|
421
|
+
270.0 71752.0 0.300 0.715
|
|
422
|
+
280.0 71736.0 0.299 0.722
|
|
423
|
+
290.0 71717.0 0.298 0.730
|
|
424
424
|
|
|
425
425
|
>>> # Now compute it for a higher Mach number
|
|
426
426
|
>>> perf = ps_nominal_grid("A320", level=level, mach_number=0.78)
|
|
427
|
-
>>> perf.to_dataframe()
|
|
427
|
+
>>> perf.to_dataframe().round({"aircraft_mass": 0, "engine_efficiency": 3, "fuel_flow": 3})
|
|
428
428
|
aircraft_mass engine_efficiency fuel_flow
|
|
429
429
|
level
|
|
430
|
-
200.0
|
|
431
|
-
210.0
|
|
432
|
-
220.0
|
|
433
|
-
230.0
|
|
434
|
-
240.0
|
|
435
|
-
250.0
|
|
436
|
-
260.0
|
|
437
|
-
270.0
|
|
438
|
-
280.0
|
|
439
|
-
290.0
|
|
430
|
+
200.0 58473.0 0.307 0.601
|
|
431
|
+
210.0 60626.0 0.307 0.621
|
|
432
|
+
220.0 63818.0 0.307 0.651
|
|
433
|
+
230.0 66994.0 0.307 0.682
|
|
434
|
+
240.0 70130.0 0.307 0.714
|
|
435
|
+
250.0 71703.0 0.307 0.733
|
|
436
|
+
260.0 71690.0 0.306 0.739
|
|
437
|
+
270.0 71673.0 0.306 0.747
|
|
438
|
+
280.0 71653.0 0.305 0.756
|
|
439
|
+
290.0 71631.0 0.304 0.766
|
|
440
440
|
"""
|
|
441
441
|
dims, coords, air_pressure, air_temperature = _parse_variables(level, air_temperature)
|
|
442
442
|
|
|
@@ -27,7 +27,6 @@ from pycontrails.core.aircraft_performance import (
|
|
|
27
27
|
)
|
|
28
28
|
from pycontrails.core.flight import Flight
|
|
29
29
|
from pycontrails.core.met import MetDataset
|
|
30
|
-
from pycontrails.core.met_var import AirTemperature, EastwardWind, MetVariable, NorthwardWind
|
|
31
30
|
from pycontrails.models.ps_model import ps_operational_limits as ps_lims
|
|
32
31
|
from pycontrails.models.ps_model.ps_aircraft_params import (
|
|
33
32
|
PSAircraftEngineParams,
|
|
@@ -39,7 +38,7 @@ from pycontrails.utils.types import ArrayOrFloat
|
|
|
39
38
|
# mypy: disable-error-code = "type-var, arg-type"
|
|
40
39
|
|
|
41
40
|
#: Path to the Poll-Schumann aircraft parameters CSV file.
|
|
42
|
-
PS_SYNONYM_FILE_PATH = pathlib.Path(__file__).parent / "static" / "ps-synonym-list-
|
|
41
|
+
PS_SYNONYM_FILE_PATH = pathlib.Path(__file__).parent / "static" / "ps-synonym-list-20250328.csv"
|
|
43
42
|
|
|
44
43
|
|
|
45
44
|
@dataclasses.dataclass
|
|
@@ -70,8 +69,6 @@ class PSFlight(AircraftPerformance):
|
|
|
70
69
|
|
|
71
70
|
name = "PSFlight"
|
|
72
71
|
long_name = "Poll-Schumann Aircraft Performance Model"
|
|
73
|
-
met_variables: tuple[MetVariable, ...] = (AirTemperature,)
|
|
74
|
-
optional_met_variables = EastwardWind, NorthwardWind
|
|
75
72
|
default_params = PSFlightParams
|
|
76
73
|
|
|
77
74
|
aircraft_engine_params: Mapping[str, PSAircraftEngineParams]
|
|
@@ -160,10 +157,10 @@ class PSFlight(AircraftPerformance):
|
|
|
160
157
|
time=fl["time"],
|
|
161
158
|
true_airspeed=true_airspeed,
|
|
162
159
|
air_temperature=fl["air_temperature"],
|
|
163
|
-
aircraft_mass=self.
|
|
164
|
-
thrust=self.
|
|
165
|
-
engine_efficiency=self.
|
|
166
|
-
fuel_flow=self.
|
|
160
|
+
aircraft_mass=self.get_data_param(fl, "aircraft_mass", None),
|
|
161
|
+
thrust=self.get_data_param(fl, "thrust", None),
|
|
162
|
+
engine_efficiency=self.get_data_param(fl, "engine_efficiency", None),
|
|
163
|
+
fuel_flow=self.get_data_param(fl, "fuel_flow", None),
|
|
167
164
|
q_fuel=q_fuel,
|
|
168
165
|
n_iter=self.params["n_iter"],
|
|
169
166
|
amass_oew=amass_oew,
|
|
@@ -999,8 +996,5 @@ def get_aircraft_synonym_dict_ps() -> dict[str, str]:
|
|
|
999
996
|
Dictionary of the form ``{"icao_aircraft_type": "ps_aircraft_type"}``.
|
|
1000
997
|
"""
|
|
1001
998
|
# get path to static PS synonym list
|
|
1002
|
-
|
|
1003
|
-
df_atyp_icao_to_ps
|
|
1004
|
-
synonym_path, usecols=["ICAO Aircraft Code", "PS ATYP"], index_col=0
|
|
1005
|
-
)
|
|
1006
|
-
return df_atyp_icao_to_ps.squeeze("columns").to_dict()
|
|
999
|
+
df_atyp_icao_to_ps = pd.read_csv(PS_SYNONYM_FILE_PATH, index_col="ICAO Aircraft Code")
|
|
1000
|
+
return df_atyp_icao_to_ps["PS ATYP"].to_dict()
|