gmprocess 2.7.0__tar.gz → 2.8.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 (259) hide show
  1. gmprocess-2.8.0/.coveragerc +13 -0
  2. {gmprocess-2.7.0 → gmprocess-2.8.0}/.gitlab-ci.yml +23 -0
  3. {gmprocess-2.7.0 → gmprocess-2.8.0}/CHANGELOG.md +36 -0
  4. {gmprocess-2.7.0 → gmprocess-2.8.0}/PKG-INFO +13 -7
  5. {gmprocess-2.7.0 → gmprocess-2.8.0}/README.md +6 -3
  6. {gmprocess-2.7.0 → gmprocess-2.8.0}/pyproject.toml +6 -4
  7. gmprocess-2.8.0/pytest.ini +7 -0
  8. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/apps/gmrecords.py +51 -16
  9. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/export_ff_sac.py +16 -2
  10. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/get_cali_cloud.py +55 -24
  11. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/core/scalar_event.py +1 -1
  12. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/core/stationstream.py +40 -10
  13. gmprocess-2.8.0/src/gmprocess/extended_xml/extended_xml_parser.py +602 -0
  14. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/rupture.py +4 -4
  15. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/station_metrics_xml.py +5 -2
  16. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/stream_workspace.py +8 -0
  17. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/global_fetcher.py +4 -22
  18. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/knet/core.py +27 -9
  19. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/knet/knet_fetcher.py +36 -32
  20. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/obspy/fdsn_fetcher.py +36 -38
  21. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/station_metric_collection.py +14 -14
  22. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/assemble.py +0 -1
  23. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/autoshakemap.py +0 -1
  24. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/base.py +43 -0
  25. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/compute_station_metrics.py +0 -1
  26. gmprocess-2.8.0/src/gmprocess/subcommands/compute_waveform_metrics.py +127 -0
  27. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/download.py +1 -4
  28. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/export_cosmos.py +0 -1
  29. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/export_failure_tables.py +4 -4
  30. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/export_metric_tables.py +4 -3
  31. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/export_provenance_tables.py +2 -2
  32. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/import_data.py +3 -4
  33. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/process_waveforms.py +56 -52
  34. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/constants.py +12 -9
  35. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/tests_utils.py +1 -1
  36. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/clipping/std_dev.py +15 -11
  37. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/corner_frequencies.py +11 -2
  38. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/nn_quality_assurance.py +22 -18
  39. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/phase.py +4 -2
  40. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/prism_adaptive_baseline.py +25 -25
  41. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/processing.py +4 -2
  42. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/sanity_checks.py +13 -0
  43. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/spectrum.py +0 -1
  44. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/windows.py +9 -5
  45. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess.egg-info/PKG-INFO +13 -7
  46. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess.egg-info/SOURCES.txt +3 -0
  47. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess.egg-info/requires.txt +6 -3
  48. gmprocess-2.8.0/src/gmprocess.egg-info/scm_file_list.json +1248 -0
  49. gmprocess-2.8.0/src/gmprocess.egg-info/scm_version.json +8 -0
  50. gmprocess-2.7.0/.coveragerc +0 -8
  51. gmprocess-2.7.0/pytest.ini +0 -4
  52. gmprocess-2.7.0/src/gmprocess/subcommands/compute_waveform_metrics.py +0 -136
  53. {gmprocess-2.7.0 → gmprocess-2.8.0}/.gitignore +0 -0
  54. {gmprocess-2.7.0 → gmprocess-2.8.0}/.vscode/settings.json +0 -0
  55. {gmprocess-2.7.0 → gmprocess-2.8.0}/CODE_OF_CONDUCT.md +0 -0
  56. {gmprocess-2.7.0 → gmprocess-2.8.0}/CONTRIBUTING.md +0 -0
  57. {gmprocess-2.7.0 → gmprocess-2.8.0}/DISCLAIMER.md +0 -0
  58. {gmprocess-2.7.0 → gmprocess-2.8.0}/LICENSE.md +0 -0
  59. {gmprocess-2.7.0 → gmprocess-2.8.0}/MANIFEST.in +0 -0
  60. {gmprocess-2.7.0 → gmprocess-2.8.0}/code.json +0 -0
  61. {gmprocess-2.7.0 → gmprocess-2.8.0}/setup.cfg +0 -0
  62. {gmprocess-2.7.0 → gmprocess-2.8.0}/setup.py +0 -0
  63. {gmprocess-2.7.0 → gmprocess-2.8.0}/setup_env.sh +0 -0
  64. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/__init__.py +0 -0
  65. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/apps/__init__.py +0 -0
  66. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/__init__.py +0 -0
  67. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/bundle_datarelease.py +0 -0
  68. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/cwa_gather.py +0 -0
  69. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/fetch_orfeus.py +0 -0
  70. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/fix_inventory.py +0 -0
  71. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/gmconvert.py +0 -0
  72. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/gminfo.py +0 -0
  73. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/gmprocess_config.py +0 -0
  74. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/gmrecords.py +0 -0
  75. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/gmworkspace.py +0 -0
  76. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/bin/update_event_json.sh +0 -0
  77. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/core/__init__.py +0 -0
  78. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/core/provenance.py +0 -0
  79. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/core/stationtrace.py +0 -0
  80. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/core/streamarray.py +0 -0
  81. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/core/streamcollection.py +0 -0
  82. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/CESMD_NGA_ids.csv +0 -0
  83. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/__init__.py +0 -0
  84. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/config_production.yml +0 -0
  85. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/config_production_v1.yml +0 -0
  86. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/config_test.yml +0 -0
  87. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/config_test_download.yml +0 -0
  88. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/cosmos_table10.xls +0 -0
  89. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/cosmos_table4.xls +0 -0
  90. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/demo/ci38457511/raw/CICCC.RAW +0 -0
  91. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/demo/ci38457511/raw/CICLC.v1 +0 -0
  92. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/demo/ci38457511/raw/CITOW2.RAW +0 -0
  93. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/demo/nc72282711/workspace.h5 +0 -0
  94. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/fdsn_codes.csv +0 -0
  95. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/lme/SA_rotd50.0_2020.03.31.csv +0 -0
  96. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/modules.yml +0 -0
  97. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nga_w2_selected.csv +0 -0
  98. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_clipping/bias_1.csv +0 -0
  99. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_clipping/bias_output.csv +0 -0
  100. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_clipping/masterF.txt +0 -0
  101. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_clipping/weight_1.csv +0 -0
  102. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_clipping/weight_output.csv +0 -0
  103. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/M.csv +0 -0
  104. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/bias_1.csv +0 -0
  105. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/bias_2.csv +0 -0
  106. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/bias_output.csv +0 -0
  107. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/final_training.csv +0 -0
  108. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/masterF.txt +0 -0
  109. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/model_3.txt +0 -0
  110. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/model_5.txt +0 -0
  111. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/mu_sigma.csv +0 -0
  112. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/weight_1.csv +0 -0
  113. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/weight_2.csv +0 -0
  114. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/Cant/weight_output.csv +0 -0
  115. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/M.csv +0 -0
  116. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/bias_1.csv +0 -0
  117. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/bias_2.csv +0 -0
  118. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/bias_output.csv +0 -0
  119. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/final_training.csv +0 -0
  120. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/masterF.txt +0 -0
  121. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/model_0.txt +0 -0
  122. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/mu_sigma.csv +0 -0
  123. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/weight_1.csv +0 -0
  124. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/weight_2.csv +0 -0
  125. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/nn_qa/CantWell/weight_output.csv +0 -0
  126. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/picker.yml +0 -0
  127. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/station_coordinates.xlsx +0 -0
  128. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/data/usgs_ids_nga_and_srcmod_cross_reference.xlsx +0 -0
  129. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/gui/__init__.py +0 -0
  130. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/gui/gui_ucla/Documentation.md +0 -0
  131. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/gui/gui_ucla/GUI_human_review.ipynb +0 -0
  132. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/gui/gui_ucla/HumanReviewGUI.py +0 -0
  133. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/gui/gui_ucla/__init__.py +0 -0
  134. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/__init__.py +0 -0
  135. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/__init__.py +0 -0
  136. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/base_metrics_xml.py +0 -0
  137. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/core.py +0 -0
  138. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/flatfile.py +0 -0
  139. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/flatfile_constants.py +0 -0
  140. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/path_utils.py +0 -0
  141. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/utils.py +0 -0
  142. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/waveform_metrics_xml.py +0 -0
  143. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/asdf/workspace_constants.py +0 -0
  144. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/bhrc/__init__.py +0 -0
  145. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/bhrc/core.py +0 -0
  146. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/cosmos/__init__.py +0 -0
  147. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/cosmos/cesmd_fetcher.py +0 -0
  148. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/cosmos/cesmd_search.py +0 -0
  149. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/cosmos/core.py +0 -0
  150. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/cosmos/cosmos_writer.py +0 -0
  151. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/cosmos/data_structures.py +0 -0
  152. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/cwb/__init__.py +0 -0
  153. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/cwb/core.py +0 -0
  154. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/dmg/__init__.py +0 -0
  155. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/dmg/core.py +0 -0
  156. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/dynamic_search_parameters.py +0 -0
  157. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/esm/__init__.py +0 -0
  158. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/esm/core.py +0 -0
  159. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/fetcher.py +0 -0
  160. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/geonet/__init__.py +0 -0
  161. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/geonet/core.py +0 -0
  162. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/knet/__init__.py +0 -0
  163. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/nga.py +0 -0
  164. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/nsmn/__init__.py +0 -0
  165. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/nsmn/core.py +0 -0
  166. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/obspy/__init__.py +0 -0
  167. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/obspy/core.py +0 -0
  168. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/read.py +0 -0
  169. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/read_directory.py +0 -0
  170. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/renadic/__init__.py +0 -0
  171. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/renadic/core.py +0 -0
  172. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/report.py +0 -0
  173. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/seedname.py +0 -0
  174. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/smc/__init__.py +0 -0
  175. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/smc/core.py +0 -0
  176. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/unam/__init__.py +0 -0
  177. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/unam/core.py +0 -0
  178. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/usc/__init__.py +0 -0
  179. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/usc/core.py +0 -0
  180. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/io/utils.py +0 -0
  181. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/__init__.py +0 -0
  182. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/combine.py +0 -0
  183. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/containers.py +0 -0
  184. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/metric_collection_base.py +0 -0
  185. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/oscillator.py +0 -0
  186. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/reduce.py +0 -0
  187. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/rotate.py +0 -0
  188. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/station_metric.py +0 -0
  189. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/transform.py +0 -0
  190. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/utils.py +0 -0
  191. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/waveform_metric_calculator.py +0 -0
  192. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/waveform_metric_calculator_component_base.py +0 -0
  193. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/waveform_metric_collection.py +0 -0
  194. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/waveform_metric_component.py +0 -0
  195. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/waveform_metric_list.py +0 -0
  196. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/metrics/waveform_metric_type.py +0 -0
  197. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/__init__.py +0 -0
  198. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/arg_dicts.py +0 -0
  199. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/autoprocess.py +0 -0
  200. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/clean.py +0 -0
  201. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/export_gmpacket.py +0 -0
  202. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/generate_regression_plot.py +0 -0
  203. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/generate_report.py +0 -0
  204. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/generate_station_maps.py +0 -0
  205. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/init.py +0 -0
  206. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/lazy_loader.py +0 -0
  207. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/processing_steps.py +0 -0
  208. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/subcommands/projects.py +0 -0
  209. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/__init__.py +0 -0
  210. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/args.py +0 -0
  211. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/assemble_utils.py +0 -0
  212. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/config.py +0 -0
  213. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/config_versioning.py +0 -0
  214. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/download_utils.py +0 -0
  215. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/export_gmpacket_utils.py +0 -0
  216. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/ground_motion_models.py +0 -0
  217. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/logging.py +0 -0
  218. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/memory.py +0 -0
  219. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/misc.py +0 -0
  220. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/misc_plots.py +0 -0
  221. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/prompt.py +0 -0
  222. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/report_utils.py +0 -0
  223. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/rupture_utils.py +0 -0
  224. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/strec.py +0 -0
  225. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/summary_plots.py +0 -0
  226. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/utils/tables.py +0 -0
  227. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/__init__.py +0 -0
  228. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/adjust_highpass.py +0 -0
  229. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/adjust_highpass_ridder.py +0 -0
  230. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/baseline_correction.py +0 -0
  231. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/clipping/clip_detection.py +0 -0
  232. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/clipping/clipping_ann.py +0 -0
  233. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/clipping/clipping_check.py +0 -0
  234. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/clipping/histogram.py +0 -0
  235. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/clipping/jerk.py +0 -0
  236. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/clipping/max_amp.py +0 -0
  237. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/clipping/ping.py +0 -0
  238. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/convert_units.py +0 -0
  239. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/count_stats.py +0 -0
  240. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/detrend.py +0 -0
  241. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/fft.py +0 -0
  242. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/filtering.py +0 -0
  243. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/instrument_response.py +0 -0
  244. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/integrate.py +0 -0
  245. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/pretesting.py +0 -0
  246. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/processing_step.py +0 -0
  247. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/resample.py +0 -0
  248. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/snr.py +0 -0
  249. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/taper.py +0 -0
  250. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/zero_crossings.py +0 -0
  251. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess/waveform_processing/zero_pad.py +0 -0
  252. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess.egg-info/dependency_links.txt +0 -0
  253. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess.egg-info/entry_points.txt +0 -0
  254. {gmprocess-2.7.0 → gmprocess-2.8.0}/src/gmprocess.egg-info/top_level.txt +0 -0
  255. {gmprocess-2.7.0 → gmprocess-2.8.0}/tools/matlab/README.md +0 -0
  256. {gmprocess-2.7.0 → gmprocess-2.8.0}/tools/matlab/get_all_waveforms.m +0 -0
  257. {gmprocess-2.7.0 → gmprocess-2.8.0}/tools/matlab/get_events.m +0 -0
  258. {gmprocess-2.7.0 → gmprocess-2.8.0}/tools/matlab/get_waveform_metrics.m +0 -0
  259. {gmprocess-2.7.0 → gmprocess-2.8.0}/tools/matlab/waveform_plot.png +0 -0
