PyGeoFetch 2.6.2.6__tar.gz → 2.6.2.8__tar.gz

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 (235) hide show
  1. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/CHANGELOG.md +7 -7
  2. {pygeofetch-2.6.2.6/pygeofetch.egg-info → pygeofetch-2.6.2.8}/PKG-INFO +31 -30
  3. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/README.md +30 -29
  4. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/__init__.py +1 -1
  5. pygeofetch-2.6.2.8/pygeofetch/geotech/__init__.py +0 -0
  6. pygeofetch-2.6.2.8/pygeofetch/geotech/risk_mapper.py +276 -0
  7. pygeofetch-2.6.2.8/pygeofetch/insar/auto_fallback.py +348 -0
  8. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/meta.yaml +1 -1
  9. pygeofetch-2.6.2.8/pygeofetch/processing/uq_exporter.py +227 -0
  10. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/usgs.py +31 -11
  11. pygeofetch-2.6.2.8/pygeofetch/stac_compute/__init__.py +0 -0
  12. pygeofetch-2.6.2.8/pygeofetch/stac_compute/lightweight_prefetch.py +406 -0
  13. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8/pygeofetch.egg-info}/PKG-INFO +31 -30
  14. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch.egg-info/SOURCES.txt +12 -2
  15. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pyproject.toml +1 -1
  16. pygeofetch-2.6.2.8/tests/test_auto_fallback.py +186 -0
  17. pygeofetch-2.6.2.8/tests/test_auto_fallback_fixed.py +226 -0
  18. pygeofetch-2.6.2.8/tests/test_lightweight_prefetch.py +279 -0
  19. pygeofetch-2.6.2.8/tests/test_risk_mapper.py +200 -0
  20. pygeofetch-2.6.2.8/tests/test_uq_exporter.py +212 -0
  21. pygeofetch-2.6.2.6/tests/test_provider_geometry_audit (1).py +0 -204
  22. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/LICENSE +0 -0
  23. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/MANIFEST.in +0 -0
  24. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/__init__.py +0 -0
  25. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/auth_commands.py +0 -0
  26. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/config_commands.py +0 -0
  27. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/download_commands.py +0 -0
  28. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/index_commands.py +0 -0
  29. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/main.py +0 -0
  30. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/monitor_commands.py +0 -0
  31. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/multisensor_commands.py +0 -0
  32. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/optical_commands.py +0 -0
  33. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/pipeline_process_commands.py +0 -0
  34. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/postprocess_commands.py +0 -0
  35. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/preprocess_commands.py +0 -0
  36. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/sar_commands.py +0 -0
  37. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/cli/search_commands.py +0 -0
  38. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/config/__init__.py +0 -0
  39. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/config/defaults.yaml +0 -0
  40. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/config/settings.py +0 -0
  41. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/__init__.py +0 -0
  42. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/authenticator.py +0 -0
  43. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/cache_manager.py +0 -0
  44. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/data_organizer.py +0 -0
  45. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/downloader.py +0 -0
  46. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/engine.py +0 -0
  47. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/logging.py +0 -0
  48. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/monitor.py +0 -0
  49. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/orbits.py +0 -0
  50. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/scheduler.py +0 -0
  51. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/searcher.py +0 -0
  52. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/core/state.py +0 -0
  53. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/__init__.py +0 -0
  54. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/advanced_safeguards.py +0 -0
  55. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/analysis.py +0 -0
  56. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/annotation.py +0 -0
  57. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/atmosphere.py +0 -0
  58. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/coregister.py +0 -0
  59. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/deburst.py +0 -0
  60. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/esd.py +0 -0
  61. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/extraction.py +0 -0
  62. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/flatearth.py +0 -0
  63. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/geolocation.py +0 -0
  64. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/gpu.py +0 -0
  65. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/interferogram.py +0 -0
  66. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/ionosphere.py +0 -0
  67. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/offset_geometry.py +0 -0
  68. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/offset_tracking.py +0 -0
  69. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/preflight.py +0 -0
  70. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/provenance.py +0 -0
  71. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/ps_selection.py +0 -0
  72. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/splitspectrum_diagnostic.py +0 -0
  73. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/stack_selection.py +0 -0
  74. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/synthetic.py +0 -0
  75. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/timeseries.py +0 -0
  76. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/unwrap.py +0 -0
  77. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/validate.py +0 -0
  78. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/visualize.py +0 -0
  79. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/insar/workflow.py +0 -0
  80. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/models/__init__.py +0 -0
  81. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/models/download_task.py +0 -0
  82. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/models/satellite_data.py +0 -0
  83. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/models/search_query.py +0 -0
  84. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/models/user_auth.py +0 -0
  85. /pygeofetch-2.6.2.6/pygeofetch/multisensor/multisensor_init.py → /pygeofetch-2.6.2.8/pygeofetch/multisensor/_init.py +0 -0
  86. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/multisensor/dem_differencing.py +0 -0
  87. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/multisensor/flood_mapping.py +0 -0
  88. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/multisensor/insar_optical_fusion.py +0 -0
  89. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/multisensor/terrain_corrected_change.py +0 -0
  90. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/multisensor/vegetation_disturbance.py +0 -0
  91. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/optical/__init__.py +0 -0
  92. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/optical/offset_tracking.py +0 -0
  93. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processing/__init__.py +0 -0
  94. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processing/base.py +0 -0
  95. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processing/batch.py +0 -0
  96. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processing/indices.py +0 -0
  97. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processing/pipeline.py +0 -0
  98. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processing/postprocessor.py +0 -0
  99. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processing/preprocessor.py +0 -0
  100. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processing/sar.py +0 -0
  101. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processor/__init__.py +0 -0
  102. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processor/indices.py +0 -0
  103. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processor/landsat.py +0 -0
  104. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processor/loader.py +0 -0
  105. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processor/stacker.py +0 -0
  106. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/processor/timeseries.py +0 -0
  107. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/__init__.py +0 -0
  108. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/airbus_oneatlas.py +0 -0
  109. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/alaska_satellite_facility.py +0 -0
  110. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/aws_earth.py +0 -0
  111. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/base.py +0 -0
  112. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/copernicus.py +0 -0
  113. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/copernicus_nodes.py +0 -0
  114. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/digitalglobe.py +0 -0
  115. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/earth_explorer_additional.py +0 -0
  116. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/element84.py +0 -0
  117. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/eodag_provider.py +0 -0
  118. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/esa_scihub.py +0 -0
  119. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/geoserver_generic.py +0 -0
  120. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/google_earth_engine.py +0 -0
  121. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/inpe_cbers.py +0 -0
  122. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/isro_bhuvan.py +0 -0
  123. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/jaxa_earth.py +0 -0
  124. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/maxar_gbdx.py +0 -0
  125. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/nasa_earthdata.py +0 -0
  126. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/nasa_earthdata_cloud.py +0 -0
  127. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/noaa_big_data.py +0 -0
  128. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/opentopography.py +0 -0
  129. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/planet.py +0 -0
  130. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/planetary_computer.py +0 -0
  131. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/sentinel_hub.py +0 -0
  132. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/providers/terrabotics.py +0 -0
  133. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/sar/__init__.py +0 -0
  134. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/sar/_native.py +0 -0
  135. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/sar/_ost.py +0 -0
  136. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/sar/_sarxarray.py +0 -0
  137. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/sar/extraction.py +0 -0
  138. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/sar/math.py +0 -0
  139. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/sar/pipelines.py +0 -0
  140. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/sar/processor.py +0 -0
  141. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/utils/__init__.py +0 -0
  142. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/utils/file_utils.py +0 -0
  143. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/utils/gcp_recovery.py +0 -0
  144. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/utils/geo_utils.py +0 -0
  145. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/utils/logging_setup.py +0 -0
  146. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/utils/retry_handler.py +0 -0
  147. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/utils/sar_math.py +0 -0
  148. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/utils/validators.py +0 -0
  149. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/validation/__init__.py +0 -0
  150. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/validation/optical_validator.py +0 -0
  151. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/viz/__init__.py +0 -0
  152. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/viz/map.py +0 -0
  153. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch/viz/plot.py +0 -0
  154. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch.egg-info/dependency_links.txt +0 -0
  155. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch.egg-info/entry_points.txt +0 -0
  156. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch.egg-info/not-zip-safe +0 -0
  157. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch.egg-info/requires.txt +0 -0
  158. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/pygeofetch.egg-info/top_level.txt +0 -0
  159. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/setup.cfg +0 -0
  160. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_advanced_safeguards.py +0 -0
  161. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_airbus_oneatlas.py +0 -0
  162. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_alaska_satellite_facility.py +0 -0
  163. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_atmospheric_circular_regression.py +0 -0
  164. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_build_sbas_network-new.py +0 -0
  165. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_build_sbas_network.py +0 -0
  166. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_burst_metadata.py +0 -0
  167. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_burst_processing_integration.py +0 -0
  168. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_burst_sync_large_gap.py +0 -0
  169. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_burst_sync_prescreening.py +0 -0
  170. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_burst_synchronization.py +0 -0
  171. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_circuit_breaker_wiring.py +0 -0
  172. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_cli_optical_validation.py +0 -0
  173. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_copernicus_nodes.py +0 -0
  174. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_coregister_integration.py +0 -0
  175. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_coregister_upgrades (1).py +0 -0
  176. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_coregister_upgrades.py +0 -0
  177. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_credential_encryption.py +0 -0
  178. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_data_organizer.py +0 -0
  179. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_dem_differencing_pipeline.py +0 -0
  180. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_digitalglobe.py +0 -0
  181. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_earth_explorer_additional.py +0 -0
  182. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_era5_atmospheric_correction.py +0 -0
  183. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_esa_scihub.py +0 -0
  184. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_extraction.py +0 -0
  185. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_flat_earth_phase.py +0 -0
  186. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_flood_mapping_pipeline.py +0 -0
  187. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_gcp_reprojection.py +0 -0
  188. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_geology_indices_and_rvi_fix.py +0 -0
  189. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_geoserver_generic.py +0 -0
  190. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_google_earth_engine.py +0 -0
  191. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_inpe_cbers.py +0 -0
  192. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_insar.py +0 -0
  193. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_insar_optical_fusion_pipeline.py +0 -0
  194. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_ionosphere.py +0 -0
  195. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_isro_bhuvan.py +0 -0
  196. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_jaxa_earth.py +0 -0
  197. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_map_preview_consolidation.py +0 -0
  198. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_models.py +0 -0
  199. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_monitor.py +0 -0
  200. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_nasa_earthdata_cloud_s3_fix.py +0 -0
  201. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_nasa_earthdata_public_search.py +0 -0
  202. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_noaa_big_data.py +0 -0
  203. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_offset_tracking.py +0 -0
  204. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_opentopography_pointcloud_usgs.py +0 -0
  205. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_optical_offset_tracking.py +0 -0
  206. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_optical_validation_wiring.py +0 -0
  207. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_optical_validator.py +0 -0
  208. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_optical_validator_stac.py +0 -0
  209. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_pgv_integration_contract.py +0 -0
  210. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_pipeline_process_export.py +0 -0
  211. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_planet_asset_type_fix.py +0 -0
  212. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_preflight_gate.py +0 -0
  213. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_preflight_spatial_baseline.py +0 -0
  214. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_provider_geometry_audit.py +0 -0
  215. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_provider_scene_disambiguation.py +0 -0
  216. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_providers.py +0 -0
  217. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_ps_selection.py +0 -0
  218. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_raster_collocation_integration.py +0 -0
  219. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_reference_pixel_and_despike.py +0 -0
  220. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_risk_mapping.py +0 -0
  221. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_sar_pipelines.py +0 -0
  222. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_screen_stack_orchestration.py +0 -0
  223. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_search_download.py +0 -0
  224. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_sentinel_hub_catalog_fix.py +0 -0
  225. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_sign_convention.py +0 -0
  226. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_splitspectrum_diagnostic.py +0 -0
  227. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_stack_selection_consolidation.py +0 -0
  228. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_state.py +0 -0
  229. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_strain_and_fusion.py +0 -0
  230. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_terrain_corrected_change_pipeline.py +0 -0
  231. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_topo_r2_bug.py +0 -0
  232. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_utils.py +0 -0
  233. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_vegetation_disturbance_pipeline.py +0 -0
  234. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_viz_plot.py +0 -0
  235. {pygeofetch-2.6.2.6 → pygeofetch-2.6.2.8}/tests/test_wls_inversion.py +0 -0
