hyplan 1.6.2__py3-none-any.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.
Files changed (97) hide show
  1. hyplan/__init__.py +257 -0
  2. hyplan/_auth.py +50 -0
  3. hyplan/_trochoid_solver.py +669 -0
  4. hyplan/_version.py +24 -0
  5. hyplan/aircraft/__init__.py +102 -0
  6. hyplan/aircraft/_base.py +2265 -0
  7. hyplan/aircraft/_models.py +2577 -0
  8. hyplan/aircraft/_planned_sortie.py +829 -0
  9. hyplan/aircraft/adsb/__init__.py +35 -0
  10. hyplan/aircraft/adsb/airdata.py +209 -0
  11. hyplan/aircraft/adsb/fitting.py +434 -0
  12. hyplan/aircraft/adsb/io.py +205 -0
  13. hyplan/aircraft/adsb/models.py +155 -0
  14. hyplan/aircraft/adsb/phases.py +218 -0
  15. hyplan/aircraft/adsb/pipeline.py +195 -0
  16. hyplan/aircraft/adsb/priors.py +42 -0
  17. hyplan/aircraft/eol_ncar.py +55 -0
  18. hyplan/aircraft/icartt.py +332 -0
  19. hyplan/aircraft/iwg1.py +376 -0
  20. hyplan/aircraft/wind_path.py +202 -0
  21. hyplan/airports.py +521 -0
  22. hyplan/airspace.py +1970 -0
  23. hyplan/atmosphere.py +170 -0
  24. hyplan/campaign.py +829 -0
  25. hyplan/clouds/__init__.py +57 -0
  26. hyplan/clouds/analysis.py +175 -0
  27. hyplan/clouds/forecast.py +185 -0
  28. hyplan/clouds/plotting.py +327 -0
  29. hyplan/clouds/sources.py +574 -0
  30. hyplan/data/__init__.py +7 -0
  31. hyplan/data/de421.bsp +0 -0
  32. hyplan/data/faa_radar_exclusion_zones.geojson +26044 -0
  33. hyplan/download.py +45 -0
  34. hyplan/dubins3d.py +702 -0
  35. hyplan/exceptions.py +49 -0
  36. hyplan/exports/__init__.py +49 -0
  37. hyplan/exports/_common.py +191 -0
  38. hyplan/exports/csv.py +159 -0
  39. hyplan/exports/excel.py +323 -0
  40. hyplan/exports/gpx.py +54 -0
  41. hyplan/exports/icartt.py +180 -0
  42. hyplan/exports/kml.py +101 -0
  43. hyplan/exports/text.py +172 -0
  44. hyplan/flight_box.py +708 -0
  45. hyplan/flight_line.py +807 -0
  46. hyplan/flight_optimizer.py +931 -0
  47. hyplan/flight_patterns.py +797 -0
  48. hyplan/flight_plan.py +18 -0
  49. hyplan/geometry.py +852 -0
  50. hyplan/glint.py +795 -0
  51. hyplan/instruments/__init__.py +76 -0
  52. hyplan/instruments/_base.py +77 -0
  53. hyplan/instruments/awp.py +978 -0
  54. hyplan/instruments/frame_camera.py +853 -0
  55. hyplan/instruments/line_scanner.py +323 -0
  56. hyplan/instruments/lvis.py +937 -0
  57. hyplan/instruments/profilinglidar.py +294 -0
  58. hyplan/instruments/radar.py +396 -0
  59. hyplan/pattern.py +399 -0
  60. hyplan/phenology/__init__.py +39 -0
  61. hyplan/phenology/_appeears.py +223 -0
  62. hyplan/phenology/_qa.py +147 -0
  63. hyplan/phenology/analysis.py +125 -0
  64. hyplan/phenology/plotting.py +391 -0
  65. hyplan/phenology/sources.py +942 -0
  66. hyplan/planning/__init__.py +30 -0
  67. hyplan/planning/engine.py +554 -0
  68. hyplan/planning/isochrone.py +2915 -0
  69. hyplan/planning/segments.py +360 -0
  70. hyplan/plotting.py +1279 -0
  71. hyplan/py.typed +0 -0
  72. hyplan/satellites.py +884 -0
  73. hyplan/sun.py +412 -0
  74. hyplan/swath.py +295 -0
  75. hyplan/terrain/__init__.py +99 -0
  76. hyplan/terrain/_demgrid.py +42 -0
  77. hyplan/terrain/elevation.py +138 -0
  78. hyplan/terrain/intersection.py +237 -0
  79. hyplan/terrain/io.py +292 -0
  80. hyplan/units.py +176 -0
  81. hyplan/waypoint.py +208 -0
  82. hyplan/winds/__init__.py +82 -0
  83. hyplan/winds/base.py +38 -0
  84. hyplan/winds/factory.py +136 -0
  85. hyplan/winds/gridded.py +297 -0
  86. hyplan/winds/providers/__init__.py +8 -0
  87. hyplan/winds/providers/gfs.py +262 -0
  88. hyplan/winds/providers/gmao.py +87 -0
  89. hyplan/winds/providers/iwg1_trace.py +83 -0
  90. hyplan/winds/providers/merra2.py +91 -0
  91. hyplan/winds/simple.py +58 -0
  92. hyplan/winds/utils.py +358 -0
  93. hyplan-1.6.2.dist-info/METADATA +466 -0
  94. hyplan-1.6.2.dist-info/RECORD +97 -0
  95. hyplan-1.6.2.dist-info/WHEEL +5 -0
  96. hyplan-1.6.2.dist-info/licenses/LICENSE.md +250 -0
  97. hyplan-1.6.2.dist-info/top_level.txt +1 -0