@@ -0,0 +1,13 @@
1
+ [report]
2
+ precision=2
3
+ omit=
4
+ # No way to test GUI
5
+ src/gmprocess/gui/gui_ucla/*
6
+ */__init__.py
7
+ # This is just a helper script that is only useful for USGS staff
8
+ src/gmprocess/bin/bundle_datarelease.py
9
+ # To be removed, includes a warning that it is not tested
10
+ src/gmprocess/waveform_processing/nn_quality_assurance.py
11
+ [run]
12
+ patch = subprocess
13
+ parallel = true
@@ -48,6 +48,9 @@ run tests and coverage:
48
48
  rules:
49
49
  - *fork
50
50
  - *upstream
51
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
52
+ variables:
53
+ VCR_RECORD_MODE: "none"
51
54
  script:
52
55
  - pip install -e .[test]
53
56
  - strec_cfg update --datafolder /home/usgs-user/ --gcmt
@@ -102,3 +105,23 @@ pages:
102
105
  - cd docs
103
106
  - bash makedocs.sh
104
107
  stage: docs
108
+
109
+ regression test:
110
+ rules:
111
+ - if: $CI_PIPELINE_SOURCE == "schedule"
112
+ variables:
113
+ ENVIRONMENT: staging
114
+ - if: >
115
+ $CI_PIPELINE_SOURCE != "schedule"
116
+ && $CI_PIPELINE_SOURCE != "merge_request_event"
117
+ when: manual
118
+ allow_failure: true
119
+ script:
120
+ - pip install -e .[test]
121
+ - pip install polars
122
+ - strec_cfg update --datafolder /home/usgs-user/ --gcmt
123
+ - mkdir /home/usgs-user/slabs
124
+ - cp tests/data/slab_data/*.grd /home/usgs-user/slabs/.
125
+ - cd tests/regression
126
+ - python regression_test.py --parameters ci.yml
127
+ stage: test
@@ -1,5 +1,41 @@
1
1
  ## main
2
2
 
3
+ ## 2.8.0 / 2026-08-27
4
+
5
+ - Enhancements
6
+ - Configure pytest to track subprocesses.
7
+ - Regression test with ci.yml config and nn00919749 event for CI monthly pipeline schedule
8
+ - Add extended StationXML parser.
9
+ - Increase use of pytest fixtures in an attempt to speed up unit tests.
10
+ - Vectorize the std_dev clipping check.
11
+ - Optimized the PRISM adaptive baseline correction method.
12
+ - Undo a the use of LazyLoader for situations where it is not necessary.
13
+ - Stop using SciPy for physical constants.
14
+ - Update tests to copy data into tmp_path, making tests independent and parallel-safe.
15
+ - Added FDSNFetcher tests.
16
+ - Added validation check to StationStream to look for traces with all identical values.
17
+ - Fixed bug in knet fetcher related to directory names in downloaded zip files.
18
+ - Fixed bug in check_tail when the trace ends before the window.
19
+ - Dependencies
20
+ - Removed esi-utils-rupture and replaced with esi-shakelib (min version 1.2.1)
21
+ - numpy>=2.0
22
+ - ps2ff>=1.5.9
23
+ - Added pytest-xdist to test dependencies; set addopts = "-n auto" in pyproject.toml to enable.
24
+ - Bugfix
25
+ - Fixed a crash in the SCEDC cloud channel query for windows spanning midnight UTC.
26
+ - Cloud download windows crossing a month or year boundary were treated as a single UTC day.
27
+ - The NCEDC cloud channel query returned a dataframe with no columns when the query failed.
28
+ - handle numpy integer and float in stream_workspace \_serializer
29
+ - FDSNFetcher was not handling the international date line crossing correctly and skipping GeoNet data.
30
+ - Removed the usage of StreamCollection objects in the global fetcher, as they are not used and were not
31
+ consistently returned by all fetcher classes.
32
+ - Fixing bug in knet reader where both horizontal channels were assigned an azimuth of 90.0.
33
+ - Fixing bug in knet fetcher where it was not handling multiple candidate events.
34
+ - Changed output units of SAC files in export_ff_sac.py to be m/s^2, since that is what FFM expects.
35
+ - Other
36
+ - Remove test for nnet_qa step, issue warning that it is on longer tested, and will soon be removed; this is because I don't think anyone uses it and it is a lot of code and the unit tests take a long time.
37
+ - CI/Pipelines
38
+ - Fix issue with unscheduled (unit tests) not running automatically due to scheduled regression test
3
39
 
4
40
  ## 2.7.0 / 2026-06-04
5
41
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gmprocess
3
- Version: 2.7.0
3
+ Version: 2.8.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
@@ -57,7 +57,7 @@ Requires-Dist: configobj>=5.0.6
57
57
  Requires-Dist: esi-core>=1.2.1
58
58
  Requires-Dist: esi-utils-colors>1.0
59
59
  Requires-Dist: esi-utils-io>1.0
60
- Requires-Dist: esi-utils-rupture<=1.0.4,>1.0
60
+ Requires-Dist: esi-shakelib>=1.2.1
61
61
  Requires-Dist: folium>=0.12
62
62
  Requires-Dist: gmpacket>=0.1.6
63
63
  Requires-Dist: h3
@@ -65,13 +65,13 @@ Requires-Dist: h5py>=3.11
65
65
  Requires-Dist: lxml>=4.6.1
66
66
  Requires-Dist: matplotlib>=3.1.0
67
67
  Requires-Dist: numba>=0.58
68
- Requires-Dist: numpy>=1.26
68
+ Requires-Dist: numpy<2.4,>=2.0
69
69
  Requires-Dist: obspy>=1.5.0
70
70
  Requires-Dist: openpyxl>=3.1.0
71
71
  Requires-Dist: openquake.engine>=3.18
72
72
  Requires-Dist: pandas>=1.3.0
73
73
  Requires-Dist: Pint>0.24.3
74
- Requires-Dist: ps2ff>=1.5.2
74
+ Requires-Dist: ps2ff>=1.5.9
75
75
  Requires-Dist: pyarrow
76
76
  Requires-Dist: pyasdf>=0.7
77
77
  Requires-Dist: pydantic[email]>=2.0
@@ -93,10 +93,13 @@ Requires-Dist: flake8>=3.9; extra == "dev"
93
93
  Requires-Dist: ipython>=7.26; extra == "dev"
94
94
  Requires-Dist: pylint>=2.17; extra == "dev"
95
95
  Provides-Extra: test
96
+ Requires-Dist: pytest-xdist>=3.8; extra == "test"
96
97
  Requires-Dist: pytest>=6.2; extra == "test"
97
98
  Requires-Dist: pytest-cov>=2.12; extra == "test"
98
99
  Requires-Dist: pytest-console-scripts>=1.4; extra == "test"
100
+ Requires-Dist: pytest-subprocess>=1.6.0; extra == "test"
99
101
  Requires-Dist: vcrpy>=4.1; extra == "test"
102
+ Requires-Dist: polars; extra == "test"
100
103
  Provides-Extra: doc
101
104
  Requires-Dist: altair>=4.2.2; extra == "doc"
102
105
  Requires-Dist: furo>=2023.3.27; extra == "doc"
@@ -129,10 +132,13 @@ Most of the extensions that we provide are to handle strong motion data and rela
129
132
  # Getting Help
130
133
  The developers can be reached at [gmprocess@usgs.gov](mailto:gmprocess@usgs.gov).
131
134
 
132
- If you would like to post an issue to ask a question, request a new feature, or report a bug, you can do so at the [github mirror](https://github.com/DOI-USGS/ghsc-esi-groundmotion-processing) of this repository.
135
+ If you would like to post an issue, ask a question, request a new feature, or report a bug, you can do so at here in
136
+ [Work Items](https://code.usgs.gov/ghsc/esi/groundmotion-processing/-/work_items).
137
+ This GitLab instance, however, is restricted to registered users, and registering a user is not immediate or automatic, requiring an internal approval process.
138
+ Posting issues is easier on GitHub, and the developers of this repository monitor the
139
+ [groundmotion-processing-github](https://github.com/DOI-USGS/groundmotion-processing-github) repository's issues to alleviate need to deal with the code.usgs.gov restrictions.
133
140
 
134
- If you would like to contribute merge requests to this repository, please let us know and we can add you as a collaborator.
135
- This will require that you create an account at code.usgs.gov, which is a more involved process than creating a personal account at github.com and posting to the issues on the github mirror.
141
+ If you would like to contribute merge requests to this repository, please let us know and we can assist you in registering an account at [code.usgs.gov](code.usgs.gov).
136
142
 
137
143
  # Suggested Citation
138
144
  If you wish to cite this software please cite:
@@ -12,10 +12,13 @@ Most of the extensions that we provide are to handle strong motion data and rela
12
12
  # Getting Help
13
13
  The developers can be reached at [gmprocess@usgs.gov](mailto:gmprocess@usgs.gov).
14
14
 
15
- If you would like to post an issue to ask a question, request a new feature, or report a bug, you can do so at the [github mirror](https://github.com/DOI-USGS/ghsc-esi-groundmotion-processing) of this repository.
15
+ If you would like to post an issue, ask a question, request a new feature, or report a bug, you can do so at here in
16
+ [Work Items](https://code.usgs.gov/ghsc/esi/groundmotion-processing/-/work_items).
17
+ This GitLab instance, however, is restricted to registered users, and registering a user is not immediate or automatic, requiring an internal approval process.
18
+ Posting issues is easier on GitHub, and the developers of this repository monitor the
19
+ [groundmotion-processing-github](https://github.com/DOI-USGS/groundmotion-processing-github) repository's issues to alleviate need to deal with the code.usgs.gov restrictions.
16
20
 
17
- If you would like to contribute merge requests to this repository, please let us know and we can add you as a collaborator.
18
- This will require that you create an account at code.usgs.gov, which is a more involved process than creating a personal account at github.com and posting to the issues on the github mirror.
21
+ If you would like to contribute merge requests to this repository, please let us know and we can assist you in registering an account at [code.usgs.gov](code.usgs.gov).
19
22
 
20
23
  # Suggested Citation
21
24
  If you wish to cite this software please cite:
@@ -23,7 +23,7 @@ dependencies = [
23
23
  "esi-core>=1.2.1",
24
24
  "esi-utils-colors>1.0",
25
25
  "esi-utils-io>1.0",
26
- "esi-utils-rupture>1.0,<=1.0.4",
26
+ "esi-shakelib>=1.2.1",
27
27
  "folium>=0.12",
28
28
  "gmpacket>=0.1.6",
29
29
  "h3",
@@ -31,13 +31,13 @@ dependencies = [
31
31
  "lxml>=4.6.1",
32
32
  "matplotlib>=3.1.0",
33
33
  "numba>=0.58",
34
- "numpy>=1.26",
34
+ "numpy>=2.0,<2.4",
35
35
  "obspy>=1.5.0",
36
36
  "openpyxl>=3.1.0",
37
37
  "openquake.engine>=3.18",
38
38
  "pandas>=1.3.0",
39
39
  "Pint>0.24.3",
40
- "ps2ff>=1.5.2",
40
+ "ps2ff>=1.5.9",
41
41
  "pyarrow",
42
42
  "pyasdf>=0.7",
43
43
  "pydantic[email]>=2.0",
@@ -63,10 +63,13 @@ dev = [
63
63
  "pylint>=2.17",
64
64
  ]
65
65
  test = [
66
+ "pytest-xdist>=3.8",
66
67
  "pytest>=6.2",
67
68
  "pytest-cov>=2.12",
68
69
  "pytest-console-scripts>=1.4",
70
+ "pytest-subprocess>=1.6.0",
69
71
  "vcrpy>=4.1",
72
+ "polars",
70
73
  ]
71
74
  doc = [
72
75
  "altair>=4.2.2",
@@ -119,4 +122,3 @@ include = ["gmprocess*"]
119
122
  exclude = ["tests*"]
120
123
 
121
124
  [tool.setuptools_scm]
122
-
@@ -0,0 +1,7 @@
1
+ [pytest]
2
+ addopts =
3
+ --ignore=src/gmprocess/gui/gui_ucla/
4
+ -n auto
5
+ norecursedirs = tests/regression
6
+ filterwarnings =
7
+ ignore::DeprecationWarning
@@ -8,16 +8,15 @@ import inspect
8
8
  import io
9
9
  import logging
10
10
  import os
11
- from pathlib import Path
12
11
  import pkgutil
13
12
  import shutil
14
13
  import sys
15
14
  import traceback
15
+ from pathlib import Path
16
16
 
17
+ from gmprocess.subcommands.lazy_loader import LazyLoader
17
18
  from gmprocess.subcommands.projects import Project
18
19
 
19
- from ..subcommands.lazy_loader import LazyLoader
20
-
21
20
  VERSION = importlib.metadata.version("gmprocess")
22
21
 
23
22
  configobj = LazyLoader("configobj", globals(), "configobj")
@@ -78,7 +77,9 @@ class GMrecordsApp(object):
78
77
 
79
78
  def main(self, **kwargs):
80
79
  self.args = (
81
- argparse.Namespace(**kwargs) if kwargs else self._parse_command_line()
80
+ argparse.Namespace(**kwargs)
81
+ if kwargs
82
+ else self._parse_command_line()
82
83
  )
83
84
  if self.args.subcommand is None:
84
85
  self.parser.print_help()
@@ -86,7 +87,9 @@ class GMrecordsApp(object):
86
87
  else:
87
88
  if self.args.datadir is None and self.args.confdir is None:
88
89
  self.use_projects = True
89
- elif self.args.datadir is not None and self.args.confdir is not None:
90
+ elif (
91
+ self.args.datadir is not None and self.args.confdir is not None
92
+ ):
90
93
  self.use_projects = False
91
94
  else:
92
95
  raise ValueError(
@@ -100,10 +103,15 @@ class GMrecordsApp(object):
100
103
  self._initialize()
101
104
 
102
105
  subcmds_quiet = ["init", "projects", "proj", "processing_steps"]
103
- if self.args.subcommand not in subcmds_quiet and not self.args.quiet:
106
+ if (
107
+ self.args.subcommand not in subcmds_quiet
108
+ and not self.args.quiet
109
+ ):
104
110
  if self.use_projects:
105
111
  # Print the current project information to avoid confusion
106
- proj = Project.from_config(self.projects_conf, self.project_name)
112
+ proj = Project.from_config(
113
+ self.projects_conf, self.project_name
114
+ )
107
115
  else:
108
116
  proj_paths = {
109
117
  "conf_path": self.args.confdir,
@@ -143,7 +151,9 @@ class GMrecordsApp(object):
143
151
  mod = importlib.import_module("gmprocess.subcommands")
144
152
  subcommands = {
145
153
  name: importlib.import_module(name)
146
- for _, name, _ in pkgutil.iter_modules(mod.__path__, mod.__name__ + ".")
154
+ for _, name, _ in pkgutil.iter_modules(
155
+ mod.__path__, mod.__name__ + "."
156
+ )
147
157
  }
148
158
  self.classes = {}
149
159
  for name, module in subcommands.items():
@@ -179,14 +189,18 @@ class GMrecordsApp(object):
179
189
  @property
180
190
  def conf_path(self):
181
191
  if self.projects_path:
182
- return (self.projects_path / self.current_project["conf_path"]).resolve()
192
+ return (
193
+ self.projects_path / self.current_project["conf_path"]
194
+ ).resolve()
183
195
  else:
184
196
  return Path(self.current_project["conf_path"]).resolve()
185
197
 
186
198
  @property
187
199
  def data_path(self):
188
200
  if self.projects_path:
189
- return (self.projects_path / self.current_project["data_path"]).resolve()
201
+ return (
202
+ self.projects_path / self.current_project["data_path"]
203
+ ).resolve()
190
204
  else:
191
205
  return Path(self.current_project["data_path"]).resolve()
192
206
 
@@ -200,10 +214,15 @@ class GMrecordsApp(object):
200
214
 
201
215
  # get the email error notification portion of config, if present
202
216
  error_dict = {}
203
- if self.conf is not None and self.conf["error_notification"] is not None:
217
+ if (
218
+ self.conf is not None
219
+ and self.conf["error_notification"] is not None
220
+ ):
204
221
  error_dict = dict(self.conf["error_notification"])
205
222
 
206
- log_utils.setup_logger(self.args, log_file=log_file, error_dict=error_dict)
223
+ log_utils.setup_logger(
224
+ self.args, log_file=log_file, error_dict=error_dict
225
+ )
207
226
  logging.info("Logging level includes INFO.")
208
227
  logging.debug("Logging level includes DEBUG.")
209
228
  logging.info(f"PROJECTS_PATH: {self.projects_path}")
@@ -255,7 +274,9 @@ class GMrecordsApp(object):
255
274
  str(self.projects_file), encoding="utf-8"
256
275
  )
257
276
 
258
- projmod.validate_projects_config(self.projects_conf, self.projects_path)
277
+ projmod.validate_projects_config(
278
+ self.projects_conf, self.projects_path
279
+ )
259
280
 
260
281
  if "CALLED_FROM_PYTEST" in os.environ:
261
282
  # Check if we are running unit tests
@@ -270,12 +291,19 @@ class GMrecordsApp(object):
270
291
 
271
292
  # Otherwise use the default testing config
272
293
  else:
273
- test_conf_file = (const.DATA_DIR / const.CONFIG_FILE_TEST).resolve()
294
+ test_conf_file = (
295
+ const.DATA_DIR / const.CONFIG_FILE_TEST
296
+ ).resolve()
274
297
 
275
298
  # Copy into the tmp gmptest project directory
276
299
  shutil.copyfile(test_conf_file, conf_path / const.CONFIG_FILE_TEST)
277
300
 
278
- subcommands_need_conf = ["download", "assemble", "autoshakemap", "autoprocess"]
301
+ subcommands_need_conf = [
302
+ "download",
303
+ "assemble",
304
+ "autoshakemap",
305
+ "autoprocess",
306
+ ]
279
307
  if self.args.func.command_name in subcommands_need_conf:
280
308
  self.conf = configmod.get_config(config_path=self.conf_path)
281
309
 
@@ -415,7 +443,9 @@ class GMrecordsApp(object):
415
443
 
416
444
  # Parsers for subcommands
417
445
  subparsers = parser.add_subparsers(
418
- title="Subcommands", dest="subcommand", metavar="<command> (<aliases>)"
446
+ title="Subcommands",
447
+ dest="subcommand",
448
+ metavar="<command> (<aliases>)",
419
449
  )
420
450
 
421
451
  # Get subcommands and their arguments
@@ -450,3 +480,8 @@ class GMrecordsApp(object):
450
480
  parsers[-1].add_argument(*pargs, **targ_dict)
451
481
  parsers[-1].set_defaults(func=cdict["class"])
452
482
  return parser.parse_args()
483
+
484
+
485
+ if __name__ == "__main__":
486
+ app = GMrecordsApp()
487
+ app.main()
@@ -5,9 +5,12 @@ from pathlib import Path
5
5
 
6
6
  import matplotlib.pyplot as plt
7
7
  import numpy as np
8
- from gmprocess.io.asdf.stream_workspace import StreamWorkspace
9
8
  from obspy.geodetics import gps2dist_azimuth
10
9
 
10
+ from gmprocess.io.asdf.stream_workspace import StreamWorkspace
11
+
12
+ GALS_TO_MPS2 = 1 / 100.0 # convert from gals to m/s^2
13
+
11
14
 
12
15
  def get_parser():
13
16
  parser = argparse.ArgumentParser(
@@ -199,6 +202,9 @@ def write_sac_files(streams, passing_indices, id_selected, out_dir):
199
202
  for id_sel in id_selected:
200
203
  stream = streams[passing_indices[id_sel]]
201
204
  for trace in stream:
205
+ # convert to m/s^2
206
+ trace.data = trace.data * GALS_TO_MPS2
207
+ trace.stats.standard["units"] = "m/s^2"
202
208
  trace.stats.sac = make_sac_headers(
203
209
  trace.stats.channel,
204
210
  trace.stats.coordinates.latitude,
@@ -223,6 +229,9 @@ def write_supp_sac_files(sc, sta_ids, supp_dir):
223
229
  for stream in sc:
224
230
  if stream.passed and stream[0].stats.station in sta_ids:
225
231
  for trace in stream:
232
+ # convert to m/s^2
233
+ trace.data = trace.data * GALS_TO_MPS2
234
+ trace.stats.standard["units"] = "m/s^2"
226
235
  trace.stats.sac = make_sac_headers(
227
236
  trace.stats.channel,
228
237
  trace.stats.coordinates.latitude,
@@ -262,7 +271,11 @@ def save_summary_plot(
262
271
  ax.set_xlabel("Longitude")
263
272
  ax.set_ylabel("Latitude")
264
273
  ax.legend()
265
- fname = Path(outdir) / f"{eqid}_select_summary.png"
274
+ foutdir = Path(outdir)
275
+ if not foutdir.exists():
276
+ foutdir.mkdir(parents=True)
277
+ fname = foutdir / f"{eqid}_select_summary.png"
278
+
266
279
  fig.savefig(fname, dpi=300)
267
280
  plt.close(fig)
268
281
  print(f"Wrote summary plot: {fname}")
@@ -274,6 +287,7 @@ def main():
274
287
 
275
288
  sw = StreamWorkspace.open(args.workspace)
276
289
  sc = sw.get_streams(args.event_id, labels=["default"])
290
+ print(f"{len(sc)} streams found.")
277
291
  event = sw.get_event(args.event_id)
278
292
 
279
293
  lat, lon, dist, pgv, passing_indices = collect_stream_data(sc, event)
@@ -74,6 +74,17 @@ SCEDC_INDEX_FILE_TEMPLATE = (
74
74
  "year_doy={year}_{jday}/{year}_{jday}_waveform_index.parquet"
75
75
  )
76
76
 
77
+ CHANNEL_COLUMNS = [
78
+ "network",
79
+ "station",
80
+ "location",
81
+ "channel",
82
+ "latitude",
83
+ "longitude",
84
+ "starttime",
85
+ "endtime",
86
+ ]
87
+
77
88
  WAVEFORM_TIMEFMT = "%Y%m%dT%H%M%SZ"
78
89
  COMCAT_TIMEFMT = "%Y-%m-%dT%H:%M:%S"
79
90
 
@@ -216,7 +227,7 @@ def to_standard_waveform(provider, key_filename):
216
227
  if provider == "ncedc":
217
228
  parts = key_filename.split(".")
218
229
  station, network, channel, location = parts[0:4]
219
- jday = parts[-2]
230
+ jday = parts[-1]
220
231
  else:
221
232
  network = key_filename[0:2]
222
233
  station = key_filename[2:7].rstrip("_")
@@ -323,25 +334,27 @@ def get_ncedc_channel_dataframe(
323
334
  level="channel",
324
335
  )
325
336
  except Exception as e:
326
- channel_dataframe = pd.DataFrame([])
327
- return channel_dataframe
337
+ logging.warning(f"Failed to download NCEDC station metadata: '{e}'")
338
+ # Return an empty frame that still has the expected columns, so that
339
+ # downstream column access does not raise.
340
+ return pd.DataFrame(columns=CHANNEL_COLUMNS)
328
341
  channel_rows = []
329
- for network in inventory.networks:
330
- for station in network.stations:
331
- for channel in station.channels:
342
+ for inv_network in inventory.networks:
343
+ for inv_station in inv_network.stations:
344
+ for inv_channel in inv_station.channels:
332
345
  channel_row = {
333
- "network": network.code,
334
- "station": station.code,
335
- "location": channel.location_code,
336
- "channel": channel.code,
337
- "latitude": channel.latitude,
338
- "longitude": channel.longitude,
346
+ "network": inv_network.code,
347
+ "station": inv_station.code,
348
+ "location": inv_channel.location_code,
349
+ "channel": inv_channel.code,
350
+ "latitude": inv_channel.latitude,
351
+ "longitude": inv_channel.longitude,
339
352
  "starttime": starttime,
340
353
  "endtime": endtime,
341
354
  }
342
355
  channel_rows.append(channel_row)
343
356
 
344
- channel_dataframe = pd.DataFrame(data=channel_rows)
357
+ channel_dataframe = pd.DataFrame(data=channel_rows, columns=CHANNEL_COLUMNS)
345
358
  # restrict the networks in this dataframe to only those that
346
359
  # NC supports
347
360
  # supported_networks = get_provider_networks("ncedc")
@@ -376,6 +389,22 @@ def get_provider_networks(provider):
376
389
  return supported_networks
377
390
 
378
391
 
392
+ def spans_multiple_days(starttime, endtime):
393
+ """Determine whether a time window crosses a UTC day boundary.
394
+
395
+ Comparing the day of the month alone would treat windows that cross a month
396
+ or year boundary as falling on a single day.
397
+
398
+ Args:
399
+ starttime (UTCDateTime): Start of the window.
400
+ endtime (UTCDateTime): End of the window.
401
+
402
+ Returns:
403
+ bool: True if the window spans more than one UTC day.
404
+ """
405
+ return (starttime.year, starttime.julday) != (endtime.year, endtime.julday)
406
+
407
+
379
408
  def get_scedc_channel_dataframe(
380
409
  network,
381
410
  station,
@@ -400,17 +429,18 @@ def get_scedc_channel_dataframe(
400
429
  bucket = PROVIDERS["scedc"]["bucket"]
401
430
  s3_client.download_fileobj(bucket, index_file1, fobj)
402
431
  dataframe = pd.read_parquet(fobj)
403
- if endtime.day != starttime.day:
432
+ if spans_multiple_days(starttime, endtime):
404
433
  index_file2 = SCEDC_INDEX_FILE_TEMPLATE.format(
405
434
  year=endtime.year, jday=endtime.strftime("%j")
406
435
  )
407
436
  fobj = BytesIO()
408
437
  s3_client.download_fileobj(bucket, index_file2, fobj)
409
438
  dataframe2 = pd.read_parquet(fobj)
410
- dataframe = pd.concat([dataframe, dataframe2])
439
+ dataframe = pd.concat([dataframe, dataframe2], ignore_index=True)
411
440
  dataframe.drop_duplicates(
412
441
  subset=["net", "sta", "location", "seedchan"],
413
442
  inplace=True,
443
+ ignore_index=True,
414
444
  )
415
445
  channel_dataframe = filter_scindex_dataframe(
416
446
  dataframe,
@@ -516,12 +546,12 @@ def get_channels_regex(oldchannel):
516
546
 
517
547
 
518
548
  def filter_by_channels(dataframe, channels):
519
- indices = []
549
+ # Accumulate the match mask positionally. Building a DataFrame from the
550
+ # per-pattern boolean Series would force an index union, which fails when
551
+ # the caller's frame has duplicate labels (e.g. concatenated daily indices).
552
+ newindex = np.zeros(len(dataframe), dtype=bool)
520
553
  for channel in channels:
521
- index = dataframe["seedchan"].str.contains(channel)
522
- indices.append(index)
523
- iframe = pd.DataFrame(indices)
524
- newindex = iframe.any(axis=0)
554
+ newindex |= dataframe["seedchan"].str.contains(channel).to_numpy(dtype=bool)
525
555
  newframe = dataframe[newindex].copy()
526
556
  return newframe
527
557
 
@@ -574,7 +604,7 @@ def filter_scindex_dataframe(
574
604
  and maxlongitude is not None
575
605
  )
576
606
  if has_radius:
577
- dataframe["distance_deg"] = vincenty(
607
+ dataframe["distance_deg"] = get_distance(
578
608
  latitude, longitude, dataframe["lat"], dataframe["lon"]
579
609
  )
580
610
  if not has_center:
@@ -638,7 +668,7 @@ def get_waveform_jobs(provider, dataframe, directory):
638
668
  )
639
669
  job = {"provider": provider, "key": key1, "directory": directory}
640
670
  jobs.append(job)
641
- if endtime.day != starttime.day:
671
+ if spans_multiple_days(starttime, endtime):
642
672
  key2 = format_waveform_key(
643
673
  provider, endtime, network, station, location, channel
644
674
  )
@@ -669,7 +699,8 @@ def get_metadata_jobs(provider, dataframe, directory):
669
699
  else:
670
700
  unmatched_rows.append(group.iloc[0])
671
701
 
672
- unmatched = pd.DataFrame(data=unmatched_rows)
702
+ # The rows carry their source labels, which are not guaranteed to be unique.
703
+ unmatched = pd.DataFrame(data=unmatched_rows).reset_index(drop=True)
673
704
  return (jobs, unmatched)
674
705
 
675
706
 
@@ -768,7 +799,7 @@ def trim_waveform(job):
768
799
  filename.unlink()
769
800
 
770
801
 
771
- def vincenty(lat1, lon1, lat2, lon2):
802
+ def get_distance(lat1, lon1, lat2, lon2):
772
803
  lmb1 = np.deg2rad(lon1)
773
804
  lmb2 = np.deg2rad(lon2)
774
805
  phi1 = np.deg2rad(lat1)
@@ -20,7 +20,7 @@ class ScalarEvent(Event):
20
20
  Note that depth in obspy's Origin object is in meters, but we use km.
21
21
 
22
22
  Also, be careful because we have a similar object with the same name:
23
- esi_utils_rupture.origin.Origin.
23
+ esi_shakelib.rupture.origin.Origin.
24
24
 
25
25
  """
26
26