ジェット燃料の節約
Saving Jet Fuel (tech.marksblogg.com)
要約
この記事は、オープンソースのフレームワークであるScikit-decideと航空機性能モデルであるOpenAPを活用し、風の条件や航空機の性能データに基づいて最適な飛行経路を計算することで、ジェット燃料の消費を削減する方法を解説しています。必要なソフトウェアのインストール手順や、OpenAPが提供する様々な航空機モデルのデータ構造についても詳細に説明しています。
全文翻訳
ジェット燃料の節約
ニューアーク・リバティー国際空港(EWR)からレオナルド・ダ・ヴィンチ=フィウミチーノ空港(FCO)までのノンストップフライトで、ボーイング787-9ドリームライナーは8.5時間の飛行で68,000ドルのジェット燃料を必要とする可能性があります。風の条件に合わせて飛行経路を調整することで、燃料消費を削減し、数千ドルを節約できる可能性があります。
Jeppesenのような企業もこの分野でサービスを提供していますが、Scikit-decideは、デルフト工科大学の教授が構築したナローボディおよびワイドボディの燃料消費モデルとNOAAの風データと組み合わせることで、オープンソースのソリューションを提供します。
Scikit-decideは6年間開発が進められています。これは、強化学習、自動計画、スケジューリングのためのフレームワークです。このプロジェクトは、飛行経路の最適化、航空会社の労働力スケジュールの再編成、ドローンの群れの経路計算を行うことができます。
OpenAPは、Junzi Sun博士によって開発された航空機性能モデルおよびツールキットです。Sun博士は航空交通管理の博士号を持ち、オランダのTU Delftで准教授としてこの分野のコースを教えています。
Scikit-decideの最適な飛行経路ソルバーは、異なる燃料消費モデルを使用するように設定できます。この記事では、Airbus A320とOpenAPの燃料消費モデルを使用して飛行した2つの飛行経路を比較します。
私のワークステーション
私は5.7 GHzのAMD Ryzen 9 9950X CPUを使用しています。16コア32スレッド、1.2 MBのL1、16 MBのL2、64 MBのL3キャッシュを備えています。液体クーラーが取り付けられており、広々としたフルサイズのCooler Master HAF 700コンピューターケースに収められています。
システムは4,800 MT/sでクロックされた96 GBのDDR5 RAMと、最大12,400 MB/sの読み取り速度を持つ第5世代Crucial T700 4 TB NVMe M.2 SSDを搭載しています。SSDにはヒートシンクがあり、温度を下げるのに役立ちます。これが私のシステムのCドライブです。
システムは1,200ワットのフルモジュラーCorsair電源によって電力を供給されており、ASRock X870E Nova 90マザーボード上に配置されています。
Windows 11 Pro上のUbuntu for Windowsを介してUbuntu 24 LTSを実行しています。なぜ私のプライマリワーク環境としてLinuxベースのデスクトップを実行しないのか疑問に思っているかもしれませんが、私はまだNvidia GTX 1080 GPUを使用しており、Windowsの方がドライバーのサポートが優れており、ArcGIS ProはネイティブでWindowsのみをサポートしているためです。
前提条件のインストール
この記事では、Python 3.12とjqを使用します。
$ sudo add-apt-repository ppa:deadsnakes/ppa
$ sudo apt update
$ sudo apt install \
jq \
python3-pip \
python3.12-venv
Python仮想環境をセットアップし、scikit-decide、OpenAPオープン航空機パフォーマンスモデル、およびSun博士が開発したフライト軌道ツールキットであるOpenTopをインストールします。
$ python3 -m venv ~/.flight_planning
$ source ~/.flight_planning/bin/activate
$ pip install \
'scikit-decide[all]' \
'openap[all]' \
opentop
上記は少なくとも8 GBのストレージ容量が必要です。インストールされたパッケージは以下の通りです。
$ pip install pipdeptree
$ pipdeptree -d0
lz4==4.4.5
openevolve==0.3.2
opentop==2.6.0
pip==24.0
pipdeptree==4.2.5
plado==0.1.6
pygeodesy==26.9.9
pygrib==2.1.8
pyRDDLGym-gurobi==0.2
pyRDDLGym-jax==3.1
pyRDDLGym-rl==0.2
pytz==2026.3.post1
ray==2.37.0
rddlrepository==2.2
sb3_contrib==2.3.0
scikit-decide==1.1.1
scikit-image==0.26.0
tensorboardX==2.6.5
torch-geometric==2.8.0.post1
typer==0.27.2
unified-planning==1.2.0
up-enhsp==0.0.27
up_fast_downward==0.5.2
up-pyperplan==1.1.0
z3-solver==5.1.0.0
この記事では、DuckDBとそのH3、JSON、Lindel、Parquet、Spatial拡張機能を使用します。
$ cd ~
$ wget -c https://github.com/duckdb/duckdb/releases/download/v1.5.4/duckdb_cli-linux-amd64.zip
$ unzip -j duckdb_cli-linux-amd64.zip
$ chmod +x duckdb
$ ~/duckdb
INSTALL h3 FROM community;
INSTALL lindel FROM community;
INSTALL json;
INSTALL parquet;
INSTALL spatial;
DuckDBを起動するたびにすべてのインストール済み拡張機能をロードするように設定します。
$ vi ~/.dudkbrc
.timer on
.width 180
LOAD h3;
LOAD lindel;
LOAD json;
LOAD parquet;
LOAD spatial;
この記事の地図はQGISバージョン4.2.1でレンダリングされました。QGISはWindows、macOS、Linuxで動作するデスクトップアプリケーションです。このアプリケーションは近年人気が高まっており、世界中のユーザーから毎月約2200万回のアプリケーション起動があります。
境界線と地名はNatural Earthから、海洋境界線はMarine Regionsから取得しました。
OpenAPの航空機タイプ
まずOpenAPリポジトリをクローンします。
$ git clone https://github.com/junzis/openap
単体テストとユーティリティスクリプトを除くと、このパッケージには3,369行のPythonコードが含まれています。
OpenAPのモデルは、コードベースにバンドルされた多数のデータセットに依存しています。これらは多種多様な航空機をカバーしています。以下は航空機メーカーのカウントです。
$ grep -ho 'aircraft: .*[a-z] '
openap/data/aircraft/*.yml \
| cut -d' ' -f2 \
| sort \
| uniq -c \
| sort -rn
17 Boeing
13 Airbus
5 Embraer
1 Gulfstream
1 Cessna
これらはAirbus A380-800のプロパティです。
$ cat openap/data/aircraft/a388.yml
aircraft: Airbus A380-800
mtow: 560000
mlw: 386000
oew: 277000
mfc: 320000
vmo: 340
mmo: 0.89
ceiling: 13100
pax:
max: 853
low: 410
high: 620
fuselage:
length: 72.72
height: 8.41
width: 7.14
wing:
area: 845
span: 79.75
mac: null
sweep: 33.5
t/c: 0.08
flaps:
type: single-slotted
area: null
bf/b: null
lambda_f: 0.900
cf/c: 0.150
Sf/S: 0.150
cruise:
height: 12800
mach: 0.85
range: 14800
engine:
type: turbofan
mount: wing
number: 4
default: GP7270
options:
A380-841: Trent 970-84
A380-842: Trent 972-84
A380-861: GP7270
drag:
cd0: 0.016
k: 0.050
e: 0.855
gears: 0.012
これらはその抗力係数です。
$ cat openap/data/dragpolar/a388.yml
aircraft: Airbus A380-800
clean:
cd0: 0.016
k: 0.050
e: 0.855
gears: 0.012
flaps:
lambda_f: 0.900
cf/c: 0.150
Sf/S: 0.150
これらは追加のプロパティです。
$ echo "import pandas as pd; print(
pd.read_fwf('openap/data/wrap/a388.txt')
.to_csv(index=False))" \
| python3 \
| ~/duckdb \
-c '.maxwidth 150'
-c "SELECT * EXCLUDE(parameters),
parameters: SPLIT(parameters, '|')
FROM READ_CSV('/dev/stdin')"
┌──────────────────────┬────────────────┬───────────────────────────────────────┬────────┬────────┬─────────┬─────────┬──────────────────────────────┐
│ variable │ flight phase │ name │ opt │ min │ max │ model │ parameters │
│ varchar │ varchar │ varchar │ double │ double │ double │ varchar │ varchar[] │
├──────────────────────┼────────────────┼───────────────────────────────────────┼────────┼────────┼─────────┼─────────┼──────────────────────────────┤
│ to_v_lof │ takeoff │ Liftoff speed │ 89.9 │ 75.4 │ 104.4 │ norm │ [89.93, 10.07] │
│ to_d_tof │ takeoff │ Takeoff distance │ 2.56 │ 1.35 │ 3.78 │ norm │ [2.56, 0.74] │
│ to_acc_tof │ takeoff │ Mean takeoff accelaration │ 1.35 │ 1.04 │ 1.66 │ norm │ [1.35, 0.19] │
│ ic_va_avg │ initial_climb │ Mean airspeed │ 88.0 │ 80.0 │ 96.0 │ norm │ [88.15, 5.64] │
│ ic_vs_avg │ initial_climb │ Mean vertical rate │ 5.65 │ 4.4 │ 8.94 │ gamma │ [4.76, 3.22, 0.65] │
│ cl_d_range │ climb │ Climb range │ 296.0 │ 200.0 │ 446.0 │ beta │ [3.23, 5.18, 179.46, 335.24] │
│ cl_v_cas_const │ climb │ Constant CAS │ 163.0 │ 155.0 │ 170.0 │ norm │ [163.39, 4.51] │
│ cl_v_mach_const │ climb │ Constant Mach │ 0.84 │ 0.8 │ 0.86 │ beta │ [12.23, 5.32, 0.72, 0.17] │
│ cl_h_cas_const │ climb │ Constant CAS crossover altitude │ 3.3 │ 1.3 │ 5.3 │ norm │ [3.29, 1.24] │
│ cl_h_mach_const │ climb │ Constant Mach crossover altitude │ 8.9 │ 8.2 │ 9.7 │ norm │ [8.94, 0.47] │
│ cl_vs_avg_pre_cas │ climb │ Mean climb rate, pre-constant-CAS │ 7.85 │ 5.95 │ 9.75 │ norm │ [7.85, 1.16] │
│ cl_vs_avg_cas_const │ climb │ Mean climb rate, constant-CAS │ 7.51 │ 5.2 │ 9.82 │ norm │ [7.51, 1.40] │
│ cl_vs_avg_mach_const │ climb │ Mean climb rate, constant-Mach │ 5.56 │ 3.23 │ 7.91 │ norm │ [5.57, 1.42] │
│ cr_d_range │ cruise │ Cruise range │ 4348.0 │ 892.0 │ 20565.0 │ gamma │ [2.81, 246.73, 2274.81] │
│ cr_v_cas_mean │ cruise │ Mean cruise CAS │ 136.0 │ 130.0 │ 145.0 │ beta │ [3.32, 5.27, 126.00, 29.75] │
│ cr_v_cas_max │ cruise │ Maximum cruise CAS │ 145.0 │ 134.0 │ 164.0 │ beta │ [2.02, 3.21, 130.38, 46.65] │
│ cr_v_mach_mean │ cruise │ Mean cruise Mach │ 0.84 │ 0.82 │ 0.86 │ norm │ [0.84, 0.01] │
│ cr_v_mach_max │ cruise │ Maximum cruise Mach │ 0.87 │ 0.85 │ 0.9 │ gamma │ [16.14, 0.80, 0.00] │
│ cr_h_init │ cruise │ Initial cruise altitude │ 11.55 │ 9.3 │ 12.23 │ beta │ [3.82, 1.66, 7.49, 5.01] │
│ cr_h_mean │ cruise │ Mean cruise altitude │ 11.73 │ 10.87 │ 12.28 │ beta │ [7.22, 3.92, 9.59, 3.14] │
│ cr_h_max │ cruise │ Maximum cruise altitude │ 12.06 │ 11.52 │ 12.6 │ norm │ [12.06, 0.33] │
│ de_d_range │ descent │ Descent range │ 310.0 │ 238.0 │ 528.0 │ gamma │ [4.73, 213.47, 25.87] │
│ de_v_mach_const │ descent │ Constant Mach │ 0.83 │ 0.8 │ 0.87 │ norm │ [0.83, 0.02] │
│ de_v_cas_const │ descent │ Constant CAS │ 154.0 │ 142.0 │ 167.0 │ norm │ [154.84, 7.74] │
│ de_h_mach_const │ descent │ Constant Mach crossover altitude │ 10.1 │ 8.6 │ 11.5 │ norm │ [10.06, 0.88] │
│ de_h_cas_const │ descent │ Constant CAS crossover altitude │ 6.6 │ 3.9 │ 9.4 │ norm │ [6.64, 1.69] │
│ de_vs_avg_mach_const │ descent │ Mean descent rate, constant-Mach │ -6.06 │ -11.9 │ -2.97 │ beta │ [3.43, 2.08, -15.98, 14.36] │
│ de_vs_avg_cas_const │ descent │ Mean descent rate, constant-CAS │ -8.36 │ -11.74 │ -4.97 │ norm │ [-8.36, 2.06] │
│ de_vs_avg_after_cas │ descent │ Mean descent rate, after-constant-CAS │ -5.48 │ -6.93 │ -4.02 │ norm │ [-5.48, 0.88] │
│ fa_va_avg │ final_approach │ Mean airspeed │ 73.0 │ 68.0 │ 77.0 │ norm │ [73.28, 3.02] │
│ fa_vs_avg │ final_approach │ Mean vertical rate │ -3.71 │ -4.13 │ -2.92 │ gamma │ [9.49, -4.74, 0.12] │
│ fa_agl │ final_approach │ Approach angle │ 2.9 │ 2.42 │ 3.38 │ norm │ [2.90, 0.29] │
│ ld_v_app │ landing │ Touchdown speed │ 70.0 │ 62.1 │ 78.0 │ norm │ [70.00, 5.52] │
│ ld_d_brk │ landing │ Braking distance │ 2.26 │ 0.73 │ 3.8 │ norm │ [2.26, 0.93] │
│ ld_acc_brk │ landing │ Mean braking acceleration │ -1.01 │ -1.51 │ -0.52 │ norm │ [-1.01, 0.30] │
└──────────────────────┴────────────────┴───────────────────────────────────────┴────────┴────────┴─────────┴─────────┴──────────────────────────────┘
これらは航空機タイプ名の別名リストです。
$ ~/duckdb -c "FROM READ_CSV('/dev/stdin')"
< openap/data/aircraft/_synonym.csv
┌─────────┬─────────┐
│ orig │ new │
│ varchar │ varchar │
├─────────┼─────────┤
│ a124 │ b744 │
│ a306 │ a332 │
│ a310 │ a318 │
│ at72 │ e145 │
│ at75 │ e145 │
│ at76 │ e145 │
│ b733 │ b734 │
│ b735 │ b734 │
│ b762 │ b763 │
│ b77l │ b77w │
│ c25a │ c550 │
│ c525 │ c550 │
│ c56x │ c550 │
│ crj2 │ e145 │
│ crj9 │ e75l │
│ e290 │ e190 │
│ glf5 │ glf6 │
│ gl5t │ glf6 │
│ lj45 │ glf6 │
│ md11 │ b773 │
│ pc24 │ c550 │
│ su95 │ e170 │
└─────────┴─────────┘
航空機エンジン
航空機はしばしば少なくとも2つの異なるエンジンから選択するオプションを持っています。このパッケージのデータセットには427基のエンジンがリストされています。
$ wc -l openap/data/engine/engines.csv # 427
これらはTrent 970-84の詳細です。
$ echo "FROM 'openap/data/engine/engines.csv'
WHERE name = 'Trent 970-84'
LIMIT 1" \
| ~/duckdb -json \
| jq -S .
[
{
"bpr": 8.45,
"cruise_alt": null,
"cruise_mach": null,
"cruise_sfc": null,
"cruise_thrust": null,
"ei_co_app": 1.16,
"ei_co_co": 0.31,
"ei_co_idl": 13.38,
"ei_co_to": 0.32,
"ei_hc_app": 0.08,
"ei_hc_co": 0.12,
"ei_hc_idl": 0.04,
"ei_hc_to": 0.02,
"ei_nox_app": 12.09,
"ei_nox_co": 29.42,
"ei_nox_idl": 5.44,
"ei_nox_to": 38.29,
"ff_app": 0.72,
"ff_co": 2.157,
"ff_idl": 0.255,
"ff_to": 2.605,
"fuel_lto": 965.0,
"manufacturer": "Rolls-Royce plc",
"max_thrust": 338700.0,
"name": "Trent 970-84",
"pr": 38.0,
"type": "TF",
"uid": "18RR081"
}
]
これらはエンジンメーカーのカウントです。
$ ~/duckdb
CREATE OR REPLACE TABLE a AS
FROM 'openap/data/engine/engines.csv';
SELECT COUNT(*),
manufacturer
FROM a
GROUP BY 2
ORDER BY 1 DESC;
┌──────────────┬────────────────────────────┐
│ count_star() │ manufacturer │
│ int64 │ varchar │
├──────────────┼────────────────────────────┤
│ 108 │ GE Aircraft Engines │
│ 94 │ CFM International │
│ 85 │ Pratt & Whitney │
│ 62 │ Rolls-Royce plc │
│ 13 │ International Aero Engines │
│ 12 │ Pratt & Whitney Canada │
│ 11 │ Rolls-Royce Corporation │
│ 8 │ Rolls-Royce Deutschland │
│ 8 │ Honeywell │
│ 7 │ Aviadvigatel │
│ 5 │ Textron Lycoming │
│ 4 │ KKBM │
│ 3 │ IVCHENKO PROGRESS ZMBK │
│ 2 │ PowerJet S.A. │
│ 2 │ Allied Signal │
│ 1 │ Engine Alliance │
│ 1 │ Garret AiResearch │
└──────────────┴────────────────────────────┘
これらは、このデータセットにおけるターボファン(TF)、混合流ターボファン(MTF)、ターボプロップ(TP)、ピストン(PS)エンジンのタイプ別カウントです。
SELECT COUNT(*),
type
FROM a
GROUP BY 2
ORDER BY 1 DESC;
┌──────────────┬─────────┐
│ count_star() │ type │
│ int64 │ varchar │
├──────────────┼─────────┤
│ 322 │ TF │
│ 98 │ MTF │
│ 5 │ TP │
│ 1 │ PS │
└──────────────┴─────────┘
これは、最大推力でランク付けされたエンジンのリストです。
SELECT manufacturer,
name,
type,
max_thrust
FROM a
ORDER BY 4 DESC
LIMIT 25;
┌─────────────────────┬───────────────┬─────────┬────────────┐
│ manufacturer │ name │ type │ max_thrust │
│ varchar │ varchar │ varchar │ double │
├─────────────────────┼───────────────┼─────────┼────────────┤
│ GE Aircraft Engines │ GE90-115B │ TF │ 513900.0 │
│ GE Aircraft Engines │ GE90-113B │ TF │ 504900.0 │
│ GE Aircraft Engines │ GE90-110B1 │ TF │ 492600.0 │
│ Rolls-Royce plc │ Trent XWB-97 │ TF │ 436748.0 │
│ GE Aircraft Engines │ GE90-94B │ TF │ 430920.0 │
│ GE Aircraft Engines │ GE90-92B │ TF │ 426720.0 │
│ GE Aircraft Engines │ GE90-90B │ TF │ 419250.0 │
│ Rolls-Royce plc │ Trent 895 │ TF │ 413050.0 │
│ Rolls-Royce plc │ Trent 892 │ TF │ 411480.0 │
│ Pratt & Whitney │ PW4090 │ TF │ 408300.0 │
│ GE Aircraft Engines │ GE90-85B │ TF │ 397210.0 │
│ Rolls-Royce plc │ Trent 884 │ TF │ 390100.0 │
│ Pratt & Whitney │ PW4084D │ TF │ 385900.0 │
│ Rolls-Royce plc │ Trent XWB-84 │ TF │ 379000.0 │
│ Pratt & Whitney │ PW4084 │ TF │ 369600.0 │
│ GE Aircraft Engines │ GE90-77B │ TF │ 366750.0 │
│ Rolls-Royce plc │ Trent 1000-R3 │ TF │ 363900.0 │
│ GE Aircraft Engines │ GE90-76B │ TF │ 363220.0 │
│ Rolls-Royce plc │ Trent 877 │ TF │ 361640.0 │
│ Rolls-Royce plc │ Trent 1000-M3 │ TF │ 358100.0 │
│ Rolls-Royce plc │ Trent 1000-N3 │ TF │ 358100.0 │
│ Pratt & Whitney │ PW4077D │ TF │ 355700.0 │
│ Rolls-Royce plc │ Trent XWB-79B │ TF │ 355200.0 │
│ Rolls-Royce plc │ Trent XWB-79 │ TF │ 355200.0 │
│ Rolls-Royce plc │ Trent 970B-84 │ TF │ 352900.0 │
└─────────────────────┴───────────────┴─────────┴────────────┘
これらは燃料モデルのデフォルト値とオーバーライドです。
$ ~/duckdb -c "FROM READ_CSV('/dev/stdin')"
< openap/data/fuel/fuel_models.csv
┌──────────┬─────────────┬────────────────────┬────────────────────┬────────────────────┐
│ typecode │ engine_type │ c1 │ c2 │ c3 │
│ varchar │ varchar │ double │ double │ double │
├──────────┼─────────────┼────────────────────┼────────────────────┼────────────────────┤
│ A318 │ CFM56-5B9/3 │ 0.7769784596099123 │ 1.765377288174942 │ 2.5349134936316693 │
│ A319 │ V2524-A5 │ 0.8694169413032631 │ 1.9542690629047836 │ 2.5028187026860103 │
│ A320 │ CFM56-5B4/P │ 1.0453208160586924 │ 2.3633720747416573 │ 1.2378127479131922 │
│ A321 │ V2533-A5 │ 1.3979999999999444 │ 2.054028451829268 │ 1.0008941993511127 │
│ A332 │ Trent 772 │ 2.886430057340283 │ 1.0960397632560752 │ 2.3772585567580293 │
│ A333 │ Trent 772 │ 3.1199999999999997 │ 1.0365152289922772 │ 1.950599421257047 │
│ B737 │ CFM56-7B26 │ 1.0237419750954273 │ 1.4670109921175798 │ 3.2566140275646456 │
│ B738 │ CFM56-7B26E │ 1.075484518912494 │ 1.8777303165419037 │ 1.8895522140156369 │
│ B739 │ CFM56-7B27E │ 1.3079999999999998 │ 1.5986016771932572 │ 1.2789091908108752 │
│ CRJ9 │ CF34-8C5 │ 0.6437136288905128 │ 1.9690234662778772 │ 1.4375859706162741 │
│ E170 │ CF34-8E5 │ 0.6341784688704629 │ 2.778729428440142 │ 1.0149695061665696 │
│ E190 │ CF34-10E5 │ 0.8339999999998783 │ 2.3343013671118475 │ 0.4847704716061958 │
│ E195 │ CF34-10E5A1 │ 0.911999999999993 │ 1.929664699695295 │ 0.8452746256489131 │
│ E75L │ CF34-8E5 │ 0.6340709359225759 │ 2.614653287356019 │ 0.8714282723568036 │
│ default │ default │ 0.937564901246902 │ 1.9767611682280135 │ 1.3954794843472482 │
└──────────┴─────────────┴────────────────────┴────────────────────┴────────────────────┘
## 空港とナビゲーション
このパッケージには約14,000の空港の場所とコードが含まれています。
$ wc -l openap/data/nav/airports.csv # 13796
$ ~/duckdb -c "FROM READ_CSV('/dev/stdin')
WHERE country = 'CA'
ORDER BY lat
LIMIT 20"
< openap/data/nav/airports.csv
┌─────────┬──────────┬───────────┬───────┬─────────┬───────────────────────────────┬────────────────┐
│ icao │ lat │ lon │ alt │ country │ name │ location │
│ varchar │ double │ double │ int64 │ varchar │ varchar │ varchar │
├─────────┼──────────┼───────────┼───────┼─────────┼───────────────────────────────┼────────────────┤
│ CYQG │ 42.27334 │ -82.97056 │ 622 │ CA │ Windsor │ Windsor │
│ CYQS │ 42.77202 │ -81.11923 │ 778 │ CA │ St Thomas Muni │ St. Thomas │
│ CYZR │ 43.00444 │ -82.31528 │ 594 │ CA │ Sarnia - Chris Hadfield │ Sarnia │
│ CYXU │ 43.04211 │ -81.1598 │ 912 │ CA │ London │ London │
│ CYFD │ 43.12389 │ -80.34667 │ 815 │ CA │ Brantford │ Brant │
│ CYHM │ 43.18056 │ -79.95306 │ 780 │ CA │ John C Munro Hamilton Intl │ Ancaster │
│ CYSN │ 43.18792 │ -79.1786 │ 321 │ CA │ Niagara District │ St. Catharines │
│ CYCE │ 43.28306 │ -81.51806 │ 824 │ CA │ Huron Airpark │ South Huron │
│ CYSA │ 43.41087 │ -80.93994 │ 1215 │ CA │ Stratford Municipal │ Stratford │
│ CZBA │ 43.445 │ -79.85472 │ 602 │ CA │ Burlington Airpark │ Burlington │
│ CYKF │ 43.45694 │ -80.39056 │ 1054 │ CA │ Waterloo │ Cambridge │
│ CYTZ │ 43.62747 │ -79.40336 │ 251 │ CA │ Toronto City Centre │ Toronto │
│ CYYZ │ 43.66073 │ -79.62394 │ 568 │ CA │ Toronto Lester B Pearson Intl │ Etobicoke │
│ CYZD │ 43.74972 │ -79.47417 │ 652 │ CA │ Downsview │ Concord │
│ CYGD │ 43.77111 │ -81.71639 │ 712 │ CA │ Goderich │ Goderich │
│ CYQI │ 43.8175 │ -66.0975 │ 141 │ CA │ Yarmouth │ Yarmouth │
│ CYKZ │ 43.86444 │ -79.37334 │ 650 │ CA │ Buttonville Muni │ Richmond Hill │
│ CYOO │ 43.92444 │ -78.90389 │ 459 │ CA │ Oshawa │ Oshawa │
│ CYTR │ 44.10889 │ -77.54222 │ 283 │ CA │ Trenton │ Quinte West │
│ CYGK │ 44.21833 │ -76.60083 │ 305 │ CA │ Kingston │ Kingston │
└─────────┴──────────┴───────────┴───────┴─────────┴───────────────────────────────┴────────────────┘
これらの空港は236の異なる国にまたがっています。
$ ~/duckdb
SELECT COUNT(DISTINCT country)
FROM READ_CSV('openap/data/nav/airports.csv');
236
これらは空港データセットで最も多く代表されている国です。
SELECT COUNT(*),
country
FROM READ_CSV('openap/data/nav/airports.csv')
GROUP BY 2
ORDER BY 1 DESC
LIMIT 20;
┌──────────────┬─────────┐
│ count_star() │ country │
│ int64 │ varchar │
├──────────────┼─────────┤
│ 2849 │ BR │
│ 2459 │ US │
│ 2062 │ AU │
│ 441 │ FR │
│ 345 │ CA │
│ 325 │ DE │
│ 258 │ GB │
│ 234 │ ID │
│ 176 │ NA │
│ 168 │ VE │
│ 156 │ RU │
│ 148 │ IN │
│ 143 │ AR │
│ 139 │ SE │
│ 126 │ JP │
│ 118 │ IT │
│ 106 │ NZ │
│ 99 │ CZ │
│ 98 │ BO │
│ 97 │ ZA │
└──────────────┴─────────┘
これらはナビゲーションウェイポイントの一部です。
$ echo "import pandas as pd; print(
pd.read_fwf('openap/data/nav/fix.dat',
skiprows=3,
header=None,
encoding='unicode_escape')
.to_csv(index=False))"
| python3
| ~/duckdb
-c '.maxwidth 150'
-c "FROM READ_CSV('/dev/stdin')
WHERE column0 BETWEEN 57 AND 59
AND column1 BETWEEN 21 AND 27
LIMIT 20"
┌──────────┬───────────┬─────────┐
│ column0 │ column1 │ column2 │
│ double │ double │ varchar │
├──────────┼───────────┼─────────┤
│ 57.133196 │ 23.888414 │ ALISA │
│ 57.105833 │ 25.254167 │ AMOLI │
│ 58.416389 │ 24.478333 │ ANAMA │
│ 58.412778 │ 22.521667 │ EIKLA │
│ 58.506944 │ 25.715278 │ EKLON │
│ 58.626667 │ 21.766111 │ EVERI │
│ 57.278611 │ 25.050556 │ GEKLI │
│ 58.9425 │ 25.576944 │ GONOS │
│ 58.053333 │ 26.762778 │ KANEP │
│ 58.331944 │ 22.221111 │ KARLA │
│ 58.7225 │ 24.586944 │ KEMET │
│ 58.725753 │ 26.736943 │ KOLEV │
│ 58.708056 │ 22.845833 │ KUKET │
│ 58.931111 │ 24.661944 │ KUNUX │
│ 58.176667 │ 26.93 │ KUUST │
│ 58.441667 │ 26.451667 │ LAEVA │
│ 58.553333 │ 25.934444 │ LALSI │
│ 57.336944 │ 22.636944 │ LAPSA │
│ 57.774167 │ 22.104444 │ LATEG │
│ 58.180278 │ 25.779167 │ LATKA │
└───────────┴───────────┴─────────┘
これらはナビゲーションエイドの一部です。
$ wc -l openap/data/nav/nav.dat # 26775
$ echo "import pandas as pd; print(
pd.read_fwf('openap/data/nav/nav.dat',
skiprows=3,
header=None,
encoding='unicode_escape')
.to_csv(index=False))"
| python3
| ~/duckdb
-c '.maxwidth 150'
-c "SELECT * EXCLUDE(column9)
FROM READ_CSV('/dev/stdin')
WHERE column1 BETWEEN 57 AND 59
AND column2 BETWEEN 21 AND 27
LIMIT 20"
┌─────────┬───────────┬───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────────────────┐
│ column0 │ column1 │ column2 │ column3 │ column4 │ column5 │ column6 │ column7 │ column8 │
│ int64 │ double │ double │ varchar │ double │ double │ double │ varchar │ varchar │
├─────────┼───────────┼───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────────────────┤
│ 2 │ 58.957117 │ 22.872158 │ 0 │ 317.0 │ 80.0 │ 0.0 │ OZ │ KARDLA NDB │
│ 2 │ 58.270722 │ 22.508778 │ 0 │ 350.0 │ 80.0 │ 0.0 │ WA │ KURESSAARE NDB │
│ 2 │ 58.490806 │ 24.571556 │ 0 │ 425.0 │ 80.0 │ 0.0 │ RC │ PARNU NDB │
│ 2 │ 58.435833 │ 24.495861 │ 0 │ 376.0 │ 25.0 │ 0.0 │ R │ PARNU NDB │
│ 2 │ 58.308583 │ 26.768417 │ 0 │ 397.0 │ 80.0 │ 0.0 │ UM │ TARTU NDB │
│ 3 │ 58.228333 │ 22.515361 │ 39 │ 240.0 │ 50.0 │ 3.0 │ KRS │ KURESSAARE VOR-DME │
│ 3 │ 58.416583 │ 24.465972 │ 58 │ 590.0 │ 25.0 │ 6.0 │ PRN │ PARNU VOR-DME │
│ 3 │ 57.366944 │ 21.556222 │ 0 │ 360.0 │ 130.0 │ 5.3 │ VNT │ VENTSPILS VOR-DME │
│ 3 │ 58.655889 │ 25.574778 │ 227 │ 490.0 │ 80.0 │ 5.0 │ VI │ VOHMA VOR-DME │
│ 1 │ 58.228333 │ 22.515361 │ 3 │ 124.0 │ 5.0 │ 0.0 │ KR │ KURESSAARE VOR-DME │
│ 1 │ 58.416583 │ 24.465972 │ 5 │ 159.0 │ 2.0 │ 0.0 │ PR │ PARNU VOR-DME │
│ 1 │ 57.366944 │ 21.556222 │ NULL │ 136.0 │ 13.0 │ 0.0 │ VN │ VENTSPILS VOR-DME │
│ 1 │ 58.655889 │ 25.574778 │ 22 │ 149.0 │ 8.0 │ 0.0 │ VI │ VOHMA VOR-DME │
│ 1 │ 58.992083 │ 22.830972 │ 3 │ 176.0 │ 2.0 │ 0.0 │ KR │ KARDLA DME │
└─────────┴───────────┴───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────────────────┘
トゥールーズからベルリンへ
以下で、トゥールーズ・ブラニャック空港(LFBO / TLS)からベルリン・ブランデンブルク空港(EDDB / BER)までの最適な飛行経路を見つけます。
$ python3
import numpy as np
from openap.aero import cas2mach, ft, kts
from openap.extra.nav import airport
from pygeodesy.ellipsoidalVincenty import LatLon
from skdecide.hub.domain\
.flight_planning\
.aircraft_performance\
.bean.aircraft_state \
import AircraftState
from skdecide.hub.domain\
.flight_planning\
.aircraft_performance\
.performance.performance_model_enum \
import PerformanceModelEnum
from skdecide.hub.domain\
.flight_planning\
.aircraft_performance\
.performance.phase_enum \
import PhaseEnum
from skdecide.hub.domain\
.flight_planning\
.aircraft_performance\
.performance.rating_enum \
import RatingEnum
from skdecide.hub.domain\
.flight_planning\
.domain \
import FlightPlanningDomain, \
WeatherDate
from skdecide.hub.domain\
.flight_planning\
.flightplanning_utils \
import plot_network_adapted
from skdecide.hub.solver.astar import Astar
ヒューリスティックパラメータは、「time」、「distance」、「lazy_fuel」、「lazy_time」、またはNoneのいずれかです。何も渡されない場合、A*はDijkstraライクな探索アルゴリズムを使用します。
origin = "LFPG"
destination = "LFBO"
aircraft = "A320"
weather_date = WeatherDate(day=1, month=5, year=2026)
heuristic = "lazy_fuel"
cost_function = "fuel"
acState = AircraftState(
model_type="A320",
performance_model_type=PerformanceModelEnum.OPENAP,
gw_kg=80_000,
zp_ft=10_000,
mach=cas2mach(250 * kts, h=10_000 * ft),
phase=PhaseEnum.CLIMB,
rating_level=RatingEnum.MCL,
cg=0.3)
domain_factory = lambda: FlightPlanningDomain(
aircraft_state=acState,
mach_cruise=0.78,
mach_climb=0.7,
mach_descent=0.65,
nb_forward_points=20,
nb_lateral_points=10,
nb_climb_descent_steps=5,
flight_levels_ft=list(np.arange(30_000, 38_000 + 2_000, 2_000)),
graph_width="medium",
origin=LatLon(43.629444, 1.363056),
destination="EDDB",
objective=cost_function,
heuristic_name=heuristic,
weather_date=weather_date)
domain = domain_factory()
上記が実行されると、天気データがNOAAから取得されておらず、フライトの日付が過去6ヶ月以内である場合、GRB2ファイルがダウンロードされます。
$ du -hs ~/skdecide_data/weather/grib/nowcast/*/*.grb2
144M /home/mark/skdecide_data/weather/grib/nowcast/20260501/gfs_4_20260501_0000_000.grb2
144M /home/mark/skdecide_data/weather/grib/nowcast/20260501/gfs_4_20260501_0600_000.grb2
143M /home/mark/skdecide_data/weather/grib/nowcast/20260501/gfs_4_20260501_1200_000.grb2
143M /home/mark/skdecide_data/weather/grib/nowcast/20260501/gfs_4_20260501_1800_000.grb2
各ファイルは地球全体をカバーするデータを含んでいます。これらは、QGISでグローブ上にレンダリングされたgfs_4_20260501_1800_000.grb2の内容です。
これはソルバーの高度と地理的な探索空間です。
plot_network_adapted(
graph=domain.network,
p0=LatLon(43.629444, 1.363056),
p1=LatLon(
airport("EDDB")["lat"],
airport("EDDB")["lon"],
airport("EDDB")["alt"] * ft))
これはソルバーによる最適な飛行経路です。
solver = Astar(
domain_factory=domain_factory,
heuristic=lambda d, s: d.heuristic(s),
parallel=False)
solver.solve()
A* finished to solve from state ... in 0.28 seconds
domain.custom_rollout(solver=solver, make_img=True)
Goal reached after 19 steps!
({'time': 7666.281474928903, 'fuel': 5855.093906205222}, None)
飛行計画の各ステップを、より読みやすいようにフォーマットします。
domain.observation.trajectory.to_csv('TLS-BER.csv', index=None)
$ ~/duckdb
SELECT phase: UPPER(phase),
time_: ts::INT,
alt: alt::INT,
mass: mass::INT,
mach: ROUND(mach, 2),
cas: cas::INT,
fuel: fuel::INT,
geom: ST_POINT(lon, lat)
FROM 'TLS-BER.csv'
ORDER BY ts;
┌─────────┬───────┬───────┬───────┬────────┬───────┬───────┬────────────────────────────────────────────────┐
│ phase │ time_ │ alt │ mass │ mach │ cas │ fuel │ geom │
│ varchar │ int32 │ int32 │ int32 │ double │ int32 │ int32 │ geometry │
├─────────┼───────┼───────┼───────┼────────┼───────┼───────┼────────────────────────────────────────────────┤
│ CLIMB │ 28800 │ 0 │ 80000 │ 0.45 │ 154 │ 0 │ POINT (1.363056 43.629444) │
│ CLIMB │ 29183 │ 12000 │ 79402 │ 0.7 │ 194 │ 598 │ POINT (1.3614644301412264 44.431571122861556) │
│ CLIMB │ 29767 │ 18000 │ 78717 │ 0.7 │ 173 │ 685 │ POINT (0.8028803270337778 45.54329961845038) │
│ CLIMB │ 30367 │ 24000 │ 78104 │ 0.7 │ 154 │ 2 │ POINT (0.22308186850312028 46.64860136322122) │
│ CLIMB │ 30369 │ 24000 │ 78102 │ 0.7 │ 154 │ 2 │ POINT (0.2213600223765711 46.65181397470445) │
│ CLIMB │ 30691 │ 30000 │ 77808 │ 0.7 │ 135 │ 294 │ POINT (0.781910701674247 47.146798229437145) │
│ CRUISE │ 31222 │ 30000 │ 77331 │ 0.78 │ 152 │ 477 │ POINT (0.18057649919536045 48.254448220756515) │
│ CRUISE │ 31515 │ 30000 │ 77070 │ 0.78 │ 152 │ 262 │ POINT (0.7571242215277763 48.74964861278412) │
│ CRUISE │ 31805 │ 30000 │ 76812 │ 0.78 │ 152 │ 258 │ POINT (1.3446668642885302 49.24219441171162) │
│ CRUISE │ 32093 │ 30000 │ 76555 │ 0.78 │ 152 │ 256 │ POINT (1.943586016571517 49.732000774167815) │
│ CRUISE │ 32382 │ 30000 │ 76298 │ 0.78 │ 152 │ 257 │ POINT (2.554285524033502 50.218985517421046) │
│ CRUISE │ 32672 │ 30000 │ 76041 │ 0.78 │ 152 │ 257 │ POINT (3.1771982015706532 50.70307279893911) │
│ CRUISE │ 32961 │ 30000 │ 75786 │ 0.78 │ 152 │ 256 │ POINT (3.812797488711077 51.18419969012497) │
│ CRUISE │ 33252 │ 30000 │ 75529 │ 0.78 │ 152 │ 257 │ POINT (4.461619033936127 51.66232853895605) │
│ CRUISE │ 33547 │ 32000 │ 75270 │ 0.78 │ 146 │ 259 │ POINT (5.1243038676232 52.13747186609129) │
│ CRUISE │ 34103 │ 30000 │ 74794 │ 0.78 │ 152 │ 476 │ POINT (7.006628090474678 51.93831668841654) │
│ DESCENT │ 34458 │ 24031 │ 74503 │ 0.65 │ 142 │ 290 │ POINT (7.7011825929472675 52.40044729715865) │
│ DESCENT │ 35058 │ 18063 │ 73995 │ 0.65 │ 160 │ 51 │ POINT (9.423199233939213 52.1821111144618) │
│ DESCENT │ 35114 │ 18063 │ 73944 │ 0.65 │ 160 │ 51 │ POINT (9.580613666598857 52.160789987133924) │
│ DESCENT │ 35714 │ 12094 │ 73388 │ 0.65 │ 179 │ 13 │ POINT (11.398384342445423 51.895274115132494) │
│ DESCENT │ 35727 │ 12094 │ 73375 │ 0.65 │ 179 │ 13 │ POINT (11.435080901553494 51.88959204464927) │
│ DESCENT │ 36063 │ 6126 │ 73023 │ 0.65 │ 199 │ 352 │ POINT (12.17769156482302 52.32776873134525) │
│ DESCENT │ 36466 │ 48 │ 72534 │ 0.65 │ 221 │ 488 │ POINT (13.48503 52.36769) │
└─────────┴───────┴───────┴───────┴────────┴───────┴───────┴────────────────────────────────────────────────┘
飛行計画をParquetにエクスポートし、地上レベルの風データの上にQGISでレンダリングします。
COPY (
SELECT * EXCLUDE(lon, lat),
geometry: ST_POINT(lon, lat)
FROM 'TLS-BER.csv'
ORDER BY ts
) TO 'TLS-BER.parquet' (
FORMAT 'PARQUET',
CODEC 'ZSTD',
COMPRESSION_LEVEL 22,
ROW_GROUP_SIZE 15000);
トゥールーズからワルシャワへ
以下で、トゥールーズ・ブラニャック空港(LFBO / TLS)からワルシャワ・ショパン空港(EPWA / WAW)までの最適な飛行経路を見つけます。
初期目標高度は、前の例よりもはるかに高くなります。その結果、はるかに直接的なルートを取ることができるフライトになります。
acState = AircraftState(
model_type="A320",
performance_model_type=PerformanceModelEnum.OPENAP,
gw_kg=80_000,
zp_ft=18000.0,
mach=cas2mach(250 * kts, h=10_000 * ft),
phase=PhaseEnum.CLIMB,
rating_level=RatingEnum.MCL,
cg=0.3,
x_graph=5,
y_graph=5,
z_graph=10)
domain_factory = lambda: FlightPlanningDomain(
aircraft_state=acState,
mach_cruise=0.78,
mach_climb=0.7,
mach_descent=0.65,
nb_forward_points=20,
nb_lateral_points=10,
nb_climb_descent_steps=5,
flight_levels_ft=list(np.arange(30_000, 38_000 + 2_000, 2_000)),
graph_width="medium",
origin=LatLon(43.629444, 1.363056),
destination="EPWA",
objective=cost_function,
heuristic_name=heuristic,
weather_date=weather_date)
domain = domain_factory()
solver = Astar(
domain_factory=domain_factory,
heuristic=lambda d, s: d.heuristic(s),
parallel=False)
solver.solve()
A* finished to solve from state ... in 29.45 seconds.
domain.custom_rollout(solver=solver, make_img=True)
Goal reached after 14 steps!
({'time': 6153.660431613251, 'fuel': 5600.171145693044}, None)
ワルシャワはベルリンよりもトゥールーズから500km遠いですが、与えられた風条件下での巡航高度へのより速い上昇により、航空機はより直接的なルートを取ることができました。ワルシャワには約45分早く到着し、ベルリン便が必要とした燃料の76%しか必要としませんでした。
これらは上記の飛行計画のステップです。
domain.observation.trajectory.to_csv('TLS-WAW.csv', index=None)
$ ~/duckdb
SELECT phase: UPPER(phase),
time_: ts::INT,
alt: alt::INT,
mass: mass::INT,
mach: ROUND(mach, 2),
cas: cas::INT,
fuel: fuel::INT,
geom: ST_POINT(lon, lat)
FROM 'TLS-WAW.csv'
ORDER BY ts;
┌─────────┬───────┬───────┬───────┬────────┬───────┬───────┬───────────────────────────────────────────────┐
│ phase │ time_ │ alt │ mass │ mach │ cas │ fuel │ geom │
│ varchar │ int32 │ int32 │ int32 │ double │ int32 │ int32 │ geometry │
├─────────┼───────┼───────┼───────┼────────┼───────┼───────┼───────────────────────────────────────────────┤
│ CLIMB │ 28800 │ 30000 │ 80000 │ 0.45 │ 85 │ 0 │ POINT (6.321780309765473 45.78957852956533) │
│ CRUISE │ 29196 │ 32000 │ 79639 │ 0.78 │ 146 │ 361 │ POINT (7.274006698354081 46.275553205520794) │
│ CRUISE │ 29604 │ 34000 │ 79276 │ 0.78 │ 139 │ 363 │ POINT (8.243146568075773 46.75332543362598) │
│ CRUISE │ 30018 │ 36000 │ 78915 │ 0.78 │ 133 │ 361 │ POINT (9.229481862337197 47.22261290149568) │
│ CRUISE │ 30436 │ 38000 │ 78555 │ 0.78 │ 127 │ 360 │ POINT (10.23327610333648 47.68312559281413) │
│ CRUISE │ 30861 │ 38000 │ 78191 │ 0.78 │ 127 │ 365 │ POINT (11.25477083484032 48.13456566890824) │
│ CRUISE │ 31297 │ 36000 │ 77819 │ 0.78 │ 133 │ 371 │ POINT (12.29418112454121 48.57662718213212) │
│ CRUISE │ 31732 │ 34000 │ 77449 │ 0.78 │ 139 │ 370 │ POINT (13.351689351409924 49.00899540355703) │
│ CRUISE │ 32161 │ 32000 │ 77082 │ 0.78 │ 146 │ 367 │ POINT (14.427435465032865 49.431345252175966) │
│ CRUISE │ 32589 │ 30000 │ 76710 │ 0.78 │ 152 │ 372 │ POINT (15.521498988740307 49.843337488922174) │
│ DESCENT │ 33101 │ 24066 │ 76280 │ 0.65 │ 142 │ 429 │ POINT (16.633858546975723 50.2446086742223) │
│ DESCENT │ 33589 │ 18131 │ 75861 │ 0.65 │ 160 │ 420 │ POINT (17.764276668345886 50.63474030548783) │
│ DESCENT │ 34046 │ 12197 │ 75433 │ 0.65 │ 179 │ 428 │ POINT (18.91184798374883 51.01313503252613) │
│ DESCENT │ 34472 │ 6262 │ 74984 │ 0.65 │ 199 │ 449 │ POINT (20.071843186874247 51.378167839584854) │
│ DESCENT │ 34954 │ 100 │ 74400 │ 0.65 │ 221 │ 584 │ POINT (20.94663 52.17147) │
└─────────┴───────┴───────┴───────┴────────┴───────┴───────┴───────────────────────────────────────────────┘
## Airbus A320 vs Boeing 737
OpenTopはOpenAPと組み合わせて、空港間の飛行軌道を計算するために使用できます。
そのオプティマイザーはグリッドコストファイルを必要とします。まず、プロジェクトが提供する例の142 MBのNetCDFファイルをダウンロードします。
$ wget https://opendap.4tu.nl/thredds/fileServer/data2/djht/bea8a3fe-e34c-4598-9f94-c5a5c63348e5/1/contrail_original.nc
コストファイルはCasadiまたはParquet形式のいずれかです。私はそのドキュメントの[例](https://openap.dev/optimize/contrails.html)から作業し、246 KBのCasadiファイルが生成されました。
import openap
import pandas as pd
from scipy.ndimage import gaussian_filter
from opentop.tools import cached_interpolant_from_dataframe
import xarray as xr
ds = xr.open_dataset('contrail_original.nc')
.sel(time='2015-12-18')
level_pressure = [
0.0000,
10.0000,
30.0000,
50.0000,
70.0000,
90.0787,
110.6606,
132.3968,
155.7909,
181.1544,
208.6494,
238.3258,
270.1530,
304.0465,
339.8891,
377.5467,
416.8789,
457.7442,
500.0000,
543.4970,
588.0685,
633.5144,
679.5799,
725.9285,
772.1102,
817.5241,
861.3757,
902.6287,
939.9520,
971.6610,
995.6532,
1009.3396]
df = (
ds.to_dataframe()
.reset_index()
.assign(lev=lambda x: x.lev.astype(int))
.merge(
pd.DataFrame(level_pressure, columns=["hPa"]).reset_index(names="lev"),
on="lev",
)
.assign(height=lambda x: openap.aero.h_isa(x.hPa * 100).round(-2))
.assign(longitude=lambda x: ((x.lon + 180) % 360 - 180))
.query("height<15000"))
df_cost_world = df.rename(
columns={
"lat": "latitude",
"atr20_contrail": "cost",
}
)[["time",
"latitude",
"longitude",
"hPa",
"height",
"cost"]]
df_cost = df_cost_world.query(
"-20<longitude<40 and 30<latitude<70 and time.dt.hour==12"
).sort_values(["height", "latitude", "longitude"])
cost = df_cost.cost.values.reshape(
df_cost.height.nunique(),
df_cost.latitude.nunique(),
df_cost.longitude.nunique())
cost_ = gaussian_filter(cost, sigma=1, mode="nearest")
df_cost = df_cost.assign(cost=cost_.flatten())
interpolant = cached_interpolant_from_dataframe(
df_cost,
"contrail.casadi",
shape="bspline")
これらはその内容の最初と最後の数バイトです。
$ hexdump -C contrail.casadi | head
00000000 6a 68 70 6e 6e 61 67 69 69 65 61 68 61 61 61 61 |jhpnnagiieahaaaa|
00000010 64 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |daaaaaaaaaaaaaaa|
00000020 61 61 66 61 65 67 61 61 6c 61 61 61 61 61 61 61 |aafaegaalaaaaaaa|
00000030 6a 65 6f 67 65 68 66 67 63 68 61 68 70 67 6d 67 |jeogehfgchahpgmg|
00000040 62 67 6f 67 65 68 68 61 61 61 61 61 61 61 63 67 |bgogehhaaaaaaacg|
00000050 64 68 61 68 6d 67 6a 67 6f 67 66 67 63 61 61 61 |dhahmgjgogfgcaaa|
00000060 61 61 61 61 6a 61 61 61 61 61 61 61 68 67 63 68 |aaaajaaaaaaahgch|
00000070 6a 67 65 67 70 66 64 67 70 67 64 68 65 68 61 61 |jgegpfdgpgdhehaa|
00000080 61 61 61 61 61 61 62 61 69 61 61 61 61 61 61 61 |aaaaaabaiaaaaaaa|
00000090 62 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |baaaaaaaaaaaaaaa|
$ hexdump -C contrail.casadi | tail
0003d620 61 61 61 61 61 61 64 62 61 61 61 61 61 61 61 61 |aaaaaadbaaaaaaaa|
0003d630 61 61 61 61 61 61 67 62 61 61 61 61 61 61 61 61 |aaaaaagbaaaaaaaa|
0003d640 61 61 61 61 61 61 68 62 61 61 61 61 61 61 61 61 |aaaaaahbaaaaaaaa|
0003d650 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |aaaaaaaaaaaaaaaa|
0003d660 61 61 61 61 61 61 62 61 61 61 61 61 61 61 61 61 |aaaaaabaaaaaaaaa|
0003d670 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 |aaaaaaaaaaaaaaaa|
0003d680 61 61 61 61 61 61 62 61 61 61 62 61 61 61 61 61 |aaaaaabaaabaaaaa|
0003d690 61 61 61 61 61 61 61 61 61 61 63 68 67 61 61 61 |aaaaaaaaaachgaaa|
0003d6a0 61 61 61 61 61 61 61 61 61 61 61 61 |aaaaaaaaaaaa|
0003d6ac
内容は繰り返しが多く、よく圧縮されることに気づきました。
$ gzip -9 < contrail.casadi | wc -c
90949
アムステルダム・スキポール空港(EHAM / AMS)とフランクフルト(EDDF / FRA)間のエアバスA320での最適なフライトの指標を取得します。
$ opentop optimize
EHAM EDDF
-a A320
--phase all
--obj "0.3fuel+0.7grid"
--grid contrail.casadi
aircraft: A320
route: EHAM → EDDF
phase: all
objective: 0.3fuel+0.7grid
m0: 0.85
max_iter: 1500
grid file: contrail.casadi
success: True
return_status: Solve_Succeeded
iter_count: 179
wall time: 12.2 s
objective: 4.8768e+02
fuel burn: 1625.6 kg
max altitude: 19891 ft
flight time: 35.8 min
次に、同様のことをボーイング737で行います。
$ opentop optimize
EHAM EDDF
-a B737
--phase all
--obj "0.3fuel+0.7grid"
--grid contrail.casadi
aircraft: B737
route: EHAM → EDDF
phase: all
objective: 0.3fuel+0.7grid
m0: 0.85
max_iter: 1500
grid file: contrail.casadi
success: True
return_status: Solve_Succeeded
iter_count: 141
wall time: 9.9 s
objective: 4.8662e+02
fuel burn: 1622.1 kg
max altitude: 21968 ft
flight time: 39.2 min
この記事をお読みいただきありがとうございます。北米とヨーロッパのクライアント向けにコンサルティングおよび実務開発サービスを提供しています。私のサービスがビジネスにどのように役立つかについてご相談したい場合は、[LinkedIn](https://uk.linkedin.com/in/marklitwintschik/)からご連絡ください。