gmprocess 2.6.0__tar.gz → 2.7.0__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 (254) hide show
  1. {gmprocess-2.6.0 → gmprocess-2.7.0}/.gitignore +1 -0
  2. {gmprocess-2.6.0 → gmprocess-2.7.0}/.vscode/settings.json +1 -1
  3. {gmprocess-2.6.0 → gmprocess-2.7.0}/CHANGELOG.md +19 -0
  4. {gmprocess-2.6.0 → gmprocess-2.7.0}/PKG-INFO +1 -1
  5. {gmprocess-2.6.0 → gmprocess-2.7.0}/code.json +41 -0
  6. {gmprocess-2.6.0 → gmprocess-2.7.0}/pyproject.toml +2 -0
  7. gmprocess-2.7.0/src/gmprocess/bin/export_ff_sac.py +315 -0
  8. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/core/stationstream.py +38 -26
  9. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/core/streamcollection.py +7 -1
  10. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/flatfile.py +18 -3
  11. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/flatfile_constants.py +3 -0
  12. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/cosmos/cesmd_fetcher.py +14 -1
  13. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/cosmos/cosmos_writer.py +5 -5
  14. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/global_fetcher.py +6 -4
  15. gmprocess-2.7.0/src/gmprocess/io/knet/knet_fetcher.py +420 -0
  16. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/waveform_metric_collection.py +5 -2
  17. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/compute_station_metrics.py +10 -6
  18. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/export_gmpacket_utils.py +12 -2
  19. gmprocess-2.7.0/src/gmprocess/waveform_processing/count_stats.py +14 -0
  20. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/detrend.py +2 -1
  21. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/instrument_response.py +21 -11
  22. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess.egg-info/PKG-INFO +1 -1
  23. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess.egg-info/SOURCES.txt +2 -0
  24. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess.egg-info/entry_points.txt +1 -0
  25. gmprocess-2.6.0/src/gmprocess/io/knet/knet_fetcher.py +0 -441
  26. {gmprocess-2.6.0 → gmprocess-2.7.0}/.coveragerc +0 -0
  27. {gmprocess-2.6.0 → gmprocess-2.7.0}/.gitlab-ci.yml +0 -0
  28. {gmprocess-2.6.0 → gmprocess-2.7.0}/CODE_OF_CONDUCT.md +0 -0
  29. {gmprocess-2.6.0 → gmprocess-2.7.0}/CONTRIBUTING.md +0 -0
  30. {gmprocess-2.6.0 → gmprocess-2.7.0}/DISCLAIMER.md +0 -0
  31. {gmprocess-2.6.0 → gmprocess-2.7.0}/LICENSE.md +0 -0
  32. {gmprocess-2.6.0 → gmprocess-2.7.0}/MANIFEST.in +0 -0
  33. {gmprocess-2.6.0 → gmprocess-2.7.0}/README.md +0 -0
  34. {gmprocess-2.6.0 → gmprocess-2.7.0}/pytest.ini +0 -0
  35. {gmprocess-2.6.0 → gmprocess-2.7.0}/setup.cfg +0 -0
  36. {gmprocess-2.6.0 → gmprocess-2.7.0}/setup.py +0 -0
  37. {gmprocess-2.6.0 → gmprocess-2.7.0}/setup_env.sh +0 -0
  38. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/__init__.py +0 -0
  39. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/apps/__init__.py +0 -0
  40. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/apps/gmrecords.py +0 -0
  41. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/__init__.py +0 -0
  42. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/bundle_datarelease.py +0 -0
  43. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/cwa_gather.py +0 -0
  44. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/fetch_orfeus.py +0 -0
  45. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/fix_inventory.py +0 -0
  46. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/get_cali_cloud.py +0 -0
  47. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/gmconvert.py +0 -0
  48. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/gminfo.py +0 -0
  49. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/gmprocess_config.py +0 -0
  50. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/gmrecords.py +0 -0
  51. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/gmworkspace.py +0 -0
  52. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/bin/update_event_json.sh +0 -0
  53. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/core/__init__.py +0 -0
  54. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/core/provenance.py +0 -0
  55. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/core/scalar_event.py +0 -0
  56. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/core/stationtrace.py +0 -0
  57. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/core/streamarray.py +0 -0
  58. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/CESMD_NGA_ids.csv +0 -0
  59. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/__init__.py +0 -0
  60. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/config_production.yml +0 -0
  61. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/config_production_v1.yml +0 -0
  62. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/config_test.yml +0 -0
  63. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/config_test_download.yml +0 -0
  64. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/cosmos_table10.xls +0 -0
  65. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/cosmos_table4.xls +0 -0
  66. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/demo/ci38457511/raw/CICCC.RAW +0 -0
  67. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/demo/ci38457511/raw/CICLC.v1 +0 -0
  68. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/demo/ci38457511/raw/CITOW2.RAW +0 -0
  69. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/demo/nc72282711/workspace.h5 +0 -0
  70. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/fdsn_codes.csv +0 -0
  71. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/lme/SA_rotd50.0_2020.03.31.csv +0 -0
  72. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/modules.yml +0 -0
  73. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nga_w2_selected.csv +0 -0
  74. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_clipping/bias_1.csv +0 -0
  75. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_clipping/bias_output.csv +0 -0
  76. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_clipping/masterF.txt +0 -0
  77. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_clipping/weight_1.csv +0 -0
  78. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_clipping/weight_output.csv +0 -0
  79. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/M.csv +0 -0
  80. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/bias_1.csv +0 -0
  81. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/bias_2.csv +0 -0
  82. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/bias_output.csv +0 -0
  83. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/final_training.csv +0 -0
  84. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/masterF.txt +0 -0
  85. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/model_3.txt +0 -0
  86. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/model_5.txt +0 -0
  87. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/mu_sigma.csv +0 -0
  88. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/weight_1.csv +0 -0
  89. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/weight_2.csv +0 -0
  90. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/Cant/weight_output.csv +0 -0
  91. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/M.csv +0 -0
  92. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/bias_1.csv +0 -0
  93. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/bias_2.csv +0 -0
  94. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/bias_output.csv +0 -0
  95. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/final_training.csv +0 -0
  96. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/masterF.txt +0 -0
  97. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/model_0.txt +0 -0
  98. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/mu_sigma.csv +0 -0
  99. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/weight_1.csv +0 -0
  100. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/weight_2.csv +0 -0
  101. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/nn_qa/CantWell/weight_output.csv +0 -0
  102. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/picker.yml +0 -0
  103. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/station_coordinates.xlsx +0 -0
  104. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/data/usgs_ids_nga_and_srcmod_cross_reference.xlsx +0 -0
  105. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/gui/__init__.py +0 -0
  106. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/gui/gui_ucla/Documentation.md +0 -0
  107. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/gui/gui_ucla/GUI_human_review.ipynb +0 -0
  108. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/gui/gui_ucla/HumanReviewGUI.py +0 -0
  109. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/gui/gui_ucla/__init__.py +0 -0
  110. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/__init__.py +0 -0
  111. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/__init__.py +0 -0
  112. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/base_metrics_xml.py +0 -0
  113. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/core.py +0 -0
  114. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/path_utils.py +0 -0
  115. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/rupture.py +0 -0
  116. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/station_metrics_xml.py +0 -0
  117. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/stream_workspace.py +0 -0
  118. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/utils.py +0 -0
  119. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/waveform_metrics_xml.py +0 -0
  120. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/asdf/workspace_constants.py +0 -0
  121. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/bhrc/__init__.py +0 -0
  122. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/bhrc/core.py +0 -0
  123. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/cosmos/__init__.py +0 -0
  124. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/cosmos/cesmd_search.py +0 -0
  125. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/cosmos/core.py +0 -0
  126. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/cosmos/data_structures.py +0 -0
  127. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/cwb/__init__.py +0 -0
  128. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/cwb/core.py +0 -0
  129. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/dmg/__init__.py +0 -0
  130. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/dmg/core.py +0 -0
  131. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/dynamic_search_parameters.py +0 -0
  132. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/esm/__init__.py +0 -0
  133. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/esm/core.py +0 -0
  134. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/fetcher.py +0 -0
  135. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/geonet/__init__.py +0 -0
  136. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/geonet/core.py +0 -0
  137. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/knet/__init__.py +0 -0
  138. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/knet/core.py +0 -0
  139. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/nga.py +0 -0
  140. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/nsmn/__init__.py +0 -0
  141. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/nsmn/core.py +0 -0
  142. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/obspy/__init__.py +0 -0
  143. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/obspy/core.py +0 -0
  144. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/obspy/fdsn_fetcher.py +0 -0
  145. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/read.py +0 -0
  146. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/read_directory.py +0 -0
  147. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/renadic/__init__.py +0 -0
  148. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/renadic/core.py +0 -0
  149. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/report.py +0 -0
  150. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/seedname.py +0 -0
  151. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/smc/__init__.py +0 -0
  152. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/smc/core.py +0 -0
  153. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/unam/__init__.py +0 -0
  154. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/unam/core.py +0 -0
  155. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/usc/__init__.py +0 -0
  156. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/usc/core.py +0 -0
  157. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/io/utils.py +0 -0
  158. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/__init__.py +0 -0
  159. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/combine.py +0 -0
  160. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/containers.py +0 -0
  161. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/metric_collection_base.py +0 -0
  162. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/oscillator.py +0 -0
  163. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/reduce.py +0 -0
  164. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/rotate.py +0 -0
  165. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/station_metric.py +0 -0
  166. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/station_metric_collection.py +0 -0
  167. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/transform.py +0 -0
  168. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/utils.py +0 -0
  169. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/waveform_metric_calculator.py +0 -0
  170. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/waveform_metric_calculator_component_base.py +0 -0
  171. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/waveform_metric_component.py +0 -0
  172. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/waveform_metric_list.py +0 -0
  173. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/metrics/waveform_metric_type.py +0 -0
  174. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/__init__.py +0 -0
  175. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/arg_dicts.py +0 -0
  176. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/assemble.py +0 -0
  177. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/autoprocess.py +0 -0
  178. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/autoshakemap.py +0 -0
  179. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/base.py +0 -0
  180. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/clean.py +0 -0
  181. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/compute_waveform_metrics.py +0 -0
  182. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/download.py +0 -0
  183. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/export_cosmos.py +0 -0
  184. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/export_failure_tables.py +0 -0
  185. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/export_gmpacket.py +0 -0
  186. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/export_metric_tables.py +0 -0
  187. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/export_provenance_tables.py +0 -0
  188. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/generate_regression_plot.py +0 -0
  189. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/generate_report.py +0 -0
  190. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/generate_station_maps.py +0 -0
  191. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/import_data.py +0 -0
  192. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/init.py +0 -0
  193. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/lazy_loader.py +0 -0
  194. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/process_waveforms.py +0 -0
  195. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/processing_steps.py +0 -0
  196. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/subcommands/projects.py +0 -0
  197. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/__init__.py +0 -0
  198. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/args.py +0 -0
  199. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/assemble_utils.py +0 -0
  200. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/config.py +0 -0
  201. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/config_versioning.py +0 -0
  202. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/constants.py +0 -0
  203. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/download_utils.py +0 -0
  204. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/ground_motion_models.py +0 -0
  205. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/logging.py +0 -0
  206. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/memory.py +0 -0
  207. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/misc.py +0 -0
  208. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/misc_plots.py +0 -0
  209. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/prompt.py +0 -0
  210. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/report_utils.py +0 -0
  211. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/rupture_utils.py +0 -0
  212. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/strec.py +0 -0
  213. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/summary_plots.py +0 -0
  214. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/tables.py +0 -0
  215. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/utils/tests_utils.py +0 -0
  216. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/__init__.py +0 -0
  217. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/adjust_highpass.py +0 -0
  218. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/adjust_highpass_ridder.py +0 -0
  219. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/baseline_correction.py +0 -0
  220. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/clipping/clip_detection.py +0 -0
  221. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/clipping/clipping_ann.py +0 -0
  222. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/clipping/clipping_check.py +0 -0
  223. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/clipping/histogram.py +0 -0
  224. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/clipping/jerk.py +0 -0
  225. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/clipping/max_amp.py +0 -0
  226. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/clipping/ping.py +0 -0
  227. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/clipping/std_dev.py +0 -0
  228. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/convert_units.py +0 -0
  229. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/corner_frequencies.py +0 -0
  230. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/fft.py +0 -0
  231. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/filtering.py +0 -0
  232. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/integrate.py +0 -0
  233. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/nn_quality_assurance.py +0 -0
  234. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/phase.py +0 -0
  235. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/pretesting.py +0 -0
  236. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/prism_adaptive_baseline.py +0 -0
  237. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/processing.py +0 -0
  238. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/processing_step.py +0 -0
  239. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/resample.py +0 -0
  240. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/sanity_checks.py +0 -0
  241. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/snr.py +0 -0
  242. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/spectrum.py +0 -0
  243. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/taper.py +0 -0
  244. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/windows.py +0 -0
  245. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/zero_crossings.py +0 -0
  246. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess/waveform_processing/zero_pad.py +0 -0
  247. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess.egg-info/dependency_links.txt +0 -0
  248. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess.egg-info/requires.txt +0 -0
  249. {gmprocess-2.6.0 → gmprocess-2.7.0}/src/gmprocess.egg-info/top_level.txt +0 -0
  250. {gmprocess-2.6.0 → gmprocess-2.7.0}/tools/matlab/README.md +0 -0
  251. {gmprocess-2.6.0 → gmprocess-2.7.0}/tools/matlab/get_all_waveforms.m +0 -0
  252. {gmprocess-2.6.0 → gmprocess-2.7.0}/tools/matlab/get_events.m +0 -0
  253. {gmprocess-2.6.0 → gmprocess-2.7.0}/tools/matlab/get_waveform_metrics.m +0 -0
  254. {gmprocess-2.6.0 → gmprocess-2.7.0}/tools/matlab/waveform_plot.png +0 -0