@@ -20,7 +20,7 @@ date, and marked accordingly rather than filled in with invented
20
20
  bullet points.
21
21
  ```
22
22
 
23
- ## [Unreleased] — v2.6.2.6.4
23
+ ## [Unreleased] — v2.6.2.8.4
24
24
 
25
25
  ```{note}
26
26
  Not yet published to PyPI. This entry documents work completed and
@@ -130,7 +130,7 @@ audit and remain open for a follow-up pass.
130
130
 
131
131
  ---
132
132
 
133
- ## [2.6.2.6.4] — 2026-08-25 (latest)
133
+ ## [2.6.2.8.4] — 2026-08-25 (latest)
134
134
 
135
135
  Confirmed via direct fetch of the current PyPI listing.
136
136
 
@@ -149,7 +149,7 @@ Confirmed via direct fetch of the current PyPI listing.
149
149
  - `SearchQuery.sort_ascending: bool` — earlier examples showed a `sort_order: "asc"/"desc"` string field that doesn't exist on the model (the CLI's `--sort-order` flag does convert to this internally, so CLI docs were unaffected)
150
150
  - `DownloadOptions.post_process` requires a list of `PostProcessAction` objects — passing plain strings raises a real `pydantic.ValidationError`
151
151
 
152
- ## [2.6.2.6] — 2026-08-24
152
+ ## [2.6.2.8] — 2026-08-24
153
153
  Real, verified release. Detailed notes not independently recovered from PyPI's release-history page (no distinct per-version notes exposed for this release specifically).