hyplan/__init__.py ADDED
@@ -0,0 +1,257 @@
1
+ """
2
+ HyPlan - Planning software for airborne remote sensing science campaigns.
3
+
4
+ Core objects are re-exported here for convenience::
5
+
6
+ from hyplan import FlightLine, FlightBox, Airport, ureg
7
+ from hyplan import KingAirB200, AVIRIS3
8
+
9
+ Specialized modules (clouds, terrain, satellites, glint, sun) should be
10
+ imported directly::
11
+
12
+ from hyplan.clouds import create_cloud_data_array_with_limit
13
+ from hyplan.terrain import download_dem
14
+ """
15
+
16
+ try:
17
+ from ._version import version as __version__
18
+ except ImportError:
19
+ # Package not installed via setuptools-scm (e.g. editable dev install
20
+ # before first build), fall back to a default.
21
+ __version__ = "0.0.0.dev0"
22
+
23
+ import logging as _logging
24
+
25
+
26
+ def setup_logging(
27
+ level: int = _logging.INFO,
28
+ format: str = "%(asctime)s %(name)s %(levelname)s: %(message)s",
29
+ ) -> None:
30
+ """Attach a StreamHandler to the ``hyplan`` logger.
31
+
32
+ Library code uses ``logging.getLogger(__name__)`` everywhere and never
33
+ configures handlers itself. Call this once from a notebook, script, or
34
+ CLI to see hyplan's INFO/WARNING messages. Idempotent — re-calling
35
+ replaces the handler instead of stacking duplicates.
36
+ """
37
+ logger = _logging.getLogger("hyplan")
38
+ for h in list(logger.handlers):
39
+ if getattr(h, "_hyplan_managed", False):
40
+ logger.removeHandler(h)
41
+ handler = _logging.StreamHandler()
42
+ handler.setFormatter(_logging.Formatter(format))
43
+ handler._hyplan_managed = True # type: ignore[attr-defined] # custom attr on logging.Handler
44
+ logger.addHandler(handler)
45
+ logger.setLevel(level)
46
+ logger.propagate = False
47
+
48
+
49
+ # --- Core re-exports ---
50
+
51
+ # Exceptions
52
+ from .exceptions import (
53
+ HyPlanError,
54
+ HyPlanValueError,
55
+ HyPlanTypeError,
56
+ HyPlanRuntimeError,
57
+ )
58
+
59
+ # Units
60
+ from .units import ureg, convert_distance, convert_speed, convert_angle, convert_time, altitude_to_flight_level
61
+
62
+ # Flight geometry
63
+ from .flight_line import FlightLine
64
+ from .pattern import Pattern
65
+ from .flight_box import box_around_center_line, box_around_polygon, box_around_center_terrain, box_around_polygon_terrain, altitude_msl_for_pixel_size
66
+
67
+ # Aircraft
68
+ from .aircraft import (
69
+ Aircraft,
70
+ NASA_ER2,
71
+ NASA_GIII,
72
+ NASA_GIV,
73
+ NASA_GV,
74
+ NASA_C20A,
75
+ NASA_P3,
76
+ NOAA_WP3D,
77
+ NOAA_GIV,
78
+ NASA_WB57,
79
+ NASA_B777,
80
+ KingAirB200,
81
+ KingAirA90,
82
+ KingAir350,
83
+ NASA_C130,
84
+ NOAA_TwinOtter,
85
+ BAS_TwinOtter,
86
+ FAAM_BAe146,
87
+ SAFIRE_ATR42,
88
+ NERC_DO228,
89
+ AWI_BaslerBT67,
90
+ DLR_HALO,
91
+ )
92
+
93
+ # Airports
94
+ from .airports import (
95
+ Airport,
96
+ initialize_data,
97
+ find_nearest_airport,
98
+ find_nearest_airports,
99
+ airports_within_radius,
100
+ )
101
+
102
+ # Sensors
103
+ from .instruments import (
104
+ Sensor,
105
+ LineScanner,
106
+ AVIRISClassic,
107
+ AVIRISNextGen,
108
+ AVIRIS3,
109
+ AVIRIS5,
110
+ HyTES,
111
+ PRISM,
112
+ MASTER,
113
+ GLiHT_VNIR,
114
+ GLiHT_Thermal,
115
+ GLiHT_SIF,
116
+ GCAS_UV_Vis,
117
+ GCAS_VNIR,
118
+ eMAS,
119
+ PICARD,
120
+ SENSOR_REGISTRY,
121
+ create_sensor,
122
+ FrameCamera,
123
+ MultiCameraRig,
124
+ LVISLens,
125
+ LVIS_LENS_NARROW,
126
+ LVIS_LENS_MEDIUM,
127
+ LVIS_LENS_WIDE,
128
+ LVIS_LENSES,
129
+ LVIS,
130
+ AerosolWindProfiler,
131
+ flag_awp_stable_segments,
132
+ awp_profile_locations_for_flight_line,
133
+ awp_profile_locations_for_plan,
134
+ ProfilingLidar,
135
+ HSRL2,
136
+ HALO,
137
+ CPL,
138
+ RadarExclusionConflict,
139
+ check_lband_radar_exclusions,
140
+ SidelookingRadar,
141
+ UAVSAR_Lband,
142
+ UAVSAR_Pband,
143
+ UAVSAR_Kaband,
144
+ )
145
+ # Waypoint and Dubins path planning
146
+ from .waypoint import Waypoint
147
+ from .dubins3d import DubinsPath2D
148
+
149
+ # Swath
150
+ from .swath import generate_swath_polygon, calculate_swath_widths, analyze_swath_gaps_overlaps
151
+
152
+ # Flight patterns
153
+ from .flight_patterns import racetrack, rosette, polygon, sawtooth, spiral, flight_lines_to_waypoint_path, coordinated_line
154
+
155
+ # Flight planning and optimization
156
+ from .planning import compute_flight_plan, compute_isochrone, compute_concentric_isochrones, compute_refuel_isochrone, evaluate_target_reachability, isochrone_polygon, plot_isochrone
157
+
158
+ # Wind fields
159
+ from .winds import WindField, StillAirField, ConstantWindField, MERRA2WindField, GMAOWindField, GFSWindField, wind_field_from_plan
160
+ from .flight_optimizer import build_graph, greedy_optimize
161
+
162
+ # Plotting
163
+ from .plotting import (
164
+ map_flight_lines, plot_flight_plan, plot_altitude_trajectory,
165
+ terrain_profile_along_track,
166
+ plot_airspace_map, plot_isochrone_static,
167
+ plot_oceanic_tracks, plot_vertical_profile,
168
+ plot_conflict_matrix, map_airspace,
169
+ )
170
+
171
+ # Exports
172
+ from .exports import (
173
+ to_excel, to_pilot_excel, to_foreflight_csv,
174
+ to_honeywell_fms, to_er2_csv, to_icartt,
175
+ to_kml, to_gpx, to_txt,
176
+ )
177
+
178
+ # Airspace
179
+ from .airspace import (
180
+ Airspace, AirspaceConflict, OpenAIPClient,
181
+ check_airspace_conflicts, check_airspace_proximity,
182
+ fetch_and_check, clear_airspace_cache,
183
+ classify_severity, FAATFRClient, NASRAirspaceSource,
184
+ convert_agl_floors, filter_by_schedule,
185
+ summarize_airspaces,
186
+ OceanicTrack, FlightPlanDBClient,
187
+ )
188
+
189
+ # Campaign
190
+ from .campaign import Campaign
191
+
192
+ __all__ = [
193
+ # Logging
194
+ "setup_logging",
195
+ # Exceptions
196
+ "HyPlanError", "HyPlanValueError", "HyPlanTypeError", "HyPlanRuntimeError",
197
+ # Units
198
+ "ureg", "convert_distance", "convert_speed", "convert_angle", "convert_time", "altitude_to_flight_level",
199
+ # Flight geometry
200
+ "FlightLine", "Pattern", "box_around_center_line", "box_around_polygon", "box_around_center_terrain", "box_around_polygon_terrain", "altitude_msl_for_pixel_size",
201
+ # Aircraft
202
+ "Aircraft",
203
+ "NASA_ER2", "NASA_GIII", "NASA_GIV", "NASA_GV", "NASA_C20A", "NASA_P3", "NOAA_WP3D", "NOAA_GIV",
204
+ "NASA_WB57", "NASA_B777",
205
+ "KingAirB200", "KingAirA90", "KingAir350",
206
+ "NASA_C130", "NOAA_TwinOtter",
207
+ "BAS_TwinOtter", "FAAM_BAe146", "SAFIRE_ATR42", "NERC_DO228", "AWI_BaslerBT67", "DLR_HALO",
208
+ # Airports
209
+ "Airport", "initialize_data",
210
+ "find_nearest_airport", "find_nearest_airports", "airports_within_radius",
211
+ # Sensors
212
+ "Sensor", "LineScanner",
213
+ "AVIRISClassic", "AVIRISNextGen", "AVIRIS3", "AVIRIS5",
214
+ "HyTES", "PRISM", "MASTER",
215
+ "GLiHT_VNIR", "GLiHT_Thermal", "GLiHT_SIF",
216
+ "GCAS_UV_Vis", "GCAS_VNIR", "eMAS", "PICARD",
217
+ "SENSOR_REGISTRY", "create_sensor",
218
+ "FrameCamera", "MultiCameraRig",
219
+ "LVISLens", "LVIS_LENS_NARROW", "LVIS_LENS_MEDIUM", "LVIS_LENS_WIDE", "LVIS_LENSES", "LVIS",
220
+ "AerosolWindProfiler", "ProfilingLidar", "HSRL2", "HALO", "CPL",
221
+ "RadarExclusionConflict", "check_lband_radar_exclusions",
222
+ "SidelookingRadar", "UAVSAR_Lband", "UAVSAR_Pband", "UAVSAR_Kaband",
223
+ # Dubins
224
+ "Waypoint", "DubinsPath2D",
225
+ # Swath
226
+ "generate_swath_polygon", "calculate_swath_widths", "analyze_swath_gaps_overlaps",
227
+ # AWP profiling
228
+ "flag_awp_stable_segments", "awp_profile_locations_for_flight_line", "awp_profile_locations_for_plan",
229
+ # Flight patterns
230
+ "racetrack", "rosette", "polygon", "sawtooth", "spiral", "flight_lines_to_waypoint_path",
231
+ "coordinated_line",
232
+ # Wind
233
+ "WindField", "StillAirField", "ConstantWindField", "MERRA2WindField", "GMAOWindField", "GFSWindField", "wind_field_from_plan",
234
+ # Flight planning
235
+ "compute_flight_plan", "plot_flight_plan", "plot_altitude_trajectory",
236
+ "compute_isochrone", "compute_concentric_isochrones", "compute_refuel_isochrone", "evaluate_target_reachability", "isochrone_polygon", "plot_isochrone",
237
+ "build_graph", "greedy_optimize",
238
+ # Plotting
239
+ "map_flight_lines", "terrain_profile_along_track",
240
+ "plot_airspace_map", "plot_isochrone_static",
241
+ "plot_oceanic_tracks", "plot_vertical_profile",
242
+ "plot_conflict_matrix", "map_airspace",
243
+ # Exports
244
+ "to_excel", "to_pilot_excel", "to_foreflight_csv",
245
+ "to_honeywell_fms", "to_er2_csv", "to_icartt",
246
+ "to_kml", "to_gpx", "to_txt",
247
+ # Airspace
248
+ "Airspace", "AirspaceConflict", "OpenAIPClient",
249
+ "check_airspace_conflicts", "check_airspace_proximity",
250
+ "fetch_and_check", "clear_airspace_cache",
251
+ "classify_severity", "FAATFRClient", "NASRAirspaceSource",
252
+ "convert_agl_floors", "filter_by_schedule",
253
+ "summarize_airspaces",
254
+ "OceanicTrack", "FlightPlanDBClient",
255
+ # Campaign
256
+ "Campaign",
257
+ ]
hyplan/_auth.py ADDED
@@ -0,0 +1,50 @@
1
+ """Shared NASA Earthdata authentication utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from .exceptions import HyPlanRuntimeError
8
+
9
+
10
+ def _require_earthaccess() -> Any:
11
+ """Import and return earthaccess, raising a clear error if not installed."""
12
+ try:
13
+ import earthaccess
14
+
15
+ return earthaccess
16
+ except ImportError:
17
+ raise HyPlanRuntimeError(
18
+ "earthaccess is required for NASA Earthdata authentication. "
19
+ "Install with: pip install earthaccess"
20
+ ) from None
21
+
22
+
23
+ def _earthdata_login() -> Any:
24
+ """Authenticate with NASA Earthdata using ``earthaccess``.
25
+
26
+ Tries strategies in order: ``EARTHDATA_TOKEN`` env var, ``~/.netrc``,
27
+ then interactive prompt. Returns an authenticated ``requests.Session``
28
+ with a bearer token suitable for OPeNDAP access.
29
+
30
+ Raises :class:`~hyplan.exceptions.HyPlanRuntimeError` if ``earthaccess``
31
+ is not installed or login fails.
32
+ """
33
+ earthaccess = _require_earthaccess()
34
+
35
+ # Try non-interactive strategies first
36
+ for strategy in ("environment", "netrc"):
37
+ try:
38
+ auth = earthaccess.login(strategy=strategy)
39
+ if auth.authenticated:
40
+ return earthaccess.get_requests_https_session()
41
+ except Exception:
42
+ continue
43
+
44
+ raise HyPlanRuntimeError(
45
+ "NASA Earthdata login failed. Authenticate via one of:\n"
46
+ " 1. Set EARTHDATA_TOKEN environment variable\n"
47
+ " 2. Add to ~/.netrc:\n"
48
+ " machine urs.earthdata.nasa.gov login <user> password <pass>\n"
49
+ "Register at https://urs.earthdata.nasa.gov if needed."
50
+ )