@@ -22,3 +22,4 @@ dask-worker-space/
22
22
  # Vim tags
23
23
  tags
24
24
  public
25
+ .vscode/
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "python.formatting.provider": "black",
3
3
  "editor.formatOnSave": true
4
- }
4
+ }
@@ -1,5 +1,24 @@
1
1
  ## main
2
2
 
3
+
4
+ ## 2.7.0 / 2026-06-04
5
+
6
+ - Enhancements
7
+ - Support PSA metric for gmpacket files
8
+ - Add export_ff_sac script for selecting SAC files for finite fault inversion
9
+ - Add unit test for export_ff_sac script
10
+ - Treat an empty location code as the same as "--" when checking for duplicate records
11
+ - Updated KNET fetcher to use NIED http directory interface
12
+ - Added unit tests to test V3 cosmos writer (and updated workspace.h5)
13
+ - Add "count_mean", "count_min", and "count_max" as trace parameters.
14
+ - Add logging to show query for CESMD fetcher if a timeout occurs
15
+ - Bugfix
16
+ - Fixed cosmos v3 writer where damping_values was assigned in wrong scope
17
+ - Fixed cosmos v3 bug with concatenate_channels=False (only one trace got periods)
18
+ - Set trace warnings and failures for instrument response mismatches between total sensitivity and stages.
19
+ - Fix station metric bug in imc_sort by forcing waveform metric to match station metric before writing
20
+ - Fix compute_station_metrics.py to write to station metrics if any stream passed
21
+
3
22
  ## 2.6.0 / 2026-04-20