154
154
 
155
155
  ## [2.6.1] — 2026-08-22
@@ -261,9 +261,9 @@ recovered.
261
261
 
262
262
  ```{note}
263
263
  The previous version of this changelog had an entry labeled
264
- **"2.6.2.6.4 — 2026-07-12"** describing 22+ providers, Sentinel-1C/1D
264
+ **"2.6.2.8.4 — 2026-07-12"** describing 22+ providers, Sentinel-1C/1D
265
265
  support, SLC search with provider routing, precise orbit file
266
- management, 17 spectral indices, and various bug fixes. **2.6.2.6.4 was
266
+ management, 17 spectral indices, and various bug fixes. **2.6.2.8.4 was
267
267
  only ever released once, on 2026-08-25** — it was never released on
268
268
  2026-07-12. The date matches this real release, **1.0.8**, exactly.
269
269
  That content is reproduced below under the version it actually
@@ -406,8 +406,8 @@ The version of this file uploaded for this update had **5 entries
406
406
  covering 5 dates**. PyPI's real release history has **54 releases**.
407
407
  Specific issues found and fixed:
408
408
 
409
- 1. **Two different entries were both labeled `2.6.2.6.4`**, dated
410
- 2026-07-29 and 2026-07-12. **2.6.2.6.4 was only ever released once**,
409
+ 1. **Two different entries were both labeled `2.6.2.8.4`**, dated
410
+ 2026-07-29 and 2026-07-12. **2.6.2.8.4 was only ever released once**,
411
411
  on 2026-08-25 (confirmed directly from the live PyPI listing).
412
412
  2. **The 2026-07-12 entry's date exactly matches a real release**
413
413
  — version **1.0.8** — and its content (22+ providers, Sentinel-1C/D,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygeofetch
3
- Version: 2.6.2.6
3
+ Version: 2.6.2.8
4
4
  Summary: Universal satellite data pipeline + geospatial processing platform
5
5
  Author-email: Samuel Appiah Kubi <appiahkubis14@gmail.com>
6
6
  License: MIT License
@@ -146,8 +146,9 @@ Dynamic: license-file
146
146
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22087230.svg)](https://doi.org/10.5281/zenodo.22087230)
147
147
  [![Tests](https://github.com/EOCoreINT/pygeofetch/actions/workflows/tests.yml/badge.svg)](https://github.com/EOCoreINT/pygeofetch/actions/workflows/tests.yml)
148
148
  [![codecov](https://codecov.io/gh/appiahkubis14/pygeofetch/graph/badge.svg?token=2PS2A2VZL6)](https://codecov.io/gh/appiahkubis14/pygeofetch)
149
+ [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-ea4aaa?logo=githubsponsors)](https://github.com/sponsors/appiahkubis14)
149
150
 
150
- **A unified satellite data and geospatial processing platform — one CLI, one Python API, 24 providers, and a fully verified InSAR chain.**
151
+ **A unified satellite data and geospatial processing platform — one CLI, one Python API, 22 verified providers, and a fully verified InSAR chain.**
151
152
 
152
153
  [Quick Start](#-quick-start) · [Mexico City Case Study](#-case-study-mapping-mexico-city-land-subsidence-with-insar) · [Case Study Repo ↗](https://github.com/EOCoreINT/mexico-subsidence-project) · [Documentation](https://pygeofetch.readthedocs.io/en/latest/) · [Notebooks](#-notebooks)
153
154
 
@@ -158,7 +159,7 @@ Dynamic: license-file
158
159
 
159
160
  ## Overview
160
161
 
161
- pygeofetch is a production-ready framework for acquiring and processing Earth observation data. It provides authenticated, unified access to **24 satellite repositories** — Sentinel, Landsat, Planet, Maxar, Airbus, Copernicus, USGS, NASA, JAXA, and more — through a single CLI and Python API, and layers a complete geospatial processing engine on top.
162
+ pygeofetch is a production-ready framework for acquiring and processing Earth observation data. It provides authenticated, unified access to **22 verified satellite providers** — Sentinel, Landsat, Planet, Maxar, Airbus, Copernicus, USGS, NASA, JAXA, and more — through a single CLI and Python API, and layers a complete geospatial processing engine on top.
162
163
 
163
164
  Where pygeofetch goes further than most data-access libraries is in its **InSAR chain**: burst-aware coregistration, real flat-earth and topographic phase removal, ERA5 tropospheric and ionospheric correction, phase unwrapping, and SBAS time-series inversion — each stage independently verified against synthetic ground truth or real, published deformation studies, not assumed correct from theory alone. The [Mexico City case study](#-case-study-mapping-mexico-city-land-subsidence-with-insar) below walks through that chain end to end on real Sentinel-1 data.
164
165
 
@@ -166,13 +167,13 @@ Where pygeofetch goes further than most data-access libraries is in its **InSAR
166
167
 
167
168
  | | |
168
169
  |---|---|
169
- | 🔐 **Authenticated access** | 24 providers, credentials stored via system keyring (Keychain / Credential Manager / Secret Service) |
170
- | 🔍 **Federated search** | One query across all providers → STAC 1.0 GeoJSON / GeoParquet / CSV, with real footprint geometry where the provider supplies it |
171
- | 📥 **Resilient downloads** | Parallel, resumable, checksum-verified, band-selective, atomic writes |
172
- | ⚙️ **Preprocessing** | Atmospheric correction, cloud masking, reprojection, resampling, pan-sharpening, mosaicking |
173
- | 📊 **17 spectral indices** | NDVI, EVI, SAVI, NDWI, MNDWI, NDBI, LST, Albedo, dNBR, GLCM texture, and more |
174
- | 🌐 **Verified InSAR chain** | Coregistration → phase removal → atmospheric/ionospheric correction → unwrapping → SBAS inversion |
175
- | 📋 **YAML pipelines** | Chainable, schedulable, repeatable workflows with full run history |
170
+ | **Authenticated access** | 22 verified providers; credentials stored via a Fernet-encrypted local file by default, or the system keyring (Keychain / Credential Manager / Secret Service) as an opt-in alternative |
171
+ | **Federated search** | One query across all providers → STAC 1.0 GeoJSON / GeoParquet / CSV, with real footprint geometry where the provider supplies it |
172
+ | **Resilient downloads** | Parallel, resumable, checksum-verified, band-selective, atomic writes |
173
+ | **Preprocessing** | Atmospheric correction, cloud masking, reprojection, resampling, pan-sharpening, mosaicking |
174
+ | **17 spectral indices** | NDVI, EVI, SAVI, NDWI, MNDWI, NDBI, LST, Albedo, dNBR, GLCM texture, and more |
175
+ | **Verified InSAR chain** | Coregistration → phase removal → atmospheric/ionospheric correction → unwrapping → SBAS inversion |
176
+ | **YAML pipelines** | Chainable, schedulable, repeatable workflows with full run history |
176
177
 
177
178
  ---
178
179
 
@@ -192,7 +193,7 @@ Satellite data access is fragmented — every provider has its own auth scheme,
192
193
 
193
194
  | Feature | pygeofetch | EODAG | pystac-client | satpy | sentinelsat |
194
195
  |---|---|---|---|---|---|
195
- | Providers | **24** | 10+ | STAC only | Limited | Sentinel only |
196
+ | Providers | **22** | 10+ | STAC only | Limited | Sentinel only |
196
197
  | Processing engine | ✅ Full | ❌ | ❌ | Partial | ❌ |
197
198
  | Spectral indices | ✅ 17+ | ❌ | ❌ | ❌ | ❌ |
198
199
  | Full InSAR chain | ✅ Verified | ❌ | ❌ | ❌ | ❌ |
@@ -204,9 +205,9 @@ Satellite data access is fragmented — every provider has its own auth scheme,
204
205
 
205
206
  ## Providers
206
207
 
207
- **11 open-access providers**, no login required — including `planetary_computer`, `aws_earth`, `element84`, `noaa_big_data`, `esa_scihub`, `jaxa_earth`, and `geoserver_generic` for any OGC WMS/WFS/WCS endpoint.
208
+ **22 verified providers total.** Open-access, no login required — including `planetary_computer`, `aws_earth`, `element84`, `noaa_big_data`, `jaxa_earth`, and `geoserver_generic` for any OGC WMS/WFS/WCS endpoint.
208
209
 
209
- **13 authenticated providers** — USGS, Copernicus CDSE, NASA Earthdata (+ Cloud), Alaska SAR Facility, OpenTopography, Planet Labs, Sentinel Hub, Maxar GBDX, Airbus OneAtlas, Google Earth Engine, TerraBotics, and Earth Explorer.
210
+ Authenticated — USGS, Copernicus CDSE, NASA Earthdata (+ Cloud), Alaska SAR Facility, OpenTopography, Planet Labs, Sentinel Hub, Maxar GBDX, Airbus OneAtlas, and Earth Explorer.
210
211
 
211
212
  Every provider has been directly verified to return at minimum a correct bounding box; several are further confirmed to return real, precise footprint geometry against a live API response (marked in `pygeofetch providers info PROVIDER`). Run `pygeofetch providers list` for the full, current table.
212
213
 
@@ -260,23 +261,12 @@ Mexico City sits on a drained lakebed and is subsiding at some of the fastest ra
260
261
 
261
262
  **1. Authenticated federated search.** `client.search()` against Copernicus Data Space for SLC scenes over the city (bbox `-99.183, 19.278, -99.003, 19.438`, July 2016 – September 2017) returns a stack of Sentinel-1A/1B candidates in seconds, filterable straight down to a single consistent track.
262
263
 
263
- <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/data-search.png" width="85%" /></p>
264
-
265
264
  Results carry real footprint geometry and drop straight onto a map via `MapViewer`, with hover info for scene ID, date, satellite, and provider — useful for spotting swath overlap before committing to a download.
266
265
 
267
- <p align="center">
268
- <img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/search_1.png" width="48%" />
269
- <img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/search.png" width="48%" />
270
- </p>
271
-
272
266
  **2. DEM acquisition.** A matching search against OpenTopography returns seven DEM products for the AOI; pygeofetch downloads and clips the selected one (SRTM 30 m) automatically for topographic phase removal.
273
267
 
274
- <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/dem_acquisition.png" width="85%" /></p>
275
-
276
268
  **3. Preflight validation.** Before anything downloads, the `PreflightGate` checks search truncation, AOI coverage, temporal network connectivity, and burst-timing family compatibility from lightweight annotation XMLs — catching acquisitions that would waste compute before they cost bandwidth. This run avoided roughly 360 GB of downloads by excluding 48 of 115 candidate scenes at this stage alone.
277
269
 
278
- <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/preflight-log.png" width="85%" /></p>
279
-
280
270
  Real orbit state vectors then pre-filter the candidate pair list against Sentinel-1's own mission thresholds, rejecting pairs for excess burst-sync error, temporal baseline, or spatial baseline before any interferogram is attempted.
281
271
 
282
272
  <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/pre-filter-for-interferogram.png" width="85%" /></p>
@@ -298,8 +288,6 @@ Real orbit state vectors then pre-filter the candidate pair list against Sentine
298
288
 
299
289
  **7. SBAS time-series inversion.** The full 58-date descending stack, once low-coherence and unreliable-reference-pixel pairs are excluded, fractures into 17 disconnected network "islands" — a genuine finding about this AOI's data quality, not a bug. The largest connected island (10 dates, 11 pairs) carries the final inversion, referenced near Cerro de la Estrella.
300
290
 
301
- <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/1.png" width="85%" /></p>
302
-
303
291
  The resulting velocity field, uncertainty map, reliability mask, and displacement time series recover a 2nd–98th-percentile vertical velocity of **−35.5 to −2.9 cm/year** where reliable pixels exist.
304
292
 
305
293
  <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/island1_sbas_full_analysis.png" width="90%" /></p>
@@ -381,7 +369,7 @@ If you use PyGeoFetch in your research or operational work, please cite it using
381
369
  title = {PyGeoFetch: A Unified Python Framework for Multi-Provider Satellite Data Acquisition, Pre-download Quality Control, and Geospatial Processing},
382
370
  year = {2026},
383
371
  publisher = {Zenodo},
384
- version = {2.6.2.6.1},
372
+ version = {2.6.2.8.1},
385
373
  doi = {10.5281/zenodo.22087230},
386
374
  url = {https://doi.org/10.5281/zenodo.22087230}
387
375
  }
@@ -391,15 +379,28 @@ If you use PyGeoFetch in your research or operational work, please cite it using
391
379
 
392
380
  Full documentation: **https://pygeofetch.readthedocs.io/en/latest/** — CLI reference, provider auth guides, pipeline configuration, post-processing catalogue, and InSAR verification methodology.
393
381
 
382
+ ## Support this project
383
+
384
+ pygeofetch is built and maintained by a single developer, in the open,
385
+ alongside a full-time workload — the InSAR/optical fusion chain, the
386
+ provider verification work, and the documentation are all real,
387
+ independently-verified engineering, not a side project maintained on
388
+ autopilot. If pygeofetch is useful to your research or your
389
+ organization, sponsoring its development directly funds the time spent
390
+ keeping 22 provider integrations current as their real APIs change, and
391
+ building out the multi-sensor pipelines documented above.
392
+
393
+ [![Sponsor on GitHub](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-ea4aaa?logo=githubsponsors)](https://github.com/sponsors/appiahkubis14)
394
+
394
395
  ## Contributing
395
396
 
396
397
  Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Good first issues include extending real footprint geometry to remaining bbox-only providers, wiring stub providers to full API integrations, and adding new post-processing actions.
397
398
 
398
399
  ```bash