4
23
 
5
24
  - Enhancements
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gmprocess
3
- Version: 2.6.0
3
+ Version: 2.7.0
4
4
  Summary: USGS Automated Ground Motion Processing Software
5
5
  Author-email: Eric Thompson <emthompsone@usgs.gov>, Mike Hearne <mhearne@usgs.gov>, Brad Aagaard <baagaard@usgs.gov>, Bruce Worden <cbworden@contractor.usgs.gov>, John Rekoske <jrekoske@ucsd.edu>, Heather Hunsinger <hhunsinger@usgs.gov>, Gabe Ferragut <gferragut@usgs.gov>
6
6
  License: License
@@ -1,4 +1,45 @@
1
1
  [
2
+ {
3
+ "name": "groundmotion-processing",
4
+ "description": "Read and process ground motion waveform data",
5
+ "version": "v2.7.0",
6
+ "status": "Production",
7
+ "organization": "U.S. Geological Survey",
8
+ "vcs": "git",
9
+ "repositoryURL": "https://code.usgs.gov/ghsc/esi/groundmotion-processing.git",
10
+ "homepageURL": "https://code.usgs.gov/ghsc/esi/groundmotion-processing",
11
+ "downloadURL": "https://code.usgs.gov/ghsc/esi/groundmotion-processing/-/archive/v2.7.0/groundmotion-processing-v2.7.0.zip",
12
+ "disclaimerURL": "https://code.usgs.gov/ghsc/esi/groundmotion-processing/-/raw/v2.7.0/DISCLAIMER.md",
13
+ "permissions": {
14
+ "licenses": [
15
+ {
16
+ "name": "Public Domain, CC0-1.0",
17
+ "URL": "https://code.usgs.gov/ghsc/esi/groundmotion-processing/-/raw/v2.7.0/LICENSE.md"
18
+ }
19
+ ],
20
+ "usageType": "openSource",
21
+ "exemptionText": null
22
+ },
23
+ "laborHours": 1,
24
+ "languages": [
25
+ "python"
26
+ ],
27
+ "tags": [
28
+ "earthquake",
29
+ "impact",
30
+ "strong motion",
31
+ "amplitudes",
32
+ "ground motion",
33
+ "usg-artificial-intelligence"
34
+ ],
35
+ "contact": {
36
+ "name": "Eric Thompson",
37
+ "email": "emthompson@usgs.gov"
38
+ },
39
+ "date": {
40
+ "metadataLastUpdated": "2026-06-04"
41
+ }
42
+ },
2
43
  {
3
44
  "name": "groundmotion-processing",
4
45
  "description": "Read and process ground motion waveform data",
@@ -98,6 +98,8 @@ cwa_gather = "gmprocess.bin.cwa_gather:cli"
98
98
  fix_inventory = "gmprocess.bin.fix_inventory:main"
99
99
  fetch_orfeus = "gmprocess.bin.fetch_orfeus:cli"
100
100
  get_cali_cloud = "gmprocess.bin.get_cali_cloud:main"
101
+ export_ff_sac = "gmprocess.bin.export_ff_sac:main"
102
+
101
103
 
102
104
  [build-system]
103
105
  requires = [
@@ -0,0 +1,315 @@
1
+ """Export SAC files for finite fault inversion from a gmprocess workspace.h5"""
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ import matplotlib.pyplot as plt
7
+ import numpy as np
8
+ from gmprocess.io.asdf.stream_workspace import StreamWorkspace
9
+ from obspy.geodetics import gps2dist_azimuth
10
+
11
+
12
+ def get_parser():
13
+ parser = argparse.ArgumentParser(
14
+ description=(
15
+ "Select a set of stations from a gmprocess workspace"
16
+ " and export SAC files for finite fault inversion."
17
+ )
18
+ )
19
+ parser.add_argument(
20
+ "workspace",
21
+ type=Path,
22
+ help="Path to the gmprocess workspace HDF5 file (e.g. workspace.h5).",
23
+ )
24
+ parser.add_argument(
25
+ "event_id",
26
+ help="Event ID as stored in the workspace (e.g. us6000sri7).",
27
+ )
28
+ parser.add_argument(
29
+ "--max-dist",
30
+ type=float,
31
+ default=300.0,
32
+ help="Maximum epicentral distance in km for station inclusion (default: 300).",
33
+ )
34
+ parser.add_argument(
35
+ "--n-max",
36
+ type=int,
37
+ default=20,
38
+ help="Maximum number of stations to select (default: 20).",
39
+ )
40
+ parser.add_argument(
41
+ "--n-lat",
42
+ type=int,
43
+ default=5,
44
+ help="Number of latitude grid rows for spatial sampling (default: 5).",
45
+ )
46
+ parser.add_argument(
47
+ "--n-lon",
48
+ type=int,
49
+ default=4,
50
+ help="Number of longitude grid columns for spatial sampling (default: 4).",
51
+ )
52
+ parser.add_argument(
53
+ "--out-dir",
54
+ type=Path,
55
+ default=None,
56
+ help="Output directory for SAC files (default: <event_id>/).",
57
+ )
58
+ parser.add_argument(
59
+ "--supp-stations",
60
+ nargs="+",
61
+ default=[],
62
+ metavar="STA",
63
+ help="Additional station IDs to include.",
64
+ )
65
+ return parser
66
+
67
+
68
+ def collect_stream_data(sc, event):
69
+ """Extract per-stream arrays of lat, lon, dist, pgv for passing streams.
70
+
71
+ Args:
72
+ sc (StreamCollection): Streams from the workspace.
73
+ event (ScalarEvent): Event object with latitude and longitude attributes.
74
+
75
+ Returns:
76
+ tuple: lat, lon, dist, pgv (np.ndarray) and passing_indices (list of int).
77
+ """
78
+ lat, lon, dist, pgv, passing_indices = [], [], [], [], []
79
+
80
+ for i, stream in enumerate(sc):
81
+ if not stream.passed:
82
+ continue
83
+ passing_indices.append(i)
84
+ trace = stream[0]
85
+ slat = trace.stats.coordinates.latitude
86
+ slon = trace.stats.coordinates.longitude
87
+ lat.append(slat)
88
+ lon.append(slon)
89
+ dist.append(
90
+ gps2dist_azimuth(slat, slon, event.latitude, event.longitude)[0]
91
+ / 1000.0
92
+ )
93
+ pgvs = [
94
+ np.max(np.abs(tr.copy().integrate().data))
95
+ for tr in stream
96
+ if tr.stats.channel[2] != "Z"
97
+ ]
98
+ pgv.append(np.max(pgvs) if pgvs else 0.0)
99
+
100
+ return (
101
+ np.array(lat),
102
+ np.array(lon),
103
+ np.array(dist),
104
+ np.array(pgv),
105
+ passing_indices,
106
+ )
107
+
108
+
109
+ def select_stations(lat, lon, dist, pgv, max_dist, n_max, n_lat, n_lon):
110
+ """Select a spatially distributed subset of stations ranked by PGV.
111
+
112
+ Divides the region into an n_lat x n_lon grid and picks the highest-PGV
113
+ station from each occupied cell, then fills remaining slots by global PGV
114
+ rank up to n_max.
115
+
116
+ Args:
117
+ lat (np.ndarray): Station latitudes.
118
+ lon (np.ndarray): Station longitudes.
119
+ dist (np.ndarray): Epicentral distances in km.
120
+ pgv (np.ndarray): Peak ground velocity (horizontal) in m/s.
121
+ max_dist (float): Distance cutoff in km.
122
+ n_max (int): Maximum total stations to select.
123
+ n_lat (int): Number of latitude grid rows.
124
+ n_lon (int): Number of longitude grid columns.
125
+
126
+ Returns:
127
+ tuple: id_selected (list of int), idx (np.ndarray), lat_bks
128
+ (np.ndarray), lon_bks (np.ndarray).
129
+ """
130
+ idx = np.where(dist < max_dist)[0]
131
+
132
+ eps = 1e-6
133
+ lat_bks = np.linspace(
134
+ lat[idx].min() - eps, lat[idx].max() + eps, n_lat + 1
135
+ )
136
+ lon_bks = np.linspace(
137
+ lon[idx].min() - eps, lon[idx].max() + eps, n_lon + 1
138
+ )
139
+
140
+ quad_id = np.full(len(dist), -1, dtype=int)
141
+ for i, (qx, qy) in enumerate(
142
+ [(x, y) for x in range(n_lon) for y in range(n_lat)]
143
+ ):
144
+ q_idx = np.where(
145
+ (lat[idx] > lat_bks[qy])
146
+ & (lat[idx] < lat_bks[qy + 1])
147
+ & (lon[idx] > lon_bks[qx])
148
+ & (lon[idx] < lon_bks[qx + 1])
149
+ )[0]
150
+ if len(q_idx):
151
+ quad_id[idx[q_idx]] = i
152
+
153
+ # Pick highest PGV from each occupied grid cell
154
+ id_selected = []
155
+ for qid in range(n_lat * n_lon):
156
+ idx_quad = np.where(qid == quad_id)[0]
157
+ if len(idx_quad):
158
+ id_selected.append(idx_quad[np.argmax(pgv[idx_quad])])
159
+
160
+ # Fill remaining slots by global PGV rank
161
+ if n_max > len(id_selected):
162
+ n_add = n_max - len(id_selected)
163
+ idx_rem = np.setdiff1d(idx, id_selected)
164
+ id_selected.extend(idx_rem[np.flip(np.argsort(pgv[idx_rem]))][:n_add])
165
+
166
+ return id_selected, idx, lat_bks, lon_bks
167
+
168
+
169
+ def make_sac_headers(channel_code, slat, slon):
170
+ """Return SAC header dict with cmpaz/cmpinc set for the given channel.
171
+
172
+ Args:
173
+ channel_code (str): Channel code (e.g. HNN, HNE, HNZ).
174
+ slat (float): Station latitude.
175
+ slon (float): Station longitude.
176
+
177
+ Returns:
178
+ dict: SAC header dict suitable for assignment to ``trace.stats.sac``.
179
+ """
180
+ component = channel_code[2]
181
+ if component == "Z":
182
+ cmpinc, cmpaz = 90.0, 0.0
183
+ else:
184
+ cmpinc = 0.0
185
+ cmpaz = 0.0 if component in ("N", "1") else 90.0
186
+ return {"stla": slat, "stlo": slon, "cmpaz": cmpaz, "cmpinc": cmpinc}
187
+
188
+
189
+ def write_sac_files(streams, passing_indices, id_selected, out_dir):
190
+ """Write SAC files for selected streams to out_dir.
191
+
192
+ Args:
193
+ streams (StreamCollection): Streams from the workspace.
194
+ passing_indices (list of int): Indices of passing stations.
195
+ id_selected (list of int): Indices of selected stations.
196
+ out_dir (Path): Output directory (created if absent).
197
+ """
198
+ out_dir.mkdir(parents=True, exist_ok=True)
199
+ for id_sel in id_selected:
200
+ stream = streams[passing_indices[id_sel]]
201
+ for trace in stream:
202
+ trace.stats.sac = make_sac_headers(
203
+ trace.stats.channel,
204
+ trace.stats.coordinates.latitude,
205
+ trace.stats.coordinates.longitude,
206
+ )
207
+ trace.write(
208
+ filename=str(out_dir / (trace.id + ".SAC")), format="SAC"
209
+ )
210
+
211
+
212
+ def write_supp_sac_files(sc, sta_ids, supp_dir):
213
+ """Write SAC files for supplemental stations to supp_dir.
214
+
215
+ Args:
216
+ sc (StreamCollection): Streams from the workspace.
217
+ sta_ids (list of str): Station IDs to include.
218
+ supp_dir (Path): Output directory for supplemental files (created if absent).
219
+ """
220
+ if not sta_ids:
221
+ return
222
+ supp_dir.mkdir(parents=True, exist_ok=True)
223
+ for stream in sc:
224
+ if stream.passed and stream[0].stats.station in sta_ids:
225
+ for trace in stream:
226
+ trace.stats.sac = make_sac_headers(
227
+ trace.stats.channel,
228
+ trace.stats.coordinates.latitude,
229
+ trace.stats.coordinates.longitude,
230
+ )
231
+ trace.write(
232
+ filename=str(supp_dir / (trace.id + ".SAC")), format="SAC"
233
+ )
234
+ print(f"Wrote supplemental stations to {supp_dir}/")
235
+
236
+
237
+ def save_summary_plot(
238
+ lat, lon, idx, id_selected, lat_bks, lon_bks, event, eqid, outdir
239
+ ):
240
+ """Save a map of candidate and selected stations.
241
+
242
+ Args:
243
+ lat (np.ndarray): Station latitudes for all passing streams.
244
+ lon (np.ndarray): Station longitudes for all passing streams.
245
+ idx (np.ndarray): Indices of candidate stations within the distance cutoff.
246
+ id_selected (list of int): Indices of the selected stations.
247
+ lat_bks (np.ndarray): Latitude grid breakpoints.
248
+ lon_bks (np.ndarray): Longitude grid breakpoints.
249
+ event (ScalarEvent): Event object providing epicenter coordinates.
250
+ eqid (str): Event ID used to construct the output filename.
251
+ """
252
+ fig, ax = plt.subplots()
253
+ ax.plot(lon[idx], lat[idx], "vk", label="Candidate")
254
+ for lb in lon_bks:
255
+ ax.axvline(x=lb, color="gray", linewidth=0.5)
256
+ for lb in lat_bks:
257
+ ax.axhline(y=lb, color="gray", linewidth=0.5)
258
+ ax.plot(lon[id_selected], lat[id_selected], "vg", label="Selected")
259
+ ax.plot(
260
+ event.longitude, event.latitude, "*r", markersize=12, label="Epicenter"
261
+ )
262
+ ax.set_xlabel("Longitude")
263
+ ax.set_ylabel("Latitude")
264
+ ax.legend()
265
+ fname = Path(outdir) / f"{eqid}_select_summary.png"
266
+ fig.savefig(fname, dpi=300)
267
+ plt.close(fig)
268
+ print(f"Wrote summary plot: {fname}")
269
+
270
+
271
+ def main():
272
+ parser = get_parser()
273
+ args = parser.parse_args()
274
+
275
+ sw = StreamWorkspace.open(args.workspace)
276
+ sc = sw.get_streams(args.event_id, labels=["default"])
277
+ event = sw.get_event(args.event_id)
278
+
279
+ lat, lon, dist, pgv, passing_indices = collect_stream_data(sc, event)
280
+
281
+ if len(lat) == 0:
282
+ print("No passing streams found in workspace. Exiting.")
283
+ return
284
+
285
+ id_selected, idx, lat_bks, lon_bks = select_stations(
286
+ lat,
287
+ lon,
288
+ dist,
289
+ pgv,
290
+ max_dist=args.max_dist,
291
+ n_max=args.n_max,
292
+ n_lat=args.n_lat,
293
+ n_lon=args.n_lon,
294
+ )
295
+ out_dir = args.out_dir if args.out_dir is not None else Path(event.id)
296
+ save_summary_plot(
297
+ lat,
298
+ lon,
299
+ idx,
300
+ id_selected,
301
+ lat_bks,
302
+ lon_bks,
303
+ event,
304
+ args.event_id,
305
+ out_dir,
306
+ )
307
+
308
+ write_sac_files(sc, passing_indices, id_selected, out_dir)
309
+ print(f"Wrote {len(id_selected)} stations to {out_dir}/")
310
+
311
+ write_supp_sac_files(sc, args.supp_stations, out_dir / "supp")
312
+
313
+
314
+ if __name__ == "__main__":
315
+ main()
@@ -1,4 +1,4 @@
1
- """Module for the StationStream classs."""
1
+ """Module for the StationStream class."""
2
2
 
3
3
  # stdlib imports
4
4
  import logging
@@ -225,7 +225,9 @@ class StationStream(Stream):
225
225
  all_codes = []
226
226
  for tr in self:
227
227
  stats = tr.stats
228
- all_codes.append(f"{stats.network}.{stats.station}.{stats.location}.{stats.channel}")
228
+ all_codes.append(
229
+ f"{stats.network}.{stats.station}.{stats.location}.{stats.channel}"
230
+ )
229
231
  if len(set(all_codes)) != len(all_codes):
230
232
  for tr in self:
231
233
  tr.fail("Nonunique channel code in StationStream.")
@@ -236,40 +238,50 @@ class StationStream(Stream):
236
238
  use_array = hasattr(self, "use_array") and self.use_array
237
239
  stats = self[0].stats
238
240
  if use_array:
239
- id_str = ".".join([
240
- stats.network,
241
- stats.station,
242
- stats.location,
243
- stats.channel,
244
- ])
245
- else:
246
- id_str = ".".join([
247
- stats.network,
248
- stats.station,
249
- stats.location,
250
- stats.channel[0:2],
251
- ])
252
-
253
- # Check that the id would be the same for all traces
254
- for tr in self: # Use self to avoid creating temporary object
255
- stats = tr.stats
256
- if use_array:
257
- test_str = ".".join([
241
+ id_str = ".".join(
242
+ [
258
243
  stats.network,
259
244
  stats.station,
260
245
  stats.location,
261
246
  stats.channel,
262
- ])
263
- else:
264
- test_str = ".".join([
247
+ ]
248
+ )
249
+ else:
250
+ id_str = ".".join(
251
+ [
265
252
  stats.network,
266
253
  stats.station,
267
254
  stats.location,
268
255
  stats.channel[0:2],
269
- ])
256
+ ]
257
+ )
258
+
259
+ # Check that the id would be the same for all traces
260
+ for tr in self: # Use self to avoid creating temporary object
261
+ stats = tr.stats
262
+ if use_array:
263
+ test_str = ".".join(
264
+ [
265
+ stats.network,
266
+ stats.station,
267
+ stats.location,
268
+ stats.channel,
269
+ ]
270
+ )
271
+ else:
272
+ test_str = ".".join(
273
+ [
274
+ stats.network,
275
+ stats.station,
276
+ stats.location,
277
+ stats.channel[0:2],
278
+ ]
279
+ )
270
280
 
271
281
  if id_str != test_str:
272
- raise ValueError(f"Inconsistent stream IDs {id_str} and {test_str} for different traces.")
282
+ raise ValueError(
283
+ f"Inconsistent stream IDs {id_str} and {test_str} for different traces."
284
+ )
273
285
  self.id = id_str
274
286
 
275
287
  def get_id(self):
@@ -636,6 +636,7 @@ def are_duplicates(tr1, tr2, max_dist_tolerance):
636
636
  Returns:
637
637
  bool. True if traces are duplicates, False otherwise.
638
638
  """
639
+ # Need to simplify the use of 1/2 vs N/E
639
640
  orientation_codes = set()
640
641
  for tr in [tr1, tr2]:
641
642
  if tr.stats.channel[2] in ["1", "N"]:
@@ -645,9 +646,14 @@ def are_duplicates(tr1, tr2, max_dist_tolerance):
645
646
  else:
646
647
  orientation_codes.add("Z")
647
648
 
649
+ # Replace "--" with "" due to inconsistent use despite meaning the same thing
650
+ loc_codes = [tr1.stats.location, tr2.stats.location]
651
+ loc_codes = set([c.replace("--", "") for c in loc_codes])
652
+
648
653
  # First, check if the ids match (net.sta.loc.cha)
649
654
  if tr1.id[:-1] == tr2.id[:-1] and len(orientation_codes) == 1:
650
655
  return True
656
+
651
657
  # If not matching IDs, check the station, instrument code, and distance
652
658
  else:
653
659
  distance = gps2dist_azimuth(
@@ -659,7 +665,7 @@ def are_duplicates(tr1, tr2, max_dist_tolerance):
659
665
  if (
660
666
  tr1.stats.station == tr2.stats.station
661
667
  and tr1.stats.channel[:2] == tr2.stats.channel[:2]
662
- and tr1.stats.location == tr2.stats.location
668
+ and len(loc_codes) == 1
663
669
  and len(orientation_codes) == 1
664
670
  and distance < max_dist_tolerance
665
671
  ):
@@ -81,12 +81,24 @@ class Flatfile(object):
81
81
 
82
82
  wmc = WaveformMetricCollection.from_workspace(self.workspace, self.label)
83
83
  smc = StationMetricCollection.from_workspace(self.workspace)
84
- for wml, stream_meta, station_metrics in zip(
85
- wmc.waveform_metrics, wmc.stream_metadata, smc.station_metrics
86
- ):
84
+
85
+ # Use dictionary to ensure each waveform metric has associated station metric
86
+ sm_dict = {}
87
+ for sm_path, sm in zip(smc.stream_paths, smc.station_metrics):
88
+ net_sta = ".".join(sm_path.split(".")[:3])
89
+ sm_dict[net_sta] = sm
90
+
91
+ for wml, stream_meta in zip(wmc.waveform_metrics, wmc.stream_metadata):
87
92
  if not wml.metric_list:
88
93
  continue
89
94
 
95
+ tr_met = stream_meta[0]
96
+ sta_id = f"{tr_met['network']}.{tr_met['station']}.{tr_met['location']}"
97
+ station_metrics = sm_dict.get(sta_id)
98
+ if station_metrics is None:
99
+ logging.warning("No station metrics found for %s; skipping.", sta_id)
100
+ continue
101
+
90
102
  self._station_metrics = station_metrics
91
103
  passed_traces = [tr_met for tr_met in stream_meta if tr_met["passed"]]
92
104
  n_total = len(stream_meta)
@@ -177,6 +189,9 @@ class Flatfile(object):
177
189
  "StationElevation": trace_meta["elevation"],
178
190
  "SamplingRate": trace_meta["sampling_rate"],
179
191
  "SourceFile": source_file,
192
+ "CountMean": trace_meta.get("count_mean", None),
193
+ "CountMin": trace_meta.get("count_min", None),
194
+ "CountMax": trace_meta.get("count_max", None),
180
195
  }
181
196
 
182
197
  def get_sta_dict(self):
@@ -66,6 +66,9 @@ FLATFILE_COLUMNS = {
66
66
  "ZLowpass": "Vertical channel lowpass frequency (Hz)",
67
67
  "ZHighpass": "Vertical channel highpass frequency (Hz)",
68
68
  "SourceFile": "Source file",
69
+ "CountMean": "Mean of raw counts (if available)",
70
+ "CountMin": "Minimum of raw counts (if available)",
71
+ "CountMax": "Maximum of raw counts (if available)",
69
72
  }
70
73
 
71
74
  FLATFILE_IMT_COLUMNS = {
@@ -148,6 +148,10 @@ class CESMDFetcher(DataFetcher):
148
148
  raise Exception(fmt)
149
149
 
150
150
  if email == "EMAIL":
151
+ logging.warning(
152
+ "CESMDFetcher: email is still the placeholder 'EMAIL'; "
153
+ "CESMD will be skipped."
154
+ )
151
155
  fmt = (
152
156
  "Email address is required to retrieve CESMD\n"
153
157
  "data. This tool can download data from the CESMD\n"
@@ -197,6 +201,13 @@ class CESMDFetcher(DataFetcher):
197
201
  - depth Event depth
198
202
  - mag Event magnitude
199
203
  """
204
+ logging.info(
205
+ "CESMDFetcher: querying metadata (lat=%s, lon=%s, time=%s, "
206
+ "eq_radius=%s km, eq_dt=%s s, station_radius=%s km, "
207
+ "station_type=%s)",
208
+ self.lat, self.lon, self.time, self.radius, self.dt,
209
+ self.station_radius, self.station_type,
210
+ )
200
211
  try:
201
212
  metadata = get_metadata(
202
213
  eqlat=self.lat,
@@ -208,7 +219,9 @@ class CESMDFetcher(DataFetcher):
208
219
  eqradius=self.radius, # km
209
220
  station_radius=self.station_radius,
210
221
  )
211
- except BaseException:
222
+ except BaseException as ex:
223
+ logging.warning("CESMDFetcher: metadata query failed: %r", ex)
224
+ logging.debug("CESMDFetcher metadata traceback:", exc_info=True)
212
225
  return []
213
226
 
214
227
  tmp_events = metadata["results"]["events"]
@@ -886,7 +886,7 @@ class CosmosWriter(object):
886
886
  elif self.volume == Volume.SPECTRA:
887
887
  extension = "v3"
888
888
  self.wmc = WaveformMetricCollection.from_workspace(
889
- self._workspace, "default"
889
+ self._workspace, self._label
890
890
  )
891
891
  for station_id in station_list:
892
892
  streams = self._workspace.get_streams(
@@ -1042,11 +1042,11 @@ class CosmosWriter(object):
1042
1042
  return (files, nevents, nstreams, ntraces)
1043
1043
 
1044
1044
  def _write_spectra(self):
1045
- if self.trace_idx == 0:
1045
+ mconf = self._workspace.config["metrics"]
1046
+ damping_values = mconf["type_parameters"]["sa"]["damping"]
1047
+ self.periods = mconf["type_parameters"]["sa"]["periods"]
1048
+ if self.trace_idx == 0 or not self._concatenate_channels:
1046
1049
  self._write_data(self.cosmos_file, self.trace)
1047
- mconf = self._workspace.config["metrics"]
1048
- damping_values = mconf["type_parameters"]["sa"]["damping"]
1049
- self.periods = mconf["type_parameters"]["sa"]["periods"]
1050
1050
  self.cosmos_file.write(
1051
1051
  f"{len(damping_values)} damping values for which spectra are "
1052
1052
  f"computed:{damping_values}\n"
@@ -5,14 +5,14 @@ import logging
5
5
  import pathlib
6
6
 
7
7
  import numpy as np
8
+ from gmprocess.io.dynamic_search_parameters import SearchParameters
9
+ from gmprocess.io.utils import _walk
10
+ from gmprocess.utils.config import get_config
8
11
 
9
12
  from obspy.geodetics import kilometers2degrees
10
13
 
11
14
  # local imports
12
15
  from .fetcher import DataFetcher
13
- from gmprocess.utils.config import get_config
14
- from gmprocess.io.utils import _walk
15
- from gmprocess.io.dynamic_search_parameters import SearchParameters
16
16
 
17
17
  FETCHER_DIRS = [
18
18
  "cosmos",
@@ -172,7 +172,9 @@ def find_fetchers(lat, lon):
172
172
  fetcher_mod = cfile
173
173
  break
174
174
  idx = max(
175
- loc for loc, val in enumerate(fetcher_mod.parts) if val == "gmprocess"
175
+ loc
176
+ for loc, val in enumerate(fetcher_mod.parts)
177
+ if val == "gmprocess"
176
178
  )
177
179
  mod_tuple = fetcher_mod.parts[idx:]
178
180
  mod_name = ".".join(mod_tuple)