399
400
  git clone git@github.com:EOCoreINT/pygeofetch.git && cd pygeofetch
400
- pip install -e ".[dev,all]" && pytest tests/unit/ -v
401
-
401
+ pip install -e ".[test]" && pytest tests/ -v
402
+ ```
402
403
 
403
404
  ## License
404
405
 
405
- MIT — see [LICENSE](LICENSE). © 2026 Samuel Appiah Kubi. Part of the **PyGeoVision** platform, alongside [pygeofetch](https://github.com/appiahkubis14/pygeofetch) itself.
406
+ MIT — see [LICENSE](LICENSE). © 2026 Samuel Appiah Kubi.
@@ -6,8 +6,9 @@
6
6
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22087230.svg)](https://doi.org/10.5281/zenodo.22087230)
7
7
  [![Tests](https://github.com/EOCoreINT/pygeofetch/actions/workflows/tests.yml/badge.svg)](https://github.com/EOCoreINT/pygeofetch/actions/workflows/tests.yml)
8
8
  [![codecov](https://codecov.io/gh/appiahkubis14/pygeofetch/graph/badge.svg?token=2PS2A2VZL6)](https://codecov.io/gh/appiahkubis14/pygeofetch)
9
+ [![Sponsor](https://img.shields.io/badge/Sponsor-%E2%9D%A4-ea4aaa?logo=githubsponsors)](https://github.com/sponsors/appiahkubis14)
9
10
 
10
- **A unified satellite data and geospatial processing platform — one CLI, one Python API, 24 providers, and a fully verified InSAR chain.**
11
+ **A unified satellite data and geospatial processing platform — one CLI, one Python API, 22 verified providers, and a fully verified InSAR chain.**
11
12
 
12
13
  [Quick Start](#-quick-start) · [Mexico City Case Study](#-case-study-mapping-mexico-city-land-subsidence-with-insar) · [Case Study Repo ↗](https://github.com/EOCoreINT/mexico-subsidence-project) · [Documentation](https://pygeofetch.readthedocs.io/en/latest/) · [Notebooks](#-notebooks)
13
14
 
@@ -18,7 +19,7 @@
18
19
 
19
20
  ## Overview
20
21
 
21
- pygeofetch is a production-ready framework for acquiring and processing Earth observation data. It provides authenticated, unified access to **24 satellite repositories** — Sentinel, Landsat, Planet, Maxar, Airbus, Copernicus, USGS, NASA, JAXA, and more — through a single CLI and Python API, and layers a complete geospatial processing engine on top.
22
+ pygeofetch is a production-ready framework for acquiring and processing Earth observation data. It provides authenticated, unified access to **22 verified satellite providers** — Sentinel, Landsat, Planet, Maxar, Airbus, Copernicus, USGS, NASA, JAXA, and more — through a single CLI and Python API, and layers a complete geospatial processing engine on top.
22
23
 
23
24
  Where pygeofetch goes further than most data-access libraries is in its **InSAR chain**: burst-aware coregistration, real flat-earth and topographic phase removal, ERA5 tropospheric and ionospheric correction, phase unwrapping, and SBAS time-series inversion — each stage independently verified against synthetic ground truth or real, published deformation studies, not assumed correct from theory alone. The [Mexico City case study](#-case-study-mapping-mexico-city-land-subsidence-with-insar) below walks through that chain end to end on real Sentinel-1 data.
24
25
 
@@ -26,13 +27,13 @@ Where pygeofetch goes further than most data-access libraries is in its **InSAR
26
27
 
27
28
  | | |
28
29
  |---|---|
29
- | 🔐 **Authenticated access** | 24 providers, credentials stored via system keyring (Keychain / Credential Manager / Secret Service) |
30
- | 🔍 **Federated search** | One query across all providers → STAC 1.0 GeoJSON / GeoParquet / CSV, with real footprint geometry where the provider supplies it |
31
- | 📥 **Resilient downloads** | Parallel, resumable, checksum-verified, band-selective, atomic writes |
32
- | ⚙️ **Preprocessing** | Atmospheric correction, cloud masking, reprojection, resampling, pan-sharpening, mosaicking |
33
- | 📊 **17 spectral indices** | NDVI, EVI, SAVI, NDWI, MNDWI, NDBI, LST, Albedo, dNBR, GLCM texture, and more |
34
- | 🌐 **Verified InSAR chain** | Coregistration → phase removal → atmospheric/ionospheric correction → unwrapping → SBAS inversion |
35
- | 📋 **YAML pipelines** | Chainable, schedulable, repeatable workflows with full run history |
30
+ | **Authenticated access** | 22 verified providers; credentials stored via a Fernet-encrypted local file by default, or the system keyring (Keychain / Credential Manager / Secret Service) as an opt-in alternative |
31
+ | **Federated search** | One query across all providers → STAC 1.0 GeoJSON / GeoParquet / CSV, with real footprint geometry where the provider supplies it |
32
+ | **Resilient downloads** | Parallel, resumable, checksum-verified, band-selective, atomic writes |
33
+ | **Preprocessing** | Atmospheric correction, cloud masking, reprojection, resampling, pan-sharpening, mosaicking |
34
+ | **17 spectral indices** | NDVI, EVI, SAVI, NDWI, MNDWI, NDBI, LST, Albedo, dNBR, GLCM texture, and more |
35
+ | **Verified InSAR chain** | Coregistration → phase removal → atmospheric/ionospheric correction → unwrapping → SBAS inversion |
36
+ | **YAML pipelines** | Chainable, schedulable, repeatable workflows with full run history |
36
37
 
37
38
  ---
38
39
 
@@ -52,7 +53,7 @@ Satellite data access is fragmented — every provider has its own auth scheme,
52
53
 
53
54
  | Feature | pygeofetch | EODAG | pystac-client | satpy | sentinelsat |
54
55
  |---|---|---|---|---|---|
55
- | Providers | **24** | 10+ | STAC only | Limited | Sentinel only |
56
+ | Providers | **22** | 10+ | STAC only | Limited | Sentinel only |
56
57
  | Processing engine | ✅ Full | ❌ | ❌ | Partial | ❌ |
57
58
  | Spectral indices | ✅ 17+ | ❌ | ❌ | ❌ | ❌ |
58
59
  | Full InSAR chain | ✅ Verified | ❌ | ❌ | ❌ | ❌ |
@@ -64,9 +65,9 @@ Satellite data access is fragmented — every provider has its own auth scheme,
64
65
 
65
66
  ## Providers
66
67
 
67
- **11 open-access providers**, no login required — including `planetary_computer`, `aws_earth`, `element84`, `noaa_big_data`, `esa_scihub`, `jaxa_earth`, and `geoserver_generic` for any OGC WMS/WFS/WCS endpoint.
68
+ **22 verified providers total.** Open-access, no login required — including `planetary_computer`, `aws_earth`, `element84`, `noaa_big_data`, `jaxa_earth`, and `geoserver_generic` for any OGC WMS/WFS/WCS endpoint.
68
69
 
69
- **13 authenticated providers** — USGS, Copernicus CDSE, NASA Earthdata (+ Cloud), Alaska SAR Facility, OpenTopography, Planet Labs, Sentinel Hub, Maxar GBDX, Airbus OneAtlas, Google Earth Engine, TerraBotics, and Earth Explorer.
70
+ Authenticated — USGS, Copernicus CDSE, NASA Earthdata (+ Cloud), Alaska SAR Facility, OpenTopography, Planet Labs, Sentinel Hub, Maxar GBDX, Airbus OneAtlas, and Earth Explorer.
70
71
 
71
72
  Every provider has been directly verified to return at minimum a correct bounding box; several are further confirmed to return real, precise footprint geometry against a live API response (marked in `pygeofetch providers info PROVIDER`). Run `pygeofetch providers list` for the full, current table.
72
73
 
@@ -120,23 +121,12 @@ Mexico City sits on a drained lakebed and is subsiding at some of the fastest ra
120
121
 
121
122
  **1. Authenticated federated search.** `client.search()` against Copernicus Data Space for SLC scenes over the city (bbox `-99.183, 19.278, -99.003, 19.438`, July 2016 – September 2017) returns a stack of Sentinel-1A/1B candidates in seconds, filterable straight down to a single consistent track.
122
123
 
123
- <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/data-search.png" width="85%" /></p>
124
-
125
124
  Results carry real footprint geometry and drop straight onto a map via `MapViewer`, with hover info for scene ID, date, satellite, and provider — useful for spotting swath overlap before committing to a download.
126
125
 
127
- <p align="center">
128
- <img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/search_1.png" width="48%" />
129
- <img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/search.png" width="48%" />
130
- </p>
131
-
132
126
  **2. DEM acquisition.** A matching search against OpenTopography returns seven DEM products for the AOI; pygeofetch downloads and clips the selected one (SRTM 30 m) automatically for topographic phase removal.
133
127
 
134
- <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/dem_acquisition.png" width="85%" /></p>
135
-
136
128
  **3. Preflight validation.** Before anything downloads, the `PreflightGate` checks search truncation, AOI coverage, temporal network connectivity, and burst-timing family compatibility from lightweight annotation XMLs — catching acquisitions that would waste compute before they cost bandwidth. This run avoided roughly 360 GB of downloads by excluding 48 of 115 candidate scenes at this stage alone.
137
129
 
138
- <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/preflight-log.png" width="85%" /></p>
139
-
140
130
  Real orbit state vectors then pre-filter the candidate pair list against Sentinel-1's own mission thresholds, rejecting pairs for excess burst-sync error, temporal baseline, or spatial baseline before any interferogram is attempted.
141
131
 
142
132
  <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/pre-filter-for-interferogram.png" width="85%" /></p>
@@ -158,8 +148,6 @@ Real orbit state vectors then pre-filter the candidate pair list against Sentine
158
148
 
159
149
  **7. SBAS time-series inversion.** The full 58-date descending stack, once low-coherence and unreliable-reference-pixel pairs are excluded, fractures into 17 disconnected network "islands" — a genuine finding about this AOI's data quality, not a bug. The largest connected island (10 dates, 11 pairs) carries the final inversion, referenced near Cerro de la Estrella.
160
150
 
161
- <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/1.png" width="85%" /></p>
162
-
163
151
  The resulting velocity field, uncertainty map, reliability mask, and displacement time series recover a 2nd–98th-percentile vertical velocity of **−35.5 to −2.9 cm/year** where reliable pixels exist.
164
152
 
165
153
  <p align="center"><img src="https://raw.githubusercontent.com/EOCoreINT/mexico-subsidence-project/main/analysis/island1_sbas_full_analysis.png" width="90%" /></p>
@@ -241,7 +229,7 @@ If you use PyGeoFetch in your research or operational work, please cite it using
241
229
  title = {PyGeoFetch: A Unified Python Framework for Multi-Provider Satellite Data Acquisition, Pre-download Quality Control, and Geospatial Processing},
242
230
  year = {2026},
243
231
  publisher = {Zenodo},
244
- version = {2.6.2.6.1},
232
+ version = {2.6.2.8.1},
245
233
  doi = {10.5281/zenodo.22087230},
246
234
  url = {https://doi.org/10.5281/zenodo.22087230}
247
235
  }
@@ -251,15 +239,28 @@ If you use PyGeoFetch in your research or operational work, please cite it using
251
239
 
252
240
  Full documentation: **https://pygeofetch.readthedocs.io/en/latest/** — CLI reference, provider auth guides, pipeline configuration, post-processing catalogue, and InSAR verification methodology.
253
241
 
242
+ ## Support this project
243
+
244
+ pygeofetch is built and maintained by a single developer, in the open,
245
+ alongside a full-time workload — the InSAR/optical fusion chain, the
246
+ provider verification work, and the documentation are all real,
247
+ independently-verified engineering, not a side project maintained on
248
+ autopilot. If pygeofetch is useful to your research or your
249
+ organization, sponsoring its development directly funds the time spent
250
+ keeping 22 provider integrations current as their real APIs change, and
251
+ building out the multi-sensor pipelines documented above.
252
+
253
+ [![Sponsor on GitHub](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-ea4aaa?logo=githubsponsors)](https://github.com/sponsors/appiahkubis14)
254
+
254
255
  ## Contributing
255
256
 
256
257
  Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Good first issues include extending real footprint geometry to remaining bbox-only providers, wiring stub providers to full API integrations, and adding new post-processing actions.
257
258
 
258
259
  ```bash
259
260
  git clone git@github.com:EOCoreINT/pygeofetch.git && cd pygeofetch
260
- pip install -e ".[dev,all]" && pytest tests/unit/ -v
261
-
261
+ pip install -e ".[test]" && pytest tests/ -v
262
+ ```
262
263
 
263
264
  ## License
264
265
 
265
- MIT — see [LICENSE](LICENSE). © 2026 Samuel Appiah Kubi. Part of the **PyGeoVision** platform, alongside [pygeofetch](https://github.com/appiahkubis14/pygeofetch) itself.
266
+ MIT — see [LICENSE](LICENSE). © 2026 Samuel Appiah Kubi.
@@ -30,7 +30,7 @@ CLI::
30
30
  pygeofetch doctor
31
31
  """
32
32
 
33
- __version__ = "2.6.2.6.4"
33
+ __version__ = "2.6.2.8.4"
34
34
  __author__ = "PyGeoFetch Contributors"
35
35
  __license__ = "MIT"
36
36
 
File without changes
@@ -0,0 +1,276 @@
1
+ """
2
+ Domain-specific geotechnical risk mapping.
3
+
4
+ Extends this project's existing strain calculation
5
+ (`pygeofetch.optical.offset_tracking.compute_horizontal_strain`) with
6
+ curvature -- the real, standard second spatial derivative of a
7
+ displacement field -- and combines both with velocity into a single,
8
+ normalized, physically-capped risk index.
9
+
10
+ Real, standard geotechnical grounding: curvature of the ground surface
11
+ is a real, long-established predictor of structural damage in mining
12
+ subsidence engineering (National Coal Board, 1975, *Subsidence
13
+ Engineering Handbook*) -- a curved ground surface bends whatever rigid
14
+ structure sits on it, and that bending strain is what actually cracks
15
+ foundations and walls, not subsidence magnitude alone. The NCB's own
16
+ real, cited strain-based damage categories are reused here as the real
17
+ reference scale for this module's strain sub-score (see
18
+ `compute_geotechnical_risk_index`'s own docstring).
19
+
20
+ Real, honest note on `compute_curvature`'s two real inputs: the
21
+ standard subsidence-engineering convention computes curvature from a
22
+ *single* vertical displacement/subsidence field, not two horizontal
23
+ components. This module's own `compute_curvature(dx, dy, ...)`
24
+ generalizes that to accept displacement magnitude
25
+ (sqrt(dx^2 + dy^2)) computed from two real horizontal components -- a
26
+ real, honest extension for this project's own broader, multi-modal
27
+ scope (lateral landslide movement, co-seismic horizontal slip), not
28
+ identical to the classic vertical-subsidence-only NCB convention. Pass
29
+ the same real array for both `dx` and `dy=0` (a real zero array, same
30
+ shape) to reproduce standard single-field vertical curvature exactly.
31
+
32
+ Real, direct connection to a previously-found bug, stated explicitly
33
+ rather than left implicit: this project's own real, live Bu'ertai
34
+ validation run produced a genuine 617% strain artifact from a small
35
+ number of spurious optical correlator matches -- caught and fixed with
36
+ real outlier protection in `compute_horizontal_strain` itself. The
37
+ "strict, physically plausible capping" this module applies on top of
38
+ that is a second, independent real safeguard: even a genuinely
39
+ outlier-filtered strain value should never be allowed to dominate a
40
+ risk score computed from it, since real ground strain at the level
41
+ mining-subsidence engineering considers "very severe" is on the order
42
+ of 1% (NCB, 1975) -- several orders of magnitude below any of the
43
+ 617%-class artifacts this project has directly, empirically observed.
44
+ """
45
+
46
+ from __future__ import annotations
47
+
48
+ import logging
49
+ from typing import Any
50
+
51
+ from pydantic import BaseModel, Field
52
+
53
+ logger = logging.getLogger("pygeofetch.geotech.risk_mapper")
54
+
55
+
56
+ class RiskMapperConfig(BaseModel):
57
+ """
58
+ Real, configurable reference scales for
59
+ `compute_geotechnical_risk_index`.
60
+
61
+ Real, cited defaults for strain (National Coal Board, 1975): the
62
+ NCB's own published damage categories place "very severe" damage
63
+ at real ground strains at or above 1.0% (0.01) -- used here as the
64
+ real strain value that alone saturates this sub-score to 100.
65
+
66
+ Real, honest note on the velocity and curvature defaults: unlike
67
+ strain, there is no single, universally-cited numeric threshold
68
+ for "high-risk" velocity or curvature across all real deformation
69
+ contexts (mining, landslide, urban subsidence each have their own
70
+ real, site-specific conventions) -- the defaults below are
71
+ reasonable, real, commonly-encountered reference points (matching
72
+ the same order of magnitude routinely reported in real InSAR
73
+ mining-subsidence literature this project's own Bu'ertai/Mexico
74
+ City validation work references), not a cited universal standard
75
+ the way the strain threshold is. Override them with a real,
76
+ site-specific reference value whenever one is available.
77
+ """
78
+
79
+ max_severe_strain: float = Field(
80
+ 0.01,
81
+ gt=0,
82
+ description="Real strain (fraction, not %) at which the strain sub-score saturates to 100 -- NCB (1975) 'very severe' threshold.",
83
+ )
84
+ max_severe_velocity_m_per_year: float = Field(
85
+ 0.5,
86
+ gt=0,
87
+ description="Real velocity magnitude (m/yr) at which the velocity sub-score saturates to 100 -- a reasonable, site-adjustable reference, not a cited universal standard.",
88
+ )
89
+ max_severe_curvature_per_m: float = Field(
90
+ 0.001,
91
+ gt=0,
92
+ description="Real curvature magnitude (1/m) at which the curvature sub-score saturates to 100 -- a reasonable, site-adjustable reference, not a cited universal standard.",
93
+ )
94
+ strain_cap: float = Field(
95
+ 0.10,
96
+ gt=0,
97
+ description="Real, hard physical plausibility ceiling (fraction) applied to strain before it enters the risk index at all -- protects against exactly the class of spurious, order-of-magnitude-too-large artifact this project has directly observed (a real 617% strain case), independent of whatever outlier protection already ran upstream.",
98
+ )
99
+ combination: str = Field(
100
+ "max_weighted",
101
+ description="'max_weighted' (default) or 'mean' -- see compute_geotechnical_risk_index's own docstring.",
102
+ )
103
+
104
+
105
+ def compute_curvature(dx: Any, dy: Any, pixel_size_m: float) -> dict:
106
+ """
107
+ Real curvature (second spatial derivative) of a displacement
108
+ field -- see this module's own docstring for the real, important
109
+ distinction between this generalized, magnitude-based computation
110
+ and the classic, single-field vertical-subsidence convention.
111
+
112
+ Real, standard central finite-difference implementation: computes
113
+ `np.gradient` twice (first derivative, then the derivative of that)
114
+ on the real displacement magnitude field, matching the exact same
115
+ real numerical approach `compute_horizontal_strain` already uses
116
+ for its own first-derivative strain tensor.
117
+
118
+ Parameters
119
+ ----------
120
+ dx, dy : np.ndarray
121
+ Real horizontal displacement components, metres, same shape
122
+ (e.g. from `compute_pixel_offsets`). Pass a real zero array for
123
+ `dy` to compute standard single-field curvature on `dx` alone.
124
+ pixel_size_m : float
125
+ Real ground distance between adjacent grid samples, metres.
126
+
127
+ Returns
128
+ -------
129
+ dict
130
+ Real keys: ``"curvature_xx"``, ``"curvature_yy"`` (the two real
131
+ principal second-derivative components of displacement
132
+ magnitude), and ``"curvature_max"`` (real, per-pixel maximum
133
+ absolute value of the two -- the real, standard single scalar
134
+ used as the risk-relevant curvature magnitude in mining
135
+ subsidence engineering).
136
+
137
+ Raises
138
+ ------
139
+ ValueError
140
+ If `dx`/`dy` don't share a real, identical shape.
141
+ """
142
+ import numpy as np
143
+
144
+ dx = np.asarray(dx, dtype="float64")
145
+ dy = np.asarray(dy, dtype="float64")
146
+ if dx.shape != dy.shape:
147
+ raise ValueError(
148
+ f"compute_curvature: dx/dy shape mismatch {dx.shape} vs {dy.shape}"
149
+ )
150
+
151
+ magnitude = np.sqrt(dx**2 + dy**2)
152
+
153
+ # First derivative (real, same np.gradient convention already
154
+ # verified in compute_horizontal_strain: returns (d/d_row, d/d_col)).
155
+ d_mag_drow, d_mag_dcol = np.gradient(magnitude, pixel_size_m)
156
+ # Second derivative -- the real curvature.
157
+ _, curvature_xx = np.gradient(d_mag_dcol, pixel_size_m)
158
+ curvature_yy, _ = np.gradient(d_mag_drow, pixel_size_m)
159
+
160
+ curvature_max = np.maximum(np.abs(curvature_xx), np.abs(curvature_yy))
161
+
162
+ return {
163
+ "curvature_xx": curvature_xx,
164
+ "curvature_yy": curvature_yy,
165
+ "curvature_max": curvature_max,
166
+ }
167
+
168
+
169
+ def compute_geotechnical_risk_index(
170
+ velocity: Any,
171
+ max_shear_strain: Any,
172
+ curvature: Any,
173
+ config: "RiskMapperConfig | None" = None,
174
+ ) -> dict:
175
+ """
176
+ Real, normalized (0-100) geotechnical risk index combining
177
+ velocity, strain, and curvature -- with real, physically-plausible
178
+ capping on strain before it enters the index at all.
179
+
180
+ Parameters
181
+ ----------
182
+ velocity : np.ndarray
183
+ Real displacement velocity magnitude, m/yr (vertical InSAR
184
+ velocity, fused multi-modal velocity, or horizontal magnitude
185
+ -- whichever real quantity is the relevant risk driver for
186
+ your specific site).
187
+ max_shear_strain : np.ndarray
188
+ Real max shear strain (fraction, not %) -- e.g. from
189
+ `compute_horizontal_strain`'s own `exy` output, or a real,
190
+ independently-computed principal shear strain.
191
+ curvature : np.ndarray
192
+ Real curvature magnitude (1/m) -- e.g.
193
+ `compute_curvature(...)["curvature_max"]`.
194
+ config : RiskMapperConfig, optional
195
+ Real, configurable reference scales and combination method.
196
+
197
+ Returns
198
+ -------
199
+ dict
200
+ Real keys: ``"risk_index"`` (0-100, per-pixel), ``"velocity_score"``,
201
+ ``"strain_score"``, ``"curvature_score"`` (each 0-100, the real
202
+ per-factor sub-scores before combination), and
203
+ ``"n_strain_capped"`` (real count of pixels where the real,
204
+ physical plausibility cap in `config.strain_cap` actually
205
+ triggered -- inspect this; a large number here means a lot of
206
+ your input strain is implausible and worth investigating at
207
+ its real source before trusting this risk map).
208
+
209
+ Notes
210
+ -----
211
+ Real, deliberate combination logic (`config.combination`):
212
+
213
+ - ``"max_weighted"`` (default): the risk index is dominated by
214
+ whichever single real factor is worst, not diluted by averaging
215
+ it with two moderate ones -- matching real geotechnical practice,
216
+ where one severe factor (e.g. curvature alone, even with modest
217
+ velocity and strain) is a real, standalone reason for concern.
218
+ Computed as `0.6 * max(scores) + 0.4 * mean(scores)`.
219
+ - ``"mean"``: a plain, equal-weighted average of the three real
220
+ sub-scores -- provided as a simpler, real alternative, but will
221
+ understate risk in a real scenario where only one factor is
222
+ severe.
223
+ """
224
+ import numpy as np
225
+
226
+ config = config or RiskMapperConfig()
227
+
228
+ velocity = np.abs(np.asarray(velocity, dtype="float64"))
229
+ strain = np.asarray(max_shear_strain, dtype="float64")
230
+ curvature = np.abs(np.asarray(curvature, dtype="float64"))
231
+
232
+ # Real, physical plausibility cap -- applied BEFORE strain enters
233
+ # the index at all, independent of whatever outlier protection
234
+ # already ran upstream (see this module's own docstring for the
235
+ # real, directly-observed 617% artifact this specifically guards
236
+ # against).
237
+ strain_capped = np.abs(strain)
238
+ n_strain_capped = int((strain_capped > config.strain_cap).sum())
239
+ strain_capped = np.clip(strain_capped, 0, config.strain_cap)
240
+
241
+ velocity_score = np.clip(
242
+ 100 * velocity / config.max_severe_velocity_m_per_year, 0, 100
243
+ )
244
+ strain_score = np.clip(100 * strain_capped / config.max_severe_strain, 0, 100)
245
+ curvature_score = np.clip(
246
+ 100 * curvature / config.max_severe_curvature_per_m, 0, 100
247
+ )
248
+
249
+ if config.combination == "max_weighted":
250
+ stacked = np.stack([velocity_score, strain_score, curvature_score])
251
+ risk_index = 0.6 * stacked.max(axis=0) + 0.4 * stacked.mean(axis=0)
252
+ elif config.combination == "mean":
253
+ risk_index = (velocity_score + strain_score + curvature_score) / 3.0
254
+ else:
255
+ raise ValueError(
256
+ f"compute_geotechnical_risk_index: config.combination must be "
257
+ f"'max_weighted' or 'mean', got {config.combination!r}"
258
+ )
259
+
260
+ if n_strain_capped > 0:
261
+ logger.warning(
262
+ "compute_geotechnical_risk_index: %d pixels had strain above the "
263
+ "real physical plausibility cap (%.1f%%) and were clipped -- "
264
+ "investigate the real source of these values before trusting "
265
+ "this risk map at those pixels.",
266
+ n_strain_capped,
267
+ 100 * config.strain_cap,
268
+ )
269
+
270
+ return {
271
+ "risk_index": np.clip(risk_index, 0, 100),
272
+ "velocity_score": velocity_score,
273
+ "strain_score": strain_score,
274
+ "curvature_score": curvature_score,
275
+ "n_strain_capped": n_strain_capped,
276
+ }