From ada69561a013141aaf88d4df0fbe2490cad1c760 Mon Sep 17 00:00:00 2001 From: "Stephen R. Guiwits" Date: Tue, 13 Jun 2017 23:09:26 +0000 Subject: [PATCH 01/18] created new directory structures with trunk, tags, and branches sub directories git-svn-id: svn+ssh://eew-repo.gps.caltech.edu/eew/eewrt/trunk@2327 60991594-3ae1-49b3-9084-6570e54bf7ff From ffc012b45a380795ce29114c97fda1b01b05e461 Mon Sep 17 00:00:00 2001 From: Carl Ulberg Date: Wed, 21 Dec 2022 21:44:04 +0000 Subject: [PATCH 02/18] Add GFAST to ShakeAlert main branch --- Makefile | 64 + include/dmlibWrapper.h | 133 + include/gfast.h | 55 + include/gfast_activeMQ.h | 88 + include/gfast_config.h | 8 + include/gfast_core.h | 714 ++++ include/gfast_eewUtils.h | 118 + include/gfast_enum.h | 82 + include/gfast_hdf5.h | 401 ++ include/gfast_struct.h | 592 +++ include/gfast_traceBuffer.h | 304 ++ include/gfast_xml.h | 354 ++ run/bin/run_gfast.sh | 205 + run/params/M99.txt | 24 + run/params/gfast.props | 1 + run/params/gfast.props.NOAA | 113 + run/params/gfast.props.SA | 195 + run/params/pgd_threshold_PW.txt | 15 + run/params/raw_sigma_threshold_PW.txt | 1 + src/Makefile | 139 + src/activeMQ/Makefile | 67 + src/activeMQ/ShakeAlertConsumer.cpp | 348 ++ src/activeMQ/ShakeAlertConsumer.h | 175 + src/activeMQ/ShakeAlertProducer.cpp | 303 ++ src/activeMQ/ShakeAlertProducer.h | 145 + src/activeMQ/activeMQ.c | 87 + src/activeMQ/activeMQ.cpp | 39 + src/activeMQ/consumer.cpp | 208 + src/activeMQ/producer.cpp | 171 + src/activeMQ/readIni.c | 180 + src/core/Makefile | 82 + src/core/cmt/Makefile | 66 + src/core/cmt/decomposeMomentTensor.c | 207 + src/core/cmt/depthGridSearch.c | 330 ++ src/core/cmt/finalize.c | 76 + src/core/cmt/gridSearch.c | 203 + src/core/cmt/initialize.c | 121 + src/core/cmt/readIni.c | 143 + src/core/cmt/setDiagonalWeightMatrix.c | 114 + src/core/cmt/setForwardModel.c | 150 + src/core/cmt/setRHS.c | 54 + src/core/cmt/weightForwardModel.c | 99 + src/core/cmt/weightObservations.c | 58 + src/core/coordtools/Makefile | 64 + src/core/coordtools/ll2utm.c | 83 + src/core/coordtools/utm2ll.c | 96 + src/core/data/Makefile | 64 + src/core/data/finalize.c | 31 + src/core/data/initialize.c | 63 + src/core/data/readMetaDataFile.c | 418 ++ src/core/data/readSiteMaskFile.c | 158 + src/core/events/Makefile | 65 + src/core/events/freeEvents.c | 21 + src/core/events/getMinOriginTime.c | 42 + src/core/events/newEvent.c | 139 + src/core/events/printEvent.c | 40 + src/core/events/removeCancelledEvent.c | 110 + src/core/events/removeExpiredEvent.c | 116 + src/core/events/removeExpiredEvents.c | 72 + src/core/events/syncXMLStatusWithEvents.c | 103 + src/core/events/updateEvent.c | 77 + src/core/ff/Makefile | 67 + src/core/ff/faultPlaneGridSearch.c | 516 +++ src/core/ff/finalize.c | 124 + src/core/ff/initialize.c | 116 + src/core/ff/meshFaultPlane.c | 248 ++ src/core/ff/readIni.c | 122 + src/core/ff/setDiagonalWeightMatrix.c | 110 + src/core/ff/setForwardModel.c | 477 +++ src/core/ff/setRHS.c | 47 + src/core/ff/setRegularizer.c | 170 + src/core/ff/weightForwardModel.c | 71 + src/core/ff/weightObservations.c | 56 + src/core/log/Makefile | 69 + src/core/log/log.c | 576 +++ src/core/log/log.cpp | 43 + src/core/properties/Makefile | 65 + src/core/properties/finalize.c | 85 + src/core/properties/initialize.c | 491 +++ src/core/properties/print.c | 315 ++ src/core/scaling/Makefile | 68 + src/core/scaling/pgd_depthGridSearch.c | 341 ++ src/core/scaling/pgd_finalize.c | 83 + src/core/scaling/pgd_gridSearch.c | 185 + src/core/scaling/pgd_initialize.c | 119 + src/core/scaling/pgd_readIni.c | 207 + src/core/scaling/pgd_sanityChecks.c | 117 + .../scaling/pgd_setDiagonalWeightMatrix.c | 62 + src/core/scaling/pgd_setForwardModel.c | 42 + src/core/scaling/pgd_setRHS.c | 47 + src/core/scaling/pgd_weightForwardModel.c | 57 + src/core/scaling/pgd_weightObservations.c | 57 + src/core/scaling/readPgdThresholdLookupFile.c | 98 + .../scaling/readRawSigmaThresholdLookupFile.c | 87 + src/core/scaling/readSigmaLookupFile.c | 88 + src/core/waveformProcessor/Makefile | 64 + src/core/waveformProcessor/offset.c | 311 ++ src/core/waveformProcessor/peakDisplacement.c | 308 ++ .../peakDisplacementHelper.c | 179 + src/dmlib/Makefile | 70 + src/dmlib/dmlibWrapper.cpp | 574 +++ src/doxygen.conf | 40 + src/eewUtils/Makefile | 74 + src/eewUtils/driveCMT.c | 472 +++ src/eewUtils/driveFF.c | 521 +++ src/eewUtils/driveGFAST.c | 913 +++++ src/eewUtils/drivePGD.c | 296 ++ src/eewUtils/makeXML.c | 593 +++ src/eewUtils/parseCoreXML.c | 171 + src/eewUtils/setLogFileNames.c | 52 + src/gfast_eew.c | 657 ++++ src/gfast_playback.c | 291 ++ src/hdf5/Makefile | 69 + src/hdf5/copy.c | 1276 ++++++ src/hdf5/createType.c | 796 ++++ src/hdf5/getMaxGroupNumber.c | 41 + src/hdf5/h5_cinter.c | 1010 +++++ src/hdf5/initialize.c | 152 + src/hdf5/memory.c | 159 + src/hdf5/setFileName.c | 78 + src/hdf5/update.c | 614 +++ src/tests/CoreActiveMqUT.cc | 26 + src/tests/CoreCoordtoolsUT.cc | 80 + src/tests/CoreDataUT.cc | 114 + src/tests/CoreEventsUT.cc | 151 + src/tests/CoreScalingUT.cc | 200 + src/tests/CoreWaveformProcessorUT.cc | 139 + src/tests/EewUtilsUT.cc | 289 ++ src/tests/Makefile | 169 + src/tests/TraceBufferEwrrUT.cc | 105 + src/tests/data/M99.txt | 24 + src/tests/data/final_cmt.maule.txt | 321 ++ src/tests/data/final_ff.maule.txt | 74 + src/tests/data/final_pgd.maule.txt | 221 ++ src/tests/data/gfast.props | 180 + src/tests/data/merged_chanfile_coord.dat | 3446 +++++++++++++++++ src/tests/data/pgd_threshold_PW.txt | 4 + src/tests/data/raw_sigma_threshold_PW.txt | 1 + src/tests/data/sa_message.xml | 67 + src/tests/gfast_ut_utils.h | 313 ++ src/traceBuffer/Makefile | 99 + src/traceBuffer/ewrr/Makefile | 67 + src/traceBuffer/ewrr/classifyRetval.c | 78 + src/traceBuffer/ewrr/finalize.c | 36 + src/traceBuffer/ewrr/flushRing.c | 46 + src/traceBuffer/ewrr/freetb2Data.c | 37 + src/traceBuffer/ewrr/freetb2Trace.c | 38 + src/traceBuffer/ewrr/getMessagesFromRing.c | 211 + src/traceBuffer/ewrr/initialize.c | 149 + src/traceBuffer/ewrr/settb2Data.c | 78 + src/traceBuffer/ewrr/settb2DataFromGFAST.c | 93 + src/traceBuffer/ewrr/tb2_hash.c | 188 + .../ewrr/unpackTraceBuf2Messages.c | 593 +++ src/traceBuffer/h5/Makefile | 67 + src/traceBuffer/h5/copyTraceBufferToGFAST.c | 298 ++ src/traceBuffer/h5/finalize.c | 64 + src/traceBuffer/h5/getData.c | 192 + src/traceBuffer/h5/getDoubleArray.c | 71 + src/traceBuffer/h5/getScalars.c | 157 + src/traceBuffer/h5/initialize.c | 361 ++ src/traceBuffer/h5/readData.c | 125 + src/traceBuffer/h5/setData.c | 310 ++ src/traceBuffer/h5/setFileName.c | 64 + src/traceBuffer/h5/setScalars.c | 127 + src/traceBuffer/h5/setTraceBufferFromGFAST.c | 196 + src/uw/beachball.c | 1235 ++++++ src/uw/beachball.h | 101 + src/uw/gfast2web.c | 485 +++ src/xml/Makefile | 79 + src/xml/quakeML/Makefile | 65 + src/xml/quakeML/depth.c | 78 + src/xml/quakeML/epoch2string.c | 39 + src/xml/quakeML/focalMechanism.c | 194 + src/xml/quakeML/latitude.c | 78 + src/xml/quakeML/longitude.c | 78 + src/xml/quakeML/magnitude.c | 73 + src/xml/quakeML/momentTensor.c | 125 + src/xml/quakeML/nodalPlanes.c | 114 + src/xml/quakeML/origin.c | 170 + src/xml/quakeML/principalAxes.c | 136 + src/xml/quakeML/tensor.c | 97 + src/xml/quakeML/time.c | 78 + src/xml/quakeML/units.c | 141 + src/xml/shakeAlert/Makefile | 63 + src/xml/shakeAlert/coreInfo.c | 512 +++ src/xml/shakeAlert/geometry.c | 79 + src/xml/shakeAlert/segment.c | 144 + src/xml/shakeAlert/slip.c | 261 ++ src/xml/shakeAlert/vertex.c | 237 ++ src/xml/shakeAlert/vertices.c | 213 + unit_tests/CMakeLists.txt | 9 + unit_tests/cmt.c | 480 +++ unit_tests/coord.c | 164 + unit_tests/ff.c | 683 ++++ unit_tests/files/final_cmt.maule.txt | 321 ++ unit_tests/files/final_ff.maule.txt | 74 + unit_tests/files/final_fp1.maule.txt | 51 + unit_tests/files/final_fp2.maule.txt | 51 + unit_tests/files/final_pgd.maule.txt | 221 ++ unit_tests/files/rtok.txt | 1201 ++++++ unit_tests/files/rtok_dip0.txt | 1201 ++++++ unit_tests/files/treg.txt | 493 +++ unit_tests/files/xrs.txt | 201 + unit_tests/files/yrs.txt | 201 + unit_tests/files/zrs.txt | 201 + unit_tests/message.xml | 50 + unit_tests/mt.c | 509 +++ unit_tests/numpy.c | 187 + unit_tests/pgd.c | 256 ++ unit_tests/readCoreInfo.c | 95 + unit_tests/tests.c | 121 + 211 files changed, 45315 insertions(+) create mode 100644 Makefile create mode 100644 include/dmlibWrapper.h create mode 100644 include/gfast.h create mode 100644 include/gfast_activeMQ.h create mode 100644 include/gfast_config.h create mode 100644 include/gfast_core.h create mode 100644 include/gfast_eewUtils.h create mode 100644 include/gfast_enum.h create mode 100644 include/gfast_hdf5.h create mode 100644 include/gfast_struct.h create mode 100644 include/gfast_traceBuffer.h create mode 100644 include/gfast_xml.h create mode 100755 run/bin/run_gfast.sh create mode 100644 run/params/M99.txt create mode 120000 run/params/gfast.props create mode 100644 run/params/gfast.props.NOAA create mode 100644 run/params/gfast.props.SA create mode 100644 run/params/pgd_threshold_PW.txt create mode 100644 run/params/raw_sigma_threshold_PW.txt create mode 100644 src/Makefile create mode 100644 src/activeMQ/Makefile create mode 100644 src/activeMQ/ShakeAlertConsumer.cpp create mode 100644 src/activeMQ/ShakeAlertConsumer.h create mode 100644 src/activeMQ/ShakeAlertProducer.cpp create mode 100644 src/activeMQ/ShakeAlertProducer.h create mode 100644 src/activeMQ/activeMQ.c create mode 100644 src/activeMQ/activeMQ.cpp create mode 100644 src/activeMQ/consumer.cpp create mode 100644 src/activeMQ/producer.cpp create mode 100644 src/activeMQ/readIni.c create mode 100644 src/core/Makefile create mode 100644 src/core/cmt/Makefile create mode 100644 src/core/cmt/decomposeMomentTensor.c create mode 100644 src/core/cmt/depthGridSearch.c create mode 100644 src/core/cmt/finalize.c create mode 100644 src/core/cmt/gridSearch.c create mode 100644 src/core/cmt/initialize.c create mode 100644 src/core/cmt/readIni.c create mode 100644 src/core/cmt/setDiagonalWeightMatrix.c create mode 100644 src/core/cmt/setForwardModel.c create mode 100644 src/core/cmt/setRHS.c create mode 100644 src/core/cmt/weightForwardModel.c create mode 100644 src/core/cmt/weightObservations.c create mode 100644 src/core/coordtools/Makefile create mode 100644 src/core/coordtools/ll2utm.c create mode 100644 src/core/coordtools/utm2ll.c create mode 100644 src/core/data/Makefile create mode 100644 src/core/data/finalize.c create mode 100644 src/core/data/initialize.c create mode 100644 src/core/data/readMetaDataFile.c create mode 100644 src/core/data/readSiteMaskFile.c create mode 100644 src/core/events/Makefile create mode 100644 src/core/events/freeEvents.c create mode 100644 src/core/events/getMinOriginTime.c create mode 100644 src/core/events/newEvent.c create mode 100644 src/core/events/printEvent.c create mode 100644 src/core/events/removeCancelledEvent.c create mode 100644 src/core/events/removeExpiredEvent.c create mode 100644 src/core/events/removeExpiredEvents.c create mode 100644 src/core/events/syncXMLStatusWithEvents.c create mode 100644 src/core/events/updateEvent.c create mode 100644 src/core/ff/Makefile create mode 100644 src/core/ff/faultPlaneGridSearch.c create mode 100644 src/core/ff/finalize.c create mode 100644 src/core/ff/initialize.c create mode 100644 src/core/ff/meshFaultPlane.c create mode 100644 src/core/ff/readIni.c create mode 100644 src/core/ff/setDiagonalWeightMatrix.c create mode 100644 src/core/ff/setForwardModel.c create mode 100644 src/core/ff/setRHS.c create mode 100644 src/core/ff/setRegularizer.c create mode 100644 src/core/ff/weightForwardModel.c create mode 100644 src/core/ff/weightObservations.c create mode 100644 src/core/log/Makefile create mode 100644 src/core/log/log.c create mode 100644 src/core/log/log.cpp create mode 100644 src/core/properties/Makefile create mode 100644 src/core/properties/finalize.c create mode 100644 src/core/properties/initialize.c create mode 100644 src/core/properties/print.c create mode 100644 src/core/scaling/Makefile create mode 100644 src/core/scaling/pgd_depthGridSearch.c create mode 100644 src/core/scaling/pgd_finalize.c create mode 100644 src/core/scaling/pgd_gridSearch.c create mode 100644 src/core/scaling/pgd_initialize.c create mode 100644 src/core/scaling/pgd_readIni.c create mode 100644 src/core/scaling/pgd_sanityChecks.c create mode 100644 src/core/scaling/pgd_setDiagonalWeightMatrix.c create mode 100644 src/core/scaling/pgd_setForwardModel.c create mode 100644 src/core/scaling/pgd_setRHS.c create mode 100644 src/core/scaling/pgd_weightForwardModel.c create mode 100644 src/core/scaling/pgd_weightObservations.c create mode 100644 src/core/scaling/readPgdThresholdLookupFile.c create mode 100644 src/core/scaling/readRawSigmaThresholdLookupFile.c create mode 100644 src/core/scaling/readSigmaLookupFile.c create mode 100644 src/core/waveformProcessor/Makefile create mode 100644 src/core/waveformProcessor/offset.c create mode 100644 src/core/waveformProcessor/peakDisplacement.c create mode 100644 src/core/waveformProcessor/peakDisplacementHelper.c create mode 100644 src/dmlib/Makefile create mode 100644 src/dmlib/dmlibWrapper.cpp create mode 100644 src/doxygen.conf create mode 100644 src/eewUtils/Makefile create mode 100644 src/eewUtils/driveCMT.c create mode 100644 src/eewUtils/driveFF.c create mode 100644 src/eewUtils/driveGFAST.c create mode 100644 src/eewUtils/drivePGD.c create mode 100644 src/eewUtils/makeXML.c create mode 100644 src/eewUtils/parseCoreXML.c create mode 100644 src/eewUtils/setLogFileNames.c create mode 100644 src/gfast_eew.c create mode 100644 src/gfast_playback.c create mode 100644 src/hdf5/Makefile create mode 100644 src/hdf5/copy.c create mode 100644 src/hdf5/createType.c create mode 100644 src/hdf5/getMaxGroupNumber.c create mode 100644 src/hdf5/h5_cinter.c create mode 100644 src/hdf5/initialize.c create mode 100644 src/hdf5/memory.c create mode 100644 src/hdf5/setFileName.c create mode 100644 src/hdf5/update.c create mode 100644 src/tests/CoreActiveMqUT.cc create mode 100644 src/tests/CoreCoordtoolsUT.cc create mode 100644 src/tests/CoreDataUT.cc create mode 100644 src/tests/CoreEventsUT.cc create mode 100644 src/tests/CoreScalingUT.cc create mode 100644 src/tests/CoreWaveformProcessorUT.cc create mode 100644 src/tests/EewUtilsUT.cc create mode 100644 src/tests/Makefile create mode 100644 src/tests/TraceBufferEwrrUT.cc create mode 100644 src/tests/data/M99.txt create mode 100644 src/tests/data/final_cmt.maule.txt create mode 100644 src/tests/data/final_ff.maule.txt create mode 100644 src/tests/data/final_pgd.maule.txt create mode 100644 src/tests/data/gfast.props create mode 100644 src/tests/data/merged_chanfile_coord.dat create mode 100644 src/tests/data/pgd_threshold_PW.txt create mode 100644 src/tests/data/raw_sigma_threshold_PW.txt create mode 100644 src/tests/data/sa_message.xml create mode 100644 src/tests/gfast_ut_utils.h create mode 100644 src/traceBuffer/Makefile create mode 100644 src/traceBuffer/ewrr/Makefile create mode 100644 src/traceBuffer/ewrr/classifyRetval.c create mode 100644 src/traceBuffer/ewrr/finalize.c create mode 100644 src/traceBuffer/ewrr/flushRing.c create mode 100644 src/traceBuffer/ewrr/freetb2Data.c create mode 100644 src/traceBuffer/ewrr/freetb2Trace.c create mode 100644 src/traceBuffer/ewrr/getMessagesFromRing.c create mode 100644 src/traceBuffer/ewrr/initialize.c create mode 100644 src/traceBuffer/ewrr/settb2Data.c create mode 100644 src/traceBuffer/ewrr/settb2DataFromGFAST.c create mode 100644 src/traceBuffer/ewrr/tb2_hash.c create mode 100644 src/traceBuffer/ewrr/unpackTraceBuf2Messages.c create mode 100644 src/traceBuffer/h5/Makefile create mode 100644 src/traceBuffer/h5/copyTraceBufferToGFAST.c create mode 100644 src/traceBuffer/h5/finalize.c create mode 100644 src/traceBuffer/h5/getData.c create mode 100644 src/traceBuffer/h5/getDoubleArray.c create mode 100644 src/traceBuffer/h5/getScalars.c create mode 100644 src/traceBuffer/h5/initialize.c create mode 100644 src/traceBuffer/h5/readData.c create mode 100644 src/traceBuffer/h5/setData.c create mode 100644 src/traceBuffer/h5/setFileName.c create mode 100644 src/traceBuffer/h5/setScalars.c create mode 100644 src/traceBuffer/h5/setTraceBufferFromGFAST.c create mode 100644 src/uw/beachball.c create mode 100644 src/uw/beachball.h create mode 100644 src/uw/gfast2web.c create mode 100644 src/xml/Makefile create mode 100644 src/xml/quakeML/Makefile create mode 100644 src/xml/quakeML/depth.c create mode 100644 src/xml/quakeML/epoch2string.c create mode 100644 src/xml/quakeML/focalMechanism.c create mode 100644 src/xml/quakeML/latitude.c create mode 100644 src/xml/quakeML/longitude.c create mode 100644 src/xml/quakeML/magnitude.c create mode 100644 src/xml/quakeML/momentTensor.c create mode 100644 src/xml/quakeML/nodalPlanes.c create mode 100644 src/xml/quakeML/origin.c create mode 100644 src/xml/quakeML/principalAxes.c create mode 100644 src/xml/quakeML/tensor.c create mode 100644 src/xml/quakeML/time.c create mode 100644 src/xml/quakeML/units.c create mode 100644 src/xml/shakeAlert/Makefile create mode 100644 src/xml/shakeAlert/coreInfo.c create mode 100644 src/xml/shakeAlert/geometry.c create mode 100644 src/xml/shakeAlert/segment.c create mode 100644 src/xml/shakeAlert/slip.c create mode 100644 src/xml/shakeAlert/vertex.c create mode 100644 src/xml/shakeAlert/vertices.c create mode 100644 unit_tests/CMakeLists.txt create mode 100644 unit_tests/cmt.c create mode 100644 unit_tests/coord.c create mode 100644 unit_tests/ff.c create mode 100644 unit_tests/files/final_cmt.maule.txt create mode 100644 unit_tests/files/final_ff.maule.txt create mode 100644 unit_tests/files/final_fp1.maule.txt create mode 100644 unit_tests/files/final_fp2.maule.txt create mode 100644 unit_tests/files/final_pgd.maule.txt create mode 100644 unit_tests/files/rtok.txt create mode 100644 unit_tests/files/rtok_dip0.txt create mode 100644 unit_tests/files/treg.txt create mode 100644 unit_tests/files/xrs.txt create mode 100644 unit_tests/files/yrs.txt create mode 100644 unit_tests/files/zrs.txt create mode 100644 unit_tests/message.xml create mode 100644 unit_tests/mt.c create mode 100644 unit_tests/numpy.c create mode 100644 unit_tests/pgd.c create mode 100644 unit_tests/readCoreInfo.c create mode 100644 unit_tests/tests.c diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..3f0a2a45 --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ +# Toplevel Makefile for GFAST + +SUBDIRS=src + +.PHONY: all show-targets $(SUBDIRS) +show-targets: + @echo TARGETS: $(TARGET_LIST) +TARGET_LIST=show-targets + +all: $(SUBDIRS) + +# define macro to generate rules for target, list of sub targets and rule for each. +define gen_recursive_targets +.PHONY: $(1) $(2:%=$(1)-%) +$(1): $(2:%=$(1)-%) +$(2:%=$(1)-%): + $(MAKE) -C $$(@:$$$(1)-%=%) $1 + @echo -e "" +TARGET_LIST+= $(1) $(2:%=$(1)-%) +endef + +# use macro to define recursive targets +$(eval $(call gen_recursive_targets, all, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, ids, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, rm-ids, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, clean, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, depend, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, veryclean, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, ut, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, test, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, docs, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, cleancoverage, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, buildcoverage, $(SUBDIRS))) +$(eval $(call gen_recursive_targets, runcoverage, $(SUBDIRS))) + +ut: # no-op + +test: # no-op + +# test report +GTEST_OUTPUT_DIR = ../utsummary/gfast +allreports testreport: export DO_GTEST_OUTPUT = 1 +allreports: cleantestreport coverage +testreport: cleantestreport test + +cleantestreport: + -rm -rf $(GTEST_OUTPUT_DIR) + +# coverage +INFODIR = ../coverage/info +COVDIR = ../coverage/html + +covdirs: + if [ ! -d "$(COVDIR)" ]; then mkdir -p $(COVDIR); fi + if [ ! -d "$(INFODIR)" ]; then mkdir -p $(INFODIR); fi + +coverage: cleancoverage covdirs buildcoverage runcoverage + genhtml $(INFODIR)/*.info -o $(COVDIR) -s --legend + +cleancoverage: + -rm -rf $(COVDIR) + +printvars: + @echo SUBDIRS=$(SUBDIRS) diff --git a/include/dmlibWrapper.h b/include/dmlibWrapper.h new file mode 100644 index 00000000..35eb82f8 --- /dev/null +++ b/include/dmlibWrapper.h @@ -0,0 +1,133 @@ +#ifndef _dmlibWrapper_h +#define _dmlibWrapper_h + +#include "gfast_struct.h" + +/*! + * @file dmlibWrapper.h + * @brief variables and functions to expose dmlib functionality to GFAST c code + */ + +#ifdef __cplusplus +extern "C" { +#endif /*ifdef __cplusplus*/ + + /*! + @brief Start connection to activemq instance + @param[in] AMQuser Authenticating username. + @param[in] AMQpassword Authenticating password. + @param[in] destinationURL URL of host computer (e.g. tcp://localhost:61616). + @param[in] msReconnect Number of milliseconds to wait for a reconnect + attempt. If 0 or if maxAttempts is 0 then this + command will be ignored. + @param[in] maxAttempts Number of attempts to connect before giving up. + If 0 this command will be ignored. + @param[in] verbose logging verbosity. default=1 + @return 1 if success, 0 if already connected and -1 for error + Points new connection to static amqconnection pointer or sets pointer to NULL + if unsuccessful. + */ + int startDestinationConnection(const char AMQuser[], + const char AMQpassword[], + const char destinationURL[], + const int msReconnect, + const int maxAttempts, + const int verbose); + /*! + @brief stops active activemq connection + Stops and destroys connection and sets amqconnection pointer to NULL + @return 1 if success, 0 if not connected and -1 for error + */ + int stopDestinationConnection(); + /*! + @brief tests if connection is started + @return true if connected, false if not + */ + bool isDestinationConnected(); + + int startEventReceiver(const char originURL[], + const char user[], + const char password[], + const char originTopic[], + const int msReconnect, + const int maxAttempts); + char *eventReceiverGetMessage(const int ms_wait, int *ierr); + int stopEventReceiver(); + + /*! + @brief instantiates and starts new DMMessageSender for events. + @return 1 if success, 0 if already connected and -1 for error + */ + int startEventSender(const char topic[]); + /*! + @brief stops active DMMessageSender for events. + Stops and destroys DMMessageSender object. + @return 1 if success, 0 if not initialized and -1 for error + */ + int stopEventSender(); + + /*! + @brief sends static event message + @return 1 if success, 0 if not initialized and -1 for error + */ + int sendEventMessage(); + + /*! + @brief sends event message as preformatted xml + @param xmlstr preformatted xml message to send to ShakeAlert + @return 1 if success, 0 if not initialized and -1 for error (todo. currently dummy) + */ + int sendEventXML(const char xmlstr[]); + + /*! + @brief start heartbeat producer + Points new HBProducer to static hbproducer pointer or sets pointer to NULL + if unsuccessful. + @param[in] sender identifier string for sending instance + @param[in] hbtopic target topic for heartbeats + @param[in] interval heartbeat interval in seconds (0=manual heartbeats) + @param[in] verbose logging verbosity. default=1 + @return 1 if success, 0 if already initialized and -1 for error + */ + int startHBProducer(const char sender[], const char hbtopic[], int interval, int verbose); + /*! + @brief stops active HBProducer + Stops and destroys HBProducer object and sets amqconnection pointer to NULL + @return 1 if success, 0 if not initialized and -1 for error + */ + int stopHBProducer(); + /*! + @brief sends heartbeat message + @return 1 if success, 0 if not initialized and -1 for error + */ + int sendHeartbeat(); + + /*! + @brief create xml message from coreEvent_info and GFAST_peakDisplacementData_struct + @param[in] mode Live or test mode + @param[in] alg_vers Version of GFAST + @param[in] instance Instance running the code + @param[in] message_type Describes a new or updated message + @param[in] max_assoc_stations Max # of stations with the 'assoc=True' attribute for + SA station association + @param[in] core CoreEventInfo to go into message + @param[in] pgd Contains information on if a site was used for pgd + @param[in] pgd_obs PGD observations to go into gm_info + @param[out] ierr 0 for success, -1 for error + @return returns a ShakeAlert xml message + */ + char *dmlibWrapper_createPGDXML(const enum opmode_type mode, + const char *alg_vers, + const char *instance, + const char *message_type, + const int max_assoc_stations, + const struct coreInfo_struct *core, + const struct GFAST_pgdResults_struct *pgd, + const struct GFAST_peakDisplacementData_struct *pgd_obs, + int *ierr); + +#ifdef __cplusplus +} /*end of extern "C"*/ +#endif + +#endif /*_dmlibWrapper_h*/ diff --git a/include/gfast.h b/include/gfast.h new file mode 100644 index 00000000..73cdeb65 --- /dev/null +++ b/include/gfast.h @@ -0,0 +1,55 @@ +#ifndef _gfast__h_ +#define _gfast__h_ 1 +#include +#include "gfast_config.h" +#ifdef GFAST_USE_AMQ +#include "gfast_activeMQ.h" +#endif +#include "gfast_core.h" +#include "gfast_eewUtils.h" +#include "gfast_enum.h" +#include "gfast_hdf5.h" +#include "gfast_struct.h" +#include "gfast_traceBuffer.h" +#include "gfast_xml.h" + +#ifdef __cplusplus +extern "C" +{ +#endif +/* Buffer initialization */ +int GFAST_buffer__getNumberOfStreams(struct GFAST_props_struct props); +int GFAST_buffer__setBufferSpace(struct GFAST_props_struct props, + struct GFAST_data_struct *gps_data); +int GFAST_buffer__setSitesAndLocations(struct GFAST_props_struct props, + struct GFAST_data_struct *gps_data); +int GFAST_buffer__setSiteSamplingPeriod(struct GFAST_props_struct props, + struct GFAST_data_struct *gps_data); +int GFAST_buffer__readDataFromSAC(int job, + struct GFAST_props_struct props, + struct GFAST_data_struct *gps_data); +void GFAST_buffer_print__samplingPeriod(struct GFAST_data_struct gps_data); +void GFAST_buffer_print__locations(struct GFAST_data_struct gps_data); +void GFAST_buffer__setInitialTime(double epoch0, + struct GFAST_data_struct *gps_data); +/* Frees memory on pointers and data structures */ +void GFAST_memory_freeWaveformData(struct GFAST_waveform3CData_struct *data); +void GFAST_memory_freeData(struct GFAST_data_struct *gps_data); +void GFAST_memory_freeProps(struct GFAST_props_struct *props); +void GFAST_memory_freeEvents(struct GFAST_activeEvents_struct *events); +void GFAST_memory_freePGDResults(struct GFAST_pgdResults_struct *pgd); +void GFAST_memory_freeCMTResults(struct GFAST_cmtResults_struct *cmt); +void GFAST_memory_freeFaultPlane(struct GFAST_faultPlane_struct *fp); +void GFAST_memory_freeFFResults(struct GFAST_ffResults_struct *ff); +void GFAST_memory_freePGDData( + struct GFAST_peakDisplacementData_struct *pgd_data); +void GFAST_memory_freeOffsetData(struct GFAST_offsetData_struct *offset_data); +/* Initializes the GFAST parameters */ +int GFAST_properties_initialize(const char *propfilename, + const enum opmode_type opmode, + struct GFAST_props_struct *props); +void GFAST_properties_print(struct GFAST_props_struct props); +#ifdef __cplusplus +} +#endif +#endif /* #ifndef _gfast__h_ */ diff --git a/include/gfast_activeMQ.h b/include/gfast_activeMQ.h new file mode 100644 index 00000000..953f58f3 --- /dev/null +++ b/include/gfast_activeMQ.h @@ -0,0 +1,88 @@ +#ifndef gfast_activemq_h +#define gfast_activemq_h 1 +#include "gfast_struct.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /*ifdef __cplusplus*/ + +/* Helps C start and stop the ActiveMQ library */ +void activeMQ_start(void); +void activeMQ_stop(void); +/* Private stuff - really not for general use */ +void activeMQ_setInit(void); +void activeMQ_setUninit(void); +bool activeMQ_isInit(void); + +/* Initialize and finalize activeMQ library */ +void activeMQ_initialize(void); +void activeMQ_finalize(void); + +/* Read parmaeters from the ini file */ +int activeMQ_readIni(const char *propfilename, + const char *group, + struct GFAST_activeMQ_struct *activeMQ_props); + +/* Initialize activeMQ parameters */ +void *activeMQ_consumer_initialize(const char AMQuser[], + const char AMQpassword[], + const char AMQurl[], + const char AMQdestination[], + const int msReconnect, + const int maxAttempts, + const bool useTopic, + const bool clientAck, + const bool luseListener, + const unsigned int maxMessages, + const int verbose, + int *ierr); +/* Get a message from activeMQ */ +char *activeMQ_consumer_getMessage(void *consumer, + const int ms_wait, int *ierr); +/* Get a message from activeMQ listener */ +char *activeMQ_consumer_getMessageFromListener(void *consumer, + int *ierr); +/* Shut down activeMQ consumer */ +void activeMQ_consumer_finalize(void *consumerIn); +/* Shut down activeMQ producer */ +void activeMQ_producer_finalize(void *producerIn); +/* Send a text message */ +int activeMQ_producer_sendMessage(void *producerIn, + const char *message); +/* Convenience function to set the tcp URI request */ +char *activeMQ_setTcpURIRequest(const char *url, + const int msReconnect, + const int maxAttempts); +/* Initialize the ActiveMQ producer */ +void *activeMQ_producer_initialize(const char AMQuser[], + const char AMQpassword[], + const char AMQurl[], + const char AMQdestination[], + const bool useTopic, + const bool clientAck, + const int verbose, + int *ierr); + + +#ifndef __cplusplus +#define GFAST_activeMQ_consumer_initialize(...) \ + activeMQ_consumer_initialize(__VA_ARGS__) +#define GFAST_activeMQ_consumer_getMessage(...) \ + activeMQ_consumer_getMessage(__VA_ARGS__) +#define GFAST_activeMQ_consumer_finalize(...) \ + activeMQ_consumer_finalize(__VA_ARGS__) +#define GFAST_activeMQ_producer_finalize(...) \ + activeMQ_producer_finalize(__VA_ARGS__) +#define GFAST_activeMQ_producer_sendMessage(...) \ + activeMQ_producer_sendMessage(__VA_ARGS__) + +#define GFAST_activeMQ_setTcpURIRequest(...) \ + activeMQ_setTcpURIRequest(__VA_ARGS__) +#endif /*ifndef __cplusplus*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _gfast_activemq_h__ */ diff --git a/include/gfast_config.h b/include/gfast_config.h new file mode 100644 index 00000000..e8e0eac7 --- /dev/null +++ b/include/gfast_config.h @@ -0,0 +1,8 @@ +#ifndef _gfast_config__h_ +#define _gfast_config__h_ 1 +#define GFAST_VERSION "gfast-1.2.1-2022-11-28" +#define GFAST_MAXMSG_LEN 4096 +#define MAX_OUTPUT_INTERVALS 16 +#define MAX_THROTTLING_THRESHOLDS 100 +#define MAX_SIGMA_LOOKUP_VALUES 100 +#endif diff --git a/include/gfast_core.h b/include/gfast_core.h new file mode 100644 index 00000000..0c24c841 --- /dev/null +++ b/include/gfast_core.h @@ -0,0 +1,714 @@ +#ifndef GFAST_CORE_H +#define GFAST_CORE_H 1 +#include +#include +#include +#include +#ifdef _OPENMP +#include +#endif +#include "gfast_struct.h" +#ifdef __cplusplus +extern "C" +{ +#endif + +//----------------------------------------------------------------------------// +// CMT // +//----------------------------------------------------------------------------// +/* Decompose a moment tensor */ +int core_cmt_decomposeMomentTensor(const int nmt, + const double *__restrict__ M, + double *__restrict__ DC_pct, + double *__restrict__ Mw, + double *__restrict__ strike1, + double *__restrict__ strike2, + double *__restrict__ dip1, + double *__restrict__ dip2, + double *__restrict__ rake1, + double *__restrict__ rake2); +/* CMT depth grid search */ +int core_cmt_depthGridSearch(const int l1, const int ndeps, + const int verbose, + const bool deviatoric, + const double utmSrcEasting, + const double utmSrcNorthing, + const double *__restrict__ srcDepths, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ nObsOffset, + const double *__restrict__ eObsOffset, + const double *__restrict__ uObsOffset, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + double *__restrict__ nEst, + double *__restrict__ eEst, + double *__restrict__ uEst, + double *__restrict__ mts); +/* Frees memory on the CMT structures */ +void core_cmt_finalizeResults(struct GFAST_cmtResults_struct *cmt); +void core_cmt_finalizeOffsetData(struct GFAST_offsetData_struct *offset_data); +void core_cmt_finalize(struct GFAST_cmt_props_struct *cmt_props, + struct GFAST_offsetData_struct *offset_data, + struct GFAST_cmtResults_struct *cmt); +/* Full grid search */ +int core_cmt_gridSearch(const int l1, + const int ndeps, const int nlats, const int nlons, + const int verbose, + const bool deviatoric, + const double *__restrict__ utmSrcEastings, + const double *__restrict__ utmSrcNorthings, + const double *__restrict__ srcDepths, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ nObsOffset, + const double *__restrict__ eObsOffset, + const double *__restrict__ uObsOffset, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + double *__restrict__ nEst, + double *__restrict__ eEst, + double *__restrict__ uEst, + double *__restrict__ mts); +/* Initialize CMT data structures */ +int core_cmt_initialize(struct GFAST_cmt_props_struct props, + struct GFAST_data_struct gps_data, + struct GFAST_cmtResults_struct *cmt, + struct GFAST_offsetData_struct *cmt_data); +/* Reads the initialization parameters from the ini file */ +int core_cmt_readIni(const char *propfilename, + const char *group, + const int verbose, const int utm_zone, + struct GFAST_cmt_props_struct *cmt_props); +/* Set diagonal weight matrix in CMT inversion */ +int core_cmt_setDiagonalWeightMatrix(const int n, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + double *__restrict__ diagWt); +/* Set forward model in CMT inversion */ +int core_cmt_setForwardModel(const int l1, const bool ldeviatoric, + const double *__restrict__ x1, + const double *__restrict__ y1, + const double *__restrict__ z1, + double *__restrict__ G); +/* Set RHS In CMT inversion */ +int core_cmt_setRHS(const int n, + const double *__restrict__ nOffset, + const double *__restrict__ eOffset, + const double *__restrict__ uOffset, + double *__restrict__ U); +/* Weight the forward model by the diagonal weight matrix */ +int core_cmt_weightForwardModel(const int mrows, const int ncols, + const double *__restrict__ diagWt, + const double *__restrict__ G, + double *__restrict__ diagWtG); +/* Weight the observations by the diagonal weight matrix */ +int core_cmt_weightObservations(const int mrows, + const double *__restrict__ diagWt, + const double *__restrict__ b, + double *__restrict__ diagWb); + +//----------------------------------------------------------------------------// +// coordtools // +//----------------------------------------------------------------------------// +/* Convert lat/lon to UTM */ +#ifdef _OPENMP +#pragma omp declare simd +#endif +void core_coordtools_ll2utm(const double lat_deg, const double lon_deg, + double *UTMNorthing, double *UTMEasting, + bool *lnorthp, int *zone); +/* Convert UTM to lat/lon */ +#ifdef _OPENMP +#pragma omp declare simd +#endif +void core_coordtools_utm2ll(const int zone, const bool lnorthp, + const double UTMNorthing, const double UTMEasting, + double *lat_deg, double *lon_deg); +//----------------------------------------------------------------------------// +// GFAST gps data streams // +//----------------------------------------------------------------------------// +/* Frees memory on the GPS data buffer */ +void core_data_finalize(struct GFAST_data_struct *gps_data); +/* Initializes the GPS metadata */ +int core_data_initialize(struct GFAST_props_struct props, + struct GFAST_data_struct *gps_data); +/* Reads the metadata file */ +int core_data_readMetaDataFile(const char *metaDataFile, + char **metaDataNetworks, + int n_networks, + struct GFAST_data_struct *gps_data); +/* Reads the site mask file */ +int core_data_readSiteMaskFile(const char *siteMaskFile, + const int verbose, + struct GFAST_data_struct *gps_data); + +//----------------------------------------------------------------------------// +// GFAST event handler // +//----------------------------------------------------------------------------// +/* Frees memory on an event structure */ +void core_events_freeEvents(struct GFAST_activeEvents_struct *events); +/* Convenience function to find min origin time in event list */ +double core_events_getMinOriginTime(struct GFAST_props_struct props, + struct GFAST_activeEvents_struct events, + bool *lnoEvents); +/* Adds a new event to the event list */ +bool core_events_newEvent(struct GFAST_shakeAlert_struct SA, + struct GFAST_activeEvents_struct *events, + struct GFAST_activeEvents_xml_status *xml_status); +bool core_events_syncXMLStatusWithEvents(struct GFAST_activeEvents_struct *events, + struct GFAST_activeEvents_xml_status *xml_status); + +/* Print the events in the event list */ +void core_events_printEvents(struct GFAST_shakeAlert_struct SA); +/* Remove a cancelled event from the events list */ +bool core_events_removeCancelledEvent(const char *evid, + const double currentTime, + const int verbose, + struct GFAST_shakeAlert_struct SA, + struct GFAST_activeEvents_struct *events); +/* Look through the events list and remove expired events */ +int core_events_removeExpiredEvents(const double maxTime, + const double currenTime, + const int verbose, + struct GFAST_activeEvents_struct *events); +/* Remove an expired event from the events list */ +bool core_events_removeExpiredEvent(const double maxtime, + const double currentTime, + const int verbose, + struct GFAST_shakeAlert_struct SA, + struct GFAST_activeEvents_struct *events); +/* Potentially add the shakeAlert event to the event list */ +bool core_events_updateEvent(struct GFAST_shakeAlert_struct SA, + struct GFAST_activeEvents_struct *events, + int *ierr); + + +//----------------------------------------------------------------------------// +// finite fault // +//----------------------------------------------------------------------------// +/* Gridsearch on fault planes */ +int core_ff_faultPlaneGridSearch(const int l1, const int l2, + const int nstr, const int ndip, + const int nfp, const int verbose, + const double *__restrict__ nObsOffset, + const double *__restrict__ eObsOffset, + const double *__restrict__ uObsOffset, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ fault_xutm, + const double *__restrict__ fault_yutm, + const double *__restrict__ fault_alt, + const double *__restrict__ length, + const double *__restrict__ width, + const double *__restrict__ strike, + const double *__restrict__ dip, + double *__restrict__ sslip, + double *__restrict__ dslip, + double *__restrict__ Mw, + double *__restrict__ vr, + double *__restrict__ NN, + double *__restrict__ EN, + double *__restrict__ UN, + double *__restrict__ sslip_unc, + double *__restrict__ dslip_unc + ); +/* Frees finite fault structures */ +void core_ff_finalizeFaultPlane(struct GFAST_faultPlane_struct *fp); +void core_ff_finalizeResults(struct GFAST_ffResults_struct *ff); +void core_ff_finalizeOffsetData(struct GFAST_offsetData_struct *offset_data); +void core_ff_finalize(struct GFAST_ff_props_struct *ff_props, + struct GFAST_offsetData_struct *ff_data, + struct GFAST_ffResults_struct *ff); +/* Initializes finite fault data structures */ +int core_ff_initialize(struct GFAST_ff_props_struct props, + struct GFAST_data_struct gps_data, + struct GFAST_ffResults_struct *ff, + struct GFAST_offsetData_struct *ff_data); +/* Meshes the fault plane */ +int core_ff_meshFaultPlane(const double ev_lat, + const double ev_lon, + const double ev_dep, + const double flen_pct, + const double fwid_pct, + const double M, + const double strikeF, const double dipF, + const int nstr, const int ndip, + const int utm_zone, const int verbose, + int *__restrict__ fault_ptr, + double *__restrict__ lat_vtx, + double *__restrict__ lon_vtx, + double *__restrict__ dep_vtx, + double *__restrict__ fault_xutm, + double *__restrict__ fault_yutm, + double *__restrict__ fault_alt, + double *__restrict__ strike, + double *__restrict__ dip, + double *__restrict__ length, + double *__restrict__ width); +/* Reads the finite fault parameters from the ini file */ +int core_ff_readIni(const char *propfilename, + const char *group, + const int verbose, const int utm_zone, + const int cmtMinSites, + struct GFAST_ff_props_struct *ff_props); +/* Set the diagonal data weight matrix */ +int core_ff_setDiagonalWeightMatrix(const int n, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + double *__restrict__ diagWt); +/* Set the (unregularized) forward modeling matrix */ +int core_ff_setForwardModel__okadagreenF(const int l1, const int l2, + const double *__restrict__ e, + const double *__restrict__ n, + const double *__restrict__ depth, + const double *__restrict__ strike, + const double *__restrict__ dip, + const double *__restrict__ W, + const double *__restrict__ L, + double *__restrict__ G); +/* Set the regularization matrix for the finite fault inversion */ +int core_ff_setRegularizer(const int l2, const int nstr, + const int ndip, const int nt, + const double *__restrict__ width, + const double *__restrict__ length, + double *__restrict__ T); +/* Set the RHS */ +int core_ff_setRHS(const int n, + const double *__restrict__ nOffset, + const double *__restrict__ eOffset, + const double *__restrict__ uOffset, + double *__restrict__ U); +/* Weight the forward modeling matrix */ +int core_ff_weightForwardModel(const int mrows, const int ncols, + const double *__restrict__ diagWt, + const double *__restrict__ G, + double *__restrict__ diagWtG); +/* Weight the observations */ +int core_ff_weightObservations(const int mrows, + const double *__restrict__ diagWt, + const double *__restrict__ b, + double *__restrict__ diagWb); + +//----------------------------------------------------------------------------// +// Logging // +//----------------------------------------------------------------------------// + +void init_plog(); +void core_log_plog_V(const char *msg); +void core_log_plog_D(const char *msg); +void core_log_plog_I(const char *msg); +void core_log_plog_W(const char *msg); +void core_log_plog_E(const char *msg); +void core_log_plog_F(const char *msg); +void core_log_plog_N(const char *msg); + +#ifndef ERRMSG +#define ERRMSG(msg, fmt, ...) \ +{ \ + memset(msg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + sprintf(msg, "[ERROR]: (%s:%s:line=%d) ", __FILE__, __func__, __LINE__ ); \ + do \ + { \ + snprintf(&msg[strlen(msg)], GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + } while(0) \ +}; +#endif + +#ifndef LOG_ERRMSG +#define LOG_ERRMSG(fmt, ...) \ +{ \ + char errmsg[GFAST_MAXMSG_LEN]; \ + memset(errmsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + snprintf(errmsg, GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + core_log_plog_E(errmsg); \ +}; +#endif + +#ifndef LOG_WARNMSG +#define LOG_WARNMSG(fmt, ...) \ +{ \ + char warnmsg[GFAST_MAXMSG_LEN]; \ + memset(warnmsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + snprintf(warnmsg, GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + core_log_plog_W(warnmsg); \ +}; +#endif + +#ifndef LOG_INFOMSG +#define LOG_INFOMSG(fmt, ...) \ +{ \ + char infoMsg[GFAST_MAXMSG_LEN]; \ + memset(infoMsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + snprintf(infoMsg, GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + core_log_plog_I(infoMsg); \ +}; +#endif + +#ifndef LOG_DEBUGMSG +#define LOG_DEBUGMSG(fmt, ...) \ +{ \ + char debugMsg[GFAST_MAXMSG_LEN]; \ + memset(debugMsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + snprintf(debugMsg, GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + core_log_plog_D(debugMsg); \ +}; +#endif + +#ifndef LOG_MSG +#define LOG_MSG(fmt, ...) \ +{ \ + char debugMsg[GFAST_MAXMSG_LEN]; \ + memset(debugMsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + snprintf(debugMsg, GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + core_log_plog_I(debugMsg); \ +}; +#endif + +int core_log_closeLogs(void); +int core_log_closeErrorLog(void); +int core_log_closeInfoLog(void); +int core_log_closeWarningLog(void); +int core_log_closeDebugLog(void); +int core_log_closeLog(void); + +int core_log_createErrorLog(const char *fileName); +int core_log_closeLogs(void); +int core_log_closeErrorLog(void); +int core_log_closeInfoLog(void); +int core_log_closeWarningLog(void); +int core_log_closeDebugLog(void); +int core_log_closeLog(void); + +int core_log_createErrorLog(const char *fileName); +int core_log_createInfoLog(const char *fileName); +int core_log_createWarningLog(const char *fileName); +int core_log_createDebugLog(const char *fileName); +int core_log_createLog(const char *fileName); + +int core_log_openErrorLog(const char *fileName); +int core_log_openInfoLog(const char *fileName); +int core_log_openWarningLog(const char *fileName); +int core_log_openDebugLog(const char *fileName); +int core_log_openLog(const char *fileName); + +void core_log_logErrorMessage(const char *msg); +void core_log_logWarningMessage(const char *msg); +void core_log_logDebugMessage(const char *msg); +void core_log_logInfoMessage(const char *msg); +void core_log_logMessage(const char *msg); +//----------------------------------------------------------------------------// +// Properties/initialization // +//----------------------------------------------------------------------------// +/* Finalize/free properties */ +void core_properties_finalizePGDProperties( + struct GFAST_pgd_props_struct *pgd_props); +void core_properties_finalizeCMTProperties( + struct GFAST_cmt_props_struct *cmt_props); +void core_properties_finalizeFFProperties( + struct GFAST_ff_props_struct *ff_props); +void core_properties_finalizeActiveMQProperties( + struct GFAST_activeMQ_struct *activeMQ_props); +void core_properties_finalize(struct GFAST_props_struct *props); +/* Initialize the properties from an ini file */ +int core_properties_initialize(const char *propfilename, + const enum opmode_type opmode, + struct GFAST_props_struct *props); +/* Print the properties */ +void core_properties_print(struct GFAST_props_struct props); + +//----------------------------------------------------------------------------// +// PGD scaling // +//----------------------------------------------------------------------------// + +/* Depth grid search in PGD scaling */ +int core_scaling_pgd_depthGridSearch(const int l1, const int ndeps, + const int verbose, + const double dist_tol, + const double disp_def, + const double utmSrcEasting, + const double utmSrcNorthing, + const double *__restrict__ srcDepths, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ d, + const double *__restrict__ wts, + double *__restrict__ srdist, + double *__restrict__ M, + double *__restrict__ VR, + double *__restrict__ iqt75_25, + double *__restrict__ Uest); +/* Finalize the PGD data structures */ +void core_scaling_pgd_finalizeData( + struct GFAST_peakDisplacementData_struct *pgd_data); +void core_scaling_pgd_finalizeResults( + struct GFAST_pgdResults_struct *pgd); +void core_scaling_pgd_finalize( + struct GFAST_pgd_props_struct *pgd_props, + struct GFAST_peakDisplacementData_struct *pgd_data, + struct GFAST_pgdResults_struct *pgd); +/* Initialize PGD scaling data structures */ +int core_scaling_pgd_initialize(struct GFAST_pgd_props_struct pgd_props, + struct GFAST_data_struct gps_data, + struct GFAST_pgdResults_struct *pgd, + struct GFAST_peakDisplacementData_struct *pgd_data); +/* Drives full grid search */ +int core_scaling_pgd_gridSearch(const int l1, const int ndeps, + const int nlats, const int nlons, + const int verbose, + const double dist_tol, + const double disp_def, + const double *__restrict__ utmSrcEastings, + const double *__restrict__ utmSrcNorthings, + const double *__restrict__ srcDepths, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ d, + const double *__restrict__ wts, + double *__restrict__ srdist, + double *__restrict__ M, + double *__restrict__ VR, + double *__restrict__ iqr, + double *__restrict__ Uest); +/* Read ini file for PGD properties */ +int core_scaling_pgd_readIni(const char *propfilename, + const char *group, + const int verbose, const int utm_zone, + struct GFAST_pgd_props_struct *pgd_props); +/* Set the diagonal data weighting matrix */ +int core_scaling_pgd_setDiagonalWeightMatrix(const int l1, + const double *__restrict__ repi, + const double *__restrict__ wts, + double *__restrict__ W); +/* Set the forward modeling matrix */ +int core_scaling_pgd_setForwardModel(const int n, + const double B, const double C, + const double *__restrict__ r, + double *__restrict__ G); +/* Set the RHS */ +int core_scaling_pgd_setRHS(const int n, + const double dist_tol, + const double dist_def, + const double A, + const double *__restrict__ d, + double *__restrict__ b); + +/* MTH: Check dist/amp */ +int core_scaling_pgd_sanityChecks(const int n, + const double dist_tol, + const double dist_def, + const double *__restrict__ repi, + const double *__restrict__ d); + +/* Weight the PGD forward modeling operator */ +int core_scaling_pgd_weightForwardModel(const int l1, + const double *__restrict__ W, + const double *__restrict__ G, + double *__restrict__ WG); +/* Weight the PGD RHS */ +int core_scaling_pgd_weightObservations(const int l1, + const double *__restrict__ W, + const double *__restrict__ b, + double *__restrict__ Wb); +/* Reads the sigma-time-magnitude lookup table */ +int core_scaling_readSigmaLookupFile(const char *sigmaLookupFile, + struct GFAST_pgd_props_struct *pgd_props); +/* Reads the pgd thresholds */ +int core_scaling_readPgdThresholdLookupFile(const char *pgdThresholdLookupFile, + struct GFAST_pgd_props_struct *pgd_props); +/* Reads the raw sigma threshold file */ +int core_scaling_readRawSigmaThresholdLookupFile(const char *rawSigmaThresholdLookupFile, + struct GFAST_pgd_props_struct *pgd_props); + +//----------------------------------------------------------------------------// +// Waveform processor // +//----------------------------------------------------------------------------// +/* Compute the offset in north, east, and up */ +int core_waveformProcessor_offset(const int utm_zone, + const double svel_window, + const double ev_lat, + const double ev_lon, + const double ev_dep, + const double ev_time, + struct GFAST_data_struct gps_data, + struct GFAST_offsetData_struct *offset_data, + int *ierr); +/* Compute the peak displacement from gps_data*/ +int core_waveformProcessor_peakDisplacement( + const struct GFAST_pgd_props_struct *pgd_props, + const double ev_lat, + const double ev_lon, + const double ev_dep, + const double ev_time, + struct GFAST_data_struct gps_data, + struct GFAST_peakDisplacementData_struct *pgd_data, + int *ierr); +/* Compute the peak displacement from buffers. Called by peakDisplacement */ +double core_waveformProcessor_peakDisplacementHelper( + const int npts, + const double dt, + const double ev_time, + const double epoch, + const double *__restrict__ ubuff, + const double *__restrict__ nbuff, + const double *__restrict__ ebuff, + const double *__restrict__ usigmabuff, + const double *__restrict__ nsigmabuff, + const double *__restrict__ esigmabuff, + const int nMaxLeader, + const double tmin, + const double tmax, + double *obsTime, + double *uMaxUncertainty, + double *nMaxUncertainty, + double *eMaxUncertainty); + +#define GFAST_core_cmt_decomposeMomentTensor(...) \ + core_cmt_decomposeMomentTensor(__VA_ARGS__) +#define GFAST_core_cmt_depthGridSearch(...) \ + core_cmt_depthGridSearch(__VA_ARGS__) +#define GFAST_core_cmt_finalizeResults(...) \ + core_cmt_finalizeResults(__VA_ARGS__) +#define GFAST_core_cmt_finalizeOffsetData(...) \ + core_cmt_finalizeOffsetData(__VA_ARGS__) +#define GFAST_core_cmt_finalize(...) \ + core_cmt_finalize(__VA_ARGS__) +#define GFAST_core_cmt_initialize(...) \ + core_cmt_initialize(__VA_ARGS__) +#define GFAST_core_cmt_setDiagonalWeightMatrix(...) \ + core_cmt_setDiagonalWeightMatrix(__VA_ARGS__) +#define GFAST_core_cmt_setForwardModel(...) \ + core_cmt_setForwardModel(__VA_ARGS__) +#define GFAST_core_cmt_setRHS(...) \ + core_cmt_setRHS(__VA_ARGS__) +#define GFAST_core_cmt_setForwardModel__deviatoric(...) \ + core_cmt_setForwardModel__deviatoric(__VA_ARGS__) +#define GFAST_core_cmt_setRHS(...) \ + core_cmt_setRHS(__VA_ARGS__) +#define GFAST_core_cmt_weightForwardModel(...) \ + core_cmt_weightForwardModel(__VA_ARGS__) +#define GFAST_core_cmt_weightObservations(...) \ + core_cmt_weightObservations(__VA_ARGS__) + +#define GFAST_core_coordtools_ll2utm(...) \ + core_coordtools_ll2utm(__VA_ARGS__) +#define GFAST_core_coordtools_utm2ll(...) \ + core_coordtools_utm2ll(__VA_ARGS__) + +#define GFAST_core_data_finalize(...) \ + core_data_finalize(__VA_ARGS__) +#define GFAST_core_data_initialize(...) \ + core_data_initialize(__VA_ARGS__) +#define GFAST_core_data_readMetaDataFile(...) \ + core_data_readMetaDataFile(__VA_ARGS__) +#define GFAST_core_data_readSiteMaskFile(...) \ + core_data_readSiteMaskFile(__VA_ARGS__) + +#define GFAST_core_events_freeEvents(...) \ + core_events_freeEvents(__VA_ARGS__) +#define GFAST_core_events_getMinOriginTime(...) \ + core_events_getMinOriginTime(__VA_ARGS__) +#define GFAST_core_events_newEvent(...) \ + core_events_newEvent(__VA_ARGS__) +#define GFAST_core_events_syncXMLStatusWithEvents(...) \ + core_events_syncXMLStatusWithEvents(__VA_ARGS__) + +#define GFAST_core_events_printEvents(...) \ + core_events_printEvents(__VA_ARGS__) +#define GFAST_core_events_removeCancelledEvent(...) \ + core_events_removeCancelledEvent(__VA_ARGS__) +#define GFAST_core_events_removeExpiredEvent(...) \ + core_events_removeExpiredEvent(__VA_ARGS__) +#define GFAST_core_events_updateEvent(...) \ + core_events_updateEvent(__VA_ARGS__) + +#define GFAST_core_ff_faultPlaneGridSearch(...) \ + core_ff_faultPlaneGridSearch(__VA_ARGS__) +#define GFAST_core_ff_finalizeResults(...) \ + core_ff_finalizeResults(__VA_ARGS__) +#define GFAST_core_ff_finalizeFaultPlane(...) \ + core_ff_finalizeFaultPlane(__VA_ARGS__) +#define GFAST_core_ff_finalizeOffsetData(...) \ + core_ff_finalizeOffsetData(__VA_ARGS__) +#define GFAST_core_ff_finalize(...) \ + core_ff_finalize(__VA_ARGS__) +#define GFAST_core_ff_initialize(...) \ + core_ff_initialize(__VA_ARGS__) +#define GFAST_core_scaling_pgd_finalize__props(...) \ + core_scaling_pgd_finalize__props(__VA_ARGS__) +#define GFAST_core_scaling_pgd_finalizeData(...) \ + core_scaling_pgd_finalizeData(__VA_ARGS__) +#define GFAST_core_scaling_pgd_finalizeResults(...) \ + core_scaling_pgd_finalizeResults(__VA_ARGS__) +#define GFAST_core_scaling_pgd_finalize(...) \ + core_scaling_pgd_finalize(__VA_ARGS__) +#define GFAST_core_ff_meshFaultPlane(...) \ + core_ff_meshFaultPlane(__VA_ARGS__) +#define GFAST_core_ff_setDiagonalWeightMatrix(...) \ + core_ff_setDiagonalWeightMatrix(__VA_ARGS__) +#define GFAST_core_ff_setForwardModel__okadagreenF(...) \ + core_ff_setForwardModel__okadagreenF(__VA_ARGS__) +#define GFAST_core_ff_setRegularizer(...) \ + core_ff_setRegularizer(__VA_ARGS__) +#define GFAST_core_ff_setRHS(...) \ + core_ff_setRHS(__VA_ARGS__) +#define GFAST_core_ff_weightForwardModel(...) \ + core_ff_weightForwardModel(__VA_ARGS__) +#define GFAST_core_ff_weightObservations(...) \ + core_ff_weightObservations(__VA_ARGS__) + +#define GFAST_core_properties_finalizePGDProperties(...) \ + core_properties_finalizePGDProperties(__VA_ARGS__) +#define GFAST_core_properties_finalizeCMTProperties(...) \ + core_properties_finalizeCMTProperties(__VA_ARGS__) +#define GFAST_core_properties_finalizeFFProperties(...) \ + core_properties_finalizeFFProperties(__VA_ARGS__) +#define GFAST_core_properties_finalizeActiveMQProperties(...) \ + core_properties_finalizeActiveMQProperties(__VA_ARGS__) +#define GFAST_core_properties_finalize(...) \ + core_properties_finalize(__VA_ARGS__) +#define GFAST_core_properties_initialize(...) \ + core_properties_initialize(__VA_ARGS__) +#define GFAST_core_properties_print(...) \ + core_properties_print(__VA_ARGS__) + +#define GFAST_core_scaling_pgd_depthGridSearch(...) \ + core_scaling_pgd_depthGridSearch(__VA_ARGS__) +#define GFAST_core_scaling_pgd_setDiagonalWeightMatrix(...) \ + core_scaling_pgd_setDiagonalWeightMatrix(__VA_ARGS__) +#define GFAST_core_scaling_pgd_initialize(...) \ + core_scaling_pgd_initialize(__VA_ARGS__) +#define GFAST_core_scaling_pgd_setForwardModel(...) \ + core_scaling_pgd_setForwardModel(__VA_ARGS__) +#define GFAST_core_scaling_pgd_setRHS(...) \ + core_scaling_pgd_setRHS(__VA_ARGS__) +#define GFAST_core_scaling_pgd_sanityChecks(...) \ + core_scaling_pgd_sanityChecks(__VA_ARGS__) +#define GFAST_core_scaling_pgd_weightForwardModel(...) \ + core_scaling_pgd_weightForwardModel(__VA_ARGS__) +#define GFAST_core_scaling_pgd_weightObservations(...) \ + core_scaling_pgd_weightObservations(__VA_ARGS__) + +#define GFAST_core_waveformProcessor_offset(...) \ + core_waveformProcessor_offset(__VA_ARGS__) +#define GFAST_core_waveformProcessor_peakDisplacement(...) \ + core_waveformProcessor_peakDisplacement(__VA_ARGS__) +#define GFAST_core_waveformProcessor_peakDisplacementHelper(...) \ + core_waveformProcessor_peakDisplacementHelper(__VA_ARGS__) + +#ifdef __cplusplus +} +#endif +#endif /* _gfast_core_h__ */ diff --git a/include/gfast_eewUtils.h b/include/gfast_eewUtils.h new file mode 100644 index 00000000..7eced1c4 --- /dev/null +++ b/include/gfast_eewUtils.h @@ -0,0 +1,118 @@ +#ifndef GFAST_EEWUTILS_H__ +#define GFAST_EEWUTILS_H__ 1 +#include "gfast_struct.h" +#include "gfast_traceBuffer.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SA_NAN -12345.0 /* NaN for shakeAlert event lat/lon/depth */ + +/* Drive the CMT computation */ +int eewUtils_driveCMT(struct GFAST_cmt_props_struct cmt_props, + const double SA_lat, + const double SA_lon, + const double SA_dep, + struct GFAST_offsetData_struct cmt_data, + struct GFAST_cmtResults_struct *cmt); +/* Drive the finite fault computation */ +int eewUtils_driveFF(struct GFAST_ff_props_struct ff_props, + const double SA_lat, + const double SA_lon, + struct GFAST_offsetData_struct ff_data, + struct GFAST_ffResults_struct *ff); +/* Drive GFAST */ +int eewUtils_driveGFAST(const double currentTime, + const char *program_instance, + struct GFAST_props_struct props, + struct GFAST_activeEvents_struct *events, + struct GFAST_data_struct *gps_data, + struct h5traceBuffer_struct *h5traceBuffer, + struct GFAST_peakDisplacementData_struct *pgd_data, + struct GFAST_offsetData_struct *cmt_data, + struct GFAST_offsetData_struct *ff_data, + struct GFAST_pgdResults_struct *pgd, + struct GFAST_cmtResults_struct *cmt, + struct GFAST_ffResults_struct *ff, + struct GFAST_xmlMessages_struct *xmlMessages, + struct GFAST_activeEvents_xml_status *xml_status); +/* Drive the PGD computation */ +int eewUtils_drivePGD(const struct GFAST_pgd_props_struct pgd_props, + const double SA_lat, + const double SA_lon, + const double SA_dep, + const double age_of_event, + struct GFAST_peakDisplacementData_struct pgd_data, + struct GFAST_pgdResults_struct *pgd); +/* Make finite fault XML for shakeAlert */ +char *eewUtils_makeXML__ff(const enum opmode_type mode, + const char *orig_sys, + const char *alg_vers, + const char *instance, + const char *message_type, + const char *version, + const struct coreInfo_struct *core, + const int nseg, + const int *fault_ptr, + const double *lat_vtx, + const double *lon_vtx, + const double *dep_vtx, + const double *strike, + const double *dip, + const double *ss, + const double *ds, + const double *ss_unc, + const double *ds_unc, + int *ierr); +/* Make the quakeML */ +char *eewUtils_makeXML__quakeML(const char *network, + const char *domain, + const char *evid, + const double evla, + const double evlo, + const double evdp, + const double t0, + const double mt[6], + int *ierr); +/* Make the PGD XML */ +char *eewUtils_makeXML__pgd(const enum opmode_type mode, + const char *orig_sys, + const char *alg_vers, + const char *instance, + const char *message_type, + const char *version, + const struct coreInfo_struct *core, + int *ierr); +/* Parses the core XML message */ +int eewUtils_parseCoreXML(const char *message, + const double saNaN, + struct GFAST_shakeAlert_struct *SA); +/* Make the EEW log file names */ +void eewUtils_setLogFileNames(const char *eventid, + const char *outputDir, + char errorLogFileName[PATH_MAX], + char infoLogFileName[PATH_MAX], + char debugLogFileName[PATH_MAX], + char warnLogFileName[PATH_MAX]); + +#define GFAST_eewUtils_driveCMT(...) \ + eewUtils_driveCMT(__VA_ARGS__) +#define GFAST_eewUtils_driveFF(...) \ + eewUtils_driveFF(__VA_ARGS__) +#define GFAST_eewUtils_driveGFAST(...) \ + eewUtils_driveGFAST(__VA_ARGS__) +#define GFAST_eewUtils_makeXML__ff(...) \ + eewUtils_makeXML__ff(__VA_ARGS__) +#define GFAST_eewUtils_makeXML__quakeML(...) \ + eewUtils_makeXML__quakeML(__VA_ARGS__) +#define GFAST_eewUtils_parseCoreXML(...) \ + eewUtils_parseCoreXML(__VA_ARGS__) +#define GFAST_eewUtils_setLogFileNames(...) \ + eewUtils_setLogFileNames(__VA_ARGS__) + +#ifdef __cplusplus +} +#endif +#endif /* __GFAST_EEWUTILS_H__ */ diff --git a/include/gfast_enum.h b/include/gfast_enum.h new file mode 100644 index 00000000..90c36dd0 --- /dev/null +++ b/include/gfast_enum.h @@ -0,0 +1,82 @@ +#ifndef GFAST_ENUM_H +#define GFAST_ENUM_H 1 + +enum dtinit_type +{ + INIT_DT_FROM_DEFAULT = 1, /*!< Sets GPS sampling period to default */ + INIT_DT_FROM_FILE = 2, /*!< Obtains GPS sampling period from file */ + INIT_DT_FROM_TRACEBUF = 3, /*!< Obtains GPS sampling period from + Earthworm tracebuf */ + INIT_DT_FROM_SAC = 4 /*!< Obtains GPS sampling period from + SAC file */ +}; + +enum locinit_type +{ + INIT_LOCS_FROM_FILE = 1, /*!< Sets the GPS site locations from + SOPAC SECTOR web service file */ + INIT_LOCS_FROM_TRACEBUF = 2, /*!< Sets the GPS site locations from + Earthworm tracbuf */ + INIT_LOCS_FROM_SAC = 3 /*!< Sets the GPS site locations from + SAC file */ +}; + +enum opmode_type +{ + REAL_TIME_EEW = 1, /*!< GFAST is running in real time mode for + earthquake early warning */ + //REAL_TIME_PTWC = 2, /*!< GFAST is running in real time mode for PTWC */ + //REAL_TIME_ATWC = 3, /*!< GFAST is running in real time mode for ATWC */ + PLAYBACK = 21, /*!< GFAST is running in historical playback mode */ + OFFLINE = 31 /*!< GFAST is running offline and obtaining data + and configuration purely from files */ +}; + +enum acquisition_type +{ + DATA_FROM_EARTHWORM = 1, /*!< GFAST will acquire data from earthworm */ + DATA_FROM_H5 = 2 /*!< GFAST will read data from disk */ +}; + +enum pgd_return_enum +{ + PGD_SUCCESS = 0, /*!< PGD computation was successful */ + PGD_STRUCT_ERROR = 1, /*!< PGD structure is invalid */ + PGD_PD_DATA_ERROR = 2, /*!< PGD data structure invalid */ + PGD_INSUFFICIENT_DATA = 3, /*!< Insufficient data to invert */ + PGD_COMPUTE_ERROR = 4 /*!< An internal error was encountered */ +}; + +enum cmt_return_enum +{ + CMT_SUCCESS = 0, /*!< CMT computation was successful */ + CMT_STRUCT_ERROR = 1, /*!< CMT structure is invalid */ + CMT_OS_DATA_ERROR = 2, /*!< CMT offset data structure invalid */ + CMT_INSUFFICIENT_DATA = 3, /*!< Insufficient data to invert */ + CMT_COMPUTE_ERROR = 4 /*!< An internal error was encountered */ +}; + +enum ff_return_enum +{ + FF_SUCCESS = 0, /*!< FF computation was successful */ + FF_STRUCT_ERROR = 1, /*!< FF structure is invalid */ + FF_OS_DATA_ERROR = 2, /*!< FF offset data structure is invalid */ + FF_INSUFFICIENT_DATA = 3, /*!< Insufficient data to invert */ + FF_COMPUTE_ERROR = 4, /*!< An internal error was encountered */ + FF_MEMORY_ERROR = 5 /*!< Error during memory allocation */ +}; + +enum alert_units_enum +{ + UNKNOWN_UNITS = 0, /*!< No units defined */ + DEGREES = 1, /*!< Distance/location - degrees */ + KILOMETERS = 2, /*!< Distance - kilometers */ + METERS = 3, /*!< Distance - meters */ + SECONDS = 4, /*!< Time - seconds */ + UTC = 5, /*!< Time - UTC */ + MOMENT_MAGNITUDE = 6, /*!< Moment magnitude Mw */ + DYNE_CENTIMETERS = 7, /*!< Torque - dyne centimeters */ + NEWTON_METERS= 8 /*!< Torque - Newton meters */ +}; + +#endif /* _gfast_enum__ */ diff --git a/include/gfast_hdf5.h b/include/gfast_hdf5.h new file mode 100644 index 00000000..15f5eda8 --- /dev/null +++ b/include/gfast_hdf5.h @@ -0,0 +1,401 @@ +#ifndef _gfast_hdf5_h__ +#define _gfast_hdf5_h__ 1 +#if defined WINNT || defined WIN32 || defined WIN64 +#include +#include +#else +#include +#endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_struct.h" +#include "gfast_enum.h" +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +enum data2h5_enum +{ + COPY_DATA_TO_H5 = 0, /*!< Copies data structure to HDF5 structure */ + COPY_H5_TO_DATA = 1, /*!< Copies HDF5 structure to data structure */ +}; + +struct h5_waveform3CData_struct +{ + hvl_t netw; + hvl_t stnm; + hvl_t chan; + hvl_t loc; + hvl_t ubuff; + hvl_t nbuff; + hvl_t ebuff; + hvl_t tbuff; + hvl_t gain; + double dt; + double sta_lat; + double sta_lon; + double sta_alt; + int maxpts; + int npts; + int lskip_pgd; + int lskip_cmt; + int lskip_ff; +}; + +struct h5_gpsData_struct +{ + hvl_t data; + int stream_length; +}; + +struct h5_peakDisplacementData_struct +{ + hvl_t stnm; + hvl_t pd; + hvl_t wt; + hvl_t sta_lat; + hvl_t sta_lon; + hvl_t sta_alt; + hvl_t lmask; + hvl_t lactive; + int nsites; +}; + +struct h5_pgdResults_struct +{ + hvl_t mpgd; + hvl_t mpgd_vr; + hvl_t dep_vr_pgd; + hvl_t UP; + hvl_t UPinp; + hvl_t srcDepths; + hvl_t srdist; + hvl_t iqr; + hvl_t lsiteUsed; + int ndeps; + int nsites; + int nlats; + int nlons; +}; + +struct h5_cmtResults_struct +{ + hvl_t l2; + hvl_t pct_dc; + hvl_t objfn; + hvl_t mts; + hvl_t str1; + hvl_t str2; + hvl_t dip1; + hvl_t dip2; + hvl_t rak1; + hvl_t rak2; + hvl_t Mw; + hvl_t srcDepths; + hvl_t EN; + hvl_t NN; + hvl_t UN; + hvl_t Einp; + hvl_t Ninp; + hvl_t Uinp; + hvl_t lsiteUsed; + int opt_indx; + int ndeps; + int nsites; + int nlats; + int nlons; +}; + +struct h5_offsetData_struct +{ + hvl_t stnm; + hvl_t ubuff; + hvl_t nbuff; + hvl_t ebuff; + hvl_t wtu; + hvl_t wtn; + hvl_t wte; + hvl_t sta_lat; + hvl_t sta_lon; + hvl_t sta_alt; + hvl_t lmask; + hvl_t lactive; + int nsites; +}; + +struct h5_faultPlane_struct +{ + hvl_t lon_vtx; + hvl_t lat_vtx; + hvl_t dep_vtx; + hvl_t fault_xutm; + hvl_t fault_yutm; + hvl_t fault_alt; + hvl_t strike; + hvl_t dip; + hvl_t length; + hvl_t width; + hvl_t sslip; + hvl_t dslip; + hvl_t sslip_unc; + hvl_t dslip_unc; + hvl_t EN; + hvl_t NN; + hvl_t UN; + hvl_t Einp; + hvl_t Ninp; + hvl_t Uinp; + hvl_t fault_ptr; + int maxobs; + int nsites_used; + int nstr; + int ndip; +}; + +struct h5_ffResults_struct +{ + hvl_t fp; + hvl_t vr; + hvl_t Mw; + hvl_t str; + hvl_t dip; + double SA_lat; + double SA_lon; + double SA_dep; + double SA_mag; + int preferred_fault_plane; + int nfp; +}; + +struct h5_hypocenter_struct +{ + char eventid[128]; /*!< Event ID */ + double lat; /*!< Event latitude (degrees) */ + double lon; /*!< Event longitude (degrees) */ + double dep; /*!< Event depth (kilometers) */ + double mag; /*!< Event magnitude */ + double time; /*!< Event epochal time (s) */ +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + +int hdf5_copyCMTResults(const enum data2h5_enum job, + struct GFAST_cmtResults_struct *cmt, + struct h5_cmtResults_struct *h5_cmt); +int hdf5_copyFaultPlane(const enum data2h5_enum job, + struct GFAST_faultPlane_struct *fp, + struct h5_faultPlane_struct *h5_fp); +int hdf5_copyFFResults(const enum data2h5_enum job, + struct GFAST_ffResults_struct *ff, + struct h5_ffResults_struct *h5_ff); +int hdf5_copyGPSData(const enum data2h5_enum job, + struct GFAST_data_struct *gps_data, + struct h5_gpsData_struct *h5_gpsData); +int hdf5_copyHypocenter(const enum data2h5_enum job, + struct GFAST_shakeAlert_struct *hypo, + struct h5_hypocenter_struct *h5_hypo); +int hdf5_copyOffsetData(const enum data2h5_enum job, + struct GFAST_offsetData_struct *offset_data, + struct h5_offsetData_struct *h5_offset_data); +int hdf5_copyPeakDisplacementData( + const enum data2h5_enum job, + struct GFAST_peakDisplacementData_struct *pgd_data, + struct h5_peakDisplacementData_struct *h5_pgd_data); +int hdf5_copyPGDResults(const enum data2h5_enum job, + struct GFAST_pgdResults_struct *pgd, + struct h5_pgdResults_struct *h5_pgd); +int hdf5_copyWaveform3CData(const enum data2h5_enum job, + struct GFAST_waveform3CData_struct *data, + struct h5_waveform3CData_struct *h5_data); + +herr_t hdf5_createType_cmtResults(hid_t group_id); +herr_t hdf5_createType_faultPlane(hid_t group_id); +herr_t hdf5_createType_ffResults(hid_t group_id); +herr_t hdf5_createType_gpsData(hid_t group_id); +herr_t hdf5_createType_hypocenter(hid_t group_id); +herr_t hdf5_createType_offsetData(hid_t group_id); +herr_t hdf5_createType_peakDisplacementData(hid_t group_id); +herr_t hdf5_createType_pgdResults(hid_t group_id); +herr_t hdf5_createType_waveform3CData(hid_t group_id); + +int hdf5_getMaxGroupNumber(const hid_t h5fl); + +int hdf5_initialize(const char *adir, + const char *evid, + const char *propfilename); + + +int hdf5_memory_freeCMTResults(struct h5_cmtResults_struct *cmt); +int hdf5_memory_freeFaultPlane(struct h5_faultPlane_struct *fp); +int hdf5_memory_freeFFResults(struct h5_ffResults_struct *ff); +int hdf5_memory_freeGPSData(struct h5_gpsData_struct *gpsData); +int hdf5_memory_freeOffsetData( + struct h5_offsetData_struct *h5_offset_data); +int hdf5_memory_freePGDData( + struct h5_peakDisplacementData_struct *h5_pgd_data); +int hdf5_memory_freePGDResults(struct h5_pgdResults_struct *pgd); +int hdf5_memory_freeWaveform3CData(struct h5_waveform3CData_struct *data); + +int hdf5_setFileName(const char *adir, + const char *evid, + char fname[PATH_MAX]); + +int hdf5_updateCMT(const char *adir, + const char *evid, + const int h5k, + struct GFAST_offsetData_struct cmt_data, + struct GFAST_cmtResults_struct cmt); +int hdf5_updateFF(const char *adir, + const char *evid, + const int h5k, + struct GFAST_ffResults_struct ff); +int hdf5_update_gpsData(const char *adir, + const char *evid, + const int h5k, + struct GFAST_data_struct data); +int hdf5_updateXMLMessage(const char *adir, + const char *evid, + const int h5k, + const char *messageName, char *message); +int hdf5_updateHypocenter(const char *adir, + const char *evid, + const int h5k, + struct GFAST_shakeAlert_struct hypo); +int hdf5_updateGetIteration(const char *adir, + const char *evid, + const double epoch); +int hdf5_updatePGD(const char *adir, + const char *evid, + const int h5k, + struct GFAST_peakDisplacementData_struct pgd_data, + struct GFAST_pgdResults_struct pgd); + + + +//----------------------------------------------------------------------------// +// hdf5 convenience functions // +//----------------------------------------------------------------------------// +hid_t h5_open_rdonly(const char *flname); +hid_t h5_open_rdwt(const char *flname); +int h5_close(const hid_t file_id); +int h5_write_array__float(const char *dset_name, const hid_t file_id, + const int n, const float *x); +int h5_write_array__double(const char *dset_name, const hid_t file_id, + const int n, const double *x); +int h5_write_array__int(const char *dset_name, const hid_t file_id, + const int n, const int *x); +int h5_write_array__chars(const char *citem_chr, const hid_t file_id, + const int n, char **c); +int h5_read_array__double(const char *dset_name, const hid_t file_id, + const int nref, double *x); +char **h5_read_array__string(const char *citem, const hid_t file_id, + int *nitems, int *ierr); +int h5_read_array__float(const char *dset_name, const hid_t file_id, + const int nref, float *x); +int h5_read_array__int(const char *dset_name, const hid_t file_id, + const int nref, int *x); +char **h5_read_array__char(const char *citem, const hid_t file_id, + int *nitems, int *ierr); +int h5_write_attribute__double(const char *citem, const hid_t hdf5_id, + const int n, const double *attr_data); +int h5_write_attribute__int(const char *citem, const hid_t hdf5_id, + const int n, const int *attr_data); +int h5_write_attribute__char(const char *citem, const hid_t hdf5_id, + const int n, const char **cattr); +int h5_n_group_members(const char *group_name, const hid_t file_id); +int h5_get_array_size(const hid_t file_id, const char *citem); +bool h5_item_exists(const hid_t file_id, const char *citem_in); +herr_t h5_create_group(const hid_t file_id, const char *cgroup); + +#define GFAST_hdf5_setFileName(...) \ + hdf5_setFileName(__VA_ARGS__) + +#define GFAST_hdf5_copyCMTResults(...) \ + hdf5_copyCMTResults(__VA_ARGS__) +#define GFAST_hdf5_copyFaultPlane(...) \ + hdf5_copyFaultPlane(__VA_ARGS__) +#define GFAST_hdf5_copyFFResults(...) \ + hdf5_copyFFResults(__VA_ARGS__) +#define GFAST_hdf5_copyGPSData(...) \ + hdf5_copyGPSData(__VA_ARGS__) +#define GFAST_hdf5_copyHypocenter(...) \ + hdf5_copyHypocenter(__VA_ARGS__) +#define GFAST_hdf5_copyOffsetData(...) \ + hdf5_copyOffsetData(__VA_ARGS__) +#define GFAST_hdf5_copyPeakDisplacementData(...) \ + hdf5_copyPeakDisplacementData(__VA_ARGS__) +#define GFAST_hdf5_copyPGDResults(...) \ + hdf5_copyPGDResults(__VA_ARGS__) +#define GFAST_hdf5_copyWaveform3CData(...) \ + hdf5_copyWaveform3CData(__VA_ARGS__) + +#define GFAST_hdf5_createType_cmtResults(...) \ + hdf5_createType_cmtResults(__VA_ARGS__) +#define GFAST_hdf5_createType_faultPlane(...) \ + hdf5_createType_faultPlane(__VA_ARGS__) +#define GFAST_hdf5_createType_ffResults(...) \ + hdf5_createType_ffResults(__VA_ARGS__) +#define GFAST_hdf5_createType_gpsData(...) \ + hdf5_createType_gpsData(__VA_ARGS__) +#define GFAST_hdf5_createType_hypocenter(...) \ + hdf5_createType_hypocenter(__VA_ARGS__) +#define GFAST_hdf5_createType_offsetData(...) \ + hdf5_createType_offsetData(__VA_ARGS__) +#define GFAST_hdf5_createType_peakDisplacementData(...) \ + hdf5_createType_peakDisplacementData(__VA_ARGS__) +#define GFAST_hdf5_createType_pgdResults(...) \ + hdf5_createType_pgdResults(__VA_ARGS__) +#define GFAST_hdf5_createType_waveform3CData(...) \ + hdf5_createType_waveform3CData(__VA_ARGS__) + +#define GFAST_hdf5_initialize(...) \ + hdf5_initialize(__VA_ARGS__) +#define GFAST_hdf5_memory_freeCMTResults(...) \ + hdf5_memory_freeCMTResults(__VA_ARGS__) +#define GFAST_hdf5_memory_freeGPSData(...) \ + hdf5_memory_freeGPSData(__VA_ARGS__) +#define GFAST_hdf5_memory_freePGDData(...) \ + hdf5_memory_freePGDData(__VA_ARGS__) +#define GFAST_hdf5_memory_freePGDResults(...) \ + hdf5_memory_freePGDResults(__VA_ARGS__) +#define GFAST_hdf5_memory_freeFaultPlane(...) \ + hdf5_memory_freeFaultPlane(__VA_ARGS__) +#define GFAST_hdf5_memory_freeFFResults(...) \ + hdf5_memory_freeFFResults(__VA_ARGS__) +#define GFAST_hdf5_memory_freeOffsetData(...) \ + hdf5_memory_freeOffsetData(__VA_ARGS__) +#define GFAST_hdf5_memory_freeWaveform3CData(...) \ + hdf5_memory_freeWaveform3CData(__VA_ARGS__) +#define GFAST_hdf5_updateCMT(...) \ + hdf5_updateCMT(__VA_ARGS__) +#define GFAST_hdf5_updateFF(...) \ + hdf5_updateFF(__VA_ARGS__) +#define GFAST_hdf5_updateGetIteration(...) \ + hdf5_updateGetIteration(__VA_ARGS__) +#define GFAST_hdf5_update_gpsData(...) \ + hdf5_update_gpsData(__VA_ARGS__) +#define GFAST_hdf5_updateHypocenter(...) \ + hdf5_updateHypocenter(__VA_ARGS__) +#define GFAST_hdf5_updatePGD(...) \ + hdf5_updatePGD(__VA_ARGS__) + + +#ifdef __cplusplus +} +#endif +#endif /* _gfast_hdf5_h__ */ diff --git a/include/gfast_struct.h b/include/gfast_struct.h new file mode 100644 index 00000000..fbee04fd --- /dev/null +++ b/include/gfast_struct.h @@ -0,0 +1,592 @@ +#ifndef GFAST_STRUCT_H +#define GFAST_STRUCT_H 1 +#if defined WINNT || defined WIN32 || defined WIN64 +#include +#include +#else +#include +#endif +#include +#include "gfast_enum.h" +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif +#include "gfast_config.h" + + +struct GFAST_pgd_props_struct +{ + bool do_pgd; /*!< Should PGD be calculated? */ + double window_vel; /*!< Velocity (km/s) used in determining if enough + data has arrived at a station in PGD + inversion. */ + double min_window_vel; /*!< min S vel to use for tmax=dist/min_s_vel PGD peak search*/ + double dist_tol; /*!< Source-receiver distance tolerance (km). */ + double disp_def; /*!< If the source receiver epicentral distance + is less than dist_tol this is the value assigned + to the PGD observation (cm). */ + double dLat; /*!< Latitude perturbation (degrees) in epicentral + grid search. */ + double dLon; /*!< Longitude perturbation (degrees) in epicentral + grid search. */ + int min_sites; /*!< Minimum number of sites required to + proceed with PGD inversion. */ + int verbose; /*!< Controls verbosity - errors will always + be output.
+ = 1 -> Output generic information.
+ = 2 -> Output generic information and + warnings.
+ = 3 -> Output generic information, + warnings, and debug information + and debug information. */ + int utm_zone; /*!< UTM zone. If this is -12345 then will + extract the UTM zone from the event + origin. */ + int ngridSearch_lats; /*!< Number of latitudes in epicentral grid-search. */ + int ngridSearch_lons; /*!< Number of longitudes in epicentral grid-search.*/ + int ngridSearch_deps; /*!< Number of depths in PGD grid-search. */ + double t99[MAX_SIGMA_LOOKUP_VALUES];/*!< Time after origin (s) from lookup table [n99] */ + double m99[MAX_SIGMA_LOOKUP_VALUES];/*!< Magnitude from lookup table [n99] */ + int n99; /*!< Number of t99, m99 values */ + int throttle_num_stations[MAX_THROTTLING_THRESHOLDS]; /*!< Threshold number of stations to send a message */ + double throttle_pgd_threshold[MAX_THROTTLING_THRESHOLDS]; /*!< Threshold pgd value (cm) */ + double throttle_time_threshold[MAX_THROTTLING_THRESHOLDS]; /*!< Threshold time value (s) */ + int n_throttle; /*!< number of throttle criteria. num_stations, pgd_threshold, + time_threshold should be the same length */ + double u_raw_sigma_threshold; /*!< Maximum raw sigma (up) to allow in pd calculations (cm) */ + double n_raw_sigma_threshold; /*!< Maximum raw sigma (east) to allow in pd calculations (cm) */ + double e_raw_sigma_threshold; /*!< Maximum raw sigma (north) to allow in pd calculations (cm) */ + double pgd_sigma_throttle; /*!< Maximum pgd magnitude uncertainty to allow in sending xml */ + double SA_mag_threshold; /*!< Magnitude threshold above which to send xml messages */ + double minimum_pgd_cm; /*!< Minimum value to include a pgd value in inversion (cm) */ + double maximum_pgd_cm; /*!< Maximum value to include a pgd value in inversion (cm) */ + int max_assoc_stations; /*!< Maximum stations to add the 'assoc' tag to in xml */ +}; + +struct GFAST_cmt_props_struct +{ + bool do_cmt; /*!< Should CMT be calculated? */ + double window_vel; /*!< Velocity (km/s) used in determining if S wave + has passed through the station in CMT + inversion. */ + double window_avg; /*!< Amount of time (s) required after S wave + has passed through for averaging + the offset. */ + double dLat; /*!< Latitude perturbation (degrees) in epicentral + grid search. */ + double dLon; /*!< Longitude perturbation (degrees) in epicentral + grid search. */ + int min_sites; /*!< Minimum number of sites required to + proceed with CMT inversion. */ + int verbose; /*!< Controls verbosity - errors will always + be output.
+ = 1 -> Output generic information. \n + = 2 -> Output generic information and + warnings. \n + = 3 -> Output generic information, + warnings, and debug information + and debug information. */ + int utm_zone; /*!< UTM zone. If this is -12345 then will + extract the UTM zone from the event + origin. */ + int ngridSearch_lats; /*!< Number of latitudes in epicenter grid-search. */ + int ngridSearch_lons; /*!< Number of longitudes in epicenter grid-search. */ + int ngridSearch_deps; /*!< Number of depths in CMT grid-search. */ + bool ldeviatoric; /*!< If true then the CMT inversion is + constrained to purely deviatoric sources. + Otherwise, all 6 moment tensor terms + are inverted for. */ +}; + +struct GFAST_ff_props_struct +{ + bool do_ff; /*!< Should FF be calculated? */ + double window_vel; /*!< Velocity (km/s) used in determining if S wave + has passed through the station in FF + inversion. */ + double window_avg; /*!< Amount of time (s) required after S wave + has passed through for averaging + the offset. */ + double flen_pct; /*!< Fault length safety factor. */ + double fwid_pct; /*!< Fault width safety factor. */ + int verbose; /*!< Controls verbosity - errors will always + be output. \n + = 1 -> Output generic information. \n + = 2 -> Output generic information and + warnings. \n + = 3 -> Output generic information, + warnings, and debug information + and debug information. */ + int utm_zone; /*!< UTM zone. If this is -12345 then will + extract the UTM zone from the event + origin. */ + int min_sites; /*!< Minimum number of sites to proceed with + FF estimation. */ + int nstr; /*!< Number of fault patches along strike. */ + int ndip; /*!< Number of fault patches down dip. */ + int nfp; /*!< Number of fault planes considered in + inversion (should be 2). */ +}; + +struct GFAST_activeMQ_struct +{ + char user[512]; /*!< Username for ActiveMQ host computer. */ + char password[512]; /*!< Password to ActiveMQ host computer. */ + char originURL[512]; /*!< EEW ActiveMQ URL for reading event trigger messages */ + char originTopic[512]; /*!< This is the topic (ActiveMQ destination) + that GFAST reads event trigger messages from*/ + char destinationURL[512]; /*!< EEW ActiveMQ URL for writing algorithm output to */ + char destinationTopic[512]; /*!< This is the topic (ActiveMQ destination) + that GFAST will send messages to. */ + char hbTopic[512]; /*!< This is the topic (ActiveMQ destination) + that GFAST will send heartbeats to. */ + int hbInterval; /*!< interval between heartbeats in seconds */ + int msReconnect; /*!< milliseconds to wait before reconnect + (default is 500). */ + int maxAttempts; /*!< Max number of attempts before declaring + inability to connect to the host + (default is 5). */ + int msWaitForMessage; /*!< Milliseconds to wait for a message + (default is 0). */ + unsigned int maxMessages; /*!< Maximum messages in consumer FIFO buffer + (default is 5). */ +}; + +struct GFAST_ew_struct +{ + char gpsRingName[256]; /*!< Name of earthworm ring with GPS data. */ + char moduleName[256]; /*!< Earthworm module name. */ +}; + +struct GFAST_props_struct +{ + struct GFAST_pgd_props_struct pgd_props; /*!< PGD properties structure. */ + struct GFAST_cmt_props_struct cmt_props; /*!< CMT properties structure. */ + struct GFAST_ff_props_struct ff_props; /*!< FF properties structure. */ + struct GFAST_activeMQ_struct activeMQ_props; /*!< ShakeAlert ActiveMQ properties */ + struct GFAST_ew_struct ew_props; /*!< Earthworm properties. */ + char metaDataFile[PATH_MAX]; /*!< Contains the GPS metadata file + which defines the sites, locations, + sampling periods, etc. to be used + by GFAST. */ + char *metaDataNetworks[16]; /*!< Networks that are allowed to be used */ + int n_networks; /*!< Number of networks to use. If 0, use any available */ + char SAeventsDir[PATH_MAX]; /*!< Location of dir containing SA events + SA.xml to trigger on */ + char SAoutputDir[PATH_MAX]; /*!< Location of dir where SA XML files will be written + at output_interval_mins minutes */ + char siteMaskFile[PATH_MAX]; /*!< Contains a list of sites to mask from + the inversions. If not specified then + all sites will be read. */ + char eewsfile[PATH_MAX]; /*!< In playback mode this XML decision + module style module has the event + hypocenter and origin time. */ + char obsdataDir[PATH_MAX]; /*!< Observed data file directory. */ + char obsdataFile[PATH_MAX]; /*!< Observed (archived) data file. */ + char h5ArchiveDir[PATH_MAX]; /*!< HDF5 archive directory. */ + char propfilename[PATH_MAX]; /*!< Name of GFAST properties file. */ + char anssNetwork[512]; /*!< ANSS network when writing quakeML + (e.g. UW, PM, etc.). */ + char anssDomain[512]; /*!< ANSS domain when writing quake ML + (e.g. anss.org, tsunami.gov, etc) */ + double dt_default; /*!< Default sampling period (s) for GPS + stations. */ + double bufflen; /*!< The number of seconds to keep in the data + buffers. */ + double processingTime; /*!< Max processing time (s) after origin time + which GFAST module will declare an event + done. This must be less than bufflen + less than or equal to the synthetic + runtime. */ + double eqDefaultDepth; /*!< Default earthquake depth (km) to be applied + to shakeAlert structure */ + double synthetic_runtime; /*!< Simulation runtime (s) for offline mode. */ + double waitTime; /*!< Number of seconds to wait before running + another iteration of the realtime code. */ + int n_intervals; + int output_interval_mins[16]; /*!< Intervals (mins) at which to output event solution XMLs */ + int utm_zone; /*!< UTM zone. If this is -12345 then will + extract the UTM zone from the event + origin. */ + int verbose; /*!< Controls verbosity - errors will always + be output. \n + = 1 -> Output generic information. \n + = 2 -> Output generic information and + warnings. \n + = 3 -> Output generic information, + warnings, and debug information + and debug information. */ + bool lh5SummaryOnly; /*!< If true then only the HDF5 summary + will be written. */ + enum opmode_type opmode; /*!< GFAST operation mode (realtime, + playback, offline). */ + enum dtinit_type dt_init; /*!< Defines how to initialize GPS sampling + period. */ + enum locinit_type loc_init; /*!< Defines how to initialize GPS locations. */ +}; + + +struct GFAST_faultPlane_struct +{ + double *lon_vtx; /*!< For plotting this defines the longitude of each + vertex (degrees) on each fault patch. The ifp'th + fault patch is accessed by 4*(idip*nstr + istr). + The size is [4 x nstr x ndip] */ + double *lat_vtx; /*!< For plotting this defines the latitude of each + vertex (degrees) on each fault patch. The ifp'th + fault patch is accessed by 4*(idip*nstr + istr). + The size is [4 x nstr x ndip] */ + double *dep_vtx; /*!< For plotting this defines the depth of each + vertex (km) on each fault patch. The ifp'th + fault patch is accessed by 4*(idip*nstr + istr). + The size is [4 x nstr x ndip] */ + double *fault_xutm; /*!< Fault easting UTM (m). The size is + [nstr x ndip] with leading dimension nstr */ + double *fault_yutm; /*!< Fault northing UTM (m). The size is + [nstr x ndip] with leading dimension nstr */ + double *fault_alt; /*!< Depth at fault patch (km) The size is + [nstr x ndip] with leading dimension nstr */ + double *strike; /*!< Strike angles of fault patches (degrees) + [nstr x ndip] with leading dimension nstr */ + double *dip; /*!< Dip angles of fault patches (degrees). The size + is [nstr x ndip] with leading dimension nstr */ + double *length; /*!< Length of fault patches (m). The size is + [nstr x ndip] with leading dimension nstr */ + double *width; /*!< Width of fault patches (m). The size is + [nstr x ndip] with leading dimension nstr */ + double *sslip; /*!< Strike-slip along each fault patch. The size + is [nstr x ndip] with leading dimension nstr */ + double *dslip; /*!< Dip-slip along each fault patch. The size + is [nstr x ndip] with leading dimension nstr */ + double *sslip_unc; /*!< Uncertainty in strike-slip on each fault patch. + The size is [nstr x ndip] with leading dimension + nstr. */ + double *dslip_unc; /*!< Uncertainty in dip slip on each fault patch. + The size is [nstr x ndip] with leading dimension + nstr. */ + double *EN; /*!< Modeled east displacements [nsites_used] */ + double *NN; /*!< Modeled north displacements [nsites_used] */ + double *UN; /*!< Modeled vertical displacements [nsites_used] */ + double *Einp; /*!< Observed input east displacements [nsites_used] */ + double *Ninp; /*!< Observed input north displacements [nsites_used] */ + double *Uinp; /*!< Observed input vertical displacements + [nsites_used] */ + int *fault_ptr; /*!< Maps from the ifp'th fault patch to the + start index of in (lon_vtx, lat_vtx, dep_vtx) + [nstr*ndip + 1] */ + int maxobs; /*!< Max number of allowable observations */ + int nsites_used; /*!< Number of sites used in inversion */ + int nstr; /*!< Number of fault patches along strike */ + int ndip; /*!< Number of fault patches down dip */ +}; + +struct GFAST_ffResults_struct +{ + struct GFAST_faultPlane_struct *fp; /*!< Fault planes [nfp] */ + double *vr; /*!< Variance reduction on ifp'th + fault plane [nfp] */ + double *Mw; /*!< Moment magnitude on ifp'th + fault plane [nfp] */ + double *str; /*!< Strike of ifp'th fault + (degrees) [nfp] */ + double *dip; /*!< Dip on ifp'th fault plane + (degrees) [nfp] */ + double SA_lat; /*!< Source latitude (degrees) [-90,90] */ + double SA_lon; /*!< Source longitude (degrees) [-180,360) */ + double SA_dep; /*!< Source depth (km) */ + double SA_mag; /*!< Source magnitude (Mw) */ + int preferred_fault_plane; /*!< Preferred fault plane */ + int nfp; /*!< Number of fault planes */ +}; + +struct GFAST_cmtResults_struct +{ + double *l2; /*!< L_2 objective function at all depths [ndeps] */ + double *pct_dc; /*!< Percent double couple at each depth [ndeps] */ + double *objfn; /*!< Objective function at all depths = l2/pct_dc */ + double *mts; /*!< Holds the NED moment tensor terms packed + \f$ \{m_{xx}, m_{yy}, m_{zz}, + m_{xy}, m_{xz}, m_{yz} \} \f$. [6*ndeps] */ + double *str1; /*!< Strike (degrees) on first nodal plane for + all depths [ndeps]. \f$ \phi \in [0,360] \f$ */ + double *str2; /*!< Strike (degrees) on second nodal plane for + all depths [ndeps]. \f$ \phi \in [0,360] \f$ */ + double *dip1; /*!< Dip (degrees) on first nodal plane for + all depths [ndeps]. \f$ \delta \in [0,90] \f$ */ + double *dip2; /*!< Dip (degrees) on second nodal plane for + all depths [ndeps]. \f$ \delta \in [0,90] \f$ */ + double *rak1; /*!< Rake (degrees) on first nodal plane for + all depths [ndeps]. + \f$ \lambda \in [-180,180] \f$ */ + double *rak2; /*!< Rake (degrees) on second nodal plane for + all depths [ndeps]. + \f$ \lambda \in [-180,180] \f$ */ + double *Mw; /*!< Moment magnitude for all depths [ndeps] */ + double *srcDepths; /*!< Source depths in moment tensor inversion grid + search (km) [ndeps] */ + double *EN; /*!< Estimates on east component. The estimate + for the i'th site at the j'th depth is accessed by + j*sites+i [ndeps*nsites] */ + double *NN; /*!< Estimates on north component. The estimate + for the i'th site at the j'th depth is accessed by + j*nsites+i [ndeps*nsites] */ + double *UN; /*!< Estimates on vertical component. The estimate + for the i'th site at the j'th depth is accessed by + j*nsites+i [ndeps*nsites] */ + double *Einp; /*!< Observed input east displacements [nsites] */ + double *Ninp; /*!< Observed input north displacements [nsites] */ + double *Uinp; /*!< Observed input vertical displacements [nsites] */ + bool *lsiteUsed; /*!< If true then the isite'th site from the + site list was used in the CMT estimation [nsite] */ + int opt_indx; /*!< Optimal index in depth grid search [0, ndeps) */ + int nlats; /*!< Number of latitudes in grid search */ + int nlons; /*!< Number of longitudes in grid serach */ + int ndeps; /*!< Number of depths in grid search */ + int nsites; /*!< Should equal GFAST_data_struct's stream_length */ +}; + +struct GFAST_pgdResults_struct +{ + double *mpgd; /*!< PGD magnitude at id'th depth [ndeps] */ + double *mpgd_sigma;/*!< PGD magnitude uncertainty at id'th depth [ndeps] */ + double *mpgd_vr; /*!< PGD variance reduction at id'th depth [ndeps] */ + double *dep_vr_pgd;/*!< PGD variance reduction at id'th depth + normalized by the interquartile range [ndeps] */ + double *UP; /*!< PGD estimates for each source depth + [nsites*ndeps] */ + double *UPinp; /*!< PGD observations for each site [nsites] */ + double *srcLats; /*!< Source latitudes in grid search (degrees) [nlats] */ + double *srcLons; /*!< Source longitudes in grid search (degrees) [nlons] */ + double *srcDepths; /*!< PGD source depths in grid search (km) [ndeps] */ + double *srdist; /*!< Source receiver distance (km) [ndeps*nsites] */ + double *iqr; /*!< interquartile range (75 - 25) of the weighted + residuals at each depth [ndeps] */ + bool *lsiteUsed; /*!< If true then the isite'th site from the + site list was used in the PGD estimation [nsites] */ + int nlats; /*!< Number of latitudes in grid search */ + int nlons; /*!< Number of longitudes in grid serach */ + int ndeps; /*!< Number of depths in PGD estimation */ + int nsites; /*!< Should equal GFAST_data_struct's stream_length */ +}; + +struct GFAST_peakDisplacementData_struct +{ + char **stnm; /*!< Name of i'th site */ + double *pd; /*!< Peak displacement (meters) observed at the i'th + site [nsites] */ + double *wt; /*!< Data weight on the i'th peak displacement observation + [nsites] */ + double *sta_lat; /*!< Site latitude [-90,90] (degrees) */ + double *sta_lon; /*!< Site longitude [0,360] (degrees) */ + double *sta_alt; /*!< Site altitude (m) above sea-level */ + double *pd_time; /*!< Epoch time of peak displacement observation */ + bool *lmask; /*!< If true then mask the i'th site in this inversion + [nsites] */ + bool *lactive; /*!< If true then the i'th site has data from the waveform + processor and can be an active participant in the + inversion [nsites] */ + int nsites; /*!< Number of sites (should be consistent with + buffered data) */ +}; + +struct GFAST_offsetData_struct +{ + char **stnm; /*!< Name of i'th site [nsites x 64] */ + double *ubuff; /*!< Offset (meters) in up component observed at the + i'th site [nsites] */ + double *nbuff; /*!< Offset (meters) in north component observed at the + i'th site [nsites] */ + double *ebuff; /*!< Offset (meters) in east component observed at the + i'th site [nsites] */ + double *wtu; /*!< Data weight on the i'th up offset + observation [nsites] */ + double *wtn; /*!< Data weight on the i'th north offset + observation [nsites] */ + double *wte; /*!< Data weight on the i'th east offset + observation [nsites] */ + double *sta_lat; /*!< Site latitude [-90,90] (degrees) */ + double *sta_lon; /*!< Site longitude [0,360] (degrees) */ + double *sta_alt; /*!< Site altitude (m) above sea-level */ + bool *lmask; /*!< If true then mask the i'th site in this inversion + [nsites] */ + bool *lactive; /*!< If true then the i'th site has data from the waveform + processor and can be an active participant in the + inversion [nsites] */ + int nsites; /*!< Number of sites */ +}; + + +struct GFAST_waveform3CData_struct +{ + char netw[64]; /*!< Network name */ + char stnm[64]; /*!< Station name */ + char chan[6][64]; /*!< Channel codes (Z, N, E, 3, 2, 1) */ + char loc[64]; /*!< Location code */ + double *ubuff; /*!< Up precise-point position buffer (meters). If any + sample is not known it should be a NAN. [maxpts] */ + double *nbuff; /*!< North precise-point position buffer (meters). If any + sample is not known it should be a NAN. [maxpts] */ + double *ebuff; /*!< East precise-point position buffer (meters). If any + sample is not known it should be a NAN. */ + double *usigmabuff; /*!< Up precise-point position buffer (meters). If any + sample is not known it should be a NAN. [maxpts] */ + double *nsigmabuff; /*!< North precise-point position buffer (meters). If any + sample is not known it should be a NAN. [maxpts] */ + double *esigmabuff; /*!< East precise-point position buffer (meters). If any + sample is not known it should be a NAN. */ + double *tbuff; /*!< Epochal time buffer (s) [maxpts] */ + //double epoch; /*!< Epoch time (seconds) corresponding to first sample + // of u, n, and e traces */ + double dt; /*!< Sampling period (seconds). */ + double sta_lat; /*!< Site latitude [-90,90] (degrees) */ + double sta_lon; /*!< Site longitude [0,360] (degrees) */ + double sta_alt; /*!< Site altitude (m) */ + double gain[6]; /*!< Instrument gain on all three channels */ + int maxpts; /*!< Max number of poitns in buffer. This is + computed from the site sampling period and + the GFAST_parm_struct's bufflen */ + int npts; /*!< Number of points in time series. This cannot + exceed maxpts */ + bool lskip_pgd; /*!< True -> This site is ignored during the PGD + estimation. + False -> Will attempt to use this site during + the PGD estimation. */ + bool lskip_cmt; /*!< True -> this site is ignored during the CMT + inversion. + False -> Will attempt to use this site during the + CMT inversion */ + bool lskip_ff; /*!< True -> this site is ignored during the finite + fault inversion + False -> Will attempt to use this during the + finite fault inversion */ +}; + +struct GFAST_data_struct +{ + struct GFAST_waveform3CData_struct *data; /*!< Collocated data structure. + This is an array with + dimension [stream_length] */ + int stream_length; /*!< Number of streams. */ +}; + +struct GFAST_shakeAlert_struct +{ + char eventid[128]; /*!< Event ID. */ + char orig_sys[12]; /*!< originating algorithm */ + int version; /*!< message version */ + double lat; /*!< Event latitude (degrees). */ + double lon; /*!< Event longitude (degrees). */ + double dep; /*!< Event depth (kilometers). */ + double mag; /*!< Event magnitude. */ + double time; /*!< Event epochal time (s). */ +}; + +struct GFAST_activeEvents_struct +{ + struct GFAST_shakeAlert_struct *SA; /*!< Shake alert structure with + requisite event info. This + an array with dimension [nev]. */ + int nev; /*!< Number of events. */ + char pad1[4]; +}; + +struct GFAST_xml_output_status +{ + char eventid[128]; /*!< Event ID. */ + int version; /*!< GFAST iteration version for this event ID. */ + bool interval_complete[3][MAX_OUTPUT_INTERVALS]; /*!< intervals_complete[] for pgd + cmt + ff = 3 */ +}; + +struct GFAST_activeEvents_xml_status +{ + struct GFAST_xml_output_status *SA_status; + int nev; + //char pad1[4]; /* MTH: seems to be for byte alignment but **check this** */ +}; + +struct coreInfo_struct +{ + char id[128]; /*!< Event ID */ + int version; /*!< Version number */ + double mag; /*!< Magnitude */ + bool lhaveMag; /*!< If true then mag is defined */ + enum alert_units_enum magUnits; /*!< Magnitude units */ + bool lhaveMagUnits; /*!< If true then mag units are + defined */ + double magUncer; /*!< Magnitude uncertainty */ + bool lhaveMagUncer; /*!< If true then mag_uncer is + defined */ + enum alert_units_enum magUncerUnits; /*!< Magnitude uncertainty units */ + bool lhaveMagUncerUnits; /*!< If true then mag uncer units + is defined */ + double lat; /*!< Event latitude */ + bool lhaveLat; /*!< If true then the latitude + is defined */ + enum alert_units_enum latUnits; /*!< Latitude units */ + bool lhaveLatUnits; /*!< If true then the lat units + are defined */ + double latUncer; /*!< Latitude uncertainty */ + bool lhaveLatUncer; /*!< If true then the latitude + uncertainty is defined */ + enum alert_units_enum latUncerUnits; /*!< Latitude uncertainty units */ + bool lhaveLatUncerUnits; /*!< If true then the latitude + uncertainty units are + defined */ + double lon; /*!< Event longitude */ + bool lhaveLon; /*!< If true then the longitude + is defined */ + enum alert_units_enum lonUnits; /*!< Longitude units */ + bool lhaveLonUnits; /*!< If true then the longitude + units are defined */ + double lonUncer; /*!< Longitude uncertainty */ + bool lhaveLonUncer; /*!< If true then the longitude + uncertainty units are + defined */ + enum alert_units_enum lonUncerUnits; /*!< Longitude uncertainty units */ + bool lhaveLonUncerUnits; /*!< If true then the longitude + uncertainty units are + defined */ + double depth; /*!< Event depth */ + bool lhaveDepth; /*!< If true then the depth is + defined */ + enum alert_units_enum depthUnits; /*!< Event depth units */ + bool lhaveDepthUnits; /*!< If true then the depth + units are defined */ + double depthUncer; /*!< Depth uncertainty */ + bool lhaveDepthUncer; /*!< If true then the depth + uncertainty is defined */ + enum alert_units_enum depthUncerUnits; /*!< Depth uncertainty units */ + bool lhaveDepthUncerUnits; /*!< If true then the depth + uncertainty units are + defined */ + double origTime; /*!< UTC origin time */ + bool lhaveOrigTime; /*!< If true then the origin + time is defined */ + enum alert_units_enum origTimeUnits; /*!< Origin time units */ + bool lhaveOrigTimeUnits; /*!< If true then the origin + time units are defined */ + double origTimeUncer; /*!< Origin time uncertainty */ + bool lhaveOrigTimeUncer; /*!< If true then the origin time + uncertainty is defined */ + enum alert_units_enum + origTimeUncerUnits; /*!< Origin time uncertainty + units */ + bool lhaveOrigTimeUncerUnits; /*!< If true then the origin time + uncertainty units are + defined */ + double likelihood; /*!< TODO: I have no idea what likelihood means */ + bool lhaveLikelihood; /*!< If true then the likelihood is defined */ + int numStations; /*!< Number of stations used in event. */ +}; + +struct GFAST_xmlMessages_struct +{ + char **evids; /*!< Event IDs. */ + char **cmtQML; /*!< CMT quakeML message. */ + char **ffXML; /*!< Finite fault shakeAlert XML message. */ + char **pgdXML; /*!< PGD shakeAlert XML message. */ + int nmessages; /*!< Number of XML messages. */ + int mmessages; /*!< Max number of XML messages. */ +}; + +#endif /* _gfast_struct_h__ */ diff --git a/include/gfast_traceBuffer.h b/include/gfast_traceBuffer.h new file mode 100644 index 00000000..d3c19674 --- /dev/null +++ b/include/gfast_traceBuffer.h @@ -0,0 +1,304 @@ +#ifndef _gfast_tracebuffer_h__ +#define _gfast_tracebuffer_h__ 1 +#if defined WINNT || defined WIN32 || defined WIN64 +#include +#include +#else +#include +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wstrict-prototypes" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_struct.h" +#include "gfast_config.h" +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif +#include "gfast_config.h" +#ifdef GFAST_USE_EW +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wstrict-prototypes" +#endif +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +int WaveMsg2MakeLocal( TRACE2_HEADER* wvmsg ); +struct ewRing_struct +{ + char ewRingName[512]; /*!< Earthworm ring name to which we will connect */ + SHM_INFO region; /*!< Earthworm shared memory region corresponding to + the earthworm ring */ + MSG_LOGO *getLogo; /*!< Logos to scrounge from the ring [nlogo] */ + long ringKey; /*!< Ring key number */ + short nlogo; /*!< Number of logos */ + bool linit; /*!< True if the structure is initialized. + False if the structure is not initialized. */ + unsigned msWait; /*!< milliseconds to wait after reading ring */ + unsigned char + traceBuffer2Type; /*!< traceBuffer2type earthworm type */ + unsigned char + heartBeatType; /*!< earthworm heartbeat type */ + unsigned char + errorType; /*!< earthworm error type */ + unsigned char + instLocalID; /*!< earthworm local installation ID type */ + unsigned char + instWildcardID; /*!< installation wildcard ID */ + unsigned char + modWildcardID; /*!< module wildcard ID */ +}; +#else +#ifndef MAX_TRACEBUF_SIZ +#define MAX_TRACEBUF_SIZ 4096 +#endif +struct ewRing_struct +{ + bool linit; /*!< Bogus value so that compilation proceeds */ +}; +#endif + +/* Linked list node for hash_set */ +struct tb2_node { + struct tb2_node *next; /* next entry in chain */ + char *name; /* defined name (NSCL) */ + int i; /* index into tb2Data_struct for this NSCL */ +}; + +struct tb2_hashmap_struct { + struct tb2_node **map; /* hash array [hashsize] */ + uint32_t hashsize; /* hashsize for hashmap array */ +}; + +struct tb2Trace_struct +{ + char netw[64]; /*!< Network name */ + char stnm[64]; /*!< Station name */ + char chan[64]; /*!< Channel name */ + char loc[64]; /*!< Location name */ + double *times; /*!< Epochal times (UTC seconds) at each point data + point [npts] */ + int *data; /*!< Data [npts] */ + int *chunkPtr; /*!< Points to first index of continuous trace + [nchunks+1]. The first index should be zero and + the last index should be npts. */ + double dt; /*!< Sampling period (s) */ + int nchunks; /*!< Number of chunks */ + int npts; /*!< Number of points in times and data */ +}; + +struct tb2Data_struct +{ + struct tb2Trace_struct *traces; /*!< Concatenated traces */ + int ntraces; /*!< Number of traces */ + struct tb2_hashmap_struct *hashmap; /*!< Hashmap for trace NSCLs */ + bool linit; /*!< If true then the structure is + initialized. */ +}; + +struct h5trace_struct +{ + char netw[64]; /*!< Network name for forming earthworm requests */ + char stnm[64]; /*!< Station name for forming earthworm requests */ + char chan[64]; /*!< Channel name for forming earthworm requests */ + char loc[64]; /*!< Location code for forming earthworm requests */ + char *groupName; /*!< Full path to HDF5 data group (null terminated) */ + char *metaGroupName; /*!< Full path to HDF5 metadata group name (null + terminated) */ + //double *buffer1; /*!< Dataset 1 [maxpts] - TODO - delete its in h5 */ + //double *buffer2; /*!< Dataset 2 [maxpts] - TODO - delete its in h5 */ + double *data; /*!< Data to be copied onto other structure [ncopy] */ + double t1; /*!< Start time of data (UTC-seconds) */ + //double t1beg; /*!< Epochal start time of buffer1 (UTC-seconds) - TODO - delete */ + //double t2beg; /*!< Epochal start time of buffer2 (UTC-seconds) - TODO - delete */ + double slat; /*!< Station latitude (degrees) */ + double slon; /*!< Station longitude (degrees) */ + double selev; /*!< Station elevation above sea level (m) */ + double dt; /*!< Sampling period (seconds) */ + double gain; /*!< Instrument gain */ + int idest; /*!< Maps this trace back to the appropriate + six-component data stream */ + int maxpts; /*!< Max number of points in data buffers */ + int npts1; /*!< Number of points in buffer 1 - TODO - delete */ + int npts2; /*!< Number of points in buffer 2 - TODO - delete */ + int ncopy; /*!< Number of points to copy from Earthworm traceBuffer + to HDF5 or number of points to copy from HDF5 to + GFAST data buffer */ + int traceNumber; /*!< Trace number of H5 data block */ + int dtGroupNumber; /*!< Sampling period group number */ +}; + +struct h5traceBuffer_struct +{ + struct h5trace_struct *traces; /*!< HDF5 trace data structure */ + char **dtGroupName; /*!< Name of sampling period groups + [ndtGroups] */ + int *dtPtr; /*!< Maps from idt'th dtGroup to start index + of traces [ndtGroups+1] */ + hid_t fileID; /*!< HDF5 file handle */ + int ndtGroups; /*!< Number of sampling period groups */ + int ntraces; /*!< Number of traces to collect */ + bool linit; /*!< True if the structure has been + initialized */ +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + +///// Methods for hashing tb2 channels +/* Hashing function */ +uint32_t traceBuffer_ewrr_hash(const char *s); +/* Calls hash() and returns index into array with given hashsize */ +uint32_t traceBuffer_ewrr_make_hash(const char *s, uint32_t hashsize); +/* Add a value to the set */ +struct tb2_node *traceBuffer_ewrr_hashmap_add(struct tb2_hashmap_struct *hashmap, + const char *name, + int index); +/* Remove a value from the set */ +int traceBuffer_ewrr_hashmap_remove(struct tb2_hashmap_struct *hashmap, const char *name); +/* Check if set contains a value */ +struct tb2_node *traceBuffer_ewrr_hashmap_contains(struct tb2_hashmap_struct *hashmap, + const char *name); +/* Free hashmap node */ +void traceBuffer_ewrr_free_node(struct tb2_node *np); +/* Free hashmap table */ +void traceBuffer_ewrr_free_hashmap(struct tb2_hashmap_struct *hashmap); +/* Print the full set structure, for debugging */ +void traceBuffer_ewrr_print_hashmap(struct tb2_hashmap_struct *hashmap); +/* Use the un-modded hash value to determine whether there are any true collisions (debugging) */ +int traceBuffer_ewrr_print_true_collisions(struct tb2_hashmap_struct *hashmap); +///// End hashing functions + +/* Classify the result of earthworm tport_copyfrom */ +int traceBuffer_ewrr_classifyGetRetval(const int retval); +/* Finalize earthworm ring reader */ +int traceBuffer_ewrr_finalize(struct ewRing_struct *ringInfo); +/* Flush an earthworm ring */ +int traceBuffer_ewrr_flushRing(struct ewRing_struct *ringInfo); + /* Read messages from the ring */ +char *traceBuffer_ewrr_getMessagesFromRing(const int messageBlock, + const bool showWarnings, + struct ewRing_struct *ringInfo, + struct tb2_hashmap_struct *hashmap, + int *nRead, int *ierr); +/* Initialize the earthworm ring reader connection */ +int traceBuffer_ewrr_initialize(const char *ewRing, + const int msWait, + struct ewRing_struct *ringInfo); + +/* Classify return value from Earthworm get transport call */ +int traceBuffer_ewrr_classifyGetRetval(const int retval); +/* Flush an earthworm ring */ +int traceBuffer_ewrr_flushRing(struct ewRing_struct *ringInfo); +/* Finalize earthworm ring reader */ +int traceBuffer_ewrr_finalize(struct ewRing_struct *ringInfo); +/* Frees memory on the tb2data structure */ +void traceBuffer_ewrr_freetb2Data(struct tb2Data_struct *tb2data); +/* Frees memory on the tb2data trace structure */ +void traceBuffer_ewrr_freetb2Trace(const bool clearSNCL, + struct tb2Trace_struct *trace); +/* Sets the tb2Data structure and desired SNCL's from the input gpsData */ +int traceBuffer_ewrr_settb2DataFromGFAST(struct GFAST_data_struct *gpsData, + struct tb2Data_struct *tb2Data); +/* Unpack messages */ +int traceBuffer_ewrr_unpackTraceBuf2Messages( + const int nRead, + const char *msgs, + struct tb2Data_struct *tb2Data); +/* Reads a chunk of data from a Data group */ +double *traceBuffer_h5_readData(const hid_t groupID, + const int ntraces, + int *maxpts, + double *dt, double *ts1, double *ts2, + double *gain, int *ierr); +/* Sets data in h5 file */ +int traceBuffer_h5_setData(const double currentTime, + struct tb2Data_struct tb2Data, + struct h5traceBuffer_struct h5traceBuffer); +/* Copies the trace buffer to the GFAST structure */ +int traceBuffer_h5_copyTraceBufferToGFAST( + struct h5traceBuffer_struct *traceBuffer, + struct GFAST_data_struct *gps_data); +/* Initialize tracebuffer structure from GFAST */ +int traceBuffer_h5_setTraceBufferFromGFAST( + const double bufflen, + struct GFAST_data_struct gps_data, + struct h5traceBuffer_struct *traceBuffer); +/* Close the HDF5 file with the traces */ +int traceBuffer_h5_finalize(struct h5traceBuffer_struct *h5trace); +/* Get data from the HDF5 file */ +int traceBuffer_h5_getData(const double t1, const double t2, + struct h5traceBuffer_struct *h5traceBuffer); +/* Get a double array */ +int traceBuffer_h5_getDoubleArray(const hid_t groupID, + const int i1, const int i2, + const char *citem, + const double traceNaN, + const int nwork, + double *__restrict__ work); +/* Get scalar data from the HDF5 file */ +int traceBuffer_h5_getScalars(const hid_t groupID, + const int intNaN, + const double doubleNaN, + int *maxpts, + double *dt, double *gain, + double *ts1, double *ts2); +/* Initialize the HDF5 tracebuffer structure */ +int traceBuffer_h5_initialize(const int job, + const bool linMemory, + const char *h5dir, + const char *h5file, + struct h5traceBuffer_struct *h5traceBuffer); +/* Sets the HDF5 file name */ +int traceBuffer_h5_setFileName(const char *h5dir, + const char *h5file, + char h5name[PATH_MAX]); +/* Set scalar data */ +int traceBuffer_h5_setDoubleScalar(const hid_t groupID, + const char *citem, + const double scalar); +int traceBuffer_h5_setIntegerScalar(const hid_t groupID, + const char *citem, + const int scalar); + +#define GFAST_traceBuffer_h5_copyTraceBufferToGFAST(...) \ + traceBuffer_h5_copyTraceBufferToGFAST(__VA_ARGS__) +#define GFAST_traceBuffer_h5_finalize(...) \ + traceBuffer_h5_finalize(__VA_ARGS__) +#define GFAST_traceBuffer_h5_getData(...) \ + traceBuffer_h5_getData(__VA_ARGS__) +#define GFAST_traceBuffer_h5_getDoubleArray(...) \ + traceBuffer_h5_getDoubleArray(__VA_ARGS__) +#define GFAST_traceBuffer_h5_getScalars(...) \ + traceBuffer_h5_getScalars(__VA_ARGS__) +#define GFAST_traceBuffer_h5_initialize(...) \ + traceBuffer_h5_initialize(__VA_ARGS__) +#define GFAST_traceBuffer_h5_setFileName(...) \ + traceBuffer_h5_setFileName(__VA_ARGS__) +#define GFAST_traceBuffer_h5_setDoubleScalar(...) \ + traceBuffer_h5_setDoubleScalar(__VA_ARGS__) +#define GFAST_traceBuffer_h5_setIntegerScalar(...) \ + traceBuffer_h5_setIntegerScalar(__VA_ARGS__) +#define GFAST_traceBuffer_h5_setTraceBufferFromGFAST(...) \ + traceBuffer_h5_setTraceBufferFromGFAST(__VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif /* _gfast_tracebuffer_h__ */ diff --git a/include/gfast_xml.h b/include/gfast_xml.h new file mode 100644 index 00000000..0bf96fe0 --- /dev/null +++ b/include/gfast_xml.h @@ -0,0 +1,354 @@ +#ifndef _gfast_xml_h__ +#define _gfast_xml_h__ 1 + +#include "gfast_struct.h" +#include "gfast_enum.h" +#define XML_ENCODING "UTF-8" /*!< UTF encoding consistent with shakeAlert */ + +enum xml_segmentShape_enum +{ + LINE = 2, /*!< segment shape is a line with 2 points */ + TRIANGLE = 3, /*!< segment shape is a triangle with 3 points */ + RECTANGLE = 4 /*!< segment shape is a rectangle with 3 points */ +}; + +struct qmlMT_struct +{ + char id[256]; /*!< Moment tensor ID */ + char agencyID[256]; /*!< AgencyID (e.g. PNSN) */ + double m[6]; /*!< Moment tensor in Up, South, East coordinates with + units Dyne-centimeters. The moment tensor terms + are ordered + \f$ \{ m_{rr}, m_{\theta \theta} m_{\phi \phi}, + m_{r \theta} m_{r \phi} m_{\theta \phi} + \} \f$ */ + double np1[3]; /*!< Nodal plane 1 described by its strike, dip, and + rake respectively (degrees) */ + double np2[3]; /*!< Nodal plane 2 described by its strike, dip, and + rake respectively (degrees) */ + double taxis[3]; /*!< Tension axis (degrees), plunge (degrees), + and length (Dyne-cm) respectively */ + double naxis[3]; /*!< Null axis azimuth (degrees), plunge (degrees), + and length (Dyne-cm) respectively */ + double paxis[3]; /*!< Pressure axis azimuth (degrees), plunge (degrees), + and length (Dyne-cm) respectively */ + double M0; /*!< Scalar moment (Dyne-cm) */ + int nstations; /*!< Number of sites used in inversion */ + int ncomp; /*!< Number of components used in inversion. For + example if 2 three-component sites are used then + this is 6 and not 3. */ +}; + +struct qmlConfidenceEllipse_struct +{ + int bogus; /* TODO fix me */ +}; + +struct qmlOriginUncertainty_struct +{ + int bogus; /* TODO fix me */ +}; + +struct qmlMagnitude_struct +{ + double magnitude; /*!< Magnitude */ + double magUncer; /*!< Magnitude uncertainty */ + char type[64]; /*!< Event type TODO: should be an enum */ + bool lhaveMag; /*!< If true then have the magnitude */ + bool lhaveMagUncer; /*!< Magnitude uncertainty */ + bool lhaveType; /*!< If true then have the magnitude type */ +}; + +struct qmlTime_struct +{ + double time; /*!< Time */ + double timeUncer; /*!< Time uncertainty */ + double confidenceLevel; /*!< Confidence level */ + enum alert_units_enum time_units; /*!< Time units */ + enum alert_units_enum timeUncer_units; /*!< Time uncertainty units */ + bool lhaveTime; /*!< If true then time is defined */ + bool lhaveTimeUncer; /*!< If true timeUncer is defined */ + bool lhaveConfidence; /*!< If true confidenceLevel + is defined */ +}; + +struct qmlLatitude_struct +{ + double latitude; /*!< Event latitude */ + double latUncer; /*!< Latitude uncertainty */ + double confidenceLevel; /*!< Confidence level */ + enum alert_units_enum latitude_units; /*!< Latitude units */ + enum alert_units_enum latUncer_units; /*!< Latitude uncertainty units */ + bool lhaveLat; /*!< If true then latitude is + defined */ + bool lhaveLatUncer; /*!< If true latUncer is defined */ + bool lhaveConfidence; /*!< If true confidenceLevel + is defined */ +}; + +struct qmlLongitude_struct +{ + double longitude; /*!< Event longitude */ + double lonUncer; /*!< Longitude uncertainty */ + double confidenceLevel; /*!< Confidence level */ + enum alert_units_enum longitude_units; /*!< Latitude units */ + enum alert_units_enum lonUncer_units; /*!< Longitude uncertainty units */ + bool lhaveLon; /*!< If true then longitude is + defined */ + bool lhaveLonUncer; /*!< If true lonUncer is defined */ + bool lhaveConfidence; /*!< If true confidenceLevel + is defined */ +}; + +struct qmlDepth_struct +{ + double depth; /*!< Event depth */ + double depthUncer; /*!< Depth uncertainty */ + double confidenceLevel; /*!< Confidence level */ + enum alert_units_enum depth_units; /*!< Depth units */ + enum alert_units_enum depthUncer_units; /*!< Depth uncertainty units */ + bool lhaveDepth; /*!< If true then depth is + defined */ + bool lhaveDepthUncer; /*!< If true depthUncer is + defined */ + bool lhaveConfidence; /*!< If true confidenceLevel + is defined */ +}; + +struct qmlOrigin_struct +{ + struct qmlConfidenceEllipse_struct ellipse; /*!< Error ellipsoid */ + struct qmlOriginUncertainty_struct oriUnc; /*!< Origin uncertainty */ + struct qmlLatitude_struct latitude; /*!< Event latitude */ + struct qmlLongitude_struct longitude; /*!< Event longitude */ + struct qmlDepth_struct depth; /*!< Event depth */ + struct qmlTime_struct originTime; /*!< Event origin time */ + bool lhaveEllipse; /*!< If true then there is a confidence ellipse */ + bool lhaveOriUnc; /*!< If true then there is an origin uncertainty */ + bool lhaveLatitude; /*!< If true then there is a latitude */ + bool lhaveLongitude; /*!< If true then there is a lognitude */ + bool lhaveDepth; /*!< If true then there is a depth */ + bool lhaveOriginTime; /*!< If true then there is an origin time */ +}; + +#ifdef __cplusplus +extern "C" { +#endif +/* Convert epochal time to string */ +int xml_epoch2string(const double epoch, char cepoch[128]); +/* Convert enumerated units to a string */ +void __xml_units__enum2string(const enum alert_units_enum enum_units, + char char_units[128]); +/* Convert string to enumerated units */ +enum alert_units_enum + __xml_units__string2enum(const char *char_units); +/* Write quakeML depth */ +int xml_quakeML_writeDepth(const double depth, + const enum alert_units_enum depth_units, + const bool lhaveDepth, + const double depthUncer, + const enum alert_units_enum depthUncer_units, + const bool lhaveDepthUncer, + const double confidence, + const bool lhaveConfidence, + void *xml_writer); +/* Write quakeML latitude */ +int xml_quakeML_writeLatitude(const double latitude, + const enum alert_units_enum lat_units, + const bool lhaveLat, + const double latUncer, + const enum alert_units_enum latUncer_units, + const bool lhaveLatUncer, + const double confidence, + const bool lhaveConfidence, + void *xml_writer); +/* Write quakeML longitude */ +int xml_quakeML_writeLongitude(const double longitude, + const enum alert_units_enum lon_units, + const bool lhaveLon, + const double lonUncer, + const enum alert_units_enum lonUncer_units, + const bool lhaveLonUncer, + const double confidence, + const bool lhaveConfidence, + void *xml_writer); +/* Write magnitude */ +int xml_quakeML_writeMagnitude(const double magnitude, + const bool lhaveMag, + const double magUncer, + const bool lhaveMagUncer, + const char *type, + const bool lhaveType, + void *xml_writer); +/* Write the focal mechanism */ +int xml_quakeML_writeFocalMechanism(const char *publicIDroot, + const char *evid, + const char *method, + const double mt[6], + void *xml_writer); +/* Write the moment tensor to XML message */ +int xml_quakeML_writeMomentTensor(const char *publicIDroot, + const char *evid, + const char *method, + const double M_use[6], + const double M0, + const double dc_pct, + const double clvd_pct, + void *xml_writer); +/* Write the nodal planes */ +int xml_quakeML_writeNodalPlanes(const double np1[3], + const double np2[3], + void *xml_writer); +/* Write the origin */ +int xml_quakeML_writeOrigin(const char *publicIDroot, + const char *evid, + const char *method, + struct qmlOrigin_struct origin, + void *xml_writer); +/* Write the principal axes */ +int xml_quakeML_writePrincipalAxes(const double taxis[3], + const double paxis[3], + const double naxis[3], + void *xml_writer); +/* Write a (moment) tensor */ +int xml_quakeML_writeTensor(const double Mrr, const double Mtt, + const double Mpp, const double Mrt, + const double Mrp, const double Mtp, + void *xml_writer); +/* Write (origin) time */ +int xml_quakeML_writeTime(const double time, + const enum alert_units_enum time_units, + const bool lhaveTime, + const double timeUncer, + const enum alert_units_enum timeUncer_units, + const bool lhaveTimeUncer, + const double confidence, + const bool lhaveConfidence, + void *xml_writer); +//----------------------------------------------------------------------------// +// shakeAlert // +//----------------------------------------------------------------------------// +/* Read shakeAlert coreInfo */ +int xml_shakeAlert_readCoreInfo(void *xml_reader, + const double saNaN, + struct coreInfo_struct *core); +/* Write shakeAlert coreInfo */ +int xml_shakeAlert_writeCoreInfo(const struct coreInfo_struct core, + void *xml_writer); +/* Write a shakeAlert finite fault segment */ +int xml_shakeAlert_writeSegment(const enum xml_segmentShape_enum shape, + const double *lats, + const enum alert_units_enum lat_units, + const double *lons, + const enum alert_units_enum lon_units, + const double *depths, + const enum alert_units_enum depth_units, + const double strike, + const enum alert_units_enum strike_units, + const double dip, + const enum alert_units_enum dip_units, + const double ss, + const enum alert_units_enum ss_units, + const double ds, + const enum alert_units_enum ds_units, + const double ss_uncer, + const enum alert_units_enum ss_uncer_units, + const double ds_uncer, + const enum alert_units_enum ds_uncer_units, + void *xml_writer); +/* Read slip */ +int xml_shakeAlert_readSlip(void *xml_reader, const double VTX_NAN, + double *ss, double *ss_uncer, + double *ds, double *ds_uncer); +/* Write slip */ +int xml_shakeAlert_writeSlip(const double ss, + const enum alert_units_enum ss_units, + const double ds, + const enum alert_units_enum ds_units, + const double ss_uncer, + const enum alert_units_enum ss_uncer_units, + const double ds_uncer, + const enum alert_units_enum ds_uncer_units, + void *xml_writer); +/* Write fault geometry */ +int xml_shakeAlert_writeGeometry(const double strike, + const enum alert_units_enum strike_units, + const double dip, + const enum alert_units_enum dip_units, + void *xml_writer); +/* Read shakeAlert finite fault vertices */ +int xml_shakeAlert_readVertices(void *xml_reader, + const enum xml_segmentShape_enum shape, + const double VTX_NAN, + double *__restrict__ lat, + double *__restrict__ lon, + double *__restrict__ depth); +/* Write shakeAlert finite fault vertices */ +int xml_shakeAlert_writeVertices(const enum xml_segmentShape_enum shape, + const double *lats, + const enum alert_units_enum lat_units, + const double *lons, + const enum alert_units_enum lon_units, + const double *depths, + const enum alert_units_enum depth_units, + void *xml_writer); +/* Read vertex */ +int xml_shakeAlert_readVertex(void *xml_reader, const double VTX_NAN, + double *lat, double *lon, double *depth); +/* Write a vertex */ +int xml_shakeAlert_writeVertex(const double lat, + const enum alert_units_enum lat_units, + const double lon, + const enum alert_units_enum lon_units, + const double depth, + const enum alert_units_enum depth_units, + void *xml_writer); +#define GFAST_xml_quakeML_writeDepth(...) \ + xml_quakeML_writeDepth(__VA_ARGS__) +#define GFAST_xml_quakeML_writeLatitude(...) \ + xml_quakeML_writeLatitude(__VA_ARGS__) +#define GFAST_xml_quakeML_writeLongitude(...) \ + xml_quakeML_writeLongitude(__VA_ARGS__) +#define GFAST_xml_quakeML_writeFocalMechanism(...) \ + xml_quakeML_writeFocalMechanism(__VA_ARGS__) +#define GFAST_xml_quakeML_writeMagnitude(...) \ + xml_quakeML_writeMagnitude(__VA_ARGS__) +#define GFAST_xml_quakeML_writeMomentTensor(...) \ + xml_quakeML_writeMomentTensor(__VA_ARGS__) +#define GFAST_xml_quakeML_writeNodalPlanes(...) \ + xml_quakeML_writeNodalPlanes(__VA_ARGS__) +#define GFAST_xml_quakeML_writeOrigin(...) \ + xml_quakeML_writeOrigin(__VA_ARGS__) +#define GFAST_xml_quakeML_writePrincipalAxes(...) \ + xml_quakeML_writePrincipalAxes(__VA_ARGS__) +#define GFAST_xml_quakeML_writeTensor(...) \ + xml_quakeML_writeTensor(__VA_ARGS__) +#define GFAST_xml_quakeML_writeTime(...) \ + xml_quakeML_writeTime(__VA_ARGS__) + + +#define GFAST_xml_shakeAlert_readCoreInfo(...) \ + xml_shakeAlert_readCoreInfo(__VA_ARGS__) +#define GFAST_xml_shakeAlert_writeCoreInfo(...) \ + xml_shakeAlert_writeCoreInfo(__VA_ARGS__) +#define GFAST_xml_shakeAlert_writeSegment(...) \ + xml_shakeAlert_writeSegment(__VA_ARGS__) +#define GFAST_xml_shakeAlert_readSlip(...) \ + xml_shakeAlert_readSlip(__VA_ARGS__) +#define GFAST_xml_shakeAlert_writeSlip(...) \ + xml_shakeAlert_writeSlip(__VA_ARGS__) +#define GFAST_xml_shakeAlert_writeGeometry(...) \ + xml_shakeAlert_writeGeometry(__VA_ARGS__) +#define GFAST_xml_shakeAlert_readVertex(...) \ + xml_shakeAlert_readVertex(__VA_ARGS__) +#define GFAST_xml_shakeAlert_writeVertex(...) \ + xml_shakeAlert_writeVertex(__VA_ARGS__) +#define GFAST_xml_shakeAlert_readVertices(...) \ + xml_shakeAlert_readVertices(__VA_ARGS__) +#define GFAST_xml_shakeAlert_writeVertices(...) \ + xml_shakeAlert_writeVertices(__VA_ARGS__) +#ifdef __cplusplus +} +#endif +#endif /* _gfast_xml_h__ */ + diff --git a/run/bin/run_gfast.sh b/run/bin/run_gfast.sh new file mode 100755 index 00000000..4d19fc51 --- /dev/null +++ b/run/bin/run_gfast.sh @@ -0,0 +1,205 @@ +#!/bin/sh +# +# run_gfast.sh This application shell script takes care of directly +# starting and stopping gfast in ShakeAlert context +# + +echo -e 'Version: 0.0 dev: run_gfast.sh\n' + +RETVAL=0 +ulimit -c unlimited + +# App details +APP="gfast_eew" + +cd `dirname $0`/.. +APP_DIR=`pwd` +PARENT=`dirname $APP_DIR` +APP_RUNDIR="${APP_DIR}" +APP_BINDIR="${APP_RUNDIR}/bin" +APP_CFGDIR="${APP_RUNDIR}/params" +APP_LOGDIR="${APP_RUNDIR}/logs" +APP_CMD="${APP_BINDIR}/${APP} ${APP_CFGDIR}/gfast.props" +APP_LOG="/app/share/bin/conlog -l ${APP_LOGDIR}/${APP}" + +#earthworm environment +export EW_PARAMS=/app/eewdata/run/params +export EW_INSTALLATION=INST_UW + +# Location of PID file(s) +PIDDIR="${APP_RUNDIR}/pids" + +# Timeout for starting and stopping APP +NUMBER_OF_CHECKS=10 +PAUSE=1 + +# Kill running process(es) +kill_proc() { + RC=2 + + # Find pid. + pid=`pid_of_proc $1 $2` + + # Kill it. + if [ "$pid" != "" ] ; then + if ps -p "$pid">/dev/null 2>&1; then + # TERM first, then KILL if not dead + kill -TERM $pid 2>/dev/null + sleep 1 + if ps -p "$pid" >/dev/null 2>&1 ; then + sleep 1 + if ps -p "$pid" >/dev/null 2>&1 ; then + sleep 3 + if ps -p "$pid" >/dev/null 2>&1 ; then + kill -KILL $pid 2>/dev/null + fi + fi + fi + fi + ps -p "$pid" >/dev/null 2>&1 + RC=$? + else + RC=1 + fi + # Remove PID file if no more process(es) + [ $RC = 1 ] && rm -f ${PIDDIR}/$1.pid + return $RC +} + +# Determine state of process(es) +check_proc() { + RC=2 + + # Find pid. + pid=`pid_of_proc $1 $2` + + if [ "$pid" != "" ] ; then + RC=0 + else + RC=1 + fi + return $RC +} + +# Get the PID of running process(es) +pid_of_proc() { + pid="" + + # Look for PID file + if [ -f ${PIDDIR}/$1.pid ] ; then + pid=`tail -n 1 ${PIDDIR}/$1.pid` + fi + + if [ "$pid" != "" ] ; then + bup=`ps -o args -p $pid | fgrep "$2"` + if [ $? != 0 ] ; then + pid="" + fi + fi + + echo $pid +} + +# Report application run status based on return code +report_run_status() { + + case "$1" in + 0) echo -n "UP" + ;; + 1) echo -n "DOWN" + ;; + 2) echo -n "UNKNOWN" + ;; + *) echo -n "ERROR" + ;; + esac +} + +# Start function +start() { + echo -n $"Starting ${APP}: " + + # Determine if process is already running. + pid=`pid_of_proc ${APP} "${APP_CMD}"` + + if [ "$pid" = "" ] ; then + # Setup environment before running program. + #. ${APP_BINDIR}/gfast_env.sh + echo "${APP_CMD} 2>&1 | ${APP_LOG} &" + ${APP_CMD} 2>&1 | ${APP_LOG} & + PID=`jobs -p` + RETVAL=$? + if [ $RETVAL = 0 ] && [ $PID != "" ]; then + echo $PID > ${PIDDIR}/${APP}.pid + fi + fi + + report_run_status $RETVAL + echo + return $RETVAL +} + +# Stop function +stop() { + echo -n $"Stopping ${APP}: " + + kill_proc ${APP} "${APP_CMD}" + RETVAL=$? + report_run_status $RETVAL + + # Swap 0 and 1 return values, because internally 1 means process stopped + # but exiting with 0 means successful attempt by script to stop process, + # and 0 means process not stopped, so exit with 1, meaning unsuccessful. + case "$RETVAL" in + 0) RETVAL=1 + ;; + 1) RETVAL=0 + ;; + esac + + echo + return $RETVAL +} + +# Status function +status() { + echo -n $"Status of ${APP}: " + + check_proc ${APP} "${APP_CMD}" + RETVAL=$? + + report_run_status $RETVAL + echo + return $RETVAL +} + +# See how we were called. +case "$1" in + start) + start + ;; + stop) + stop + ;; + status) + status + ;; + restart) + stop + for ((i=0; i GFAST is running in `real time' and being data through Earthworm +# 2 -> GFAST is running historical playbacks through Earthworm +# 3 -> GFAST is running offline and is obtaining data purely from files +opmode = 3 +# The synthetic mode driver file +syndriver=nisqually_driver.txt +# The synthetic mode output file +synoutput=nisqually_output.txt +# If working in specific area where the fault may straddle a UTM zone large +# distortions can arise. In this case it may be beneficial to set the UTM +# zone. Otherwise, if utm_zone is set to -12345 or not specified the UTM +# zone will be estimated from the event hpyocenter provided in the ElarmS +# message +utm_zone = 19 +# Mechanism for initializing sampling period +# 1 -> Sets GPS sampling period to default (dt_default) +# 2 -> Obtains the sampling period from the dtfile +# 3 -> Obtains the sampling period from Earthworm +dt_init = 2 +# Default GPS sampling period (s) +dt_default = 1.0 +# Location initialization strategy +# 1 -> Initialize locations from SOPAC SECTOR web service (siteposfile) +# 2 -> Initialize from trace buffer (if running in real-time this will +# happen automatically) +loc_init = 1 +# Controls verbosity: +# 0 -> Try to output nothing +# 1 -> Output errors only +# 2 -> Output errors and generic information (default) +# 3 -> Output errors, generic information, and debug information +verbose=3 + +################################################################################ +# PGD Properties # +################################################################################ +[PGD] +# PGD source-receiver distance tolerance in km (cannot be negative) +dist_tolerance = 0.5 +# If PGD source-receiver distance tolerance falls below dist_tol this is the +# default value given in km (must be positive) +dist_default = 0.01 +#ngridSearch_deps = 10 +ndepths_in_pgd_gridSearch = 10 +# These are the defaults: +pgd_window_vel = 3.0 +pgd_min_sites = 4 +################################################################################ +# CMT/Finite Fault Properties # +################################################################################ +[CMT] +ndepths_in_cmt_gridSearch = 10 +# These are the defaults: +cmt_window_vel = 2.0 +cmt_min_sites = 4 +[FF] +# These are the defaults: +ff_window_vel = 3.0 +ff_min_sites = 4 + +################################################################################ +# ActiveMQ Properties # +################################################################################ +[general] +verbose=4 + +[ActiveMQ] +# ActiveMQ host:port +### amq_dm openwire 61616 +### amq_sa openwire 63616 +#URL for event trigger messages +originURL=tcp://localhost:63616 +# ActiveMQ topic to read event trigger messages from +originTopic=eew.agg.sa.data +#URL to publish event messages and heartbeats on +destinationURL=tcp://localhost:61616 +# ActiveMQ topic to publish events on. +destinationTopic = eew.alg.gfast.data +# ActiveMQ topic to publish heartbeats on +hbTopic=eew.alg.gfast.hb +# heartbeat interval +hbInterval=5 +# ActiveMQ username to access ElarmS messages +user=glarms +# ActiveMQ password to access ElarmS messages +password=12345 diff --git a/run/params/gfast.props.SA b/run/params/gfast.props.SA new file mode 100644 index 00000000..a9fcc8ca --- /dev/null +++ b/run/params/gfast.props.SA @@ -0,0 +1,195 @@ +################################################################################ +# Global G-FAST properties # +################################################################################ +[general] +# File for log output +logFileName = /app/gfast/run/logs/gfast.log +# File with station names +metaDataFile = /app/share/etc/geodetic/merged_chanfile_coord.dat +# If set, only use channels from the given networks +metaDataNetworks = PW +# note: if SA_events_dir is set, activemq will be ignored! +#SA_events_dir= +SA_output_dir=/app/gfast/run/out +#if output_interval commented, it will output as available. +#output_interval_mins=1,2,3,4,5,10 +#siteMaskFile=ridgecrest-mask.txt +# File with station names and sampling periods +#dtfile=GFAST_streams_dt.txt +# ElarmS message file +#eewsfile=ElarmS_messages.txt +# GFAST results file +#eewgfile=GFAST_output.txt +# File of all the site locations. The format used is currently from +# the SOPAC SECTOR web service. +#siteposfile=site_pos.csv +# GFAST operation mode +# 1 -> GFAST is running in `real time' and being data through Earthworm +# 2 -> GFAST is running historical playbacks through Earthworm +# 3 -> GFAST is running offline and is obtaining data purely from files +opmode = 1 +# minimum time for main loop (defaults to 1 second) +waitTime=1.0 +# The synthetic mode driver file +#syndriver=nisqually_driver.txt +# The synthetic mode output file +#synoutput=nisqually_output.txt +# If working in specific area where the fault may straddle a UTM zone large +# distortions can arise. In this case it may be beneficial to set the UTM +# zone. Otherwise, if utm_zone is set to -12345 or not specified the UTM +# zone will be estimated from the event hpyocenter provided in the ElarmS +# message +utm_zone = 10 +# Mechanism for initializing sampling period +# 1 -> Sets GPS sampling period to default (dt_default) +# 2 -> Obtains the sampling period from the dtfile +# 3 -> Obtains the sampling period from Earthworm +dt_init = 3 +# Default GPS sampling period (s) +dt_default = 1.0 +# Location initialization strategy +# 1 -> Initialize locations from SOPAC SECTOR web service (siteposfile) +# 2 -> Initialize from trace buffer (if running in real-time this will +# happen automatically) +loc_init = 1 +# Controls verbosity: +# 0 -> Try to output nothing +# 1 -> Output errors only +# 2 -> Output errors and generic information (default) +# 3 -> Output errors, generic information, and debug information +verbose=3 + +synthetic_runtime = 0.0 +# Buffer length (s) +bufflen=140. +processing_time=120. +default_event_depth = 8.0 + +h5ArchiveDirectory = /app/gfast/run/h5archive +H5SummaryOnly = 1 + +anssNetwork = UW +anssDomain = anss.org + +################################################################################ +# Earthworm Properties # +################################################################################ +[earthworm] + +gpsRingName = GPS_RING +moduleName = geojson2ew + +################################################################################ +# PGD Properties # +################################################################################ +[PGD] +# Should PGD be processed? +do_pgd = 1 +# PGD tolerance in cm (must be positive) +dist_tolerance = 0.5 +# If PGD value falls below dist_tol this is the +# default PGD value given in cm (must be positive) +dist_default = 0.01 +#some search variables +deltaLatitude = 0.1 +deltaLongitude = 0.1 +nlats_in_pgd_gridSearch = 1 +nlons_in_pgd_gridSearch = 1 +ndepths_in_pgd_gridSearch = 10 +# These are the defaults: +pgd_window_vel = 3.0 +pgd_min_sites = 4 + +# Message throttling logic and related +# Lookup table for non-density corrected value to generate magnitude +# uncertainty based on time and magnitude +sigmaLookupFile = /app/gfast/run/params/M99.txt +# Lookup table for time-dependant PGD thresholds +# columns: time (s) | threshold (cm) | n stations +pgdThresholdLookupFile = /app/gfast/run/params/pgd_threshold_PW.txt +# Positional uncertainty thresholds for including peak displacement observations +# If not specified, allow any or NAN uncertainties +rawSigmaThresholdLookupFile = /app/gfast/run/params/raw_sigma_threshold_PW.txt +# If defined, don't send xml if pgd_sigma is greater than this value +pgd_sigma_throttle = 0.5 +# Message throttling logic +SA_mag_threshold = 6.0 +# Minimum and maximum thresholds for using pgd values in inversion (cm). Any +# values equal or outside these bounds will be ignored in the inversion. +minimum_pgd_cm = 0.0 +maximum_pgd_cm = 3500.0 +# Number of observations to be given the 'assoc=true' attribute, which is used +# by the ShakeAlert Solution Aggregator in associating algorithm messages. +max_assoc_stations = 6 + +################################################################################ +# CMT/Finite Fault Properties # +################################################################################ +[CMT] +# Should CMT be processed? +do_cmt = 0 +#some search variables +deltaLatitude = 0.1 +deltaLongitude = 0.1 +nlats_in_cmt_gridSearch = 1 +nlons_in_cmt_gridSearch = 1 +ndepths_in_cmt_gridSearch = 10 +# These are the defaults: +cmt_window_vel = 2.0 +cmt_min_sites = 4 +# Error window average must be positive +cmt_window_avg = 0.0 +# Error general CMT inversions not yet programmed +ldeviatoric_cmt = 1 + +################################################################################ +# FF/Finite Fault Properties # +################################################################################ +[FF] +# Should FF be processed? +do_ff = 0 +ff_number_of_faultplanes = 2 +# Number of fault patches along strike +ff_nstr = 10 +# Number of fault patches down dip +ff_ndip = 5 +# Min number of sites (must be greater than CMT) +ff_min_sites = 4 +# Error window velocity +ff_window_vel = 3.0 +# error window average time +ff_window_avg = 10.0 +ff_flen_pct = 10.0 +ff_fwid_pct = 10.0 + +################################################################################ +# ActiveMQ Properties # +################################################################################ +[ActiveMQ] +# ActiveMQ host:port +### amq_dm openwire 61616 +### amq_wp openwire 62616 +### amq_sa openwire 63616 +#URL for event trigger messages +originURL=tcp://localhost:63616 +# ActiveMQ topic to read event trigger messages from +originTopic=eew.agg.sa.data +#URL to publish event messages and heartbeats on +destinationURL=tcp://localhost:62616 +# ActiveMQ topic to publish events on. +destinationTopic = eew.alg.gfast.data +# ActiveMQ topic to publish heartbeats on +hbTopic=eew.alg.gfast.hb +# heartbeat interval +hbInterval=5 +# ActiveMQ username to access ElarmS messages +user=gfast +# ActiveMQ password to access ElarmS messages +password=[password] + +# connection settings +msReconnect = 500 +maxAttempts = 5 +msWaitForMessage = 10 + +maxMessages = 5 diff --git a/run/params/pgd_threshold_PW.txt b/run/params/pgd_threshold_PW.txt new file mode 100644 index 00000000..4b80f0fe --- /dev/null +++ b/run/params/pgd_threshold_PW.txt @@ -0,0 +1,15 @@ +20 18 3 +25 27 3 +30 37 3 +35 47 3 +40 56 3 +45 66 3 +50 75 3 +55 85 3 +60 94 3 +65 104 3 +70 114 3 +75 123 3 +80 133 3 +85 142 3 +90 152 3 \ No newline at end of file diff --git a/run/params/raw_sigma_threshold_PW.txt b/run/params/raw_sigma_threshold_PW.txt new file mode 100644 index 00000000..1305b825 --- /dev/null +++ b/run/params/raw_sigma_threshold_PW.txt @@ -0,0 +1 @@ +35 17 14 diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..58271b19 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,139 @@ +# Makefile for GFAST +EEWDIR = ../.. +include $(EEWDIR)/Make.include.$(shell uname) + +EW_INCL = -I$(EWDIR)/include +EWLIB = $(EWDIR)/lib + +DM_DIR = $(EEWDIR)/libs/dmlib +DM_LIB = $(DM_DIR)/libdm.a + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +# Used to add more information on program startup output +UFLAGS = -DBUILDER=\"$(BUILDER)\" + +SUBDIRS = activeMQ hdf5 traceBuffer core eewUtils xml dmlib +INCL = -I ../include $(ISCL_INCL) $(ACTIVEMQ_INCL) $(EW_INCL) $(HDF5_INCL) +EXE = gfast_eew +#gfast_playback +EWOBJS = $(EWLIB)/swap.o +OBJS = activeMQ/gfast_amq.a eewUtils/gfast_utils.a xml/gfast_xml.a core/gfast_core.a \ +traceBuffer/traceBuffer.a hdf5/hdf5.a activeMQ/gfast_amq.a dmlib/dmlibWrapper.cpp.o \ +$(EWOBJS) + +LIBS = $(EW_LIB) $(ISCL_LIB) $(INIPARSER_LIB) $(XML2_LIB) $(HDF5_LIB) $(COMPEARTH_LIB) \ +$(ACTIVEMQ_LIB) $(DM_LIB) $(APR_LIB) $(LAPACKE_LIB) $(CBLAS_LIB) $(FFTW_LIB) $(SSL_LIB) \ +$(XERCES_LIB) $(QLIB2_LIB) $(CRYPTO_LIB) $(EWLIB)/libew_mt.a + +SYSLIBS = -ldl -lm -lnsl -lrt -pthread -lz -lsz -lstdc++ + +%.o: %.c + $(cc) -c $< -o $@ $(UFLAGS) $(CFLAGS) $(DEBUG) $(INCL) + +all: $(SUBDIRS) $(EXE) +$(SUBDIRS): + $(MAKE) -C $@ + +.PHONY: $(SUBDIRS) + +gfast_playback: gfast_playback.o $(OBJS) + $(CC) -o $@ $(CCFLAGS) gfast_eew.o $(UFLAGS) $(OBJS) $(LIBS) $(SYSLIBS) + +gfast_eew: gfast_eew.o $(OBJS) + $(CC) -o $@ $(CCFLAGS) gfast_eew.o $(UFLAGS) $(OBJS) $(LIBS) $(SYSLIBS) + +activeMQ/gfast_amq.a: + make -C activeMQ lib + +eewUtils/gfast_utils.a: + make -C eewUtils lib + +xml/gfast_xml.a: + make -C xml lib + +core/gfast_core.a: + make -C core lib + +all: $(EXE) + +ids: $(ALL) + for dir in $(SUBDIRS) ; do \ + make -C $$dir ids ; \ + done + +rm-ids: $(ALL) + for dir in $(SUBDIRS) ; do \ + make -C $$dir rm-ids ; \ + done + +install: + for dir in $(SUBDIRS) ; do \ + make -C $$dir install ; \ + done + +clean: + -rm -f *.o $(EXE) + for dir in $(SUBDIRS) ; do \ + make -C $$dir clean ; \ + done + make -C $(TESTDIR) clean + +veryclean: cleandocs + for dir in $(SUBDIRS) ; do \ + make -C $$dir veryclean ; \ + done + +depend: + for dir in $(SUBDIRS) ; do \ + make -C $$dir depend ; \ + done + +TESTDIR = ./tests +ut: + make -C $(TESTDIR) ut +test: + make -C $(TESTDIR) test + +# coverage +INFODIR = $(EEWDIR)/coverage/info +COVDIR = $(EEWDIR)/coverage/html + +covdirs: + if [ ! -d "$(COVDIR)" ]; then mkdir -p $(COVDIR); fi + if [ ! -d "$(INFODIR)" ]; then mkdir -p $(INFODIR); fi + +coverage: cleancoverage covdirs buildcoverage runcoverage + genhtml $(INFODIR)/*.info -o $(COVDIR) -s --legend + +cleancoverage: + -rm -rf *.gcno *.gcda *.gcov *.info $(COVDIR) + make -C tests cleancoverage + for dir in $(SUBDIRS) ; do \ + make -C $$dir cleancoverage ; \ + done + +buildcoverage: + for dir in $(SUBDIRS) ; do \ + make -C $$dir buildcoverage ; \ + done + +runcoverage: + make -C tests runcoverage + +# documentation +DOCDIR=$(EEWDIR)/docs/gfast +docs: doxygen.conf + mkdir -p $(DOCDIR) + doxygen doxygen.conf + +cleandocs: + rm -rf $(DOCDIR) *.tag diff --git a/src/activeMQ/Makefile b/src/activeMQ/Makefile new file mode 100644 index 00000000..8e2275a7 --- /dev/null +++ b/src/activeMQ/Makefile @@ -0,0 +1,67 @@ +# Makefile for GFAST/src/activeMQ +# +EEWDIR = ../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = activeMQ.c.o activeMQ.cpp.o readIni.c.o +# ShakeAlertConsumer.cpp.o consumer.cpp.o +LIB = gfast_amq.a +DEBUG = -g +#CCFLAGS += -std=c++0x -O0 -D_REENTRANT -Dstatic_config + +INCL= -I ../../include $(APR_INCL) $(ACTIVEMQ_INCL) $(INIPARSER_INCL) $(ISCL_INCL) + +all: $(LIB) +lib: $(LIB) + +$(LIB): $(OBJS) + $(AR) $(LIB) $(OBJS) + +%.c.o: %.c + $(cc) -c $< -o $@ $(CFLAGS) $(DEBUG) $(INCL) +%.cpp.o: %.cpp + $(CXX) -c $< -o $@ $(CCFLAGS) $(DEBUG) $(INCL) + +ids: *.c *cpp *.h + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c *cpp *.h + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(LIB) + +veryclean: clean rm-ids cleandepend + +install: #no-op + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/activeMQ/ShakeAlertConsumer.cpp b/src/activeMQ/ShakeAlertConsumer.cpp new file mode 100644 index 00000000..ae614235 --- /dev/null +++ b/src/activeMQ/ShakeAlertConsumer.cpp @@ -0,0 +1,348 @@ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wdocumentation" +#pragma clang diagnostic ignored "-Wshadow-field-in-constructor" +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wunused-exception-parameter" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wextra-semi" +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Weverything" +#pragma clang diagnostic pop +#endif + +#include "gfast_core.h" +#include "ShakeAlertConsumer.h" + +ShakeAlertConsumer::ShakeAlertConsumer() { + return; +} + +ShakeAlertConsumer::~ShakeAlertConsumer() { + this->cleanup(); + return; +} + +void ShakeAlertConsumer::initialize(const string username, + const string password, + const string destination, + const string brokerURI, + bool useTopic = true, + bool clientAck = false, + bool luseListener = false, + int maxMessages = 5, + int verbose = 0) { + __connection = NULL; + __session = NULL; + __destination = NULL; + __consumer = NULL; + + __messageCount = 0; + __user = username; + __password = password; + __destURI = destination; + __brokerURI = brokerURI; + + __useTopic = useTopic; + __clientAck = clientAck; + __luseListener = luseListener; + __maxMessages = (maxMessages>0)?maxMessages:5; //error trap + __verbose = verbose; + __isInitialized = true; + __lconnected = false; + __textMessage = ""; + return; +} + +void ShakeAlertConsumer::startMessageListener() +{ + const char *fcnm = "ShakeAlertConsumer startMessageListener\0"; + try + { + // Create a connection factory + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Setting the broker URI: %s", + fcnm, __brokerURI.c_str()); + } + auto_ptr connectionFactory( + cms::ConnectionFactory::createCMSConnectionFactory(__brokerURI)); + + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Creating connection for username (%s)", + fcnm, __user.c_str()); + } + // Create a connection + __connection = connectionFactory->createConnection(__user.c_str(), + __password.c_str()); + connectionFactory.reset(); //destroy + + activemq::core::ActiveMQConnection *amqConnection; + amqConnection = + dynamic_cast(__connection); + if (amqConnection != NULL) + { + amqConnection->addTransportListener(this); + } + + __connection->setExceptionListener(this); + if (__connection == NULL) + { + LOG_DEBUGMSG("%s: Failed to start connection!", fcnm); + return; + } + if (__verbose > 2){LOG_DEBUGMSG("%s: Connection set", fcnm);} + + // Create a session + if (!__clientAck) + { + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Automatic message acknowledgement", fcnm); + } + __session + = __connection->createSession(cms::Session::AUTO_ACKNOWLEDGE); + } + else + { + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Client will acknowledge transaction", + fcnm); + } + __session + = __connection->createSession(cms::Session::SESSION_TRANSACTED); + } + // Create the destination (topic or queue) + if (__useTopic) + { + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Topic destination is %s", + fcnm, __destURI.c_str()); + } + __destination = __session->createTopic(__destURI); + } + else + { + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Queue destination is %s", + fcnm, __destURI.c_str()); + } + __destination = __session->createQueue(__destURI); + } + // Create a messageConsumer from the session + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Creating message consumer...", fcnm); + } + __consumer = __session->createConsumer(__destination); + if (__luseListener){ + __consumer->setMessageListener(this); + } + if (__verbose > 2){LOG_DEBUGMSG("%s: Starting connection", fcnm);} + __connection->start(); + if (__connection == NULL) + { + LOG_WARNMSG("%s: Failed to start connection!", fcnm); + return; + } + if (__verbose > 2){LOG_DEBUGMSG("%s: Connection set", fcnm);} + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: ActiveMQ consumer on-line...", fcnm); + } + __lconnected = true; + } + catch (cms::CMSException &e) + { + e.printStackTrace(); + } + return; +} // End startMessageListener + +void ShakeAlertConsumer::onMessage(const cms::Message *message) +{ + const char *fcnm = "ShakeAlertConsumer onMessage\0"; + string newmsg; + if (message == NULL){return;} //shouldn't happen + try + { + const cms::TextMessage *textMessage; + textMessage = dynamic_cast(message); + if (textMessage != NULL) + { + newmsg = textMessage->getText(); + // check if queue full and if so clean old messages + int ndel=__maxMessages-__messageBuffer.size()+1; + while (ndel>0) { + if (__verbose > 2) { + LOG_DEBUGMSG("%s: delete old msg to make space in messageBuffer", fcnm); + } + __messageBuffer.pop(); + } + __messageBuffer.push(newmsg); + if (__verbose > 2) { + LOG_DEBUGMSG("%s: Message received:\n%s", + fcnm, newmsg.c_str()); + } + } + if (__clientAck) + { + message->acknowledge(); + } + delete textMessage; + __messageCount = __messageCount + 1; + } + catch (cms::CMSException &e) + { + e.printStackTrace(); + } + return; +} + +bool ShakeAlertConsumer::isInitialized() +{ + return __isInitialized; +} + +int ShakeAlertConsumer::pollAMQ(const int ms_wait, int *ierr) +{ + const char *fcnm = "ShakeAlertConsumer pollAMQ\0"; + const cms::Message *message; + const cms::TextMessage *textMessage; + string text; + *ierr = 0; + if (__luseListener) { //set for asynchronous. Return n messages in buffer + return __messageBuffer.size(); + } + if (! __lconnected) + { + LOG_ERRMSG("%s: The listener isn't connected!", fcnm); + *ierr = 1; + return 0; + } + // Check my mail + do { + if (ms_wait > 0) + { + message = __consumer->receive(ms_wait); + } + else + { + message = __consumer->receiveNoWait(); + } + textMessage = dynamic_cast(message); + // If I have a message then push to messageBuffer + if (textMessage != NULL) + { + text = textMessage->getText(); + if (__messageBuffer.size()==__maxMessages) { + if (__verbose > 2) { + LOG_WARNMSG("%s: delete old msg to make space in messageBuffer", fcnm); + } + __messageBuffer.pop(); + } + __messageBuffer.push(text); + } + } + while (textMessage != NULL); + delete message; + return __messageBuffer.size(); +} + +char *ShakeAlertConsumer::getMessage() +{ + char *charMessage = NULL; + string msgstr; + size_t lenos; + + if (! __messageBuffer.empty()) { + msgstr=__messageBuffer.front(); + lenos = strlen(msgstr.c_str()); + charMessage = static_cast(calloc(lenos+1, sizeof(char))); + memset(charMessage, 0, lenos+1); + strcpy(charMessage, msgstr.c_str()); + __messageBuffer.pop(); + } + return charMessage; +} + +void ShakeAlertConsumer::onException(const cms::CMSException& ex AMQCPP_UNUSED) +{ + LOG_ERRMSG("%s", + "CMS Exception occurred. Shutting down client."); + ex.printStackTrace(); + exit(1); // This looks dangerous +} + +void ShakeAlertConsumer::cleanup() +{ + const char *fcnm = "cleanup\0"; + + if (!__isInitialized) + { + LOG_WARNMSG("%s: Program was never initialized", fcnm); + } + if (__verbose > 0) + { + LOG_MSG("%s: Closing consumer...", fcnm); + } + // Close the connection + try + { + if (__connection != NULL){__connection->close();} + } + catch (cms::CMSException &e) + { + e.printStackTrace(); + } + // Close the session + try + { + if (__session != NULL){__session->close();} + } + catch (cms::CMSException &e) + { + e.printStackTrace(); + } + // Free destination + try + { + if (__destination != NULL){ + delete __destination; + __destination = NULL; + delete __consumer; + __consumer = NULL; + delete __session; + __session = NULL; + } + } + catch (cms::CMSException& e) + { + e.printStackTrace(); + } + // Reset internal variables + __isInitialized = false; + __lconnected = false; + __messageCount = 0; + __user = ""; + __password = ""; + __brokerURI = ""; + __destURI = ""; + + __useTopic = true; + __clientAck = false; + __luseListener = false; + __verbose = 0; + __isInitialized = false; + __lconnected = false; + __textMessage = ""; + return; +} diff --git a/src/activeMQ/ShakeAlertConsumer.h b/src/activeMQ/ShakeAlertConsumer.h new file mode 100644 index 00000000..3a7b4c3f --- /dev/null +++ b/src/activeMQ/ShakeAlertConsumer.h @@ -0,0 +1,175 @@ +#ifndef _ShakeAlertConsumer_h_ +#define _ShakeAlertConsumer_h_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "gfast_activeMQ.h" + +using namespace std; +/*! + * @brief GFAST ActiveMQ message consumer class + * Interface class between GFAST c code and activemqcpp library + */ +class ShakeAlertConsumer : public cms::ExceptionListener, + public cms::MessageListener, + public activemq::transport::DefaultTransportListener +{ +private: + // AMQ private variables + cms::Connection *__connection; + cms::Session *__session; + cms::Destination *__destination; + cms::MessageConsumer *__consumer; + activemq::core::ActiveMQConnection *amqConnection; + string __user; + string __password; + string __destURI; + string __brokerURI; + string __textMessage; + long __messageCount; + int __verbose; + bool __useTopic; + bool __clientAck; + bool __luseListener; + bool __isInitialized; + bool __lconnected; + queue __messageBuffer; //!< buffer containing unprocessed messages + unsigned int __maxMessages; //!< maximum number of messages in messageBuffer + +public: + /*! + @brief Simple constructor + */ + ShakeAlertConsumer(); + + /*! + @brief Simple destructor + */ + ~ShakeAlertConsumer(); + + /*! + * @brief Initializes the internal variables for the ActiveMQ message + * listener. + * + * @param[in] username Authenticating user name. + * @param[in] password Authenticating user password. + * @param[in] destination Queue or topic name on the broker. + * @param[in] brokerURI URI of message broker. + * @param[in] useTopic If true then the message receiver connects + * to a topic (default). + * If false then the message receiver connects + * to a queue. + * @param[in] clientAck If true then the session will acknowledge + * a message has been received. + * If false then the session automatically + * acknowledges a client's receipt of a message + * either when the session has successfully + * returned from a call to receive or when the + * session's message listener has successfully + * processed the message (default). + * If true then the session is transacted + * and the acknowledgement of messages is + * handled internally. + * @param[in] luseListener If false then you must actively check your + * messages (default). + * If true then use a message listener - + * this is useful when the driving program + * language is threaded and/or uses triggers. + * @param[in] maxMessages Maximum number of messages in local queue (default 5). + * @param[in] verbose Controls the verbosity - use 0 for reporting + * of errors only. Default=0. + * + */ + void initialize(const string username, + const string password, + const string destination, + const string brokerURI, + bool useTopic, + bool clientAck, + bool luseListener, + int maxMessages, + int verbose); + + /*! + * @brief Starts the message listener. To use this you must first + * initialize the private variables with the initialize() + * function. This is similar to the decision module's + * DMMessageReceiver. + */ + void startMessageListener(); + + /*! + * @brief Called in asynchronous configurations when new message arrives on listener. + * New messages are pushed onto messageBuffer queue. + * + * @param[in] message ActiveMQ Message type which can be NULL. + * + */ + virtual void onMessage(const cms::Message *message); + + /*! + * @brief Convenience function to determine if the class was + * initialized. + * + * @result If true then the class was initialized. + * + * @author Ben Baker (ISTI) + * + */ + bool isInitialized(); + + /*! + * @brief Synchronous poll of ActiveQ topic. + * Checks if message is on topic and returns after ms_wait milliseconds + * with or without message. Can currently handle only one message per call. + * + * @param[in] ms_wait Number of milliseconds to wait for a message + * prior to returning. If 0 (default) + * then the function will not wait. + * + * @param[out] ierr 0 indicates success. + * + * @result number of messages received. + */ + int pollAMQ(const int ms_wait, int *ierr); + + /* @brief pop oldest message off of messageBuffer stack. + * + * @result If NULL there is no message. Otherwise, this is the NULL + * terminated char * message from the AMQ listener. + * + */ + char *getMessage(); + + /*! + * @brief In asynchronous implementations, method will be called on exception. + * This class is registered as an ExceptionListener with the connection. + */ + virtual void onException(const cms::CMSException& ex AMQCPP_UNUSED); + + private: + /*! + * @brief Private function which frees and resets ActiveMQ variables + * prior to the final AMQ shutdownLibrary call. + */ + void cleanup(); +}; + +#endif diff --git a/src/activeMQ/ShakeAlertProducer.cpp b/src/activeMQ/ShakeAlertProducer.cpp new file mode 100644 index 00000000..345f5129 --- /dev/null +++ b/src/activeMQ/ShakeAlertProducer.cpp @@ -0,0 +1,303 @@ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wdocumentation" +#pragma clang diagnostic ignored "-Wshadow-field-in-constructor" +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wunused-exception-parameter" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wextra-semi" +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Weverything" +#pragma clang diagnostic pop +#endif + +#include "gfast_core.h" +#include "ShakeAlertProducer.h" + +using namespace decaf::lang; +using namespace activemq::core; +using namespace activemq::transport; +using namespace activemq::util; +using namespace cms; +using namespace std; + +ShakeAlertProducer::ShakeAlertProducer() { + __isInitialized = false; + return; +} + +ShakeAlertProducer::~ShakeAlertProducer() { + this->cleanup(); + return; +} + +void ShakeAlertProducer::initialize(const string username, + const string password, + const string destination, + const string brokerURI, + bool useTopic = true, + bool sessionTransacted = false, + int verbose = 0) { + __connection = NULL; + __session = NULL; + __destination = NULL; + __producer = NULL; + + __messageCount = 0; + __user = username; + __password = password; + __destURI = destination; + __brokerURI = brokerURI; + + __useTopic = useTopic; + __sessionTransacted = sessionTransacted; + __verbose = verbose; + __isInitialized = true; + __lconnected = false; + __lhaveMessage = false; + __textMessage = ""; + memset(__pad, 0, sizeof(__pad)); + return; +} + +bool ShakeAlertProducer::isInitialized(void) +{ + return __isInitialized; +} + +void ShakeAlertProducer::startMessageSender() +{ + const char *fcnm = "ShakeAlertSender startMessageSender\0"; + try + { + // Create a connection factory + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Setting the broker URI: %s", + fcnm, __brokerURI.c_str()); + } + auto_ptr connectionFactory( + cms::ConnectionFactory::createCMSConnectionFactory(__brokerURI)); + + connectionFactory.reset(); //destroy + + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Creating connection for username (%s)", + fcnm, __user.c_str()); + } + // Create a connection + __connection = connectionFactory->createConnection(__user.c_str(), + __password.c_str()); + + __connection->setExceptionListener(this); + if (__connection == NULL) + { + LOG_WARNMSG("%s: Failed to start connection!", fcnm); + return; + } + + // Create a session + if (!__sessionTransacted) + { + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Automatic message acknowledgement", fcnm); + } + __session + = __connection->createSession(cms::Session::AUTO_ACKNOWLEDGE); + } + else + { + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Session will acknowledge transaction", + fcnm); + } + __session + = __connection->createSession(cms::Session::SESSION_TRANSACTED); + } + if (__session == NULL) + { + LOG_ERRMSG("%s: Error session not made", fcnm); + return; + } + // Create the destination (topic or queue) + if (__useTopic) + { + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Topic destination is %s", + fcnm, __destURI.c_str()); + } + __destination = __session->createTopic(__destURI); + } + else + { + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: Queue destination is %s", + fcnm, __destURI.c_str()); + } + __destination = __session->createQueue(__destURI); + } + // Create a messageConsumer from the session + if (__verbose > 2) + { + LOG_MSG("%s: Creating message producer...", fcnm); + } + __producer = __session->createProducer(__destination); + + if (__verbose > 2){LOG_DEBUGMSG("%s: Starting connection", fcnm);} + __connection->start(); + if (__connection == NULL) + { + LOG_WARNMSG("%s: Failed to start connection!", fcnm); + return; + } + if (__verbose > 2){LOG_DEBUGMSG("%s: Connection set", fcnm);} + + if (__verbose > 2) + { + LOG_DEBUGMSG("%s: ActiveMQ producer on-line...", fcnm); + } + __lconnected = true; + + } + catch (cms::CMSException &e) + { + e.printStackTrace(); + } + return; +} + +int ShakeAlertProducer::sendMessage(const char *message) +{ + const char *fcnm = "ShakeAlertSender sendMessage\0"; + if (!__isInitialized) + { + LOG_ERRMSG("%s: Producer not yet initialized", fcnm); + return -1; + } + if (!__lconnected) + { + LOG_ERRMSG("%s: Producer not yet connected", fcnm); + return -1; + } + if (message == NULL) + { + LOG_WARNMSG("%s: NULL message!", fcnm); + return -1; + } + string msg = string(message); + cms::TextMessage *amqMessage = __session->createTextMessage(msg); + __producer->send(amqMessage); + delete amqMessage; + return 0; +} + +/* +int ShakeAlertProducer::sendBytesMessage(const unsigned char *cbytes, + int bsize) +{ + cms::BytesMessage message = __session->createBytesMessage(cbytes,bsize); + __producer->send(message); + delete message; + return 0; +} +*/ + +void ShakeAlertProducer::onException(const cms::CMSException& ex AMQCPP_UNUSED) +{ + LOG_ERRMSG("%s", + "CMS Exception occurred. Shutting down client."); + ex.printStackTrace(); + exit(1); // This looks dangerous +} + +void ShakeAlertProducer::cleanup() +{ + const char *fcnm = "cleanup\0"; + if (__verbose > 0) + { + LOG_MSG("%s: Closing producer...", fcnm); + } + if (!__isInitialized) + { + LOG_WARNMSG("%s: Program was never initialized", fcnm); + } + + // Close the connection + try + { + if (__connection != NULL){ + __connection->close(); + } + } + catch (cms::CMSException &e) + { + e.printStackTrace(); + } + + // Free destination + try + { + if (__destination != NULL){ + delete __destination; + } + } + catch (cms::CMSException& e) + { + e.printStackTrace(); + } + __destination = NULL; + // Free producer + try + { + if (__producer != NULL){delete __producer;} + } + catch (cms::CMSException &e) + { + e.printStackTrace(); + } + __producer = NULL; + // Close the session + try + { + if (__session != NULL) + { + __session->close(); + } + } + catch (cms::CMSException &e) + { + e.printStackTrace(); + } + __session = NULL; + + delete __connection; + __connection = NULL; + + // Reset internal variables + __isInitialized = false; + __lconnected = false; + __messageCount = 0; + __user = ""; + __password = ""; + __brokerURI = ""; + __destURI = ""; + + __useTopic = true; + __sessionTransacted = false; + __verbose = 0; + __isInitialized = false; + __lconnected = false; + __lhaveMessage = false; + __textMessage = ""; + + return; +} diff --git a/src/activeMQ/ShakeAlertProducer.h b/src/activeMQ/ShakeAlertProducer.h new file mode 100644 index 00000000..d4c1bf1e --- /dev/null +++ b/src/activeMQ/ShakeAlertProducer.h @@ -0,0 +1,145 @@ +#ifndef _ShakeAlertProducer_h_ +#define _ShakeAlertProducer_h_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gfast_activeMQ.h" + +using namespace std; + +/*! + * @brief GFAST ActiveMQ message producer class + * Interface class between GFAST c code and activemqcpp library + */ +class ShakeAlertProducer : public cms::ExceptionListener +{ +private: + cms::Connection *__connection; + cms::Session *__session; + cms::Destination *__destination; + cms::MessageProducer *__producer; + string __user; + string __password; + string __destURI; + string __brokerURI; + string __textMessage; + size_t __messageCount; + int __verbose; + bool __useTopic; + bool __sessionTransacted; + bool __isInitialized; + bool __lconnected; + bool __lhaveMessage; + char __pad[7]; + +public: + /*! + @brief Simple constructor + */ + ShakeAlertProducer(); + + /*! + @brief Simple destructor + */ + ~ShakeAlertProducer(); + + /*********************************************************************/ + /*! + * @brief Initializes the internal variables for the ActiveMQ message + * listener. + * + * @param[in] username Authenticating user name. + * @param[in] password Authenticating user password. + * @param[in] destination Queue or topic name on the broker. + * @param[in] brokerURI URI of message broker. + * @param[in] useTopic If true then the message receiver connects + * to a topic (default). + * If false then the message receiver connects + * to a queue. + * @param[in] sessionTransacted Look this up. Default=False + * @param[in] verbose Controls the verbosity - use 0 for reporting + * of errors only. Default=0. + */ + void initialize(const string username, + const string password, + const string destination, + const string brokerURI, + bool useTopic, + bool sessionTransacted, + int verbose); + + /*! + * @brief Convenience function to determine if the class was + * initialized. + * + * @result If true then the class was initialized. + * + * @author Ben Baker (ISTI) + * + */ + bool isInitialized(void); + + /*! + * @brief Starts the message sender. To use this you must first + * initialize the private variables with the initialize() + * function. This is similar to the decision module's + * DMMessageSender. + */ + void startMessageSender(); + + /*! + * @brief Sends a text message. + * + * @param[in] message Message to send. + * + * @result 0 indicates success. + * + */ + int sendMessage(const char *message); + + /* + / *! + * @brief Sends a bytes message. + * + * @param[in] cbytes pointer to bytes array. + * @param[in] bsize length of cbytes + * + * @result 0 indicates success. + * + * / + int sendBytesMessage(const unsigned char *cbytes, int bsize); + */ + + /*! + * @brief In asynchronous implementations, method will be called on exception. + * This class is registered as an ExceptionListener with the connection. + */ + virtual void onException(const cms::CMSException& ex AMQCPP_UNUSED); + +private: + + /*! + * @brief Private function which frees and resets ActiveMQ variables + * prior to the final AMQ shutdownLibrary call. + */ + void cleanup(); +}; + +#endif diff --git a/src/activeMQ/activeMQ.c b/src/activeMQ/activeMQ.c new file mode 100644 index 00000000..d80cc5bf --- /dev/null +++ b/src/activeMQ/activeMQ.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include "gfast_activeMQ.h" +#include "gfast_core.h" + +/*! static variable to keep track of whether activeMQCPP library has been initialized */ +static bool isinit = false; + +/*! @brief Initialize activeMQCPP library */ +void activeMQ_start(void) +{ + if (isinit) + { + LOG_MSG("%s", "activeMQ_start: Library already initialized"); + return; + } + activeMQ_initialize(); + isinit = true; +} + +/*! @brief Shut down activeMQCPP library */ +void activeMQ_stop(void) +{ + if (!isinit) + { + LOG_MSG("%s", "activeMQ_stop: Library already shut down"); + return; + } + activeMQ_finalize(); + isinit = false; + return; +} + +/*! @brief simple utility function to access activeMQCPP library state */ +bool activeMQ_isInit(void) +{ + return isinit; +} +//============================================================================// +/*! + * @brief Sets the tcp URI from the host name, port number, max milliseconds + * for a reconnect, and max number of attempts to connect. + * + * @param[in] AMQurl url pointing to target host and port (e.g. tcp://localhost:61616). + * @param[in] msReconnect Number of milliseconds to wait for a reconnect + * attempt. If 0 or if maxAttempts is 0 then this + * command will be ignored. + * @param[in] maxAttempts Number of attempts to connect before giving up + * if 0 this command will be ignored. + * + * @result tcp URI request for ActiveMQ connection. + * + */ +char *activeMQ_setTcpURIRequest(const char *AMQurl, + const int msReconnect, + const int maxAttempts) +{ + char *uri = NULL; + char cwork[4096], cbuff[64]; + memset(cwork, 0, sizeof(cwork)); + memset(cbuff, 0, sizeof(cbuff)); + strcpy(cwork, "failover:(\0"); + strcat(cwork, AMQurl); + strcat(cwork, ")\0"); + // Max milliseconds for reconnect + if (msReconnect > 0 && maxAttempts > 0) + { + memset(cbuff, 0, sizeof(cbuff)); + sprintf(cbuff, "%d", msReconnect); + strcat(cwork, "?initialReconnectDelay=\0"); + strcat(cwork, cbuff); + } + // Max number of attempts + if (maxAttempts > 0) + { + memset(cbuff, 0, sizeof(cbuff)); + sprintf(cbuff, "%d", maxAttempts); + strcat(cwork, "?startupMaxReconnectAttempts=\0"); + strcat(cwork, cbuff); + } + uri = (char *)malloc((strlen(cwork)+1)*sizeof(char)); + memset(uri, 0, strlen(cwork)+1); + strcpy(uri, cwork); + return uri; +} diff --git a/src/activeMQ/activeMQ.cpp b/src/activeMQ/activeMQ.cpp new file mode 100644 index 00000000..02dc45c0 --- /dev/null +++ b/src/activeMQ/activeMQ.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include "gfast_activeMQ.h" +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wdocumentation" +#pragma clang diagnostic ignored "-Wshadow-field-in-constructor" +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wunused-exception-parameter" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wextra-semi" +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Weverything" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +/*! @brief c wrapper on activeMQCPP library initialization */ +extern "C" void activeMQ_initialize(void) +{ + activemq::library::ActiveMQCPP::initializeLibrary(); + return; +} + +/*! @brief c wrapper on activeMQCPP library shutdown */ +extern "C" void activeMQ_finalize(void) +{ + activemq::library::ActiveMQCPP::shutdownLibrary(); + return; +} + diff --git a/src/activeMQ/consumer.cpp b/src/activeMQ/consumer.cpp new file mode 100644 index 00000000..66eece84 --- /dev/null +++ b/src/activeMQ/consumer.cpp @@ -0,0 +1,208 @@ +/*! @file consumer.cpp + * @brief Wrapper functions to allow c programs to access ShaleAlertConsumer + * c++ class. + */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wdocumentation" +#pragma clang diagnostic ignored "-Wshadow-field-in-constructor" +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wunused-exception-parameter" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wextra-semi" +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Weverything" +#pragma clang diagnostic pop +#endif + +#include +#include +#include +#include +#include "gfast_activeMQ.h" +#include "gfast_core.h" +#include "ShakeAlertConsumer.h" + +//static bool linit_amqlib = false; + +/*! + * @brief C interface function to initialize a ShakeAlertConsumer class instance + * decision module message listener. This function must be called + * first. + * + * This is a AMQ connection strategy which will be deprecated in the future in favor of dmlib. + * + * @param[in] AMQuser Authenticating username. + * @param[in] AMQpassword Authenticating password. + * @param[in] AMQurl URL string specifying target broker host and port (e.g. tcp://localhost:61616) + * @param[in] AMQdestination Queue or topic name on the broker. + * @param[in] msReconnect Number of milliseconds to wait for a reconnect + * attempt. If 0 or if maxAttempts is 0 then this + * command will be ignored. + * @param[in] maxAttempts Number of attempts to connect before giving up. + * If 0 this command will be ignored. + * @param[in] useTopic If true then the message receiver connects + * to a topic (default). + * If false then the message receiver connects + * to a queue. + * @param[in] clientAck If true then the session will acknowledge + * a message has been received. + * If false then the session automatically + * acknowledges a client's receipt of a message + * either when the session has successfully + * returned from a call to receive or when the + * session's message listener has successfully + * processed the message (default). + * If true then the session is transacted + * and the acknowledgement of messages is + * handled internally. + * @param[in] luseListener If false then you must actively check your + * messages (default). + * If true then use a message listener - + * this is useful when the driving program + * language is threaded and/or uses triggers. + * @param[in] maxMessages Max number of messages in local message buffer + * @param[in] verbose controls verobosity. + * + * @param[out] ierr 0 indicates success\n + * 1 indicates an internal error has occurred. + * + * @return pointer to ShakeAlertConsumer class instance cast to (void *) so it can be passed in c. + * + * @author Ben Baker, ISTI + * + */ +extern "C" void *activeMQ_consumer_initialize(const char AMQuser[], + const char AMQpassword[], + const char AMQurl[], + const char AMQdestination[], + const int msReconnect, + const int maxAttempts, + const bool useTopic, + const bool clientAck, + const bool luseListener, + const unsigned int maxMessages, + const int verbose, + int *ierr) +{ + const char *fcnm = "activeMQ_consumer_initialize\0"; + ShakeAlertConsumer *consumer = NULL; + string brokerURI, destination, password, username; + *ierr = 0; + if (AMQuser != NULL) + { + username = string(AMQuser); + } + else + { + username = ""; + } + if (AMQpassword != NULL) + { + password = string(AMQpassword); + } + else + { + password = ""; + } + if (AMQdestination != NULL) + { + destination = string(AMQdestination); + } + else + { + destination = ""; + } + // Set the URI + char *brokerURIchar; + brokerURIchar = activeMQ_setTcpURIRequest(AMQurl,msReconnect, maxAttempts); + brokerURI = string(brokerURIchar); + delete[] brokerURIchar; + // Make sure the library is initialized + if (!activeMQ_isInit()) + { + activeMQ_start(); + } + if (verbose > 0) + { + LOG_DEBUGMSG("%s: Initializing the consumer...", fcnm); + } + consumer = new ShakeAlertConsumer; + consumer->initialize(username, password, destination, brokerURI, + useTopic, clientAck, luseListener, maxMessages, + verbose); + consumer->startMessageListener(); + if (!consumer->isInitialized()) + { + LOG_ERRMSG("%s: Failed to initialize consumer", fcnm); + // fprintf(stderr, "%s: Failed to initialize consumer\n", fcnm); + *ierr = 1; + delete consumer; + consumer = NULL; + } + brokerURI = ""; + destination = ""; + password = ""; + username = ""; + return static_cast (consumer); +} +//============================================================================// +/*! + * @brief C interface function to destroy the ActiveMQ listener. + * + * @author Ben Baker, ISTI + * + */ +extern "C" void activeMQ_consumer_finalize(void *consumerIn) +{ + ShakeAlertConsumer *consumer = NULL; + consumer = static_cast (consumerIn); + delete consumer; + return; +} +//============================================================================// +/*! + * @brief Polls ActiveMQ for new messages and returns oldest message in local queue. + * + * @param[in] consumerIn Pointer to a ShakeAlertConsumer to use for getting messages + * @param[in] ms_wait Number of milliseconds to wait for a message. If 0 + * then it will not wait. + * + * @param[out] ierr 0 indicates success (note a successful call can return + * no message). \n + * 1 indicates an internal error has occurred. + * + * @result On successful exit either is NULL to indicate there are no messages + * or contains a null terminated char * shakeAlert decision module + * message. + */ +extern "C" char *activeMQ_consumer_getMessage(void *consumerIn, + const int ms_wait, int *ierr) +{ + const char *fcnm = "activeMQ_consumer_getMessage\0"; + char *message = NULL; + ShakeAlertConsumer *consumer = NULL; + int nmsg; + *ierr = 0; + consumer = static_cast (consumerIn); + if (!consumer->isInitialized()) + { + *ierr = 1; + LOG_ERRMSG("%s: Error consumer never initialized", fcnm); + consumer = NULL; + return message; + } + nmsg = consumer->pollAMQ(ms_wait, ierr); + if (nmsg>0) message = consumer->getMessage(); + if (*ierr != 0) + { + LOG_ERRMSG("%s: Error getting message", fcnm); + } + consumer = NULL; + return message; +} + diff --git a/src/activeMQ/producer.cpp b/src/activeMQ/producer.cpp new file mode 100644 index 00000000..d7b53ac9 --- /dev/null +++ b/src/activeMQ/producer.cpp @@ -0,0 +1,171 @@ +/*! @file producer.cpp + * @brief Wrapper functions to allow c programs to access ShaleAlertProducer + * c++ class. + */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wdocumentation" +#pragma clang diagnostic ignored "-Wshadow-field-in-constructor" +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wunused-exception-parameter" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wextra-semi" +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Weverything" +#pragma clang diagnostic pop +#endif + +#include +#include +#include +#include +#include "gfast_activeMQ.h" +#include "gfast_core.h" +#include "ShakeAlertProducer.h" + +//static ShakeAlertProducer producer; +//static bool linit_amqlib = false; + +/*! + * @brief C interface function to initialize the ActiveMQ producer. + * This function must be called prior to any other functions in this + * class. + * + * This is a AMQ connection strategy which is deprecated in current SA in favor of dmlib. + * + * @param[in] AMQuser Authenticating username. + * @param[in] AMQpassword Authenticating password. + * @param[in] AMQurl URL string specifying target broker host and port (e.g. tcp://localhost:61616) + * @param[in] AMQdestination Queue or topic name on the broker. + * @param[in] useTopic If true then the message receiver connects + * to a topic (default). + * If false then the message receiver connects + * to a queue. + * @param[in] clientAck If true then the session will acknowledge + * a message has been received. + * If false then the session automatically + * acknowledges a client's receipt of a message + * either when the session has successfully + * returned from a call to receive or when the + * session's message listener has successfully + * processed the message (default). + * If true then the session is transacted + * and the acknowledgement of messages is + * handled internally. + * @param[in] verbose Controls verobosity. 0 is quiet. + * + * @param[in] ierr 0 indicates success\n + * 1 indicates an internal error has occurred. + * + * @return pointer to ShakeAlertProducer class instance cast to (void *) so it can be passed in c. + * + * @author Ben Baker, ISTI + * + */ +extern "C" void *activeMQ_producer_initialize(const char AMQuser[], + const char AMQpassword[], + const char AMQurl[], + const char AMQdestination[], + const bool useTopic, + const bool clientAck, + const int verbose, + int *ierr) +{ + const char *fcnm = "activeMQ_producer_initialize\0"; + ShakeAlertProducer *producer = NULL; + string brokerURI, destination, password, username; + *ierr = 0; + if (AMQuser != NULL) + { + username = AMQuser; + } + else + { + username = ""; + } + if (AMQpassword != NULL) + { + password = AMQpassword; + } + else + { + password = ""; + } + if (AMQdestination != NULL) + { + destination = AMQdestination; + } + else + { + destination = ""; + } + // Give the producer a unique name + //string prodID = IdGenerator().generateId(); + // Set the URI + char *brokerURIchar; + brokerURIchar = activeMQ_setTcpURIRequest(AMQurl, 0 , 0); + brokerURI = string(brokerURIchar); + delete[] brokerURIchar; + // Make sure the library is initialized + if (!activeMQ_isInit()){activeMQ_start();} + if (verbose > 0) + { + LOG_MSG("%s: Initializing the producer...", fcnm); + } + producer = new ShakeAlertProducer; + producer->initialize(username, password, destination, brokerURI, + useTopic, clientAck, verbose); + producer->startMessageSender(); + if (!producer->isInitialized()) + { + LOG_WARNMSG("%s: Failed to initialize the producer", fcnm); + *ierr = 1; + } + brokerURI = ""; + return static_cast (producer); +} + +/*! + * @brief C interface function to destroy the ActiveMQ producer. + * + * @author Ben Baker, ISTI + * + */ +extern "C" void activeMQ_producer_finalize(void *producerIn) +{ + ShakeAlertProducer *producer = NULL; + producer = static_cast (producerIn); + delete producer; + return; +} + +/*! + * @brief C interface function to send a message. + * + * @param[in] producerIn Handle to the ActiveMQ message broker. + * @param[in] message Message to send. + * + * @result 0 indicates success. + * + * @author Ben Baker, ISTI + * + */ +extern "C" int activeMQ_producer_sendMessage(void *producerIn, + const char *message) +{ + const char *fcnm = "activeMQ_producer_sendMessage\0"; + ShakeAlertProducer *producer = NULL; + int ierr; + producer = static_cast (producerIn); + ierr = producer->sendMessage(message); + producer = NULL; + if (ierr != 0) + { + LOG_ERRMSG("%s: Error sending message", fcnm); + } + return ierr; +} diff --git a/src/activeMQ/readIni.c b/src/activeMQ/readIni.c new file mode 100644 index 00000000..a1c4b74a --- /dev/null +++ b/src/activeMQ/readIni.c @@ -0,0 +1,180 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_core.h" +#include "gfast_activeMQ.h" +#include "iscl/os/os.h" + +static void setVarName(const char *group, const char *variable, + char *var) +{ + memset(var, 0, 256*sizeof(char)); + sprintf(var, "%s:%s", group, variable); + return; +} +/*! + * @brief Reads the ActiveMQ properties from the initialization file. + * + * @param[in] propfilename Name of properties file. + * @param[in] group Group in ini file. Likely "ActiveMQ". + * + * @param[out] activeMQ_props ActiveMQ properties. + * + * @result 0 indicates success. + * + * @author Ben Baker (ISTI) + * + */ +int activeMQ_readIni(const char *propfilename, + const char *group, + struct GFAST_activeMQ_struct *activeMQ_props) +{ + const char *s; + char var[256]; + int ierr; + dictionary *ini; + ierr = 1; + memset(activeMQ_props, 0, sizeof(struct GFAST_activeMQ_struct)); + if (!os_path_isfile(propfilename)) + { + LOG_ERRMSG("%s: Properties file: %s does not exist\n", + __func__, propfilename); + return ierr; + } + ini = iniparser_load(propfilename); + // Read the properties + setVarName(group, "originURL\0", var); + s = iniparser_getstring(ini, var, NULL); + if (s == NULL) + { + LOG_ERRMSG("%s: Could not find ActiveMQ originURL!\n", __func__); + goto ERROR; + } + else + { + strcpy(activeMQ_props->originURL, s); + } + + setVarName(group, "destinationURL\0", var); + s = iniparser_getstring(ini, var, NULL); + if (s == NULL) + { + LOG_ERRMSG("%s: Could not find ActiveMQ destinationURL!\n", __func__); + goto ERROR; + } + else + { + strcpy(activeMQ_props->destinationURL, s); + } + + setVarName(group, "user\0", var); + s = iniparser_getstring(ini, var, NULL); + if (s == NULL) + { + LOG_ERRMSG("%s: Could not find ActiveMQ user!\n", __func__); + goto ERROR; + } + else + { + strcpy(activeMQ_props->user, s); + } + + setVarName(group, "password\0", var); + s = iniparser_getstring(ini, var, NULL); + if (s == NULL) + { + LOG_ERRMSG("%s: Could not find password!\n", __func__); + goto ERROR; + } + else + { + strcpy(activeMQ_props->password, s); + } + + setVarName(group, "originTopic\0", var); + s = iniparser_getstring(ini, var, NULL); + if (s == NULL) + { + LOG_ERRMSG("%s: Could not find activeMQ originTopic\n", __func__); + goto ERROR; + } + else + { + strcpy(activeMQ_props->originTopic, s); + } + + setVarName(group, "destinationTopic\0", var); + s = iniparser_getstring(ini, var, NULL); + if (s == NULL) + { + LOG_ERRMSG("%s: Could not find ActiveMQ destinationTopic!\n",__func__); + goto ERROR; + } + else + { + strcpy(activeMQ_props->destinationTopic, s); + } + + setVarName(group, "hbTopic\0", var); + s = iniparser_getstring(ini, var, NULL); + if (s == NULL) + { + LOG_ERRMSG("%s: Could not find ActiveMQ hbTopic!\n", + __func__); + goto ERROR; + } + else + { + strcpy(activeMQ_props->hbTopic, s); + } + setVarName(group, "hbInterval\0", var); + activeMQ_props->hbInterval = iniparser_getint(ini, var, 5); + if (activeMQ_props->hbInterval < 0) + { + LOG_ERRMSG("%s: hbInterval = %d not usable \n", __func__,activeMQ_props->hbInterval); + goto ERROR; + } + setVarName(group, "msReconnect\0", var); + activeMQ_props->msReconnect = iniparser_getint(ini, var, 500); + if (activeMQ_props->msReconnect < 0) + { + LOG_WARNMSG("%s: Overriding msReconnect to 500\n", __func__); + activeMQ_props->msReconnect = 500; + } + setVarName(group, "maxAttempts\0", var); + activeMQ_props->maxAttempts = iniparser_getint(ini, var, 5); + if (activeMQ_props->maxAttempts < 0) + { + LOG_WARNMSG("%s: Overriding maxAttempts to 5\n", __func__); + activeMQ_props->maxAttempts = 5; + } + setVarName(group, "msWaitForMessage\0", var); + activeMQ_props->msWaitForMessage = iniparser_getint(ini, var, 1); + if (activeMQ_props->msWaitForMessage < 0) + { + LOG_WARNMSG("%s: ActiveMQ could hang indefinitely, overriding to 1\n", + __func__); + activeMQ_props->msWaitForMessage = 1; + } + setVarName(group, "maxMessages\0", var); + activeMQ_props->maxMessages = iniparser_getint(ini, var, 5); + if (activeMQ_props->maxMessages <= 0) + { + LOG_WARNMSG("%s: ActiveMQ message buffer must be >0, overriding to 5\n", + __func__); + activeMQ_props->maxMessages = 5; + } + + ierr = 0; + ERROR:; + iniparser_freedict(ini); + return ierr; +} diff --git a/src/core/Makefile b/src/core/Makefile new file mode 100644 index 00000000..e82119e3 --- /dev/null +++ b/src/core/Makefile @@ -0,0 +1,82 @@ +# Makefile for GFAST/src/core + +EEWDIR = ../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +SDIRS = cmt data events ff log properties scaling waveformProcessor coordtools +LIB = gfast_core.a +OBJS := $(foreach dir,$(SDIRS),$(dir)/*.o) + +all: $(LIB) +lib: $(LIB) + +$(LIB): $(SDIRS) + for dir in $(SDIRS) ; do \ + make -C $$dir all ; \ + done + $(AR) $(LIB) $(OBJS) + +ids: $(SDIRS) + for dir in $(SDIRS) ; do \ + make -C $$dir ids ; \ + done + +rm-ids: $(SDIRS) + for dir in $(SDIRS) ; do \ + make -C $$dir rm-ids ; \ + done + +install: + for dir in $(SDIRS) ; do \ + make -C $$dir install ; \ + done + +docs: + doxygen doxygen.conf + +cleandocs: + rm -rf ../docs/epic + +clean: + for dir in $(SDIRS) ; do \ + make -C $$dir clean ; \ + done + -rm -f $(LIB) + +veryclean: cleandocs + for dir in $(SDIRS) ; do \ + make -C $$dir veryclean ; \ + done + +depend: + for dir in $(SDIRS) ; do \ + make -C $$dir depend ; \ + done + +test: # no-op + +# coverage +cleancoverage: clean + for dir in $(SDIRS) ; do \ + make -C $$dir cleancoverage ; \ + done + +buildcoverage: + for dir in $(SDIRS) ; do \ + make -C $$dir buildcoverage ; \ + done + $(AR) $(LIB) $(OBJS) + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/core/cmt/Makefile b/src/core/cmt/Makefile new file mode 100644 index 00000000..bb85691b --- /dev/null +++ b/src/core/cmt/Makefile @@ -0,0 +1,66 @@ +# Makefile for GFAST/src/core/cmt +# + +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = decomposeMomentTensor.o gridSearch.o setDiagonalWeightMatrix.o \ +weightForwardModel.o depthGridSearch.o initialize.o setForwardModel.o \ +weightObservations.o finalize.o readIni.o setRHS.o + +DEBUG = -g + +#INIPARSER_INCL to be deleted later +INCL = -I ../../../include $(COMPEARTH_INCL) $(INIPARSER_INCL) $(LAPACKE_INCL) $(ISCL_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(cc) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/core/cmt/decomposeMomentTensor.c b/src/core/cmt/decomposeMomentTensor.c new file mode 100644 index 00000000..7326eb77 --- /dev/null +++ b/src/core/cmt/decomposeMomentTensor.c @@ -0,0 +1,207 @@ +#include +#include +#include "gfast_core.h" +#include "compearth.h" +#include "iscl/array/array.h" + +#define TEST_COMPEARTH 0 +#if (TEST_COMPEARTH == 1) +#include "cmopad/cmopad.h" +#endif + +/*! + * @brief Finds the moment tensor decomposition of the NED moment tensor + * + * @param[in] nmt number of moment tensors to decompose + * @param[in] M moment tensors (Nm) in NED for all nmt moment + * tensors. the i'th moment tensor is begins at + * index 6*i. the moment tensor packing is: + * \f$ \{ m_{xx}, m_{yy}, m_{zz}, + * m_{xy}, m_{xz}, m_{yz} \} \f$ + * [6*nmt] + * @param[out] DC_pct double couple percentage for each moment tensor + * [nmt] + * @param[out] Mw moment magnitude (e.g. Kanamori 1977) for each + * moment tensor [nmt] + * @param[out] strike1 strike of nodal plane 1 (degrees) for each + * moment tensor [nmt] + * @param[out] strike2 strike of nodal plane 2 (degrees) for each + * moment tensor [nmt] + * @param[out] dip1 dip of nodal plane 1 (degrees) for each moment + * tensor [nmt] + * @param[out] dip2 dip of nodal plane 2 (degrees) for each moment + * tensor [nmt] + * @param[out] rake1 rake on nodal plane 1 (degrees) for each moment + * tensor [nmt] + * @param[out] rake2 rake on nodal plane 2 (degrees) for each moment + * tensor [nmt] + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int core_cmt_decomposeMomentTensor(const int nmt, + const double *__restrict__ M, + double *__restrict__ DC_pct, + double *__restrict__ Mw, + double *__restrict__ strike1, + double *__restrict__ strike2, + double *__restrict__ dip1, + double *__restrict__ dip2, + double *__restrict__ rake1, + double *__restrict__ rake2) +{ +#if (TEST_COMPEARTH == 1) + struct cmopad_struct cmt; + double M33[3][3]; + int ierr1; + int verbose = 0; +#endif + double *M0, *fp1, *fp2, *pAxis, *tAxis, *bAxis, *isoPct, *devPct, *clvdPct; + int i, ierr; + //------------------------------------------------------------------------// + // Initialize output + ierr = 0; + M0 = (double *) calloc((size_t) nmt, sizeof(double)); + fp1 = (double *) calloc((size_t) (3*nmt), sizeof(double)); + fp2 = (double *) calloc((size_t) (3*nmt), sizeof(double)); + pAxis = (double *) calloc((size_t) (3*nmt), sizeof(double)); + bAxis = (double *) calloc((size_t) (3*nmt), sizeof(double)); + tAxis = (double *) calloc((size_t) (3*nmt), sizeof(double)); + isoPct = (double *) calloc((size_t) nmt, sizeof(double)); + devPct = (double *) calloc((size_t) nmt, sizeof(double)); + clvdPct = (double *) calloc((size_t) nmt, sizeof(double)); + ierr = compearth_standardDecomposition(nmt, M, CE_NED, + M0, Mw, fp1, fp2, + pAxis, bAxis, tAxis, + isoPct, devPct, DC_pct, clvdPct); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error in compearth moment tensor decomposition"); + array_zeros64f_work(nmt, DC_pct); + array_zeros64f_work(nmt, Mw); + array_zeros64f_work(nmt, strike1); + array_zeros64f_work(nmt, strike2); + array_zeros64f_work(nmt, dip1); + array_zeros64f_work(nmt, dip2); + array_zeros64f_work(nmt, rake1); + array_zeros64f_work(nmt, rake2); + } + else + { + for (i=0; i 1.e-10) + { + LOG_ERRMSG("dc mistmatch %f %f\n", cmt.DC_percentage, DC_pct[i]); + return -1; + } + if (fabs(cmt.moment_magnitude - Mw[i]) > 1.e-10) + { + LOG_ERRMSG("Mw mistmatch %f %f\n", cmt.moment_magnitude, Mw[i]); + return -1; + } + if (fabs(cmt.fp1[0] - strike1[i]) > 1.e-10) + { + LOG_ERRMSG("str1 mistmatch %f %f\n", cmt.fp1[0], strike1[i]); + return -1; + } + if (fabs(cmt.fp1[1] - dip1[i]) > 1.e-10) + { + LOG_ERRMSG("dip1 mistmatch %f %f\n", cmt.fp1[1], dip1[i]); + return -1; + } + if (fabs(cmt.fp1[2] - rake1[i]) > 1.e-10) + { + LOG_ERRMSG("rak1 mistmatch %f %f\n", cmt.fp1[2], rake1[i]); + return -1; + } + if (fabs(cmt.fp2[0] - strike2[i]) > 1.e-10) + { + LOG_ERRMSG("str2 mistmatch %f %f\n", cmt.fp2[0], strike2[i]); + return -1; + } + if (fabs(cmt.fp2[1] - dip2[i]) > 1.e-10) + { + LOG_ERRMSG("dip2 mistmatch %f %f\n", cmt.fp2[1], dip2[i]); + return -1; + } + if (fabs(cmt.fp2[2] - rake2[i]) > 1.e-10) + { + LOG_ERRMSG("rak2 mistmatch %f %f\n", cmt.fp2[2], rake2[i]); + return -1; + } + // Double couple percentage + DC_pct[i] = cmt.DC_percentage; + // Moment magnitude + Mw[i] = cmt.moment_magnitude; + // Nodal plane 1 + strike1[i] = cmt.fp1[0]; + dip1[i] = cmt.fp1[1]; + rake1[i] = cmt.fp1[2]; + // Nodal plane 2 + strike2[i] = cmt.fp2[0]; + dip2[i] = cmt.fp2[1]; + rake2[i] = cmt.fp2[2]; + } + if (ierr != 0) + { + LOG_ERRMSG("%s", "Errors during moment tensor decomposition"); + } +#endif + return ierr; +} diff --git a/src/core/cmt/depthGridSearch.c b/src/core/cmt/depthGridSearch.c new file mode 100644 index 00000000..35dfbd8d --- /dev/null +++ b/src/core/cmt/depthGridSearch.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include "gfast_core.h" +#ifdef GFAST_USE_INTEL + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Weverything" + #endif + #include + #include + #ifdef __clang__ + #pragma clang diagnostic pop + #endif +#else +#include +#include +#endif +#include "iscl/array/array.h" +#include "iscl/linalg/linalg.h" +#include "iscl/memory/memory.h" +#include "iscl/time/time.h" + +/*! + * @brief Performs the CMT depth grid search. + * + * @param[in] l1 number of sites + * @param[in] ndeps number of depths + * @param[in] verbose controls the verbosity (0 is quiet) + * @param[in] deviatoric if true then constrain the inversion s.t. + * resulting moment tensor is purely deviatoric. + * otherwise, invert for all six moment tensor + * terms. + * @param[in] utmSrcEasting source easting UTM position (m) + * @param[in] utmSrcNorthing source northing UTM position (m) + * @param[in] srcDepths source depths (km) in grid-search [ndeps] + * @param[in] utmRecvEasting receiver easting UTM positions (m) [l1] + * @param[in] utmRecvNorthing receiver northing UMT positions (m) [l1] + * @param[in] staAlt station elevations above sea level (m) [l1] + * @param[in] nObsOffset observed offset in north component (m) + * for i'th site [l1] + * @param[in] eObsOffset observed offset in east component (m) + * for i'th site [l1] + * @param[in] uObsOffset observed offset in vertical comonent (m) + * for i'th site [l1] + * @param[in] nWts weight corresponding to i'th north offset + * observation [l1] + * @param[in] eWts weight corresponding to i'th east offset + * observation [l1] + * @param[in] uWts weight corresponding to i'th vertical offset + * observation [l1] + * + * @param[out] nEst estimate offset in the north component (m) + * for the i'th site at all depths [l1*ndeps] + * the i'th site at the idep'th depth is given by + * idep*l1 + i + * @param[out] eEst estimate offset in the east component (m) + * for the i'th site at all depths [l1*ndeps] + * the i'th site at the idep'th depth is given by + * idep*l1 + i + * @param[out] uEst estimate offset in the vertical component (m) + * for the i'th site at all depths [l1*ndeps] + * the i'th site at the idep'th depth is given by + * idep*l1 + i + * @param[out] mts the moment tensor terms (Nm) inverted for in + * an NED system at each depth. the id'th depth + * is begins at index 6*id. the moment tensors at + * at each depth are packed: + * \f$ \{m_{xx}, m_{yy}, m_{zz}, + * m_{xy}, m_{xz}, m_{yz} \} \f$. + * + * @result 0 indicates success + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @bug Only deviatoric constraint programmed. + * + */ +int core_cmt_depthGridSearch(const int l1, const int ndeps, + const int verbose, + const bool deviatoric, + const double utmSrcEasting, + const double utmSrcNorthing, + const double *__restrict__ srcDepths, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ nObsOffset, + const double *__restrict__ eObsOffset, + const double *__restrict__ uObsOffset, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + double *__restrict__ nEst, + double *__restrict__ eEst, + double *__restrict__ uEst, + double *__restrict__ mts) +{ + double *diagWt, *G, *U, *UP, *WG, *WU, *xrs, *yrs, *zrs_negative, S[6], + eq_alt, m11, m12, m13, m22, m23, m33; + int i, idep, ierr, ierr1, ldg, mrows, ncols; + // Initialize + ierr = 0; + diagWt = NULL; + WG = NULL; + G = NULL; + WU = NULL; + U = NULL; + UP = NULL; + xrs = NULL; + yrs = NULL; + zrs_negative = NULL; + // Error check + if (l1 < 1) + { + LOG_ERRMSG("Error invalid number of input stations: %d",l1); + ierr = 1; + goto ERROR; + } + if (srcDepths == NULL || utmRecvEasting == NULL || + utmRecvNorthing == NULL || staAlt == NULL || + nObsOffset == NULL || eObsOffset == NULL || uObsOffset == NULL || + nEst == NULL || eEst == NULL || uEst == NULL || + mts == NULL) + { + if (srcDepths == NULL){LOG_ERRMSG("%s", "srcDepths is NULL!");} + if (utmRecvEasting == NULL) + { + LOG_ERRMSG("%s", "utmRecvEasting is NULL!"); + } + if (utmRecvNorthing == NULL) + { + LOG_ERRMSG("%s", "utmRecvNorthing is NULL!"); + } + if (staAlt == NULL){LOG_ERRMSG("%s", "staAlt is NULL");} + if (nObsOffset == NULL){LOG_ERRMSG("%s", "nObsOffset is NULL");} + if (eObsOffset == NULL){LOG_ERRMSG("%s", "eObsOffset is NULL");} + if (uObsOffset == NULL){LOG_ERRMSG("%s", "uObsOffset is NULL");} + if (nEst == NULL){LOG_ERRMSG("%s", "nEst is NULL");} + if (eEst == NULL){LOG_ERRMSG("%s", "eEst is NULL");} + if (uEst == NULL){LOG_ERRMSG("%s", "uEst is NULL");} + if (mts == NULL){LOG_ERRMSG("%s", "mts is NULL");} + ierr = 1; + goto ERROR; + } + if (ndeps < 1) + { + LOG_ERRMSG("Error invalid number of source depths: %d", ndeps); + ierr = 1; + goto ERROR; + } + if (!deviatoric) + { + LOG_ERRMSG("%s", "Cannot perform general MT gridsearch!"); + ierr = 1; + goto ERROR; + } + // Initialize results to nothing + array_zeros64f_work(6*ndeps, mts); + array_zeros64f_work(l1*ndeps, uEst); + array_zeros64f_work(l1*ndeps, nEst); + array_zeros64f_work(l1*ndeps, eEst); + // Set space + ncols = 6; + if (deviatoric){ncols = 5;} + mrows = 3*l1; + ldg = ncols; // In row major format + diagWt = memory_calloc64f(mrows); + WU = memory_calloc64f(mrows); + U = memory_calloc64f(mrows); + xrs = memory_calloc64f(l1); + yrs = memory_calloc64f(l1); + // Compute the source-receiver offsets in (x, y) cartesian +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i 2) + { + LOG_DEBUGMSG("%s", "Beginning search on depths..."); + } +#ifdef PARALLEL_CMT + #pragma omp parallel \ + private (G, UP, WG, zrs_negative) \ + private (i, idep, ierr1, eq_alt, m11, m22, m33, m12, m13, m23, S ) \ + shared (diagWt, eEst, ldg, mts, mrows, \ + ncols, nEst, srcDepths, staAlt, \ + uEst, U, WU, xrs, yrs) reduction(+:ierr) default (none) + { +#endif + G = memory_calloc64f(mrows*ncols); + WG = memory_calloc64f(mrows*ncols); + UP = memory_calloc64f(mrows); + zrs_negative = memory_calloc64f(l1); +#ifdef PARALLEL_CMT + #pragma omp for +#endif + for (idep=0; idep 2) + { + LOG_DEBUGMSG("Grid-search time: %f (s)", time_toc()); + } + } +ERROR:; + memory_free64f(&diagWt); + memory_free64f(&WU); + memory_free64f(&U); + memory_free64f(&xrs); + memory_free64f(&yrs); + return ierr; +} + diff --git a/src/core/cmt/finalize.c b/src/core/cmt/finalize.c new file mode 100644 index 00000000..03ae725e --- /dev/null +++ b/src/core/cmt/finalize.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Free the CMT results structure. + * + * @param[out] cmt CMT results structure with memory to be freed. + * + * @author Ben Baker, ISTI + * + */ +void core_cmt_finalizeResults(struct GFAST_cmtResults_struct *cmt) +{ + if (cmt == NULL){return;} + memory_free64f(&cmt->l2); + memory_free64f(&cmt->pct_dc); + memory_free64f(&cmt->objfn); + memory_free64f(&cmt->mts); + memory_free64f(&cmt->str1); + memory_free64f(&cmt->str2); + memory_free64f(&cmt->dip1); + memory_free64f(&cmt->dip2); + memory_free64f(&cmt->rak1); + memory_free64f(&cmt->rak2); + memory_free64f(&cmt->Mw); + memory_free64f(&cmt->srcDepths); + memory_free64f(&cmt->EN); + memory_free64f(&cmt->NN); + memory_free64f(&cmt->UN); + memory_free64f(&cmt->Einp); + memory_free64f(&cmt->Ninp); + memory_free64f(&cmt->Uinp); + memory_free8l(&cmt->lsiteUsed); + memset(cmt, 0, sizeof(struct GFAST_cmtResults_struct)); + return; +} +//============================================================================// +/*! + * @brief Frees memory associated with the offset data. + * + * @param[out] offset_data Offset data structure with memory to be freed. + * + * @author Ben Baker (ISTI) + * + */ +void core_cmt_finalizeOffsetData(struct GFAST_offsetData_struct *offset_data) +{ + GFAST_core_ff_finalizeOffsetData(offset_data); + return; +} +//============================================================================// +/*! + * @brief Convenience function for freeing the CMT data structures and data. + * + * @param[out] cmt_props Nulled out CMT properties. + * @param[out] offset_data Offset data structure whose memory has been + * freed and variables set to 0. + * @param[out] cmt CMT results structure whose memory hsa been + * freed and variables set to 0. + * + * @author Ben Baker (ISTI) + * + */ +void core_cmt_finalize(struct GFAST_cmt_props_struct *cmt_props, + struct GFAST_offsetData_struct *offset_data, + struct GFAST_cmtResults_struct *cmt) +{ + core_properties_finalizeCMTProperties(cmt_props); + core_cmt_finalizeOffsetData(offset_data); + core_cmt_finalizeResults(cmt); + return; +} + diff --git a/src/core/cmt/gridSearch.c b/src/core/cmt/gridSearch.c new file mode 100644 index 00000000..0da05efb --- /dev/null +++ b/src/core/cmt/gridSearch.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include "gfast_core.h" + +/*! + * @brief Performs the CMT depth grid search. + * + * @param[in] l1 number of sites + * @param[in] ndeps number of depths + * @param[in] nlats number of latitudes (northings) + * @param[in] nlons number of longitudes (eastings) + * @param[in] verbose controls the verbosity (0 is quiet) + * @param[in] deviatoric if true then constrain the inversion s.t. + * resulting moment tensor is purely deviatoric. + * otherwise, invert for all six moment tensor + * terms. + * @param[in] utmSrcEastings source easting UTM position (m). the + * ilat,ilon'th position in the grid is given by + * ilon*nlats + ilat [nlats*nlons] + * @param[in] utmSrcNorthings source northing UTM position (m). the + * ilat,ilon'th position in the grid is given by + * ilon*nlats + ilat [nlats*nlons] + * @param[in] srcDepths source depths (km) in grid-search [ndeps] + * @param[in] utmRecvEasting receiver easting UTM positions (m) [l1] + * @param[in] utmRecvNorthing receiver northing UMT positions (m) [l1] + * @param[in] staAlt station elevations above sea level (m) [l1] + * @param[in] nObsOffset observed offset in north component (m) + * for i'th site [l1] + * @param[in] eObsOffset observed offset in east component (m) + * for i'th site [l1] + * @param[in] uObsOffset observed offset in vertical comonent (m) + * for i'th site [l1] + * @param[in] nWts weight corresponding to i'th north offset + * observation [l1] + * @param[in] eWts weight corresponding to i'th east offset + * observation [l1] + * @param[in] uWts weight corresponding to i'th vertical offset + * observation [l1] + * + * @param[out] nEst estimate offset in the north component (m) + * for the i'th site at all depths, lats, and lons. + * [l1*ndeps*nlats*nlons] + * the i'th site at the idep'th depth is given by + * idep*l1 + i + * @param[out] eEst estimate offset in the east component (m) + * for the i'th site at all depths, lats, and lons. + * [l1*ndeps*nlats*nlons] + * the i'th site at the idep'th depth is given by + * ilon*nlats*ndeps*l1 + ilat*ndeps*l1 + idep*l1 + i + * @param[out] uEst estimate offset in the vertical component (m) + * for the i'th site at all depths + * [l1*ndeps*nlats*nlons] + * the i'th site at the idep'th depth is given by + * ilon*nlats*ndeps*l1 + ilat*ndeps*l1 + idep*l1 + i + * @param[out] mts the moment tensor terms (Nm) inverted for in + * an NED system at each depth. the id'th depth + * is begins at index 6*id. the moment tensors at + * at each depth are packed: + * \f$ \{m_{xx}, m_{yy}, m_{zz}, + * m_{xy}, m_{xz}, m_{yz} \} \f$. + * [6*l1*ndeps*nlats*nlons] + * + * @result 0 indicates success + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @bug Only deviatoric constraint programmed. + */ +int core_cmt_gridSearch(const int l1, + const int ndeps, const int nlats, const int nlons, + const int verbose, + const bool deviatoric, + const double *__restrict__ utmSrcEastings, + const double *__restrict__ utmSrcNorthings, + const double *__restrict__ srcDepths, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ nObsOffset, + const double *__restrict__ eObsOffset, + const double *__restrict__ uObsOffset, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + double *__restrict__ nEst, + double *__restrict__ eEst, + double *__restrict__ uEst, + double *__restrict__ mts) +{ + int ierr, ierr1, ilat, ilon, ilatLon; + //------------------------------------------------------------------------// + // + // Check for NULL arrays + if (utmSrcEastings == NULL || utmSrcNorthings == NULL || + srcDepths == NULL || utmRecvEasting == NULL || + utmRecvNorthing == NULL || staAlt == NULL || + nObsOffset == NULL || eObsOffset == NULL || uObsOffset == NULL || + nEst == NULL || eEst == NULL || uEst == NULL || + mts == NULL) + { + if (utmSrcEastings == NULL) + { + LOG_ERRMSG("%s", "utmSrcEastings is NULL!"); + } + if (utmSrcNorthings == NULL) + { + LOG_ERRMSG("%s", "utmSrcNorthings is NULL!"); + } + if (srcDepths == NULL){LOG_ERRMSG("%s", "srcDepths is NULL!");} + if (utmRecvEasting == NULL) + { + LOG_ERRMSG("%s", "utmRecvEasting is NULL!"); + } + if (utmRecvNorthing == NULL) + { + LOG_ERRMSG("%s", "utmRecvNorthing is NULL!"); + } + if (staAlt == NULL){LOG_ERRMSG("%s", "staAlt is NULL");} + if (nObsOffset == NULL){LOG_ERRMSG("%s", "nObsOffset is NULL");} + if (eObsOffset == NULL){LOG_ERRMSG("%s", "eObsOffset is NULL");} + if (uObsOffset == NULL){LOG_ERRMSG("%s", "uObsOffset is NULL");} + if (nEst == NULL){LOG_ERRMSG("%s", "nEst is NULL");} + if (eEst == NULL){LOG_ERRMSG("%s", "eEst is NULL");} + if (uEst == NULL){LOG_ERRMSG("%s", "uEst is NULL");} + if (mts == NULL){LOG_ERRMSG("%s", "mts is NULL");} + return -1; + } + // Verify the sizes + if (l1 < 1 || ndeps < 1 || nlats < 1 || nlons < 1) + { + if (l1 < 1) + { + LOG_ERRMSG("Error no observations %d", l1); + } + if (ndeps < 1) + { + LOG_ERRMSG("Error invalid number of source depths: %d", ndeps); + } + if (nlons < 1) + { + LOG_ERRMSG("Error invalid number of lons (easting): %d", nlons); + } + if (nlats < 1) + { + LOG_ERRMSG("Error invalid number of lats (northings): %d", nlats); + } + return -1; + } + // Prevent problems with deviatoric + if (!deviatoric) + { + LOG_ERRMSG("%s", "Cannot perform general MT gridsearch!"); + return -1; + } + // Loop on the longitudes (eastings) + ierr = 0; +#ifdef PARALLEL_CMT + #pragma omp parallel for collapse(2) \ + private(ilatLon, ilat, ilon) \ + reduction(+:ierr), shared(nEst, eEst, uEst, mts) \ + default(none) +#endif + for (ilon=0; ilon +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Allocates space for the CMT grid search + * + * @param[in] props holds the CMT parameters + * @param[in] gps_data holds the site stream length + * + * @param[out] cmt has space allocated for the CMT depth gridsearch + * @param[out] cmt_data has space sufficient to carry the offset data + * and weights. also, contains an initial data + * mask. + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + * @bug Can't accept arbitrary source depths from input file + * + */ +int core_cmt_initialize(struct GFAST_cmt_props_struct props, + struct GFAST_data_struct gps_data, + struct GFAST_cmtResults_struct *cmt, + struct GFAST_offsetData_struct *cmt_data) +{ + int i, nlld; + //------------------------------------------------------------------------// + cmt->ndeps = props.ngridSearch_deps; + cmt->nlats = props.ngridSearch_lats; + cmt->nlons = props.ngridSearch_lons; + if (cmt->ndeps < 1 || cmt->nlats < 1 || cmt->nlons < 1) + { + if (cmt->ndeps < 1) + { + LOG_ERRMSG("No depths in CMT grid search %d\n", + props.ngridSearch_deps); + } + if (cmt->nlats < 1) + { + LOG_ERRMSG("No lats in CMT grid search %d\n", + props.ngridSearch_lats); + } + if (cmt->nlats < 1) + { + LOG_ERRMSG("No lons in CMT grid search %d\n", + props.ngridSearch_lons); + } + return -1; + } + nlld = cmt->nlats*cmt->nlons*cmt->ndeps; + cmt->nsites = gps_data.stream_length; + if (gps_data.stream_length < 1) + { + LOG_ERRMSG("Error insufficient data to estimate CMT %d\n", + gps_data.stream_length); + } + // data + cmt_data->stnm = (char **)calloc((size_t) gps_data.stream_length, + sizeof(char *)); + cmt_data->ubuff = memory_calloc64f(gps_data.stream_length); + cmt_data->nbuff = memory_calloc64f(gps_data.stream_length); + cmt_data->ebuff = memory_calloc64f(gps_data.stream_length); + cmt_data->wtu = memory_calloc64f(gps_data.stream_length); + cmt_data->wtn = memory_calloc64f(gps_data.stream_length); + cmt_data->wte = memory_calloc64f(gps_data.stream_length); + cmt_data->sta_lat = memory_calloc64f(gps_data.stream_length); + cmt_data->sta_lon = memory_calloc64f(gps_data.stream_length); + cmt_data->sta_alt = memory_calloc64f(gps_data.stream_length); + cmt_data->lmask = memory_calloc8l(gps_data.stream_length); + cmt_data->lactive = memory_calloc8l(gps_data.stream_length); + cmt_data->nsites = gps_data.stream_length; + for (i=0; insites; i++) + { + cmt_data->sta_lat[i] = gps_data.data[i].sta_lat; + cmt_data->sta_lon[i] = gps_data.data[i].sta_lon; + cmt_data->sta_alt[i] = gps_data.data[i].sta_alt; + cmt_data->stnm[i] = (char *)calloc(64, sizeof(char)); + strcpy(cmt_data->stnm[i], gps_data.data[i].netw); + strcat(cmt_data->stnm[i], ".\0"); + strcat(cmt_data->stnm[i], gps_data.data[i].stnm); + strcat(cmt_data->stnm[i], ".\0"); + strncpy(cmt_data->stnm[i], gps_data.data[i].chan[0], 2); + strcat(cmt_data->stnm[i], "?.\0"); + if (strlen(gps_data.data[i].loc) > 0) + { + strcat(cmt_data->stnm[i], gps_data.data[i].loc); + } + if (gps_data.data[i].lskip_cmt){cmt_data->lmask[i] = true;} + } + // cmt structure + cmt->l2 = memory_calloc64f(nlld); //cmt->ndeps); + cmt->pct_dc = memory_calloc64f(nlld); //cmt->ndeps); + cmt->objfn = memory_calloc64f(nlld); //cmt->ndeps); + cmt->mts = memory_calloc64f(6*nlld); //6*cmt->ndeps); + cmt->str1 = memory_calloc64f(nlld); //cmt->ndeps); + cmt->str2 = memory_calloc64f(nlld); //cmt->ndeps); + cmt->dip1 = memory_calloc64f(nlld); //cmt->ndeps); + cmt->dip2 = memory_calloc64f(nlld); //cmt->ndeps); + cmt->rak1 = memory_calloc64f(nlld); //cmt->ndeps); + cmt->rak2 = memory_calloc64f(nlld); //cmt->ndeps); + cmt->Mw = memory_calloc64f(nlld); //cmt->ndeps); + cmt->srcDepths = memory_calloc64f(nlld); //cmt->ndeps); + cmt->EN = memory_calloc64f(cmt->nsites*nlld); //cmt->nsites); + cmt->NN = memory_calloc64f(cmt->nsites*nlld); //cmt->nsites); + cmt->UN = memory_calloc64f(cmt->nsites*nlld); //cmt->nsites); + cmt->Einp = memory_calloc64f(cmt->nsites); + cmt->Ninp = memory_calloc64f(cmt->nsites); + cmt->Uinp = memory_calloc64f(cmt->nsites); + cmt->lsiteUsed = memory_calloc8l(cmt->nsites); + /* TODO fix me */ + for (i=0; indeps; i++) + { + cmt->srcDepths[i] = (double) (i + 1); + } + return 0; +} diff --git a/src/core/cmt/readIni.c b/src/core/cmt/readIni.c new file mode 100644 index 00000000..f36e32a8 --- /dev/null +++ b/src/core/cmt/readIni.c @@ -0,0 +1,143 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_core.h" +#include "iscl/os/os.h" + +static void setVarName(const char *group, const char *variable, + char *var) +{ + memset(var, 0, 256*sizeof(char)); + sprintf(var, "%s:%s", group, variable); + return; +} +/*! + * @brief Reads the CMT properties from the initialization file. + * + * @param[in] propfilename Name of properties file. + * @param[in] group Group in ini file. Likely "CMT". + * @param[in] verbose This is the verbosity from the general + * parameters. + * @param[in] utm_zone This is the default UTM zone from the + * general parameters. + * + * @param[out] cmt_props CMT scaling properties. + * + * @result 0 indicates success. + * + * @author Ben Baker (ISTI) + * + */ +int core_cmt_readIni(const char *propfilename, + const char *group, + const int verbose, const int utm_zone, + struct GFAST_cmt_props_struct *cmt_props) +{ + char var[256]; + int ierr; + dictionary *ini; + ierr = 1; + memset(cmt_props, 0, sizeof(struct GFAST_cmt_props_struct)); + if (!os_path_isfile(propfilename)) + { + LOG_ERRMSG("Properties file: %s does not exist", propfilename); + return ierr; + } + ini = iniparser_load(propfilename); + // Read the properties + cmt_props->verbose = verbose; + cmt_props->utm_zone = utm_zone; + setVarName(group, "do_cmt\0", var); + cmt_props->do_cmt = iniparser_getboolean(ini, var, true); + setVarName(group, "deltaLatitude\0", var); + cmt_props->dLat = iniparser_getdouble(ini, var, 0.1); + if (cmt_props->dLat < 0.0) + { + LOG_ERRMSG("Error CMT latitude serach %f must be positive", + cmt_props->dLat); + goto ERROR; + } + setVarName(group, "deltaLongitude\0", var); + cmt_props->dLon = iniparser_getdouble(ini, var, 0.1); + if (cmt_props->dLon < 0.0) + { + LOG_ERRMSG("Error CMT longitudes %f must be positive", + cmt_props->dLon); + goto ERROR; + } + setVarName(group, "nlats_in_cmt_gridSearch\0", var); + cmt_props->ngridSearch_lats = iniparser_getint(ini, var, 1); + if (cmt_props->ngridSearch_lats < 1) + { + LOG_ERRMSG("Error CMT grid search lats %d must be positive", + cmt_props->ngridSearch_lats); + goto ERROR; + } + if (cmt_props->ngridSearch_lats%2 == 0) + { + LOG_WARNMSG("%s", "Adding 1 point to CMT lat gridsearch"); + cmt_props->ngridSearch_lats = cmt_props->ngridSearch_lats + 1; + } + setVarName(group, "nlons_in_cmt_gridSearch\0", var); + cmt_props->ngridSearch_lons = iniparser_getint(ini, var, 1); + if (cmt_props->ngridSearch_lons < 1) + { + LOG_ERRMSG("Error CMT grid search lons %d must be positive", + cmt_props->ngridSearch_lons); + goto ERROR; + } + if (cmt_props->ngridSearch_lons%2 == 0) + { + LOG_WARNMSG("%s", "Adding 1 point to CMT lon gridsearch"); + cmt_props->ngridSearch_lons = cmt_props->ngridSearch_lons + 1; + } + setVarName(group, "ndepths_in_cmt_gridSearch\0", var); + cmt_props->ngridSearch_deps = iniparser_getint(ini, var, 100); + if (cmt_props->ngridSearch_deps < 1) + { + LOG_ERRMSG("Error CMT grid search depths %d must be positive", + cmt_props->ngridSearch_deps); + goto ERROR; + } + setVarName(group, "cmt_min_sites\0", var); + cmt_props->min_sites = iniparser_getint(ini, var, 4); + if (cmt_props->min_sites < 3) + { + LOG_ERRMSG("%s", "Error at least two sites needed to estimate CMT!"); + goto ERROR; + } + setVarName(group, "cmt_window_vel\0", var); + cmt_props->window_vel = iniparser_getdouble(ini, var, 2.0); + if (cmt_props->window_vel <= 0.0) + { + LOG_ERRMSG("%s", "Error window velocity must be positive!"); + goto ERROR; + } + setVarName(group, "cmt_window_avg\0", var); + cmt_props->window_avg = iniparser_getdouble(ini, var, 0.0); + if (cmt_props->window_avg < 0.0) + { + LOG_ERRMSG("%s", "Error window average time must be positive!"); + goto ERROR; + } + setVarName(group, "ldeviatoric_cmt\0", var); + cmt_props->ldeviatoric + = iniparser_getboolean(ini, var, true); + if (!cmt_props->ldeviatoric) + { + LOG_ERRMSG("%s", "Error general CMT inversions not yet programmed"); + goto ERROR; + } + ierr = 0; +ERROR:; + iniparser_freedict(ini); + return ierr; +} diff --git a/src/core/cmt/setDiagonalWeightMatrix.c b/src/core/cmt/setDiagonalWeightMatrix.c new file mode 100644 index 00000000..fc8995f5 --- /dev/null +++ b/src/core/cmt/setDiagonalWeightMatrix.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Sets the diagonal weight matrix in the inversion. + * + * @param[in] n number of of observations + * @param[in] nWts data weights on north observation [n] + * @param[in] eWts data weights on east observation [n] + * @param[in] uWts data weights on vertical observations [n] + * + * @param[out] diagWt diagonal matrix of data weights to apply to + * \f$ diag{W} G m = diag{W} U \f$ [3*n] + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_cmt_setDiagonalWeightMatrix(const int n, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + double *__restrict__ diagWt) +{ + int i, i3; + bool leWts, lnWts, luWts; + if (n < 1) + { + LOG_ERRMSG("Invalid number of points: %d", n); + return -1; + } + if (diagWt == NULL) + { + LOG_ERRMSG("%s", "Error diagWt is NULL!"); + return -1; + } + if (nWts == NULL || eWts == NULL || uWts == NULL) + { + if (nWts == NULL && eWts == NULL && uWts == NULL) + { + LOG_WARNMSG("%s", "Setting diagonal weight matrix to unity"); +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i<3*n; i++) + { + diagWt[i] = 1.0; + } + } + else // Selectively make weights 1 + { + lnWts = true; + leWts = true; + luWts = true; + if (nWts == NULL) + { + LOG_WARNMSG("%s", "Setting nWts to unity"); + lnWts = false; + } + if (eWts == NULL) + { + LOG_WARNMSG("%s", "Setting eWts to unity"); + leWts = false; + } + if (uWts == NULL) + { + LOG_WARNMSG("%s", "Setting uWts to unity"); + luWts = false; + } + i3 = 0; + if (lnWts && leWts && luWts) + { +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +/*! + * @brief Computes matrix of Green's functions for the CMT inversion. + * If the deviatoric constraint is applied then the columns of + * the Green's functions matrix correspond to the moment tensor + * terms: + * \f$ \{ m_{xy}, + * m_{xz}, + * m_{zz}, + * \frac{1}{2} \left ( m_{xx} - m_{yy} \right ), + * m_{yz} + * \} \f$. + * + * Otherwise, at the moment, the general case is not yet defined. + * + * Additionally, site l, the 3*l'th row corresponds to the north + * observation, the 3*l+1'th row corresponds to the east observation, + * and 3*l+2'th row corresponds to the negative vertical observation. + * + * @param[in] l1 Length of arrays. + * @param[in] ldeviatoric If true then compute the Green's functions matrix + * G with the deviatoric constraint. + * Otherwise compute the general Green's functions + * matrix for all six moment tensor terms. + * @param[in] x1 x (North) receiver-source distance (meters). + * This is an array of dimension [l1]. + * @param[in] y1 y (East) receiver-source distance (meters). + * This is an array of dimension [l1]. + * @param[in] z1 z receiver-source distance (meters). + * This is an array of dimension [l1]. + * Note, that z increases up from the free + * surface in the observation frame, hence, for most + * applications z will be negative. + * + * @param[out] G Matrix of Green's functions stored in row major + * format with dimension [3*l1 x ncol]. If + * ldeviatoric is true then ncol is 5, otherwise, + * ncol is 6. + * + * @result 0 indicates success. + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @date April, 2016 + * + * @bug General case, ncols = 6, not yet programmed. + * + */ +int core_cmt_setForwardModel(const int l1, const bool ldeviatoric, + const double *__restrict__ x1, + const double *__restrict__ y1, + const double *__restrict__ z1, + double *__restrict__ G) +{ + double C1, C2, + g111, g122, g133, g112, g113, g123, + g211, g222, g233, g212, g213, g223, + g311, g322, g333, g312, g313, g323, + R, R3, x, y, z; + int i, indx; + const double MU = 3.e10; + const double K = 5.0*MU/3.0; + //------------------------------------------------------------------------// + // + // Size check + if (l1 < 1) + { + LOG_ERRMSG("Error invalid number of points %d", l1); + return -1; + } + if (!ldeviatoric) + { + LOG_ERRMSG("%s", "General case not yet programmed"); + return -1; + } + if (ldeviatoric) + { + // Loop on sites and fill up Green's function deviatoric matrix + indx = 0; + for (i=0; i +#include +#include "gfast_core.h" +/*! + * @brief Sets the RHS for the moment tensor inversion. The right hand + * side for the i'th site is packed + * \f$ \{ n_{avg}^{(i)}, e_{avg}^{(i)}, -u_{avg}^{(i)} \} \f$. + * + * @param[in] n Number of observations. + * @param[in] nOffset Offset measured on north channel. This is + * an array of dimension [n]. + * @param[in] eOffset offset measured on east channel. This is + * an array of dimension [n]. + * @param[in] uOffset offset measured on vertical channel. This is + * an array of dimension [n]. + * + * @param[out] U Right hand side in Gm = U. This is an array + * of dimension [3*n]. + * + * @result 0 indicates success. + * + * @author Ben Baker (ISTI) + * + */ +int core_cmt_setRHS(const int n, + const double *__restrict__ nOffset, + const double *__restrict__ eOffset, + const double *__restrict__ uOffset, + double *__restrict__ U) +{ + int i, i3; + if (n < 1 || U == NULL || + nOffset == NULL || eOffset == NULL || uOffset == NULL) + { + if (n < 1){LOG_ERRMSG("Invalid number of points: %d", n);} + if (U == NULL){LOG_ERRMSG("%s", "U is NULL");} + if (nOffset == NULL){LOG_ERRMSG("%s", "nOffset is NULL");} + if (eOffset == NULL){LOG_ERRMSG("%s", "eOffset is NULL");} + if (uOffset == NULL){LOG_ERRMSG("%s", "uOffset is NULL");} + return -1; + } + i3 = 0; +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include "gfast_core.h" +#include "iscl/array/array.h" + +/*! + * @brief Weights a forward modeling matrix by the diagonal data weights. + * + * @param[in] mrows Number of rows in forward modeling matrix. This + * should be 3 x number of observations. + * @param[in] ncols Number of columns in forward modeling matrix. + * This should be 5 or 6. + * @param[in] diagWt Diagonal of data weight matrix. This is an array + * of dimension [mrows]. + * @param[in] G Unweighted forward modeling matrix. This is + * in row major format and has dimension [mrows x ncols]. + * + * @param[out] diagWtG Weighted forward modeling matrix obtained by + * computing \f$ \tilde{G} \leftarrow diag\{W\} G \f$. + * This is in row major format and has of dimension + * [mrows x ncols] + * + * @retval -1 indicates an input error. + * @retval 0 indicates success. + * @retval 1 indicates the diagonal weight matrix is NULL. G will + * not be modified in this instance. + * + * @author Ben Baker, ISTI + * + */ +int core_cmt_weightForwardModel(const int mrows, const int ncols, + const double *__restrict__ diagWt, + const double *__restrict__ G, + double *__restrict__ diagWtG) +{ + int i, j; + if (mrows < 1 || ncols < 1) + { + LOG_ERRMSG("Error G has invalid dimension %d %d", mrows, ncols); + return -1; + } + if (G == NULL || diagWtG == NULL) + { + if (G == NULL){LOG_ERRMSG("%s", "Error G cannot be NULL");} + if (diagWtG == NULL){LOG_ERRMSG("%s", "Error diagWtG cannot be NULL");} + return -1; + } + // Avoid a segmentation fault + if (diagWt == NULL) + { + LOG_WARNMSG("%s", "Warning diagWt is NULL; G will not be weighted"); + array_copy64f_work(mrows*ncols, G, diagWtG); + return 1; + } + // Compute \tilde{G} = diag\{W\}*G - most likely a deviatoric source + if (ncols == 5) + { +#ifdef _OPENMP + #pragma omp simd collapse(2) +#endif + for (i=0; i +#include +#include "gfast_core.h" +#include "iscl/array/array.h" +/*! + * @brief Applies the diagonal data weight matrix to the observations. + * + * @param[in] mrows Number of rows (observations). This should be + * 3 x number of sites. + * @param[in] diagWt Diagonal matrix of data weights. This is an array + * of dimension [mrows]. + * @param[in] b Observations. This is an array of dimensoin [mrows]. + * + * @param[out] diagWb Weighted observations such that + * \f$ \tilde{b} = diag \{W\} b \f$. + * This is an array of dimension [mrows]. + * + * @retval -1 indicates an error. + * @retval 0 indicates success. + * @retval 1 indicates that diagWt is NULL and it is assumed that diagWt + * is identity. + * + * @author Ben Baker (ISTI) + * + */ +int core_cmt_weightObservations(const int mrows, + const double *__restrict__ diagWt, + const double *__restrict__ b, + double *__restrict__ diagWb) +{ + int i; + if (mrows < 1) + { + LOG_ERRMSG("%s", "Error no rows!"); + return -1; + } + if (b == NULL || diagWb == NULL) + { + if (b == NULL){LOG_ERRMSG("%s", "Error b is NULL");} + if (diagWb == NULL){LOG_ERRMSG("%s", "Error diagWb is NULL");} + return -1; + } + if (diagWt == NULL) + { + LOG_WARNMSG("%s", "Warning diagWt is NULL - assuming identity"); + array_copy64f_work(mrows, b, diagWb); + return 1; + } + // Apply diagonal data weights to observations +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include +#include "gfast_core.h" + +/*! + * @brief This takes lat and lon values and converts to UTM northing and + * easting. + * + * @param[in] lon_deg Longitude to convert to UTM easting (degrees). + * @param[in] lat_deg Latitude to convert to UTM northing (degrees). + * @param[out] UTMNorthing Corresponding northing UTM coordinate (m). + * @param[out] UTMEasting Corresponding easting UTM coordinate (m). + * @param[out] lnorthp If true then this UTM point is in the northern + * hemisphere. \n + * If false then this UTM point is in the southern + * hemisphere. + * @param[inout] zone If ==-1 then choose the central meridian from the + * input longitude. \n + * Otherwise set the desired zone in range [0,60] + * from the input longitude. + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +#ifdef _OPENMP +#pragma omp declare simd +#endif +void core_coordtools_ll2utm(const double lat_deg, const double lon_deg, + double *UTMNorthing, double *UTMEasting, + bool *lnorthp, int *zone) +{ + double A, C, lat, lon, lon_deg_use, lon0, lon0_deg, M, T, v; + int zone_loc; + // WGS84 parameters + const double a = 6378137.0000; + const double esq = 0.006694380069978522; + const double epsq = esq/(1.0 - esq); + const double k0 = 0.9996; + const double pi180 = M_PI/180.0; + //------------------------------------------------------------------------// + lon_deg_use = lon_deg; + if (lon_deg_use > 180.0){lon_deg_use = lon_deg_use - 360.0;} // [0,360] + lon = lon_deg_use*pi180; + lat = lat_deg*pi180; + zone_loc = *zone; + if (zone_loc ==-1) + { + zone_loc = (int) (fmod(floor((lon_deg_use + 180.0)/6.0), 60.0) + 0.5) + + 1; + } + lon0_deg = (double) (abs(zone_loc)*6) - 183.0; + lon0 = lon0_deg*pi180; //central meridian (-123 for zone 10) + + A = (lon - lon0)*cos(lat); + v = a/sqrt(1.0 - esq*pow(sin(lat), 2)); + T = pow(tan(lat), 2); + C = esq*pow(cos(lat), 2)/(1.0 - esq); + + M = a*( + (1.0 - esq/4.0 - 3.0*pow(esq, 2)/64.0 - 5.0*pow(esq, 3)/256.0)*lat + -(3.0*esq/8.0 + 3.0*pow(esq, 2)/32.0 + + 45.0*pow(esq, 3)/1024.0)*sin(2.0*lat) + +(15.0*pow(esq, 2)/256.0 + 45.0*pow(esq, 3)/1024.0)*sin(4.0*lat) + -(35.0*pow(esq, 3)/3072.0)*sin(6.0*lat) + ); + + *UTMNorthing = k0*( M + v*tan(lat)*( A*A/2.0 + (5.0 - T + 9.0*C +4.0*C*C) + *pow(A, 4)/24.0 + (61.0 - 58.0*T + T*T + + 600.0*C - 330.0*epsq)*pow(A, 6)/720.0 ) ); + + *UTMEasting = k0*v*( A + (1.0 - T + C)*pow(A, 3)/6.0 + + (5.0 - 18.0*T + T*T + + 72.0*C - 58.0*epsq)*pow(A, 5)/120.0 ) + 500000.0; + *lnorthp = true; + if (lat_deg < 0.0){*UTMNorthing = *UTMNorthing + 10000000.0;} + if (lat_deg < 0.0){*lnorthp = false;} + if (*zone ==-1) + { + *zone = (int) (fmod(floor((lon0_deg + 180.0)/6.0), 60.0) + 0.5) + 1; + } + return; +} diff --git a/src/core/coordtools/utm2ll.c b/src/core/coordtools/utm2ll.c new file mode 100644 index 00000000..110e6426 --- /dev/null +++ b/src/core/coordtools/utm2ll.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Takes UTM easting and northing with a central meridian and converts + * to lat and lon. This is the inverse function for ll2utm. + * + * @param[in] zone UTM zone. + * @param[in] lnorthp If true then we are in the northern hemistphere. \n + * If false then we are in the southern hemisphere. + * @param[in] UTMNorthing UTM north coordinate to convert to latitude (m). + * @param[in] UTMEasting UTM east coordinate to convert to longitude (m). + * + * @param[out] lat_deg Corresponding latitude (degrees). + * @param[out] lon_deg Corresponding longitude (degrees). + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +#ifdef _OPENMP +#pragma omp declare simd +#endif +void core_coordtools_utm2ll(const int zone, const bool lnorthp, + const double UTMNorthing, const double UTMEasting, + double *lat_deg, double *lon_deg) +{ + double C1, C1_2, D, D_2, D_3, D_4, D_5, D_6, e1, e1_2, e1_3, e1_4, + lat, lat1, lon, lon0, lon0_deg, + M1, mu1, T1, T1_2, p1, v1; + // WGS84 parameters + const double a = 6378137.0000; + const double esq = 0.006694380069978522; + const double epsq = esq/(1.0 - esq); + const double k0 = 0.9996; + const double pi180 = M_PI/180.0; + const double pi180i = 180.0/M_PI; + //------------------------------------------------------------------------// + lon0_deg = abs(zone)*6.0 - 183.0; + lon0 = lon0_deg*pi180; + M1 = UTMNorthing/k0; + if (!lnorthp){M1 = (UTMNorthing - 10000000.0)/k0;} + mu1 = M1/(a * (1.0 - esq/4.0 - 3.0/64.0*pow(esq, 2) + - 5.0/256.0*pow(esq, 3)) ); + e1 = ( 1.0 - sqrt(1.0 - esq) ) / ( 1.0 + sqrt(1.0 - esq) ); + e1_2 = e1*e1; + e1_3 = e1_2*e1; + e1_4 = e1_3*e1; + lat1 = mu1 + (3.0*e1/2.0 - 27.0/32.0*e1_3)*sin(2.0*mu1) + + (21.0/16.0*e1_2 - 55.0/32.0*e1_4)*sin(4.0*mu1) + + (151.0/96.0*e1_3)*sin(6.0*mu1) + + (1097.0/512.0*e1_4)*sin(8.0*mu1); +/* + lat1 = mu1 + (3.0*e1/2.0 - 27.0/32.0*pow(e1, 3))*sin(2.0*mu1) + + (21.0/16.0*pow(e1, 2) - 55.0/32.0*pow(e1, 4))*sin(4.0*mu1) + + (151.0/96.0*pow(e1, 3))*sin(6.0*mu1) + + (1097.0/512.0*pow(e1, 4))*sin(8.0*mu1); +*/ + T1 = pow(tan(lat1), 2); + C1 = epsq*pow(cos(lat1), 2); + + v1 = a/sqrt(1.0 - esq*pow(sin(lat1), 2)); + p1 = a*(1.0 - esq)/pow(1.0 - esq*pow(sin(lat1), 2), 1.5); + D = (UTMEasting - 500000.0)/v1/k0; + + C1_2 = C1*C1; + T1_2 = T1*T1; + D_2 = D*D; + D_3 = D_2*D; + D_4 = D_3*D; + D_5 = D_4*D; + D_6 = D_5*D; + lat = lat1 - (v1*tan(lat1)/p1) * ( D_2/2.0 - (5.0 + 3.0*T1 + 10.0*C1 + - 4.0*C1_2 - 9.0*epsq)*D_4/24.0 + (61.0 + 90.0*T1 + + 298.0*C1 + 45.0*T1_2 - 252.0*epsq - 3.0*C1_2) + *D_6/720.0 ); + lon = lon0 + ( D - (1.0 + 2.0*T1 + C1)*D_3/6.0 + (5.0 - 2.0*C1 + + 28.0*T1 - 3.0*C1_2 + 8.0*epsq + 24.0*T1_2) + *D_5/120.0 )/cos(lat1); +/* +printf("%f %f\n", lat, lon); + lat = lat1 - (v1*tan(lat1)/p1) * ( pow(D, 2)/2.0 - (5.0 + 3.0*T1 + 10.0*C1 + - 4.0*pow(C1,2) - 9.0*epsq)*pow(D, 4)/24.0 + (61.0 + 90.0*T1 + + 298.0*C1 + 45.0*pow(T1, 2) - 252.0*epsq - 3.0*pow(C1, 2)) + *pow(D, 6)/720.0 ); + lon = lon0 + ( D - (1.0 + 2.0*T1 + C1)*pow(D, 3)/6.0 + (5.0 - 2.0*C1 + + 28.0*T1 - 3.0*pow(C1, 2) + 8.0*epsq + 24.0*pow(T1, 2)) + *pow(D, 5)/120.0 )/cos(lat1); +printf("%f %f\n", lat, lon); +*/ + + *lat_deg = lat*pi180i; + *lon_deg = lon*pi180i; + if (*lon_deg < 0.0){*lon_deg = *lon_deg + 360.0;} + return; +} diff --git a/src/core/data/Makefile b/src/core/data/Makefile new file mode 100644 index 00000000..b8d20941 --- /dev/null +++ b/src/core/data/Makefile @@ -0,0 +1,64 @@ +# Makefile for GFAST/src/core/data +# + +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = finalize.o initialize.o readMetaDataFile.o readSiteMaskFile.o + +DEBUG = -g +CCFLAGS += -O0 -D_REENTRANT -Dstatic_config + +INCL = -I ../../../include $(ISCL_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(CC) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/core/data/finalize.c b/src/core/data/finalize.c new file mode 100644 index 00000000..d56435c8 --- /dev/null +++ b/src/core/data/finalize.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Frees the GPS data structure + * + * @param[out] gps_data GPS data structure to be freed/reset + * + * @author Ben Baker (ISTI) + * + */ +void core_data_finalize(struct GFAST_data_struct *gps_data) +{ + int k; + if (gps_data->data != NULL) + { + for (k=0; kstream_length; k++) + { + memory_free64f(&gps_data->data[k].ubuff); + memory_free64f(&gps_data->data[k].nbuff); + memory_free64f(&gps_data->data[k].ebuff); + memory_free64f(&gps_data->data[k].tbuff); + } + free(gps_data->data); + } + memset(gps_data, 0, sizeof(struct GFAST_data_struct)); + return; +} diff --git a/src/core/data/initialize.c b/src/core/data/initialize.c new file mode 100644 index 00000000..2b81fc24 --- /dev/null +++ b/src/core/data/initialize.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" +#include "iscl/os/os.h" + +/*! + * @brief Initializes the GPS data streams + * + * @param[in] props holds the GFAST properties + * + * @param[out] gps_data this should have been pre-initialized to NULL. + * on successful output holds the GPS data structure, + * metadata such (station SNCL's, locations, instrument + * sampling period) and requisite memory. + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_data_initialize(struct GFAST_props_struct props, + struct GFAST_data_struct *gps_data) +{ + int ierr, k, mpts; + // Get the sites to be used + ierr = 0; + if (props.verbose > 0){LOG_MSG("%s", "Initializing metadata...");} + ierr = core_data_readMetaDataFile(props.metaDataFile, + props.metaDataNetworks, + props.n_networks, + gps_data); + if (ierr != 0) + { + LOG_ERRMSG("Error reading sites file: %s", props.metaDataFile); + return -1; + } + if (os_path_isfile(props.siteMaskFile)) + { + ierr = core_data_readSiteMaskFile(props.siteMaskFile, + props.verbose, gps_data); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading site mask file"); + return -1; + } + } + // Set the buffer lengths + for (k=0; kstream_length; k++) + { + mpts = (int) (props.bufflen/gps_data->data[k].dt + 0.5) + 1; + gps_data->data[k].maxpts = mpts; + gps_data->data[k].ubuff = memory_calloc64f(mpts); + gps_data->data[k].nbuff = memory_calloc64f(mpts); + gps_data->data[k].ebuff = memory_calloc64f(mpts); + gps_data->data[k].usigmabuff = memory_calloc64f(mpts); + gps_data->data[k].nsigmabuff = memory_calloc64f(mpts); + gps_data->data[k].esigmabuff = memory_calloc64f(mpts); + gps_data->data[k].tbuff = memory_calloc64f(mpts); + } + return 0; +} diff --git a/src/core/data/readMetaDataFile.c b/src/core/data/readMetaDataFile.c new file mode 100644 index 00000000..ae1948cf --- /dev/null +++ b/src/core/data/readMetaDataFile.c @@ -0,0 +1,418 @@ +#include +#include +#include +#include +#include "gfast_core.h" +#include "iscl/os/os.h" + +static int splitLine(const char *cline, + char netw[64], char stat[64], char loc[64], char chan[64], + double *lat, double *lon, double *elev, + double *dt, double *gain, + char units[64], char sensorType[64]); +/*! + * @brief Reads the site metadata file. From this we initialize the site + * network, station, channel, and location code, it's position (latitude, + * longitude, elevation), sampling period, and gain) + * + * @param[in] metaDataFile name of GPS metadata file + * + * @param[in] metaDataNetworks networks to use (ignore the rest) + * + * @param[in] n_networks number of networks + * + * @param[out] gps_data GPS streams with + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_data_readMetaDataFile(const char *metaDataFile, + char **metaDataNetworks, + int n_networks, + struct GFAST_data_struct *gps_data) +{ + FILE *infl; + char **textfl, **sites, cline[1024], + site[256], chan[64], chan1[64], loc[64], loc1[64], + netw[64], netw1[64], stat[64], stat1[64], + sensorType[64], units[64]; + double gain0[6], dt, elev, gain, lat, lon; + int *lines, i, ierr, j, k, lfound, nlines, nlines_total, ns; + // Initialize + ierr = 0; + infl = NULL; + textfl = NULL; + sites = NULL; + lines = NULL; + nlines = 0; + nlines_total = 0; + ns = 0; + // Require the site file exists + if (!os_path_isfile(metaDataFile)) + { + LOG_ERRMSG("Error site file does not exist: %s", metaDataFile); + return -1; + } + // Open the file for reading and count the total lines (including comments) + infl = fopen(metaDataFile, "r"); + while (fgets(cline, 1024, infl) != NULL) + { + nlines_total = nlines_total + 1; + } + if (nlines_total < 1) + { + LOG_ERRMSG("%s", "Error no data read!"); + ierr = 1; + goto ERROR; + } + rewind(infl); + + // Allocate space (potentially over-allocated with comments) + textfl = (char **)calloc((size_t) nlines_total, sizeof(char *)); + sites = (char **)calloc((size_t) nlines_total, sizeof(char *)); + for (i=0; i 0) + { + bool skipLine = true; + for (k = 0; k < n_networks; k++) + { + if (strcasecmp(netw, metaDataNetworks[k]) == 0) + { + skipLine = false; + break; + } + } + if (skipLine) + { + LOG_DEBUGMSG("Skip line, not in metaDataNetworks: %s", textfl[i]); + continue; + } + } + + // Make the site name + strcpy(site, netw); + strcat(site, "_\0"); + strcat(site, stat); + strcat(site, "_\0"); + if (strlen(chan) != 3) + { + ierr = 1; + LOG_ERRMSG("I don't know how to parse this channel %s", chan); + goto ERROR; + } + strncat(site, chan, 2); + strcat(site, "_\0"); + strcat(site, loc); +//printf("readMetaDataFile: %s.%s.%s.%s gain:%e site:%s\n",netw, stat, chan, loc, gain, site); + // Does this site exist? + for (k=0; kstream_length] = i; + gps_data->stream_length = gps_data->stream_length + 1; + if (lfound == 3 || lfound == 6) + { + if (fabs(gain0[0] - gain0[1]) > 1.e-6 || + fabs(gain0[0] - gain0[2]) > 1.e-6) + { + LOG_ERRMSG("%s", "Error inconsistent gain"); + goto ERROR; + } + } + else if (lfound == 6) + { + if (fabs(gain0[3] - gain0[4]) > 1.e-6 || + fabs(gain0[3] - gain0[5]) > 1.e-6 || + fabs(gain0[3] - gain0[0]) > 1.e-6) + { + LOG_ERRMSG("%s", "Error inconsistent gain"); + goto ERROR; + } + } + } + else + { + LOG_ERRMSG("Couldn't find other channels %s", site); + } +NEXT_LINE:; // Try another site to match + } + // Did we get anything? + if (gps_data->stream_length < 1) + { + LOG_ERRMSG("%s", "No three-component sites found!"); + ierr = 1; + goto ERROR; + } + if (ns != gps_data->stream_length) + { + LOG_WARNMSG("%s", "Warning - counting problem"); + } + gps_data->data = (struct GFAST_waveform3CData_struct *) + calloc((size_t) gps_data->stream_length, + sizeof(struct GFAST_waveform3CData_struct)); + // Now parse the lines + LOG_DEBUGMSG("Creating %d data streams", gps_data->stream_length); + for (k=0; kstream_length; k++) + { + // Parse the line + ierr = splitLine(textfl[lines[k]], + netw, stat, loc, chan, + &lat, &lon, &elev, + &dt, &gain, + units, sensorType); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error parsing line!"); + goto ERROR; + } + // Verify the inputs + if (lat <-90.0 || lat > 90.0) + { + LOG_ERRMSG("Input latitude %f is invalid", lat); + ierr = 1; + goto ERROR; + } + if (lon <-180.0) + { + lon += 360; + } + if (lon <-180.0 || lon > 360.0) + { + LOG_ERRMSG("Input longitude %f is invalid", lon); + ierr = 1; + goto ERROR; + } + if (dt <= 0.0) + { + LOG_ERRMSG("Input sampling period %f is invalid", dt); + ierr = 1; + goto ERROR; + } + if (lon < 0.0){lon = lon + 360.0;} + // And now set the site information + strcpy(gps_data->data[k].netw, netw); + strcpy(gps_data->data[k].stnm, stat); + strncpy(gps_data->data[k].chan[0], chan, 2); + strcat( gps_data->data[k].chan[0], "Z\0"); + strncpy(gps_data->data[k].chan[1], chan, 2); + strcat( gps_data->data[k].chan[1], "N\0"); + strncpy(gps_data->data[k].chan[2], chan, 2); + strcat( gps_data->data[k].chan[2], "E\0"); + strncpy(gps_data->data[k].chan[3], chan, 2); + strcat( gps_data->data[k].chan[3], "3\0"); + strncpy(gps_data->data[k].chan[4], chan, 2); + strcat( gps_data->data[k].chan[4], "2\0"); + strncpy(gps_data->data[k].chan[5], chan, 2); + strcat( gps_data->data[k].chan[5], "1\0"); + strcpy(gps_data->data[k].loc, loc); + gps_data->data[k].sta_lat = lat; + gps_data->data[k].sta_lon = lon; + gps_data->data[k].sta_alt = elev; + gps_data->data[k].dt = dt; + gps_data->data[k].gain[0] = gain; + gps_data->data[k].gain[1] = gain; + gps_data->data[k].gain[2] = gain; + gps_data->data[k].gain[3] = gain; + gps_data->data[k].gain[4] = gain; + gps_data->data[k].gain[5] = gain; + if (gain == 0.0 || dt <= 0.0 || isnan(dt)) + { + if (gain == 0.0) + { + LOG_WARNMSG("%s", "Instrument gain will mute station"); + } + if (dt <= 0.0) + { + LOG_ERRMSG("Sampling period %f is invalid", dt); + ierr = 1; + goto ERROR; + } + if (isnan(dt)) + { + LOG_ERRMSG("%s", "Sampling rate input was zero"); + ierr = 1; + goto ERROR; + } + } + //if (iuse == 0) + //{ + // gps_data->data[k].lskip_pgd = true; + // gps_data->data[k].lskip_cmt = true; + // gps_data->data[k].lskip_ff = true; + //} + } +ERROR:; + if (lines != NULL){free(lines);} + if (textfl != NULL) + { + for (i=0; i +#include +#include +#include "gfast_core.h" +#include "iscl/os/os.h" + +static int splitLine(const char *cline, + char netw[64], char stnm[64], char loc[64], char chan[64], + int *iusePGD, int *iuseCMT, int *iuseFF); + +/*! + * @brief Reads the site mask file and if a SNCL is found mutes the + * site's channel + * + * @param[in] siteMaskFile name of the site mask file + * @param[in] verbose if > 0 then will report on the masked sites + * + * @param[in,out] gps_data on input contains the sites and SNCL's. + * on output, if the SNCL is located in the + * site mask file, the site is masked from the + * inverserions. + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_data_readSiteMaskFile(const char *siteMaskFile, + const int verbose, + struct GFAST_data_struct *gps_data) +{ + FILE *infl; + char cline[1024], netw[64], stnm[64], chan[64], loc[64]; + int i, ierr, iuseCMT, iuseFF, iusePGD, k, nlines; + // No mask file so nothing to do + if (!os_path_isfile(siteMaskFile)){return 0;} + infl = fopen(siteMaskFile, "r"); + nlines = 0; + while (fgets(cline, 1024, infl) != NULL) + { + nlines = nlines + 1; + } + if (nlines < 1) + { + LOG_WARNMSG("%s", "No sites in maskFile"); + fclose(infl); + return 0; + } + rewind(infl); + for (i=0; istream_length; k++) + { + if (strcasecmp(gps_data->data[k].netw, netw) == 0 && + strcasecmp(gps_data->data[k].stnm, stnm) == 0 && + strcasecmp(gps_data->data[k].loc, loc) == 0) + { + if (strcasecmp(gps_data->data[k].chan[0], chan) == 0 || + strcasecmp(gps_data->data[k].chan[1], chan) == 0 || + strcasecmp(gps_data->data[k].chan[2], chan) == 0 || + strcasecmp(gps_data->data[k].chan[3], chan) == 0 || + strcasecmp(gps_data->data[k].chan[4], chan) == 0 || + strcasecmp(gps_data->data[k].chan[5], chan) == 0) + { + if (verbose > 0) + { + LOG_INFOMSG("Masking %s.%s.%s.%s", + netw, stnm, chan, loc); + } + if (iusePGD == 0) + { + gps_data->data[k].lskip_pgd = true; + } + if (iuseCMT == 0) + { + gps_data->data[k].lskip_cmt = true; + } + if (iuseFF == 0) + { + gps_data->data[k].lskip_ff = true; + } + } + } + } // Loop on streams + } // Loop on lines in file + fclose(infl); + return 0; +} + +static int splitLine(const char *cline, + char netw[64], char stnm[64], char loc[64], char chan[64], + int *iusePGD, int *iuseCMT, int *iuseFF) +{ + char *token, *work; + int i, ierr; + const char *split = " "; + // Copy the input + ierr = 0; + i = 0; + work = (char *)calloc(strlen(cline)+1, sizeof(char)); + strcpy(work, cline); + // Set the outputs + memset(netw, 0, sizeof(char)*64); + memset(stnm, 0, sizeof(char)*64); + memset(chan, 0, sizeof(char)*64); + memset(loc, 0, sizeof(char)*64); + *iusePGD = 1; + *iuseCMT = 1; + *iuseFF = 1; + token = strtok(work, split); + while (token) + { + if (i == 0){strcpy(netw, token);} + if (i == 1){strcpy(stnm, token);} + if (i == 2){strcpy(loc, token);} + if (i == 3){strcpy(chan, token);} + if (i == 4){*iusePGD = atoi(token);} + if (i == 5){*iuseCMT = atoi(token);} + if (i == 6){*iuseFF = atoi(token);} + i = i + 1; + token = strtok(NULL, split); + } + if (i != 7) + { + LOG_ERRMSG("Failed to split line %d %s\n", i, cline); + ierr = 1; + } + free(work); + return ierr; +} + diff --git a/src/core/events/Makefile b/src/core/events/Makefile new file mode 100644 index 00000000..1543074d --- /dev/null +++ b/src/core/events/Makefile @@ -0,0 +1,65 @@ +# Makefile for GFAST/src/core/events +# + +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = freeEvents.o newEvent.o removeCancelledEvent.o removeExpiredEvents.o\ + getMinOriginTime.o printEvent.o removeExpiredEvent.o updateEvent.o syncXMLStatusWithEvents.o + +DEBUG = -g +CCFLAGS += -O0 -D_REENTRANT -Dstatic_config + +INCL = -I ../../../include + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(CC) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/core/events/freeEvents.c b/src/core/events/freeEvents.c new file mode 100644 index 00000000..cd8499d7 --- /dev/null +++ b/src/core/events/freeEvents.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Frees memory on the active events structure. + * + * @param[out] events Active event list with data to be freed. + * + * @author Ben Baker, ISTI + * + */ +void core_events_freeEvents(struct GFAST_activeEvents_struct *events) +{ + if (events->nev > 0) + { + free(events->SA); + } + memset(events, 0, sizeof(struct GFAST_activeEvents_struct)); + return; +} diff --git a/src/core/events/getMinOriginTime.c b/src/core/events/getMinOriginTime.c new file mode 100644 index 00000000..321d2c97 --- /dev/null +++ b/src/core/events/getMinOriginTime.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Finds the minimum origin time (UTC epochal seconds) in the + * events list. + * + * @param[in] props Controls verboseness. Less than 1 is quiet. + * @param[in] events A list of the current events in processing. + * + * @param[out] lnoEvents If true then there are no events in the events + * structure or there are no valid origin times. + * + * @result The minimum origin time in the events structure. + * + * @author Ben Baker, ISTI + * + */ +double core_events_getMinOriginTime(struct GFAST_props_struct props, + struct GFAST_activeEvents_struct events, + bool *lnoEvents) +{ + double t0; + int iev; + *lnoEvents = true; + t0 = DBL_MAX; + if (events.nev < 1){return t0;} + *lnoEvents = false; + for (iev=0; iev 1 && fabs(t0 - DBL_MAX) < 1.e-10) + { + *lnoEvents = true; + LOG_WARNMSG("%s", "Warning origin times are screwy"); + } + return t0; +} diff --git a/src/core/events/newEvent.c b/src/core/events/newEvent.c new file mode 100644 index 00000000..dd12e4b0 --- /dev/null +++ b/src/core/events/newEvent.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include "gfast_core.h" +#include +/*! + * @brief Adds a new event to the working events list. + * + * @param[in] SA This is the shakeAlert event whose existence is + * checked for in events struture. If it does not + * exist in events then it is added. + * + * @param[in,out] events On input holds the current active list of events.
+ * On output holds the new event in SA provided that + * SA does not already exist. + * @param[in,out] xml_status On input holds the current active list of GFAST events + * and version numbers. On output holds the new event + * + * @result If true then the new event in SA has been added to the events list. + * + * @author Ben Baker, ISTI + * + */ +bool core_events_newEvent(struct GFAST_shakeAlert_struct SA, + struct GFAST_activeEvents_struct *events, + struct GFAST_activeEvents_xml_status *xml_status) +{ + struct GFAST_activeEvents_struct SAtemp; + + struct GFAST_xml_output_status output_status; + struct GFAST_activeEvents_xml_status Xtemp; + + memset(&output_status, 0, sizeof( struct GFAST_xml_output_status)); + + int iev, nev0, imodified; + bool lnewEvent = true; + bool lupdateEvent = false; + + // New event -> copy and update + nev0 = events->nev; + + for (iev=0; ievSA[iev].eventid) == 0) + { + lnewEvent = false; + if (fabs(SA.lat - events->SA[iev].lat) > 1.e-10 || + fabs(SA.lon - events->SA[iev].lon) > 1.e-10 || + fabs(SA.dep - events->SA[iev].dep) > 1.e-10 || + fabs(SA.mag - events->SA[iev].mag) > 1.e-10 || + fabs(SA.time - events->SA[iev].time) > 1.e-5) + { + lupdateEvent = true; + imodified = iev; + LOG_MSG("MTH: SA.eventid=%s xml has changed NEW OT:%.3f lat:%6.3f lon:%6.3f dep:%.2f mag:%.2f", + SA.eventid, SA.time, SA.lat, SA.lon, SA.dep, SA.mag); + LOG_MSG("MTH: SA.eventid=%s xml has changed OLD OT:%.3f lat:%6.3f lon:%6.3f dep:%.2f mag:%.2f", + events->SA[iev].eventid, events->SA[iev].time, events->SA[iev].lat, + events->SA[iev].lon, events->SA[iev].dep, events->SA[iev].mag); + } + break; + } + } + + if (lnewEvent) + { + // Copy new event into workspace + SAtemp.nev = nev0 + 1; + SAtemp.SA = (struct GFAST_shakeAlert_struct *) + calloc((size_t) SAtemp.nev, + sizeof(struct GFAST_shakeAlert_struct)); + + //LOG_MSG("MTH: nev0=%d --> Copy new event into workspace", nev0); + for (iev=0; ievSA[iev], sizeof(struct GFAST_shakeAlert_struct)); + } + //LOG_MSG("MTH: nev0=%d --> Copy SA to SAtemp.SA", nev0); + memcpy(&SAtemp.SA[nev0], &SA, sizeof(struct GFAST_shakeAlert_struct)); + // Resize events + core_events_freeEvents(events); + events->nev = SAtemp.nev; + events->SA = (struct GFAST_shakeAlert_struct *) + calloc((size_t) events->nev, + sizeof(struct GFAST_shakeAlert_struct)); + // Copy old events back + for (iev=0; ievnev; iev++) + { + memcpy(&events->SA[iev], &SAtemp.SA[iev], + sizeof(struct GFAST_shakeAlert_struct)); + } + // Free SAtemp + core_events_freeEvents(&SAtemp); + + //LOG_MSG("MTH: nev0=%d --> Copy new event into workspace DONE", nev0); + // MTH: Same thing for xml output status structs + // Create a status output_status from incoming SA eventid + strcpy(output_status.eventid, SA.eventid); + output_status.version=-1; /*will increment to 0 on first xml update*/ + // Append this output_status to the incoming xml_status list of records + Xtemp.nev = nev0 + 1; + Xtemp.SA_status = (struct GFAST_xml_output_status *) calloc((size_t) Xtemp.nev, sizeof(struct GFAST_xml_output_status)); + for (iev=0; ievSA_status[iev], sizeof(struct GFAST_xml_output_status)); + } + memcpy(&Xtemp.SA_status[nev0], &output_status, sizeof(struct GFAST_xml_output_status)); + // Free xml_status and copy Xtemp back in + if (xml_status->nev > 0) { + free(xml_status->SA_status); + //memset(xml_status, 0, sizeof(struct GFAST_activeEvents_xml_status)); + } + /* + else { // xml_status is empty + memset(xml_status, 0, sizeof(struct GFAST_activeEvents_xml_status)); + xml_status->SA_status = (struct GFAST_xml_output_status *) calloc((size_t) 1, sizeof(struct GFAST_xml_output_status)); + } + */ + xml_status->nev = Xtemp.nev; + xml_status->SA_status = (struct GFAST_xml_output_status *) calloc((size_t) xml_status->nev, + sizeof(struct GFAST_xml_output_status)); + + //LOG_MSG("MTH: SA.eventid=%s --> Copy Xtemp back to xml_status nev=%d", SA.eventid, xml_status->nev); + // Copy new list back to xml_status: + for (iev=0; ievnev; iev++){ + memcpy(&xml_status->SA_status[iev], &Xtemp.SA_status[iev], sizeof(struct GFAST_xml_output_status)); + } + + // Free Xtemp + free(Xtemp.SA_status); + } + else { + if (lupdateEvent){ + //LOG_MSG("MTH: SA.eventid=%s xml has changed --> update events->SA[%d]", SA.eventid, imodified); + memcpy(&events->SA[imodified], &SA, sizeof(struct GFAST_shakeAlert_struct)); + } + } + return lnewEvent; +} diff --git a/src/core/events/printEvent.c b/src/core/events/printEvent.c new file mode 100644 index 00000000..d1f24910 --- /dev/null +++ b/src/core/events/printEvent.c @@ -0,0 +1,40 @@ +#include +#include +#include "gfast_core.h" +/*! + * @brief Convenience function that prints the details of an event to debug. + * + * @param[in] SA shakeAlert event information structure to print. + * + * @author Ben Baker, ISTI + */ +void core_events_printEvents(struct GFAST_shakeAlert_struct SA) +{ + const char *lspace = " \0"; + char line[128], msg[1024]; + memset(msg, 0, 1024*sizeof(char)); + sprintf(msg, "\n%s Event %s statistics:\n", lspace, SA.eventid); + + memset(line, 0, 128*sizeof(char)); + sprintf(line, "%s Event latitude %f (degrees)\n", lspace, SA.lat); + strcat(msg, line); + + memset(line, 0, 128*sizeof(char)); + sprintf(line, "%s Event longitude %f (degrees)\n", lspace, SA.lon); + strcat(msg, line); + + memset(line, 0, 128*sizeof(char)); + sprintf(line, "%s Event depth %f (km)\n", lspace, SA.dep); + strcat(msg, line); + + memset(line, 0, 128*sizeof(char)); + sprintf(line, "%s Event magnitude %f (km)\n", lspace, SA.mag); + strcat(msg, line); + + memset(line, 0, 128*sizeof(char)); + sprintf(line, "%s Event epochal time %f (s)\n", lspace, SA.time); + strcat(msg, line); + + LOG_DEBUGMSG("%s", msg); + return; +} diff --git a/src/core/events/removeCancelledEvent.c b/src/core/events/removeCancelledEvent.c new file mode 100644 index 00000000..98b4ca52 --- /dev/null +++ b/src/core/events/removeCancelledEvent.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Removes an event ID from the active event list in the case that is + * was cancelled. + * + * @param[in] evid Event ID to remove from events list. + * @param[in] currentTime Current epochal time (UTC seconds). + * @param[in] SA shakeAlert event information to possibly remove. + * @param[in] verbose Controls verbosity. Less than 1 is quiet. + * + * @param[in,out] events On input contains all events.
+ * On output the event list sans the SA event. + * + * @result If true then the event SA was removed from the events list. + * + * @author Ben Baker (ISTI) + * + */ +bool core_events_removeCancelledEvent(const char *evid, + const double currentTime, + const int verbose, + struct GFAST_shakeAlert_struct SA, + struct GFAST_activeEvents_struct *events) +{ + struct GFAST_activeEvents_struct SAtemp; + int iev, jev, nev0, pop_indx; + bool lpopped; + lpopped = false; + if (events == NULL) + { + if (verbose > 0) + { + LOG_WARNMSG("%s", "Warning no events in list"); + } + return lpopped; + } + // Find the event and see if I can remove it + pop_indx =-2; + nev0 = events->nev; + for (iev=0; ievSA[iev].eventid) == 0) + { + pop_indx =-1; + if (strcasecmp(evid, events->SA[iev].eventid) == 0) + { + if (verbose > 0) + { + LOG_INFOMSG("Removing %s %f from event list at %f", + SA.eventid, SA.time, currentTime); + } + pop_indx = iev; + break; + } + } + } + // I couldn't even find the event in the event list + if (pop_indx ==-2) + { + if (verbose > 0) + { + LOG_WARNMSG("Strangely cannot find this event %s", + SA.eventid); + } + return lpopped; + } + // Remove the event? + if (pop_indx >-1) + { + // Only event - good bye + if (nev0 == 1) + { + core_events_freeEvents(events); + events->nev = 0; + return lpopped; + } + // Copy old events into workspace ignoring event at pop_indx + SAtemp.nev = nev0 - 1; + SAtemp.SA = (struct GFAST_shakeAlert_struct *) + calloc((size_t) SAtemp.nev, + sizeof(struct GFAST_shakeAlert_struct)); + jev = 0; + for (iev=0; ievSA[iev], + sizeof(struct GFAST_shakeAlert_struct)); + jev = jev + 1; + } + memcpy(&SAtemp.SA[nev0], &SA, sizeof(struct GFAST_shakeAlert_struct)); + // Resize events + core_events_freeEvents(events); + events->nev = SAtemp.nev; + events->SA = (struct GFAST_shakeAlert_struct *) + calloc((size_t) events->nev, + sizeof(struct GFAST_shakeAlert_struct)); + // Copy old events back + for (iev=0; ievnev; iev++) + { + memcpy(&events->SA[iev], &SAtemp.SA[iev], + sizeof(struct GFAST_shakeAlert_struct)); + } + // Free SAtemp + core_events_freeEvents(&SAtemp); + } + return lpopped; +} diff --git a/src/core/events/removeExpiredEvent.c b/src/core/events/removeExpiredEvent.c new file mode 100644 index 00000000..5fcea5fc --- /dev/null +++ b/src/core/events/removeExpiredEvent.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Removes an event from the active event list if + * (currentTime - SA.time) > maxtime. + * + * @param[in] maxtime Maximum amount of time (s) after the origin + * time which the event can be retained. + * @param[in] currentTime Current time (UTC seconds since epoch). + * @param[in] SA shakeAlert event information to possibly remove. + * @param[in] verbose Controls verbosity. + * + * @param[in,out] events On input contains all events.
+ * On output may contain the removed SA event. + * + * @result If true then the event SA was removed from the events list. + * + * @author Ben Baker (ISTI) + * + */ +bool core_events_removeExpiredEvent(const double maxtime, + const double currentTime, + const int verbose, + struct GFAST_shakeAlert_struct SA, + struct GFAST_activeEvents_struct *events) +{ + struct GFAST_activeEvents_struct SAtemp; + int iev, jev, nev0, pop_indx; + bool lpopped; + lpopped = false; + if (events == NULL) + { + if (verbose > 0) + { + LOG_WARNMSG("%s", "Warning no events in list"); + } + return lpopped; + } + // Find the event and see if I can remove it + pop_indx =-2; + nev0 = events->nev; + for (iev=0; ievSA[iev].eventid) == 0) + { + pop_indx =-1; + + if ((currentTime - SA.time) > maxtime) + { + LOG_MSG("time:%lf Remove evid:%s otime:%f from event list", + currentTime, SA.eventid, SA.time); + if (verbose > 0) + { + LOG_INFOMSG("Removing %s %f from event list at %f", + SA.eventid, SA.time, currentTime); + } + pop_indx = iev; + break; + } + } + } + // I couldn't even find the event in the event list + if (pop_indx ==-2) + { + if (verbose > 0) + { + LOG_WARNMSG("Strangely cannot find this event %s", SA.eventid); + } + return lpopped; + } + // Remove the event? + lpopped = true; + if (pop_indx >-1) + { + // Only event - good bye + if (nev0 == 1) + { + core_events_freeEvents(events); + events->nev = 0; + return lpopped; + } + // Copy old events into workspace ignoring event at pop_indx + //LOG_MSG("Copy nev0-1=%d events into workspace, ignore expired event[%d]", nev0-1, pop_indx); + SAtemp.nev = nev0 - 1; + SAtemp.SA = (struct GFAST_shakeAlert_struct *) + calloc((size_t) SAtemp.nev, sizeof(struct GFAST_shakeAlert_struct)); + jev = 0; + for (iev=0; ievSA[iev].eventid, jev); + memcpy(&SAtemp.SA[jev], &events->SA[iev], sizeof(struct GFAST_shakeAlert_struct)); + jev = jev + 1; + } + //LOG_MSG("%s", "Copy SAtemp into SA"); + //memcpy(&SAtemp.SA[nev0], &SA, sizeof(struct GFAST_shakeAlert_struct)); + // Resize events + core_events_freeEvents(events); + events->nev = SAtemp.nev; + events->SA = (struct GFAST_shakeAlert_struct *) + calloc((size_t) events->nev, sizeof(struct GFAST_shakeAlert_struct)); + // Copy old events back + for (iev=0; ievnev; iev++) + { + //LOG_MSG("memcpy SAtemp.SA[%d] evid:%s back to events->SA", + //iev, SAtemp.SA[iev].eventid); + memcpy(&events->SA[iev], &SAtemp.SA[iev], sizeof(struct GFAST_shakeAlert_struct)); + } + // Free SAtemp + core_events_freeEvents(&SAtemp); + } + return lpopped; +} diff --git a/src/core/events/removeExpiredEvents.c b/src/core/events/removeExpiredEvents.c new file mode 100644 index 00000000..d6b61576 --- /dev/null +++ b/src/core/events/removeExpiredEvents.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Convenience function to pop expired events from the events list. + * An event is expired when: + * currentTime - eventOriginTime > processingTime. + * + * @param[in] processingTime Max processing time (seconds) for any event. + * @param[in] currentTime Current time (UTC epochal seconds). + * @param[in] verbose Controls the verbosity. 0 is quiet. + * + * @param[in,out] events On input holds the active events list. + * On output expired events have been removed. + * + * @result The number of events removed from the list. + * + * @author Ben Baker + * + */ +int core_events_removeExpiredEvents(const double processingTime, + const double currentTime, + const int verbose, + struct GFAST_activeEvents_struct *events) +{ + struct GFAST_shakeAlert_struct *SAall; + double t1, t2; + int iev, nev0, nrem; + bool ldownDate, lgone; + // Nothing to remove + nrem = 0; + if (events->nev < 1){return 0;} + // Create a copy of the events + nev0 = events->nev; + SAall = (struct GFAST_shakeAlert_struct *) + calloc((size_t) nev0, sizeof(struct GFAST_shakeAlert_struct)); + for (iev=0; ievnev; iev++) + { + memcpy(&SAall[iev], &events->SA[iev], + sizeof(struct GFAST_shakeAlert_struct)); + } + // Look for expired events + for (iev=0; iev= processingTime){ldownDate = true;} +//LOG_MSG("removeExpiredEvents: iev=%d ldownDate=%d", iev, ldownDate); + if (ldownDate) + { + lgone = core_events_removeExpiredEvent(processingTime, + currentTime, + verbose, + SAall[iev], events); + if (!lgone) + { + LOG_WARNMSG("Strange - but keeping %s", SAall[iev].eventid); + } + else + { + nrem = nrem + 1; + } + } + } +//LOG_MSG("removeExpiredEvents: nrem=%d free(SAall)", nrem); + free(SAall); +//LOG_MSG("removeExpiredEvents: nrem=%d free(SAall) DONE --> return", nrem); + return nrem; +} diff --git a/src/core/events/syncXMLStatusWithEvents.c b/src/core/events/syncXMLStatusWithEvents.c new file mode 100644 index 00000000..0dbb5b97 --- /dev/null +++ b/src/core/events/syncXMLStatusWithEvents.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Keep xml_status in sync with events list + * + * @param[in] events On input contains all events. + * @param[in] xml_status On input contains output_complete status for all events + * + * @author Mike Hagerty (ISTI) + * + */ +bool core_events_syncXMLStatusWithEvents(struct GFAST_activeEvents_struct *events, + struct GFAST_activeEvents_xml_status *xml_status) +{ + struct GFAST_xml_output_status output_status; + struct GFAST_activeEvents_xml_status Xtemp; + + char eventid[128]; + + memset(&output_status, 0, sizeof( struct GFAST_xml_output_status)); + + int iev, jev, nev, nstats, ifound; + bool found; + + nev = events->nev; + nstats = xml_status->nev; + + if (nev == 0){ + //for (iev=0; iev release xml_status[%d]=%s", iev, xml_status->SA_status[iev].eventid); + //} + free(xml_status->SA_status); + xml_status->nev = 0; + LOG_MSG("events is empty --> release the %d xml status and return", nstats); + return true; + } + + Xtemp.nev = nev; + Xtemp.SA_status = (struct GFAST_xml_output_status *) calloc((size_t) Xtemp.nev, sizeof(struct GFAST_xml_output_status)); + + //LOG_MSG("events is NOT empty nev=%d --> sync xml_status with events", nev); + + for (iev=0; ievSA[iev].eventid); + + found = false; + for (jev=0; jevSA_status[jev].eventid, eventid) == 0){ + found = true; + ifound = jev; + break; + } + } + if (found) { + // copy this xml_status output_status record to Xtemp + //LOG_MSG("Events iev:%d eventid:%s : Copy xml_status SA_status[%d] to Xtemp SA_status[%d]", + //iev, eventid, ifound, iev); + memcpy(&Xtemp.SA_status[iev], &xml_status->SA_status[ifound], sizeof(struct GFAST_xml_output_status)); + } + else { + // create new one from this eventid + //LOG_MSG("Events iev:%d eventid:%s not found in xml_status : Create new xml_status SA record for this eventid", + //iev, eventid); + strcpy(output_status.eventid, eventid); + memcpy(&Xtemp.SA_status[iev], &output_status, sizeof(struct GFAST_xml_output_status)); + } + + } + + for (iev=0; ievnev; iev++){ + found = false; + for (jev=0; jevSA_status[iev].eventid, Xtemp.SA_status[jev].eventid) == 0){ + found = true; + break; + } + } + if (!found) { + LOG_MSG("Eventid:%s was removed from xml_status", xml_status->SA_status[iev].eventid); + } + } + + // Free xml_status and copy Xtemp back in + //LOG_MSG("free xml_status->SA_status and copy nev=%d back in", nev); + free(xml_status->SA_status); + //memset(xml_status, 0, sizeof(struct GFAST_activeEvents_xml_status)); + xml_status->nev = Xtemp.nev; + xml_status->SA_status = (struct GFAST_xml_output_status *) calloc((size_t) + xml_status->nev, sizeof(struct GFAST_xml_output_status)); + + // Copy new list back to xml_status: + //LOG_MSG("copy nev=%d back in to xml_status and release Xtemp.SA_status", nev); + for (iev=0; ievnev; iev++){ + memcpy(&xml_status->SA_status[iev], &Xtemp.SA_status[iev], sizeof(struct GFAST_xml_output_status)); + } + + // Free Xtemp + //LOG_MSG("syncXMLStatus xml_status->nev=%d Free Xtemp.SA_status and return", xml_status->nev); + free(Xtemp.SA_status); + return 0; +} diff --git a/src/core/events/updateEvent.c b/src/core/events/updateEvent.c new file mode 100644 index 00000000..eff5743c --- /dev/null +++ b/src/core/events/updateEvent.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include "gfast_core.h" +/*! + * @brief Checks if the shakeAlert event differs from the version in the + * current events list and if it does differ then this function + * updates the events list to match the input SA event + * + * @param[in] SA shakeAlert structure to check for in events list + * + * @param[in,out] events on input contains the current list of events. + * on output, if SA is not identical to an SA in the + * events list, the input SA then overrides the + * the corresponding SA in events. additionally, if + * SA does not exist in events then the program will + * attempt to add the event. + * + * @param[out] ierr 0 indicates success + * + * @result true if the event structure has been modified to accomodate the + * input shakeAlert event SA + * + * @author Ben Baker, ISTI + * + */ +bool core_events_updateEvent(struct GFAST_shakeAlert_struct SA, + struct GFAST_activeEvents_struct *events, + int *ierr) +{ + bool lfound, lmodified, lnew_event; + int iev; + *ierr = 0; + lmodified = false; + // Look for this event and + lfound = false; + for (iev=0; ievnev; iev++) + { + if (strcasecmp(events->SA[iev].eventid, SA.eventid) == 0) + { + lfound = true; + if (fabs(SA.lat - events->SA[iev].lat) > 1.e-10 || + fabs(SA.lon - events->SA[iev].lon) > 1.e-10 || + fabs(SA.dep - events->SA[iev].dep) > 1.e-10 || + fabs(SA.mag - events->SA[iev].mag) > 1.e-10 || + fabs(SA.time - events->SA[iev].time) > 1.e-5) + { + memcpy(&events->SA[iev], &SA, + sizeof(struct GFAST_shakeAlert_struct)); + lmodified = true; + } + break; + } + } + // Surprisingly i didn't find the event - try to add it + if (!lfound) + { + LOG_WARNMSG("Warning will try to append event %s to list", + SA.eventid); + // MTH: I don't believe updateEvent is used, but just in case: + //lnew_event = core_events_newEvent(SA, events); + LOG_ERRMSG("%s", "MTH: ERROR: updateEvent was called!! --> Exit!"); + exit(2); + + if (!lnew_event) + { + LOG_WARNMSG("%s", "This is really weird"); + } + else + { + lmodified = true; + } + } + return lmodified; +} diff --git a/src/core/ff/Makefile b/src/core/ff/Makefile new file mode 100644 index 00000000..aa38da74 --- /dev/null +++ b/src/core/ff/Makefile @@ -0,0 +1,67 @@ +# Makefile for GFAST/src/core/ff +# + +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +DEBUG = -g + +OBJS = faultPlaneGridSearch.o meshFaultPlane.o setForwardModel.o \ +weightForwardModel.o finalize.o readIni.o setRegularizer.o \ +weightObservations.o initialize.o setDiagonalWeightMatrix.o setRHS.o + + +#iniparser will be deleted later +INCL = -I ../../../include $(INIPARSER_INCL) $(CBLAS_INCL) $(LAPACKE_INCL) $(ISCL_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(cc) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/core/ff/faultPlaneGridSearch.c b/src/core/ff/faultPlaneGridSearch.c new file mode 100644 index 00000000..16ed398b --- /dev/null +++ b/src/core/ff/faultPlaneGridSearch.c @@ -0,0 +1,516 @@ +#include +#include +#include +#include +#include +#include "gfast_core.h" +#ifdef GFAST_USE_INTEL + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Weverything" + #endif + #include + #include + #ifdef __clang__ + #pragma clang diagnostic pop + #endif +#else +#include +#include +#endif +#include "iscl/array/array.h" +#include "iscl/linalg/linalg.h" +#include "iscl/time/time.h" +#include "iscl/memory/memory.h" + +/*! + * @brief This performs the grid-search finite-fault slip inversion + * for the given fault planes. + * + * @note The fault plane arrays (e.g. fault_xutm, fault_yutm, fault_alt, + * length, width, strike, dip, sslip, dslip, sslip_unc, dslip_unc) + * are packed such that the istr'th, idip'th element on the ifp'th fault + * plane is given ifp*l2 + idip*nstr + istr by where l2 = nstr*ndip. + * Similarly, the estimate displacement in the NN, EN, and UN + * for the i'th site for the ifp'th fault plane is given by + * ifp*l1 + i where l1 is the number of sites in the inversion. + * + * @param[in] l1 number of sites in the inversion. + * @param[in] l2 leading dimension for the fault plane + * information. this must be nstr*ndip. + * @param[in] nstr number of elements along strike in each fault + * plane. + * @param[in] ndip number of elements down dip in each fault plane. + * @param[in] nfp number of fault planes in grid-search + * @param[in] verbose controls verbosity (0 will only report on + * errors) + * @param[in] nObsOffset the observed offset (m) in the north component + * for the i'th site [l1] + * @param[in] eObsOffset the observed offset (m) in the east component + * for the i'th site [l1] + * @param[in] uObsOffset the observed offset (m) in the vertical + * component for the i'th site [l1] + * @param[in] nWts data weight on the i'th north observation [l1] + * @param[in] eWts data weight on the i'th east observation [l1] + * @param[in] uWts data weight on the i'th vertical observation [l1] + * @param[in] utmRecvEasting the UTM easting location (m) of the i'th + * site [l1] + * @param[in] utmRecvNorthing the UTM northing location (m) of the i'th + * site [l1] + * @param[in] staAlt altitude (m) of i'th site above sea-level [l1] + * @param[in] fault_xutm the UTM x (east) location (m) of the if'th + * fault patch on the ifp'th fault plane [l2*nfp]. + * @param[in] fault_yutm the UTM y (north) location (m) of the if'th + * fault patch on the ifp'th fault plane [l2*nfp]. + * @param[in] fault_alt depth (km) of the if'th fault patch on the + * ifp'th fault plane [l2*nfp]. + * @param[in] length the length (m) of the if'th fault patch on the + * ifp'th fault plane [l2*nfp]. + * @param[in] width the width (m) of the if'th fault patch on the + * ifp'th fault plane [l2*nfp]. + * @param[in] strike the strike angle (degrees) of the if'th fault + * patch on the ifp'th fault plane [l2*nfp]. + * @param[in] dip the dip angle (degrees) of the if'th fault + * patch on the ifp'th fault plane [l2*nfp]. + * + * @param[out] sslip slip along strike (m) on the if'th fault patch + * on the ifp'th fault plane [l2*nfp]. + * @param[out] dslip slip down dip (m) on the if'th fault patch + * of the ifp'th fault plane [l2*nfp]. + * @param[out] Mw moment magnitude for the event on the ifp'th + * fault plane [nfp]. + * @param[out] vr the variance reduction for the linearized slip + * inversion on the ifp'th fault plane [nfp] + * @param[out] NN the estimated displacement in the north component + * (m) for the i'th site on the ifp'th fault plane + * [l1*nfp]. + * @param[out] EN the estimated displacement in the east component + * (m) for the i'th site on the ifp'th fault plane + * [11*nfp]. + * @param[out] UN the estimated displacement in the the vertical + * component (m) for the i'th site on the ifp'th + * fault plane [l1*nfp]. + * + * @param[in,out] sslip_unc If not NULL then this is the uncertainty (m) + * estimated from the diagonal of the model + * covariance matrix for the slip along strike on + * the if'th fault patch on the ifp'th fault plane. + * Note, that it must still be multiplied by a + * confidence level and a standard deviation. + * If sslip_unc is requested then it must be an + * array of dimension of [l2*nfp]. + * @param[in,out] dslip_unc If not NULL then this is the uncertainty (m) + * estimated from the diagonal of the model + * covariance matrix for the slip down dip on + * the on the if'th fault patch on the ifp'th + * fault plane. Note, that it must still be + * multiplied by a confidence level and a + * standard deviation. If dslip_unc is requested + * then it must be an array of dimension [l2*nfp]. + * + * @result 0 indicates success. + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @date May 2016 + * + */ +int core_ff_faultPlaneGridSearch(const int l1, const int l2, + const int nstr, const int ndip, + const int nfp, const int verbose, + const double *__restrict__ nObsOffset, + const double *__restrict__ eObsOffset, + const double *__restrict__ uObsOffset, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ fault_xutm, + const double *__restrict__ fault_yutm, + const double *__restrict__ fault_alt, + const double *__restrict__ length, + const double *__restrict__ width, + const double *__restrict__ strike, + const double *__restrict__ dip, + double *__restrict__ sslip, + double *__restrict__ dslip, + double *__restrict__ Mw, + double *__restrict__ vr, + double *__restrict__ NN, + double *__restrict__ EN, + double *__restrict__ UN, + double *__restrict__ sslip_unc, + double *__restrict__ dslip_unc + ) +{ + double *diagWt, *G, *G2, *R, *S, *T, *UD, *UP, *WUD, *xrs, *yrs, *zrs, + asum, ds_unc, lampred, len0, ss_unc, st, M0, res, wid0, xden, xnum; + int i, ierr, ierr1, if_off, ifp, ij, io_off, j, + mrowsG, mrowsG2, mrowsT, ncolsG, ncolsG2, ncolsT, ng, ng2, nt; + bool lrmtx, lsslip_unc, ldslip_unc; + //------------------------------------------------------------------------// + // + // Initialize + ierr = 0; + xrs = NULL; + yrs = NULL; + zrs = NULL; + G2 = NULL; + UD = NULL; + UP = NULL; + T = NULL; + S = NULL; + R = NULL; + lrmtx = false; + lsslip_unc = false; + ldslip_unc = false; + // Error handling + if (l1 <= 0 || l2 <= 0 || l2 != nstr*ndip) + { + if (l1 <= 0){LOG_ERRMSG("%s", "Error no observations");} + if (l2 <= 0){LOG_ERRMSG("%s", "Error no points in fault plane");} + if (l2 != nstr*ndip) + { + LOG_ERRMSG("Error l2 != nstr*ndip %d %d*%d!", l2, nstr, ndip); + } + return -1; + } + if (utmRecvEasting == NULL || utmRecvNorthing == NULL || + fault_xutm == NULL || fault_yutm == NULL || + length == NULL || width == NULL || strike == NULL || dip == NULL || + sslip == NULL || dslip == NULL) + { + if (utmRecvEasting == NULL) + { + LOG_ERRMSG("%s", "Error utmRecvEasting is NULL"); + } + if (utmRecvNorthing == NULL) + { + LOG_ERRMSG("%s", "Error utmRecvNorthing is NULL"); + } + if (fault_xutm == NULL){LOG_ERRMSG("%s", "Error fault_xutm is NULL");} + if (fault_yutm == NULL){LOG_ERRMSG("%s", "Error fault_yutm is NULL");} + if (length == NULL){LOG_ERRMSG("%s", "Error length is NULL");} + if (width == NULL){LOG_ERRMSG("%s", "Error width is NULL");} + if (strike == NULL){LOG_ERRMSG("%s", "Error strike is NULL");} + if (dip == NULL){LOG_ERRMSG("%s", "Error dip is NULL");} + if (sslip == NULL){LOG_ERRMSG("%s", "Error sslip is NULL");} + if (dslip == NULL){LOG_ERRMSG("%s", "Error dslip is NULL");} + return -1; + } + if (sslip_unc != NULL || dslip_unc != NULL) + { + if (sslip_unc != NULL){lsslip_unc = true;} + if (dslip_unc != NULL){ldslip_unc = true;} + lrmtx = true; + } + // Compute sizes of matrices in G2 S = UP where G2 = [G; T] + mrowsG = 3*l1; + ncolsG = 2*l2; + mrowsT = 2*ndip*nstr + 2*(2*ndip + nstr - 2); + ncolsT = 2*l2; + mrowsG2 = mrowsG + mrowsT; + ncolsG2 = ncolsG; + nt = mrowsT*ncolsT; + ng = mrowsG*ncolsG; + ng2 = mrowsG2*ncolsG2; + // Set space + WUD = memory_calloc64f(mrowsG2); + UD = memory_calloc64f(mrowsG); + diagWt = memory_calloc64f(mrowsG); + if (WUD == NULL || UD == NULL || diagWt == NULL) + { + if (WUD == NULL){LOG_ERRMSG("%s", "Error setting space for WUD");} + if (UD == NULL){LOG_ERRMSG("%s", "Error setting space for UP");} + if (diagWt == NULL) + { + LOG_ERRMSG("%s", "Error setting space for diagWt"); + } + ierr = 5; + goto ERROR; + } + if (verbose > 2){LOG_DEBUGMSG("%s", "Setting RHS...");} + // Set the RHS + ierr = core_ff_setRHS(l1, + nObsOffset, + eObsOffset, + uObsOffset, + UD); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting right hand side"); + goto ERROR; + } + // Compute the diagonal data weights + ierr = core_ff_setDiagonalWeightMatrix(l1, + nWts, + eWts, + uWts, + diagWt); + if (ierr != 0) + { + LOG_WARNMSG("%s", "Setting data weights to unity"); + array_set64f_work(mrowsG, 1.0, diagWt); + } + // Weight the observations + ierr = core_ff_weightObservations(mrowsG, + diagWt, + UD, + WUD); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error weighting observations"); + goto ERROR; + } + // Begin the grid search on fault planes + ierr = 0; + time_tic(); + if (verbose > 2) + { + LOG_DEBUGMSG("%s", "Beginning search on fault planes..."); + } +#ifdef PARALLEL_FF + #pragma omp parallel \ + private(asum, ds_unc, G, G2, i, ierr1, ifp, if_off, ij, io_off, j, \ + lampred, len0, M0, R, res, S, ss_unc, st, T, UP, wid0, \ + xrs, xden, xnum, yrs, zrs) \ + shared(diagWt, dip, dslip, dslip_unc, EN, fault_alt, \ + fault_xutm, fault_yutm, ldslip_unc, length, \ + lrmtx, lsslip_unc, Mw, mrowsG, mrowsG2, ncolsG, ncolsG2, \ + ng, ng2, NN, nt, sslip, sslip_unc, staAlt, strike, \ + vr, WUD, UD, UN, utmRecvEasting, utmRecvNorthing, width) \ + reduction(+:ierr) default(none) + { +#endif + R = NULL; + G = memory_calloc64f(ng); + G2 = memory_calloc64f(ng2); + S = memory_calloc64f(ncolsG2); + T = memory_calloc64f(nt); + UP = memory_calloc64f(mrowsG); + xrs = memory_calloc64f(l1*l2); + yrs = memory_calloc64f(l1*l2); + zrs = memory_calloc64f(l1*l2); + if (lrmtx){R = memory_calloc64f(ncolsG2*ncolsG2);} +#ifdef PARALLEL_FF + #pragma omp for +#endif + // Loop on fault planes + for (ifp=0; ifp 0.0){Mw[ifp] = (log10(M0*1.e7) - 16.1)/1.5;} + } // Loop on fault planes + memory_free64f(&G); + memory_free64f(&G2); + memory_free64f(&S); + memory_free64f(&T); + memory_free64f(&UP); + memory_free64f(&xrs); + memory_free64f(&yrs); + memory_free64f(&zrs); + memory_free64f(&R); +#ifdef PARALLEL_FF + } +#endif + if (ierr != 0) + { + LOG_ERRMSG("%s", "There was an error in the fault plane grid-search"); + ierr = 4; + } + else + { + if (verbose > 2) + { + LOG_DEBUGMSG("Fault plane grid-search time: %f (s)", time_toc()); + } + } +ERROR:; + // Clean up + memory_free64f(&WUD); + memory_free64f(&UD); + memory_free64f(&diagWt); + return ierr; +} diff --git a/src/core/ff/finalize.c b/src/core/ff/finalize.c new file mode 100644 index 00000000..e66e3fc2 --- /dev/null +++ b/src/core/ff/finalize.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Free the fault plane structure + * + * @param[in,out] fp fault plane structure with memory to be freed + * + * @author Ben Baker (ISTI) + * + */ +void core_ff_finalizeFaultPlane(struct GFAST_faultPlane_struct *fp) +{ + if (fp == NULL){return;} + memory_free64f(&fp->lon_vtx); + memory_free64f(&fp->lat_vtx); + memory_free64f(&fp->dep_vtx); + memory_free64f(&fp->fault_xutm); + memory_free64f(&fp->fault_yutm); + memory_free64f(&fp->fault_alt); + memory_free64f(&fp->strike); + memory_free64f(&fp->dip); + memory_free64f(&fp->length); + memory_free64f(&fp->width); + memory_free64f(&fp->sslip); + memory_free64f(&fp->dslip); + memory_free64f(&fp->sslip_unc); + memory_free64f(&fp->dslip_unc); + memory_free64f(&fp->EN); + memory_free64f(&fp->NN); + memory_free64f(&fp->UN); + memory_free64f(&fp->Einp); + memory_free64f(&fp->Ninp); + memory_free64f(&fp->Uinp); + memory_free32i(&fp->fault_ptr); + memset(fp, 0, sizeof(struct GFAST_faultPlane_struct)); + return; +} +//============================================================================// +/*! + * @brief Free the finite fault results structure + * + * @param[in,out] ff finite fault results structure with memory to be freed + * + * @author Ben Baker, ISTI + * + */ +void core_ff_finalizeResults(struct GFAST_ffResults_struct *ff) +{ + int ifp; + if (ff == NULL){return;} + if (ff->nfp < 1){return;} + for (ifp=0; ifpnfp; ifp++) + { + core_ff_finalizeFaultPlane(&ff->fp[ifp]); + } + if (ff->fp != NULL){free(ff->fp);} + memory_free64f(&ff->vr); + memory_free64f(&ff->Mw); + memory_free64f(&ff->str); + memory_free64f(&ff->dip); + memset(ff, 0, sizeof(struct GFAST_ffResults_struct)); + return; +} +//============================================================================// +/*! + * @brief Frees memory associated with the offset data + * + * @param[in,out] offset_data offset data structure with memory to be freed + * + * @author Ben Baker (ISTI) + * + */ +void core_ff_finalizeOffsetData(struct GFAST_offsetData_struct *offset_data) +{ + int i; + if (offset_data->stnm != NULL) + { + for (i=0; insites; i++) + { + free(offset_data->stnm[i]); + } + free(offset_data->stnm); + } + memory_free64f(&offset_data->ubuff); + memory_free64f(&offset_data->nbuff); + memory_free64f(&offset_data->ebuff); + memory_free64f(&offset_data->wtu); + memory_free64f(&offset_data->wtn); + memory_free64f(&offset_data->wte); + memory_free64f(&offset_data->sta_lat); + memory_free64f(&offset_data->sta_lon); + memory_free64f(&offset_data->sta_alt); + memory_free8l(&offset_data->lmask); + memory_free8l(&offset_data->lactive); + memset(offset_data, 0, sizeof(struct GFAST_offsetData_struct)); + return; +} +//============================================================================// +/*! + * @brief Convenience function for freeing the finite fault structure and + * the data + * + * @param[out] ff_props nulled out finite fault properties + * @param[out] offset_data offset data structure with memory to be freed + * @param[out] ff finite fault results structure with memory + * to be freed + * + * @author Ben Baker (ISTI) + * + */ +void core_ff_finalize(struct GFAST_ff_props_struct *ff_props, + struct GFAST_offsetData_struct *offset_data, + struct GFAST_ffResults_struct *ff) +{ + core_properties_finalizeFFProperties(ff_props); + core_ff_finalizeOffsetData(offset_data); + core_ff_finalizeResults(ff); + return; +} + diff --git a/src/core/ff/initialize.c b/src/core/ff/initialize.c new file mode 100644 index 00000000..8c97a612 --- /dev/null +++ b/src/core/ff/initialize.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Allocates space for the finite fault inversion. It is assumed + * here that only two planes are inverted on. + * + * @param[in] props holds the FF parameters + * @param[in] gps_data holds the site stream length + * + * @param[out] ff has space allocated for the FF inversion + * @param[out] ff_data holds space for the offset data to be used + * in the FF inversion as well as requisite + * site information + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_ff_initialize(struct GFAST_ff_props_struct props, + struct GFAST_data_struct gps_data, + struct GFAST_ffResults_struct *ff, + struct GFAST_offsetData_struct *ff_data) +{ + int i, ifp, maxobs, nstr_ndip; + //------------------------------------------------------------------------// + maxobs = gps_data.stream_length; + if (maxobs < 1) + { + LOG_ERRMSG("There will be no data %d in FF inversion!", maxobs); + return -1; + } + nstr_ndip = props.ndip*props.nstr; + if (nstr_ndip < 1) + { + LOG_ERRMSG("Error not fault patches %d!", nstr_ndip); + return -1; + } + // data + ff_data->stnm = (char **)calloc((size_t) (gps_data.stream_length), + sizeof(char *)); + ff_data->ubuff = memory_calloc64f(gps_data.stream_length); + ff_data->nbuff = memory_calloc64f(gps_data.stream_length); + ff_data->ebuff = memory_calloc64f(gps_data.stream_length); + ff_data->wtu = memory_calloc64f(gps_data.stream_length); + ff_data->wtn = memory_calloc64f(gps_data.stream_length); + ff_data->wte = memory_calloc64f(gps_data.stream_length); + ff_data->sta_lat = memory_calloc64f(gps_data.stream_length); + ff_data->sta_lon = memory_calloc64f(gps_data.stream_length); + ff_data->sta_alt = memory_calloc64f(gps_data.stream_length); + ff_data->lmask = memory_calloc8l(gps_data.stream_length); + ff_data->lactive = memory_calloc8l(gps_data.stream_length); + ff_data->nsites = gps_data.stream_length; + for (i=0; insites; i++) + { + ff_data->sta_lat[i] = gps_data.data[i].sta_lat; + ff_data->sta_lon[i] = gps_data.data[i].sta_lon; + ff_data->sta_alt[i] = gps_data.data[i].sta_alt; + ff_data->stnm[i] = (char *)calloc(64, sizeof(char)); + strcpy(ff_data->stnm[i], gps_data.data[i].netw); + strcat(ff_data->stnm[i], ".\0"); + strcat(ff_data->stnm[i], gps_data.data[i].stnm); + strcat(ff_data->stnm[i], ".\0"); + strncpy(ff_data->stnm[i], gps_data.data[i].chan[0], 2); + strcat(ff_data->stnm[i], "?.\0"); + if (strlen(gps_data.data[i].loc) > 0) + { + strcat(ff_data->stnm[i], gps_data.data[i].loc); + } + if (gps_data.data[i].lskip_ff){ff_data->lmask[i] = true;} + } + // ff inversion structure + ff->preferred_fault_plane = 0; + ff->nfp = props.nfp; + ff->vr = memory_calloc64f(ff->nfp); + ff->Mw = memory_calloc64f(ff->nfp); + ff->str = memory_calloc64f(ff->nfp); + ff->dip = memory_calloc64f(ff->nfp); + ff->fp = (struct GFAST_faultPlane_struct *) + calloc((size_t) ff->nfp, + sizeof(struct GFAST_faultPlane_struct)); + for (ifp=0; ifpnfp; ifp++) + { + ff->fp[ifp].maxobs = maxobs; + ff->fp[ifp].nsites_used = 0; + ff->fp[ifp].nstr = props.nstr; + ff->fp[ifp].ndip = props.ndip; + ff->fp[ifp].lon_vtx = memory_calloc64f(4*nstr_ndip); + ff->fp[ifp].lat_vtx = memory_calloc64f(4*nstr_ndip); + ff->fp[ifp].dep_vtx = memory_calloc64f(4*nstr_ndip); + ff->fp[ifp].fault_xutm = memory_calloc64f(nstr_ndip); + ff->fp[ifp].fault_yutm = memory_calloc64f(nstr_ndip); + ff->fp[ifp].fault_alt = memory_calloc64f(nstr_ndip); + ff->fp[ifp].strike = memory_calloc64f(nstr_ndip); + ff->fp[ifp].dip = memory_calloc64f(nstr_ndip); + ff->fp[ifp].length = memory_calloc64f(nstr_ndip); + ff->fp[ifp].width = memory_calloc64f(nstr_ndip); + ff->fp[ifp].sslip = memory_calloc64f(nstr_ndip); + ff->fp[ifp].dslip = memory_calloc64f(nstr_ndip); + ff->fp[ifp].sslip_unc = memory_calloc64f(nstr_ndip); + ff->fp[ifp].dslip_unc = memory_calloc64f(nstr_ndip); + ff->fp[ifp].EN = memory_calloc64f(maxobs); + ff->fp[ifp].NN = memory_calloc64f(maxobs); + ff->fp[ifp].UN = memory_calloc64f(maxobs); + ff->fp[ifp].Einp = memory_calloc64f(maxobs); + ff->fp[ifp].Ninp = memory_calloc64f(maxobs); + ff->fp[ifp].Uinp = memory_calloc64f(maxobs); + ff->fp[ifp].fault_ptr = memory_calloc32i(nstr_ndip + 1); + } + return 0; +} + diff --git a/src/core/ff/meshFaultPlane.c b/src/core/ff/meshFaultPlane.c new file mode 100644 index 00000000..3637bf50 --- /dev/null +++ b/src/core/ff/meshFaultPlane.c @@ -0,0 +1,248 @@ +#include +#include +#include +#include "gfast_core.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +/*! + * @brief Meshes a fault plane from the magnitude, strike, and dip + * computed in the CMT inversion. Note the fault patch at + * (istr, idep) is accessed by kndx = idip*nstr + istr. + * For more information on the magnitude to fault size scaling + * see D. Dreger and A Kaverina, Seismic Remote Sending for the + * Earthquake Source Process and Near-Source STrong Shaking: A Case + * Study of the October 16, 1999 Hector Mine Earthquake. + * Geophysical Research Letters, Volume 27 (No 13), 1941-1944, (2000). + * + * @param[in] ev_lat event latitude (degrees) + * @param[in] ev_lon event longitude (degrees) + * @param[in] ev_dep event depth (km) + * @param[in] flen_pct safety factor (percentage) added to fault length + * s.t. the entire unilateral rupture is accounted + * for. [0,100] - Dreger and Kaverina recommend + * 10 percent + * @param[in] fwid_pct safety factor (percentage) added to fault width + * s.t. the entire unilateral rupture is accounted + * for. [0,100] - Dreger and Kaverina recommend + * 10 percent + * @param[in] M moment magnitude + * @param[in] strikeF strike angle (degrees) of the fault plane. + * this is measured clockwise positive from north + * [0,360]. + * @param[in] dipF dip angle (degrees) of the fault plane. + * this is measured positive down from horizontal + * [0,90] + * @param[in] nstr number of fault patches along strike + * @param[in] ndip number of fault patches down dip + * @param[in] utm_zone UTM zone. If out of bounds [0,60] then the UTM zone + * will be selected by computing the UTM zone for the + * source and applying that too all the receivers + * @param[in] verbose controls verbosity (< 2 is quiet) + * + * @param[out] fault_ptr maps from the ifp'th fault to the start index + * (lat_vtx, lon_vtx, dep_vtx) [nstr*ndip + 1] + * @param[out] lat_vtx defines the latitudes on each vertex of a + * rectangular fault patch (degrees) [4*nstr*ndip] + * @param[out] lon_vtx defines the longitudes on each vertex of a + * rectangular fault patch (degrees) [4*nstr*ndip] + * @param[out] dep_vtx defines the depths on each vertex of a + * retangular fault patch (km) [4*nstr*ndip] + * @param[out] fault_xutm fault patch easting UTM (m) [nstr*ndip] + * @param[out] fault_yutm fault patch northing UTM (m) [nstr*ndip] + * @param[out] fault_alt fault patch depths (km) [nstr*ndip] + * @param[out] strike strike on each fault patch [nstr*ndip] + * @param[out] dip dip of each fault patch [nstr*ndip] + * @param[out] length length of each fault patch (m) [nstr*ndip] + * @param[out] width width of each fault patch (m) [nstr*ndip] + * + * @result 0 indicates success + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +int core_ff_meshFaultPlane(const double ev_lat, + const double ev_lon, + const double ev_dep, + const double flen_pct, + const double fwid_pct, + const double M, + const double strikeF, const double dipF, + const int nstr, const int ndip, + const int utm_zone, const int verbose, + int *__restrict__ fault_ptr, + double *__restrict__ lat_vtx, + double *__restrict__ lon_vtx, + double *__restrict__ dep_vtx, + double *__restrict__ fault_xutm, + double *__restrict__ fault_yutm, + double *__restrict__ fault_alt, + double *__restrict__ strike, + double *__restrict__ dip, + double *__restrict__ length, + double *__restrict__ width) +{ + double area, dalt, di, dj, dlen, dwid, + fact_len, fact_wid, + fault_X, fault_X1, fault_X2, fault_X3, fault_X4, + fault_Y, fault_Y1, fault_Y2, fault_Y3, fault_Y4, + fault_Z, fault_Z1, fault_Z2, fault_Z3, fault_Z4, + latF, len, lonF, wid, + x0, xdoff, xsoff, y0, ydoff, ysoff, z0; + int i, j, k, zone_loc; + bool lnorthp; + const double pi180 = M_PI/180.0; + //------------------------------------------------------------------------// + // + // Error handling + if (ndip < 1 || nstr < 1) + { + if (ndip < 1) + { + LOG_ERRMSG("Invalid number of fault patches down dip: %d", ndip); + } + if (nstr < 1) + { + LOG_ERRMSG("Invalid number of fault patches along strike: %d", + nstr); + } + return -1; + } + // Ensures safety factors are okay + fact_len = 0.1; + if (flen_pct < 0.0) + { + if (verbose > 1) + { + LOG_WARNMSG("Width safety factor %f is invalid; setting to 10 pct", + flen_pct); + } + } + else + { + fact_len = flen_pct/100.0; + } + fact_wid = 0.1; + if (fwid_pct < 0.0) + { + if (verbose > 0) + { + LOG_WARNMSG("Length safety factor %f is invalid; setting to 10 pct", + fwid_pct); + } + } + else + { + fact_wid = fwid_pct/100.0; + } + // Get the source location + zone_loc = utm_zone; + if (zone_loc ==-12345){zone_loc =-1;} // Get UTM zone from source lat/lon + core_coordtools_ll2utm(ev_lat, ev_lon, + &y0, &x0, + &lnorthp, &zone_loc); + x0 = x0*1.e-3; // Convert to km + y0 = y0*1.e-3; // Convert to km + // Estimate the fault size + area = pow(10.0, -3.49+0.91*M); // Fault area (Dreger and Kaverina, 2000) + len = pow(10.0, -2.44+0.59*M); // Fault length (Dreger and Kaverina, 2000) + wid = area/len; // Fault width is area divided by length + // Add a safety factor to encapsulate entire rupture + len = len + fact_len*len; + wid = wid + fact_wid*wid; + // Set the initial top depth - either depth-width/2*sin(dip) or 0 + // depending on how wide and close the surface fault is + if (wid/2.0*sin(dipF*pi180) > ev_dep) + { + z0 = 0.0; + x0 = x0 - len/2.0*sin(strikeF*pi180) + - ev_dep*cos(dipF*pi180)*sin((strikeF + 90.0)*pi180); + y0 = y0 - len/2.0*cos(strikeF*pi180) + - ev_dep*cos(dipF*pi180)*cos((strikeF + 90.0)*pi180); + } + else + { + z0 = ev_dep - wid/2.0*sin(dipF*pi180); + x0 = x0 - len/2.0*sin(strikeF*pi180) + - wid/2.0*cos(dipF*pi180)*sin((strikeF + 90.0)*pi180); + y0 = y0 - len/2.0*cos(strikeF*pi180) + - wid/2.0*cos(dipF*pi180)*cos((strikeF + 90.0)*pi180); + } + // Compute the intervals + dlen = len/(double) nstr; // Intervals along strike + dwid = wid/(double) ndip; // Intervals down dip + dalt = dwid*sin(dipF*pi180); // Change in fault altitude + // Compute step step vectors by first looking down dip then moving + // taking vector components along strike + xdoff = dwid*cos(dipF*pi180)*sin((strikeF + 90.0)*pi180); + ydoff = dwid*cos(dipF*pi180)*cos((strikeF + 90.0)*pi180); + // Compute step size along strike by taking vector components + xsoff = dlen*sin(strikeF*pi180); + ysoff = dlen*cos(strikeF*pi180); + // Mesh fault by quickly stepping along strike and slowly stepping down dip + fault_ptr[0] = 0; + for (j=0; jm + fault_Y3 = (y0 + (di + 1.0)*ysoff + (dj + 1.0)*ydoff)*1.e3; //km->m + fault_Z3 = z0 + (dj + 1.0)*dalt; // km + + fault_X4 = (x0 + di*xsoff + (dj + 1.0)*xdoff)*1.e3; //km->m + fault_Y4 = (y0 + di*ysoff + (dj + 1.0)*ydoff)*1.e3; //km->m + fault_Z4 = z0 + (dj + 1.0)*dalt; // km + + // Convert from UTMs back to lat/lon + fault_X = fault_X*1000.0; // km -> m + fault_Y = fault_Y*1000.0; // km -> m + core_coordtools_utm2ll(zone_loc, lnorthp, + fault_Y, fault_X, + &latF, &lonF); + k = j*nstr + i; + fault_ptr[k+1] = 4*(k + 1); + // Generate output + core_coordtools_utm2ll(zone_loc, lnorthp, + fault_Y1, fault_X1, + &lat_vtx[4*k+0], &lon_vtx[4*k+0]); + core_coordtools_utm2ll(zone_loc, lnorthp, + fault_Y2, fault_X2, + &lat_vtx[4*k+1], &lon_vtx[4*k+1]); + core_coordtools_utm2ll(zone_loc, lnorthp, + fault_Y3, fault_X3, + &lat_vtx[4*k+2], &lon_vtx[4*k+2]); + core_coordtools_utm2ll(zone_loc, lnorthp, + fault_Y4, fault_X4, + &lat_vtx[4*k+3], &lon_vtx[4*k+3]); + dep_vtx[4*k+0] = fault_Z1; //depF; + dep_vtx[4*k+1] = fault_Z2; //depF; + dep_vtx[4*k+2] = fault_Z3; //depF; + dep_vtx[4*k+3] = fault_Z4; //depF; + // Save the fault patch centers for the actual inversion + fault_xutm[k] = fault_X; + fault_yutm[k] = fault_Y; + fault_alt[k] = fault_Z; + strike[k] = strikeF; + dip[k] = dipF; + length[k] = dlen*1.e3; // km -> m + width[k] = dwid*1.e3; // km -> m + } // Loop on strike + } // Loop on dip + return 0; +} diff --git a/src/core/ff/readIni.c b/src/core/ff/readIni.c new file mode 100644 index 00000000..af096172 --- /dev/null +++ b/src/core/ff/readIni.c @@ -0,0 +1,122 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_core.h" +#include "iscl/os/os.h" + +static void setVarName(const char *group, const char *variable, + char *var) +{ + memset(var, 0, 256*sizeof(char)); + sprintf(var, "%s:%s", group, variable); + return; +} +/*! + * @brief Reads the finite fault properties from the initialization file. + * + * @param[in] propfilename Name of properties file. + * @param[in] group Group in ini file. Likely "FF". + * @param[in] cmtMinSites Minimum number of sites in CMT inversion. + * @param[in] verbose This is the verbosity from the general + * parameters. + * @param[in] utm_zone This is the default UTM zone from the + * general parameters. + * + * @param[out] ff_props Finite fault properties. + * + * @result 0 indicates success. + * + * @author Ben Baker (ISTI) + * + */ +int core_ff_readIni(const char *propfilename, + const char *group, + const int verbose, const int utm_zone, + const int cmtMinSites, + struct GFAST_ff_props_struct *ff_props) +{ + char var[256]; + int ierr; + dictionary *ini; + ierr = 1; + memset(ff_props, 0, sizeof(struct GFAST_ff_props_struct)); + if (!os_path_isfile(propfilename)) + { + LOG_ERRMSG("Properties file: %s does not exist", propfilename); + return ierr; + } + ini = iniparser_load(propfilename); + // Read the properties + ff_props->verbose = verbose; + ff_props->utm_zone = utm_zone; + setVarName(group, "do_ff\0", var); + ff_props->do_ff = iniparser_getboolean(ini, var, true); + setVarName(group, "ff_number_of_faultplanes\0", var); + ff_props->nfp = iniparser_getint(ini, var, 2); + if (ff_props->nfp != 2) + { + LOG_ERRMSG("%s", "Error only 2 fault planes considered in ff"); + goto ERROR; + } + setVarName(group, "ff_nstr\0", var); + ff_props->nstr = iniparser_getint(ini, var, 10); + if (ff_props->nstr < 1) + { + LOG_ERRMSG("%s", "Error no fault patches along strike!"); + goto ERROR; + } + setVarName(group, "ff_ndip\0", var); + ff_props->ndip = iniparser_getint(ini, var, 5); + if (ff_props->ndip < 1) + { + LOG_ERRMSG("%s", "Error no fault patches down dip!"); + goto ERROR; + } + setVarName(group, "ff_min_sites\0", var); + ff_props->min_sites = iniparser_getint(ini, var, 4); + if (ff_props->min_sites < cmtMinSites) + { + LOG_ERRMSG("%s", "Error FF needs at least as many sites as CMT"); + goto ERROR; + } + setVarName(group, "ff_window_vel\0", var); + ff_props->window_vel = iniparser_getdouble(ini, var, 3.0); + if (ff_props->window_vel <= 0.0) + { + LOG_ERRMSG("%s", "Error window velocity must be positive!"); + goto ERROR; + } + setVarName(group, "ff_window_avg\0", var); + ff_props->window_avg = iniparser_getdouble(ini, var, 10.0); + if (ff_props->window_avg <= 0.0) + { + LOG_ERRMSG("%s", "Error window average time must be positive!"); + goto ERROR; + } + setVarName(group, "ff_flen_pct\0", var); + ff_props->flen_pct = iniparser_getdouble(ini, var, 10.0); + if (ff_props->flen_pct < 0.0) + { + LOG_ERRMSG("%s", "Error cannot shrink fault length"); + goto ERROR; + } + setVarName(group, "ff_fwid_pct\0", var); + ff_props->fwid_pct = iniparser_getdouble(ini, var, 10.0); + if (ff_props->fwid_pct < 0.0) + { + LOG_ERRMSG("%s", "Error cannot shrink fault width"); + goto ERROR; + } + ierr = 0; + ERROR:; + iniparser_freedict(ini); + return ierr; +} diff --git a/src/core/ff/setDiagonalWeightMatrix.c b/src/core/ff/setDiagonalWeightMatrix.c new file mode 100644 index 00000000..efebd854 --- /dev/null +++ b/src/core/ff/setDiagonalWeightMatrix.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/array/array.h" +/*! + * @brief Sets the diagonal weight matrix in the inversion. + * + * @param[in] n number of of observations + * @param[in] nWts data weights on north observation [n] + * @param[in] eWts data weights on east observation [n] + * @param[in] uWts data weights on vertical observations [n] + * + * @param[out] diagWt diagonal matrix of data weights to apply to + * \f$ diag{W} G m = diag{W} U \f$ [3*n] + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_ff_setDiagonalWeightMatrix(const int n, + const double *__restrict__ nWts, + const double *__restrict__ eWts, + const double *__restrict__ uWts, + double *__restrict__ diagWt) +{ + int i, i3; + bool leWts, lnWts, luWts; + if (n < 1) + { + LOG_ERRMSG("Invalid number of points: %d", n); + return -1; + } + if (diagWt == NULL) + { + LOG_ERRMSG("%s", "Error diagWt is NULL!"); + return -1; + } + if (nWts == NULL || eWts == NULL || uWts == NULL) + { + // Weights not specified + if (nWts == NULL && eWts == NULL && uWts == NULL) + { + LOG_WARNMSG("%s", "Setting diagonal weight matrix to unity"); + array_set64f_work(3*n, 1.0, diagWt); + } + else // Selectively make weights 1 + { + lnWts = true; + leWts = true; + luWts = true; + if (nWts == NULL) + { + LOG_WARNMSG("%s", "Setting nWts to unity"); + lnWts = false; + } + if (eWts == NULL) + { + LOG_WARNMSG("%s", "Setting eWts to unity"); + leWts = false; + } + if (uWts == NULL) + { + LOG_WARNMSG("%s", "Setting uWts to unity"); + luWts = false; + } + i3 = 0; + if (lnWts && leWts && luWts) + { +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include +#include "gfast_core.h" +// Small number to test cos(90) = 0 +#define eps 6.1232e-14 /*!< A close number for okadaGreenF */ +// Poisson's ratio +#define nu 0.25 /*!< Poisson's ratio for okadaGreenF */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifdef _OPENMP +#pragma omp declare simd +#endif +static inline void __ss_ds(const double cos_dip, const double sin_dip, + const double xi, const double eta, const double q, + double *ux_ss, double *uy_ss, double *uz_ss, + double *ux_ds, double *uy_ds, double *uz_ds); +#ifdef _OPENMP +#pragma omp declare simd +#endif +static inline void __ss_ds_zeroDip(const double sin_dip, + const double xi, const double eta, + const double q, + double *ux_ss, double *uy_ss, double *uz_ss, + double *ux_ds, double *uy_ds, double *uz_ds); +#ifdef _OPENMP +#pragma omp declare simd +#endif +static inline void __ss_ds_withDip(const double cos_dip, const double sin_dip, + const double xi, const double eta, + const double q, + double *ux_ss, double *uy_ss, double *uz_ss, + double *ux_ds, double *uy_ds, double *uz_ds); + +/*! + * @brief This program computes the Green's functions from Okada's formulation + * for slip on fault patches at a set of station locations + * + * @param[in] l1 number of station locations + * @param[in] l2 number of fault locations + * @param[in] e station/fault offset (m) fault eastings [l1 x l2 - row + * major order] + * @param[in] n station/fault offset (m) fault northings [l1 x l2 - row + major order] + * @param[in] depth station/fault depth offsets (m) [l1 x l2 - row major + order] + * @param[in] strike fault strikes (degrees) [l2] + * @param[in] dip fault dips (degrees) [l2] + * @param[in] W fault widths (m) [l2] + * @param[in] L fault lengths (m) [l2] + * + * @param[out] G [3*l1 x 2*l2] stored in column major format with + * leading dimension 2*l2 + * + * @author Brendan Crowell, PNSN + * Ben Baker, ISTI -> translated to C + * @date February 2016 + * + */ +int core_ff_setForwardModel__okadagreenF(const int l1, const int l2, + const double *__restrict__ e, + const double *__restrict__ n, + const double *__restrict__ depth, + const double *__restrict__ strike, + const double *__restrict__ dip, + const double *__restrict__ W, + const double *__restrict__ L, + double *__restrict__ G) +{ + double cos_dip, cos_strike, d, dip1, ec, + g1, g1n, g2, g2n, g3, g3n, g4, g4n, g5, g6, + nc, p, q, + ux_ss_1, uy_ss_1, uz_ss_1, ux_ds_1, uy_ds_1, uz_ds_1, + ux_ss_2, uy_ss_2, uz_ss_2, ux_ds_2, uy_ds_2, uz_ds_2, + ux_ss_3, uy_ss_3, uz_ss_3, ux_ds_3, uy_ds_3, uz_ds_3, + ux_ss_4, uy_ss_4, uz_ss_4, ux_ds_4, uy_ds_4, uz_ds_4, + strike1, sin_dip, sin_strike, x, y; + int i, j, ij, indx; + bool ldip; + const double pi180 = M_PI/180.0; + const double one_twopi = 1.0/(2.0*M_PI); + const bool lverif = false; + //------------------------------------------------------------------------// + if (l1 < 1 || l2 < 1) + { + if (l1 < 1){LOG_ERRMSG("%s", "Error no observations");} + if (l2 < 1){LOG_ERRMSG("%s", "Error no fault patches");} + return -1; + } + // classify the job + ldip = false; + for (i=0; i eps){ldip = true;} + } + // This is the non-vertical fault case + indx = 0; + if (ldip) + { + // Loop on the observations + for (j=0; j eps || + fabs(G[indx+1] - g2n) > eps) + { + LOG_WARNMSG("%s", "g1n g2n failed"); + G[indx+0] = g1n; + G[indx+1] = g2n; + } + + //indx = 3*(j+1)*l2 + 2*i; + if (fabs(G[indx+2*l2+0]) - g3n > eps || + fabs(G[indx+2*l2+1]) - g4n > eps) + { + LOG_WARNMSG("%s", "g3n g4n failed"); + G[indx+2*l2+0] = g3n; + G[indx+2*l2+1] = g4n; + } + + //indx = 3*(j+2)*l2 + 2*i; + if (fabs(G[indx+4*l2+0]) - g5 > eps || + fabs(G[indx+4*l2+1]) - g6 > eps) + { + LOG_WARNMSG("%s", "g5 g6 failed"); + G[indx+4*l2+0] = g5; + G[indx+4*l2+1] = g6; + } + } // Loop on faults (i) + } // Loop on observations (j) + } // End check on verification + return 0; +} + +#ifdef _OPENMP +#pragma omp declare simd +#endif +static inline void __ss_ds(const double cos_dip, const double sin_dip, + const double xi, const double eta, const double q, + double *ux_ss, double *uy_ss, double *uz_ss, + double *ux_ds, double *uy_ds, double *uz_ds) +{ + double atan_xeqr, db, I1, I2, I3, I4, I5, log_rpeta, pow_rpdb2, R, X, yb; + R = sqrt(xi*xi + eta*eta + q*q); + yb = eta*cos_dip + q*sin_dip; + db = eta*sin_dip - q*cos_dip; + X = sqrt(xi*xi + q*q); + log_rpeta = log(R + eta); + pow_rpdb2 = pow(R + db, 2); + atan_xeqr = atan(xi*eta/(q*R)); + if (cos_dip > eps) + { + I5 = (1.0 - 2.0*nu)*2.0/cos_dip + *atan( ( eta*(X + q*cos_dip) + X*(R + X)*sin_dip ) + /(xi*(R + X)*cos_dip)); + I4 = (1.0 - 2.0*nu)/cos_dip*(log(R+db) - sin_dip*log_rpeta); + I3 = (1.0 - 2.0*nu)*(yb/cos_dip/(R+db) - log_rpeta) + + sin_dip/cos_dip*I4; + I2 = (1.0 - 2.0*nu)*(-log_rpeta) - I3; + I1 = (1.0 - 2.0*nu)*(-xi/cos_dip/(R+db)) + - sin_dip/cos_dip*I5; + } + else + { + I5 =-(1.0 - 2.0*nu)*xi*sin_dip/(R + db); + I4 =-(1.0 - 2.0*nu)*q/(R + db); + I3 = (1.0 - 2.0*nu)/2.0*( eta/(R+db) + yb*q/pow_rpdb2 - log_rpeta ); + I2 = (1.0 - 2.0*nu)*(-log_rpeta) - I3; + I1 =-(1.0 - 2.0*nu)/2.0*xi*q/pow_rpdb2; + } + *ux_ss = xi*q/(R*(R+eta)) + + atan_xeqr + + I1*sin_dip; + *uy_ss = yb*q/(R*(R + eta)) + + q*cos_dip/(R + eta) + + I2*sin_dip; + *uz_ss = db*q/(R*(R + eta)) + + q*sin_dip/(R + eta) + + I4*sin_dip; + *ux_ds = q/R + - I3*sin_dip*cos_dip; + *uy_ds = yb*q/(R*(R + xi)) + + cos_dip*atan_xeqr + - I1*sin_dip*cos_dip; + *uz_ds = db*q/(R*(R + xi)) + + sin_dip*atan_xeqr + - I5*sin_dip*cos_dip; + return; +} + +#ifdef _OPENMP +#pragma omp declare simd +#endif +static inline void __ss_ds_zeroDip(const double sin_dip, + const double xi, const double eta, + const double q, + double *ux_ss, double *uy_ss, double *uz_ss, + double *ux_ds, double *uy_ds, double *uz_ds) +{ + double atan_xeqr, db, I1, I2, I3, I4, log_rpeta, pow_rpdb2, + R, Rpdb, yb; + R = sqrt(xi*xi + eta*eta + q*q); + yb = q*sin_dip; + db = eta*sin_dip; + //X = sqrt(xi*xi + q*q); + log_rpeta = log(R + eta); + Rpdb = R + db; + pow_rpdb2 = Rpdb*Rpdb; //pow(R + db, 2); + atan_xeqr = atan(xi*eta/(q*R)); + + //I5 =-(1.0 - 2.0*nu)*xi*sin_dip/(R + db); + I4 =-(1.0 - 2.0*nu)*q/(R + db); + I3 = (1.0 - 2.0*nu)/2.0*( eta/(R+db) + yb*q/pow_rpdb2 - log_rpeta ); + I2 = (1.0 - 2.0*nu)*(-log_rpeta) - I3; + I1 =-(1.0 - 2.0*nu)/2.0*xi*q/pow_rpdb2; + + *ux_ss = xi*q/(R*(R+eta)) + + atan_xeqr + + I1*sin_dip; + *uy_ss = yb*q/(R*(R + eta)) + + I2*sin_dip; + *uz_ss = db*q/(R*(R + eta)) + + q*sin_dip/(R + eta) + + I4*sin_dip; + *ux_ds = q/R; + *uy_ds = yb*q/(R*(R + xi)); + *uz_ds = db*q/(R*(R + xi)) + + sin_dip*atan_xeqr; + return; +} + +#ifdef _OPENMP +#pragma omp declare simd +#endif +static inline void __ss_ds_withDip(const double cos_dip, const double sin_dip, + const double xi, const double eta, + const double q, + double *ux_ss, double *uy_ss, double *uz_ss, + double *ux_ds, double *uy_ds, double *uz_ds) +{ + double atan_xeqr, db, I1, I2, I3, I4, I5, log_rpeta, R, + X, yb; + R = sqrt(xi*xi + eta*eta + q*q); + yb = eta*cos_dip + q*sin_dip; + db = eta*sin_dip - q*cos_dip; + X = sqrt(xi*xi + q*q); + log_rpeta = log(R + eta); + //Rpdb = R + db; + //pow_rpdb2 = Rpdb*Rpdb; //pow(R + db, 2); + atan_xeqr = atan(xi*eta/(q*R)); + + I5 = (1.0 - 2.0*nu)*2.0/cos_dip + *atan( ( eta*(X + q*cos_dip) + X*(R + X)*sin_dip ) + /(xi*(R + X)*cos_dip)); + I4 = (1.0 - 2.0*nu)/cos_dip*(log(R+db) - sin_dip*log_rpeta); + I3 = (1.0 - 2.0*nu)*(yb/cos_dip/(R+db) - log_rpeta) + + sin_dip/cos_dip*I4; + I2 = (1.0 - 2.0*nu)*(-log_rpeta) - I3; + I1 = (1.0 - 2.0*nu)*(-xi/cos_dip/(R+db)) + - sin_dip/cos_dip*I5; + + *ux_ss = xi*q/(R*(R+eta)) + + atan_xeqr + + I1*sin_dip; + *uy_ss = yb*q/(R*(R + eta)) + + q*cos_dip/(R + eta) + + I2*sin_dip; + *uz_ss = db*q/(R*(R + eta)) + + q*sin_dip/(R + eta) + + I4*sin_dip; + *ux_ds = q/R + - I3*sin_dip*cos_dip; + *uy_ds = yb*q/(R*(R + xi)) + + cos_dip*atan_xeqr + - I1*sin_dip*cos_dip; + *uz_ds = db*q/(R*(R + xi)) + + sin_dip*atan_xeqr + - I5*sin_dip*cos_dip; + return; +} diff --git a/src/core/ff/setRHS.c b/src/core/ff/setRHS.c new file mode 100644 index 00000000..74b20a4c --- /dev/null +++ b/src/core/ff/setRHS.c @@ -0,0 +1,47 @@ +#include +#include +#include "gfast_core.h" +/*! + * @brief Sets the RHS for the finite fault inversion. The right hand + * side for the i'th site is packed + * \f$ \{ e_{avg}^{(i)}, n_{avg}^{(i)}, u_{avg}^{(i)} \} \f$. + * + * @param[in] n number of points + * @param[in] nOffset offset on north channel [n] + * @param[in] eOffset offset on east channel [n] + * @param[in] uOffset offset on vertical channel [n] + * + * @param[out] U right hand side in Gm = U [3*n] + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + * @date April 2016 + * + */ +int core_ff_setRHS(const int n, + const double *__restrict__ nOffset, + const double *__restrict__ eOffset, + const double *__restrict__ uOffset, + double *__restrict__ U) +{ + int i, i3; + if (n < 1) + { + LOG_ERRMSG("Invalid number of points: %d", n); + return -1; + } + i3 = 0; +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include "gfast_core.h" +/*! + * @brief Computes the second order Tikhonov regularizer along + * strike and down dip for estimation of the slip + * along strike and slip down dip. There is an additional + * penalty on slip occurring on the the model boundaries + * excluding the most nstr - 2 updip elements + * + * @param[in] l2 total number of faults in plane (nstr*ndip) + * @param[in] nstr number of faults along strike + * @param[in] ndip number of faults down dip + * @param[in] nt length of T + * @param[in] width width of fault patches (km) [l2] + * @param[in] length length of fault patches (km) [l2] + * + * @param[out] T second order Tikonov regularizer. T is size + * [(2*l2 + 2*(2*ndip + nstr - 2))*2*l2] with + * leading dimension 2*l2 stored in row major + * order. + * + * @result 0 indicates success + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @date April 2016 + * + */ +int core_ff_setRegularizer(const int l2, const int nstr, + const int ndip, const int nt, + const double *__restrict__ width, + const double *__restrict__ length, + double *__restrict__ T) +{ + double len02i, lnwidi, wid02i; + int i, indx1, indx2, indx3, indx4, indx5, j, k, l, ldt, + kndx1, kndx2, kndx3, kndx4, kndx5, m, ntref; + //------------------------------------------------------------------------// + // + // Error handling + ntref = (2*l2 + 2*(2*ndip + nstr - 2))*2*l2; + if (nstr < 1 || ndip < 1 || l2 != nstr*ndip || nt != ntref) + { + if (nstr < 1) + { + LOG_ERRMSG("Error no faults along strike %d", nstr); + } + if (ndip < 1) + { + LOG_ERRMSG("Error no faults down dip %d", ndip); + } + if (nstr*ndip != l2) + { + LOG_ERRMSG("Error size inconsistency %d %d", l2, nstr*ndip); + } + if (nt != ntref) + { + LOG_ERRMSG("Error nt is not proper size %d %d", nt, ntref); + } + return -1; + } + if (width == NULL || length == NULL || T == NULL) + { + if (width == NULL) + { + LOG_ERRMSG("%s", "Error width can't be NULL"); + } + if (length == NULL) + { + LOG_ERRMSG("%s", "Error length can't be NULL"); + } + if (T == NULL) + { + LOG_ERRMSG("%s", "Error regularizer T can't be NULL"); + } + return -1; + } + // Null out regularizer +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i m^2 + len02i = 1.0/(length[l]*length[l])*1.e6; // 1/dx^2; km^2 -> m^2 + lnwidi = 1.0/(width[l]*length[l])*1.e6; // 1/dx/dy; km^2 -> m^2 + indx1 = j*nstr + i; // Grid index + indx2 = j*nstr + i - 1; // Backward along strike + indx3 = j*nstr + i + 1; // Forward along strike + indx4 = (j - 1)*nstr + i; // Backward along dip (up dp) + indx5 = (j + 1)*nstr + i; // Forward along dip (down dip) + kndx1 = k*ldt + 2*indx1 + m; // T[k,2*index1+m] + kndx2 = k*ldt + 2*indx2 + m; // T[k,2*index2+m] + kndx3 = k*ldt + 2*indx3 + m; // T[k,2*index3+m] + kndx4 = k*ldt + 2*indx4 + m; // T[k,2*index4+m] + kndx5 = k*ldt + 2*indx5 + m; // T[k,2*index5+m] + // Fill s.t. the column numbers always increase + if (indx4 >= 0 && indx4 < l2) + { + T[kndx4] = wid02i; + } + if (indx2 >= 0 && indx2 < l2) + { + T[kndx2] = len02i; + } + if (indx1 >= 0 && indx1 < l2) + { + T[kndx1] =-2.0*(len02i + wid02i); + } + if (indx3 >= 0 && indx3 < l2) + { + T[kndx3] = len02i; + } + if (indx5 >= 0 && indx5 < l2) + { + T[kndx5] = wid02i; + } + } // Loop on m + } // Loop on strike + } // Loop on dip + if (k != 2*ndip*nstr - 1) + { + LOG_ERRMSG("Error lost count part 1 %d %d", k, 2*ndip*nstr - 1); + return -1; + } + // Now apply boundary conditions s.t. the fault ends excluding + // the free surface are penalized if they slip + k = 2*ndip*nstr; // Begin row counter at end + for (j=0; j m^2 + lnwidi = 1.0/(width[l]*length[l])*1.e6; + T[kndx1] = 100.0*lnwidi; + k = k + 1; // Update row + } + } // Loop on m + } // Loop on strike + } // Loop on on dip + // Did we get them all? + if (k != (2*l2 + 2*(2*ndip + nstr - 2))) + { + LOG_WARNMSG("Warning failed to initialize all rows in T %d %d", + k, 2*l2 + 2*(2*ndip + nstr - 2)); + } + return 0; +} diff --git a/src/core/ff/weightForwardModel.c b/src/core/ff/weightForwardModel.c new file mode 100644 index 00000000..53da9711 --- /dev/null +++ b/src/core/ff/weightForwardModel.c @@ -0,0 +1,71 @@ +#include +#include +#include "gfast_core.h" +#include "iscl/array/array.h" +/*! + * @brief Weights a forward modeling matrix by the diagonal data weights + * + * @param[in] mrows number of rows in forward modeling matrix (should + * be 3*number_of_observations) + * @param[in] ncols number of columns in forward modeling matrix + * @param[in] diagWt diagonal of data weight matrix [mrows] + * @param[in] G unweighted forward modeling matrix. This is + * in row major format and is of size [mrows x ncols] + * Notice, because G is in row major order that it + * is okay to apply this function to the regularized + * matrix G understanding the regulizartion terms of + * G will be scaled by unity (i.e. unchanged). + * + * @param[out] diagWtG weighted forward modeling matrix obtained by + * computing \f$ \tilde{G} \leftarrow diag\{W\} G \f$. + * This is in row major format and is of size + * [mrows x ncols] + * + * @result -1 indicates an input error + * 0 indicates success + * 1 indicates the diagonal weight matrix is NULL. G will + * not be modified in this instance. + * + * @author Ben Baker, ISTI + * + */ +int core_ff_weightForwardModel(const int mrows, const int ncols, + const double *__restrict__ diagWt, + const double *__restrict__ G, + double *__restrict__ diagWtG) +{ + int i, j; + if (mrows < 1 || ncols < 1) + { + LOG_ERRMSG("Error G has invalid dimension %d %d", mrows, ncols); + return -1; + } + if (G == NULL || diagWtG == NULL) + { + if (G == NULL){LOG_ERRMSG("%s", "Error G cannot be NULL");} + if (diagWtG == NULL) + { + LOG_ERRMSG("%s", "Error diagWtG cannot be NULL"); + } + return -1; + } + // Avoid a segmentation fault + if (diagWt == NULL) + { + LOG_WARNMSG("%s", "Warning diagWt is NULL; G will not be weighted"); + array_copy64f_work(mrows*ncols, G, diagWtG); + return 1; + } + // Compute \tilde{G} = diag\{W\}*G +#ifdef _OPENMP + #pragma omp simd collapse(2) +#endif + for (i=0; i +#include +#include "gfast_core.h" +#include "iscl/array/array.h" +/*! + * @brief Applies the diagonal data weight matrix to the observations + * + * @param[in] mrows number of rows (observations - should be 3 x number + * of sites) + * @param[in] diagWt diagonal matrix of data weights [mrows] + * @param[in] b observations [mrows] + * + * @param[out] diagWb weighted observations such that + * \f$ \tilde{b} = diag \{W\} b \f$ [mrows] + * + * @result -1 indicates an error + * 0 indicates success + * 1 indicates that diagWt is NULL and it is assumed that diagWt + * is identity + * + * @author Ben Baker (ISTI) + * + */ +int core_ff_weightObservations(const int mrows, + const double *__restrict__ diagWt, + const double *__restrict__ b, + double *__restrict__ diagWb) +{ + int i; + if (mrows < 1) + { + LOG_ERRMSG("Error no rows = %d!", mrows); + return -1; + } + if (b == NULL || diagWb == NULL) + { + if (b == NULL){LOG_ERRMSG("%s", "Error b is NULL");} + if (diagWb == NULL){LOG_ERRMSG("%s", "Error diagWb is NULL");} + return -1; + } + if (diagWt == NULL) + { + LOG_WARNMSG("%s", "Warning diagWt is NULL - assuming identity"); + array_copy64f_work(mrows, b, diagWb); + return 1; + } + // Apply diagonal data weights to observations +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include +#include +#include +#include +#include "gfast_core.h" +#include "iscl/os/os.h" + +enum logFileType_enum +{ + ERROR_FILE = 1, + INFO_FILE = 2, + WARNING_FILE = 3, + DEBUG_FILE = 4, + // MTH: + LOG_FILE = 5 +}; + +static FILE *errorFile = NULL; +static FILE *infoFile = NULL; +static FILE *debugFile = NULL; +static FILE *warningFile = NULL; +// MTH: +static FILE *logFile = NULL; + +/*! + * @brief Closes the log file. + * + * @param[in] fileType Type of file (error, log, debug, info) to open. + * + * @result 0 indicates success. + * + */ +static int core_log_closeLogFile(const enum logFileType_enum fileType) +{ + int ierr = 0; + if (fileType == ERROR_FILE) + { + if (errorFile != NULL){ + fclose(errorFile);} + errorFile = NULL; + } + else if (fileType == INFO_FILE) + { + if (infoFile != NULL){fclose(infoFile);} + infoFile = NULL; + } + else if (fileType == WARNING_FILE) + { + if (warningFile != NULL){fclose(warningFile);} + warningFile = NULL; + } + else if (fileType == DEBUG_FILE) + { + if (debugFile != NULL){fclose(debugFile);} + debugFile = NULL; + } + else if (fileType == LOG_FILE) + { + if (logFile != NULL){fclose(logFile);} + logFile = NULL; + } + else + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Invalid option\n", + __FILE__, __func__, __LINE__); + ierr = 1; + } + return ierr; +} +/*! + * @brief Creates a log file. If the file exists then it will be over-written. + * + * @param[in] fileName Name of log file. + * @param[in] fileType Type of log file (error, debug, info, warning) to open. + * + * @result 0 indicates success. + * + */ +static int core_log_createLogFile(const char *fileName, + const enum logFileType_enum fileType) +{ + char *dirName; + + int ierr = 0; + // Does this file name make sense? + if (fileName == NULL) + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Error fileName is NULL\n", + __FILE__, __func__, __LINE__); + return -1; + } + if (strlen(fileName) < 1) + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Error fileName is blank\n", + __FILE__, __func__, __LINE__); + return -1; + } + // Make sure I don't destroy an existing file handle + ierr = core_log_closeLogFile(fileType); + if (ierr != 0) + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Error closing log file %s\n", + __FILE__, __func__, __LINE__, fileName); + return ierr; + } + // Check the output + char *dirc = strdup(fileName); + dirName = dirname(dirc); + if (!os_path_isdir(dirName)) + { + ierr = mkdir(dirName,0755); + if (ierr) + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Failed to make %s\n", + __FILE__, __func__, __LINE__, dirName); + } + } + + free(dirc); + + if (ierr != 0){return ierr;} + // Just point out this file is going to be over-written + if (os_path_isfile(fileName)) + { + fprintf(stdout, "[WARNING]: (%s:%s:line=%d) Overwriting file %s\n", + __FILE__, __func__, __LINE__, fileName); + } + // Open the desired file + if (fileType == ERROR_FILE) + { + errorFile = fopen(fileName, "w"); + } + else if (fileType == INFO_FILE) + { + infoFile = fopen(fileName, "w"); + } + else if (fileType == WARNING_FILE) + { + warningFile = fopen(fileName, "w"); + } + else if (fileType == DEBUG_FILE) + { + debugFile = fopen(fileName, "w"); + } + else if (fileType == LOG_FILE) + { + logFile = fopen(fileName, "w"); + } + else + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Invalid option\n", + __FILE__, __func__, __LINE__); + ierr = 1; + } + return ierr; +} +//============================================================================// +/*! + * @brief Opens a log file for writing. If the file exists then it will be + * appended to. + * + * @param[in] fileName Name of log file. + * @param[in] fileType Type of log file (error, debug, info, warning) to open. + * + * @result 0 indicates success. + * + */ +static int core_log_openLogFile(const char *fileName, + const enum logFileType_enum fileType) +{ + char *dirName; + int ierr = 0; + // Does this file name make sense? + if (fileName == NULL) + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Error fileName is NULL\n", + __FILE__, __func__, __LINE__); + return -1; + } + if (strlen(fileName) < 1) + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Error fileName is blank\n", + __FILE__, __func__, __LINE__); + return -1; + } + // Make sure I don't destroy an existing file handle + ierr = core_log_closeLogFile(fileType); + if (ierr != 0) + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Error closing log file %s\n", + __FILE__, __func__, __LINE__, fileName); + return ierr; + } + // Does the file exist? If not then give it an output directory + if (!os_path_isfile(fileName)) + { + char *dirc = strdup(fileName); + dirName = dirname(dirc); + if (!os_path_isdir(dirName)) + { + ierr = mkdir(dirName, 0755); + if (ierr) + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Failed to make %s\n", + __FILE__, __func__, __LINE__, dirName); + } + } + free(dirc); + } + if (ierr != 0){return ierr;} + // Open the desired file + if (fileType == ERROR_FILE) + { + errorFile = fopen(fileName, "a"); + } + else if (fileType == INFO_FILE) + { + infoFile = fopen(fileName, "a"); + } + else if (fileType == WARNING_FILE) + { + warningFile = fopen(fileName, "a"); + } + else if (fileType == DEBUG_FILE) + { + debugFile = fopen(fileName, "a"); + } + else if (fileType == LOG_FILE) + { + logFile = fopen(fileName, "a"); + } + else + { + fprintf(stderr, "[ERROR]: (%s:%s:line=%d) Invalid option\n", + __FILE__, __func__, __LINE__); + ierr = 1; + } + return ierr; +} +//============================================================================// +/*! + * @brief Convenience function to close logs. + * + * @result 0 indicates success. + * + */ +int core_log_closeLogs(void) +{ + int ierr = 0; + ierr += core_log_closeErrorLog(); + ierr += core_log_closeInfoLog(); + ierr += core_log_closeDebugLog(); + ierr += core_log_closeWarningLog(); + return ierr; +} +//============================================================================// +/*! + * @brief Opens the error log file. If the file exists then it will be + * appended to. + * + * @param[in] fileName Name of error log file to open. + * + * @result 0 indicates success. + * + */ +int core_log_openErrorLog(const char *fileName) +{ + int ierr; + ierr = core_log_openLogFile(fileName, ERROR_FILE); + return ierr; +} +/*! + * @brief Opens the info log file. If the file exists then it will be + * appended to. + * + * @param[in] fileName Name of info log file to open. + * + * @result 0 indicates success. + * + */ +int core_log_openInfoLog(const char *fileName) +{ + int ierr; + ierr = core_log_openLogFile(fileName, INFO_FILE); + return ierr; +} +/*! + * @brief Opens the warning log file. If the file exists then it will be + * appended to. + * + * @param[in] fileName Name of warning log file to open. + * + * @result 0 indicates success. + * + */ +int core_log_openWarningLog(const char *fileName) +{ + int ierr; + ierr = core_log_openLogFile(fileName, WARNING_FILE); + return ierr; +} +/*! + * @brief Opens the debug log file. If the file exists then it will be + * appended to. + * + * @param[in] fileName Name of debug log file to open. + * + * @result 0 indicates success. + * + */ +int core_log_openDebugLog(const char *fileName) +{ + int ierr; + ierr = core_log_openLogFile(fileName, DEBUG_FILE); + return ierr; +} +/*! + * @brief Opens the big log file. If the file exists then it will be + * appended to. + * + * @param[in] fileName Name of log file to open. + * + * @result 0 indicates success. + * + */ +int core_log_openLog(const char *fileName) +{ + int ierr; + ierr = core_log_openLogFile(fileName, LOG_FILE); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the error log file. If the file exists then it will be + * overwritten. + * + * @param[in] fileName Name of error log file to create. + * + * @result 0 indicates success. + * + */ +int core_log_createErrorLog(const char *fileName) +{ + int ierr; + ierr = core_log_createLogFile(fileName, ERROR_FILE); + return ierr; +} +/*! + * @brief Creates the info log file. If the file exists then it will be + * overwritten. + * + * @param[in] fileName Name of info log file to create. + * + * @result 0 indicates success. + * + */ +int core_log_createInfoLog(const char *fileName) +{ + int ierr; + ierr = core_log_createLogFile(fileName, INFO_FILE); + return ierr; +} +/*! + * @brief Creates the warning log file. If the file exists then it will be + * overwritten. + * + * @param[in] fileName Name of warning log file to create. + * + * @result 0 indicates success. + * + */ +int core_log_createWarningLog(const char *fileName) +{ + int ierr; + ierr = core_log_createLogFile(fileName, WARNING_FILE); + return ierr; +} +/*! + * @brief Creates the debug log file. If the file exists then it will be + * overwritten. + * + * @param[in] fileName Name of debug log file to create. + * + * @result 0 indicates success. + * + */ +int core_log_createDebugLog(const char *fileName) +{ + int ierr; + ierr = core_log_createLogFile(fileName, DEBUG_FILE); + return ierr; +} +/*! + * @brief Creates the big log file. If the file exists then it will be + * overwritten. + * + * @param[in] fileName Name of log file to create. + * + * @result 0 indicates success. + * + */ +int core_log_createLog(const char *fileName) +{ + int ierr; + ierr = core_log_createLogFile(fileName, LOG_FILE); + return ierr; +} +//============================================================================// +/*! + * @brief Closes the error log file. + * + * @result 0 indicates success. + * + */ +int core_log_closeErrorLog(void) +{ + int ierr; + ierr = core_log_closeLogFile(ERROR_FILE); + return ierr; +} +/*! + * @brief Closes the info log file. + * + * @result 0 indicates success. + * + */ +int core_log_closeInfoLog(void) +{ + int ierr; + ierr = core_log_closeLogFile(INFO_FILE); + return ierr; +} +/*! + * @brief Closes the warning log file. + * + * @result 0 indicates success. + * + */ +int core_log_closeWarningLog(void) +{ + int ierr; + ierr = core_log_closeLogFile(WARNING_FILE); + return ierr; +} +/*! + * @brief Closes the debug log file. + * + * @result 0 indicates success. + * + */ +int core_log_closeDebugLog(void) +{ + int ierr; + ierr = core_log_closeLogFile(DEBUG_FILE); + return ierr; +} +/*! + * @brief Closes the big log file. + * + * @result 0 indicates success. + * + */ +int core_log_closeLog(void) +{ + LOG_MSG("%s", "Close the big LOG_FILE"); + int ierr; + ierr = core_log_closeLogFile(LOG_FILE); + return ierr; +} +//============================================================================// + +/*! + * @brief Writes an error message to the error log. + * + * @param[in] msg Message to write to the error log file. + * + */ +void core_log_logErrorMessage(const char *msg) +{ + if (errorFile == NULL) + { + fprintf(stderr, "%s\n", msg); + } + else + { + fprintf(errorFile, "%s\n", msg); + } + return; +} + +/*! + * @brief Writes a warning message to the warning log. + * + * @param[in] msg Message to write to the warning log file. + * + */ +void core_log_logWarningMessage(const char *msg) +{ + if (msg == NULL){return;} + if (warningFile == NULL) + { + fprintf(stdout, "%s\n", msg); + } + else + { + fprintf(warningFile, "%s\n", msg); + } + return; +} + +/*! + * @brief Writes an info message to the info log. + * + * @param[in] msg Message to write to the info log file. + * + */ +void core_log_logInfoMessage(const char *msg) +{ + if (msg == NULL){return;} + if (infoFile == NULL) + { + fprintf(stdout, "%s\n", msg); + } + else + { + fprintf(infoFile, "%s\n", msg); + } + return; +} + +/*! + * @brief Writes a debug/extra info message to the debug log. + * + * @param[in] msg Message to write to the debug log file. + * + */ +void core_log_logDebugMessage(const char *msg) +{ + if (msg == NULL){return;} + if (debugFile == NULL) + { + fprintf(stdout, "%s\n", msg); + } + else + { + fprintf(debugFile, "%s\n", msg); + } + return; +} + +/*! + * @brief Writes a message to the big log. + * + * @param[in] msg Message to write to the log file. + * + */ +void core_log_logMessage(const char *msg) +{ + if (logFile == NULL) { + printf("MTH: logFile is NULL!\n"); + } + + if (msg == NULL){return;} + if (logFile == NULL) + { + fprintf(stdout, "%s\n", msg); + } + else + { + fprintf(logFile, "%s\n", msg); + fflush(logFile); + } + return; +} diff --git a/src/core/log/log.cpp b/src/core/log/log.cpp new file mode 100644 index 00000000..d17f1d06 --- /dev/null +++ b/src/core/log/log.cpp @@ -0,0 +1,43 @@ + +#include +#include +#include +#include + + +static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; +static eew::ExternalMutexConsoleAppender mtx_console_appender(&print_lock); + +extern "C" void init_plog(); +extern "C" void core_log_plog_V(const char *msg); +extern "C" void core_log_plog_D(const char *msg); +extern "C" void core_log_plog_I(const char *msg); +extern "C" void core_log_plog_W(const char *msg); +extern "C" void core_log_plog_E(const char *msg); +extern "C" void core_log_plog_F(const char *msg); +extern "C" void core_log_plog_N(const char *msg); + +// #define LOGV LOG_VERBOSE +// #define LOGD LOG_DEBUG +// #define LOGI LOG_INFO +// #define LOGW LOG_WARNING +// #define LOGE LOG_ERROR +// #define LOGF LOG_FATAL +// #define LOGN LOG_NONE + +void init_plog() { + + // static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; + // DMLib::setPrintLock(&print_lock); + // static eew::ExternalMutexConsoleAppender Severity_appender(&print_lock); + + plog::init(plog::verbose, &mtx_console_appender); +} + +void core_log_plog_V(const char *msg) { LOGV << msg; } +void core_log_plog_D(const char *msg) { LOGD << msg; } +void core_log_plog_I(const char *msg) { LOGI << msg; } +void core_log_plog_W(const char *msg) { LOGW << msg; } +void core_log_plog_E(const char *msg) { LOGE << msg; } +void core_log_plog_F(const char *msg) { LOGF << msg; } +void core_log_plog_N(const char *msg) { LOGN << msg; } \ No newline at end of file diff --git a/src/core/properties/Makefile b/src/core/properties/Makefile new file mode 100644 index 00000000..cd6982cc --- /dev/null +++ b/src/core/properties/Makefile @@ -0,0 +1,65 @@ +# Makefile for GFAST/src/core/properties +# + +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = finalize.o initialize.o print.o + +DEBUG = -g +CCFLAGS += -O0 -D_REENTRANT -Dstatic_config + +#iniparser will be deleted +INCL = -I ../../../include $(INIPARSER_INCL) $(ISCL_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(CC) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/core/properties/finalize.c b/src/core/properties/finalize.c new file mode 100644 index 00000000..c1e65e9f --- /dev/null +++ b/src/core/properties/finalize.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include "gfast_core.h" + +//============================================================================// +/*! + * @brief Frees/nulls ou thte GFAST PGD properties structure + * + * @param[out] pgd_props the freed/nulled out GFAST PGD properties structure + * + * @author Ben Baker (ISTI) + * + */ +void core_properties_finalizePGDProperties( + struct GFAST_pgd_props_struct *pgd_props) +{ + memset(pgd_props, 0, sizeof(struct GFAST_pgd_props_struct)); + return; +} +//============================================================================// +/*! + * @brief Frees/nulls out the GFAST CMT properties structure + * + * @param[out] cmt_props the freed/nulled out GFAST CMT properties structure + * + * @author Ben Baker (ISTI) + * + */ +void core_properties_finalizeCMTProperties( + struct GFAST_cmt_props_struct *cmt_props) +{ + memset(cmt_props, 0, sizeof(struct GFAST_cmt_props_struct)); + return; +} +//============================================================================// +/*! + * @brief Frees/nulls out the GFAST finite fault properties + * + * @param[out] ff_props the freed/nulled out GFAST finite fault properties + * structure + * + * @author Ben Baker (ISTI) + * + */ +void core_properties_finalizeFFProperties( + struct GFAST_ff_props_struct *ff_props) +{ + memset(ff_props, 0, sizeof(struct GFAST_ff_props_struct)); + return; +} +//============================================================================// +/*! + * @brief Frees/nulls out the GFAST activeMQ properties + * + * @param[out] activeMQ_props the freed/nulled out GFAST activeMQ properties + * structure + * + * @author Ben Baker (ISTI) + * + */ +void core_properties_finalizeActiveMQProperties( + struct GFAST_activeMQ_struct *activeMQ_props) +{ + memset(activeMQ_props, 0, sizeof(struct GFAST_activeMQ_struct)); + return; +} +//============================================================================// +/*! + * @brief Frees/nulls out the GFAST properties structure + * + * @param[out] props the freed/nulled out GFAST properties structure + * + * @author Ben Baker (ISTI) + * + */ +void core_properties_finalize(struct GFAST_props_struct *props) +{ + GFAST_core_properties_finalizePGDProperties(&props->pgd_props); + GFAST_core_properties_finalizeCMTProperties(&props->cmt_props); + GFAST_core_properties_finalizeFFProperties(&props->ff_props); + GFAST_core_properties_finalizeActiveMQProperties(&props->activeMQ_props); + memset(props, 0, sizeof(struct GFAST_props_struct)); + return; +} diff --git a/src/core/properties/initialize.c b/src/core/properties/initialize.c new file mode 100644 index 00000000..db95e9bd --- /dev/null +++ b/src/core/properties/initialize.c @@ -0,0 +1,491 @@ +#include +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_core.h" +#include "iscl/os/os.h" +#ifdef GFAST_USE_AMQ +#include "gfast_activeMQ.h" +#endif + +int set_array_from_string_int(const char *prop, int *array, int max_size); +int set_array_from_string_str(const char *prop, char **array, int max_size); + +/*! + * @brief Initializes the GFAST properties (parameter) structure + * + * @param[in] propfilename Name of properties file. + * @param[in] opmode GFAST operational mode. Can be OFFLINE + * for playback or REAL_TIME_EEW for real-time + * earthquake early warning. + * + * @param[out] props On successful exit holds the GFAST properties + * structure. + * + * @result 0 indicates success. + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +int core_properties_initialize(const char *propfilename, + const enum opmode_type opmode, + struct GFAST_props_struct *props) +{ + const char *s; + char cwork[PATH_MAX]; + int ierr, itemp; + // int lenos; + dictionary *ini; + //------------------------------------------------------------------------// + // Require the properties file exists + if (!os_path_isfile(propfilename)) + { + LOG_ERRMSG("properties file (%s) does not exist\n", propfilename); + return -1; + } + + ierr =-1; + memset(props, 0, sizeof(struct GFAST_props_struct)); + props->opmode = opmode; + + // Load the ini file + ini = iniparser_load(propfilename); + if (ini == NULL) { + LOG_ERRMSG("Iniparser could not read: %s\n", propfilename); + return -1; + } + strcpy(props->propfilename, propfilename); + //-------------------------GFAST General Parameters-----------------------// + + // set open output log file. + // s = iniparser_getstring(ini, "general:logFileName\0", + // "gfast.log\0"); + // LOG_DEBUGMSG("Opening %s for log output\n",s); + // core_log_openLog(s); + // if (!os_path_isfile(s)) + // { + // LOG_ERRMSG("Cannot open log output file %s\n", s); + // return -1; + // } + + //metadata file + s = iniparser_getstring(ini, "general:metaDataFile\0", + "GFAST_streams.txt\0"); + strcpy(props->metaDataFile, s); + if (!os_path_isfile(props->metaDataFile)) + { + LOG_ERRMSG("Cannot find station list (%s)\n", props->metaDataFile); + return -1; + } + + // Option to restrict the networks used + int n_networks; + s = iniparser_getstring(ini, "general:metaDataNetworks\0", "\0"); + n_networks = set_array_from_string_str(s, props->metaDataNetworks, 16); + props->n_networks = n_networks; + + //site mask file + s = iniparser_getstring(ini, "general:siteMaskFile\0", NULL); + if (s != NULL) + { + strcpy(props->siteMaskFile, s); + if (!os_path_isfile(props->siteMaskFile)) + { + memset(props->siteMaskFile, 0, sizeof(props->siteMaskFile)); + } + } + + s = iniparser_getstring(ini, "general:output_interval_mins\0", NULL); + int n_intervals; + n_intervals = set_array_from_string_int(s, props->output_interval_mins, MAX_OUTPUT_INTERVALS); + if (n_intervals > MAX_OUTPUT_INTERVALS) { + LOG_MSG("WARNING: output_interval_mins exceeds MAX_OUTPUT_INTERVALS=%d, capping at %d!\n", + MAX_OUTPUT_INTERVALS, MAX_OUTPUT_INTERVALS); + n_intervals = MAX_OUTPUT_INTERVALS; + } + props->n_intervals = n_intervals; + + s = iniparser_getstring(ini, "general:SA_events_dir\0", ".\0"); + if (s != NULL) + { + strcpy(props->SAeventsDir, s); + if (!os_path_isdir(props->SAeventsDir)) + { + LOG_ERRMSG("SA events directory %s doesn't exist", + props->SAeventsDir); + goto ERROR; + } + if (strlen(props->SAeventsDir) == 0) + { + strcpy(props->SAeventsDir, "./\0"); + } + else + { + if (props->SAeventsDir[strlen(props->SAeventsDir)-1] != '/') + { + strcat(props->SAeventsDir, "/\0"); + } + } + } + else + { + //strcpy(props->SAeventsDir, "\0"); + LOG_MSG("No SA events directory specified --> Use:%s", "."); + /*strcpy(props->SAeventsDir, "./\0");*/ + } + + s = iniparser_getstring(ini, "general:SA_output_dir\0", "."); + if (s != NULL) + { + strcpy(props->SAoutputDir, s); + if (!os_path_isdir(props->SAoutputDir)) + { + LOG_ERRMSG("SA output directory %s doesn't exist", + props->SAoutputDir); + goto ERROR; + } + if (strlen(props->SAoutputDir) == 0) + { + strcpy(props->SAoutputDir, "./\0"); + } + else + { + if (props->SAoutputDir[strlen(props->SAoutputDir)-1] != '/') + { + strcat(props->SAoutputDir, "/\0"); + } + } + } + else + { + //strcpy(props->SAoutputDir, "\0"); + LOG_MSG("No SA output directory specified --> Use:%s", "."); + } + + props->bufflen = iniparser_getdouble(ini, "general:bufflen\0", 1800.0); + if (props->bufflen <= 0.0) + { + LOG_ERRMSG("Buffer lengths=%f must be positive!", props->bufflen); + goto ERROR; + } + if (props->opmode == OFFLINE) + { + s = iniparser_getstring(ini, "general:eewsfile\0", NULL); + if (s == NULL) + { + LOG_ERRMSG("%s", "Could not find decision module XML file!"); + goto ERROR; + } + strcpy(props->eewsfile, s); + s = iniparser_getstring(ini, "general:observed_data_dir\0", NULL); + if (s != NULL) + { + strcpy(props->obsdataDir, s); + if (!os_path_isdir(props->obsdataDir)) + { + LOG_ERRMSG("Observed data directory %s doesn't exist", + props->obsdataDir); + goto ERROR; + } + if (strlen(props->obsdataDir) == 0) + { + strcpy(props->obsdataDir, "./\0"); + } + else + { + if (props->obsdataDir[strlen(props->obsdataDir)-1] != '/') + { + strcat(props->obsdataDir, "/\0"); + } + } + } + else + { + strcpy(props->obsdataDir, "./\0"); + } + s = iniparser_getstring(ini, "general:observed_data_file\0", NULL); + if (s != NULL) + { + strcpy(props->obsdataFile, s); + memset(cwork, 0, sizeof(cwork)); + strcpy(cwork, props->obsdataDir); + strcat(cwork, props->obsdataFile); + if (!os_path_isfile(cwork)) + { + LOG_ERRMSG("Observed data file %s doesn't exist", cwork); + goto ERROR; + } + } + else + { + LOG_ERRMSG("%s", "Must specify observed data file!"); + } + s = iniparser_getstring(ini, "general:synthetic_data_prefix\0", "LX\0"); + } + // UTM zone + props->utm_zone = iniparser_getint(ini, "general:utm_zone\0", -12345); + if (props->utm_zone < 0 || props->utm_zone > 60) + { + if (props->utm_zone !=-12345) + { + LOG_WARNMSG("UTM zone %d is invalid estimating from hypocenter", + props->utm_zone); + props->utm_zone =-12345; + } + } + // Verbosity + props->verbose = iniparser_getint(ini, "general:verbose\0", 2); + // Sampling period + props->dt_default = iniparser_getdouble(ini, "general:dt_default\0", 1.0); + if (props->dt_default <= 0.0) + { + LOG_WARNMSG("Default sampling period %f invalid; defaulting to %f!", + props->dt_default, 1.0); + props->dt_default = 1.0; + } + itemp = iniparser_getint(ini, "general:dt_init\0", 3); + props->dt_init = (enum dtinit_type) itemp; //iniparser_getint(ini, "general:dt_init\0", 3); + if (props->opmode != OFFLINE) + { + if (props->dt_init != INIT_DT_FROM_TRACEBUF) + { + LOG_WARNMSG("%s", "Obtaining sampling period from tracebuf"); + props->dt_init = INIT_DT_FROM_TRACEBUF; //3; + } + } + if (props->opmode == OFFLINE) + { + // Make sure the EEW XML file exists + if (!os_path_isfile(props->eewsfile)) + { + LOG_ERRMSG("Cannot find EEW XML file %s!", props->eewsfile); + goto ERROR; + } + // Figure out how to initialize sampling period + if (props->dt_init == INIT_DT_FROM_FILE) + { + itemp = iniparser_getint(ini, "general:dt_init\0", 1); + props->dt_init = (enum dtinit_type) itemp; + if (s == NULL) + { + LOG_ERRMSG("%s", "Must specify metaDataFile!"); + goto ERROR; + } + } + else if (props->dt_init == INIT_DT_FROM_SAC) + { + props->dt_init = INIT_DT_FROM_SAC; + } + else + { + if (props->dt_init != INIT_DT_FROM_DEFAULT) + { + LOG_WARNMSG("%s", "Setting dt from default"); + props->dt_init = INIT_DT_FROM_DEFAULT; + } + } + } + else + { + if (props->dt_init != INIT_DT_FROM_TRACEBUF) + { + LOG_WARNMSG("%s", "Will get GPS sampling period from tracebuffer!"); + props->dt_init = INIT_DT_FROM_TRACEBUF; + } + } + // Wait time + props->waitTime = 1.0; + if (props->opmode == REAL_TIME_EEW) + { + props->waitTime = iniparser_getdouble(ini, "general:waitTime\0", 1.0); + if (props->waitTime < 0.0) + { + LOG_ERRMSG("Invalid wait time %f!", props->waitTime); + goto ERROR; + } + } + // Location initialization + itemp = iniparser_getint(ini, "general:loc_init\0", 1); + props->loc_init = (enum locinit_type) itemp; + if (props->opmode == OFFLINE) + { + if (props->loc_init == INIT_LOCS_FROM_TRACEBUF) + { + LOG_ERRMSG("%s", "offline cant initialize locations from tracebuf"); + goto ERROR; + } + } + // Synthetic runtime + if (props->opmode == OFFLINE) + { + props->synthetic_runtime + = iniparser_getdouble(ini, "general:synthetic_runtime\0", 0.0); + } + // Processing time + props->processingTime + = iniparser_getdouble(ini, "general:processing_time\0", 300.0); + if (props->processingTime > props->bufflen) + { + LOG_ERRMSG("%s", "Error processing time cannot exceed buffer length"); + goto ERROR; + } + // Default earthquake depth + props->eqDefaultDepth + = iniparser_getdouble(ini, "general:default_event_depth\0", 8.0); + if (props->eqDefaultDepth < 0.0) + { + LOG_ERRMSG("Error default earthquake depth must be positive %f", + props->eqDefaultDepth); + goto ERROR; + } + // H5 archive directory + s = iniparser_getstring(ini, "general:h5ArchiveDirectory\0", NULL); + if (s == NULL) + { + strcpy(props->h5ArchiveDir, "./\0"); + } + else + { + strcpy(props->h5ArchiveDir, s); + if (!os_path_isdir(props->h5ArchiveDir)) + { + LOG_WARNMSG("Archive directory %s doesn't exist", + props->h5ArchiveDir); + LOG_WARNMSG("%s", "Will use current working directory"); + memset(props->h5ArchiveDir, 0, sizeof(props->h5ArchiveDir)); + strcpy(props->h5ArchiveDir, "./\0"); + } + } + // Only write summary HDF5 files? + props->lh5SummaryOnly = iniparser_getboolean(ini, "general:H5SummaryOnly\0", + false); + + // ANSS informaiton + s = iniparser_getstring(ini, "general:anssNetwork\0", "UW\0"); + strcpy(props->anssNetwork, s); + s = iniparser_getstring(ini, "general:anssDomain\0", "anss.org\0"); + strcpy(props->anssDomain, s); + //---------------------------Earthworm parameters-------------------------// + if (props->opmode == REAL_TIME_EEW) + { + s = iniparser_getstring(ini, "earthworm:gpsRingName\0", "WAVE_RING\0"); + strcpy(props->ew_props.gpsRingName, s); + if (strlen(props->ew_props.gpsRingName) < 1) + { + LOG_WARNMSG("%s", "GPS ring name may not be specified"); + } + s = iniparser_getstring(ini, "earthworm:moduleName\0", "geojson2ew\0"); + strcpy(props->ew_props.moduleName, s); + if (strlen(props->ew_props.moduleName) < 1) + { + LOG_ERRMSG("%s", "Module name is not specified"); + goto ERROR; + } + } + // Free the ini file + iniparser_freedict(ini); + //------------------------------PGD Parameters----------------------------// + ierr = core_scaling_pgd_readIni(propfilename, "PGD\0", + props->verbose, props->utm_zone, + &props->pgd_props); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading PGD parameters"); + goto ERROR; + } + //----------------------------CMT Parameters------------------------------// + ierr = core_cmt_readIni(propfilename, "CMT\0", + props->verbose, props->utm_zone, + &props->cmt_props); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading CMT parameters"); + goto ERROR; + } + //------------------------------FF Parameters-----------------------------// + ierr = core_ff_readIni(propfilename, "FF\0", + props->verbose, props->utm_zone, + props->cmt_props.min_sites, + &props->ff_props); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading FF parameters"); + goto ERROR; + } + //---------------------------ActiveMQ Parameters--------------------------// +#ifdef GFAST_USE_AMQ + if (props->opmode == REAL_TIME_EEW) + { + ierr = activeMQ_readIni(propfilename, "ActiveMQ\0", + &props->activeMQ_props); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading ActiveMQ group parameters"); + goto ERROR; + } + } // End check on need for ActiveMQ +#endif + // Success! + ierr = 0; + return ierr; + ERROR:; + return ierr; +} + +int set_array_from_string_int(const char *prop, int *array, int max_size) { + int i, j = 0; + int *arr = array; + // ensure the array is initialized to zeros + arr[0] = 0; + if (prop != NULL) + { + //// Traverse the string + for (i = 0; prop[i] != '\0'; i++) { + if (prop[i] == ',') { + j++; + // stop if the max_size is exceeded + if (j >= max_size) break; + // ensure the array is initialized to zeros + arr[j] = 0; + } + else { + // ASCII decimal for '0' is 48 + arr[j] = arr[j] * 10 + (prop[i] - 48); + } + } + } + + // return the number of items added to the array + return j + 1; +} + +int set_array_from_string_str(const char *prop, char **array, int max_size) { + + char *tok, *p, *last; + char *s = strdup(prop); + int i = 0, lens; + + tok = s; + while(((p = strtok_r(tok, ", \t", &last)) != NULL) && (i < max_size)) { + tok = NULL; + + lens = (int) (strlen(p)); + array[i] = (char *)calloc((size_t) (lens+1), sizeof(char)); + strcpy(array[i], p); + i++; + } + free(s); + + return i; +} diff --git a/src/core/properties/print.c b/src/core/properties/print.c new file mode 100644 index 00000000..e72648e7 --- /dev/null +++ b/src/core/properties/print.c @@ -0,0 +1,315 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/os/os.h" + +/*! + * @brief Prints the GFAST properties to the debug file. Note, there is + * no verbosity check. + * + * @param[in] props GFAST properties structure to write to the debug file + * + * @author Ben Baker, ISTI + * + */ +void core_properties_print(struct GFAST_props_struct props) +{ + const char *lspace = " \0"; + int i; + LOG_DEBUGMSG("%s", "GFAST properties"); + if (props.opmode == OFFLINE) + { + LOG_DEBUGMSG("%s GFAST site metadata file %s", lspace, + props.metaDataFile); + LOG_DEBUGMSG("%s GFAST is operating in offline mode", lspace); + LOG_DEBUGMSG("%s GFAST default sampling period is %f (s)", lspace, + props.dt_default); + if (props.dt_init == INIT_DT_FROM_FILE) + { + LOG_DEBUGMSG("%s GFAST will get sampling period from file %s", + lspace, props.metaDataFile); + } + else if (props.dt_init == INIT_DT_FROM_DEFAULT) + { + LOG_DEBUGMSG("%s GFAST will set GPS sampling periods to %f (s)", + lspace, props.dt_default); + } + else if (props.dt_init == INIT_DT_FROM_SAC) + { + LOG_DEBUGMSG("%s GFAST will set GPS sampling period from SAC files", + lspace); + } + if (props.loc_init == INIT_LOCS_FROM_FILE) + { + LOG_DEBUGMSG("%s GFAST will initialize locations from file %s", + lspace, props.metaDataFile); + } + else if (props.loc_init == INIT_LOCS_FROM_TRACEBUF) + { + LOG_DEBUGMSG("%s GFAST will initialize locations from tracebuf", + lspace); + } + else if (props.loc_init == INIT_LOCS_FROM_SAC) + { + LOG_DEBUGMSG("%s GFAST will initialize locations from SAC files", + lspace); + } + LOG_DEBUGMSG("%s GFAST simulation time (s) %f", + lspace, props.synthetic_runtime); + LOG_DEBUGMSG("%s GFAST observed data directory: %s", + lspace, props.obsdataDir); + LOG_DEBUGMSG("%s GFAST observed data file: %s", + lspace, props.obsdataFile); + } + else if (props.opmode == PLAYBACK) + { + LOG_DEBUGMSG("%s GFAST is operating in playback mode", lspace); + } + else if (props.opmode == REAL_TIME_EEW) + { + LOG_DEBUGMSG("%s GFAST is operating in EEW real-time mode", lspace); + LOG_DEBUGMSG("%s GFAST time between iterations is %f (s)", lspace, + props.waitTime); + LOG_DEBUGMSG("%s GFAST site position file %s", lspace, + props.metaDataFile); + if (props.n_networks == 0) + { + LOG_DEBUGMSG("%s GFAST will use any networks available from the position file", + lspace); + } + else + { + int nbuffer = 128; + char buffer_network[nbuffer]; + int cx = 0; + for (i = 0; i < props.n_networks; i++) { + if (i == props.n_networks - 1) { + cx += snprintf(buffer_network + cx, nbuffer - cx, "%s", + props.metaDataNetworks[i]); + } else { + cx += snprintf(buffer_network + cx, nbuffer - cx, "%s, ", + props.metaDataNetworks[i]); + } + } + LOG_DEBUGMSG("%s GFAST will only use %d networks from the position file: %s", + lspace, props.n_networks, buffer_network); + } + LOG_DEBUGMSG("%s GFAST default sampling period is %f (s)", lspace, + props.dt_default); + if (props.opmode == REAL_TIME_EEW) + { + LOG_DEBUGMSG("%s GFAST trigger origin url: %s", lspace, + props.activeMQ_props.originURL); + LOG_DEBUGMSG("%s GFAST origin topic: %s", + lspace, props.activeMQ_props.originTopic); + LOG_DEBUGMSG("%s GFAST results destination url: %s", lspace, + props.activeMQ_props.destinationURL); + LOG_DEBUGMSG("%s GFAST destination topic: %s", + lspace, props.activeMQ_props.destinationTopic); + LOG_DEBUGMSG("%s GFAST heartbeat topic: %s", + lspace, props.activeMQ_props.hbTopic); + LOG_DEBUGMSG("%s heartbeat interval (seconds) %d", lspace, + props.activeMQ_props.hbInterval); + if (props.activeMQ_props.maxAttempts > 0) + { + LOG_DEBUGMSG("%s Milliseconds before reconnect %d", + lspace, props.activeMQ_props.msReconnect); + LOG_DEBUGMSG("%s Max number of attempts to connect %d", + lspace, props.activeMQ_props.maxAttempts); + } + LOG_DEBUGMSG("%s Will wait %d milliseconds for a message", + lspace, props.activeMQ_props.msWaitForMessage); + } + } + LOG_DEBUGMSG("%s GFAST buffer length is %f seconds", lspace, props.bufflen); + if (props.utm_zone ==-12345) + { + LOG_DEBUGMSG("%s GFAST will get UTM zone from hypocenters", lspace); + } + else + { + LOG_DEBUGMSG("%s GFAST will set UTM zone to %d", lspace, + props.utm_zone); + } + LOG_DEBUGMSG("%s GFAST verbosity level is %d", lspace, props.verbose); + if (os_path_isfile(props.siteMaskFile)) + { + LOG_DEBUGMSG("%s GFAST will use site maskfile: %s", lspace, + props.siteMaskFile); + } + else + { + LOG_DEBUGMSG("%s GFAST will not mask any sites", lspace); + } + LOG_DEBUGMSG("%s GFAST HDF5 archive dir: %s", lspace, props.h5ArchiveDir); + LOG_DEBUGMSG("%s GFAST will finish processing an event after %f (s)", + lspace, props.processingTime); + LOG_DEBUGMSG("%s GFAST will use a default earthquake depth of %f", + lspace, props.eqDefaultDepth); + if (props.lh5SummaryOnly) + { + LOG_DEBUGMSG("%s GFAST will only write an HDF5 summary", lspace); + } + else + { + LOG_DEBUGMSG("%s GFAST will save all steps to HDF5", lspace); + } + //--------------------------------pgd-------------------------------------// + if (props.pgd_props.do_pgd) + { + LOG_DEBUGMSG("%s GFAST will calculate PGD", lspace); + LOG_DEBUGMSG("%s GFAST PGD source receiver distance tolerance %f (km)", + lspace, props.pgd_props.dist_tol); + LOG_DEBUGMSG("%s GFAST PGD default distance %f (cm)", + lspace, props.pgd_props.disp_def); + LOG_DEBUGMSG("%s GFAST Number of PGD grid search latitudes %d", + lspace, props.pgd_props.ngridSearch_lats); + LOG_DEBUGMSG("%s GFAST Number of PGD grid search longitudes %d", + lspace, props.pgd_props.ngridSearch_lons); + LOG_DEBUGMSG("%s GFAST Number of PGD grid search depths is %d", + lspace, props.pgd_props.ngridSearch_deps); + LOG_DEBUGMSG("%s GFAST PGD data selection velocity is %f (km/s)", + lspace, props.pgd_props.window_vel); + LOG_DEBUGMSG("%s GFAST Number of sites required to compute PGD is %d", + lspace, props.pgd_props.min_sites); + if (props.pgd_props.ngridSearch_lats > 1) + { + LOG_DEBUGMSG("%s GFAST PGD latitude grid spacing %f", + lspace, props.pgd_props.dLat); + } + if (props.pgd_props.ngridSearch_lons > 1) + { + LOG_DEBUGMSG("%s GFAST PGD longitude grid spacing %f", + lspace, props.pgd_props.dLon); + } + if (props.pgd_props.n99 > 0) + { + LOG_DEBUGMSG("%s GFAST PGD sigma lookup: %d values", + lspace, props.pgd_props.n99); + for (i = 0; i < props.pgd_props.n99; i++) { + LOG_DEBUGMSG("%s GFAST PGD sigma lookup: %5.1f %5.2f", + lspace, props.pgd_props.t99[i], props.pgd_props.m99[i]); + } + } + else + { + LOG_DEBUGMSG("%s GFAST PGD sigma lookup: 0 values, using default", + lspace); + } + if (props.pgd_props.n_throttle > 0) + { + LOG_DEBUGMSG("%s GFAST PGD threshold lookup: %d values", + lspace, props.pgd_props.n_throttle); + for (i = 0; i < props.pgd_props.n_throttle; i++) { + LOG_DEBUGMSG("%s GFAST PGD threshold lookup: %5.1f %5.2f %d", lspace, + props.pgd_props.throttle_time_threshold[i], + props.pgd_props.throttle_pgd_threshold[i], + props.pgd_props.throttle_num_stations[i]); + } + } + else + { + LOG_DEBUGMSG("%s GFAST PGD threshold lookup: 0 values, using default", + lspace); + } + if (props.pgd_props.u_raw_sigma_threshold >= 0) { + LOG_DEBUGMSG("%s Will ignore pd values if U raw sigma exceeds %f cm", + lspace, props.pgd_props.u_raw_sigma_threshold); + } else { + LOG_DEBUGMSG("%s Will allow any U raw sigma values for pd calculations", lspace); + } + if (props.pgd_props.n_raw_sigma_threshold >= 0) { + LOG_DEBUGMSG("%s Will ignore pd values if N raw sigma exceeds %f cm", + lspace, props.pgd_props.n_raw_sigma_threshold); + } else { + LOG_DEBUGMSG("%s Will allow any N raw sigma values for pd calculations", lspace); + } + if (props.pgd_props.e_raw_sigma_threshold >= 0) { + LOG_DEBUGMSG("%s Will ignore pd values if E raw sigma exceeds %f cm", + lspace, props.pgd_props.e_raw_sigma_threshold); + } else { + LOG_DEBUGMSG("%s Will allow any E raw sigma values in pd calculations", lspace); + } + LOG_DEBUGMSG("%s Will throttle messages below SA mag %f", + lspace, props.pgd_props.SA_mag_threshold); + LOG_DEBUGMSG("%s Will throttle messages above pgd mag sigma %f", + lspace, props.pgd_props.pgd_sigma_throttle); + + LOG_DEBUGMSG("%s GFAST Minimum PGD value to include in inversion (cm): %f", + lspace, props.pgd_props.minimum_pgd_cm); + LOG_DEBUGMSG("%s GFAST Maximum PGD value to include in inversion (cm): %f", + lspace, props.pgd_props.maximum_pgd_cm); + LOG_DEBUGMSG("%s GFAST Maximum stations to include assoc tag: %d", + lspace, props.pgd_props.max_assoc_stations); + } + else + { + LOG_DEBUGMSG("%s GFAST will not calculate PGD", lspace); + } + + //--------------------------------cmt-------------------------------------// + if (props.cmt_props.do_cmt) + { + LOG_DEBUGMSG("%s GFAST will calculate CMT", lspace); + LOG_DEBUGMSG("%s GFAST Number of latitudes in CMT grid search %d", + lspace, props.cmt_props.ngridSearch_lats); + LOG_DEBUGMSG("%s GFAST Number of longitudes in CMT grid search %d", + lspace, props.cmt_props.ngridSearch_lons); + LOG_DEBUGMSG("%s GFAST Number of depths in CMT grid search %d", + lspace, props.cmt_props.ngridSearch_deps); + LOG_DEBUGMSG("%s GFAST CMT data selection velocity is %f (km/s)", + lspace, props.cmt_props.window_vel); + LOG_DEBUGMSG("%s GFAST CMT data averaging window length %f (s)", + lspace, props.cmt_props.window_avg); + LOG_DEBUGMSG("%s GFAST Number of sites required to compute CMT is %d", + lspace, props.cmt_props.min_sites); + if (props.cmt_props.ldeviatoric) + { + LOG_DEBUGMSG("%s GFAST will apply deviatoric constraint to CMT", + lspace); + } + else + { + LOG_DEBUGMSG("%s GFAST will invert for all 6 MT terms", lspace); + } + if (props.cmt_props.ngridSearch_lats > 1) + { + LOG_DEBUGMSG("%s GFAST CMT latitude grid spacing %f", + lspace, props.cmt_props.dLat); + } + if (props.cmt_props.ngridSearch_lons > 1) + { + LOG_DEBUGMSG("%s GFAST CMT longitude grid spacing %f", + lspace, props.cmt_props.dLon); + } + } + else + { + LOG_DEBUGMSG("%s GFAST will not calculate CMT", lspace); + } + //--------------------------------ff--------------------------------------// + if (props.ff_props.do_ff) + { + LOG_DEBUGMSG("%s GFAST will calculate FF", lspace); + LOG_DEBUGMSG("%s GFAST will use %d fault patches along strike", + lspace, props.ff_props.nstr); + LOG_DEBUGMSG("%s GFAST will use %d fault patches down-dip", + lspace, props.ff_props.ndip); + LOG_DEBUGMSG("%s GFAST Number of sites required to compute FF is %d", + lspace, props.ff_props.min_sites); + LOG_DEBUGMSG("%s GFAST finite fault data selection velocity is %f (km/s)", + lspace, props.ff_props.window_vel); + LOG_DEBUGMSG("%s GFAST finite fault data averaging window length %f (s)", + lspace, props.ff_props.window_avg); + LOG_DEBUGMSG("%s GFAST fault length safety factor %.2f pct", + lspace, props.ff_props.flen_pct); + LOG_DEBUGMSG("%s GFAST fault width safety factor %.2f pct", + lspace, props.ff_props.fwid_pct); + } + else + { + LOG_DEBUGMSG("%s GFAST will not calculate FF", lspace); + } + return; +} diff --git a/src/core/scaling/Makefile b/src/core/scaling/Makefile new file mode 100644 index 00000000..304ad864 --- /dev/null +++ b/src/core/scaling/Makefile @@ -0,0 +1,68 @@ +# Makefile for GFAST/src/core/scaling +# + +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = pgd_depthGridSearch.o pgd_gridSearch.o pgd_readIni.o \ +pgd_setForwardModel.o pgd_weightForwardModel.o pgd_finalize.o \ +pgd_initialize.o pgd_setDiagonalWeightMatrix.o pgd_setRHS.o \ +pgd_weightObservations.o pgd_sanityChecks.o readSigmaLookupFile.o \ +readPgdThresholdLookupFile.o readRawSigmaThresholdLookupFile.o + +DEBUG = -g + +#iniparser will be deleted +INCL = -I ../../../include $(ISCL_INCL) $(INIPARSER_INCL) $(LAPACKE_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(cc) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/core/scaling/pgd_depthGridSearch.c b/src/core/scaling/pgd_depthGridSearch.c new file mode 100644 index 00000000..fde42a7f --- /dev/null +++ b/src/core/scaling/pgd_depthGridSearch.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include "gfast_core.h" +#ifdef GFAST_USE_INTEL + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Weverything" + #endif + #include + #include + #ifdef __clang__ + #pragma clang diagnostic pop + #endif +#else +#include +#include +#endif +#include "iscl/linalg/linalg.h" +#include "iscl/memory/memory.h" +#include "iscl/statistics/statistics.h" +#include "iscl/time/time.h" + +/*! + * @brief Computes the predicted magnitude using PGD and Pd from + * the geodetic data by solving the overdetermined system: + * \f[ + * W \left [B + C \log_{10}(r) \right ] \textbf{m} + * = W \left \{ \log_{10}(d) - A \right \} + * \f] + * for the the magnitude m. Here r is the hypocentral distance, + * d is the displacement, A, B, and C are defined in the routine. + * The weighting matrix is a diagonal matrix defined by: + * \f[ W = diag + * \left[ + * e^{-\frac{\Delta^2}{8 \min(\Delta^2) }} + * \right ] \f] + * where \f$ \Delta \f$ is the epicentral distance. + * + * @param[in] l1 number of sites + * @param[in] ndeps number of source depths + * @param[in] verbose controls verbosity (< 2 is quiet) + * @param[in] dist_tol displacement tolerance (cm). if the displacment + * is less than dist_tol it would be set to dist_tol + * @param[in] disp_def displacement default (cm) if d < dist_tol + * @param[in] utmSrcNorthing source UTM northing position (m) + * @param[in] utmSrcEasting source UTM easting position (m) + * @param[in] srcDepths source depth in grid search (km) [ndeps] + * @param[in] utmRecvNorthing receiver UTM northing position (m) [l1] + * @param[in] utmRecvEasting receiver UTM easting position (m) [l1] + * @param[in] staAlt station elevation (m) [l1] + * @param[in] d site peak ground displacements (cm) [l1] + * @param[in] wts data weights on each observation [l1]. + * if NULL or if each weight is the same then + * this array will be ignored. + * + * @param[out] srdist source receiver distance between the + * idep'th source and k'th receiver [l1*ndeps] + * @param[out] M magnitude at each depth [ndeps] + * @param[out] VR variance reduction (percentage) at each + * depth [ndeps] + * @param[out] iqr the interquartile range computed from the + * difference of the 75th percentile of the + * weighted residuals and the 25th percentile + * of the weighted residuals at each depth [ndeps] + * @param[out] Uest the PGD estimate peak ground displacements. + * the estimate for the i'th site at the + * idep'th depth is access by idep*l1 + i [l1*ndeps] + * + * @result 0 indicates success + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +int core_scaling_pgd_depthGridSearch(const int l1, const int ndeps, + const int verbose, + const double dist_tol, + const double disp_def, + const double utmSrcEasting, + const double utmSrcNorthing, + const double *__restrict__ srcDepths, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ d, + const double *__restrict__ wts, + double *__restrict__ srdist, + double *__restrict__ M, + double *__restrict__ VR, + double *__restrict__ iqr, + double *__restrict__ Uest) +{ + double *b, *G, *r, *repi, *UP, *W, *Wb, *WG, *wres, pct[2], M1[1], + est, srcDepth, xden, xnum; + int i, idep, ierr, ierr1; + const double A =-6.687; + const double B = 1.500; + const double C =-0.214; + const double q[2] = {25.0, 75.0}; + const int nq = 2; + int debug = 0; + //const double A = -4.434; /* TODO remove with approval */ + //const double B = 1.047; /* TODO remove with approval */ + //const double C = -0.138; /* TODO remove with approval */ + //------------------------------------------------------------------------// + // + // Initialize + ierr = 0; + repi = NULL; + r = NULL; + wres = NULL; + b = NULL; + G = NULL; + UP = NULL; + W = NULL; + Wb = NULL; + WG = NULL; + // Error check + if (l1 < 1) + { + LOG_ERRMSG("Error invalid number of input stations: %d", l1); + ierr = 1; + goto ERROR; + } + if (ndeps < 1) + { + LOG_ERRMSG("Error invalid number of source depths: %d", ndeps); + ierr = 1; + goto ERROR; + } + if (srcDepths == NULL || utmRecvEasting == NULL || + utmRecvNorthing == NULL || staAlt == NULL || + d == NULL || M == NULL || VR == NULL || Uest == NULL || srdist == NULL) + { + if (srcDepths == NULL){LOG_ERRMSG("%s", "srcDepths is NULL!");} + if (utmRecvEasting == NULL) + { + LOG_ERRMSG("%s", "utmRecvEasting is NULL!"); + } + if (utmRecvNorthing == NULL) + { + LOG_ERRMSG("%s", "utmRecvNorthing is NULL!"); + } + if (staAlt == NULL){LOG_ERRMSG("%s", "staAlt is NULL");} + if (d == NULL){LOG_ERRMSG("%s", "d is NULL");} + if (M == NULL){LOG_ERRMSG("%s", "M is NULL");} + if (VR == NULL){LOG_ERRMSG("%s", "VR is NULL");} + if (Uest == NULL){LOG_ERRMSG("%s", "Uest is NULL");} + if (srdist == NULL){LOG_ERRMSG("%s", "srdist is NULL");} + ierr = 1; + goto ERROR; + } + // Initialize result to nothing +#ifdef _OPENMP + #pragma omp simd +#endif + for (idep=0; idep km + } + // Sort and print + // + if (debug) { + LOG_MSG("%s", "Call core_scaling_pgd_sanityChecks"); + ierr = core_scaling_pgd_sanityChecks(l1, + dist_tol, + disp_def, + repi, d); + } + + // Set the RHS log10(d) - A + ierr = core_scaling_pgd_setRHS(l1, + dist_tol, disp_def, + A, d, + b); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error creating RHS"); + goto ERROR; + } + // Compute the diagonal data weights + ierr = core_scaling_pgd_setDiagonalWeightMatrix(l1, + repi, + wts, + W); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting diagonal weight matrix"); + goto ERROR; + } + // Weight the observations + ierr = core_scaling_pgd_weightObservations(l1, + W, + b, + Wb); + if (ierr < 0) + { + LOG_ERRMSG("%s", "Error weighting observations"); + goto ERROR; + } + // Grid search on source depths + time_tic(); + if (verbose > 2) + { + LOG_DEBUGMSG("%s", "Beginning search on depths..."); + } +#ifdef PARALLEL_PGD + #pragma omp parallel \ + firstprivate(A, B, C) \ + private(i, idep, ierr1, est, G, M1, pct, r, srcDepth, UP, WG) \ + private(wres, xden, xnum) \ + shared(b, d, iqr, M, q, repi, srdist, \ + srcDepths, staAlt, utmRecvEasting, utmRecvNorthing, \ + Uest, verbose, VR, W, Wb) \ + reduction(+:ierr) default(none) + { +#endif + G = memory_calloc64f(l1*1); + r = memory_calloc64f(l1); + UP = memory_calloc64f(l1); + WG = memory_calloc64f(l1*1); + wres = memory_calloc64f(l1); +#ifdef PARALLEL_PGD + #pragma omp for +#endif + for (idep=0; idep 2) + { + LOG_DEBUGMSG("Grid-search time: %f (s)", time_toc()); + } + } +ERROR:; // An error was encountered + // Free space + memory_free64f(&repi); + memory_free64f(&b); + memory_free64f(&W); + memory_free64f(&Wb); + return ierr; +} diff --git a/src/core/scaling/pgd_finalize.c b/src/core/scaling/pgd_finalize.c new file mode 100644 index 00000000..79e01337 --- /dev/null +++ b/src/core/scaling/pgd_finalize.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Releases the memory on the PGD data data structure + * + * @param[out] pgd_data freed PGD data data structure + * + * @author Ben Baker (ISTI) + * + */ +void core_scaling_pgd_finalizeData( + struct GFAST_peakDisplacementData_struct *pgd_data) +{ + int i; + // Free the PGD data data + if (pgd_data->stnm != NULL) + { + for (i=0; insites; i++) + { + free(pgd_data->stnm[i]); + } + free(pgd_data->stnm); + } + memory_free64f(&pgd_data->pd); + memory_free64f(&pgd_data->wt); + memory_free64f(&pgd_data->sta_lat); + memory_free64f(&pgd_data->sta_lon); + memory_free64f(&pgd_data->sta_alt); + memory_free64f(&pgd_data->pd_time); + memory_free8l(&pgd_data->lmask); + memory_free8l(&pgd_data->lactive); + memset(pgd_data, 0, sizeof(struct GFAST_peakDisplacementData_struct)); + return; +} +//============================================================================// +/*! + * @brief Releases the memory on the PGD result structure + * + * @param[out] pgd freed PGD results data structure + * + * @author Ben Baker (ISTI) + * + */ +void core_scaling_pgd_finalizeResults( + struct GFAST_pgdResults_struct *pgd) +{ + memory_free64f(&pgd->mpgd); + memory_free64f(&pgd->mpgd_vr); + memory_free64f(&pgd->dep_vr_pgd); + memory_free64f(&pgd->iqr); + memory_free64f(&pgd->UP); + memory_free64f(&pgd->UPinp); + memory_free64f(&pgd->srcDepths); + memory_free64f(&pgd->srdist); + memory_free8l(&pgd->lsiteUsed); + memset(pgd, 0, sizeof(struct GFAST_pgdResults_struct)); + return; +} +//============================================================================// +/*! + * @brief Releases the memory on the PGD data structures + * + * @param[out] pgd_props nulled out PGD properties structure + * @param[out] pgd_data freed PGD data data structure + * @param[out] pgd freed PGD results data structure + * + * @author Ben Baker (ISTI) + * + */ +void core_scaling_pgd_finalize( + struct GFAST_pgd_props_struct *pgd_props, + struct GFAST_peakDisplacementData_struct *pgd_data, + struct GFAST_pgdResults_struct *pgd) +{ + core_properties_finalizePGDProperties(pgd_props); + core_scaling_pgd_finalizeData(pgd_data); + core_scaling_pgd_finalizeResults(pgd); + return; +} diff --git a/src/core/scaling/pgd_gridSearch.c b/src/core/scaling/pgd_gridSearch.c new file mode 100644 index 00000000..f7f41e29 --- /dev/null +++ b/src/core/scaling/pgd_gridSearch.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include "gfast_core.h" +#include "iscl/time/time.h" + +/*! + * @brief PGD scaling full grid search (lat, lon, depth) driver. + * + * @param[in] l1 Number of sites. + * @param[in] ndeps Number of source depths. + * @param[in] nlats Number of latitudes in grid search. + * @param[in] nlons Number of longitudes in grid search. + * @param[in] verbose Controls verbosity (< 2 is quiet). + * @param[in] dist_tol Displacement tolerance (cm). If the displacment + * is less than dist_tol it will be set to dist_tol. + * @param[in] disp_def Displacement default (cm) if d < dist_tol. + * @param[in] utmSrcNorthings Source UTM northing positions (m). This is an + * array of dimension [nlat*nlon] with leading + * dimension nlats. + * @param[in] utmSrcEastings Source UTM easting positions (m). This is an + * array of dimension [nlat*nlon] with leading + * dimension nlats.. + * @param[in] srcDepths Source depth in grid search (km). This is + * an array of dimension [ndeps]. + * @param[in] utmRecvNorthing Receiver UTM northing position (m). This is + * an array of dimension [l1]. + * @param[in] utmRecvEasting Receiver UTM easting position (m). This is + * an array of dimension [l1]. + * @param[in] staAlt Station elevation (m). This is an array of + * dimension [l1]. + * @param[in] d Site peak ground displacements (cm). This is + * an array of dimension [l1]. + * @param[in] wts Data weights on each observation. Nominally, + * this is an array of dimension [l1]. However, + * if NULL or if each weight is the same then + * this array will be ignored. + * + * @param[out] srdist Source receiver distance between the + * idep'th source and k'th receiver. This is + * an array of length [l1*ndeps*nlat*nlon]. + * The i'th site at the idep'th depth is given by + * ilon*nlats*ndeps*l1 + ilat*ndeps*l1 + idep*l1 + i + * @param[out] M Magnitude at each depth. This is an array of + * length [ndeps*nlat*nlon]. + * The (ilat,ilon,idep)'th is given by + * ilon*nlats*ndeps + ilat*ndeps + idep. + * @param[out] VR Variance reduction (percentage) at each + * depth. This is an array of length + * [ndeps*nlat*nlon]. + * The (ilat,ilon,idep)'th is given by + * ilon*nlats*ndeps + ilat*ndeps + idep. + * @param[out] iqr The interquartile range computed from the + * difference of the 75th percentile of the + * weighted residuals and the 25th percentile + * of the weighted residuals at each depth [ndeps]. + * The (ilat,ilon,idepth)idep'th is given by + * ilon*nlats*ndeps + ilat*ndeps + idep. + * @param[out] Uest The PGD estimate peak ground displacements. This + * is an array of dimension [nlons*nlats*ndeps*l1]. + * The i'th estimate at the idep'th depth is given by + * ilon*nlats*ndeps*l1 + ilat*ndeps*l1 + idep*l1 + i. + * + * @result 0 indicates success. + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +int core_scaling_pgd_gridSearch(const int l1, const int ndeps, + const int nlats, const int nlons, + const int verbose, + const double dist_tol, + const double disp_def, + const double *__restrict__ utmSrcEastings, + const double *__restrict__ utmSrcNorthings, + const double *__restrict__ srcDepths, + const double *__restrict__ utmRecvEasting, + const double *__restrict__ utmRecvNorthing, + const double *__restrict__ staAlt, + const double *__restrict__ d, + const double *__restrict__ wts, + double *__restrict__ srdist, + double *__restrict__ M, + double *__restrict__ VR, + double *__restrict__ iqr, + double *__restrict__ Uest) +{ + int ierr, ierr1, ilat, ilatLon, ilon; + // Error check + if (l1 < 1 || ndeps < 1 || nlats < 1 || nlons < 1) + { + if (l1 < 1) + { + LOG_ERRMSG("Error invalid number of input stations: %d", l1); + } + if (ndeps < 1) + { + LOG_ERRMSG("Error invalid number of source depths: %d", ndeps); + } + if (nlons < 1) + { + LOG_ERRMSG("Error invalid number of lons (easting): %d", nlons); + } + if (nlats < 1) + { + LOG_ERRMSG("Error invalid number of lats (northings): %d", nlats); + } + return -1; + } + if (utmSrcEastings == NULL || utmSrcNorthings == NULL || + srcDepths == NULL || utmRecvEasting == NULL || + utmRecvNorthing == NULL || staAlt == NULL || + d == NULL || M == NULL || VR == NULL || Uest == NULL || srdist == NULL) + { + if (utmSrcEastings == NULL) + { + LOG_ERRMSG("%s", "utmSrcEastings is NULL!"); + } + if (utmSrcNorthings == NULL) + { + LOG_ERRMSG("%s", "utmSrcNorthings is NULL!"); + } + if (srcDepths == NULL){LOG_ERRMSG("%s", "srcDepths is NULL!");} + if (utmRecvEasting == NULL) + { + LOG_ERRMSG("%s", "utmRecvEasting is NULL!"); + } + if (utmRecvNorthing == NULL) + { + LOG_ERRMSG("%s", "utmRecvNorthing is NULL!"); + } + if (staAlt == NULL){LOG_ERRMSG("%s", "staAlt is NULL");} + if (d == NULL){LOG_ERRMSG("%s", "d is NULL");} + if (M == NULL){LOG_ERRMSG("%s", "M is NULL");} + if (VR == NULL){LOG_ERRMSG("%s", "VR is NULL");} + if (Uest == NULL){LOG_ERRMSG("%s", "Uest is NULL");} + if (srdist == NULL){LOG_ERRMSG("%s", "srdist is NULL");} + return -1; + } + // Loop on the longitudes (eastings) + ierr = 0; +#ifdef PARALLEL_PGD + #pragma omp parallel for collapse(2) \ + private(ilatLon, ilat, ilon) \ + reduction(+:ierr), shared(srdist, M, VR, iqr, Uest) \ + default(none) +#endif + for (ilon=0; ilon +#include +#include +#include +#include "gfast_core.h" +#include "iscl/memory/memory.h" +/*! + * @brief Allocates space for the PGD grid search and its data structure + * + * @param[in] pgd_props holds the PGD parameters + * @param[in] gps_data holds the site stream length + * + * @param[out] pgd has space allocated for the PGD depth gridsearch + * @param[out] pgd_data holds space for peak ground dispaclement data + * as well as requisite site information + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + */ +int core_scaling_pgd_initialize(struct GFAST_pgd_props_struct pgd_props, + struct GFAST_data_struct gps_data, + struct GFAST_pgdResults_struct *pgd, + struct GFAST_peakDisplacementData_struct *pgd_data) +{ + int i, nloc; + pgd->ndeps = pgd_props.ngridSearch_deps; + pgd->nlats = pgd_props.ngridSearch_lats; + pgd->nlons = pgd_props.ngridSearch_lons; + if (pgd->ndeps < 1 || pgd->nlats < 1 || pgd->nlons < 1) + { + if (pgd->ndeps < 1) + { + LOG_ERRMSG("No depths in PGD grid search %d", + pgd_props.ngridSearch_deps); + } + if (pgd->nlats < 1) + { + LOG_ERRMSG("No lats in PGD grid search %d", + pgd_props.ngridSearch_lats); + } + if (pgd->nlats < 1) + { + LOG_ERRMSG("No lons in PGD grid search %d", + pgd_props.ngridSearch_lons); + } + return -1; + } + pgd->nsites = gps_data.stream_length; + if (pgd->nsites < pgd_props.min_sites) + { + LOG_ERRMSG("%s", "Insufficient number of sites to compute PGD"); + return -1; + } + // data + pgd_data->stnm = (char **)calloc((size_t) gps_data.stream_length, + sizeof(char *)); + pgd_data->pd = memory_calloc64f(gps_data.stream_length); + pgd_data->wt = memory_calloc64f(gps_data.stream_length); + pgd_data->sta_lat = memory_calloc64f(gps_data.stream_length); + pgd_data->sta_lon = memory_calloc64f(gps_data.stream_length); + pgd_data->sta_alt = memory_calloc64f(gps_data.stream_length); + pgd_data->pd_time = memory_calloc64f(gps_data.stream_length); + pgd_data->lmask = memory_calloc8l(gps_data.stream_length); + pgd_data->lactive = memory_calloc8l(gps_data.stream_length); + pgd_data->nsites = gps_data.stream_length; + for (i=0; insites; i++) + { + pgd_data->sta_lat[i] = gps_data.data[i].sta_lat; + pgd_data->sta_lon[i] = gps_data.data[i].sta_lon; + pgd_data->sta_alt[i] = gps_data.data[i].sta_alt; + pgd_data->pd_time[i] = 0.0; + pgd_data->stnm[i] = (char *)calloc(64, sizeof(char)); + + sprintf(pgd_data->stnm[i],"%s.%s.%s.%s", + gps_data.data[i].netw, + gps_data.data[i].stnm, + gps_data.data[i].chan[0], + gps_data.data[i].loc); + + /* + strcpy(pgd_data->stnm[i], gps_data.data[i].netw); + strcat(pgd_data->stnm[i], ".\0"); + strcat(pgd_data->stnm[i], gps_data.data[i].stnm); + strcat(pgd_data->stnm[i], ".\0"); + strncpy(pgd_data->stnm[i], gps_data.data[i].chan[0], 2); + strcat(pgd_data->stnm[i], "?.\0"); + if (strlen(gps_data.data[i].loc) > 0) + { + strcat(pgd_data->stnm[i], gps_data.data[i].loc); + } + */ + + /* + printf("pgd_initialize: gps_data: netw:%s stnm:%s chan[0]:%s loc:%s --> pgd_data.stnm:%s\n", + gps_data.data[i].netw, gps_data.data[i].stnm, gps_data.data[i].chan[0], gps_data.data[i].loc, + pgd_data->stnm[i]); + */ + if (gps_data.data[i].lskip_pgd){pgd_data->lmask[i] = true;} + } + + nloc = pgd->ndeps*pgd->nlats*pgd->nlons; + pgd->mpgd = memory_calloc64f(nloc); + pgd->mpgd_sigma = memory_calloc64f(nloc); + pgd->mpgd_vr = memory_calloc64f(nloc); + pgd->dep_vr_pgd = memory_calloc64f(nloc); + pgd->srcDepths = memory_calloc64f(pgd->ndeps); + pgd->iqr = memory_calloc64f(nloc); + pgd->UP = memory_calloc64f(pgd->nsites*nloc); + pgd->srdist = memory_calloc64f(pgd->nsites*nloc); + pgd->UPinp = memory_calloc64f(pgd->nsites); + pgd->lsiteUsed = memory_calloc8l(pgd->nsites); + // TODO: fix me and make customizable! + for (i=0; indeps; i++) + { + pgd->srcDepths[i] = (double) i + 1; + } + return 0; +} diff --git a/src/core/scaling/pgd_readIni.c b/src/core/scaling/pgd_readIni.c new file mode 100644 index 00000000..71372e16 --- /dev/null +++ b/src/core/scaling/pgd_readIni.c @@ -0,0 +1,207 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_core.h" +#include "iscl/os/os.h" + +static void setVarName(const char *group, const char *variable, + char *var) +{ + memset(var, 0, 256*sizeof(char)); + sprintf(var, "%s:%s", group, variable); + return; +} +/*! + * @brief Reads the PGD properties from the initialization file. + * + * @param[in] propfilename Name of properties file. + * @param[in] group Group in ini file. Likely "PGD". + * @param[in] verbose This is the verbosity from the general + * parameters. + * @param[in] utm_zone This is the default UTM zone from the + * general parameters. + * + * @param[out] pgd_props PGD scaling properties. + * + * @result 0 indicates success. + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_pgd_readIni(const char *propfilename, + const char *group, + const int verbose, const int utm_zone, + struct GFAST_pgd_props_struct *pgd_props) +{ + char var[256]; + int ierr; + dictionary *ini; + ierr = 1; + memset(pgd_props, 0, sizeof(struct GFAST_pgd_props_struct)); + if (!os_path_isfile(propfilename)) + { + LOG_ERRMSG("Properties file: %s does not exist", propfilename); + return ierr; + } + ini = iniparser_load(propfilename); + // Read the properties + pgd_props->verbose = verbose; + pgd_props->utm_zone = utm_zone; + setVarName(group, "do_pgd\0", var); + pgd_props->do_pgd = iniparser_getboolean(ini, var, true); + setVarName(group, "dist_tolerance\0", var); + pgd_props->dist_tol = iniparser_getdouble(ini, var, 0.5); + if (pgd_props->dist_tol < 0.0) + { + LOG_ERRMSG("Error distance tolerance %f cannot be negative", + pgd_props->dist_tol); + goto ERROR; + } + setVarName(group, "dist_default\0", var); + pgd_props->disp_def = iniparser_getdouble(ini, var, 0.01); + if (pgd_props->disp_def <= 0.0) + { + LOG_ERRMSG("Error PGD distance default %f must be positive", + pgd_props->disp_def); + goto ERROR; + } + setVarName(group, "deltaLatitude\0", var); + pgd_props->dLat + = iniparser_getdouble(ini, var, 0.1); + if (pgd_props->dLat < 0.0) + { + LOG_ERRMSG("Error PGD latitude serach %f must be positive", + pgd_props->dLat); + goto ERROR; + } + setVarName(group, "deltaLongitude\0", var); + pgd_props->dLon + = iniparser_getdouble(ini, var, 0.1); + if (pgd_props->dLon < 0.0) + { + LOG_ERRMSG("Error PGD longitudes %f must be positive", pgd_props->dLon); + goto ERROR; + } + setVarName(group, "nlats_in_pgd_gridSearch\0", var); + pgd_props->ngridSearch_lats + = iniparser_getint(ini, var, 1); + if (pgd_props->ngridSearch_lats < 1) + { + LOG_ERRMSG("Error PGD grid search depths %d must be positive", + pgd_props->ngridSearch_lats); + goto ERROR; + } + if (pgd_props->ngridSearch_lats%2 == 0) + { + LOG_WARNMSG("%s", "Adding 1 point to CMT lat gridsearch"); + pgd_props->ngridSearch_lats + = pgd_props->ngridSearch_lats + 1; + } + setVarName(group, "nlons_in_pgd_gridSearch\0", var); + pgd_props->ngridSearch_lons + = iniparser_getint(ini, var, 1); + if (pgd_props->ngridSearch_lons < 1) + { + LOG_ERRMSG("Error PGD grid search depths %d must be positive", + pgd_props->ngridSearch_lons); + goto ERROR; + } + if (pgd_props->ngridSearch_lons%2 == 0) + { + LOG_WARNMSG("%s", "Adding 1 point to CMT lat gridsearch"); + pgd_props->ngridSearch_lons + = pgd_props->ngridSearch_lons + 1; + } + setVarName(group, "ndepths_in_pgd_gridSearch\0", var); + pgd_props->ngridSearch_deps + = iniparser_getint(ini, var, 100); + if (pgd_props->ngridSearch_deps < 1) + { + LOG_ERRMSG("Error PGD grid search depths %d must be positive", + pgd_props->ngridSearch_deps); + goto ERROR; + } + setVarName(group, "pgd_window_vel\0", var); + pgd_props->window_vel = iniparser_getdouble(ini, var, 3.0); + if (pgd_props->window_vel <= 0.0) + { + LOG_ERRMSG("%s", "Error window velocity must be positive!"); + goto ERROR; + } + setVarName(group, "pgd_min_window_vel\0", var); + pgd_props->min_window_vel = iniparser_getdouble(ini, var, 0.01); + if (pgd_props->min_window_vel <= 0.0) + { + LOG_ERRMSG("%s", "Error min window velocity must be positive!"); + goto ERROR; + } + setVarName(group, "pgd_min_sites\0", var); + pgd_props->min_sites = iniparser_getint(ini, var, 4); + if (pgd_props->min_sites < 1) + { + LOG_ERRMSG("%s", "Error at least one site needed to estimate PGD!"); + goto ERROR; + } + setVarName(group, "pgdThresholdLookupFile\0", var); + const char *pgdThresholdLookupFile; + pgdThresholdLookupFile = iniparser_getstring(ini, var, "pgd_threshold.txt\0"); + ierr = core_scaling_readPgdThresholdLookupFile(pgdThresholdLookupFile, + pgd_props); + setVarName(group, "rawSigmaThresholdLookupFile\0", var); + const char *rawSigmaThresholdLookupFile; + rawSigmaThresholdLookupFile = iniparser_getstring(ini, var, "raw_sigma_threshold.txt\0"); + ierr = core_scaling_readRawSigmaThresholdLookupFile(rawSigmaThresholdLookupFile, + pgd_props); + setVarName(group, "sigmaLookupFile\0", var); + const char *sigmaLookupFile; + sigmaLookupFile = iniparser_getstring(ini, var, "M99.txt\0"); + ierr = core_scaling_readSigmaLookupFile(sigmaLookupFile, + pgd_props); + + + // only send XML for pgd magnitude sigma below this threshold + setVarName(group, "pgd_sigma_throttle\0", var); + pgd_props->pgd_sigma_throttle = iniparser_getdouble(ini, var, 10); + // props->pgd_sigma_throttle = iniparser_getdouble(ini, "general:pgd_sigma_throttle\0", 10); + if (pgd_props->pgd_sigma_throttle <= 0) + { + LOG_ERRMSG("Error pgd_sigma_throttle must be positive: %f", + pgd_props->pgd_sigma_throttle); + goto ERROR; + } + + // only send XML for SA magnitude above this threshold + setVarName(group, "SA_mag_threshold\0", var); + pgd_props->SA_mag_threshold = iniparser_getdouble(ini, var, -10.0); + // props->SA_mag_threshold = iniparser_getdouble(ini, "general:SA_mag_threshold\0", -10.0); + + setVarName(group, "minimum_pgd_cm\0", var); + pgd_props->minimum_pgd_cm = iniparser_getdouble(ini, var, -1.0); + setVarName(group, "maximum_pgd_cm\0", var); + pgd_props->maximum_pgd_cm = iniparser_getdouble(ini, var, 10000.); + if (pgd_props->maximum_pgd_cm < pgd_props->minimum_pgd_cm) + { + LOG_ERRMSG("Error maximum_pgd_cm %f must be greater than minimum_pgd_cm %f", + pgd_props->maximum_pgd_cm, pgd_props->minimum_pgd_cm); + goto ERROR; + } + setVarName(group, "max_assoc_stations\0", var); + pgd_props->max_assoc_stations = iniparser_getint(ini, var, 6); + if (pgd_props->max_assoc_stations < 0) + { + LOG_ERRMSG("%s", "Error max_assoc_stations must be positive!"); + goto ERROR; + } + + ERROR:; + iniparser_freedict(ini); + return ierr; +} diff --git a/src/core/scaling/pgd_sanityChecks.c b/src/core/scaling/pgd_sanityChecks.c new file mode 100644 index 00000000..dd98d06d --- /dev/null +++ b/src/core/scaling/pgd_sanityChecks.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include "gfast_core.h" + +void swap_floats(float *, float *); +void swap_ints(int *, int *); +//void selectionSort(float unsorted[], int n, int index[]); +void selectionSort(const double *__restrict__ unsorted, int n, int index[]); + +/*! + * @brief Does a sanity check on values going into inversion + * + * @param[in] n number of points + * @param[in] dist_tol distance tolerance - if d is less than this then + * it will be set to a default value (cm) + * @param[in] dist_def distance default value (cm) + * @param[in] repi epicentral distance (km) [n] + * @param[in] d max displacement (cm) at each site [n] + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_pgd_sanityChecks(const int n, + const double dist_tol, + const double dist_def, + const double *__restrict__ repi, + const double *__restrict__ d + ) +{ + double dist; + int i; + if (n < 1) + { + LOG_ERRMSG("Invalid number of points: %d", n); + return -1; + } + for (i=0; i +#include +#include +#include "gfast_core.h" +#include "iscl/array/array.h" +/*! + * @brief Sets the diagonal weighting matrix for the PGD scaling. + * The diagonal weight matrix terms are defined by + * \f[ W_i = w_i e^{ \left (-\frac{r_i^2}{8 r_{min}} \right ) } \f] + * where \f$ r_i\f$ is the epicentral distance and \f$ w_i \f$ the + * data weight. If \f$ w_i\f$ is not set it is assumed to be + * unity. + * + * @param[in] l1 number of observations + * @param[in] wts if not NULL then these are the data weights + * for each observation [l1] + * @param[in] repi this epicentral distance (km) for the i'th + * observation [l1] + * + * @param[out] W the diagonal weight matrix corresponding to + * each observation [l1] + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_pgd_setDiagonalWeightMatrix(const int l1, + const double *__restrict__ repi, + const double *__restrict__ wts, + double *__restrict__ W) +{ + double repi_min, repi_min2; + int i; + enum isclError_enum isclError; + if (l1 < 1) + { + LOG_ERRMSG("%s", "Error no observations"); + return -1; + } + if (W == NULL || repi == NULL) + { + if (repi == NULL){LOG_ERRMSG("%s", "Error repi is NULL");} + if (W == NULL){LOG_ERRMSG("%s", "Error W is NULL");} + return -1; + } + // Get the min epicentral distance + repi_min = array_min64f(l1, repi, &isclError); + repi_min2 = pow(repi_min, 2); + // Set standard weights + for (i=0; i +#include +#include +#include "gfast_core.h" +/*! + * @brief Sets the forward modeling matrix G s.t. + * \f$ G = \left [ B + C \log_{10}(r) \right ] \f$ + * where B and C are scalar shifts and scale factors respectively + * and r the hypocentral distances for all stations. + * + * @param[in] n length of r and G (> 0) + * @param[in] B linear shift in G = B + C*log10(r) + * @param[in] C scale factor in G = B + C*log10(r) + * @param[in] r hypocentral distances (km) [n] + * + * @param[out] G forward modeling matrix for PGD [n x 1]. Note that + * G is in column major format. + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_pgd_setForwardModel(const int n, + const double B, const double C, + const double *__restrict__ r, + double *__restrict__ G) +{ + int i; + if (n < 1 || r == NULL || G == NULL) + { + if (n < 1){LOG_ERRMSG("Invalid number of points: %d\n", n);} + if (r == NULL){LOG_ERRMSG("%s", "Error r is NULL");} + if (G == NULL){LOG_ERRMSG("%s", "Error G is NULL");} + return -1; + } + for (i=0; i +#include +#include +#include "gfast_core.h" + +/*! + * @brief Computes the right hand side in the peak ground displacement + * estimation s.t. + * \f$ \textbf{b} = \left \{ \log_{10}(d) - A \right \} \f$ + * where A is a scalar shift and d is the distance at each station. + * + * @param[in] n number of points + * @param[in] dist_tol distance tolerance - if d is less than this then + * it will be set to a default value (cm) + * @param[in] dist_def distance default value (cm) + * @param[in] A shift so that b = log10(d) - A + * @param[in] d max distance (cm) at each site [n] + * + * @param[out] b right hand side in Gm = b [n] + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_pgd_setRHS(const int n, + const double dist_tol, + const double dist_def, + const double A, + const double *__restrict__ d, + double *__restrict__ b) +{ + double dist; + int i; + if (n < 1) + { + LOG_ERRMSG("Invalid number of points: %d", n); + return -1; + } + for (i=0; i +#include +#include "gfast_core.h" +#include "iscl/array/array.h" +/*! + * @brief Applies the diagonal data weight matrix to the forward modeling + * matrix. In the case of PGD scaling the forward modeling matrix + * is a column vector. + * + * @param[in] l1 number of observations + * @param[in] W diagonal matrix of data weights [l1] + * @param[in] G forward modeling matrix [l1] + * + * @param[out] WG weighted observations such that + * \f$ \tilde{G} = diag \{W\} G \f$ [l1] + * + * @result -1 indicates an error + * 0 indicates success + * 1 indicates that W is NULL and it is assumed that W + * is identity + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_pgd_weightForwardModel(const int l1, + const double *__restrict__ W, + const double *__restrict__ G, + double *__restrict__ WG) +{ + int i; + if (l1 < 1) + { + LOG_ERRMSG("Error no observations %d", l1); + return -1; + } + if (G == NULL || WG == NULL) + { + if (G == NULL){LOG_ERRMSG("%s", "Error G is NULL");} + if (WG == NULL){LOG_ERRMSG("%s", "Error WG is NULL");} + return -1; + } + // Don't break anything if the weights are NULL + if (W == NULL) + { + LOG_WARNMSG("%s", "Warning W is NULL - assuming identity"); + array_copy64f_work(l1, G, WG); + return 1; + } +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include "gfast_core.h" +#include "iscl/array/array.h" +/*! + * @brief Applies the diagonal data weight matrix to the observations. + * + * @param[in] l1 Number of observations. + * @param[in] W Diagonal matrix of data weights. This is an + * array of dimension [l1]. + * @param[in] b Observations. This is an array of dimension [l1]. + * + * @param[out] Wb Weighted observations such that + * \f$ \tilde{b} = diag \{W\} b \f$. + * This is an array of dimension [l1]. + * + * @retval -1 -> indicates an error. + * @retval 0 -> indicates success. + * @retval 1 -> indicates that W is NULL and it is assumed that W + * is identity. + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_pgd_weightObservations(const int l1, + const double *__restrict__ W, + const double *__restrict__ b, + double *__restrict__ Wb) +{ + int i; + if (l1 < 1) + { + LOG_ERRMSG("Error no observations %d", l1); + return -1; + } + if (b == NULL || Wb == NULL) + { + if (b == NULL){LOG_ERRMSG("%s", "Error b is NULL");} + if (Wb == NULL){LOG_ERRMSG("%s", "Error Wb is NULL");} + return -1; + } + // Don't break anything if the weights are NULL + if (W == NULL) + { + LOG_WARNMSG("%s", "Warning W is NULL - assuming identity"); + array_copy64f_work(l1, b, Wb); + return 1; + } +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include "gfast_core.h" +#include "iscl/os/os.h" + +/*! + * @brief Reads the pgd threshold file + * + * @param[in] pgdThresholdLookupFile name of the lookup file + * + * @param[in,out] pgd_props On input contains the pgd props struct, with the + * lookup values unfilled + * On output, the lookup values have been filled + * + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_readPgdThresholdLookupFile(const char *pgdThresholdLookupFile, + struct GFAST_pgd_props_struct *pgd_props) { + // Read in file and set sigma lookup values + FILE *infl; + char cline[1024]; + int nlines, i; + // There should be 3 values per line + double a0, a1; + int a2; + + pgd_props->n_throttle = 0; + nlines = 0; + + if (!os_path_isfile(pgdThresholdLookupFile)){ + LOG_WARNMSG("%s does not exist, using 0 pgd threshold values", + pgdThresholdLookupFile); + return 0; + } + + infl = fopen(pgdThresholdLookupFile, "r"); + if (!infl) { + LOG_ERRMSG("ERROR! Cannot open %s\n", pgdThresholdLookupFile); + return -1; + } + + // Count number of lines + while (fgets(cline, 1024, infl) != NULL) { + nlines = nlines + 1; + } + + if (nlines < 1) { + LOG_WARNMSG("No values in pgdThresholdLookupFile: %s", pgdThresholdLookupFile); + fclose(infl); + return 0; + } + + if (nlines > MAX_THROTTLING_THRESHOLDS) { + LOG_WARNMSG("nlines=%d in %s is greater than MAX_THROTTLING_THRESHOLDS! Setting to %d\n", + nlines, pgdThresholdLookupFile, MAX_THROTTLING_THRESHOLDS); + nlines = MAX_THROTTLING_THRESHOLDS; + } + + // Actually read and parse the lines this time + rewind(infl); + for (i = 0; i < nlines; i++) { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, 1024, infl) == NULL) + { + LOG_ERRMSG("Premature end of file %s", pgdThresholdLookupFile); + return -1; + } + if (cline[strlen(cline)-1] == '\n') + { + cline[strlen(cline)-1] = '\0'; + } + // There should be 3 values per line + if (sscanf(cline, "%lf %lf %d", + &a0, &a1, &a2) != 3) { + LOG_ERRMSG("Invalid data in %s line %d: %s\n", pgdThresholdLookupFile, i, cline); + fclose(infl); + return -1; + } + pgd_props->throttle_time_threshold[i] = a0; + pgd_props->throttle_pgd_threshold[i] = a1; + pgd_props->throttle_num_stations[i] = a2; + } + pgd_props->n_throttle = nlines; + + fclose(infl); + return 0; +} + + +// int throttle_num_stations[MAX_THROTTLING_THRESHOLDS]; /*!< Threshold number of stations to send a message */ +// double throttle_pgd_threshold[MAX_THROTTLING_THRESHOLDS]; /*!< Threshold pgd value (cm) */ +// double throttle_time_threshold[MAX_THROTTLING_THRESHOLDS]; /*!< Threshold time value (s) */ +// int n_throttle; /*!< number of throttle criteria. num_stations, pgd_threshold, +// time_threshold should be the same length */ \ No newline at end of file diff --git a/src/core/scaling/readRawSigmaThresholdLookupFile.c b/src/core/scaling/readRawSigmaThresholdLookupFile.c new file mode 100644 index 00000000..37ba2486 --- /dev/null +++ b/src/core/scaling/readRawSigmaThresholdLookupFile.c @@ -0,0 +1,87 @@ +#include +#include +#include "gfast_core.h" +#include "iscl/os/os.h" + +/*! + * @brief Reads the raw sigma threshold file + * + * @param[in] rawSigmaThresholdLookupFile name of the lookup file + * + * @param[in,out] pgd_props On input contains the pgd props struct, with the + * lookup values unfilled + * On output, the lookup values have been filled + * + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_readRawSigmaThresholdLookupFile(const char *rawSigmaThresholdLookupFile, + struct GFAST_pgd_props_struct *pgd_props) { + // Read in file and set sigma lookup values + FILE *infl; + char cline[1024]; + int nlines, i; + // There should be 3 values in one line: usigma, nsigma, esigma + double usigma, nsigma, esigma; + + // Initialize to -1, which means they won't be used + pgd_props->u_raw_sigma_threshold = -1; + pgd_props->n_raw_sigma_threshold = -1; + pgd_props->e_raw_sigma_threshold = -1; + nlines = 0; + + if (!os_path_isfile(rawSigmaThresholdLookupFile)){ + LOG_WARNMSG("%s does not exist, will ignore raw sigmas in pd calculations!", + rawSigmaThresholdLookupFile); + return 0; + } + + infl = fopen(rawSigmaThresholdLookupFile, "r"); + if (!infl) { + LOG_ERRMSG("ERROR! Cannot open %s\n", rawSigmaThresholdLookupFile); + return -1; + } + + // Count number of lines + while (fgets(cline, 1024, infl) != NULL) { + nlines = nlines + 1; + } + + if (nlines != 1) { + LOG_ERRMSG("rawSigmaThresholdLookupFile %s requires 1 line, has %d", + rawSigmaThresholdLookupFile, nlines); + fclose(infl); + return -1; + } + + // Actually read and parse the lines this time + rewind(infl); + for (i = 0; i < nlines; i++) { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, 1024, infl) == NULL) + { + LOG_ERRMSG("Premature end of file %s", rawSigmaThresholdLookupFile); + return -1; + } + if (cline[strlen(cline)-1] == '\n') + { + cline[strlen(cline)-1] = '\0'; + } + // There should be 3 values in the line + if (sscanf(cline, "%lf %lf %lf", + &usigma, &nsigma, &esigma) != 3) { + LOG_ERRMSG("Invalid data in %s line %d: %s\n", rawSigmaThresholdLookupFile, i, cline); + fclose(infl); + return -1; + } + pgd_props->u_raw_sigma_threshold = usigma; + pgd_props->n_raw_sigma_threshold = nsigma; + pgd_props->e_raw_sigma_threshold = esigma; + } + + fclose(infl); + return 0; +} diff --git a/src/core/scaling/readSigmaLookupFile.c b/src/core/scaling/readSigmaLookupFile.c new file mode 100644 index 00000000..dc4b8e08 --- /dev/null +++ b/src/core/scaling/readSigmaLookupFile.c @@ -0,0 +1,88 @@ +#include +#include +#include "gfast_core.h" +#include "iscl/os/os.h" + +/*! + * @brief Reads the sigma lookup table + * + * @param[in] sigmaLookupFile name of the lookup file + * + * @param[in,out] pgd_props On input contains the pgd props struct, with the + * lookup values unfilled + * On output, the lookup values have been filled + * + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int core_scaling_readSigmaLookupFile(const char *sigmaLookupFile, + struct GFAST_pgd_props_struct *pgd_props) { + // Read in file and set sigma lookup values + FILE *infl; + char cline[1024]; + int nlines, i; + // There should be 8 values per line, we only need the first and last + double a0, a1, a2, a3, a4, a5, a6, a7; + + pgd_props->n99 = 0; + nlines = 0; + + if (!os_path_isfile(sigmaLookupFile)){ + LOG_WARNMSG("%s does not exist, using 0 sigma values", sigmaLookupFile); + return 0; + } + + infl = fopen(sigmaLookupFile, "r"); + if (!infl) { + LOG_ERRMSG("ERROR! Cannot open %s\n", sigmaLookupFile); + return -1; + } + + // Count number of lines + while (fgets(cline, 1024, infl) != NULL) { + nlines = nlines + 1; + } + + if (nlines < 1) { + LOG_WARNMSG("No values in sigmaLookupFile: %s", sigmaLookupFile); + fclose(infl); + return 0; + } + + if (nlines > MAX_SIGMA_LOOKUP_VALUES) { + LOG_WARNMSG("nlines=%d in %s is greater than MAX_SIGMA_LOOKUP_VALUES! Setting to %d\n", + nlines, sigmaLookupFile, MAX_SIGMA_LOOKUP_VALUES); + nlines = MAX_SIGMA_LOOKUP_VALUES; + } + + // Actually read and parse the lines this time + rewind(infl); + for (i = 0; i < nlines; i++) { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, 1024, infl) == NULL) + { + LOG_ERRMSG("Premature end of file %s", sigmaLookupFile); + return -1; + } + if (cline[strlen(cline)-1] == '\n') + { + cline[strlen(cline)-1] = '\0'; + } + // There should be 8 values per line + if (sscanf(cline, "%lf %lf %lf %lf %lf %lf %lf %lf", + &a0, &a1, &a2, &a3, &a4, &a5, &a6, &a7) != 8) { + LOG_ERRMSG("Invalid data in %s line %d: %s\n", sigmaLookupFile, i, cline); + fclose(infl); + return -1; + } + pgd_props->t99[i] = a0; + pgd_props->m99[i] = a7; + } + pgd_props->n99 = nlines; + + fclose(infl); + return 0; +} \ No newline at end of file diff --git a/src/core/waveformProcessor/Makefile b/src/core/waveformProcessor/Makefile new file mode 100644 index 00000000..9a76850c --- /dev/null +++ b/src/core/waveformProcessor/Makefile @@ -0,0 +1,64 @@ +# Makefile for GFAST/src/core/waveformProcessor +# + +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = offset.o peakDisplacement.o peakDisplacementHelper.o + +DEBUG = -g +CCFLAGS += -O0 -D_REENTRANT -Dstatic_config + +INCL = -I ../../../include + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(CC) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/core/waveformProcessor/offset.c b/src/core/waveformProcessor/offset.c new file mode 100644 index 00000000..1420805d --- /dev/null +++ b/src/core/waveformProcessor/offset.c @@ -0,0 +1,311 @@ +#include +#include +#include +#include +#include "gfast_core.h" + +#ifndef MAX +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#endif +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + +static bool __getAverageOffset(const int npts, + const double dt, + const double ev_time, + const double swave_time, + const double epoch, + const double *__restrict__ ubuff, + const double *__restrict__ nbuff, + const double *__restrict__ ebuff, + double *uOffset, + double *nOffset, + double *eOffset); + +/*! + * @brief Estimates the average offset for each GPS precise point positiion + * data stream with the additional requirement that the shear wave + * has passed through through the site. + * + * @note To perform the averaging it is presumed the shear wave has passed + * through the station then the average offset is estimated from + * data beginning at the shear wave arrival and ending at the last + * sample seen at the station. The approximate shear wave arrival + * time is estimated by presuming a shear wave velocity (svel_window, + * \f$ v_{s} \f$) and an origin time \f$ t_{0} \f$ then computing the + * source receiver distance \f$ d_{s,r} \f$ and applying + * \f$ t_{s} = t_0 + \frac{ d_{s,r} }{ v_{s} } \f$. + * Because the inversion is for static offsets a conservative + * strategy to avoid modeling the dynamic response is to lower + * the shear velocity. + * + * + * @param[in] utm_zone if not -12345 then this is the desired UTM zone + * in which to compute source and receiver + * positions. + * otherwise, the UTM zone will be estimated from + * the source location + * @param[in] svel_window the shear wave velocity used in data windowing + * (km/s). if the the site/source distance is + * less than + * (current_time - ev_time)*svel_window + * then the site will be excluded + * @param[in] ev_lat source hypocentral latitude (degrees) [-90,90] + * @param[in] ev_lon source hypocentral longitude (degrees) [0,360] + * @param[in] ev_dep source hypocentral depth (km) (this is positive + * down from the free surface) + * @param[in] ev_time source origin time in seconds since epoch (UTC) + * @param[in] gps_data contains the most up-to-date precise point + * positions for each site + * + * @param[in,out] offset_data on input holds a logical mask if a site is to + * be ignored. + * on output holds the average offset at each + * site satisfying the S velocity window mask. + * in this case, all sites with data are given + * data weights of unity and all sites without + * data are given weights of zero. + * + * @param[out] ierr 0 indicates success + * + * @result the number of sites at which peak displacement was computed + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @date May 2016 + * + */ +int core_waveformProcessor_offset(const int utm_zone, + const double svel_window, + const double ev_lat, + const double ev_lon, + const double ev_dep, + const double ev_time, + struct GFAST_data_struct gps_data, + struct GFAST_offsetData_struct *offset_data, + int *ierr) +{ + double currentTime, distance, effectiveHypoDist, eOffset, epoch, nOffset, + swave_time, uOffset, x1, x2, y1, y2; + int k, nsites, zone_loc; + bool lnorthp, luse; + //------------------------------------------------------------------------// + // + // Error handling + *ierr = 0; + nsites = 0; + if (offset_data->ubuff == NULL || offset_data->nbuff == NULL || + offset_data->ebuff == NULL || offset_data->wtu == NULL || + offset_data->wtn == NULL || offset_data->wte == NULL || + offset_data->lactive == NULL) + { + LOG_ERRMSG("%s", "Error offset_data pointers not initialized"); + return -1; + } + if (gps_data.stream_length != offset_data->nsites) + { + LOG_ERRMSG("Inconsistent structure sizes %d %d\n", + gps_data.stream_length, offset_data->nsites); + *ierr = 1; + // For safety cut the inversion off at the knees + if (offset_data->nsites > 0) + { + for (k=0; knsites; k++) + { + offset_data->ubuff[k] = 0.0; + offset_data->nbuff[k] = 0.0; + offset_data->ebuff[k] = 0.0; + offset_data->wtu[k] = 0.0; + offset_data->wtn[k] = 0.0; + offset_data->wte[k] = 0.0; + offset_data->lactive[k] = false; + } + } + return nsites; + } + // Get the source location + zone_loc = utm_zone; + if (zone_loc ==-12345){zone_loc =-1;} // Get UTM zone from source lat/lon + GFAST_core_coordtools_ll2utm(ev_lat, ev_lon, + &y1, &x1, + &lnorthp, &zone_loc); + // Loop on streams and if they satisfy the S wave mask get their offsets + for (k=0; ksta_lat[k] = gps_data.data[k].sta_lat; + offset_data->sta_lon[k] = gps_data.data[k].sta_lon; + offset_data->sta_alt[k] = gps_data.data[k].sta_alt; + // Null out result + offset_data->ubuff[k] = 0.0; // Null out result + offset_data->nbuff[k] = 0.0; + offset_data->ebuff[k] = 0.0; + offset_data->wtu[k] = 0.0; // Assume no weight + offset_data->wtn[k] = 0.0; + offset_data->wte[k] = 0.0; + offset_data->lactive[k] = false; + if (offset_data->lmask[k]){continue;} + //if (gps_data.data[k].lskip_cmt){continue;} // Not in inversion + // Get the recevier UTM + GFAST_core_coordtools_ll2utm(gps_data.data[k].sta_lat, + gps_data.data[k].sta_lon, + &y2, &x2, + &lnorthp, &zone_loc); + // Get the distance - remember source is + down and receiver is + up + distance = sqrt( pow(x1 - x2, 2) + + pow(y1 - y2, 2) + + pow(ev_dep*1000.0 + gps_data.data[k].sta_alt, 2)); + distance = distance*1.e-3; // convert to km + // Apply an S wave window mask to preclude likely outliers in the + // ensuing CMT/finite fault inversions + epoch = gps_data.data[k].tbuff[0]; //gps_data.data[k].epoch + currentTime = epoch + + (gps_data.data[k].npts - 1)*gps_data.data[k].dt; + effectiveHypoDist = (currentTime - ev_time)*svel_window; + if (distance < effectiveHypoDist) + { + swave_time = ev_time + distance/svel_window; + // Compute the average offset beginning after the S wave mask + luse = __getAverageOffset(gps_data.data[k].npts, + gps_data.data[k].dt, + ev_time, + swave_time, + epoch, + gps_data.data[k].ubuff, + gps_data.data[k].nbuff, + gps_data.data[k].ebuff, + &uOffset, + &nOffset, + &eOffset); + // Only use average offset if it isn't all NaN's + if (luse) + { + offset_data->ubuff[k] = uOffset; // meters + offset_data->nbuff[k] = nOffset; + offset_data->ebuff[k] = eOffset; + offset_data->wtu[k] = 1.0; + offset_data->wtn[k] = 1.0; + offset_data->wte[k] = 1.0; + offset_data->lactive[k] = true; + nsites = nsites + 1; + } // End check on whether or not to use average offset + } // End check on S-wave mask + } // Loop on data streams + return nsites; +} +//============================================================================// +/*! + * @brief Computes the average offset on all components beginning at the + * S wave time and running to the end of the observed + * + * @param[in] npts number of points in time series + * @param[in] dt sampling period (s) of time series + * @param[in] ev_time epoch (s) of origin time (UTC) + * @param[in] swave_time epoch (s) of s wave arrival (UTC) + * @param[in] epoch epoch (s) of trace start time (UTC) + * @param[in] ubuff vertical precise point position data [npts] + * @param[in] nbuff north precise point position data [npts] + * @param[in] ebuff east precise point position data [npts] + * + * @param[out] uOffset offset in vertical position + * @param[out] nOffset offset in north position + * @param[out] eOffset offset in east position + * + * @result if true then uOffset, nOffset, and eOffset are not NaN's and can + * be used in the inversion + * + * @author Ben Baker (ISTI) + * + */ +static bool __getAverageOffset(const int npts, + const double dt, + const double ev_time, + const double swave_time, + const double epoch, + const double *__restrict__ ubuff, + const double *__restrict__ nbuff, + const double *__restrict__ ebuff, + double *uOffset, + double *nOffset, + double *eOffset) +{ + double diffT, de, dn, du, e0, n0, u0, eOffsetNan, nOffsetNan, uOffsetNan; + int i, iavg, iavg1, indx0; + bool luse; + //------------------------------------------------------------------------// + // + // Initialize result + *uOffset = (double) NAN; + *nOffset = (double) NAN; + *eOffset = (double) NAN; + luse = false; + // This is a bad input + if (ev_time > swave_time) + { + LOG_ERRMSG("%s", "event origin time exceeds S wave arrival"); + return luse; + } + // This might compromise the offset + if (epoch > ev_time) + { + LOG_WARNMSG("%s", + "Warning trace start-time is after event origint time"); + } + // Set the initial position + u0 = 0.0; + n0 = 0.0; + e0 = 0.0; + // Estimate the origin time index + diffT = ev_time - epoch; + if (diffT < 0.0){return luse;} // This will be a disaster + indx0 = MAX(0, (int) (diffT/dt + 0.5)); + indx0 = MIN(npts-1, indx0); + u0 = ubuff[indx0]; + n0 = nbuff[indx0]; + e0 = ebuff[indx0]; + // Prevent a nonsensical difference + if (isnan(u0) || isnan(n0) || isnan(e0)){return luse;} + // Estimate the S wave arrival time index + diffT = swave_time - epoch; + if (diffT < 0.0){return luse;} + indx0 = MAX(0, (int) (diffT/dt + 0.5)); + indx0 = MIN(npts-1, indx0); + // Compute the average from the S wave arrival to the end of the data + uOffsetNan = 0.0; + nOffsetNan = 0.0; + eOffsetNan = 0.0; + iavg = 0; + // Compute the average over the window + for (i=indx0; i-999.0 && nbuff[i] >-999.0 && ebuff[i] >-999.0) + if (!isnan(ubuff[i]) && !isnan(nbuff[i]) && !isnan(ebuff[i])) + { + luse = true; + } + if (luse){du = ubuff[i] - u0;} + if (luse){dn = nbuff[i] - n0;} + if (luse){de = ebuff[i] - e0;} + if (luse){iavg1 = 1;} + uOffsetNan = uOffsetNan + du; + nOffsetNan = nOffsetNan + dn; + eOffsetNan = eOffsetNan + de; + iavg = iavg + iavg1; + } // Loop on data points + // There's data - average it and use this result + if (iavg > 0) + { + *uOffset = uOffsetNan/(double) iavg; + *nOffset = nOffsetNan/(double) iavg; + *eOffset = eOffsetNan/(double) iavg; + luse = true; + } + return luse; +} diff --git a/src/core/waveformProcessor/peakDisplacement.c b/src/core/waveformProcessor/peakDisplacement.c new file mode 100644 index 00000000..4fdfc54e --- /dev/null +++ b/src/core/waveformProcessor/peakDisplacement.c @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include "gfast_core.h" + +/*! + * @brief Computes the peak displacement for each GPS precise point position + * data stream with the additional requirement that the shear wave + * has passed through the site. + * + * @param[in] pgd_props PGD properties, including utm_zone, window_vel, min_window_vel, + * minimum_pgd_cm, maximum_pgd_cm, [une]_raw_sigma_threshold + * @param[in] ev_lat source hypocentral latitude (degrees) [-90,90] + * @param[in] ev_lon source hypocentral longitude (degrees) [0,360] + * @param[in] ev_dep source hypocentral depth (km) (this is positive + * down from the free surface) + * @param[in] ev_time source origin time in seconds since epoch (UTC) + * @param[in] gps_data contains the most up-to-date precise point + * positions for each site + * + * @param[in,out] pgd_data on input holds a logical mask if a site is to + * be ignored. + * on output holds the peak ground displacement + * at each site satisfying the S velocity window mask. + * in this instance all sites with data are given + * data weights of unity and all sites without + * data are given data weights of zero. + * + * @param[out] ierr 0 indicates success + * + * @result the number of sites at which peak displacement was computed + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +int core_waveformProcessor_peakDisplacement( + const struct GFAST_pgd_props_struct *pgd_props, + const double ev_lat, + const double ev_lon, + const double ev_dep, + const double ev_time, + struct GFAST_data_struct gps_data, + struct GFAST_peakDisplacementData_struct *pgd_data, + int *ierr) +{ + double currentTime, distance, effectiveHypoDist, epoch, + peakDisp, x1, x2, y1, y2, tmin, tmax, obsTime, + uMaxUncertainty, nMaxUncertainty, eMaxUncertainty; + int k, nsites, zone_loc; + //unused int i; + bool lnorthp; + bool lnorthp_event; + bool l_use_observation; + + double s_arr_time; + int nMaxLeader; + + // Values from properties file + + // If not -12345 then this is the desired UTM zone in which to compute source and receiver positions. + // Otherwise, the UTM zone will be estimated from the source location + const int utm_zone = pgd_props->utm_zone; + // The shear wave velocity used in data windowing (km/s). + // If the site/source distance is less than (current_time - ev_time)*svel_window + // then the site will be excluded + const double svel_window = pgd_props->window_vel; + // The *minimum* shear wave velocity (km/s) used in data windowing + const double min_svel_window = pgd_props->min_window_vel; + // The *minimum* pgd value (cm) to pass on to inversion. Ignore others + const double min_pgd_cm = pgd_props->minimum_pgd_cm; + // The *maximum* pgd value (cm) to pass on to inversion. Ignore others + const double max_pgd_cm = pgd_props->maximum_pgd_cm; + // Threshold values for raw positional uncertainties (cm). If observed + // peak sigma is greater than threshold, ignore the associated pd + // observation. If sigma_threshold is < 0, allow any sigma. + const double u_raw_sigma_threshold = pgd_props->u_raw_sigma_threshold; + const double n_raw_sigma_threshold = pgd_props->n_raw_sigma_threshold; + const double e_raw_sigma_threshold = pgd_props->e_raw_sigma_threshold; + + //------------------------------------------------------------------------// + // + // Error handling + *ierr = 0; + nsites = 0; + obsTime = 0.0; + uMaxUncertainty = 0.0; + eMaxUncertainty = 0.0; + nMaxUncertainty = 0.0; + if (gps_data.stream_length != pgd_data->nsites) + { + LOG_ERRMSG("Inconsistent structure sizes %d %d", + gps_data.stream_length, pgd_data->nsites); + *ierr = 1; + // For safety cut the inversion off at the knees + if (pgd_data->nsites > 0) + { + for (k=0; knsites; k++) + { + pgd_data->pd[k] = 0.0; + pgd_data->wt[k] = 0.0; + pgd_data->lactive[k] = false; + } + } + return nsites; + } + // Get the source location + zone_loc = utm_zone; + if (zone_loc ==-12345){zone_loc =-1;} // Get UTM zone from source lat/lon + GFAST_core_coordtools_ll2utm(ev_lat, ev_lon, + &y1, &x1, + &lnorthp_event, &zone_loc); +//LOG_MSG("peakDisp: utm_zone=%d ev_lat:%f ev_lon:%f x1:%f y1:%f\n", + //utm_zone, ev_lat, ev_lon, x1, y1); + // Loop on streams and if they satisfy the S wave mask get their PGD + for (k=0; ksta_lat[k] = gps_data.data[k].sta_lat; + pgd_data->sta_lon[k] = gps_data.data[k].sta_lon; + pgd_data->sta_alt[k] = gps_data.data[k].sta_alt; + // Null out result + pgd_data->pd_time[k] = obsTime; // Null out result + pgd_data->pd[k] = 0.0; // Null out result + pgd_data->wt[k] = 0.0; // Assume no weight + pgd_data->lactive[k] = false; // Assume site is not active in inversion + if (pgd_data->lmask[k]){continue;} // Not in inversion + // Get the recevier UTM + GFAST_core_coordtools_ll2utm(gps_data.data[k].sta_lat, + gps_data.data[k].sta_lon, + &y2, &x2, + &lnorthp, &zone_loc); + // Get the distance - remember source is + down and receiver is + up + distance = sqrt( pow(x1 - x2, 2) + + pow(y1 - y2, 2) + + pow(ev_dep*1000.0 + gps_data.data[k].sta_alt, 2)); + distance = distance*1.e-3; // convert to km + if (lnorthp != lnorthp_event) { + /* + LOG_MSG("Ignore: %s.%s.%s.%s lnorthp=%d != lnorthp_event=%d", + gps_data.data[k].stnm, gps_data.data[k].chan[0], + gps_data.data[k].netw, gps_data.data[k].loc, + lnorthp, lnorthp_event); + */ + + distance = 99999; // Don't use this station + } + + // Apply an S wave window mask to preclude likely outliers in + // the ensuing PGD inversion + epoch = gps_data.data[k].tbuff[0]; //gps_data.data[k].epoch; + currentTime = epoch + + (gps_data.data[k].npts - 1)*gps_data.data[k].dt; + effectiveHypoDist = (currentTime - ev_time)*svel_window; + + // MTH: I want to open up the props.processingTime so that it will still + // process a delayed PDL event, but I don't want to include stations + // that are >> from epicenter. This seems to be a solution: + if (effectiveHypoDist > 1000.){ + effectiveHypoDist = 1000.; // Don't include stations > 1000 km + } + + // MTH: Right now gps_data[k].tbuff[0] has previously been set = ev_time + // So if for some reason n/e/ubuff[0] = nan at ev_time, + // then all subsequent PGD displacement measurements are fixed to nan. + // Let's calc where in the buff the S wave arrives and allow u0/n0/e0 + // up to this point + s_arr_time = distance / svel_window - 2.0; + + nMaxLeader = (int)(ev_time + s_arr_time - gps_data.data[k].tbuff[0])/gps_data.data[k].dt; + + /* + LOG_MSG("currentTime:%f epoch:%f effHypoDst:%.1f -vs- dist:%.1f %s.%s.%s.%s", + currentTime, epoch, effectiveHypoDist, distance, + gps_data.data[k].stnm, gps_data.data[k].chan[0], + gps_data.data[k].netw, gps_data.data[k].loc); + */ + + //if (distance < effectiveHypoDist) + if (distance < effectiveHypoDist) + { + // Compute the peak displacement max(norm(u + n + e, 2)) + tmin = distance / svel_window; + tmax = distance / min_svel_window; + //printf("Call __getPeakDisplacement dist:%.2f tmin:%.2f tmax:%.2f\n", distance, tmin, tmax); + peakDisp = core_waveformProcessor_peakDisplacementHelper( + gps_data.data[k].npts, + gps_data.data[k].dt, + ev_time, + epoch, + gps_data.data[k].ubuff, + gps_data.data[k].nbuff, + gps_data.data[k].ebuff, + gps_data.data[k].usigmabuff, + gps_data.data[k].nsigmabuff, + gps_data.data[k].esigmabuff, + nMaxLeader, + tmin, + tmax, + &obsTime, + &uMaxUncertainty, + &nMaxUncertainty, + &eMaxUncertainty); + + /* +The Crowell et al. [2016] coefficients are +log10(PGD) = A + B*M + C*M*log10(distance) +A = -6.687 +B = 1.500 +C = -0.214 +M 9 at 100km: -6.687 + 150 - 21.4*2 = 100 cm(?) + */ +/* + float mag; + float logPD; + + mag = 7.8; + logPD = -6.687 + 1.5*mag - 0.214*mag*log10(distance); + peakDisp = pow(10., logPD); + peakDisp /= 100; // Pretty sure gfast wants peakDisp in meters +*/ + + // At this point, use observation unless proven guilty + l_use_observation = true; + // Do we have a real observation? + if (isnan(peakDisp)) + { + l_use_observation = false; + LOG_MSG("currentTime:%f %s.%s.%s.%s Got peakDisp = nan ubuf=%f nbuf=%f ebuf=%f", + currentTime, + gps_data.data[k].stnm, gps_data.data[k].chan[0], + gps_data.data[k].netw, gps_data.data[k].loc, + gps_data.data[k].ubuff[gps_data.data[k].npts-1], + gps_data.data[k].nbuff[gps_data.data[k].npts-1], + gps_data.data[k].ebuff[gps_data.data[k].npts-1]); + } + else + { + LOG_MSG("%s.%s.%s.%s peakDisp=%f dist=%.2f, peakSigmas=(%.4f,%.4f,%.4f)", + gps_data.data[k].stnm, gps_data.data[k].chan[0], + gps_data.data[k].netw, gps_data.data[k].loc, + peakDisp, + distance, + uMaxUncertainty, + nMaxUncertainty, + eMaxUncertainty); + } + + // Is the observation above the defined minimum? + if (peakDisp * 100 <= min_pgd_cm) + { + l_use_observation = false; + LOG_MSG("currentTime:%f %s.%s.%s.%s Ignoring pgd, %f cm <= min_pgd_cm %f", + currentTime, + gps_data.data[k].stnm, gps_data.data[k].chan[0], + gps_data.data[k].netw, gps_data.data[k].loc, + peakDisp * 100, min_pgd_cm); + } + + // Is the observation below the defined maximum? + if (peakDisp * 100 >= max_pgd_cm) + { + l_use_observation = false; + LOG_MSG("currentTime:%f %s.%s.%s.%s Ignoring pgd, %f cm >= min_pgd_cm %f", + currentTime, + gps_data.data[k].stnm, gps_data.data[k].chan[0], + gps_data.data[k].netw, gps_data.data[k].loc, + peakDisp * 100, max_pgd_cm); + } + + // Is the observation within the uncertainty bounds? + // const double u_raw_sigma_threshold = 35; // cm + // const double n_raw_sigma_threshold = 17; // cm + // const double e_raw_sigma_threshold = 14; // cm + if (((u_raw_sigma_threshold > 0) && (uMaxUncertainty * 100 >= u_raw_sigma_threshold)) || + ((n_raw_sigma_threshold > 0) && (nMaxUncertainty * 100 >= n_raw_sigma_threshold)) || + ((e_raw_sigma_threshold > 0) && (eMaxUncertainty * 100 >= e_raw_sigma_threshold))) + { + l_use_observation = false; + LOG_DEBUGMSG("CCC PeakDisp, %s.%s.%s.%s ignoring observation, ZNE sigmas: (%.1f,%.1f,%.1f), thresholds: (%.1f,%.1f,%.1f) cm", + gps_data.data[k].stnm, gps_data.data[k].chan[0], + gps_data.data[k].netw, gps_data.data[k].loc, + uMaxUncertainty * 100, + nMaxUncertainty * 100, + eMaxUncertainty * 100, + u_raw_sigma_threshold, + n_raw_sigma_threshold, + e_raw_sigma_threshold + ); + } + + // If it isn't a NaN and within the sanity bounds then retain it for processing + if (l_use_observation) { + pgd_data->pd_time[k] = obsTime; // epoch + pgd_data->pd[k] = peakDisp; // meters + pgd_data->wt[k] = 1.0; + pgd_data->lactive[k] = true; + nsites = nsites + 1; + } + } // End check on S-wave mask + } // Loop on data streams + return nsites; +} diff --git a/src/core/waveformProcessor/peakDisplacementHelper.c b/src/core/waveformProcessor/peakDisplacementHelper.c new file mode 100644 index 00000000..d8b88134 --- /dev/null +++ b/src/core/waveformProcessor/peakDisplacementHelper.c @@ -0,0 +1,179 @@ +#include +#include +#include "gfast_core.h" + +#define PD_MAX_NAN -DBL_MAX +#ifndef MAX +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#endif +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif + +//============================================================================// +/*! + * @brief Waveform processor to estimate the peak displacement observed + * on a 3 channel GPS stream where the peak displacement at any + * sample is Euclidean norm of it's displacement. + * + * @param[in] npts number of points in time series + * @param[in] dt sampling period (s) of GPS buffers + * @param[in] ev_time epochal UTC origin time (s) + * @param[in] epoch epochal UTC start time (s) of GPS traces + * @param[in] ubuff vertical position [npts] + * @param[in] nbuff north position [npts] + * @param[in] ebuff east position [npts] + * @param[in] usigmabuff vertical position uncertainty [npts] + * @param[in] nsigmabuff north position uncertainty [npts] + * @param[in] esigmabuff east position uncertainty [npts] + * @param[in] nMaxLeader latest time index to start measurement in + * case of nan's + * @param[in] tmin distance / svel_window (s) + * @param[in] tmax distance / min_svel_window (s) + * + * @param[out] obsTime epochal time of peak displacment (s) + * @param[out] uMaxUncertainty peak vertical uncertainty at the reference + * or peak displacement times (m) + * @param[out] nMaxUncertainty peak north uncertainty at the reference + * or peak displacement times (m) + * @param[out] eMaxUncertainty peak east uncertainty at the reference + * or peak displacement times (m) + * + * + * @result the peak displacement observed on a trace. this has the same + * units as ubuff, nbuff, and ebuff. + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @date May 2016 + * + */ +double core_waveformProcessor_peakDisplacementHelper( + const int npts, + const double dt, + const double ev_time, + const double epoch, + const double *__restrict__ ubuff, + const double *__restrict__ nbuff, + const double *__restrict__ ebuff, + const double *__restrict__ usigmabuff, + const double *__restrict__ nsigmabuff, + const double *__restrict__ esigmabuff, + const int nMaxLeader, + const double tmin, + const double tmax, + double *obsTime, + double *uMaxUncertainty, + double *nMaxUncertainty, + double *eMaxUncertainty + ) +{ + double diffT, peakDisplacement_i, peakDisplacement, e0, n0, u0; + int i, indx0, indx1; + int ipeak = 0; + int debug = 0; + //------------------------------------------------------------------------// + // + // Set the initial position + *obsTime = 0.0; + *uMaxUncertainty = 0.0; + *nMaxUncertainty = 0.0; + *eMaxUncertainty = 0.0; + u0 = 0.0; + n0 = 0.0; + e0 = 0.0; + diffT = ev_time - epoch; + indx0 = MAX(0, (int) (diffT/dt + 0.5)); + indx0 = MIN(npts - 1, indx0); + + // Compute the offset + u0 = ubuff[indx0]; + n0 = nbuff[indx0]; + e0 = ebuff[indx0]; + + if (isnan(u0) || isnan(n0) || isnan(e0)) { + for (i = indx0; i < nMaxLeader; i++) { + if (!isnan(ubuff[i]) && !isnan(nbuff[i]) && !isnan(ebuff[i])) { + indx0 = i; + u0 = ubuff[indx0]; + n0 = nbuff[indx0]; + e0 = ebuff[indx0]; + //LOG_MSG("Search leader for t0: nMax:%d indx0:%d u0:%f n0:%f e0:%f", + //nMaxLeader, indx0, u0, n0, e0); + break; + } + } + } + + indx1 = (int)(tmax/dt + 0.5); + if (indx1 <= indx0) { + // LOG_MSG("ERROR: indx0=%d >= indx1=%d (tmax=%f)", indx0, indx1, tmax); + return (double) NAN; + } + if (indx1 > npts) { + // LOG_MSG("tmin=%.1f tmax=%.1f npts=%d <= indx1=%d --> Set indx1=npts", tmin, tmax, npts, indx1); + indx1 = npts; + } + + // Prevent a problem + if (isnan(u0) || isnan(n0) || isnan(e0)) + { + // LOG_MSG("Returning NAN instead of calculating epoch:%f diffT=%f indx0=%d", + // epoch, diffT, indx0); + return (double) NAN; + } + + // Get initial uncertainty for each component + if (!isnan(usigmabuff[indx0])) *uMaxUncertainty = usigmabuff[indx0]; + if (!isnan(nsigmabuff[indx0])) *nMaxUncertainty = nsigmabuff[indx0]; + if (!isnan(esigmabuff[indx0])) *eMaxUncertainty = esigmabuff[indx0]; + + // Compute the maximum peak ground displacement + peakDisplacement = PD_MAX_NAN; + if (debug) { + LOG_MSG("Loop to find peakDisp: from i=indx0=%d to i peakDisplacement) { + ipeak = i; + } + peakDisplacement = fmax(peakDisplacement_i, peakDisplacement); + } // Loop on data points + + if (debug) { + LOG_DEBUGMSG("Uncertainties at indx0:%d (%f,%f,%f), at ipeak:%d (%f,%f,%f", + indx0, *uMaxUncertainty, *nMaxUncertainty, *eMaxUncertainty, + ipeak, usigmabuff[ipeak], nsigmabuff[ipeak], esigmabuff[ipeak]); + } + + if (!isnan(usigmabuff[ipeak])) *uMaxUncertainty = fmax(usigmabuff[ipeak], *uMaxUncertainty); + if (!isnan(nsigmabuff[ipeak])) *nMaxUncertainty = fmax(nsigmabuff[ipeak], *nMaxUncertainty); + if (!isnan(esigmabuff[ipeak])) *eMaxUncertainty = fmax(esigmabuff[ipeak], *eMaxUncertainty); + + if (fabs(peakDisplacement - PD_MAX_NAN)/fabs(PD_MAX_NAN) < 1.e-10) + { + LOG_MSG("%s", "Returning NAN because peakDisp is ~ PD_MAX_NAN"); + peakDisplacement = (double) NAN; + } + if (!isnan(peakDisplacement)){ + *obsTime = epoch + dt * ipeak; + // LOG_MSG("Got peak [%f] at ipeak:%d ubuff[i]=%f (u0=%f) nbuff[i]=%f (n0=%f) ebuff[i]=%f (e0=%f) ", + // peakDisplacement, ipeak, ubuff[ipeak], u0, nbuff[ipeak], n0, ebuff[ipeak], e0); + } + + return peakDisplacement; +} \ No newline at end of file diff --git a/src/dmlib/Makefile b/src/dmlib/Makefile new file mode 100644 index 00000000..9b38c1f5 --- /dev/null +++ b/src/dmlib/Makefile @@ -0,0 +1,70 @@ +# Makefile for GFAST/src/dmlib +# + +EEWDIR = ../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +DMLIB_INCL = -I$(EEWDIR)/libs/dmlib + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = dmlibWrapper.cpp.o +LIB = +DEBUG = -g +#CCFLAGS += -std=c++0x -O0 -D_REENTRANT -Dstatic_config + +INCL= -I ../../include $(DMLIB_INCL) $(ACTIVEMQ_INCL) $(APR_INCL) $(ISCL_INCL) + +all: $(OBJS) +#lib: $(LIB) + +#$(LIB): $(OBJS) +# $(AR) $(LIB) $(OBJS) + +%.c.o: %.c + $(cc) -c $< -o $@ $(CFLAGS) $(DEBUG) $(INCL) +%.cpp.o: %.cpp + $(CXX) -c $< -o $@ $(CCFLAGS) $(DEBUG) $(INCL) + +ids: *.cpp + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.cpp + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(LIB) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/dmlib/dmlibWrapper.cpp b/src/dmlib/dmlibWrapper.cpp new file mode 100644 index 00000000..6cd3c91f --- /dev/null +++ b/src/dmlib/dmlibWrapper.cpp @@ -0,0 +1,574 @@ +/*! + * @file dmlibWrapper.cpp + * @brief variables and functions to expose dmlib functionality to GFAST c code + */ + +#include +#include +#include +#include "DMLib.h" +#include "FiniteFaultMessage.h" +#include "CoreEventInfo.h" +#include "HBProducer.h" +#include "DMMessageReceiver.h" +#include "DMMessageSender.h" +#include "dmlibWrapper.h" +#include "gfast_activeMQ.h" +#include "gfast_struct.h" +#include "gfast_core.h" +#include "gfast_enum.h" +#include "gfast_xml.h" +#include "iscl/iscl/iscl_enum.h" +#include "iscl/time/time.h" + +/*static variables local to this file*/ +namespace { + static cms::Connection *destinationConnection=NULL; + static HBProducer *hbproducer=NULL; + static DMMessageReceiver *eventreceiver=NULL; + static DMMessageSender *eventsender=NULL; + static CoreEventInfo *eventmessage=NULL; + static std::string hbSender=""; + static std::string hbTopic=""; + static int conVerbose=0; + static int hbVerbose=0; +} + +/* + * compareDist and dist_index are both used to sort pgd observations by distance from source + * when creating xml message. Needed for adding the 'assoc' attribute correctly. + */ +static int compareDist(const void *x, const void *y); +struct dist_index { + double dist; + int indx; +}; + +int startDestinationConnection(const char AMQuser[], + const char AMQpassword[], + const char destinationURL[], + const int msReconnect, + const int maxAttempts, + const int verbose=1) { + conVerbose = verbose; + if (destinationConnection != NULL) { + LOG_DEBUGMSG("%s: connection already exists",__func__); + return 0; + } + char *brokerURI; + brokerURI = activeMQ_setTcpURIRequest(destinationURL, + msReconnect, maxAttempts); + try + { + // Create a connection factory + if (conVerbose > 2) + { + LOG_DEBUGMSG("%s: Setting the broker URI: %s", + __func__, brokerURI); + } + auto_ptr connectionFactory( + cms::ConnectionFactory::createCMSConnectionFactory(brokerURI)); + + if (conVerbose > 2) + { + LOG_DEBUGMSG("%s: Creating connection for username (%s)", + __func__, AMQuser); + } + // Create a connection + destinationConnection = connectionFactory->createConnection(AMQuser, AMQpassword); + connectionFactory.reset(); + free(brokerURI); + if (destinationConnection==NULL) return -1; + } + catch (cms::CMSException &e) + { + LOG_ERRMSG("%s: Exception encountered creating dmlib connection\n%s",__func__,e.what()); + e.printStackTrace(); + free(brokerURI); + return -1; + } + return 1; +} + +int stopDestinationConnection() { + if ( destinationConnection == NULL ) { + LOG_DEBUGMSG("%s: connection already dead",__func__); + return 0; + } else { + try { + /*if ( not destinationConnection->isClosed() { + destinationConnection->stop(); + destinationConnection->close(); + }*/ + delete destinationConnection; + destinationConnection=NULL; + } + catch (cms::CMSException &e) { + LOG_ERRMSG("%s: CMSException encountered closing dmlib destination connection\n%s",__func__,e.what()); + e.printStackTrace(); + return -1; + } + catch (exception &e) { + LOG_ERRMSG("%s: Exception encountered closing dmlib destination connection\n%s",__func__,e.what()); + return -1; + } + } + return 1; +} + +bool isAMQconnected() { + if (destinationConnection==NULL) { + return false; + } + //vck: add real connected test here and make default -1 + LOG_DEBUGMSG("%s: dummy placeholder function call",__func__); + return true; +} + +int startEventReceiver(const char originURL[], + const char user[], + const char password[], + const char originTopic[], + const int msReconnect, + const int maxAttempts) { + std::string brokerURI; + if (conVerbose > 2) + { + LOG_DEBUGMSG("%s: Starting dmlib DMMessageReceiver on topic: %s", + __func__, originTopic); + } + if (eventreceiver != NULL) + { + LOG_DEBUGMSG("%s: Event receiver already initalized",__func__); + return 0; + } + try { + // Set the URI + char *brokerURIchar; + brokerURIchar = activeMQ_setTcpURIRequest(originURL, msReconnect, maxAttempts); + brokerURI = std::string(brokerURIchar); + delete[] brokerURIchar; + + eventreceiver = new DMMessageReceiver(brokerURI, std::string(user), std::string(password), + std::string(originTopic)); + } + catch (exception &e) + { + LOG_ERRMSG("%s: Encountered Exception creating DMMessageReceiver\n%s",__func__,e.what()); + return -1; + } + try { + eventreceiver->run(); + } + catch (exception &e) + { + LOG_ERRMSG("%s: Encountered Exception running DMMessageReceiver%s",__func__,e.what()); + return -1; + } + return 1; +} + +char *eventReceiverGetMessage(const int ms_wait, int *ierr) { + char *message = NULL; + CoreEventInfo *cei = NULL; + *ierr = 0; + if (eventreceiver == NULL) + { + LOG_DEBUGMSG("%s: Event receiver not started!",__func__); + *ierr = -1; + return message; + } + + // Finally, encode algMessage as xml, using the eventsenders encoder + std::string msg_tmp = ""; + // LOG_DEBUGMSG("%s: Calling eventreceiver->receive(%d, msg_tmp)", __func__, ms_wait); + cei = eventreceiver->receive(ms_wait, msg_tmp); + + if (msg_tmp.length() > 0) + { + message = (char *)calloc(msg_tmp.length() + 1, sizeof(char)); + strncpy(message, msg_tmp.c_str(), msg_tmp.length()); + } + + // LOG_MSG("%s - Returning", __func__); + delete cei; + cei = NULL; + return message; +} + +int stopEventReceiver() { + if (eventreceiver==NULL) { + LOG_DEBUGMSG("%s: Event receiver not running",__func__); + return 0; + } else { + delete eventreceiver; + eventreceiver=NULL; + } + return 1; +} + +int startEventSender(const char eventtopic[]) { + if (conVerbose > 2) + { + LOG_DEBUGMSG("%s: Starting dmlib DMMessageSender on topic: %s", + __func__, eventtopic); + } + if (!isAMQconnected()) { + LOG_ERRMSG("%s: Cannot start event sender without activeMQ connection.",__func__); + return -1; + } + if (eventsender != NULL) { + LOG_DEBUGMSG("%s: Event sender already initalized",__func__); + return 0; + } + try { + eventsender = new DMMessageSender(destinationConnection,eventtopic); + } + catch (exception &e) + { + LOG_ERRMSG("%s: Encountered Exception creating DMMessageSender\n%s",__func__,e.what()); + return -1; + } + try { + eventsender->run(); + } + catch (exception &e) + { + LOG_ERRMSG("%s: Encountered Exception running DMMessageSender%s",__func__,e.what()); + return -1; + } + return 1; +} + +int stopEventSender() { + if (eventsender==NULL) { + LOG_DEBUGMSG("%s: Event sender not running",__func__); + return 0; + } else { + delete eventsender; + eventsender=NULL; + } + if (eventmessage!=NULL) { + delete eventmessage; + eventmessage=NULL; + } + return 1; +} + +int sendEventMessage() { + if (conVerbose > 2) + { + LOG_DEBUGMSG("%s: Sending event message to activemq topic.", + __func__); + } + if (eventmessage==NULL) { + LOG_DEBUGMSG("%s: No message to send",__func__); + return 0; + } + try { + eventsender->sendMessage(eventmessage); + } + catch (exception &e) { + LOG_ERRMSG("%s: DMMessageSender error: %s",__func__,e.what()); + } + if (conVerbose>1) { + LOG_MSG("%s: sent GFAST message to activemqfor evid:%s",__func__,eventmessage->getID().c_str()); + } + return 1; +} + +int sendEventXML(const char xmlstr[]) { + if (conVerbose > 2) + { + LOG_DEBUGMSG("%s: Sending preformatted xml message to event topic.", + __func__); + } + if (eventsender == NULL) + { + LOG_WARNMSG("%s: Event sender not running", __func__); + return 0; + } + + eventsender->sendString(xmlstr); + if (conVerbose>1) { + LOG_MSG("%s: sent xml message to activemq",__func__); + } + return 1; +} + +int startHBProducer(const char sender[], + const char hbtopic[], + int interval=0, + int verbose=1) { + if (destinationConnection==NULL) { + LOG_ERRMSG("%s: Error: AMQ connection must be started before HBProducer",__func__); + return -1; + } + if (hbproducer!=NULL) { + LOG_DEBUGMSG("%s: HBProducer already started",__func__); + return 0; + } + hbVerbose=verbose; + hbSender=string(sender); + hbTopic=string(hbtopic); + if (hbVerbose > 2) { + LOG_DEBUGMSG("%s: Starting heartbeat producer on topic: %s",__func__, hbtopic); + } + try { + hbproducer = new HBProducer(destinationConnection,hbSender,hbTopic,interval); + } + catch (exception &e) { + LOG_ERRMSG("%s: Encountered Exception creating dmlib HB producer%s",__func__,e.what()); + return -1; + } + /* this part is not working (steals the program) + if (interval > 0) { + try { + hbproducer->run(); + } + catch (exception &e) { + printf("%s: Encountered Exception in dmlib HB producer\n%s",__func__,e.what()); + return -1; + } + } + */ + + return (hbproducer==NULL)?-1:1; +} + +int stopHBProducer() { + if (hbVerbose > 2) + { + LOG_DEBUGMSG("%s: killing heartbeat producer",__func__); + } + + if (hbproducer==NULL) { + LOG_DEBUGMSG("%s: HB producer not running",__func__); + return 0; + } else { + hbproducer->stop(); + delete hbproducer; + hbproducer=NULL; + } + return 1; +} + +int sendHeartbeat(){ + std::string timestr; + if (hbproducer==NULL) { + LOG_DEBUGMSG("%s: HB producer not running",__func__); + return 0; + } + hbproducer->sendHeartbeat("","",""); + return 1; +} + +char *dmlibWrapper_createPGDXML(const enum opmode_type mode, + const char *alg_vers, + const char *instance, + const char *message_type, + const int max_assoc_stations, + const struct coreInfo_struct *core, + const struct GFAST_pgdResults_struct *pgd, + const struct GFAST_peakDisplacementData_struct *pgd_data, + int *ierr) { + + char *xmlmsg; + xmlmsg = NULL; + *ierr = 0; + + struct dist_index *vals; + vals = (struct dist_index *) calloc((size_t) pgd->nsites, sizeof(struct dist_index)); + // int max_assoc_stations = 6; + + // Convert enum units to char + char magUnits[32], magUncerUnits[32], latUnits[32], latUncerUnits[32], lonUnits[32], + lonUncerUnits[32], depthUnits[32], depthUncerUnits[32], origTimeUnits[32], + origTimeUncerUnits[32]; + __xml_units__enum2string(core->magUnits, magUnits); + __xml_units__enum2string(core->magUncerUnits, magUncerUnits); + __xml_units__enum2string(core->latUnits, latUnits); + __xml_units__enum2string(core->latUncerUnits, latUncerUnits); + __xml_units__enum2string(core->lonUnits, lonUnits); + __xml_units__enum2string(core->lonUncerUnits, lonUncerUnits); + __xml_units__enum2string(core->depthUnits, depthUnits); + __xml_units__enum2string(core->depthUncerUnits, depthUncerUnits); + __xml_units__enum2string(core->origTimeUnits, origTimeUnits); + __xml_units__enum2string(core->origTimeUncerUnits, origTimeUncerUnits); + + // LOG_MSG("%s", "createEventXML - set unit chars"); + + // convert to CoreEventInfo MessageCategory + enum MessageCategory imode; + if (mode == REAL_TIME_EEW) { + imode = LIVE; + } else if (mode == PLAYBACK) { + imode = TEST; + } else if (mode == OFFLINE) { + imode = TEST; + } else { + LOG_DEBUGMSG("%s", "Defaulting to live mode"); + imode = LIVE; + } + + // convert to CoreEventInfo nudMessageType + enum nudMessageType itype; + if (strcmp(message_type, "new") == 0) { + itype = NEW; + } else if (strcmp(message_type, "update") == 0) { + itype = UPDATE; + } else { + LOG_DEBUGMSG("%s", "Message type not recognized! Defaulting to update"); + itype = UPDATE; + } + + // required to create FiniteFaultMessage + enum FaultSegment::FaultSegmentShape shape = FaultSegment::UNKNOWN_SEGMENT; + + // Get time stamp for when message is sent + int rc; + char cnow[128]; + double now; + now = time_timeStamp(); + rc = xml_epoch2string(now, cnow); + if (rc != 0) { + LOG_DEBUGMSG("%s", "Error getting time string!"); + } + + FiniteFaultMessage algMessage(GFAST, shape, core->id, core->mag, core->magUncer, core->lat, + core->latUncer, core->lon, core->lonUncer, core->depth, core->depthUncer, core->origTime, + core->origTimeUncer, core->likelihood, itype, core->version, imode, cnow, alg_vers, + instance, core->numStations, magUnits, magUncerUnits, latUnits, + latUncerUnits, lonUnits, lonUncerUnits, depthUnits, depthUncerUnits, origTimeUnits, + origTimeUncerUnits); + + // LOG_MSG("%s", "createEventXML - created algMessage"); + + // Now add pgd observations to algMessage + int i, j; + int scnl_n = 8; + char obs_sta[scnl_n], obs_net[scnl_n], obs_chan[scnl_n], obs_loc[scnl_n]; + char *token = NULL, *work = NULL; + bool assoc_flag = false; + int n_assoc = 0; + double tmp_lon; + + enum ObservationType obs_type = DISPLACEMENT_OBS; + + // Later we assume pgd->nsites = pgd_data->nsites and indices correspond + if (pgd->nsites != pgd_data->nsites) + { + LOG_WARNMSG("%s: nsites don't match for pgd, pgd_data! %d, %d" ,__func__, pgd->nsites, + pgd_data->nsites); + *ierr = -1; + return xmlmsg; + } + + // Extra step to sort observations by distance, so that the first max_assoc_stations get the + // assoc_flag = true. This is used by the Solution Aggregator to associate events. Other + // algorithms might sort by observation value, but in this case we want to be sure to associate + // with the input location, since GFAST doesn't determine its own event location. + // Load distance and index to sort pgd obs by distance from source + for ( i = 0; i < pgd->nsites; i++ ) + { + vals[i].indx = i; + // srdist has ndep*nsites. Just use the first depth, they should all be relatively the same + vals[i].dist = pgd->srdist[i]; + } + + // Sort by distance + qsort((void *) vals, (size_t) pgd->nsites, sizeof(struct dist_index), compareDist); + + // Go through the observations in ascending order of source-receiver distance + for ( j = 0; j < pgd->nsites; j++ ) + { + i = vals[j].indx; + // skip site if it wasn't used + if (!pgd->lsiteUsed[i]) { continue; } + + // LOG_MSG("createEventXML - i = %d, setting chars", i); + // see core/data/readMetaDataFile for similar SNCL parsing + memset(obs_sta, 0, scnl_n*sizeof(char)); + memset(obs_net, 0, scnl_n*sizeof(char)); + memset(obs_chan, 0, scnl_n*sizeof(char)); + memset(obs_loc, 0, scnl_n*sizeof(char)); + + work = (char *)calloc(strlen(pgd_data->stnm[i])+1, sizeof(char)); + strcpy(work, pgd_data->stnm[i]); + + // LOG_MSG("%s", "createEventXML - starting NSCL tokenizing"); + token = strtok(work, "."); + int i_tok = 0; + while (token) + { + if (i_tok == 0) { strcpy(obs_net, token); } + if (i_tok == 1) { strcpy(obs_sta, token); } + if (i_tok == 2) { strcpy(obs_chan, token); } + if (i_tok == 3) { strcpy(obs_loc, token); } + i_tok++; + token = strtok(NULL, "."); + } + // LOG_MSG("%s", "createEventXML - done NSCL tokenizing, freeing work"); + delete work; + work = NULL; + // LOG_MSG("%s", "createEventXML - freed work, adding gmobs"); + + assoc_flag = (n_assoc >= max_assoc_stations) ? false : true; + // Make sure longitude follows ShakeAlert convention + tmp_lon = pgd_data->sta_lon[i]; + tmp_lon = (tmp_lon > 180) ? tmp_lon - 360 : tmp_lon; + + // Make sure to convert pgd to cm (from m) + algMessage.addGMObservation(obs_type, + obs_sta, + obs_net, + obs_chan, + obs_loc, + pgd_data->pd[i] * 100., + pgd_data->sta_lat[i], + tmp_lon, + pgd_data->pd_time[i], + "cm\0", + "deg\0", + "deg\0", + "UTC\0", + "gfast\0", + assoc_flag); + + n_assoc++; + + // LOG_DEBUGMSG("createEventXML - added obs=%f, sta=%s, i=%d, j=%d, dist=%f, assoc=%d, n_assoc=%d", + // pgd_data->pd[i] * 100., pgd_data->stnm[i], i, j, vals[j].dist, assoc_flag, n_assoc); + } + + LOG_MSG("%s", "createEventXML - finished adding gmobs, encoding message"); + + // Finally, encode algMessage as xml + std::string msg_tmp; + + try { + msg_tmp = eventsender->getEncodedMessage(&algMessage); + } + catch (exception &e) { + LOG_ERRMSG("%s: DMMessageSender error while encoding: %s",__func__,e.what()); + *ierr = -1; + return xmlmsg; + } + + xmlmsg = (char *)calloc(msg_tmp.length() + 1, sizeof(char)); + strncpy(xmlmsg, msg_tmp.c_str(), msg_tmp.length()); + + free(token); + free(vals); + LOG_MSG("%s", "createEventXML - Returning"); + return xmlmsg; +} + +static int compareDist(const void *x, const void *y) { + const struct dist_index xx = *(const struct dist_index *) x; + const struct dist_index yy = *(const struct dist_index *) y; + + if (xx.dist < yy.dist) return -1; + if (xx.dist > yy.dist) return 1; + return 0; +} diff --git a/src/doxygen.conf b/src/doxygen.conf new file mode 100644 index 00000000..40cc57b5 --- /dev/null +++ b/src/doxygen.conf @@ -0,0 +1,40 @@ +# $Id$ +# +# Doxygen for gfast + +@INCLUDE = ../../doxygen.include +# override location of layout file +LAYOUT_FILE = ../../doxygen.layout + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "GFAST" +# version number +PROJECT_NUMBER = "GFAST: gfast-1.2.1-2022-11-28" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Geodetic First Approximation of Size and Timing" + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = ../include activeMQ core/cmt core/coordtools \ + core/data core/events core/ff core/log core/properties core/scaling \ + core/waveformProcessor dmlib eewUtils hdf5 traceBuffer/ewrr \ + traceBuffer/h5 xml/quakeML xml/shakeAlert +OUTPUT_DIRECTORY = ../../docs/gfast +GENERATE_TAGFILE = gfast.tag diff --git a/src/eewUtils/Makefile b/src/eewUtils/Makefile new file mode 100644 index 00000000..c6b62048 --- /dev/null +++ b/src/eewUtils/Makefile @@ -0,0 +1,74 @@ +# Makefile for GFAST/src/eewUtils +# +# + +EEWDIR = ../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +EW_INCL = -I$(EWDIR)/include + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = driveCMT.o driveFF.o drivePGD.o makeXML.o\ +parseCoreXML.o setLogFileNames.o driveGFAST.o + +LIB = gfast_utils.a +DEBUG = -g +CFLAGS += -O0 -D_REENTRANT -Dstatic_config ${GFAST_VERSION} + +#iniparser will be deleted +INCL = -I ../../include $(ISCL_INCL) $(XML2_INCL) $(COMPEARTH_INCL) $(EW_INCL) $(HDF5_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(LIB) +lib: $(LIB) + +$(LIB): $(OBJS) + $(AR) $(LIB) $(OBJS) + +%.o: %.c + $(cc) -c $< -o $@ $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) $(LIB) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/eewUtils/driveCMT.c b/src/eewUtils/driveCMT.c new file mode 100644 index 00000000..f0653fb5 --- /dev/null +++ b/src/eewUtils/driveCMT.c @@ -0,0 +1,472 @@ +#include +#include +#include +#include "gfast_eewUtils.h" +#include +#include "gfast_core.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" + +static int __verify_cmt_structs(struct GFAST_offsetData_struct cmt_data, + struct GFAST_cmtResults_struct *cmt); + +/*! + * @brief Drives the CMT estimation. + * + * @param[in] cmt_props CMT inversion parameters + * @param[in] SA_lat event latitude (degrees) [-90,90] + * @param[in] SA_lon event longitude (degrees) [0,360] + * @param[in] SA_dep event depth (km) + * @param[in] cmt_data cmt offset data to invert + * + * @param[in,out] cmt on input contains the depths for the grid search + * on output contains the corresponding variance + * reduction, moment tensors, nodal planes at each + * depth in the CMT grid search, and optimal depth + * index. + * + * @result 0 indicates success + * 1 indicates an error on the cmt structure + * 2 indicates the offset data structure is invalid + * 3 indicates there was insufficient data to invert + * 4 indicates an error encountered during the computation + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +int eewUtils_driveCMT(struct GFAST_cmt_props_struct cmt_props, + const double SA_lat, + const double SA_lon, + const double SA_dep, + struct GFAST_offsetData_struct cmt_data, + struct GFAST_cmtResults_struct *cmt) +{ + double *utmRecvEasting, *utmRecvNorthing, *staAlt, + *eOffset, *eEst, *eWts, *nOffset, *nEst, *nWts, + *uOffset, *uEst, *uWts, + DC_pct, eres, nres, sum_res2, ures, + utmSrcEasting, utmSrcNorthing, wte, wtn, wtu, x1, y1, x2, y2; + int i, idep, ierr, ierr1, ilat, ilon, indx, k, l1, nlld, zone_loc; + bool *luse, lnorthp; + //------------------------------------------------------------------------// + // + // Verify the input data structure makes sense + ierr = CMT_SUCCESS; + luse = NULL; + utmRecvEasting = NULL; + utmRecvNorthing = NULL; + staAlt = NULL; + uOffset = NULL; + nOffset = NULL; + eOffset = NULL; + uWts = NULL; + nWts = NULL; + eWts = NULL; + nEst = NULL; + eEst = NULL; + uEst = NULL; + // Verify input data structures + ierr =__verify_cmt_structs(cmt_data, cmt); + if (ierr != CMT_SUCCESS) + { + LOG_ERRMSG("%s", "Error failed to verify data structures"); + } + if (cmt->nlats > 1 || cmt->nlons > 1) + { + LOG_ERRMSG("%s", "Error nlats > 1 | nlons > 1 not done"); + ierr = 1; + return ierr; + } + // Warn in case hypocenter is outside of grid-search + if (cmt_props.verbose > 1 && + (SA_dep < cmt->srcDepths[0] || SA_dep > cmt->srcDepths[cmt->ndeps-1])) + { + LOG_WARNMSG("%s", "Warning hypocenter isn't in grid search!"); + } + // Initialize result + nlld = cmt->nlats*cmt->nlons*cmt->ndeps; + cmt->opt_indx =-1; + // Synthetics as a function of depth + array_zeros64f_work(cmt->nsites*nlld, cmt->EN); + array_zeros64f_work(cmt->nsites*nlld, cmt->NN); + array_zeros64f_work(cmt->nsites*nlld, cmt->UN); + // Observations + array_zeros64f_work(cmt->nsites, cmt->Einp); + array_zeros64f_work(cmt->nsites, cmt->Ninp); + array_zeros64f_work(cmt->nsites, cmt->Uinp); + // MT optimizaiton information as a function of depth + nlld = cmt->nlats*cmt->nlons*cmt->ndeps; + array_zeros64f_work(nlld, cmt->l2); + array_zeros64f_work(nlld, cmt->pct_dc); + array_zeros64f_work(nlld, cmt->objfn); + array_zeros64f_work(6*nlld, cmt->mts); + array_zeros64f_work(nlld, cmt->str1); + array_zeros64f_work(nlld, cmt->str2); + array_zeros64f_work(nlld, cmt->dip1); + array_zeros64f_work(nlld, cmt->dip2); + array_zeros64f_work(nlld, cmt->rak1); + array_zeros64f_work(nlld, cmt->rak2); + array_zeros64f_work(nlld, cmt->Mw); + // Require there is a sufficient amount of data to invert + luse = memory_calloc8l(cmt_data.nsites); + l1 = 0; + for (k=0; k 1) + { + LOG_WARNMSG("Insufficient data to invert %d < %d\n", + l1, cmt_props.min_sites); + } + ierr = CMT_INSUFFICIENT_DATA; + goto ERROR; + } + // Set space + utmRecvNorthing = memory_calloc64f(l1); + utmRecvEasting = memory_calloc64f(l1); + staAlt = memory_calloc64f(l1); + uOffset = memory_calloc64f(l1); + nOffset = memory_calloc64f(l1); + eOffset = memory_calloc64f(l1); + uWts = memory_calloc64f(l1); + nWts = memory_calloc64f(l1); + eWts = memory_calloc64f(l1); + nEst = memory_calloc64f(l1*cmt->ndeps); + eEst = memory_calloc64f(l1*cmt->ndeps); + uEst = memory_calloc64f(l1*cmt->ndeps); + // Get the source location + zone_loc = cmt_props.utm_zone; // Use input UTM zone + if (zone_loc ==-12345){zone_loc =-1;} // Figure it out + core_coordtools_ll2utm(SA_lat, SA_lon, + &y1, &x1, + &lnorthp, &zone_loc); + utmSrcNorthing = y1; + utmSrcEasting = x1; + // Get cartesian positions and observations onto local arrays + l1 = 0; + for (k=0; k 2) + { + LOG_DEBUGMSG("Inverting for CMT with %d sites", l1); + } + ierr = core_cmt_gridSearch(l1, + cmt->ndeps, cmt->nlats, cmt->nlons, + cmt_props.verbose, + cmt_props.ldeviatoric, + &utmSrcEasting, + &utmSrcNorthing, + cmt->srcDepths, + utmRecvEasting, + utmRecvNorthing, + staAlt, + nOffset, + eOffset, + uOffset, + nWts, + eWts, + uWts, + nEst, + eEst, + uEst, + cmt->mts); +/* + ierr = core_cmt_depthGridSearch(l1, cmt->ndeps, + cmt_props.verbose, + cmt_props.ldeviatoric, + utmSrcEasting, + utmSrcNorthing, + cmt->srcDepths, + utmRecvEasting, + utmRecvNorthing, + staAlt, + nOffset, + eOffset, + uOffset, + nWts, + eWts, + uWts, + nEst, + eEst, + uEst, + cmt->mts); +*/ + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error in CMT gridsearch!"); + ierr = CMT_COMPUTE_ERROR; + goto ERROR; + } + // Get the estimates and observations + i = 0; + for (k=0; knsites; k++) + { + cmt->lsiteUsed[k] = luse[k]; + if (!luse[k]){continue;} + cmt->Ninp[k] = nOffset[i]; + cmt->Einp[k] = eOffset[i]; + cmt->Uinp[k] = uOffset[i]; + cmt->lsiteUsed[k] = true; + i = i + 1; + } + // Extract results and weight objective fn by percent double couple + ierr = 0; +#ifdef PARALLEL_CMT + #pragma omp parallel for collapse(3) \ + private(DC_pct, eres, i, idep, ierr1, ilat, ilon, indx, k, sum_res2, nres, ures) \ + shared(cmt, eOffset, eEst, l1, luse, nOffset, nEst, uOffset, uEst) \ + reduction(+:ierr), default(none) +#endif + for (ilon=0; ilonnlons; ilon++) + { + for (ilat=0; ilatnlats; ilat++) + { + for (idep=0; idepndeps; idep++) + { + // Get location in arrays + indx = ilon*cmt->ndeps*cmt->nlats + + ilat*cmt->ndeps + + idep; + // Compute the L2 norm + sum_res2 = 0.0; +#ifdef _OPENMP + #pragma omp simd reduction(+:sum_res2) +#endif + for (i=0; imts[6*idep], + &DC_pct, + &cmt->Mw[idep], + &cmt->str1[idep], + &cmt->str2[idep], + &cmt->dip1[idep], + &cmt->dip2[idep], + &cmt->rak1[idep], + &cmt->rak2[idep]); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error decomposing mt"); + ierr = ierr + 1; + continue; + } + // Prefer results with larger double couple percentages + cmt->l2[indx] = 0.5*sqrt(sum_res2); + cmt->pct_dc[indx] = DC_pct; + cmt->objfn[indx] = sum_res2/DC_pct; + // Save the data + i = 0; + for (k=0; knsites; k++) + { + cmt->NN[indx*cmt->nsites+k] = 0.0; + cmt->EN[indx*cmt->nsites+k] = 0.0; + cmt->UN[indx*cmt->nsites+k] = 0.0; + if (luse[k]) + { + cmt->NN[indx*cmt->nsites+k] = nEst[indx*l1+i]; + cmt->EN[indx*cmt->nsites+k] = eEst[indx*l1+i]; + cmt->UN[indx*cmt->nsites+k] = uEst[indx*l1+i]; + i = i + 1; + } + } + } // Loop on depths + } // loop on latiudes + } // loop on longitudes + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error decomposing moment tensor"); + ierr = CMT_COMPUTE_ERROR; + } + // Get the optimimum index + { /*vk needed for more stringent c++ compiler*/ + enum isclError_enum isclerr = (enum isclError_enum)ierr; + cmt->opt_indx = array_argmin64f(cmt->ndeps, cmt->objfn, &isclerr); // TODO: cmt->ndeps = nlld + } + if (cmt->ndeps < nlld) + { + LOG_WARNMSG("%s", "NEED to unpack opt_indx and make a cmt->opt_dep"); + } +ERROR:; + memory_free8l(&luse); + memory_free64f(&utmRecvNorthing); + memory_free64f(&utmRecvEasting); + memory_free64f(&staAlt); + memory_free64f(&uOffset); + memory_free64f(&nOffset); + memory_free64f(&eOffset); + memory_free64f(&nEst); + memory_free64f(&eEst); + memory_free64f(&uEst); + memory_free64f(&nWts); + memory_free64f(&eWts); + memory_free64f(&uWts); + return ierr; +} +//============================================================================// +/*! + * @brief Utility function for verifying input data structures + * + * @param[in] cmt_data cmt_data structure to verify + * @param[in] cmt cmt results structure to verify + * + * @result CMT_SUCCESS indicates input structures are ready for use + * + * @author Ben Baker (ISTI) + * + */ +static int __verify_cmt_structs(struct GFAST_offsetData_struct cmt_data, + struct GFAST_cmtResults_struct *cmt) +{ + int ierr; + ierr = CMT_SUCCESS; + // Require there is offset data + if (cmt_data.nsites < 1) + { + ierr = CMT_OS_DATA_ERROR; + LOG_ERRMSG("%s", "No offset data"); + goto ERROR; + } + // Verify the output data structures + if (cmt->ndeps < 1) + { + LOG_ERRMSG("%s", "No depths in CMT gridsearch!"); + ierr = CMT_STRUCT_ERROR; + goto ERROR; + } + if (cmt->l2 == NULL || cmt->pct_dc == NULL || + cmt->objfn == NULL || cmt->mts == NULL || + cmt->str1 == NULL || cmt->str2 == NULL || + cmt->dip1 == NULL || cmt->dip2 == NULL || + cmt->rak1 == NULL || cmt->rak2 == NULL || + cmt->Mw == NULL || cmt->srcDepths == NULL || + cmt->EN == NULL || cmt->NN == NULL || cmt->UN == NULL || + cmt->Einp == NULL || cmt->Ninp == NULL || cmt->Uinp == NULL || + cmt->lsiteUsed == NULL) + { + if (cmt->l2 == NULL) + { + LOG_ERRMSG("%s", "Error cmt->l2 is NULL"); + } + if (cmt->pct_dc == NULL) + { + LOG_ERRMSG("%s", "Error cmt->pct_dc is NULL"); + } + if (cmt->objfn == NULL) + { + LOG_ERRMSG("%s", "Error cmt->objfn is NULL"); + } + if (cmt->mts == NULL) + { + LOG_ERRMSG("%s", "Error cmt->mts is NULL"); + } + if (cmt->str1 == NULL) + { + LOG_ERRMSG("%s", "Error cmt->str1 is NULL"); + } + if (cmt->str2 == NULL) + { + LOG_ERRMSG("%s", "Error cmt->str2 is NULL"); + } + if (cmt->dip1 == NULL) + { + LOG_ERRMSG("%s", "Error cmt->dip1 is NULL"); + } + if (cmt->dip2 == NULL) + { + LOG_ERRMSG("%s", "Error cmt->dip2 is NULL"); + } + if (cmt->rak1 == NULL) + { + LOG_ERRMSG("%s", "Error cmt->rak1 is NULL"); + } + if (cmt->rak2 == NULL) + { + LOG_ERRMSG("%s", "Error cmt->rak2 is NULL"); + } + if (cmt->Mw == NULL) + { + LOG_ERRMSG("%s", "Error Mw is NULL"); + } + if (cmt->srcDepths == NULL) + { + LOG_ERRMSG("%s", "Error srcDepths is NULL"); + } + if (cmt->EN == NULL) + { + LOG_ERRMSG("%s", "Error EN is NULL"); + } + if (cmt->NN == NULL) + { + LOG_ERRMSG("%s", "Error NN is NULL"); + } + if (cmt->UN == NULL) + { + LOG_ERRMSG("%s", "Error UN is NULL"); + } + if (cmt->Einp == NULL) + { + LOG_ERRMSG("%s", "Error Einp is NULL"); + } + if (cmt->Ninp == NULL) + { + LOG_ERRMSG("%s", "Error Ninp is NULL"); + } + if (cmt->Uinp == NULL) + { + LOG_ERRMSG("%s", "Error Uinp is NULL"); + } + if (cmt->lsiteUsed == NULL) + { + LOG_ERRMSG("%s", "Error lsiteUsed is NULL"); + } + ierr = CMT_STRUCT_ERROR; + goto ERROR; + } + // Avoid a segfault + if (cmt->nsites != cmt_data.nsites) + { + LOG_ERRMSG("nsites on cmt and cmt_data differs %d %d\n", + cmt->nsites, cmt_data.nsites); + ierr = CMT_STRUCT_ERROR; + goto ERROR; + } +ERROR:; + return ierr; +} + diff --git a/src/eewUtils/driveFF.c b/src/eewUtils/driveFF.c new file mode 100644 index 00000000..9696c275 --- /dev/null +++ b/src/eewUtils/driveFF.c @@ -0,0 +1,521 @@ +#include +#include +#include +#include +#include +#include "gfast_eewUtils.h" +#include "gfast_core.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" + +static int __verify_ff_structs(struct GFAST_offsetData_struct ff_data, + struct GFAST_ffResults_struct *ff); +/*! + * @brief Drives the finite fault fault plane grid search inversion + * + * @param[in] ff_props finite fault inversion parameters + * @param[in] SA_lat event latitude (degrees) + * @param[in] SA_lon event longitude (degrees) + * @param[in] ff_data offset data for the finite fault inversion + * + * @param[in,out] ff on input contains space for the finite fault + * inversion as well as the fault strike and rake + * on all the nodal planes, and centroid depth + * in the inversion. + * on output contains the results of the finite + * fault inversion which includes slip along + * strike and slip down dip on each plane, + * uncertainties, and estimate data and observed data + * + * @result 0 indicates success. + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @date May 2016 + * + */ +int eewUtils_driveFF(struct GFAST_ff_props_struct ff_props, + const double SA_lat, + const double SA_lon, + struct GFAST_offsetData_struct ff_data, + struct GFAST_ffResults_struct *ff) +{ + double *dip, *dslip, *dslip_unc, *eOffset, *EN, *eWts, + *fault_xutm, *fault_yutm, *fault_alt, *length, + *Mw, *nOffset, *NN, *nWts, *sslip, *sslip_unc, *staAlt, + *strike, *uOffset, *utmRecvEasting, *utmRecvNorthing, + *UN, *uWts, *vr, *width, + wte, wtn, wtu, x1, x2, y1, y2; + int i, ierr, ierr1, if_off, ifp, io_off, k, l1, l2, + ndip, nfp, nstr, zone_loc; + bool *luse, lnorthp; + //------------------------------------------------------------------------// + // + // Initialize + ierr = FF_SUCCESS; + staAlt = NULL; + utmRecvEasting = NULL; + utmRecvNorthing = NULL; + uWts = NULL; + nWts = NULL; + eWts = NULL; + eOffset = NULL; + nOffset = NULL; + uOffset = NULL; + fault_xutm = NULL; + fault_yutm = NULL; + fault_alt = NULL; + length = NULL; + width = NULL; + strike = NULL; + dip = NULL; + sslip = NULL; + dslip = NULL; + Mw = NULL; + vr = NULL; + NN = NULL; + EN = NULL; + UN = NULL; + sslip_unc = NULL; + dslip_unc = NULL; + // Verify the input data structures + ierr = __verify_ff_structs(ff_data, ff); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error failed to verify data structures"); + goto ERROR; + } + // Initialize the result + nfp = ff->nfp; + nstr = ff->fp[0].nstr; + ndip = ff->fp[0].ndip; + l2 = nstr*ndip; + ff->preferred_fault_plane = 0; + for (ifp=0; ifpfp[ifp].fault_xutm); + array_zeros64f_work(l2, ff->fp[ifp].fault_yutm); + array_zeros64f_work(l2, ff->fp[ifp].fault_alt); + array_zeros64f_work(l2, ff->fp[ifp].strike); + array_zeros64f_work(l2, ff->fp[ifp].dip); + array_zeros64f_work(l2, ff->fp[ifp].length); + array_zeros64f_work(l2, ff->fp[ifp].width); + array_zeros64f_work(l2, ff->fp[ifp].sslip); + array_zeros64f_work(l2, ff->fp[ifp].dslip); + array_zeros64f_work(l2, ff->fp[ifp].sslip_unc); + array_zeros64f_work(l2, ff->fp[ifp].dslip_unc); + // Plotting information + array_zeros64f_work(4*l2, ff->fp[ifp].lon_vtx); + array_zeros64f_work(4*l2, ff->fp[ifp].lat_vtx); + array_zeros64f_work(4*l2, ff->fp[ifp].dep_vtx); + // Observations + array_zeros64f_work(ff->fp[ifp].maxobs, ff->fp[ifp].EN); + array_zeros64f_work(ff->fp[ifp].maxobs, ff->fp[ifp].NN); + array_zeros64f_work(ff->fp[ifp].maxobs, ff->fp[ifp].UN); + array_zeros64f_work(ff->fp[ifp].maxobs, ff->fp[ifp].Einp); + array_zeros64f_work(ff->fp[ifp].maxobs, ff->fp[ifp].Ninp); + array_zeros64f_work(ff->fp[ifp].maxobs, ff->fp[ifp].Uinp); + ff->fp[ifp].nsites_used = 0; + ff->Mw[ifp] = 0.0; + ff->vr[ifp] = 0.0; + } // Loop on fault planes + // Require there is a sufficient amount of data to invert + luse = memory_calloc8l(ff_data.nsites); + l1 = 0; + for (k=0; k 1) + { + LOG_WARNMSG("Insufficient data to invert %d < %d\n", + l1, ff_props.min_sites); + } + ierr = FF_INSUFFICIENT_DATA; + goto ERROR; + } + // Set space + uOffset = memory_calloc64f(l1); + nOffset = memory_calloc64f(l1); + eOffset = memory_calloc64f(l1); + utmRecvEasting = memory_calloc64f(l1); + utmRecvNorthing = memory_calloc64f(l1); + staAlt = memory_calloc64f(l1); + uWts = memory_calloc64f(l1); + nWts = memory_calloc64f(l1); + eWts = memory_calloc64f(l1); + fault_xutm = memory_calloc64f(l2*nfp); + fault_yutm = memory_calloc64f(l2*nfp); + fault_alt = memory_calloc64f(l2*nfp); + length = memory_calloc64f(l2*nfp); + width = memory_calloc64f(l2*nfp); + strike = memory_calloc64f(l2*nfp); + dip = memory_calloc64f(l2*nfp); + sslip = memory_calloc64f(l2*nfp); + dslip = memory_calloc64f(l2*nfp); + Mw = memory_calloc64f(nfp); + vr = memory_calloc64f(nfp); + NN = memory_calloc64f(l1*nfp); + EN = memory_calloc64f(l1*nfp); + UN = memory_calloc64f(l1*nfp); + sslip_unc = memory_calloc64f(l2*nfp); + dslip_unc = memory_calloc64f(l2*nfp); + // Get the source location + zone_loc = ff_props.utm_zone; // Use input UTM zone + if (zone_loc ==-12345){zone_loc =-1;} // Figure it out + core_coordtools_ll2utm(SA_lat, SA_lon, + &y1, &x1, + &lnorthp, &zone_loc); + // Get cartesian positions and observations onto local arrays + l1 = 0; + for (k=0; k 2) + { + LOG_DEBUGMSG("%s", "Meshing fault plane..."); + } +#ifdef PARALLEL_FF + #pragma omp parallel for \ + private(ierr1, ifp) \ + shared(ff, ff_props, zone_loc) \ + reduction(+:ierr) default(none) +#endif + for (ifp=0; ifpnfp; ifp++) + { + ierr1 = core_ff_meshFaultPlane(ff->SA_lat, ff->SA_lon, ff->SA_dep, + ff_props.flen_pct, + ff_props.fwid_pct, + ff->SA_mag, ff->str[ifp], ff->dip[ifp], + ff->fp[ifp].nstr, ff->fp[ifp].ndip, + zone_loc, ff_props.verbose, + ff->fp[ifp].fault_ptr, + ff->fp[ifp].lat_vtx, + ff->fp[ifp].lon_vtx, + ff->fp[ifp].dep_vtx, + ff->fp[ifp].fault_xutm, + ff->fp[ifp].fault_yutm, + ff->fp[ifp].fault_alt, + ff->fp[ifp].strike, + ff->fp[ifp].dip, + ff->fp[ifp].length, + ff->fp[ifp].width); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error meshing fault plane"); + ierr = ierr + 1; + continue; + } + } // Loop on fault planes + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error meshing fault planes!"); + goto ERROR; + } + //------------------------------ Inversion -------------------------------// + // Map the fault planes to the meshes arrays + for (ifp=0; ifpfp[ifp].fault_xutm[i]; + fault_yutm[if_off+i] = ff->fp[ifp].fault_yutm[i]; + fault_alt[if_off+i] = ff->fp[ifp].fault_alt[i]; + length[if_off+i] = ff->fp[ifp].length[i]; + width[if_off+i] = ff->fp[ifp].width[i]; + strike[if_off+i] = ff->fp[ifp].strike[i]; + dip[if_off+i] = ff->fp[ifp].dip[i]; + } + } + // Let user know an inversion is about to happen + if (ff_props.verbose > 2) + { + LOG_DEBUGMSG("Inverting for slip on %d planes with %d sites", + nfp, l1); + } + // Perform the finite fault inversion + ierr = core_ff_faultPlaneGridSearch(l1, l2, + nstr, ndip, nfp, + ff_props.verbose, + nOffset, eOffset, uOffset, + nWts, eWts, uWts, + utmRecvEasting, utmRecvNorthing, + staAlt, + fault_xutm, fault_yutm, fault_alt, + length, width, + strike, dip, + sslip, dslip, + Mw, vr, + NN, EN, UN, + sslip_unc, dslip_unc); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error performing finite fault grid search"); + goto ERROR; + } + //----------------------------Extract the Results-------------------------// + // Unpack results onto struture and choose a preferred plane + ff->preferred_fault_plane = 0; + for (ifp=0; ifpfp[ifp].sslip[i] = sslip[if_off+i]; + ff->fp[ifp].dslip[i] = dslip[if_off+i]; + ff->fp[ifp].sslip_unc[i] = sslip_unc[if_off+i]; + ff->fp[ifp].dslip_unc[i] = dslip_unc[if_off+i]; + } + // Observations + i = 0; + for (k=0; kfp[ifp].maxobs; k++) + { + if (luse[k]) + { + ff->fp[ifp].EN[k] = EN[io_off+i]; + ff->fp[ifp].NN[k] = NN[io_off+i]; + ff->fp[ifp].UN[k] = UN[io_off+i]; + ff->fp[ifp].Einp[k] = eOffset[i]; + ff->fp[ifp].Ninp[k] = nOffset[i]; + ff->fp[ifp].Uinp[k] = uOffset[i]; + i = i + 1; + } + } + ff->fp[ifp].nsites_used = i; + ff->Mw[ifp] = Mw[ifp]; // moment magnitude + ff->vr[ifp] = vr[ifp]; // variance reduction + // Preferred fault plane has greatest variance reduction + if (ff->vr[ifp] > ff->vr[ff->preferred_fault_plane]) + { + ff->preferred_fault_plane = ifp; + } + } // Loop on fault planes +ERROR:; + memory_free8l(&luse); + memory_free64f(&uOffset); + memory_free64f(&nOffset); + memory_free64f(&eOffset); + memory_free64f(&utmRecvEasting); + memory_free64f(&utmRecvNorthing); + memory_free64f(&staAlt); + memory_free64f(&nWts); + memory_free64f(&eWts); + memory_free64f(&uWts); + memory_free64f(&fault_xutm); + memory_free64f(&fault_yutm); + memory_free64f(&fault_alt); + memory_free64f(&length); + memory_free64f(&width); + memory_free64f(&strike); + memory_free64f(&dip); + memory_free64f(&sslip); + memory_free64f(&dslip); + memory_free64f(&Mw); + memory_free64f(&vr); + memory_free64f(&NN); + memory_free64f(&EN); + memory_free64f(&UN); + memory_free64f(&sslip_unc); + memory_free64f(&dslip_unc); + return ierr; +} +//============================================================================// +/*! + * @brief Utility function for verifying input data structures + * + * @param[in] ff_data ff_data structure to verify + * @param[in] ff ff results structure to verify + * + * @result FF_SUCCESS indicates input structures are ready for use + * + * @author Ben Baker (ISTI) + * + */ +static int __verify_ff_structs(struct GFAST_offsetData_struct ff_data, + struct GFAST_ffResults_struct *ff) +{ + int ierr, ifp; + ierr = FF_SUCCESS; + if (ff_data.nsites < 1) + { + ierr = FF_OS_DATA_ERROR; + LOG_ERRMSG("%s", "No peak displacement data"); + goto ERROR; + } + // Verify the output data structures + if (ff->nfp < 1) + { + LOG_ERRMSG("%s", "No fault planes in fault plane gridsearch!"); + ierr = FF_STRUCT_ERROR; + goto ERROR; + } + if (ff->fp == NULL || ff->vr == NULL || ff->Mw == NULL || + ff->str == NULL || ff->dip == NULL) + { + if (ff->fp == NULL) + { + LOG_ERRMSG("%s", "Error fault plane is NULL"); + } + if (ff->vr == NULL) + { + LOG_ERRMSG("%s", "Error ff->vr is NULL"); + } + if (ff->Mw == NULL) + { + LOG_ERRMSG("%s", "Error ff->Mw is NULL"); + } + if (ff->str == NULL) + { + LOG_ERRMSG("%s", "Error ff->str is NULL"); + } + if (ff->dip == NULL) + { + LOG_ERRMSG("%s", "Error ff->dip is NULL"); + } + ierr = FF_STRUCT_ERROR; + goto ERROR; + } + // Loop on fault planes and check each fp structure + for (ifp=0; ifpnfp; ifp++) + { + if (ff->fp[ifp].nstr != ff->fp[0].nstr) + { + LOG_ERRMSG("%s", "Error inconsistent number of strike patches"); + ierr = FF_STRUCT_ERROR; + } + if (ff->fp[ifp].ndip != ff->fp[0].ndip) + { + LOG_ERRMSG("%s", "Error inconsistent number of dip patches"); + ierr = FF_STRUCT_ERROR; + } + if (ff->fp[ifp].lon_vtx == NULL || + ff->fp[ifp].lat_vtx == NULL || + ff->fp[ifp].dep_vtx == NULL || + ff->fp[ifp].fault_xutm == NULL || + ff->fp[ifp].fault_yutm == NULL || + ff->fp[ifp].fault_alt == NULL || + ff->fp[ifp].strike == NULL || + ff->fp[ifp].dip == NULL || + ff->fp[ifp].length == NULL || + ff->fp[ifp].width == NULL || + ff->fp[ifp].sslip == NULL || + ff->fp[ifp].dslip == NULL || + ff->fp[ifp].sslip_unc == NULL || + ff->fp[ifp].dslip_unc == NULL) + { + if (ff->fp[ifp].lon_vtx == NULL) + { + LOG_ERRMSG("Error lon_vtx null on ifp %d", ifp+1); + } + if (ff->fp[ifp].lat_vtx == NULL) + { + LOG_ERRMSG("Error lat_vtx null on ifp %d", ifp+1); + } + if (ff->fp[ifp].dep_vtx == NULL) + { + LOG_ERRMSG("Error dep_vtx null on ifp %d", ifp+1); + } + if (ff->fp[ifp].fault_xutm == NULL) + { + LOG_ERRMSG(" Error fault_xutm null on ifp %d", ifp+1); + } + if (ff->fp[ifp].fault_yutm == NULL) + { + LOG_ERRMSG("Error fault_xutm null on ifp %d", ifp+1); + } + if (ff->fp[ifp].fault_alt == NULL) + { + LOG_ERRMSG("Error fault_alt null on ifp %d", ifp+1); + } + if (ff->fp[ifp].strike == NULL) + { + LOG_ERRMSG("Error strike null on ifp %d", ifp+1); + } + if (ff->fp[ifp].dip == NULL) + { + LOG_ERRMSG("Error dip null on ifp %d", ifp+1); + } + if (ff->fp[ifp].length == NULL) + { + LOG_ERRMSG("Error length null on ifp %d", ifp+1); + } + if (ff->fp[ifp].width == NULL) + { + LOG_ERRMSG("Error width null on ifp %d", ifp+1); + } + if (ff->fp[ifp].sslip == NULL) + { + LOG_ERRMSG("Error sslip null on ifp %d", ifp+1); + } + if (ff->fp[ifp].dslip == NULL) + { + LOG_ERRMSG("Error dslip null on ifp %d", ifp+1); + } + if (ff->fp[ifp].sslip_unc == NULL) + { + LOG_ERRMSG("Error sslip_unc null on ifp %d", ifp+1); + } + if (ff->fp[ifp].dslip_unc == NULL) + { + LOG_ERRMSG("Error dslip_unc null on ifp %d", ifp+1); + } + LOG_ERRMSG("Error fp %d is invalid\n", ifp+1); + ierr = FF_STRUCT_ERROR; + goto ERROR; + } + } // Loop on fault planes + // Avoid a segfault + for (ifp=0; ifpnfp; ifp++) + { + if (ff->fp[ifp].maxobs != ff_data.nsites) + { + LOG_ERRMSG("nsites on ff and ff_data differs %d %d", + ff->fp[ifp].maxobs, ff_data.nsites); + ierr = FF_STRUCT_ERROR; + goto ERROR; + } + } +ERROR:; + return ierr; +} diff --git a/src/eewUtils/driveGFAST.c b/src/eewUtils/driveGFAST.c new file mode 100644 index 00000000..a034351b --- /dev/null +++ b/src/eewUtils/driveGFAST.c @@ -0,0 +1,913 @@ +#include +#include +#include +#include +#include +#include "gfast.h" +#include "gfast_core.h" +#include "gfast_eewUtils.h" +#include "gfast_hdf5.h" +#include "gfast_traceBuffer.h" +#include "dmlibWrapper.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" +#include "iscl/time/time.h" + +/*! + * @brief writes xml message to flat file + * Need to poke at this more. + * @param[in] dirname output directory + * @param[in] eventid + * @param[in] msg_type message type + * @param[in] message xml message + * @param[in] interval write interval + * @param[in] interval_in_mins is interval in minutes? + * @return status code. + */ + +int eewUtils_writeXML(const char *dirname, const char *eventid, const char *msg_type, const char *message, int interval, bool interval_in_mins); + +bool check_mins_against_intervals(struct GFAST_props_struct props, + int mins, + char * eventid, + char * suffix, + char * xml, + bool * interval_complete, + double age); + +/*! + * @brief Fills a given coreInfo_struct with the appropriate information + * @param[in] evid Event ID + * @param[in] version Event version number + * @param[in] SA_lat Event latitude + * @param[in] SA_lon Event longitude + * @param[in] SA_depth Event depth + * @param[in] SA_mag Event magnitude + * @param[in] SA_time Event origin time (UTC) + * @param[in] num_stations Number of stations contributing + * @param[out] core struct to fill with information + * @return status code. + */ +int fill_core_event_info(const char *evid, + const int version, + const double SA_lat, + const double SA_lon, + const double SA_depth, + const double SA_mag, + const double SA_time, + const int num_stations, + struct coreInfo_struct *core); + +bool send_xml_filter(const struct GFAST_props_struct *props, + const struct GFAST_shakeAlert_struct *SA, + const struct GFAST_pgdResults_struct *pgd, + const struct GFAST_peakDisplacementData_struct *pgd_data, + const struct coreInfo_struct *core, + const double age_of_event); + +/*! + * @brief Expert earthquake early warning GFAST driver. + * + * @param[in] currentTime Current epochal time (UTC seconds) + * @param[in] props Holds the GFAST properties. + * @param[in] program_instance Program instance name (e.g. gfast_eew at eew-uw-dev1) + * @param[in,out] events The input event list. If there are no + * events this function will immediately return. + * On output, if an event has expired then it + * will be popped from the list. + * @param[in,out] gps_data Holds the GPS streams to be used in the + * inversions. + * @param[in,out] h5traceBuffer Holds the requisite information for reading. + * @param[in,out] pgd_data Workspace for the PGD data in the PGD + * inversion. + * @param[in,out] cmt_data Workspace for the offset data in the CMT + * inversion. + * @param[in,out] ff_data Workspace for the offset data in the finite + * fault inversion. + * @param[in,out] pgd Workspace for the PGD inversion. + * @param[in,out] cmt Workspace for the CMT inversion. + * @param[in,out] ff Workspace for the finite fault inversion. + * + * @param[out] xmlMessages Contains the XML messages for all events for + * the PGD and finite fault for activeMQ to + * forward onto shakeAlert as well as the CMT + * quakeML. + * @param[in,out] xml_status On input holds current active events and the + * previous message versions. On output, holds the + * updated message versions. + * + * @result 0 indicates success. + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + */ +int eewUtils_driveGFAST(const double currentTime, + const char *program_instance, + struct GFAST_props_struct props, + struct GFAST_activeEvents_struct *events, + struct GFAST_data_struct *gps_data, + struct h5traceBuffer_struct *h5traceBuffer, + struct GFAST_peakDisplacementData_struct *pgd_data, + struct GFAST_offsetData_struct *cmt_data, + struct GFAST_offsetData_struct *ff_data, + struct GFAST_pgdResults_struct *pgd, + struct GFAST_cmtResults_struct *cmt, + struct GFAST_ffResults_struct *ff, + struct GFAST_xmlMessages_struct *xmlMessages, + struct GFAST_activeEvents_xml_status *xml_status) +{ + struct GFAST_shakeAlert_struct SA; + // char errorLogFileName[PATH_MAX], infoLogFileName[PATH_MAX], + // debugLogFileName[PATH_MAX], warnLogFileName[PATH_MAX]; + char *cmtQML, *ffXML, *pgdXML; + double t1, t2, age_of_event, t_time, t_time0, t_loop, t_event; + int mins; + float secs; + int h5k, ierr, iev, ipf, nPop, nRemoved, + nsites_cmt, nsites_ff, nsites_pgd, + nstrdip, pgdOpt; + bool lcmtSuccess, lffSuccess, lfinalize, lpgdSuccess; + + const char *fcnm = "driveGFAST\0"; + //------------------------------------------------------------------------// + // + // Nothing to do + ierr = 0; + if (events->nev <= 0){return 0;} + + // Set memory for XML messages + memset(xmlMessages, 0, sizeof(struct GFAST_xmlMessages_struct)); + xmlMessages->mmessages = events->nev; + xmlMessages->nmessages = 0; + xmlMessages->evids = (char **) + calloc((size_t) xmlMessages->mmessages, sizeof(char *)); + xmlMessages->cmtQML = (char **) + calloc((size_t) xmlMessages->mmessages, sizeof(char *)); + xmlMessages->ffXML = (char **) + calloc((size_t) xmlMessages->mmessages, sizeof(char *)); + xmlMessages->pgdXML = (char **) + calloc((size_t) xmlMessages->mmessages, sizeof(char *)); + nPop = 0; + t_loop = time_timeStamp(); + /////////////////////////////////////////////////////////////////////////// + // Loop on the events + /////////////////////////////////////////////////////////////////////////// + for (iev=0; ievnev; iev++) { + t_event = time_timeStamp(); + // Get the streams for this event + memcpy(&SA, &events->SA[iev], sizeof(struct GFAST_shakeAlert_struct)); + t1 = SA.time; // Origin time + t2 = currentTime; + age_of_event = (t2 - t1); + LOG_MSG("%s: Starting event time:%lf evid:%s [age_of_event=%f]", + fcnm, t2, SA.eventid, age_of_event); + + // Skip event if the times doen't make sense + if (t1 > t2) { + LOG_WARNMSG("Origin time > currentTime? - skipping event %s [Timing: %.3fs for event]", + SA.eventid, time_timeStamp() - t_event); + continue; + } + + // Used for determining when to output results (if props.output_interval_mins[0] != 0) + mins = (int)floor(age_of_event/60.); + secs = age_of_event - 60.*mins; + + lfinalize = false; + // Exit processing this event if it is beyond the processing time + if (age_of_event >= props.processingTime) { + LOG_MSG("%s: time:%lf evid:%s has expired --> finalize [Timing: %.3fs for event]", + fcnm, t2, SA.eventid, time_timeStamp() - t_event); + nPop = nPop + 1; + lfinalize = true; + // LOG_MSG("%s: Call core_log_closeLogs() before early exit from loop", + // fcnm); + // core_log_closeLogs(); + continue; + } + + // Set the log file names. Comment out in advance of providing compile + // option to use these (for NOAA) or plog (for ShakeAlert) - CWU + // eewUtils_setLogFileNames(SA.eventid,props.SAoutputDir, + // errorLogFileName, infoLogFileName, + // debugLogFileName, warnLogFileName); + // core_log_openErrorLog(errorLogFileName); + // core_log_openInfoLog(infoLogFileName); + // core_log_openWarningLog(warnLogFileName); + // core_log_openDebugLog(debugLogFileName); + + /////////////////////////////////////////////////////////////////////////// + // Retrieve data from h5 buffer + /////////////////////////////////////////////////////////////////////////// + t_time0 = time_timeStamp(); + // Get the data for this event + ierr = GFAST_traceBuffer_h5_getData(t1, t2, h5traceBuffer); + if (ierr != 0) { + LOG_ERRMSG("%s: Error getting the data for event %s --> continue [Timing: %.3fs for event]", + fcnm, SA.eventid, time_timeStamp() - t_event); + continue; + } + // Copy the data onto the buffer + ierr = GFAST_traceBuffer_h5_copyTraceBufferToGFAST(h5traceBuffer, gps_data); + if (ierr != 0) { + LOG_ERRMSG("Error copying trace buffer, evid %s [Timing: %.3fs for event]", + SA.eventid, time_timeStamp() - t_event); + continue; + } + LOG_DEBUGMSG("Buffer handling [Timing: %.3fs]", time_timeStamp() - t_time0); + // End data buffer handling + + /////////////////////////////////////////////////////////////////////////// + // Extract pgd, cmt, ff values + /////////////////////////////////////////////////////////////////////////// + t_time0 = time_timeStamp(); + if (props.pgd_props.do_pgd) { + LOG_MSG("%s", "Get peakDisp"); + t_time = time_timeStamp(); + // Extract the peak displacement from the waveform buffer + nsites_pgd = GFAST_core_waveformProcessor_peakDisplacement( + &(props.pgd_props), + SA.lat, + SA.lon, + SA.dep, + SA.time, + *gps_data, + pgd_data, + &ierr); + LOG_MSG("%s returned ierr=%d nsites_pgd=%d [Timing: %.3fs]", "Get peakDisp", ierr, + nsites_pgd, time_timeStamp() - t_time); + if (ierr != 0) { + LOG_ERRMSG("Error processing peak displacement [Timing: %.3fs for event]", + time_timeStamp() - t_event); + continue; + } + } else { + LOG_MSG("%s", "Skipping PGD processing - do_pgd is false"); + } + if (props.cmt_props.do_cmt) { + LOG_MSG("%s", "Get Offset for CMT"); + t_time = time_timeStamp(); + // Extract the offset for the CMT inversion from the buffer + nsites_cmt = GFAST_core_waveformProcessor_offset( + props.cmt_props.utm_zone, + props.cmt_props.window_vel, + SA.lat, + SA.lon, + SA.dep, + SA.time, + *gps_data, + cmt_data, + &ierr); + LOG_MSG("%s returned ierr=%d nsites_cmt=%d [Timing: %.3fs]", "Get Offset for CMT", ierr, + nsites_cmt, time_timeStamp() - t_time); + if (ierr != 0) { + LOG_ERRMSG("Error processing CMT offset [Timing: %.3fs for event]", + time_timeStamp() - t_event); + continue; + } + } else { + LOG_MSG("%s", "Skipping CMT processing - do_cmt is false"); + } + if (props.ff_props.do_ff) { + LOG_MSG("%s", "Get Offset for FF"); + t_time = time_timeStamp(); + // Extract the offset for the FF inversion from the buffer + nsites_ff = GFAST_core_waveformProcessor_offset( + props.ff_props.utm_zone, + props.ff_props.window_vel, + SA.lat, + SA.lon, + SA.dep, + SA.time, + *gps_data, + ff_data, + &ierr); + LOG_MSG("%s returned ierr=%d nsites_ff=%d [Timing: %.3fs]", "Get Offset for FF", ierr, + nsites_ff, time_timeStamp() - t_time); + if (ierr != 0) { + LOG_ERRMSG("Error processing FF offset [Timing: %.3fs for event]", + time_timeStamp() - t_event); + continue; + } + } else { + LOG_MSG("%s", "Skipping FF processing - do_ff is false"); + } + LOG_DEBUGMSG("Value extractions [Timing: %.3fs]", time_timeStamp() - t_time0); + // End value extraction + + /////////////////////////////////////////////////////////////////////////// + // Run pgd, cmt, ff inversions + /////////////////////////////////////////////////////////////////////////// + lpgdSuccess = false; + lcmtSuccess = false; + lffSuccess = false; + t_time0 = time_timeStamp(); + // Run the PGD scaling + if (props.pgd_props.do_pgd && + nsites_pgd >= props.pgd_props.min_sites) + { + if (props.verbose > 2) { + LOG_INFOMSG("Estimating PGD scaling for %s...", SA.eventid); + } + lpgdSuccess = true; + LOG_MSG("Call drivePGD eventid=%s", SA.eventid); + t_time = time_timeStamp(); + ierr = eewUtils_drivePGD(props.pgd_props, + SA.lat, SA.lon, SA.dep, age_of_event, + *pgd_data, + pgd); + LOG_MSG("drivePGD returned ierr=%d [Timing: %.3fs]", + ierr, time_timeStamp() - t_time); + if (ierr != PGD_SUCCESS) { + LOG_ERRMSG("%s", "Error computing PGD"); + lpgdSuccess = false; + } + } + // Run the CMT inversion + if (props.cmt_props.do_cmt && + nsites_cmt >= props.cmt_props.min_sites) + { + if (props.verbose > 2) { + LOG_INFOMSG("Estimating CMT for %s...", SA.eventid); + } + lcmtSuccess = true; + LOG_MSG("%s", "calling driveCMT"); + t_time = time_timeStamp(); + ierr = eewUtils_driveCMT(props.cmt_props, + SA.lat, SA.lon, SA.dep, + *cmt_data, + cmt); + LOG_MSG("driveCMT returned ierr=%d [Timing: %.3fs]", + ierr, time_timeStamp() - t_time); + if (ierr != CMT_SUCCESS || cmt->opt_indx < 0) { + LOG_ERRMSG("%s", "Error computing CMT"); + lcmtSuccess = false; + } + } + // If we got a CMT see if we can run a finite fault inversion + if (props.ff_props.do_ff && + lcmtSuccess && + nsites_ff >= props.ff_props.min_sites) + { + if (props.verbose > 2) { + LOG_INFOMSG("Estimating finite fault for %s...", SA.eventid); + } + ff->SA_lat = events->SA[iev].lat; + ff->SA_lon = events->SA[iev].lon; + ff->SA_dep = cmt->srcDepths[cmt->opt_indx]; // TODO make cmt->opt_dep + ff->SA_mag = cmt->Mw[cmt->opt_indx]; + ff->str[0] = cmt->str1[cmt->opt_indx]; + ff->str[1] = cmt->str2[cmt->opt_indx]; + ff->dip[0] = cmt->dip1[cmt->opt_indx]; + ff->dip[1] = cmt->dip2[cmt->opt_indx]; + lffSuccess = true; + LOG_MSG("%s", "calling driveFF"); + t_time = time_timeStamp(); + ierr = eewUtils_driveFF(props.ff_props, + SA.lat, + SA.lon, + *ff_data, + ff); + LOG_MSG("driveFF returned ierr=%d [Timing: %.3fs]", + ierr, time_timeStamp() - t_time); + if (ierr != FF_SUCCESS) { + LOG_ERRMSG("%s", "Error computing finite fault"); + lffSuccess = false; + } + } + LOG_DEBUGMSG("Inversions [Timing: %.3fs]", time_timeStamp() - t_time0); + // End inversions + + // Finalize? + pgdXML = NULL; + cmtQML = NULL; + ffXML = NULL; + + // anticipate last iteration so that data are archived to h5 + if (t2 - t1 >= props.processingTime - props.dt_default) { + lfinalize = true; + } + + /////////////////////////////////////////////////////////////////////////// + // Make xml messages + /////////////////////////////////////////////////////////////////////////// + t_time0 = time_timeStamp(); + LOG_MSG("driveGFAST: make XML msgs: lpgdSuccess=%d lcmtSuccess=%d lffSuccess=%d", + lpgdSuccess, lcmtSuccess, lffSuccess); + xml_status->SA_status[iev].version += 1; + char *message_type = (xml_status->SA_status[iev].version==0)?"new\0":"update\0"; + char sversion[6]; + snprintf(sversion,6,"%d",xml_status->SA_status[iev].version); + + // Fill coreInfo_struct to pass to makeXML for pgd and ff + struct coreInfo_struct core; + memset(&core, 0, sizeof(struct coreInfo_struct)); + ierr = fill_core_event_info(SA.eventid, xml_status->SA_status[iev].version, SA.lat, + SA.lon, SA.dep, SA.mag, SA.time, 0, &core); + + // Make the PGD xml + if (props.pgd_props.do_pgd && lpgdSuccess) { + if (props.verbose > 2) { + LOG_DEBUGMSG("%s", "Generating pgd XML"); + } + // Change depth, mag to match optimal pgd (by variance reduction) + pgdOpt = array_argmax64f(pgd->ndeps, pgd->dep_vr_pgd, &ierr); + core.depth = pgd->srcDepths[pgdOpt]; + core.mag = pgd->mpgd[pgdOpt]; + core.magUncer = pgd->mpgd_sigma[pgdOpt]; + core.numStations = nsites_pgd; + +#ifdef GFAST_USE_DMLIB + // Encode xml with dmlib + LOG_MSG("%s", "driveGFAST: CWU_TEST dmlib encoding"); + pgdXML = dmlibWrapper_createPGDXML( + props.opmode, + GFAST_VERSION, + program_instance, + message_type, + props.pgd_props.max_assoc_stations, + &core, + pgd, + pgd_data, + &ierr); +#else + pgdXML = eewUtils_makeXML__pgd( + props.opmode, + "GFAST\0", + GFAST_VERSION, + program_instance, + message_type, + sversion, + &core, + &ierr); +#endif + if (ierr != 0) { + LOG_ERRMSG("%s", "Error generating PGD XML"); + if (pgdXML != NULL) { + free(pgdXML); + pgdXML = NULL; + } + } + xmlMessages->pgdXML[xmlMessages->nmessages] = pgdXML; + + // MTH: This is just a sanity check, could be done anywhere: + if (strcmp(SA.eventid, xml_status->SA_status[iev].eventid) != 0) { + LOG_WARNMSG("Mismatch between SA.eventid=%s and xml_status.SA_status[%d].eventid=%s --> Can't output PGD!\n", + SA.eventid, iev, xml_status->SA_status[iev].eventid); + } + +#if defined GFAST_USE_AMQ && defined GFAST_USE_DMLIB + // Send message via ActiveMQ if appropriate + if (!send_xml_filter(&props, &SA, pgd, pgd_data, &core, age_of_event)) { + if (pgdXML != NULL) { + sendEventXML(pgdXML); + } + LOG_MSG("== Sending xml, [GFAST t0:%f] evid:%s pgdXML=[%s]\n", + currentTime, SA.eventid, pgdXML); + } +#endif /* GFAST_USE_AMQ && GFAST_USE_DMLIB */ + + if (props.output_interval_mins[0] == 0) { // Output at every iteration + int index = core.version; + ierr = eewUtils_writeXML( + props.SAoutputDir, SA.eventid, "pgd", pgdXML, index, false); + LOG_MSG("writeXML for PGD returned ierr=%d", ierr); + } else if (secs < 3.) { + LOG_MSG("eventid:%s age:%f mins:%d secs:%f --> check PGD writeXML", + SA.eventid, age_of_event, mins, secs); + check_mins_against_intervals(props, mins, SA.eventid, "pgd", pgdXML, + xml_status->SA_status[iev].interval_complete[0], age_of_event); + } + LOG_MSG("Leaving PGD writeXML ierr=%d", ierr); + } //if props.pgd_props.do_pgd && lpgdSuccess + + // Make the CMT quakeML + if (props.cmt_props.do_cmt && lcmtSuccess) { + if (props.verbose > 2) { + LOG_DEBUGMSG("%s", "Generating CMT QuakeML"); + } + cmtQML = eewUtils_makeXML__quakeML( + props.anssNetwork, + props.anssDomain, + SA.eventid, + SA.lat, + SA.lon, + cmt->srcDepths[cmt->opt_indx], + SA.time, + &cmt->mts[6*cmt->opt_indx], + &ierr); + if (ierr != 0) { + LOG_ERRMSG("%s", "Error generating CMT quakeML"); + if (cmtQML != NULL) { + free(cmtQML); + cmtQML = NULL; + } + } + xmlMessages->cmtQML[xmlMessages->nmessages] = cmtQML; + if (props.output_interval_mins[0] == 0) { // Output at every iteration + int index = core.version; + LOG_MSG("Age_of_event=%f --> Output CMT solution at iter:%d", + age_of_event, index); + ierr = eewUtils_writeXML(props.SAoutputDir, SA.eventid, "cmt", + cmtQML, index, false); + } else if (secs < 3.) { + LOG_MSG("eventid:%s age:%f mins:%d secs:%f --> check CMT writeXML", + SA.eventid, age_of_event, mins, secs); + check_mins_against_intervals(props, mins, SA.eventid, "cmt", cmtQML, + xml_status->SA_status[iev].interval_complete[1], age_of_event); + } + } // if props.cmt_props.do_cmt && lcmtSuccess + // Make the finite fault XML + if (props.ff_props.do_ff && lffSuccess) { + if (props.verbose > 2) { + LOG_DEBUGMSG("Generating FF XML; preferred plane=%d", + ff->preferred_fault_plane+1); + } + ipf = ff->preferred_fault_plane; + nstrdip = ff->fp[ipf].nstr*ff->fp[ipf].ndip; + // Reset depth and mag to be same as SA message. + core.depth = SA.dep; + core.mag = SA.mag; + core.magUncer = 0.5; + core.numStations = nsites_ff; + ffXML = eewUtils_makeXML__ff( + props.opmode, + "GFAST\0", + GFAST_VERSION, + program_instance, + message_type, + sversion, + &core, + nstrdip, + ff->fp[ipf].fault_ptr, + ff->fp[ipf].lat_vtx, + ff->fp[ipf].lon_vtx, + ff->fp[ipf].dep_vtx, + ff->fp[ipf].strike, + ff->fp[ipf].dip, + ff->fp[ipf].sslip, + ff->fp[ipf].dslip, + ff->fp[ipf].sslip_unc, + ff->fp[ipf].dslip_unc, + &ierr); + if (ierr != 0) { + LOG_ERRMSG("%s", "Error generating finite fault XML"); + if (ffXML != NULL) { + free(ffXML); + ffXML = NULL; + } + } + xmlMessages->ffXML[xmlMessages->nmessages] = ffXML; + if (props.output_interval_mins[0] == 0) { // Output at every iteration + int index = core.version; + LOG_MSG("Age_of_event=%f --> Output FF solution at iter:%d", + age_of_event, index); + ierr = eewUtils_writeXML(props.SAoutputDir, SA.eventid, "ff", + ffXML, index, false); + } else if (secs < 3.) { + LOG_MSG("eventid:%s age:%f mins:%d secs:%f --> check FF writeXML", + SA.eventid, age_of_event, mins, secs); + check_mins_against_intervals(props, mins, SA.eventid, "ff", ffXML, + xml_status->SA_status[iev].interval_complete[2], age_of_event); + } + } // if props.ff_props.do_ff && lffSuccess + xmlMessages->evids[xmlMessages->nmessages] = (char *) + calloc(strlen(SA.eventid)+1, sizeof(char)); + strcpy(xmlMessages->evids[xmlMessages->nmessages], SA.eventid); + xmlMessages->nmessages = xmlMessages->nmessages + 1; + + LOG_MSG("Leaving writeXML ierr=%d lfinalize=%d [Timing: %.3fs]", + ierr, lfinalize, time_timeStamp() - t_time0); + // End make xmls + + /////////////////////////////////////////////////////////////////////////// + // Update the archive + /////////////////////////////////////////////////////////////////////////// + if (lfinalize || !props.lh5SummaryOnly) { + // Get the iteration number in the H5 file + h5k = 0; + h5k = GFAST_hdf5_updateGetIteration( + props.h5ArchiveDir, + SA.eventid, + currentTime); + LOG_MSG("time:%lf evid:%s h5k iteration=%d dir=%s Update h5 archive", + t2, SA.eventid, h5k, props.h5ArchiveDir); + if (props.verbose > 2) { + LOG_DEBUGMSG("Writing GPS data for iteration %d", h5k); + } + ierr = GFAST_hdf5_update_gpsData( + props.h5ArchiveDir, + SA.eventid, + h5k, + *gps_data); + LOG_MSG("update gpsData for iteration:%d returned ierr=%d", h5k, ierr); + if (props.verbose > 2) { + LOG_DEBUGMSG("Writing hypocenter for iteration %d", h5k); + } + ierr = GFAST_hdf5_updateHypocenter( + props.h5ArchiveDir, + SA.eventid, + h5k, + SA); + LOG_MSG("updateHypocenter for iteration:%d returned ierr=%d", h5k, ierr); + if (props.pgd_props.do_pgd && lpgdSuccess) { + if (props.verbose > 2) { + LOG_DEBUGMSG("Writing PGD for iteration %d", h5k); + } + ierr = GFAST_hdf5_updatePGD( + props.h5ArchiveDir, + SA.eventid, + h5k, + *pgd_data, + *pgd); + if (pgdXML) { + ierr = hdf5_updateXMLMessage( + props.h5ArchiveDir, + SA.eventid, + h5k, "pgdXML\0", + pgdXML); + } + } + if (props.cmt_props.do_cmt && lcmtSuccess) { + if (props.verbose > 2) { + LOG_DEBUGMSG("Writing CMT for iteration %d", h5k); + } + ierr = GFAST_hdf5_updateCMT( + props.h5ArchiveDir, + SA.eventid, + h5k, + *cmt_data, + *cmt); + if (cmtQML) { + ierr = hdf5_updateXMLMessage( + props.h5ArchiveDir, + SA.eventid, + h5k, "cmtQuakeML\0", + cmtQML); + } + } + if (props.ff_props.do_ff && lffSuccess) { + if (props.verbose > 2) { + LOG_DEBUGMSG("Writing FF for iteration %d", h5k); + } + ierr = GFAST_hdf5_updateFF( + props.h5ArchiveDir, + SA.eventid, + h5k, + *ff); + if (ffXML) { + ierr = hdf5_updateXMLMessage( + props.h5ArchiveDir, + SA.eventid, + h5k, "ffXML\0", + ffXML); + } + } + } // End check on updating archive or finalizing event + // Close the logs + // core_log_closeLogs(); + } // Loop on the events + LOG_MSG("MTH: end loop on events ierr=%d [Timing: %.3fs]\n", + ierr, time_timeStamp() - t_loop); + // Need to down-date the events should any have expired + if (nPop > 0) { + LOG_MSG("time:%lf RemoveExpiredEvents", currentTime); + nRemoved = core_events_removeExpiredEvents( + props.processingTime, + currentTime, + props.verbose, + events); + LOG_MSG("time:%lf syncXMLStatusWithEvents", currentTime); + core_events_syncXMLStatusWithEvents(events, xml_status); + LOG_MSG("time:%lf RemoveExpiredEvents nRemoved=%d", currentTime, nRemoved); + if (nRemoved != nPop) { + LOG_WARNMSG("%s", "Strange - check removeExpiredEvents"); + } + } + LOG_MSG("End driveGFAST time:%lf return ierr=%d", currentTime, ierr); + return ierr; +} + +#include +int eewUtils_writeXML(const char *dirname, + const char *eventid, + const char *msg_type, + const char *message, + int interval, + bool interval_in_mins) +{ + char fullpath[128]; + FILE * fp; + + if (interval_in_mins) { + sprintf(fullpath, "%s/%s.%s.%d_min", dirname, eventid, msg_type, interval); + LOG_MSG("driveGFAST: evid=%s SA xml mins=%d --> output XML to file=[%s]", + eventid, interval, fullpath); + } else { + sprintf(fullpath, "%s/%s.%s.%d", dirname, eventid, msg_type, interval); + LOG_MSG("driveGFAST: evid=%s interval=%d --> output XML to file=[%s]", + eventid, interval, fullpath); + } + + if (access( fullpath, F_OK ) != -1 ) { + LOG_MSG("File:%s already exists!\n", fullpath); + } + + fp = fopen(fullpath, "w"); + fprintf(fp, "%s\n", message); + fclose(fp); + + return 0; +} + +bool check_mins_against_intervals(struct GFAST_props_struct props, + int mins, + char * eventid, + char * suffix, + char * xml, + bool * interval_complete, + double age) +{ + int i, ierr; + + i = props.n_intervals - 1; + if (mins == props.output_interval_mins[i] && interval_complete[i] == false) { + LOG_MSG("Eventid:%s age_of_event:%f --> Output minute %d solution for suff:%s [FINAL MIN INTERVAL]", + eventid, age, props.output_interval_mins[i], suffix); + ierr = eewUtils_writeXML(props.SAoutputDir, eventid, suffix, xml, + props.output_interval_mins[i], true); + if (ierr!=0) LOG_MSG("%s: ierr=%d from eewUtils_writeXML()",__func__,ierr); + interval_complete[i] = true; + return true; + } + + for (i=0; i= props.output_interval_mins[i] && mins < props.output_interval_mins[i+1]) { + if (interval_complete[i] == false) { + ierr = eewUtils_writeXML(props.SAoutputDir, eventid, suffix, xml, + props.output_interval_mins[i], true); + interval_complete[i] = true; + return true; + } + } + } + + return false; +} + +int fill_core_event_info(const char *evid, + const int version, + const double SA_lat, + const double SA_lon, + const double SA_depth, + const double SA_mag, + const double SA_time, + const int num_stations, + struct coreInfo_struct *core) +{ + strcpy(core->id, evid); + core->version = version; + core->mag = SA_mag; + core->lhaveMag = true; + core->magUnits = MOMENT_MAGNITUDE; + core->lhaveMagUnits = true; + core->magUncer = 0.5; + core->lhaveMagUncer = true; + core->magUncerUnits = MOMENT_MAGNITUDE; + core->lhaveMagUncerUnits = true; + core->lat = SA_lat; + core->lhaveLat = true; + core->latUnits = DEGREES; + core->lhaveLatUnits = true; + core->latUncer = (double) NAN; + core->lhaveLatUncer = true; + core->latUncerUnits = DEGREES; + core->lhaveLatUncerUnits = true; + // GFAST would call lon -120 as 240 by default. Change this to be + // consistent with ShakeAlert seismic algorithms + core->lon = (SA_lon > 180) ? SA_lon - 360: SA_lon; + core->lhaveLon = true; + core->lonUnits = DEGREES; + core->lhaveLonUnits = true; + core->lonUncer = (double) NAN; + core->lhaveLonUncer = true; + core->lonUncerUnits = DEGREES; + core->lhaveLonUncerUnits = true; + core->depth = SA_depth; + core->lhaveDepth = true; + core->depthUnits = KILOMETERS; + core->lhaveDepthUnits = true; + core->depthUncer = (double) NAN; + core->lhaveDepthUncer = true; + core->depthUncerUnits = KILOMETERS; + core->lhaveDepthUncerUnits = true; + core->origTime = SA_time; + core->lhaveOrigTime = true; + core->origTimeUnits = UTC; + core->lhaveOrigTimeUnits = true; + core->origTimeUncer = (double) NAN; + core->lhaveOrigTimeUncer = true; + core->origTimeUncerUnits = SECONDS; + core->lhaveOrigTimeUncerUnits = true; + core->likelihood = 0.8; + core->lhaveLikelihood = true; + core->numStations = num_stations; + return 0; +} + +/* + * Return true if this message should not be sent (false if it should be sent) + */ +bool send_xml_filter(const struct GFAST_props_struct *props, + const struct GFAST_shakeAlert_struct *SA, + const struct GFAST_pgdResults_struct *pgd, + const struct GFAST_peakDisplacementData_struct *pgd_data, + const struct coreInfo_struct *core, + const double age_of_event) +{ + + // Conditions can be met or exceeded. + // Exceeded is used if a value being more than a threshold means no throttling + // Met is used if a value being less than a threshold means no throttling + bool pgd_exceeded = false; + bool mag_exceeded = false; + bool mag_sigma_met = false; + // Determine if pgd threshold is exceeded n times + int num_pgd_exceeded = 0, i, i_throttle; + + // Find the correct throttle criteria based on the time after origin + i_throttle = -1; + for (i = 0; i < props->pgd_props.n_throttle; i++) { + if (props->pgd_props.throttle_time_threshold[i] > age_of_event) break; + i_throttle++; + } + i_throttle = (i_throttle < 0) ? 0: i_throttle; + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: For age_of_event %.2f, using i_throttle=%d, thresholds for time=%.1f, pgd=%.1f, nsta=%d", + __func__, + age_of_event, + i_throttle, + props->pgd_props.throttle_time_threshold[i_throttle], + props->pgd_props.throttle_pgd_threshold[i_throttle], + props->pgd_props.throttle_num_stations[i_throttle]) + } + + // Assumes pgd->nsites = pgd_data->nsites and indices correspond + if (pgd->nsites != pgd_data->nsites) { + LOG_ERRMSG("%s: nsites don't match for pgd, pgd_data! %d, %d\n", + __func__, pgd->nsites, pgd_data->nsites); + return false; + } + for (i = 0; i < pgd->nsites; i++) { + // skip site if it wasn't used + if (!pgd->lsiteUsed[i]) { continue; } + // pd is in meters, so convert to cm before comparing to threshold + if (pgd_data->pd[i] * 100. > props->pgd_props.throttle_pgd_threshold[i_throttle]) { + num_pgd_exceeded++; + } + } + + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: PGD threshold of %.1f cm exceeded at %d stations (threshold num: %d)", + __func__, props->pgd_props.throttle_pgd_threshold[i_throttle], num_pgd_exceeded, + props->pgd_props.throttle_num_stations[i_throttle]); + } + if (num_pgd_exceeded >= props->pgd_props.throttle_num_stations[i_throttle]) { + LOG_MSG("%s: PGD threshold of %.1f cm exceeded at %d stations (threshold num: %d)", + __func__, props->pgd_props.throttle_pgd_threshold[i_throttle], num_pgd_exceeded, + props->pgd_props.throttle_num_stations[i_throttle]); + pgd_exceeded = true; + } + + // Determine if SA mag threshold is exceeded + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: SA mag: %f, threshold mag: %f", + __func__, SA->mag, props->pgd_props.SA_mag_threshold); + } + if (SA->mag >= props->pgd_props.SA_mag_threshold) { + mag_exceeded = true; + LOG_MSG("%s: SA magnitude exceeded! SA mag: %f, threshold mag: %f", + __func__, SA->mag, props->pgd_props.SA_mag_threshold); + } + + // Determine if pgd magnitude sigma threshold is met + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: PGD mag sigma: %f, threshold mag sigma: %f, PGD mag: %f", + __func__, core->magUncer, props->pgd_props.pgd_sigma_throttle, core->mag); + } + if (core->magUncer < props->pgd_props.pgd_sigma_throttle) { + mag_sigma_met = true; + LOG_MSG("%s: PGD mag sigma met! PGD mag sigma: %f, threshold mag sigma: %f, PGD mag: %f", + __func__, core->magUncer, props->pgd_props.pgd_sigma_throttle, core->mag); + } + + if (pgd_exceeded && mag_exceeded && mag_sigma_met) { + LOG_MSG("%s: Message not throttled (%s v%d)! pgd_exceeded: %d, mag_exceeded: %d, mag_sigma_met: %d", + __func__, core->id, core->version, pgd_exceeded, mag_exceeded, mag_sigma_met); + return false; + } + + LOG_MSG("%s: Message throttled (%s v%d)! pgd_exceeded: %d, mag_exceeded: %d, mag_sigma_met: %d", + __func__, core->id, core->version, pgd_exceeded, mag_exceeded, mag_sigma_met); + return true; +} diff --git a/src/eewUtils/drivePGD.c b/src/eewUtils/drivePGD.c new file mode 100644 index 00000000..55d12fc5 --- /dev/null +++ b/src/eewUtils/drivePGD.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include "gfast_eewUtils.h" +#include "gfast_core.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Driver for estimating earthquake magnitude from peak + * ground displacement + * + * @param[in] pgd_props PGD inversion parameters + * @param[in] SA_lat event latitude (degrees) [-90,90] + * @param[in] SA_lon event longitude (degrees) [0,360] + * @param[in] SA_dep event depth (km) + * @param[in] age_of_event time since event origin time (s) + * @param[in] pgd_data data structure holding the peak ground displacement + * data, weights, and logical mask indicating site is + * a candidate for inversion + * + * @param[out] pgd results of the PGD estimation grid-search, + * the variance reduction at each depth in the grid + * search, and the sites used in the inversion + * + * @result 0 indicates success + * 1 indicates an error on the input pgd structure + * 2 indicates error in input pgd_data structure + * 3 indicates insufficient data for inversion + * 4 indicates an error in computation + * + * @author Brendan Crowell (PNSN) and Ben Baker (ISTI) + * + * @date May 2016 + * + */ +int eewUtils_drivePGD(const struct GFAST_pgd_props_struct pgd_props, + const double SA_lat, + const double SA_lon, + const double SA_dep, + const double age_of_event, + struct GFAST_peakDisplacementData_struct pgd_data, + struct GFAST_pgdResults_struct *pgd) +{ + double *d, *srdist, *staAlt, *Uest, *utmRecvEasting, *utmRecvNorthing, *wts, + iqrMin, utmSrcEasting, utmSrcNorthing, x1, x2, y1, y2; + int i, idep, ierr, j, k, l1, nloc, zone_loc; + bool *luse, lnorthp; + //------------------------------------------------------------------------// + // + // Initialize + ierr = PGD_SUCCESS; + d = NULL; + wts = NULL; + utmRecvNorthing = NULL; + utmRecvEasting = NULL; + staAlt = NULL; + Uest = NULL; + srdist = NULL; + luse = NULL; + // Verify the input data structure makes sense + if (pgd_data.nsites < 1) + { + ierr = PGD_PD_DATA_ERROR; + if (pgd_props.verbose > 1) + { + LOG_WARNMSG("%s", "No peak displacement data"); + } + goto ERROR; + } + if (pgd_data.pd == NULL || pgd_data.wt == NULL || + pgd_data.lmask == NULL || pgd_data.lactive == NULL) + { + ierr = PGD_PD_DATA_ERROR; + if (pgd_data.pd == NULL) + { + LOG_ERRMSG("%s", "pgd_data.pd is NULL"); + } + if (pgd_data.wt == NULL) + { + LOG_ERRMSG("%s", "pgd_data.wt is NULL"); + } + if (pgd_data.lactive == NULL) + { + LOG_ERRMSG("%s", "pgd_data.lactive is NULL"); + } + if (pgd_data.lmask == NULL) + { + LOG_ERRMSG("%s", "pgd_data.lmask is NULL"); + } + goto ERROR; + } + // Verify the output data structures + if (pgd->ndeps < 1) + { + LOG_ERRMSG("%s", "No depths in PGD gridsearch!"); + ierr = PGD_STRUCT_ERROR; + goto ERROR; + } + if (pgd->mpgd == NULL || pgd->mpgd_vr == NULL || + pgd->srcDepths == NULL || pgd->UP == NULL || + pgd->UPinp == NULL || pgd->srdist == NULL || + pgd->lsiteUsed == NULL) + { + if (pgd->mpgd == NULL) + { + LOG_ERRMSG("%s", "pgd->mpgd is NULL"); + } + if (pgd->mpgd_vr == NULL) + { + LOG_ERRMSG("%s", "pgd->mpgd_vr is NULL"); + } + if (pgd->srcDepths == NULL) + { + LOG_ERRMSG("%s", "pgd->srcDepths is NULL"); + } + if (pgd->UP == NULL) + { + LOG_ERRMSG("%s", "pgd->UP is NULL"); + } + if (pgd->UPinp == NULL) + { + LOG_ERRMSG("%s", "pgd->UPinp is NULL"); + } + if (pgd->srdist == NULL) + { + LOG_ERRMSG("%s", "pgd->srdist is NULL"); + } + if (pgd->lsiteUsed == NULL) + { + LOG_ERRMSG("%s", "pgd->lsiteUsed is NULL"); + } + ierr = PGD_STRUCT_ERROR; + goto ERROR; + } + // Avoid a segfault + if (pgd->nsites != pgd_data.nsites) + { + LOG_ERRMSG("nsites on pgd and pgd_data differs %d %d\n", + pgd->nsites, pgd_data.nsites); + ierr = PGD_STRUCT_ERROR; + goto ERROR; + } + // Warn in case hypocenter is outside of grid-search + if (pgd_props.verbose > 1 && + (SA_dep < pgd->srcDepths[0] || SA_dep > pgd->srcDepths[pgd->ndeps-1])) + { + LOG_WARNMSG("%s", "Warning hypocenter isn't in grid search!"); + } + // Null out results + nloc = pgd->ndeps*pgd->nlats*pgd->nlons; + array_zeros64f_work(pgd->nsites, pgd->UPinp); + array_zeros8l_work( pgd->nsites, pgd->lsiteUsed); + array_zeros64f_work(nloc, pgd->mpgd); + array_zeros64f_work(nloc, pgd->mpgd_sigma); + array_zeros64f_work(nloc, pgd->mpgd_vr); + array_zeros64f_work(nloc, pgd->dep_vr_pgd); + array_zeros64f_work(nloc, pgd->iqr); + array_zeros64f_work(pgd->nsites*nloc, pgd->UP); + array_zeros64f_work(pgd->nsites*nloc, pgd->srdist); + // Require there is a sufficient amount of data to invert + luse = memory_calloc8l(pgd_data.nsites); + l1 = 0; + for (k=0; k 1) + { + LOG_WARNMSG("Insufficient data to invert %d < %d\n", + l1, pgd_props.min_sites); + } + ierr = PGD_INSUFFICIENT_DATA; + goto ERROR; + } + // Allocate space + d = memory_calloc64f(l1); + utmRecvNorthing = memory_calloc64f(l1); + utmRecvEasting = memory_calloc64f(l1); + staAlt = memory_calloc64f(l1); + wts = memory_calloc64f(l1); + Uest = memory_calloc64f(l1*pgd->ndeps); + srdist = memory_calloc64f(l1*pgd->ndeps); + // Get the source location + zone_loc = pgd_props.utm_zone; + if (zone_loc ==-12345){zone_loc =-1;} // Estimate UTM zone from source lon + core_coordtools_ll2utm(SA_lat, SA_lon, + &y1, &x1, + &lnorthp, &zone_loc); + utmSrcNorthing = y1; + utmSrcEasting = x1; + // Loop on the receivers, get distances, and data + l1 = 0; + for (k=0; k 2) + { + LOG_DEBUGMSG("Inverting for PGD with %d sites", l1); + } + ierr = core_scaling_pgd_depthGridSearch(l1, pgd->ndeps, + pgd_props.verbose, + pgd_props.dist_tol, + pgd_props.disp_def, + utmSrcEasting, + utmSrcNorthing, + pgd->srcDepths, + utmRecvEasting, + utmRecvNorthing, + staAlt, + d, + wts, + srdist, + pgd->mpgd, + pgd->mpgd_vr, + pgd->iqr, + Uest); + if (ierr != 0) + { + if (pgd_props.verbose > 0) + { + LOG_ERRMSG("%s", "Error in PGD grid search!"); + } + ierr = PGD_COMPUTE_ERROR; + } + // Extract observations + k = 0; + for (i=0; insites; i++) + { + pgd->lsiteUsed[i] = luse[i]; + if (!luse[i]){continue;} + pgd->UPinp[i] = d[k]; + k = k + 1; + } + { /*vk needed for more stringent c++ compiler*/ + enum isclError_enum isclerr = (enum isclError_enum)ierr; + iqrMin = array_min64f(pgd->ndeps, pgd->iqr, &isclerr); + } + // Extract the estimates and compute weighted objective function + // Also add uncertainty estimate + // First get last index value before lookup time is greater than age_of_event + int i99; + for (i99 = 0; (i99 < pgd_props.n99) && (pgd_props.t99[i99] <= age_of_event); i99++) {} + i99 = (i99 <= 0) ? 0 : i99 - 1; + for (idep=0; idepndeps; idep++) + { + if (pgd_props.n99 == 0) { + pgd->mpgd_sigma[idep] = 0.5; + } else { + pgd->mpgd_sigma[idep] = 0.5 * exp(pgd_props.m99[i99] - pgd->mpgd[idep]); + } + pgd->dep_vr_pgd[idep] = pgd->mpgd[idep]*iqrMin/pgd->iqr[idep]; + j = 0; + for (i=0; insites; i++) + { + pgd->UP[idep*pgd->nsites+i] = 0.0; + pgd->srdist[idep*pgd->nsites+i] = 0.0; + if (luse[i]) + { + pgd->UP[idep*pgd->nsites+i] = Uest[idep*l1+j]; + pgd->srdist[idep*pgd->nsites+i] = srdist[idep*l1+j]; + j = j + 1; + } + } + } +ERROR:; + memory_free64f(&d); + memory_free64f(&utmRecvNorthing); + memory_free64f(&utmRecvEasting); + memory_free64f(&staAlt); + memory_free64f(&wts); + memory_free64f(&Uest); + memory_free64f(&srdist); + memory_free8l(&luse); + return ierr; +} + diff --git a/src/eewUtils/makeXML.c b/src/eewUtils/makeXML.c new file mode 100644 index 00000000..2ee5eef7 --- /dev/null +++ b/src/eewUtils/makeXML.c @@ -0,0 +1,593 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_eewUtils.h" +#include "gfast_core.h" +#include "gfast_xml.h" +#include "compearth.h" +#include "iscl/time/time.h" + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-qual" +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +#endif +//============================================================================// +/*! + * @brief Generates the char * XML message corresponding to the finite + * fault inversion + * + * @bug fix cast quality + */ +char *eewUtils_makeXML__ff(const enum opmode_type mode, + const char *orig_sys, + const char *alg_vers, + const char *instance, + const char *message_type, + const char *version, + const struct coreInfo_struct *core, + const int nseg, + const int *fault_ptr, + const double *lat_vtx, + const double *lon_vtx, + const double *dep_vtx, + const double *strike, + const double *dip, + const double *ss, + const double *ds, + const double *ss_unc, + const double *ds_unc, + int *ierr) +{ + char *xmlmsg, cnow[128], cmode[64], cseg[64]; + enum xml_segmentShape_enum shape; + xmlTextWriterPtr writer; + xmlBufferPtr buf; + double now; + int indx, iseg, nv, msglen, rc; + //------------------------------------------------------------------------// + // + // Create a new XML buffer to which the XML document will be written + *ierr = 0; + xmlmsg = NULL; + buf = xmlBufferCreate(); + if (buf == NULL) + { + LOG_ERRMSG("%s", "Error creating XML buffer!"); + *ierr = 1; + return xmlmsg; + } + // Create a new xmlWriter for uri with no compression + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) + { + LOG_ERRMSG("%s", "Error creating xml writer"); + *ierr = 1; + return xmlmsg; + } + // Start the document with default xml version + rc = xmlTextWriterStartDocument(writer, NULL, XML_ENCODING, NULL); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error starting writer"); + *ierr = 1; + return xmlmsg; + } + //---------------------------------------------------------// + rc = xmlTextWriterStartElement(writer, BAD_CAST "event_message"); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing event_message"); + *ierr = 1; + return xmlmsg; + } + memset(cmode, 0, 64*sizeof(char)); + if (mode == REAL_TIME_EEW) + { + strcpy(cmode, "live\0"); + } + else if (mode == PLAYBACK) + { + strcpy(cmode, "playback\0"); + } + else if (mode == OFFLINE) + { + strcpy(cmode, "offline\0"); + } + else + { + LOG_WARNMSG("Defaulting to live mode %d", mode); + strcpy(cmode, "live\0"); + } + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "category\0", + BAD_CAST cmode); + now = time_timeStamp(); + rc = xml_epoch2string(now, cnow); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "timestamp\0", + BAD_CAST cnow); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST ("orig_sys\0"), + BAD_CAST orig_sys); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "alg_vers\0", + BAD_CAST alg_vers); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "instance\0", + BAD_CAST instance); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "message_type\0", + BAD_CAST message_type); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST ("version\0"), + BAD_CAST version); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error setting attributes"); + *ierr = 1; + return xmlmsg; + } + //-------------------------------------------------------------// + rc = GFAST_xml_shakeAlert_writeCoreInfo(*core, (void *)writer); + if (rc != 0) + { + LOG_ERRMSG("%s", "Error writing core info"); + *ierr = 1; + return xmlmsg; + } + //----------------------------------------------------------// + rc = xmlTextWriterStartElement(writer, BAD_CAST "finite_fault\0"); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "atten_geom\0", + BAD_CAST "false\0"); + memset(cseg, 0, sizeof(cseg)); + sprintf(cseg, "%d", nseg); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "segment_number\0", + BAD_CAST cseg); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "segment_shape\0", + BAD_CAST "rectangle"); + rc = xmlTextWriterWriteFormatElement(writer, + BAD_CAST "number_of_segments\0", + "%d", nseg); + rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "confidence\0", + "%d", 1); + for (iseg=0; iseg + rc = xmlTextWriterEndElement(writer); // + // + rc = xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error closing EVENT_MESSAGE"); + return xmlmsg; + } + // Finalize the writer + rc = xmlTextWriterEndDocument(writer); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing ending the document"); + *ierr = 1; + return xmlmsg; + } + xmlFreeTextWriter(writer); + xmlCleanupCharEncodingHandlers(); + // Finally copy the char * XML message + msglen = xmlStrlen(buf->content); //strlen((const char *)buf->content); + xmlmsg = (char *)calloc((size_t) (msglen+1), sizeof(char)); + strncpy(xmlmsg, (const char *)buf->content, msglen); + xmlCleanupParser(); + xmlBufferFree(buf); + xmlDictCleanup(); + xmlCleanupThreads(); + return xmlmsg; +} +//============================================================================// +/*! + * @brief Generates a CMT QuakeML message. + * + * @param[in] network ANSS network code. + * @param[in] domain ANSS's network's main web page domain + * (e.g. anss.org, tsunami.gov, + * www.ldeo.columbia.edu, etc.) + * @param[in] evid event ID. + * @param[in] evla Centroid latitude (degrees). + * @param[in] evlo Centroid longitude (degrees). + * @param[in] evdp Centroid depth (km). + * @param[in] t0 Origin time (seconds since epoch). + * @param[in] mt Moment tensor in NED format with units of + * Newton-meters. the moment tensor is packed + * \f$ \{ m_{xx}, m_{yy}, m_{zz}, + * m_{xy}, m_{xz}, m_{yz} \} \f$. + * + * @param[out] ierr 0 indicates success. + * + * @note https://github.com/usgs/Quakeml/wiki/ANSS-Quakeml-ID-Standards + * + * @author Ben Baker (ISTI) + * + * @bug results in no-prefix error. + * @bug memory leak --show-leak-kinds=all: xmlNewRMutex + * + */ +char *eewUtils_makeXML__quakeML(const char *network, + const char *domain, + const char *evid, + const double evla, + const double evlo, + const double evdp, + const double t0, + const double mt[6], + int *ierr) +{ + char *qml; + char publicID[512], publicIDroot[512], datasource[512], dataid[512]; + char networkLower[64]; + double mag; + int msglen, rc; + struct qmlOrigin_struct origin; + struct qmlMagnitude_struct magnitude; + xmlTextWriterPtr writer; + xmlBufferPtr buf; + // int lenos; + const char *method = "gps\0"; + const char *xmlns = "http://quakeml.org/xmlns/bed/1.2\0"; + const char *xmlns_cat = "http://anss.org/xmlns/catalog/0.1\0"; + //------------------------------------------------------------------------// + // Initialize + *ierr = 0; + qml = NULL; + //------------------------------------------------------------------------// + // Set some stuff to facilitate QML generation // + //------------------------------------------------------------------------// + // Set the network code (all lower case) + memset(networkLower, 0, 64*sizeof(char)); + strcpy(networkLower, network); + // lenos = (int) (strlen(network)); + // for (i=0; i.// + memset(publicIDroot, 0, 512*sizeof(char)); + strcpy(publicIDroot, "quakeml:\0"); + strcat(publicIDroot, networkLower); + strcat(publicIDroot, ".\0"); + strcat(publicIDroot, domain); + strcat(publicIDroot, "/\0"); + // Make the event + memset(publicID, 0, 512*sizeof(char)); + strcpy(publicID, publicIDroot); + strcat(publicID, "event/\0"); + strcat(publicID, evid); + // Make the data source + memset(datasource, 0, 512*sizeof(char)); + strcpy(datasource, networkLower); + // Make the dataid + memset(dataid, 0, 512*sizeof(char)); + strcpy(dataid, networkLower); + strcat(dataid, evid); + //------------------------------------------------------------------------// + // Make the XML writer // + //------------------------------------------------------------------------// + // Initialize XML + buf = xmlBufferCreate(); + if (buf == NULL) + { + LOG_ERRMSG("%s", "Error creating XML buffer!"); + *ierr = 1; + return qml; + } + // Create a new xmlWriter for uri with no compression + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) + { + LOG_ERRMSG("%s", "Error creating xml writer"); + *ierr = 1; + return qml; + } + // Turn indentation on + rc = xmlTextWriterSetIndentString(writer, BAD_CAST " "); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error setting indentation"); + } + // Start the document with default xml version + rc = xmlTextWriterStartDocument(writer, NULL, XML_ENCODING, NULL); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error starting writer"); + *ierr = 1; + return qml; + } + // Set the indentation + rc = xmlTextWriterSetIndent(writer, 1); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error activating indentation"); + } + //------------------------------------------------------------------------// + // Write the QuakeML // + //------------------------------------------------------------------------// + // + rc = xmlTextWriterStartElement(writer, BAD_CAST "quakeml\0"); /* TODO: q:quakeml results in no prefix error */ + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "xmlns\0", + BAD_CAST xmlns); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "xmlns:catalog\0", + BAD_CAST xmlns_cat); + // + rc = xmlTextWriterStartElement(writer, BAD_CAST "eventParameters\0"); + memset(publicID, 0, 512*sizeof(char)); + strcpy(publicID, publicIDroot); + strcat(publicID, "eventparameters/"); + strcat(publicID, evid); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "publicID\0", + BAD_CAST publicID); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "catalog:dataid\0", + BAD_CAST dataid); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "catalog:eventsource\0", + BAD_CAST networkLower); + // Make the event + rc = xmlTextWriterStartElement(writer, BAD_CAST "event\0"); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "publicID\0", + BAD_CAST publicID); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "catalog:datasource\0", + BAD_CAST networkLower); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "catalog:dataid\0", + BAD_CAST dataid); + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "catalog:eventsource\0", + BAD_CAST networkLower); + // Make the focal mechanism + *ierr = GFAST_xml_quakeML_writeFocalMechanism(publicIDroot, + evid, + method, + mt, + (void *) writer); + // Make the magnitude + memset(&magnitude, 0, sizeof(struct qmlMagnitude_struct)); + *ierr = compearth_CMT2mw(1, 1, mt, &mag); + if (*ierr == 0) + { + magnitude.magnitude = mag; + strcpy(magnitude.type, "Mw_gps\0"); /* TODO need a magnitude type */ + magnitude.lhaveMag = true; + magnitude.lhaveType = true; + } + else + { + LOG_ERRMSG("%s", "Error computing moment magnitude"); + } + xml_quakeML_writeMagnitude(magnitude.magnitude, magnitude.lhaveMag, + 0.5, false, + magnitude.type, magnitude.lhaveType, + (void *) writer); + //*ierr = GFAST_xml_quakeML_writeMagnitude(publicIDroot, + // evid, + // method, + // magnitude, + // (void *) writer); + // Make the origin + memset(&origin, 0, sizeof(struct qmlOrigin_struct)); + origin.originTime.time = t0; + origin.originTime.time_units = UTC; + origin.originTime.lhaveTime = true; + origin.lhaveOriginTime = true; + + origin.latitude.latitude = evla; + origin.latitude.latitude_units = DEGREES; + origin.latitude.lhaveLat = true; + origin.lhaveLatitude = true; + + origin.longitude.longitude = evlo; + origin.longitude.longitude_units = DEGREES; + origin.longitude.lhaveLon = true; + origin.lhaveLongitude = true; + + origin.depth.depth = evdp; + origin.depth.depth_units = KILOMETERS; + origin.depth.lhaveDepth = true; + origin.lhaveDepth = true; + + *ierr = GFAST_xml_quakeML_writeOrigin(publicIDroot, + evid, + method, + origin, + (void *) writer); + // + rc = xmlTextWriterEndElement(writer); + // + rc = xmlTextWriterEndElement(writer); + // + rc = xmlTextWriterEndElement(writer); + //------------------------------------------------------------------------// + // Finalize the XML writer and copy the result // + //------------------------------------------------------------------------// + // Finalize the writer + rc = xmlTextWriterEndDocument(writer); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing ending the document"); + *ierr = 1; + return qml; + } + xmlFreeTextWriter(writer); + xmlCleanupCharEncodingHandlers(); + // Finally copy the char * XML message + msglen = xmlStrlen(buf->content); //strlen((const char *)buf->content); + qml = (char *)calloc((size_t) msglen+1, sizeof(char)); + strncpy(qml, (const char *)buf->content, msglen); + xmlCleanupParser(); + xmlBufferFree(buf); + xmlDictCleanup(); + xmlCleanupThreads(); + return qml; +} +//============================================================================// +/*! + * + */ +char *eewUtils_makeXML__pgd(const enum opmode_type mode, + const char *orig_sys, + const char *alg_vers, + const char *instance, + const char *message_type, + const char *version, + const struct coreInfo_struct *core, + int *ierr) +{ + char *xmlmsg, cnow[128], cmode[64]; + xmlTextWriterPtr writer; + xmlBufferPtr buf; + double now; + int msglen, rc; + //------------------------------------------------------------------------// + // + // Create a new XML buffer to which the XML document will be written + *ierr = 0; + xmlmsg = NULL; + buf = xmlBufferCreate(); + if (buf == NULL) + { + LOG_ERRMSG("%s", "Error creating XML buffer!"); + *ierr = 1; + return xmlmsg; + } + // Create a new xmlWriter for uri with no compression + writer = xmlNewTextWriterMemory(buf, 0); + if (writer == NULL) + { + LOG_ERRMSG("%s", "Error creating xml writer"); + *ierr = 1; + return xmlmsg; + } + // Start the document with default xml version + rc = xmlTextWriterStartDocument(writer, NULL, XML_ENCODING, NULL); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error starting writer"); + *ierr = 1; + return xmlmsg; + } + //---------------------------------------------------------// + rc = xmlTextWriterStartElement(writer, BAD_CAST "event_message"); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing event_message"); + *ierr = 1; + return xmlmsg; + } + memset(cmode, 0, 64*sizeof(char)); + if (mode == REAL_TIME_EEW) + { + strcpy(cmode, "live\0"); + } + else if (mode == PLAYBACK) + { + strcpy(cmode, "playback\0"); + } + else if (mode == OFFLINE) + { + strcpy(cmode, "offline\0"); + } + else + { + LOG_WARNMSG("%s", "Defaulting to live mode"); + strcpy(cmode, "live\0"); + } + rc = xmlTextWriterWriteAttribute(writer, BAD_CAST "category\0", + BAD_CAST cmode); + now = time_timeStamp(); + rc += xml_epoch2string(now, cnow); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "timestamp\0", + BAD_CAST cnow); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "orig_sys\0", + BAD_CAST orig_sys); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "alg_vers\0", + BAD_CAST alg_vers); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "instance\0", + BAD_CAST instance); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "message_type\0", + BAD_CAST message_type); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "version\0", + BAD_CAST version); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error setting attributes"); + *ierr = 1; + return xmlmsg; + } + rc = GFAST_xml_shakeAlert_writeCoreInfo(*core, (void *)writer); + // + rc = xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error closing EVENT_MESSAGE"); + return xmlmsg; + } + // Finalize the writer + rc = xmlTextWriterEndDocument(writer); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing ending the document"); + *ierr = 1; + return xmlmsg; + } + xmlFreeTextWriter(writer); + xmlCleanupCharEncodingHandlers(); + // Finally copy the char * XML message + msglen = xmlStrlen(buf->content); //strlen((const char *)buf->content); + xmlmsg = (char *)calloc((size_t) msglen+1, sizeof(char)); + strncpy(xmlmsg, (const char *)buf->content, msglen); + xmlCleanupParser(); + xmlBufferFree(buf); + xmlDictCleanup(); + xmlCleanupThreads(); + return xmlmsg; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif diff --git a/src/eewUtils/parseCoreXML.c b/src/eewUtils/parseCoreXML.c new file mode 100644 index 00000000..c6b4efae --- /dev/null +++ b/src/eewUtils/parseCoreXML.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_core.h" +#include "gfast_eewUtils.h" +#include "gfast_xml.h" + +/*! + * @brief Reads a elarmS based shakeAlert message into the GFAST + * shakeAlert structure which wants to know the event ID, + * origin time, latitude, longitude, depth, and magnitude + * + * @param[in] message null terminated XML shakeAlert message to parse + * @param[in] saNaN if a value does not exist in the message it will + * be given this default value + * + * @param[out] SA shake alert structure + * + * @author Ben Baker, ISTI + * + */ +int eewUtils_parseCoreXML(const char *message, + const double saNaN, + struct GFAST_shakeAlert_struct *SA) +{ + xmlDocPtr doc; + xmlNodePtr core_xml, event_xml; + xmlChar *orig_sys, *msg_version; + + struct coreInfo_struct core; + int ierr, length; + bool lfound; + // Initialize + ierr = 0; + memset(SA, 0, sizeof(struct GFAST_shakeAlert_struct)); + memset(&core, 0, sizeof(struct coreInfo_struct)); + length = (int) (strlen(message)); + if (length == 0) + { + LOG_ERRMSG("%s", "Error the message is empty"); + return -1; + } + doc = xmlReadMemory(message, length, "noname.xml\0", NULL, 0); + if (doc == NULL) + { + LOG_ERRMSG("%s", "Error - failed to parse xml document"); + return -1; + } + // Make sure there's something in the message + event_xml = xmlDocGetRootElement(doc); + if (event_xml == NULL) + { + LOG_ERRMSG("%s", "Empty document"); + return -1; + } + lfound = false; + // Loop on the event_xml + while (event_xml != NULL) + { + if (xmlStrcmp(event_xml->name, BAD_CAST "event_message\0") != 0) + { + goto NEXT_EVENT_XML; + } + //retrieve source and version + orig_sys=xmlGetProp(event_xml,(xmlChar*)"orig_sys"); + msg_version=xmlGetProp(event_xml,(xmlChar*)"version"); + // Find the core_info in the event message + core_xml = event_xml->xmlChildrenNode; + while (core_xml != NULL) + { + // Require this be core_info + if (xmlStrcmp(core_xml->name, BAD_CAST "core_info\0") != 0) + { + goto NEXT_CORE_XML; + } + lfound = true; + // Parse it + ierr = GFAST_xml_shakeAlert_readCoreInfo((void *) core_xml, + saNaN, &core); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading core info!"); + } + break; + NEXT_CORE_XML:; + core_xml = core_xml->next; + } // Loop on search for core_xml + if (lfound){break;} + NEXT_EVENT_XML:; + event_xml = event_xml->next; + } // Loop on events + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error parsing core shakeAlert information"); + } + else + { + strcpy(SA->eventid, core.id); + //originating algorithm + if (orig_sys!=NULL) strncpy(SA->orig_sys, (char *)orig_sys, 10); + //message version + if (msg_version!=NULL) SA->version = atoi((char *)msg_version); + // origin time + if (core.lhaveOrigTime) + { + SA->time = core.origTime; + } + else + { + LOG_ERRMSG("%s", "Couldn't find origin time"); + ierr = ierr + 1; + } + // latitude + if (core.lhaveLat) + { + SA->lat = core.lat; + } + else + { + LOG_ERRMSG("%s", "Couldn't find latitude"); + ierr = ierr + 1; + } + // longitude + if (core.lhaveLon) + { + SA->lon = core.lon; + } + else + { + LOG_ERRMSG("%s", "Couldn't find longitude"); + ierr = ierr + 1; + } + // depth + if (core.lhaveDepth) + { + SA->dep = core.depth; + } + else + { + LOG_ERRMSG("%s", "Couldn't find depth"); + ierr = ierr + 1; + } + // magnitude + if (core.lhaveMag) + { + SA->mag = core.mag; + } + else + { + LOG_ERRMSG("%s", "Couldn't find magnitude"); + ierr = ierr + 1; + } + if (SA->lon < 0.0){SA->lon = SA->lon + 360.0;} + } + // Clean up + xmlFreeDoc(doc); + xmlCleanupParser(); + return ierr; +} diff --git a/src/eewUtils/setLogFileNames.c b/src/eewUtils/setLogFileNames.c new file mode 100644 index 00000000..0365067c --- /dev/null +++ b/src/eewUtils/setLogFileNames.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include "gfast_eewUtils.h" + +/*! + * @brief Creates event output log file names + * @param [in] eventid event id character string + * @param [in] outputDir directory for output + * @param [out] errorLogFileName + * @param [out] infoLogFileName + * @param [out] debugLogFileName + * @param [out] warnLogFileName + */ +void eewUtils_setLogFileNames(const char *eventid, + const char *outputDir, + char errorLogFileName[PATH_MAX], + char infoLogFileName[PATH_MAX], + char debugLogFileName[PATH_MAX], + char warnLogFileName[PATH_MAX]) +{ + // Set the log file names + char fileNameBase[PATH_MAX]; + memset(fileNameBase, 0, PATH_MAX*sizeof(char)); + if (outputDir == NULL) { + strcpy(fileNameBase, "./\0"); + } else { + strcpy(fileNameBase, outputDir); + if (outputDir[strlen(outputDir)-1] != '/') { + strcat(fileNameBase, "/\0"); + } + } + strcat(fileNameBase, eventid); + + memset(errorLogFileName, 0, PATH_MAX*sizeof(char)); + strcpy(errorLogFileName, fileNameBase); + strcat(errorLogFileName, "_error.log\0"); + + memset(infoLogFileName, 0, PATH_MAX*sizeof(char)); + strcpy(infoLogFileName, fileNameBase); + strcat(infoLogFileName, "_info.log\0"); + + memset(debugLogFileName, 0, PATH_MAX*sizeof(char)); + strcpy(debugLogFileName, fileNameBase); + strcat(debugLogFileName, "_debug.log\0"); + + memset(warnLogFileName, 0, PATH_MAX*sizeof(char)); + strcpy(warnLogFileName, fileNameBase); + strcat(warnLogFileName, "_debug.log\0"); + + return; +} diff --git a/src/gfast_eew.c b/src/gfast_eew.c new file mode 100644 index 00000000..749ba8c4 --- /dev/null +++ b/src/gfast_eew.c @@ -0,0 +1,657 @@ +#include +#include +#include +#include +#include +#include +#include "gfast.h" +#include "gfast_core.h" +#include "iscl/memory/memory.h" +#include "iscl/os/os.h" +#include "iscl/time/time.h" +#include +#include "dmlibWrapper.h" + +#include + +#define MAX_MESSAGES 100000 + +/*! + * @brief poll directory for new messages. + * @param[in] dirname directory to search for messages + * @param[out] error code + * @return contents of message(s?) read from directory + */ +char *check_dir_for_messages(const char *dirname, int *ierr); + + +/*! + * @brief GFAST earthquake early warning driver routine + * First argument assumed to be configuration file name. Defaults to gfast.props. + * + */ +int main(int argc, char **argv) +{ + const char *fcnm = "gfast_eew\0"; + char propfilename[PATH_MAX]; + char *message_dir; + struct GFAST_activeEvents_struct events; + struct GFAST_activeEvents_xml_status xml_status; + struct GFAST_cmtResults_struct cmt; + struct GFAST_ffResults_struct ff; + struct h5traceBuffer_struct h5traceBuffer; + struct tb2Data_struct tb2Data; + struct GFAST_offsetData_struct cmt_data, ff_data; + struct GFAST_peakDisplacementData_struct pgd_data; + struct GFAST_data_struct gps_data; + struct GFAST_pgdResults_struct pgd; + struct GFAST_props_struct props; + struct GFAST_shakeAlert_struct SA; + struct GFAST_xmlMessages_struct xmlMessages; + struct ewRing_struct ringInfo; + char *msgs; + double t0, t1; + const enum opmode_type opmode = REAL_TIME_EEW; + /*activeMQ variables*/ + char *amqMessage; + // const bool useTopic = true; /**< ShakeAlert uses topics */ + // const bool clientAck = false; /**< False means set session acknowledge transacations */ + // const bool luseListener = false; /**< C can't trigger so turn this off (remove?) */ + double tstatus, tstatus0, tstatus1; + // static void *amqMessageListener = NULL; /**< pointer to ShakeAlertConsumer object */ + int ierr, im, msWait, nTracebufs2Read; + bool lacquire, lnewEvent, in_loop; + const int rdwt = 2; // H5 file is read only (1) or read/write (2) + // char errorLogFileName[PATH_MAX]; + // char infoLogFileName[PATH_MAX]; + // char debugLogFileName[PATH_MAX]; + // char warnLogFileName[PATH_MAX]; + bool check_message_dir = false; + bool USE_AMQ = false; + bool USE_DMLIB = false; + int niter = 0; +#ifdef GFAST_USE_AMQ + USE_AMQ = true; +// GFAST_USE_DMLIB defined inside GFAST_USE_AMQ since dmlib won't work without amq +#ifdef GFAST_USE_DMLIB + USE_DMLIB = true; +#endif +#endif + + // logging stuff + init_plog(); + + LOG_MSG("%s Version: %s (Build %s %s by %s)", + fcnm, GFAST_VERSION, __DATE__, __TIME__, BUILDER); + // Initialize. Only works if propfile is specified + if (argc > 1) { + strncpy(propfilename, argv[1], PATH_MAX - 1); + } else { + LOG_MSG("%s", "Usage: gfast_eew propfilename"); + return EXIT_SUCCESS; + } + + // Get program instance for ShakeAlert-approved xml header + char longprog[PATH_MAX], program_instance[PATH_MAX]; + + // Get program name + strncpy(longprog, argv[0], PATH_MAX - 1); + char *pch = strrchr(longprog, '/'); + size_t lenshort = &longprog[strlen(longprog)] - pch; + if (pch != NULL) { + memcpy(program_instance, pch + 1, lenshort - 1); + program_instance[lenshort] = '\0'; + } else { + strncpy(program_instance, argv[0], PATH_MAX - 1); + } + + // Add host name to program_instance + char name[1000]; + if(gethostname(name, (int)sizeof(name) - 1) == 0) { + // if eew-bk-dev1.geo.berkeley.edu, shorten to eew-bk-dev1 + char *c = strstr(name, "."); + if(c != NULL) *c = '\0'; + strcat(program_instance, "@\0"); + strcat(program_instance, name); + } + + ierr = 0; + msgs = NULL; + memset(&props, 0, sizeof(struct GFAST_props_struct)); + memset(&gps_data, 0, sizeof(struct GFAST_data_struct)); + memset(&events, 0, sizeof(struct GFAST_activeEvents_struct)); + memset(&xml_status, 0, sizeof(struct GFAST_activeEvents_xml_status)); + memset(&pgd, 0, sizeof(struct GFAST_pgdResults_struct)); + memset(&cmt, 0, sizeof(struct GFAST_cmtResults_struct)); + memset(&ff, 0, sizeof(struct GFAST_ffResults_struct)); + memset(&pgd_data, 0, sizeof( struct GFAST_peakDisplacementData_struct)); + memset(&cmt_data, 0, sizeof(struct GFAST_offsetData_struct)); + memset(&ff_data, 0, sizeof(struct GFAST_offsetData_struct)); + memset(&ringInfo, 0, sizeof(struct ewRing_struct)); + memset(&xmlMessages, 0, sizeof(struct GFAST_xmlMessages_struct)); + memset(&h5traceBuffer, 0, sizeof(struct h5traceBuffer_struct)); + memset(&tb2Data, 0, sizeof(struct tb2Data_struct)); + + // Read the program properties + LOG_MSG("%s: Reading configuration from %s", fcnm, propfilename); + ierr = GFAST_core_properties_initialize(propfilename, opmode, &props); + if (ierr != 0) { + LOG_ERRMSG("%s: Error reading GFAST initialization file: %s\n", fcnm, propfilename); + goto ERROR; + } + + if (props.verbose > 2){GFAST_core_properties_print(props);} + // Initialize the stations locations/names/sampling periods for the module + if (props.verbose > 0) { + LOG_MSG("%s: Initializing the data buffers...", fcnm); + } + + ierr = core_data_initialize(props, &gps_data); + if (ierr != 0) { + LOG_ERRMSG("%s: Error initializing data buffers\n", fcnm); + goto ERROR; + } + + // Set the trace buffer names and open the HDF5 datafile + ierr = GFAST_traceBuffer_h5_setTraceBufferFromGFAST( + props.bufflen, gps_data, &h5traceBuffer); + if (ierr != 0) { + LOG_ERRMSG("%s: Error setting the H5 tracebuffer\n", fcnm); + goto ERROR; + } + // Initialize the tracebuffer h5 archive + ierr = traceBuffer_h5_initialize(rdwt, true, "./\0", "work.h5\0", + &h5traceBuffer); + if (ierr != 0) { + LOG_ERRMSG("%s: Error initializing the HDF5 wave file\n", fcnm); + goto ERROR; + } + + if (USE_AMQ) { + activeMQ_start(); // start library + /* + Start connection, to be used by DMMessageSender. + This should be written using just dmlib - CWU + */ + ierr = startDestinationConnection( + props.activeMQ_props.user, + props.activeMQ_props.password, + props.activeMQ_props.destinationURL, + props.activeMQ_props.msReconnect, + props.activeMQ_props.maxAttempts, + props.verbose); + if (ierr == 0) { + LOG_ERRMSG("%s: Attempted to re-initialize activeMQ connection object", fcnm); + } + if (ierr < 0) { + LOG_ERRMSG("%s: Error initializing activeMQ connection object", fcnm); + goto ERROR; + } + /* dmlib startup */ + if (USE_DMLIB) { + /*start message receiver*/ + if (props.verbose > 0) { + LOG_MSG("%s: Initializing event receiver on %s...", + fcnm, props.activeMQ_props.originTopic); + } + ierr = startEventReceiver( + props.activeMQ_props.originURL, + props.activeMQ_props.user, + props.activeMQ_props.password, + props.activeMQ_props.originTopic, + props.activeMQ_props.msReconnect, + props.activeMQ_props.maxAttempts); + if (ierr == 0) { + LOG_ERRMSG("%s: Attempted to re-initialize active event receiver object", fcnm); + } + if (ierr < 0) { + LOG_ERRMSG("%s: Error initializing event receiver object", fcnm); + goto ERROR; + } + + /* start heartbeat producer and set to manual heartbeats */ + if ((props.activeMQ_props.hbTopic != NULL) && + (strlen(props.activeMQ_props.hbTopic) > 0)) + { + char senderstr[100], *pp; + int ii; + strcpy(senderstr, "gfast."); + ii = strlen(senderstr); + gethostname(senderstr + ii, 90); /*append hostname*/ + pp = strchr(senderstr + ii, '.'); /*find . in hostname if any*/ + if (pp != NULL) *pp = '\0'; /*truncate long hostname*/ + if (props.verbose > 0) { + LOG_MSG("%s: Initializing heartbeat sender %s on %s...", fcnm, + senderstr, props.activeMQ_props.hbTopic); + } + ierr = startHBProducer( + senderstr, + props.activeMQ_props.hbTopic, + props.activeMQ_props.hbInterval, + props.verbose); + if (ierr == 0) { + LOG_ERRMSG("%s: Attempted to re-initialize active HB producer object", fcnm); + } + if (ierr < 0) { + LOG_ERRMSG("%s: Error initializing HB producer object", fcnm); + goto ERROR; + } + } + /*start message sender*/ + if (props.verbose > 0) { + LOG_MSG("%s: Initializing event sender on %s...", + fcnm, props.activeMQ_props.destinationTopic); + } + ierr = startEventSender(props.activeMQ_props.destinationTopic); + if (ierr == 0) { + LOG_ERRMSG("%s: Attempted to re-initialize active event sender object", fcnm); + } + if (ierr < 0) { + LOG_ERRMSG("%s: Error initializing event sender object", fcnm); + goto ERROR; + } + } /* end of if USE_DMLIB */ + } /* end if USE_AMQ */ + + if (strlen(props.SAeventsDir)) { + message_dir = props.SAeventsDir; + check_message_dir = true; + } + + // Initialize PGD + ierr = core_scaling_pgd_initialize(props.pgd_props, gps_data, &pgd, &pgd_data); + if (ierr != 0) { + LOG_ERRMSG("%s: Error initializing PGD\n", fcnm); + goto ERROR; + } + // Initialize CMT + ierr = core_cmt_initialize(props.cmt_props, gps_data, &cmt, &cmt_data); + if (ierr != 0) { + LOG_ERRMSG("%s: Error initializing CMT\n", fcnm); + goto ERROR; + } + // Initialize finite fault + ierr = core_ff_initialize(props.ff_props, gps_data, &ff, &ff_data); + if (ierr != 0) { + LOG_ERRMSG("%s: Error initializing FF\n", fcnm); + goto ERROR; + } + // Set up the SNCL's to target + ierr = traceBuffer_ewrr_settb2DataFromGFAST(&gps_data, &tb2Data); + if (ierr != 0) { + LOG_ERRMSG("%s: Error setting tb2Data\n", fcnm); + goto ERROR; + } + // Connect to the earthworm ring + LOG_MSG("%s: Connecting to earthworm ring %s", fcnm, ringInfo.ewRingName); + ierr = traceBuffer_ewrr_initialize(props.ew_props.gpsRingName, + 10, + &ringInfo); + if (ierr != 0) { + LOG_ERRMSG("%s: Error initializing tracebuf reader\n", fcnm); + goto ERROR; + } + // Flush the buffer + LOG_MSG("%s: Flushing ring %s", fcnm, ringInfo.ewRingName); + ierr = traceBuffer_ewrr_flushRing(&ringInfo); + if (ierr != 0) { + LOG_ERRMSG("%s: Error flusing the ring\n", fcnm); + goto ERROR; + } + // Begin the acquisition loop + LOG_MSG("%s: Beginning the acquisition...", fcnm); + amqMessage = NULL; + t0 = time_timeStamp(); + //unused: t_now = (double) (long) (time_timeStamp() + 0.5); + //unused: tbeg = t0; + tstatus = t0; + tstatus0 = t0; + lacquire = true; + in_loop = false; + + /*************************************************** + * Start of main acquisition loop + ***************************************************/ + while(lacquire) { + // Initialize the iteration + amqMessage = NULL; + // Don't start loop until prop.waitTime has elapsed (default 1 second) + t1 = time_timeStamp(); + double tloop = t1-t0; + + // Print time for the previous iteration. Only print once until + // props.waitTime has been reached and iteration actually starts again. + if (in_loop) { + LOG_MSG("== [GFAST t1:%f] Main loop [Timing: %.4fs]\n", t1, tloop); + in_loop = false; + } + + if (tloop < props.waitTime) { + continue; + } + else if ((props.waitTime>0.0)&&((tloop) >= 2*props.waitTime)) { + LOG_MSG("== [GFAST t :%f] Main loop [Timing: %.4fs] >= 2x%f s waitTimes. not keeping up", + time_timeStamp(), tloop, props.waitTime); + } + + t0 = t1; + tstatus1 = t0; + in_loop = true; + LOG_MSG("== [GFAST t0:%f] Beginning main loop", t0); + + if (tstatus1 - tstatus0 > 3600.0) { + LOG_DEBUGMSG("%s: GFAST has been running for %d hours, start time %f", + fcnm, (int) ((tstatus1 - tstatus)/3600.0), tstatus); + LOG_DEBUGMSG("%s: Version %s (Build %s %s by %s)\n", + fcnm, GFAST_VERSION, __DATE__, __TIME__, BUILDER); + tstatus0 = tstatus1; + } + + LOG_MSG("== [GFAST t :%f] Get the msgs off the EW ring", time_timeStamp()); + double tbeger = time_timeStamp(); + memory_free8c(&msgs); + msgs = traceBuffer_ewrr_getMessagesFromRing(MAX_MESSAGES, + false, + &ringInfo, + tb2Data.hashmap, + &nTracebufs2Read, + &ierr); + LOG_MSG("== [GFAST t :%f] getMessages returned nTracebufs2Read:%d", + time_timeStamp(), nTracebufs2Read); + + if (ierr < 0 || (msgs == NULL && nTracebufs2Read > 0)) { + if (ierr ==-1) { + LOG_ERRMSG("%s: Terminate message received from ring\n", fcnm); + ierr = 1; + } else if (ierr ==-2) { + LOG_ERRMSG("%s: Read error encountered on ring\n", fcnm); + ierr = 1; + } else if (ierr ==-3) { + LOG_ERRMSG("%s: Ring info structure never initialized\n", fcnm); + ierr = 1; + } else if (msgs == NULL) { + LOG_ERRMSG("%s: Message allocation error\n", fcnm); + ierr = 1; + } + goto ERROR; + } + LOG_MSG("scrounge [Timing: %.4fs]", time_timeStamp() - tbeger); + tbeger = time_timeStamp(); + + // Unpackage the tracebuf2 messages + LOG_MSG("%s", "== Calling unpackTraceBuf2Messages"); + ierr = traceBuffer_ewrr_unpackTraceBuf2Messages(nTracebufs2Read, + msgs, &tb2Data); + memory_free8c(&msgs); + LOG_MSG("== Ending unpackTraceBuf2Messages: [Timing: %.4fs]", + time_timeStamp() - tbeger); + if (ierr != 0) { + LOG_ERRMSG("%s: Error unpacking tracebuf2 messages\n", fcnm); + goto ERROR; + } + + // Update the hdf5 buffers + ierr = traceBuffer_h5_setData(t1, + tb2Data, + h5traceBuffer); + if (ierr != 0) { + LOG_ERRMSG("%s: Error setting data in H5 file\n", fcnm); + goto ERROR; + } + + // Check for an event + if (USE_AMQ) { + if (props.verbose > 2) { + LOG_MSG("%s: Checking Activemq for events", fcnm); + } + msWait = props.activeMQ_props.msWaitForMessage; + // amqMessage = GFAST_activeMQ_consumer_getMessage(amqMessageListener, msWait, &ierr); + amqMessage = eventReceiverGetMessage(msWait, &ierr); + if ((props.verbose > 2) && (amqMessage == NULL)) { + LOG_MSG("%s: Activemq returned NULL", fcnm); + } + } + if (amqMessage == NULL && check_message_dir) { + // Alternatively, check for SA message trigger in message_dir + amqMessage = check_dir_for_messages(message_dir, &ierr); + if ((ierr != 0) && (props.verbose > 2)) { + LOG_MSG("check_dir_for_messages returned ierr=%d\n", ierr); + ierr=0; + } + } + + if (ierr != 0) { + LOG_ERRMSG("%s: Internal error when getting message\n", fcnm); + goto ERROR; + } + // If there's a message then process it + if (amqMessage != NULL) { + LOG_MSG("== [GFAST t0:%f] Got new amqMessage:", t0); + LOG_MSG("%s", amqMessage); + // Parse the event message + ierr = GFAST_eewUtils_parseCoreXML(amqMessage, -12345.0, &SA); + if (ierr != 0) { + LOG_ERRMSG("%s: Error parsing the activeMQ trigger message\n", + fcnm); + LOG_ERRMSG("%s\n", amqMessage); + goto ERROR; + } + if (t1 - SA.time > props.processingTime) { + // If a message comes in more than processingTime s late, the hd5 file + // would already be closed and would lead to a crash when trying to reopen. + LOG_MSG("Ignoring message from SA, v%d, current time %f - origin time %f > process time %f", + SA.version, t1, SA.time, props.processingTime); + } else if (strncasecmp(SA.orig_sys, "gfast", 5) == 0) { + LOG_MSG("ignoring activeMQ message from gfast: evid=%s orig_sys=%s", + SA.eventid, SA.orig_sys); + } else { // don't trigger on gfast messages + // If this is a new event we have some file handling to do + LOG_MSG("MTH: call newEvent events.nev=%d xml_status.nev=%d\n", + events.nev, xml_status.nev); + lnewEvent = GFAST_core_events_newEvent(SA, &events, &xml_status); + LOG_MSG("%s", "MTH: call newEvent DONE"); + if (lnewEvent){ + LOG_MSG("NEW event evid:%s lat:%7.3f lon:%8.3f dep:%6.2f mag:%.2f time:%.2f age_now:%.0f", + SA.eventid, SA.lat, SA.lon, SA.dep, SA.mag, SA.time, t0 - SA.time); + } else { + LOG_MSG("This is NOT a new event: evid=%s", SA.eventid); + } + if (lnewEvent) { + // And the logs + if (props.verbose > 0) { + LOG_INFOMSG("%s: New event %s added", fcnm, SA.eventid); + if (props.verbose > 2){GFAST_core_events_printEvents(SA);} + } + // Initialize the HDF5 file + ierr = GFAST_hdf5_initialize(props.h5ArchiveDir, + SA.eventid, + props.propfilename); + if (ierr != 0) { + LOG_ERRMSG("%s: Error initializing the archive file", fcnm); + goto ERROR; + } + } + } //end gfast message if/else check + free(amqMessage); + amqMessage = NULL; + } // End check on ActiveMQ message + + // Are there events to process? + if (events.nev < 1){continue;} + if (props.verbose > 2) { + LOG_DEBUGMSG("%s: Processing events...", fcnm); + } + LOG_MSG("== [GFAST t0:%f] Call driveGFAST:", t0); + ierr = eewUtils_driveGFAST(t1, + program_instance, + props, + &events, + &gps_data, + &h5traceBuffer, + &pgd_data, + &cmt_data, + &ff_data, + &pgd, + &cmt, + &ff, + &xmlMessages, + &xml_status); + if (ierr != 0) { + LOG_ERRMSG("%s: Error calling GFAST driver!\n", fcnm); + goto ERROR; + } + + // This whole xmlMessages struct isn't currently necessary since messages are handled and + // sent in driveGFAST, but keeping for now in case we want to change back - CWU + // Send the messages where they need to go + if (xmlMessages.mmessages > 0) { + for (im=0; imd_name[0] != '.') { + ext = strrchr(de->d_name, '.'); + //printf("%s ext=[%s]\n", de->d_name, ext); + if (ext && !strcmp(ext+1, "xml")) { + //printf("%s ext=[%s] len=%ld\n", de->d_name, ext, strlen(de->d_name)); + + /* + 2 because of the '/' and the terminating 0 */ + fullpath = malloc(dirlen + strlen(de->d_name) + 2); + sprintf(fullpath, "%s/%s", dirname, de->d_name); + + f = fopen(fullpath, "r"); + if (f) { + fseek(f, 0, SEEK_END); + length = ftell(f); + fseek(f, 0, SEEK_SET); + buffer = (char *)malloc((length+1)*sizeof(char)); + if (buffer) { + fread(buffer,sizeof(char), length, f); + } + fclose(f); + buffer[length] = '\0'; + message = buffer; + } else { + LOG_ERRMSG("Error reading from file:%s\n", fullpath); + //return NULL; + goto ERROR; + } + + // Now remove the event file we just read: + *ierr = remove(fullpath); + if (*ierr != 0) { + LOG_ERRMSG("gfast_eew: Unable to delete file:%s\n", fullpath); + } + + free(fullpath); + nevents++; + } + } + } + closedir(dr); + //printf("Return nevents=%d\n" , nevents); + *ierr = 0; + return message; + + ERROR:; + closedir(dr); + return NULL; +} + diff --git a/src/gfast_playback.c b/src/gfast_playback.c new file mode 100644 index 00000000..bac64ca9 --- /dev/null +++ b/src/gfast_playback.c @@ -0,0 +1,291 @@ +#include +#include +#include +#include +#include +#include "gfast.h" +#include "gfast_eewUtils.h" +#include "iscl/iscl/iscl.h" +#include "iscl/os/os.h" +#include "iscl/time/time.h" + +int main(int argc, char *argv[]) +{ + const char *fcnm = "gfast_playback\0"; + char propfilename[PATH_MAX]; // = "gfast.props\0"; + FILE *elarms_xml_file; + struct GFAST_activeEvents_struct events; + struct GFAST_cmtResults_struct cmt; + struct GFAST_data_struct gps_data; + struct GFAST_ffResults_struct ff; + struct h5traceBuffer_struct h5traceBuffer; + struct GFAST_offsetData_struct cmt_data, ff_data; + struct GFAST_peakDisplacementData_struct pgd_data; + struct GFAST_pgdResults_struct pgd; + struct GFAST_props_struct props; + struct GFAST_shakeAlert_struct SA; + struct GFAST_xmlMessages_struct xmlMessages; + char errorLogFileName[PATH_MAX]; + char infoLogFileName[PATH_MAX]; + char debugLogFileName[PATH_MAX]; + char warnLogFileName[PATH_MAX]; + char *elarms_xml_message; + double currentTime, dtmax, t0sim, tbeg; + const enum opmode_type opmode = OFFLINE; + int ierr, im, k, kt, ntsim; + bool lnewEvent; + size_t message_length; + //------------------------------------------------------------------------// + // + // Read the input file + iscl_init(); + if (argc != 2) + { + printf("Usage: %s property_file_name\n", fcnm); + printf("Example: %s gfast.props\n", fcnm); + return EXIT_FAILURE; + } + memset(propfilename, 0, sizeof(propfilename)); + strcpy(propfilename, argv[1]); + if (!os_path_isfile(propfilename)) + { + LOG_ERRMSG("%s: Properties file %s doesn't exist\n", + fcnm, propfilename); + return EXIT_FAILURE; + } + // Initialize + ierr = 0; + elarms_xml_message = NULL; + memset(&props, 0, sizeof(struct GFAST_props_struct)); + memset(&gps_data, 0, sizeof(struct GFAST_data_struct)); + memset(&events, 0, sizeof(struct GFAST_activeEvents_struct)); + memset(&pgd, 0, sizeof(struct GFAST_pgdResults_struct)); + memset(&cmt, 0, sizeof(struct GFAST_cmtResults_struct)); + memset(&ff, 0, sizeof(struct GFAST_ffResults_struct)); + memset(&pgd_data, 0, sizeof( struct GFAST_peakDisplacementData_struct)); + memset(&cmt_data, 0, sizeof(struct GFAST_offsetData_struct)); + memset(&ff_data, 0, sizeof(struct GFAST_offsetData_struct)); + memset(&xmlMessages, 0, sizeof(struct GFAST_xmlMessages_struct)); + memset(&h5traceBuffer, 0, sizeof(struct h5traceBuffer_struct)); + // Read the properties file + LOG_INFOMSG("%s: Reading the properties file...\n", fcnm); + ierr = GFAST_core_properties_initialize(propfilename, opmode, &props); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error reading the GFAST properties file\n", fcnm); + goto ERROR; + } + if (props.verbose > 2) + { + GFAST_core_properties_print(props); + } + // Initialize the buffers + ierr = GFAST_core_data_initialize(props, &gps_data); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error initializing data buffers\n", fcnm); + goto ERROR; + } + // Initialize PGD + ierr = GFAST_core_scaling_pgd_initialize(props.pgd_props, gps_data, + &pgd, &pgd_data); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error initializing PGD\n", fcnm); + goto ERROR; + } + // Initialize CMT + ierr = GFAST_core_cmt_initialize(props.cmt_props, gps_data, + &cmt, &cmt_data); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error initializing CMT\n", fcnm); + goto ERROR; + } + // Initialize finite fault + ierr = GFAST_core_ff_initialize(props.ff_props, gps_data, + &ff, &ff_data); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error initializing FF\n", fcnm); + goto ERROR; + } + // Set the trace buffer names and open the HDF5 datafile + ierr = GFAST_traceBuffer_h5_setTraceBufferFromGFAST(props.bufflen, + gps_data, + &h5traceBuffer); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error setting the H5 tracebuffer\n", fcnm); + goto ERROR; + } + ierr = GFAST_traceBuffer_h5_initialize(1, true, props.obsdataDir, + props.obsdataFile, &h5traceBuffer); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error initializing H5 traebuffer\n", fcnm); + goto ERROR; + } + + // Compute the runtime + dtmax = 0.0; + for (k=0; k 0) + { + LOG_INFOMSG("%s: Number of time steps in simulation: %d\n", + fcnm, ntsim); + } + props.processingTime = fmin(props.processingTime, + (double) (ntsim - 1)*dtmax); + // Read the elarms file once and for all + elarms_xml_file = fopen(props.eewsfile, "rb"); + fseek(elarms_xml_file, 0L, SEEK_END); + message_length = (size_t) (ftell(elarms_xml_file)); + rewind(elarms_xml_file); + elarms_xml_message = (char *)calloc(message_length + 1, sizeof(char)); + if (fread(elarms_xml_message, message_length, 1, elarms_xml_file) == 0) + { + LOG_ERRMSG("%s: Error reading xml file\n", fcnm); + goto ERROR; + } + fclose(elarms_xml_file); + // Make the origin time the start time + ierr = GFAST_eewUtils_parseCoreXML(elarms_xml_message, -12345.0, &SA); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error parsing XML message\n", fcnm); + return ierr; + } + t0sim = SA.time; + tbeg = time_timeStamp(); + // Loop on time steps in simulation + for (kt=0; kt 0) + { + LOG_INFOMSG("%s: New event %s added\n", fcnm, SA.eventid); + if (props.verbose > 2){GFAST_core_events_printEvents(SA);} + } + // Set the log file names + eewUtils_setLogFileNames(SA.eventid,props.SAoutputDir, + errorLogFileName, infoLogFileName, + debugLogFileName, warnLogFileName); + if (os_path_isfile(errorLogFileName)) + { + remove(errorLogFileName); + } + if (os_path_isfile(infoLogFileName)) + { + remove(infoLogFileName); + } + if (os_path_isfile(debugLogFileName)) + { + remove(debugLogFileName); + } + if (os_path_isfile(warnLogFileName)) + { + remove(warnLogFileName); + } + // Initialize the HDF5 file + ierr = GFAST_hdf5_initialize(props.h5ArchiveDir, + SA.eventid, + props.propfilename); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error initializing the archive file\n", + fcnm); + return -1; + } + } + } + // Compute the current time + currentTime = t0sim + (double) kt*dtmax; + ierr = eewUtils_driveGFAST(currentTime, + "gfast\0", + props, + &events, + &gps_data, + &h5traceBuffer, + &pgd_data, + &cmt_data, + &ff_data, + &pgd, + &cmt, + &ff, + &xmlMessages); + if (ierr != 0) + { + LOG_ERRMSG("%s: Error calling GFAST driver!\n", fcnm); + break; + } + if (xmlMessages.mmessages > 0) + { + for (im=0; im +#include +#include +#include +#include +#include "gfast_hdf5.h" +#include "gfast_core.h" +#ifdef GFAST_USE_INTEL +#include +#else +#include +#endif +#include "iscl/memory/memory.h" + +#ifndef MAX +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#endif + +//============================================================================// +int hdf5_copyPeakDisplacementData( + const enum data2h5_enum job, + struct GFAST_peakDisplacementData_struct *pgd_data, + struct h5_peakDisplacementData_struct *h5_pgd_data) +{ + int *lactiveTemp, *lmaskTemp, i, ierr; + //char *stnTemp; unused + char *ctemp; + char (*ptr)[64]; + size_t nsites; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + // Make sure there is something to do + nsites = (size_t) pgd_data->nsites; + if (nsites < 1) + { + LOG_ERRMSG("%s", "No sites!"); + ierr = 1; + return ierr; + } + + h5_pgd_data->pd.len = nsites; + h5_pgd_data->pd.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(pgd_data->nsites, pgd_data->pd, 1, h5_pgd_data->pd.p, 1); + + h5_pgd_data->wt.len = nsites; + h5_pgd_data->wt.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(pgd_data->nsites, pgd_data->wt, 1, h5_pgd_data->wt.p, 1); + + h5_pgd_data->sta_lat.len = nsites; + h5_pgd_data->sta_lat.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(pgd_data->nsites, pgd_data->sta_lat, 1, + h5_pgd_data->sta_lat.p, 1); + + h5_pgd_data->sta_lon.len = nsites; + h5_pgd_data->sta_lon.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(pgd_data->nsites, pgd_data->sta_lon, 1, + h5_pgd_data->sta_lon.p, 1); + + h5_pgd_data->sta_alt.len = nsites; + h5_pgd_data->sta_alt.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(pgd_data->nsites, pgd_data->sta_alt, 1, + h5_pgd_data->sta_alt.p, 1); + + h5_pgd_data->stnm.len = nsites; + ctemp = (char *)calloc(64*nsites, sizeof(char)); + + h5_pgd_data->lactive.len = nsites; + lactiveTemp = (int *)calloc(nsites, sizeof(int)); + + h5_pgd_data->lmask.len = nsites; + lmaskTemp = (int *)calloc(nsites, sizeof(int)); + for (i=0; i<(int) nsites; i++) + { + lactiveTemp[i] = pgd_data->lactive[i]; + lmaskTemp[i] = pgd_data->lmask[i]; + strcpy(&ctemp[i*64], pgd_data->stnm[i]); + //printf("copy peakDisplacement pgd_data to h5: pgd_data->stnm[%d]=%s\n", i, pgd_data->stnm[i]); + } + h5_pgd_data->stnm.p = ctemp; + h5_pgd_data->lactive.p = lactiveTemp; + h5_pgd_data->lmask.p = lmaskTemp; + + h5_pgd_data->nsites = (int) nsites; + } + else if (job == COPY_H5_TO_DATA) + { + //printf("MTH: copy h5 peakDisplacementData to GFAST struct\n"); + //memset(pgd_data, 0, sizeof(struct GFAST_peakDisplacementData_struct)); + + // Make sure there is something to do + nsites = (size_t) h5_pgd_data->nsites; + //printf("MTH: copy h5 peakDisplacementData nsites=%d\n", nsites); + if (nsites < 1) + { + LOG_ERRMSG("%s", "No sites!"); + ierr = 1; + return ierr; + } + + pgd_data->nsites = nsites; + + pgd_data->pd = memory_calloc64f(pgd_data->nsites); + cblas_dcopy(pgd_data->nsites, h5_pgd_data->pd.p, 1, pgd_data->pd, 1); + + pgd_data->wt = memory_calloc64f(pgd_data->nsites); + cblas_dcopy(pgd_data->nsites, h5_pgd_data->wt.p, 1, pgd_data->wt, 1); + + pgd_data->sta_lat = memory_calloc64f(pgd_data->nsites); + cblas_dcopy(pgd_data->nsites, h5_pgd_data->sta_lat.p, 1, pgd_data->sta_lat, 1); + + pgd_data->sta_lon = memory_calloc64f(pgd_data->nsites); + cblas_dcopy(pgd_data->nsites, h5_pgd_data->sta_lon.p, 1, pgd_data->sta_lon, 1); + + pgd_data->sta_alt = memory_calloc64f(pgd_data->nsites); + cblas_dcopy(pgd_data->nsites, h5_pgd_data->sta_alt.p, 1, pgd_data->sta_alt, 1); + + pgd_data->stnm = (char **)calloc((size_t)pgd_data->nsites, sizeof(char *)); + ptr = h5_pgd_data->stnm.p; + //ctemp = (char *)calloc((size_t)64, sizeof(char)); + for (i=0;i<(int)h5_pgd_data->stnm.len;i++){ + //strcpy(ctemp, ptr[i]); + pgd_data->stnm[i] = (char *)calloc((size_t)64, sizeof(char)); + strcpy(pgd_data->stnm[i], ptr[i]); + //puts(pgd_data->stnm[i]); + } + + lmaskTemp = (int *) h5_pgd_data->lmask.p; + pgd_data->lmask = memory_calloc8l(pgd_data->nsites); + for (i=0; insites; i++) + { + pgd_data->lmask[i] = (bool) lmaskTemp[i]; + } + lactiveTemp = (int *) h5_pgd_data->lactive.p; + pgd_data->lactive = memory_calloc8l(pgd_data->nsites); + for (i=0; insites; i++) + { + pgd_data->lactive[i] = (bool) lactiveTemp[i]; + } + + } + + else + { + LOG_ERRMSG("Invalid job=%d", job); + ierr = 1; + } + //printf("MTH: copy h5 peakDisplacementData return ierr=%d\n", ierr); + return ierr; +} +//============================================================================// +int hdf5_copyOffsetData(const enum data2h5_enum job, + struct GFAST_offsetData_struct *offset_data, + struct h5_offsetData_struct *h5_offset_data) +{ + char *ctemp; + int *lactiveTemp, *lmaskTemp, i, ierr; + size_t nsites; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + memset(h5_offset_data, 0, sizeof(struct h5_offsetData_struct)); + // Make sure there is something to do + nsites = (size_t) offset_data->nsites; + if (nsites < 1) + { + if (nsites < 1){LOG_ERRMSG("%s", "No sites!");} + ierr = 1; + return ierr; + } + + h5_offset_data->ubuff.len = nsites; + h5_offset_data->ubuff.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->ubuff, 1, + h5_offset_data->ubuff.p, 1); + + h5_offset_data->nbuff.len = nsites; + h5_offset_data->nbuff.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->nbuff, 1, + h5_offset_data->nbuff.p, 1); + + h5_offset_data->ebuff.len = nsites; + h5_offset_data->ebuff.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->ebuff, 1, + h5_offset_data->ebuff.p, 1); + + h5_offset_data->wtu.len = nsites; + h5_offset_data->wtu.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->wtu, 1, + h5_offset_data->wtu.p, 1); + + h5_offset_data->wtn.len = nsites; + h5_offset_data->wtn.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->wtn, 1, + h5_offset_data->wtn.p, 1); + + h5_offset_data->wte.len = nsites; + h5_offset_data->wte.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->wte, 1, + h5_offset_data->wte.p, 1); + + h5_offset_data->sta_lat.len = nsites; + h5_offset_data->sta_lat.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->sta_lat, 1, + h5_offset_data->sta_lat.p, 1); + + h5_offset_data->sta_lon.len = nsites; + h5_offset_data->sta_lon.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->sta_lon, 1, + h5_offset_data->sta_lon.p, 1); + + h5_offset_data->sta_alt.len = nsites; + h5_offset_data->sta_alt.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(offset_data->nsites, offset_data->sta_alt, 1, + h5_offset_data->sta_alt.p, 1); + + h5_offset_data->stnm.len = nsites; + ctemp = (char *)calloc(64*nsites, sizeof(char)); + + h5_offset_data->lactive.len = nsites; + lactiveTemp = (int *)calloc(nsites, sizeof(int)); + + h5_offset_data->lmask.len = nsites; + lmaskTemp = (int *)calloc(nsites, sizeof(int)); + for (i=0; i<(int) nsites; i++) + { + lactiveTemp[i] = offset_data->lactive[i]; + lmaskTemp[i] = offset_data->lmask[i]; + strcpy(&ctemp[i*64], offset_data->stnm[i]); + } + h5_offset_data->stnm.p = ctemp; + h5_offset_data->lactive.p = lactiveTemp; + h5_offset_data->lmask.p = lmaskTemp; + + h5_offset_data->nsites = (int) nsites; + } + else if (job == COPY_H5_TO_DATA) + { + LOG_ERRMSG("%s", "Error not yet done"); + ierr = 1; + } + else + { + LOG_ERRMSG("%s", "Invalid job"); + ierr = 1; + } + return ierr; +} +//============================================================================// +/*! + * @brief Copies PGD results structure to/from HDF5 PGD results structure + * + * @param[in] job if job = COPY_DATA_TO_H5 then copy pgd -> h5_pgd. + * if job = COPY_H5_TO_DATA then copy h5_pgd -> pgd. + * + * @param[in,out] pgd if job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to h5_pgd. + * if job = COPY_H5_TO_DATA then on output this is the + * copied h5_pgd structure. + * @param[in,out] h5_pgd if job = COPY_DATA_TO_H5 then on output this is the + * HDF5 version of pgd. + * if job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to pgd. + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int hdf5_copyPGDResults(const enum data2h5_enum job, + struct GFAST_pgdResults_struct *pgd, + struct h5_pgdResults_struct *h5_pgd) +{ + int *lsiteUsedTemp, i, ierr, nlld; + size_t ndeps, nlats, nlons, nloc, nsites; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + memset(h5_pgd, 0, sizeof(struct h5_pgdResults_struct)); + // Make sure there is something to do + ndeps = (size_t) pgd->ndeps; + nsites = (size_t) pgd->nsites; + nlats = (size_t) pgd->nlats; + nlons = (size_t) pgd->nlons; + if (ndeps < 1 || nsites < 1 || nlats < 1 || nlons < 1) + { + if (nsites < 1){LOG_ERRMSG("%s", "No sites!");} + if (ndeps < 1){LOG_ERRMSG("%s", "No depths!");} + if (nlats < 1){LOG_ERRMSG("%s", "No lats!");} + if (nlons < 1){LOG_ERRMSG("%s", "No lons!");} + ierr = 1; + return ierr; + } + nloc = ndeps*nlats*nlons; + + h5_pgd->mpgd.len = nloc; + h5_pgd->mpgd.p = (double *)calloc(nloc, sizeof(double)); + cblas_dcopy((int) nloc, pgd->mpgd, 1, h5_pgd->mpgd.p, 1); + + h5_pgd->mpgd_vr.len = nloc; + h5_pgd->mpgd_vr.p = (double *)calloc(nloc, sizeof(double)); + cblas_dcopy((int) nloc, pgd->mpgd_vr, 1, h5_pgd->mpgd_vr.p, 1); + + h5_pgd->dep_vr_pgd.len = nloc; + h5_pgd->dep_vr_pgd.p = (double *)calloc(ndeps, sizeof(double)); + cblas_dcopy((int) nloc, pgd->dep_vr_pgd, 1, h5_pgd->dep_vr_pgd.p, 1); + + h5_pgd->UP.len = nsites*nloc; //ndeps; + h5_pgd->UP.p = (double *)calloc(nsites*nloc, sizeof(double)); + cblas_dcopy((int) (nsites*nloc), pgd->UP, 1, h5_pgd->UP.p, 1); + + h5_pgd->srdist.len = nsites*nloc; //ndeps; + h5_pgd->srdist.p = (double *)calloc(nsites*nloc, sizeof(double)); + cblas_dcopy((int) (nsites*nloc), pgd->srdist, 1, + h5_pgd->srdist.p, 1); + + h5_pgd->UPinp.len = nsites; + h5_pgd->UPinp.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(pgd->nsites, pgd->UPinp, 1, h5_pgd->UPinp.p, 1); + + h5_pgd->srcDepths.len = ndeps; + h5_pgd->srcDepths.p = (double *)calloc(ndeps, sizeof(double)); + cblas_dcopy(pgd->ndeps, pgd->srcDepths, 1, h5_pgd->srcDepths.p, 1); + + h5_pgd->iqr.len = nloc; //ndeps; + h5_pgd->iqr.p = (double *)calloc(nloc, sizeof(double)); + cblas_dcopy((int) nloc, pgd->iqr, 1, h5_pgd->iqr.p, 1); + + h5_pgd->lsiteUsed.len = nsites; + lsiteUsedTemp = (int *)calloc(nsites, sizeof(int)); + for (i=0; i<(int) nsites; i++) + { + lsiteUsedTemp[i] = (int) pgd->lsiteUsed[i]; + } + h5_pgd->lsiteUsed.p = lsiteUsedTemp; + + h5_pgd->ndeps = (int) ndeps; + h5_pgd->nsites = (int) nsites; + h5_pgd->nlats = pgd->nlats; + h5_pgd->nlons = pgd->nlons; + } + else if (job == COPY_H5_TO_DATA) + { + memset(pgd, 0, sizeof(struct GFAST_pgdResults_struct)); + // Make sure there is something to do + pgd->ndeps = h5_pgd->ndeps; + pgd->nsites = h5_pgd->nsites; + pgd->nlats = h5_pgd->nlats; + pgd->nlons = h5_pgd->nlons; + if (pgd->ndeps < 1 || pgd->nsites < 1 || + pgd->nlats < 1 || pgd->nlons < 1) + { + if (pgd->nsites < 1){LOG_ERRMSG("%s", "No sites!");} + if (pgd->ndeps < 1){LOG_ERRMSG("%s", "No depths!");} + if (pgd->nlats < 1){LOG_ERRMSG("%s", "No lats!");} + if (pgd->nlons < 1){LOG_ERRMSG("%s", "No lons!");} + ierr = 1; + return ierr; + } + nlld = pgd->nlats*pgd->nlons*pgd->ndeps; + + pgd->mpgd = memory_calloc64f(nlld); + cblas_dcopy(nlld, h5_pgd->mpgd.p, 1, pgd->mpgd, 1); + + pgd->mpgd_vr = memory_calloc64f(nlld); + cblas_dcopy(nlld, h5_pgd->mpgd_vr.p, 1, pgd->mpgd_vr, 1); + + pgd->dep_vr_pgd = memory_calloc64f(nlld); + cblas_dcopy(nlld, h5_pgd->dep_vr_pgd.p, 1, pgd->dep_vr_pgd, 1); + + pgd->UP = memory_calloc64f(pgd->nsites*nlld); + cblas_dcopy(pgd->nsites*nlld, h5_pgd->UP.p, 1, pgd->UP, 1); + + pgd->srdist = memory_calloc64f(pgd->nsites*nlld); + cblas_dcopy(pgd->nsites*nlld, h5_pgd->srdist.p, 1, + pgd->srdist, 1); + + pgd->UPinp = memory_calloc64f(pgd->nsites); + cblas_dcopy(pgd->nsites, h5_pgd->UPinp.p, 1, pgd->UPinp, 1); + + pgd->srcDepths = memory_calloc64f(pgd->ndeps); + cblas_dcopy(pgd->ndeps, h5_pgd->srcDepths.p, 1, pgd->srcDepths, 1); + + pgd->iqr = memory_calloc64f(nlld); + cblas_dcopy(nlld, h5_pgd->iqr.p, 1, pgd->iqr, 1); + + lsiteUsedTemp = (int *) h5_pgd->lsiteUsed.p; + pgd->lsiteUsed = memory_calloc8l(pgd->nsites); + for (i=0; insites; i++) + { + pgd->lsiteUsed[i] = (bool) lsiteUsedTemp[i]; + } + lsiteUsedTemp = NULL; + } + else + { + LOG_ERRMSG("Invalid job=%d\n", job); + ierr = 1; + } + return ierr; +} +//============================================================================// +/*! + * @brief Copies hypocenter structure to/from HDF5 hypocenter structure + * + * @param[in] job if job = COPY_DATA_TO_H5 then copy cmt -> h5_cmt. + * if job = COPY_H5_TO_DATA then copy h5_cmt -> cmt. + * + * @param[in,out] hypo if job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to h5_hypo. + * if job = COPY_H5_TO_DATA then on output this is the + * copied h5_hypo structure. + * @param[in,out] h5_hypo if job = COPY_DATA_TO_H5 then on output this is the + * HDF5 version of hypo. + * if job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to hypo. + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int hdf5_copyHypocenter(const enum data2h5_enum job, + struct GFAST_shakeAlert_struct *hypo, + struct h5_hypocenter_struct *h5_hypo) +{ + int ierr; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + memset(h5_hypo, 0, sizeof(struct h5_hypocenter_struct)); + strncpy(h5_hypo->eventid, hypo->eventid, 128*sizeof(char)); + h5_hypo->lat = hypo->lat; + h5_hypo->lon = hypo->lon; + h5_hypo->dep = hypo->dep; + h5_hypo->mag = hypo->mag; + h5_hypo->time = hypo->time; + } + else if (job == COPY_H5_TO_DATA) + { + memset(hypo, 0, sizeof(struct GFAST_shakeAlert_struct)); + memcpy(hypo->eventid, h5_hypo->eventid, 128*sizeof(char)); + hypo->lat = h5_hypo->lat; + hypo->lon = h5_hypo->lon; + hypo->dep = h5_hypo->dep; + hypo->mag = h5_hypo->mag; + hypo->time = h5_hypo->time; + } + else + { + LOG_ERRMSG("%s", "Invalid job"); + ierr = 1; + } + return ierr; +} +//============================================================================// +/*! + * @brief Copies CMT results structure to/from HDF5 CMT results structure + * + * @param[in] job if job = COPY_DATA_TO_H5 then copy cmt -> h5_cmt. + * if job = COPY_H5_TO_DATA then copy h5_cmt -> cmt. + * + * @param[in,out] cmt if job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to h5_cmt. + * if job = COPY_H5_TO_DATA then on output this is the + * copied h5_cmt structure. + * @param[in,out] h5_cmt if job = COPY_DATA_TO_H5 then on output this is the + * HDF5 version of cmt. + * if job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to cmt. + * + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int hdf5_copyCMTResults(const enum data2h5_enum job, + struct GFAST_cmtResults_struct *cmt, + struct h5_cmtResults_struct *h5_cmt) +{ + int *lsiteUsedTemp, i, ierr, ncopy; + size_t ndeps, nlats, nlons, nlld, nsites; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + memset(h5_cmt, 0, sizeof(struct h5_cmtResults_struct)); + // Make sure there is something to do + ndeps = (size_t) cmt->ndeps; + nsites = (size_t) cmt->nsites; + nlats = (size_t) cmt->nlats; + nlons = (size_t) cmt->nlons; + nlld = ndeps*nlats*nlons; + ncopy = cmt->ndeps*cmt->nlats*cmt->nlons; + if (ndeps < 1 || nsites < 1 || nlats < 1 || nlons < 1) + { + if (nsites < 1){LOG_ERRMSG("%s", "No sites!");} + if (ndeps < 1){LOG_ERRMSG("%s", "No depths!");} + if (nlats < 1){LOG_ERRMSG("%s", "No lats!");} + if (nlons < 1){LOG_ERRMSG("%s", "No lons!");} + ierr = 1; + return ierr; + } + h5_cmt->l2.len = nlld; //ndeps; + h5_cmt->l2.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->l2, 1, h5_cmt->l2.p, 1); + + h5_cmt->pct_dc.len = nlld; //ndeps; + h5_cmt->pct_dc.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->pct_dc, 1, h5_cmt->pct_dc.p, 1); + + h5_cmt->objfn.len = nlld; //ndeps; + h5_cmt->objfn.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->objfn, 1, h5_cmt->objfn.p, 1); + + h5_cmt->mts.len = 6*nlld; //ndeps; + h5_cmt->mts.p = (double *)calloc(6*nlld, sizeof(double)); + cblas_dcopy((int) (6*nlld), cmt->mts, 1, h5_cmt->mts.p, 1); + + h5_cmt->str1.len = nlld; //ndeps; + h5_cmt->str1.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->str1, 1, h5_cmt->str1.p, 1); + + h5_cmt->str2.len = nlld; //ndeps; + h5_cmt->str2.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->str2, 1, h5_cmt->str2.p, 1); + + h5_cmt->dip1.len = nlld; //ndeps; + h5_cmt->dip1.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->dip1, 1, h5_cmt->dip1.p, 1); + + h5_cmt->dip2.len = nlld; //ndeps; + h5_cmt->dip2.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->dip2, 1, h5_cmt->dip2.p, 1); + + h5_cmt->rak1.len = nlld; //ndeps; + h5_cmt->rak1.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->rak1, 1, h5_cmt->rak1.p, 1); + + h5_cmt->rak2.len = nlld; //ndeps; + h5_cmt->rak2.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->rak2, 1, h5_cmt->rak2.p, 1); + + h5_cmt->Mw.len = nlld; //ndeps; + h5_cmt->Mw.p = (double *)calloc(nlld, sizeof(double)); + cblas_dcopy((int) nlld, cmt->Mw, 1, h5_cmt->Mw.p, 1); + + h5_cmt->srcDepths.len = ndeps; + h5_cmt->srcDepths.p = (double *)calloc(ndeps, sizeof(double)); + cblas_dcopy(cmt->ndeps, cmt->srcDepths, 1, h5_cmt->srcDepths.p, 1); + + h5_cmt->EN.len = nsites*nlld; + h5_cmt->EN.p = (double *)calloc(nsites*nlld, sizeof(double)); + cblas_dcopy(cmt->nsites*ncopy, cmt->EN, 1, h5_cmt->EN.p, 1); + + h5_cmt->NN.len = nsites*nlld; + h5_cmt->NN.p = (double *)calloc(nsites*nlld, sizeof(double)); + cblas_dcopy(cmt->nsites*ncopy, cmt->NN, 1, h5_cmt->NN.p, 1); + + h5_cmt->UN.len = nsites*nlld; + h5_cmt->UN.p = (double *)calloc(nsites*nlld, sizeof(double)); + cblas_dcopy(cmt->nsites*ncopy, cmt->UN, 1, h5_cmt->UN.p, 1); + + h5_cmt->Einp.len = nsites; + h5_cmt->Einp.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(cmt->nsites, cmt->Einp, 1, h5_cmt->Einp.p, 1); + + h5_cmt->Ninp.len = nsites; + h5_cmt->Ninp.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(cmt->nsites, cmt->Ninp, 1, h5_cmt->Ninp.p, 1); + + h5_cmt->Uinp.len = nsites; + h5_cmt->Uinp.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy(cmt->nsites, cmt->Uinp, 1, h5_cmt->Uinp.p, 1); + + h5_cmt->lsiteUsed.len = nsites; + lsiteUsedTemp = (int *)calloc(nsites, sizeof(int)); + for (i=0; i<(int) nsites; i++) + { + lsiteUsedTemp[i] = (int) cmt->lsiteUsed[i]; + } + h5_cmt->lsiteUsed.p = lsiteUsedTemp; + + + h5_cmt->opt_indx = cmt->opt_indx; + h5_cmt->ndeps = (int) ndeps; + h5_cmt->nsites = (int) nsites; + h5_cmt->nlats = (int) nlats; + h5_cmt->nlons = (int) nlons; + } + else if (job == COPY_H5_TO_DATA) + { + memset(cmt, 0, sizeof(struct GFAST_cmtResults_struct)); + // Make sure there is something to do + cmt->ndeps = h5_cmt->ndeps; + cmt->nsites = h5_cmt->nsites; + cmt->nlats = h5_cmt->nlats; + cmt->nlons = h5_cmt->nlons; + if (cmt->ndeps < 1 || cmt->nsites < 1) + { + if (cmt->nsites < 1){LOG_ERRMSG("%s", "No sites!");} + if (cmt->ndeps < 1){LOG_ERRMSG("%s", "No depths!");} + ierr = 1; + return ierr; + } + ncopy = cmt->ndeps*cmt->nlats*cmt->nlons; + cmt->l2 = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->l2.p, 1, cmt->l2, 1); + + cmt->pct_dc = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->pct_dc.p, 1, cmt->pct_dc, 1); + + cmt->objfn = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->objfn.p, 1, cmt->objfn, 1); + + cmt->mts = memory_calloc64f(6*ncopy); + cblas_dcopy(6*ncopy, h5_cmt->mts.p, 1, cmt->mts, 1); + + cmt->str1 = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->str1.p, 1, cmt->str1, 1); + + cmt->str2 = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->str2.p, 1, cmt->str2, 1); + + cmt->dip1 = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->dip1.p, 1, cmt->dip1, 1); + + cmt->dip2 = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->dip2.p, 1, cmt->dip2, 1); + + cmt->rak1 = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->rak1.p, 1, cmt->rak1, 1); + + cmt->rak2 = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->rak2.p, 1, cmt->rak2, 1); + + cmt->Mw = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->Mw.p, 1, cmt->Mw, 1); + + cmt->srcDepths = memory_calloc64f(ncopy); + cblas_dcopy(ncopy, h5_cmt->srcDepths.p, 1, cmt->srcDepths, 1); + + cmt->EN = memory_calloc64f(cmt->nsites*ncopy); + cblas_dcopy(cmt->nsites*ncopy, h5_cmt->EN.p, 1, cmt->EN, 1); + + cmt->NN = memory_calloc64f(cmt->nsites*ncopy); + cblas_dcopy(cmt->nsites*ncopy, h5_cmt->NN.p, 1, cmt->NN, 1); + + cmt->UN = memory_calloc64f(cmt->nsites*ncopy); + cblas_dcopy(cmt->nsites*ncopy, h5_cmt->UN.p, 1, cmt->UN, 1); + + cmt->Einp = memory_calloc64f(cmt->nsites); + cblas_dcopy(cmt->nsites, h5_cmt->Einp.p, 1, cmt->Einp, 1); + + cmt->Ninp = memory_calloc64f(cmt->nsites); + cblas_dcopy(cmt->nsites, h5_cmt->Ninp.p, 1, cmt->Ninp, 1); + + cmt->Uinp = memory_calloc64f(cmt->nsites); + cblas_dcopy(cmt->nsites, h5_cmt->Uinp.p, 1, cmt->Uinp, 1); + + lsiteUsedTemp = (int *) h5_cmt->lsiteUsed.p; + cmt->lsiteUsed = memory_calloc8l(cmt->nsites); + for (i=0; insites; i++) + { + cmt->lsiteUsed[i] = (bool) lsiteUsedTemp[i]; + } + lsiteUsedTemp = NULL; + } + else + { + LOG_ERRMSG("%s", "Invalid job"); + ierr = 1; + } + return ierr; +} +//============================================================================// + +int hdf5_copyFaultPlane(const enum data2h5_enum job, + struct GFAST_faultPlane_struct *fp, + struct h5_faultPlane_struct *h5_fp) +{ + int *itemp, i, ierr; + size_t nfp, nfp4, ndip, nsites, nstr; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + memset(h5_fp, 0, sizeof(struct h5_faultPlane_struct)); + // Make sure there is something to do + nstr = (size_t) fp->nstr; + ndip = (size_t) fp->ndip; + nsites = (size_t) fp->maxobs; //(size_t) fp->nsites_used; + if (nstr < 1 || ndip < 1 || nsites < 1) + { + if (nsites < 1){LOG_ERRMSG("%s", "No sites!");} + if (ndip < 1){LOG_ERRMSG("%s", "No faults down dip!");} + if (nstr < 1){LOG_ERRMSG("%s", "No faults along strike!");} + ierr = 1; + return ierr; + } + nfp = nstr*ndip; // number of fault patches + + nfp4 = 4*nfp; + h5_fp->lon_vtx.len = nfp4; + h5_fp->lon_vtx.p = (double *)calloc(nfp4, sizeof(double)); + cblas_dcopy((int) nfp4, fp->lon_vtx, 1, h5_fp->lon_vtx.p, 1); + + h5_fp->lat_vtx.len = nfp4; + h5_fp->lat_vtx.p = (double *)calloc(nfp4, sizeof(double)); + cblas_dcopy((int) nfp4, fp->lat_vtx, 1, h5_fp->lat_vtx.p, 1); + + h5_fp->dep_vtx.len = (size_t) (4*nfp); + h5_fp->dep_vtx.p = (double *)calloc(nfp4, sizeof(double)); + cblas_dcopy((int) nfp4, fp->dep_vtx, 1, h5_fp->dep_vtx.p, 1); + + h5_fp->fault_xutm.len = nfp; + h5_fp->fault_xutm.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->fault_xutm, 1, h5_fp->fault_xutm.p, 1); + + h5_fp->fault_yutm.len = nfp; + h5_fp->fault_yutm.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->fault_yutm, 1, h5_fp->fault_yutm.p, 1); + + h5_fp->fault_alt.len = nfp; + h5_fp->fault_alt.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->fault_alt, 1, h5_fp->fault_alt.p, 1); + + h5_fp->strike.len = nfp; + h5_fp->strike.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->strike, 1, h5_fp->strike.p, 1); + + h5_fp->dip.len = nfp; + h5_fp->dip.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->dip, 1, h5_fp->dip.p, 1); + + h5_fp->length.len = nfp; + h5_fp->length.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->length, 1, h5_fp->length.p, 1); + + h5_fp->width.len = nfp; + h5_fp->width.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->width, 1, h5_fp->width.p, 1); + + h5_fp->sslip.len = nfp; + h5_fp->sslip.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->sslip, 1, h5_fp->sslip.p, 1); + + h5_fp->dslip.len = nfp; + h5_fp->dslip.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->dslip, 1, h5_fp->dslip.p, 1); + + h5_fp->sslip_unc.len = nfp; + h5_fp->sslip_unc.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->sslip_unc, 1, h5_fp->sslip_unc.p, 1); + + h5_fp->dslip_unc.len = nfp; + h5_fp->dslip_unc.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, fp->dslip_unc, 1, h5_fp->dslip_unc.p, 1); + + h5_fp->EN.len = nsites; + h5_fp->EN.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy((int) nsites, fp->EN, 1, h5_fp->EN.p, 1); + + h5_fp->NN.len = nsites; + h5_fp->NN.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy((int) nsites, fp->NN, 1, h5_fp->NN.p, 1); + + h5_fp->UN.len = nsites; + h5_fp->UN.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy((int) nsites, fp->UN, 1, h5_fp->UN.p, 1); + + h5_fp->Einp.len = nsites; + h5_fp->Einp.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy((int) nsites, fp->Einp, 1, h5_fp->Einp.p, 1); + + h5_fp->Ninp.len = nsites; + h5_fp->Ninp.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy((int) nsites, fp->Ninp, 1, h5_fp->Ninp.p, 1); + + h5_fp->Uinp.len = nsites; + h5_fp->Uinp.p = (double *)calloc(nsites, sizeof(double)); + cblas_dcopy((int) nsites, fp->Uinp, 1, h5_fp->Uinp.p, 1); + + h5_fp->fault_ptr.len = nfp + 1; + itemp = (int *)calloc(nfp+1, sizeof(int)); + for (i=0; i<(int) nfp+1; i++) + { + itemp[i] = fp->fault_ptr[i]; + } + h5_fp->fault_ptr.p = itemp; + + h5_fp->maxobs = fp->maxobs; + h5_fp->nsites_used = fp->nsites_used; + h5_fp->nstr = fp->nstr; + h5_fp->ndip = fp->ndip; + } + else if (job == COPY_H5_TO_DATA) + { + memset(fp, 0, sizeof(struct GFAST_faultPlane_struct)); + fp->maxobs = h5_fp->maxobs; + fp->nsites_used = h5_fp->nsites_used; + fp->nstr = h5_fp->nstr; + fp->ndip = h5_fp->ndip; + // Make sure there is something to do + nstr = (size_t) fp->nstr; + ndip = (size_t) fp->ndip; + nsites = (size_t) fp->maxobs; //(size_t) fp->nsites_used; + if (nstr < 1 || ndip < 1 || nsites < 1) + { + if (nsites < 1){LOG_ERRMSG("%s", "No sites!");} + if (ndip < 1){LOG_ERRMSG("%s", "No faults down dip!");} + if (nstr < 1){LOG_ERRMSG("%s", "No faults along strike!");} + ierr = 1; + return ierr; + } + nfp = nstr*ndip; // number of fault patches + nfp4 = 4*nfp; + fp->lon_vtx = memory_calloc64f((int) nfp4); + cblas_dcopy((int) nfp4, h5_fp->lon_vtx.p, 1, fp->lon_vtx, 1); + + fp->lat_vtx = memory_calloc64f((int) nfp4); + cblas_dcopy((int) nfp4, h5_fp->lat_vtx.p, 1, fp->lat_vtx, 1); + + fp->dep_vtx = memory_calloc64f((int) nfp4); + cblas_dcopy((int) nfp4, h5_fp->dep_vtx.p, 1, fp->dep_vtx, 1); + + fp->fault_xutm = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->fault_xutm.p, 1, fp->fault_xutm, 1); + + fp->fault_yutm = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->fault_yutm.p, 1, fp->fault_yutm, 1); + + fp->fault_alt = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->fault_alt.p, 1, fp->fault_alt, 1); + + fp->strike = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->strike.p, 1, fp->strike, 1); + + fp->dip = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->dip.p, 1, fp->dip, 1); + + fp->length = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->length.p, 1, fp->length, 1); + + fp->width = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->width.p, 1, fp->width, 1); + + fp->sslip = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->sslip.p, 1, fp->sslip, 1); + + fp->dslip = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->dslip.p, 1, fp->dslip, 1); + + fp->sslip_unc = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->sslip_unc.p, 1, fp->sslip_unc, 1); + + fp->dslip_unc = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_fp->dslip_unc.p, 1, fp->dslip_unc, 1); + + fp->EN = memory_calloc64f((int) nsites); + cblas_dcopy((int) nsites, h5_fp->EN.p, 1, fp->EN, 1); + + fp->NN = memory_calloc64f((int) nsites); + cblas_dcopy((int) nsites, h5_fp->NN.p, 1, fp->NN, 1); + + fp->UN = memory_calloc64f((int) nsites); + cblas_dcopy((int) nsites, h5_fp->UN.p, 1, fp->UN, 1); + + fp->Einp = memory_calloc64f((int) nsites); + cblas_dcopy((int) nsites, h5_fp->Einp.p, 1, fp->Einp, 1); + + fp->Ninp = memory_calloc64f((int) nsites); + cblas_dcopy((int) nsites, h5_fp->Ninp.p, 1, fp->Ninp, 1); + + fp->Uinp = memory_calloc64f((int) nsites); + cblas_dcopy((int) nsites, h5_fp->Uinp.p, 1, fp->Uinp, 1); + + itemp = h5_fp->fault_ptr.p; + fp->fault_ptr = memory_calloc32i((int) nfp+1); + for (i=0; i<(int) nfp+1; i++) + { + fp->fault_ptr[i] = itemp[i]; + } + itemp = NULL; + } + else + { + LOG_ERRMSG("%s", "Invalid job"); + ierr = 1; + } + return ierr; +} +//============================================================================// +/*! + * @brief Copies finite fault results structure to/from HDF5 finite fault + * results structure. + * + * @param[in] job If job = COPY_DATA_TO_H5 then copy ff -> h5_ff.
+ * If job = COPY_H5_TO_DATA then copy h5_ff -> ff. + * + * @param[in,out] ff If job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to h5_ff.
+ * If job = COPY_H5_TO_DATA then on output this is the + * copied h5_ff structure. + * @param[in,out] h5_ff If job = COPY_DATA_TO_H5 then on output this is the + * HDF5 version of ff.
+ * If job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to ff. + * + * @result 0 indicates success. + * + * @author Ben Baker, ISTI + * + */ +int hdf5_copyFFResults(const enum data2h5_enum job, + struct GFAST_ffResults_struct *ff, + struct h5_ffResults_struct *h5_ff) +{ + struct h5_faultPlane_struct *h5_fp = NULL; + int i, ierr; + size_t nfp; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + memset(h5_ff, 0, sizeof(struct h5_ffResults_struct)); + nfp = (size_t) ff->nfp; + if (ff->nfp <= 0) + { + LOG_ERRMSG("%s", "Error no fault planes!"); + return -1; + } + + h5_ff->fp.len = nfp; + h5_fp = (struct h5_faultPlane_struct *) + calloc(nfp, sizeof(struct h5_faultPlane_struct)); + for (i=0; i<(int) nfp; i++) + { + ierr = GFAST_hdf5_copyFaultPlane(job, &ff->fp[i], &h5_fp[i]); + } + h5_ff->fp.p = h5_fp; + + h5_ff->vr.len = nfp; + h5_ff->vr.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, ff->vr, 1, h5_ff->vr.p, 1); + + h5_ff->Mw.len = nfp; + h5_ff->Mw.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, ff->Mw, 1, h5_ff->Mw.p, 1); + + h5_ff->str.len = nfp; + h5_ff->str.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, ff->str, 1, h5_ff->str.p, 1); + + h5_ff->dip.len = nfp; + h5_ff->dip.p = (double *)calloc(nfp, sizeof(double)); + cblas_dcopy((int) nfp, ff->dip, 1, h5_ff->dip.p, 1); + + h5_ff->SA_lat = ff->SA_lat; + h5_ff->SA_lon = ff->SA_lon; + h5_ff->SA_dep = ff->SA_dep; + h5_ff->SA_mag = ff->SA_mag; + h5_ff->preferred_fault_plane = ff->preferred_fault_plane; + h5_ff->nfp = ff->nfp; + + } + else if (job == COPY_H5_TO_DATA) + { + nfp = (size_t) h5_ff->nfp; + if (nfp <= 0) + { + LOG_ERRMSG("%s", "Error no fault planes!"); + return -1; + } + + ff->SA_lat = h5_ff->SA_lat; + ff->SA_lon = h5_ff->SA_lon; + ff->SA_dep = h5_ff->SA_dep; + ff->SA_mag = h5_ff->SA_mag; + ff->preferred_fault_plane = h5_ff->preferred_fault_plane; + ff->nfp = h5_ff->nfp; + + ff->fp = (struct GFAST_faultPlane_struct *) + calloc(nfp, sizeof(struct GFAST_faultPlane_struct)); + h5_fp = h5_ff->fp.p; + for (i=0; i<(int) nfp; i++) + { + ierr = GFAST_hdf5_copyFaultPlane(job, &ff->fp[i], &h5_fp[i]); + if (ierr != 0) + { + LOG_ERRMSG("Error copying fault plane %d\n", i+1); + return -1; + } + } + h5_fp = NULL; + + ff->vr = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_ff->vr.p, 1, ff->vr, 1); + + ff->Mw = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_ff->Mw.p, 1, ff->Mw, 1); + + ff->str = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_ff->str.p, 1, ff->str, 1); + + ff->dip = memory_calloc64f((int) nfp); + cblas_dcopy((int) nfp, h5_ff->dip.p, 1, ff->dip, 1); + } + else + { + LOG_ERRMSG("Invalid job=%d", job); + ierr = 1; + } + return ierr; +} + +//============================================================================// +/*! + * @brief Copies three component waveform data structure to/from HDF5 + * three component waveform structure. + * + * @param[in] job If job = COPY_DATA_TO_H5 then copy + * data -> h5_data.
+ * If job = COPY_H5_TO_DATA then copy h5_data -> data. + * + * @param[in,out] data if job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to h5_data.
+ * if job = COPY_H5_TO_DATA then on output this is the + * copied h5_data structure. + * @param[in,out] h5_data If job = COPY_DATA_TO_H5 then on output this is the + * HDF5 version of data.
+ * If job = COPY_DATA_TO_H5 then on input this is the + * structure to copy to data. + * + * @result 0 indicates success. + * + * @author Ben Baker, ISTI + * + */ +int hdf5_copyWaveform3CData(const enum data2h5_enum job, + struct GFAST_waveform3CData_struct *data, + struct h5_waveform3CData_struct *h5_data) +{ + char *netw, *stnm, *chan, *loc; + double nanv[1] = {(double) NAN}; + int ierr, npts; + //int i; unused + size_t nalloc; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + memset(h5_data, 0, sizeof(struct h5_waveform3CData_struct)); + npts = data->npts; + nalloc = (size_t) (MAX(npts, 1)); + h5_data->ubuff.p = (double *)calloc(nalloc, sizeof(double)); + h5_data->nbuff.p = (double *)calloc(nalloc, sizeof(double)); + h5_data->ebuff.p = (double *)calloc(nalloc, sizeof(double)); + h5_data->tbuff.p = (double *)calloc(nalloc, sizeof(double)); + h5_data->gain.p = (double *)calloc(3, sizeof(double)); + h5_data->ubuff.len = nalloc; + h5_data->nbuff.len = nalloc; + h5_data->ebuff.len = nalloc; + h5_data->tbuff.len = nalloc; + h5_data->gain.len = 3; + if (npts > 0) + { + cblas_dcopy(npts, data->ubuff, 1, h5_data->ubuff.p, 1); + cblas_dcopy(npts, data->nbuff, 1, h5_data->nbuff.p, 1); + cblas_dcopy(npts, data->ebuff, 1, h5_data->ebuff.p, 1); + cblas_dcopy(npts, data->tbuff, 1, h5_data->tbuff.p, 1); + } + else + { + cblas_dcopy(1, nanv, 1, h5_data->ubuff.p, 1); + cblas_dcopy(1, nanv, 1, h5_data->nbuff.p, 1); + cblas_dcopy(1, nanv, 1, h5_data->ebuff.p, 1); + cblas_dcopy(1, nanv, 1, h5_data->tbuff.p, 1); + } + cblas_dcopy(3, data->gain, 1, h5_data->gain.p, 1); + h5_data->dt = data->dt; + h5_data->sta_lat = data->sta_lat; + h5_data->sta_lon = data->sta_lon; + h5_data->sta_alt = data->sta_alt; + h5_data->maxpts = data->maxpts; + h5_data->npts = data->npts; + h5_data->lskip_pgd = data->lskip_pgd; + h5_data->lskip_cmt = data->lskip_cmt; + h5_data->lskip_ff = data->lskip_ff; + + netw = (char *)calloc(64, sizeof(char)); + strcpy(netw, data->netw); + h5_data->netw.len = 1; + h5_data->netw.p = netw; + + stnm = (char *)calloc(64, sizeof(char)); + strcpy(stnm, data->stnm); + h5_data->stnm.len = 1; + h5_data->stnm.p = stnm; + + // MTH: h5py segfaults reading array of strings (??) + //chan = (char *)calloc(64, sizeof(char)); + //strcpy(chan, data->chan[0]); + //h5_data->chan.len = 1; + chan = (char *)calloc(3*64, sizeof(char)); + strcpy(&chan[0], data->chan[0]); + strcpy(&chan[64], data->chan[1]); + strcpy(&chan[128], data->chan[2]); + h5_data->chan.len = 3; + h5_data->chan.p = chan; + + loc = (char *)calloc(64, sizeof(char)); + strcpy(loc, data->loc); + h5_data->loc.len = 1; + h5_data->loc.p = loc; + + } + else if (job == COPY_H5_TO_DATA) + { + + memset(data, 0, sizeof(struct GFAST_waveform3CData_struct)); + npts = h5_data->npts; + nalloc = (size_t) (MAX(npts, 1)); + data->ubuff = memory_calloc64f((int) nalloc); + data->nbuff = memory_calloc64f((int) nalloc); + data->ebuff = memory_calloc64f((int) nalloc); + data->tbuff = memory_calloc64f((int) nalloc); + if (npts > 0) + { + cblas_dcopy(npts, h5_data->ubuff.p, 1, data->ubuff, 1); + cblas_dcopy(npts, h5_data->nbuff.p, 1, data->nbuff, 1); + cblas_dcopy(npts, h5_data->ebuff.p, 1, data->ebuff, 1); + cblas_dcopy(npts, h5_data->tbuff.p, 1, data->tbuff, 1); + } + else + { + cblas_dcopy(1, nanv, 1, data->ubuff, 1); + cblas_dcopy(1, nanv, 1, data->nbuff, 1); + cblas_dcopy(1, nanv, 1, data->ebuff, 1); + cblas_dcopy(1, nanv, 1, data->tbuff, 1); + } + + cblas_dcopy(3, h5_data->gain.p, 1, data->gain, 1); + data->dt = h5_data->dt; + data->sta_lat = h5_data->sta_lat; + data->sta_lon = h5_data->sta_lon; + data->sta_alt = h5_data->sta_alt; + data->maxpts = h5_data->maxpts; + data->npts = h5_data->npts; + data->lskip_pgd = h5_data->lskip_pgd; + data->lskip_cmt = h5_data->lskip_cmt; + data->lskip_ff = h5_data->lskip_ff; + + netw = (char *) h5_data->netw.p; + strcpy(data->netw, netw); + netw = NULL; + + stnm = (char *) h5_data->stnm.p; + strcpy(data->stnm, stnm); + stnm = NULL; + + chan = h5_data->chan.p; + strcpy(data->chan[0], &chan[0]); + strcpy(data->chan[1], &chan[64]); + strcpy(data->chan[2], &chan[128]); + chan = NULL; + + loc = (char *) h5_data->loc.p; + strcpy(data->loc, loc); + loc = NULL; + } + else + { + LOG_ERRMSG("Invalid job=%d\n", job); + ierr = 1; + } + return ierr; +} +//============================================================================// +/*! + * @brief Copies GPS data structure to/from HDF5 GPS data structure + * + * @param[in] job if job = COPY_DATA_TO_H5 then copy + * gps_data -> h5_gpsData. + * if job = COPY_H5_TO_DATA then copy + * h5_gpsData -> gps_data + * + * @param[in,out] gps_data if job = COPY_DATA_TO_H5 then on input this is + * the structure to copy to h5_gpsData. + * if job = COPY_H5_TO_DATA then on output this is + * the copied h5_gpsData structure. + * @param[in,out] h5_gpsData if job = COPY_DATA_TO_H5 then on output this is + * the HDF5 version of gps_data. + * if job = COPY_DATA_TO_H5 then on input this is + * the structure to copy to gps_data. + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int hdf5_copyGPSData(const enum data2h5_enum job, + struct GFAST_data_struct *gps_data, + struct h5_gpsData_struct *h5_gpsData) +{ + struct h5_waveform3CData_struct *h5_data; + int ierr, k, nstreams; + //------------------------------------------------------------------------// + ierr = 0; + if (job == COPY_DATA_TO_H5) + { + memset(h5_gpsData, 0, sizeof(struct h5_gpsData_struct)); + nstreams = gps_data->stream_length; + if (nstreams < 1 || gps_data->data == NULL) + { + LOG_ERRMSG("%s", "Error no streams to copy!"); + ierr = 1; + } + h5_data = (struct h5_waveform3CData_struct *) + calloc((size_t) nstreams, + sizeof(struct h5_waveform3CData_struct)); + h5_gpsData->stream_length = nstreams; + for (k=0; kdata[k], + &h5_data[k]); + // h5_data[].npts == h5_data[].ubuff.len + /* + printf("MTH: h5_data[%d] stnm=%s chan=%s sta_lat:%8.3f sta_lon:%8.3f npts:%d ubuff.len:%d ubuff[last]:%9.6f\n", + k, h5_data[k].stnm.p, h5_data[k].chan.p, h5_data[k].sta_lat, h5_data[k].sta_lon, + h5_data[k].npts, h5_data[k].ubuff.len, h5_data[k].ubuff.p[h5_data[k].npts-1]); + */ + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error copying 3C data"); + return ierr; + } + } + h5_gpsData->data.p = h5_data; + h5_gpsData->data.len = (size_t) nstreams; + } + else if (job == COPY_H5_TO_DATA) + { + memset(gps_data, 0, sizeof(struct GFAST_data_struct)); + nstreams = h5_gpsData->stream_length; + gps_data->stream_length = nstreams; + if (nstreams < 1) + { + LOG_ERRMSG("%s", "Error no streams to copy!"); + ierr = 1; + } + gps_data->data = (struct GFAST_waveform3CData_struct *) + calloc((size_t) nstreams, + sizeof(struct GFAST_waveform3CData_struct)); + h5_data = (struct h5_waveform3CData_struct *) h5_gpsData->data.p; + for (k=0; kdata[k], + &h5_data[k]); + } + h5_data = NULL; + } + else + { + LOG_ERRMSG("Invalid job=%d\n", job); + ierr = 1; + } + return ierr; +} diff --git a/src/hdf5/createType.c b/src/hdf5/createType.c new file mode 100644 index 00000000..e5b41c4c --- /dev/null +++ b/src/hdf5/createType.c @@ -0,0 +1,796 @@ +#include +#include +#include +#include +#include "gfast_hdf5.h" +#include "gfast_core.h" + +/*! + * @brief Creates the peak displacement data type + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_peakDisplacementData(hid_t group_id) +{ + hid_t dataType, vlenCData, vlenDData, vlenIData, string64Type; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "peakDisplacementDataStructure\0", + H5P_DEFAULT) != 0) + { + return ierr; + } + // String data type + string64Type = H5Tcopy(H5T_C_S1); + H5Tset_size(string64Type, 64); + vlenCData = H5Tvlen_create(string64Type); + vlenDData = H5Tvlen_create(H5T_NATIVE_DOUBLE); + vlenIData = H5Tvlen_create(H5T_NATIVE_INT); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_peakDisplacementData_struct)); + ierr += H5Tinsert(dataType, "stationName\0", + HOFFSET(struct h5_peakDisplacementData_struct, stnm), + vlenCData); + ierr += H5Tinsert(dataType, "peakDisplacement\0", + HOFFSET(struct h5_peakDisplacementData_struct, pd), + vlenDData); + ierr += H5Tinsert(dataType, "weight\0", + HOFFSET(struct h5_peakDisplacementData_struct, wt), + vlenDData); + ierr += H5Tinsert(dataType, "siteLatitude\0", + HOFFSET(struct h5_peakDisplacementData_struct, sta_lat), + vlenDData); + ierr += H5Tinsert(dataType, "siteLongitude\0", + HOFFSET(struct h5_peakDisplacementData_struct, sta_lon), + vlenDData); + ierr += H5Tinsert(dataType, "siteElevation\0", + HOFFSET(struct h5_peakDisplacementData_struct, sta_alt), + vlenDData); + ierr += H5Tinsert(dataType, "isMasked\0", + HOFFSET(struct h5_peakDisplacementData_struct, lmask), + vlenIData); + ierr += H5Tinsert(dataType, "isActive\0", + HOFFSET(struct h5_peakDisplacementData_struct, lactive), + vlenIData); + ierr += H5Tinsert(dataType, "numberOfSites\0", + HOFFSET(struct h5_peakDisplacementData_struct, nsites), + H5T_NATIVE_INT); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to pack type"); + return ierr; + } + // Commit it + ierr = H5Tcommit2(group_id, "peakDisplacementDataStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to create pgd data structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(vlenCData); + ierr += H5Tclose(vlenDData); + ierr += H5Tclose(vlenIData); + ierr += H5Tclose(string64Type); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the PGD results structure + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_pgdResults(hid_t group_id) +{ + hid_t dataType, vlenDData, vlenIData; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "pgdResultsStructure\0", H5P_DEFAULT) != 0) + { + return ierr; + } + vlenDData = H5Tvlen_create(H5T_NATIVE_DOUBLE); + vlenIData = H5Tvlen_create(H5T_NATIVE_INT); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_pgdResults_struct)); + ierr += H5Tinsert(dataType, "Magnitude\0", + HOFFSET(struct h5_pgdResults_struct, mpgd), + vlenDData); + ierr += H5Tinsert(dataType, "PGDVarianceReduction\0", + HOFFSET(struct h5_pgdResults_struct, mpgd_vr), + vlenDData); + ierr += H5Tinsert(dataType, "PGDVarianceReduction_ScaledByIQR\0", + HOFFSET(struct h5_pgdResults_struct, dep_vr_pgd), + vlenDData); + ierr += H5Tinsert(dataType, "PGDEstimates\0", + HOFFSET(struct h5_pgdResults_struct, UP), + vlenDData); + ierr += H5Tinsert(dataType, "PGDObservations\0", + HOFFSET(struct h5_pgdResults_struct, UPinp), + vlenDData); + ierr += H5Tinsert(dataType, "sourceDepth\0", + HOFFSET(struct h5_pgdResults_struct, srcDepths), + vlenDData); + ierr += H5Tinsert(dataType, "sourceReceiverDistance\0", + HOFFSET(struct h5_pgdResults_struct, srdist), + vlenDData); + ierr += H5Tinsert(dataType, "interQuartileRange\0", + HOFFSET(struct h5_pgdResults_struct, iqr), + vlenDData); + ierr += H5Tinsert(dataType, "siteUsed\0", + HOFFSET(struct h5_pgdResults_struct, lsiteUsed), + vlenIData); + ierr += H5Tinsert(dataType, "numberOfGridsearchDepths\0", + HOFFSET(struct h5_pgdResults_struct, ndeps), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfSites\0", + HOFFSET(struct h5_pgdResults_struct, nsites), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfLatitudes\0", + HOFFSET(struct h5_pgdResults_struct, nlats), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfLongitudes\0", + HOFFSET(struct h5_pgdResults_struct, nlons), + H5T_NATIVE_INT); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to pack type"); + return ierr; + } + // Commit it + ierr = H5Tcommit2(group_id, "pgdResultsStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to create pgd results structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(vlenDData); + ierr += H5Tclose(vlenIData); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the peak displacement data type + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_offsetData(hid_t group_id) +{ + hid_t dataType, vlenCData, vlenDData, vlenIData, string64Type; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "offsetDataStructure\0", H5P_DEFAULT) != 0) + { + return ierr; + } + // String data type + string64Type = H5Tcopy(H5T_C_S1); + H5Tset_size(string64Type, 64); + vlenCData = H5Tvlen_create(string64Type); + vlenDData = H5Tvlen_create(H5T_NATIVE_DOUBLE); + vlenIData = H5Tvlen_create(H5T_NATIVE_INT); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_offsetData_struct)); + ierr += H5Tinsert(dataType, "stationName\0", + HOFFSET(struct h5_offsetData_struct, stnm), + vlenCData); + ierr += H5Tinsert(dataType, "verticalOffset\0", + HOFFSET(struct h5_offsetData_struct, ubuff), + vlenDData); + ierr += H5Tinsert(dataType, "northOffset\0", + HOFFSET(struct h5_offsetData_struct, nbuff), + vlenDData); + ierr += H5Tinsert(dataType, "eastOffset\0", + HOFFSET(struct h5_offsetData_struct, ebuff), + vlenDData); + ierr += H5Tinsert(dataType, "verticalWeight\0", + HOFFSET(struct h5_offsetData_struct, wtu), + vlenDData); + ierr += H5Tinsert(dataType, "northWeight\0", + HOFFSET(struct h5_offsetData_struct, wtn), + vlenDData); + ierr += H5Tinsert(dataType, "eastWeight\0", + HOFFSET(struct h5_offsetData_struct, wte), + vlenDData); + ierr += H5Tinsert(dataType, "siteLatitude\0", + HOFFSET(struct h5_offsetData_struct, sta_lat), + vlenDData); + ierr += H5Tinsert(dataType, "siteLongitude\0", + HOFFSET(struct h5_offsetData_struct, sta_lon), + vlenDData); + ierr += H5Tinsert(dataType, "siteElevation\0", + HOFFSET(struct h5_offsetData_struct, sta_alt), + vlenDData); + ierr += H5Tinsert(dataType, "isMasked\0", + HOFFSET(struct h5_offsetData_struct, lmask), + vlenIData); + ierr += H5Tinsert(dataType, "isActive\0", + HOFFSET(struct h5_offsetData_struct, lactive), + vlenIData); + ierr += H5Tinsert(dataType, "numberOfSites\0", + HOFFSET(struct h5_offsetData_struct, nsites), + H5T_NATIVE_INT); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to pack type"); + return ierr; + } + // Commit it + ierr = H5Tcommit2(group_id, "offsetDataStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr < 0) + { + LOG_ERRMSG("%s", "Failed to create offset data structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(vlenCData); + ierr += H5Tclose(vlenDData); + ierr += H5Tclose(vlenIData); + ierr += H5Tclose(string64Type); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the hypocenter data type + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_hypocenter(hid_t group_id) +{ + hid_t dataType, string128Type; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "hypocenterStructure\0", H5P_DEFAULT) != 0) + { + return ierr; + } + // String data type + string128Type = H5Tcopy(H5T_C_S1); + H5Tset_size(string128Type, 128); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_hypocenter_struct)); + ierr += H5Tinsert(dataType, "eventName\0", + HOFFSET(struct h5_hypocenter_struct, eventid), + string128Type); + ierr += H5Tinsert(dataType, "latitude\0", + HOFFSET(struct h5_hypocenter_struct, lat), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "longitude\0", + HOFFSET(struct h5_hypocenter_struct, lon), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "depth\0", + HOFFSET(struct h5_hypocenter_struct, dep), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "magnitude\0", + HOFFSET(struct h5_hypocenter_struct, mag), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "originTime\0", + HOFFSET(struct h5_hypocenter_struct, time), + H5T_NATIVE_DOUBLE); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to pack type"); + return ierr; + } + // Commit it + ierr = H5Tcommit2(group_id, "hypocenterStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to create offset data structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(string128Type); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the CMT results structure + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_cmtResults(hid_t group_id) +{ + hid_t dataType, vlenDData, vlenIData; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "cmtResultsStructure\0", H5P_DEFAULT) != 0) + { + return ierr; + } + vlenIData = H5Tvlen_create(H5T_NATIVE_INT); + vlenDData = H5Tvlen_create(H5T_NATIVE_DOUBLE); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_cmtResults_struct)); + ierr += H5Tinsert(dataType, "L2norm\0", + HOFFSET(struct h5_cmtResults_struct, l2), + vlenDData); + ierr += H5Tinsert(dataType, "percentDoubleCouple\0", + HOFFSET(struct h5_cmtResults_struct, pct_dc), + vlenDData); + ierr += H5Tinsert(dataType, "ObjectiveFunction\0", + HOFFSET(struct h5_cmtResults_struct, objfn), + vlenDData); + ierr += H5Tinsert(dataType, "momentTensors\0", + HOFFSET(struct h5_cmtResults_struct, mts), + vlenDData); + ierr += H5Tinsert(dataType, "strikeFaultPlane1\0", + HOFFSET(struct h5_cmtResults_struct, str1), + vlenDData); + ierr += H5Tinsert(dataType, "dipFaultPlane1\0", + HOFFSET(struct h5_cmtResults_struct, dip1), + vlenDData); + ierr += H5Tinsert(dataType, "rakeFaultPlane1\0", + HOFFSET(struct h5_cmtResults_struct, rak1), + vlenDData); + ierr += H5Tinsert(dataType, "strikeFaultPlane2\0", + HOFFSET(struct h5_cmtResults_struct, str2), + vlenDData); + ierr += H5Tinsert(dataType, "dipFaultPlane2\0", + HOFFSET(struct h5_cmtResults_struct, dip2), + vlenDData); + ierr += H5Tinsert(dataType, "rakeFaultPlane2\0", + HOFFSET(struct h5_cmtResults_struct, rak2), + vlenDData); + ierr += H5Tinsert(dataType, "momentMagnitudes\0", + HOFFSET(struct h5_cmtResults_struct, Mw), + vlenDData); + ierr += H5Tinsert(dataType, "sourceDepths\0", + HOFFSET(struct h5_cmtResults_struct, srcDepths), + vlenDData); + ierr += H5Tinsert(dataType, "eastEstimates\0", + HOFFSET(struct h5_cmtResults_struct, EN), + vlenDData); + ierr += H5Tinsert(dataType, "northEstimates\0", + HOFFSET(struct h5_cmtResults_struct, NN), + vlenDData); + ierr += H5Tinsert(dataType, "upEstimates\0", + HOFFSET(struct h5_cmtResults_struct, UN), + vlenDData); + ierr += H5Tinsert(dataType, "eastObservedOffset\0", + HOFFSET(struct h5_cmtResults_struct, Einp), + vlenDData); + ierr += H5Tinsert(dataType, "northObservedOffset\0", + HOFFSET(struct h5_cmtResults_struct, Ninp), + vlenDData); + ierr += H5Tinsert(dataType, "upObservedOffset\0", + HOFFSET(struct h5_cmtResults_struct, Uinp), + vlenDData); + ierr += H5Tinsert(dataType, "siteUsed\0", + HOFFSET(struct h5_cmtResults_struct, lsiteUsed), + vlenIData); + + ierr += H5Tinsert(dataType, "optimumIndex\0", + HOFFSET(struct h5_cmtResults_struct, opt_indx), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfGridsearchDepths\0", + HOFFSET(struct h5_cmtResults_struct, ndeps), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfSites\0", + HOFFSET(struct h5_cmtResults_struct, nsites), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfLatitudes\0", + HOFFSET(struct h5_cmtResults_struct, nlats), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfLongitudes\0", + HOFFSET(struct h5_cmtResults_struct, nlons), + H5T_NATIVE_INT); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to pack type"); + return ierr; + } + // Commit it + ierr = H5Tcommit2(group_id, "cmtResultsStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Failed to create cmt results structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(vlenIData); + ierr += H5Tclose(vlenDData); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the finite fault fault plane structure + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_faultPlane(hid_t group_id) +{ + hid_t dataType, vlenDData, vlenIData; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "faultPlaneStructure\0", H5P_DEFAULT) != 0) + { + return ierr; + } + vlenIData = H5Tvlen_create(H5T_NATIVE_INT); + vlenDData = H5Tvlen_create(H5T_NATIVE_DOUBLE); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_faultPlane_struct)); + ierr += H5Tinsert(dataType, "longitudeVertices\0", + HOFFSET(struct h5_faultPlane_struct, lon_vtx), + vlenDData); + ierr += H5Tinsert(dataType, "latitudeVertices\0", + HOFFSET(struct h5_faultPlane_struct, lat_vtx), + vlenDData); + ierr += H5Tinsert(dataType, "depthVertices\0", + HOFFSET(struct h5_faultPlane_struct, dep_vtx), + vlenDData); + ierr += H5Tinsert(dataType, "faultPatchEastingUTM\0", + HOFFSET(struct h5_faultPlane_struct, fault_xutm), + vlenDData); + ierr += H5Tinsert(dataType, "faultPatchNorthingUTM\0", + HOFFSET(struct h5_faultPlane_struct, fault_yutm), + vlenDData); + ierr += H5Tinsert(dataType, "faultPatchDepth\0", + HOFFSET(struct h5_faultPlane_struct, fault_alt), + vlenDData); + ierr += H5Tinsert(dataType, "faultStrike\0", + HOFFSET(struct h5_faultPlane_struct, strike), + vlenDData); + ierr += H5Tinsert(dataType, "faultDip\0", + HOFFSET(struct h5_faultPlane_struct, dip), + vlenDData); + ierr += H5Tinsert(dataType, "faultLength\0", + HOFFSET(struct h5_faultPlane_struct, length), + vlenDData); + ierr += H5Tinsert(dataType, "faultWidth\0", + HOFFSET(struct h5_faultPlane_struct, width), + vlenDData); + ierr += H5Tinsert(dataType, "slipAlongStrike\0", + HOFFSET(struct h5_faultPlane_struct, sslip), + vlenDData); + ierr += H5Tinsert(dataType, "slipAlongDip\0", + HOFFSET(struct h5_faultPlane_struct, dslip), + vlenDData); + ierr += H5Tinsert(dataType, "slipAlongStrikeUncertainty\0", + HOFFSET(struct h5_faultPlane_struct, sslip_unc), + vlenDData); + ierr += H5Tinsert(dataType, "slipAlongDipUncertainty\0", + HOFFSET(struct h5_faultPlane_struct, dslip_unc), + vlenDData); + ierr += H5Tinsert(dataType, "eastEstimateOffset\0", + HOFFSET(struct h5_faultPlane_struct, EN), + vlenDData); + ierr += H5Tinsert(dataType, "northEstimateOffset\0", + HOFFSET(struct h5_faultPlane_struct, NN), + vlenDData); + ierr += H5Tinsert(dataType, "upEstimateOffset\0", + HOFFSET(struct h5_faultPlane_struct, UN), + vlenDData); + ierr += H5Tinsert(dataType, "eastObservedOffset\0", + HOFFSET(struct h5_faultPlane_struct, Einp), + vlenDData); + ierr += H5Tinsert(dataType, "northObservedOffset\0", + HOFFSET(struct h5_faultPlane_struct, Ninp), + vlenDData); + ierr += H5Tinsert(dataType, "upObservedOffset\0", + HOFFSET(struct h5_faultPlane_struct, Uinp), + vlenDData); + ierr += H5Tinsert(dataType, "faultPointerStructure\0", + HOFFSET(struct h5_faultPlane_struct, fault_ptr), + vlenIData); + ierr += H5Tinsert(dataType, "maxObservations\0", + HOFFSET(struct h5_faultPlane_struct, maxobs), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfSitesUsed\0", + HOFFSET(struct h5_faultPlane_struct, nsites_used), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfFaltPatchesAlongStrike\0", + HOFFSET(struct h5_faultPlane_struct, nstr), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfFaultPatchesAlongDip\0", + HOFFSET(struct h5_faultPlane_struct, ndip), + H5T_NATIVE_INT); + // Commit it + ierr = H5Tcommit2(group_id, "faultPlaneStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr < 0) + { + LOG_ERRMSG("%s", "Failed to create fault plane structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(vlenIData); + ierr += H5Tclose(vlenDData); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the finite fault results structure + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_ffResults(hid_t group_id) +{ + hid_t dataType, faultType, vlenDData, vlenFault; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "finiteFaultResultsStructure\0", H5P_DEFAULT) != 0) + { + return ierr; + } + if (H5Lexists(group_id, "faultPlaneStructure\0", H5P_DEFAULT) == 0) + { + LOG_WARNMSG("%s", "Making fault plane structure"); + ierr = GFAST_hdf5_createType_faultPlane(group_id); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error making fault plane structure"); + return ierr; + } + } + faultType = H5Topen(group_id, "faultPlaneStructure\0", H5P_DEFAULT); + vlenFault = H5Tvlen_create(faultType); + vlenDData = H5Tvlen_create(H5T_NATIVE_DOUBLE); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_ffResults_struct)); + ierr += H5Tinsert(dataType, "faultPlanes\0", + HOFFSET(struct h5_ffResults_struct, fp), + vlenFault); + ierr += H5Tinsert(dataType, "varianceReduction\0", + HOFFSET(struct h5_ffResults_struct, vr), + vlenDData); + ierr += H5Tinsert(dataType, "momentMagnitude\0", + HOFFSET(struct h5_ffResults_struct, Mw), + vlenDData); + ierr += H5Tinsert(dataType, "faultPlaneStrikes\0", + HOFFSET(struct h5_ffResults_struct, str), + vlenDData); + ierr += H5Tinsert(dataType, "faultPlaneDips\0", + HOFFSET(struct h5_ffResults_struct, dip), + vlenDData); + ierr += H5Tinsert(dataType, "sourceLatitude\0", + HOFFSET(struct h5_ffResults_struct, SA_lat), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "sourceLongitude\0", + HOFFSET(struct h5_ffResults_struct, SA_lon), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "sourceDepth\0", + HOFFSET(struct h5_ffResults_struct, SA_dep), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "sourceMagnitude\0", + HOFFSET(struct h5_ffResults_struct, SA_mag), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "preferredFaultPlane\0", + HOFFSET(struct h5_ffResults_struct, + preferred_fault_plane), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfFaultPlanes\0", + HOFFSET(struct h5_ffResults_struct, nfp), + H5T_NATIVE_INT); + // Commit it + ierr = H5Tcommit2(group_id, "finiteFaultResultsStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr < 0) + { + LOG_ERRMSG("%s", "Failed to create ff results structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(faultType); + ierr += H5Tclose(vlenFault); + ierr += H5Tclose(vlenDData); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the three component GPS data structure + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_waveform3CData(hid_t group_id) +{ + hid_t dataType, string64Type, vlenCData, vlenDData; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "waveform3CDataStructure\0", H5P_DEFAULT) != 0) + { + return ierr; + } + // String data type + string64Type = H5Tcopy(H5T_C_S1); + H5Tset_size(string64Type, 64); + vlenCData = H5Tvlen_create(string64Type); + vlenDData = H5Tvlen_create(H5T_NATIVE_DOUBLE); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_waveform3CData_struct)); + ierr += H5Tinsert(dataType, "Network\0", + HOFFSET(struct h5_waveform3CData_struct, netw), + vlenCData); + ierr += H5Tinsert(dataType, "Station\0", + HOFFSET(struct h5_waveform3CData_struct, stnm), + vlenCData); + ierr += H5Tinsert(dataType, "Channels\0", + HOFFSET(struct h5_waveform3CData_struct, chan), + vlenCData); + ierr += H5Tinsert(dataType, "Location\0", + HOFFSET(struct h5_waveform3CData_struct, loc), + vlenCData); + ierr += H5Tinsert(dataType, "UpPrecisePointPosition\0", + HOFFSET(struct h5_waveform3CData_struct, ubuff), + vlenDData); + ierr += H5Tinsert(dataType, "NorthPrecisePointPosition\0", + HOFFSET(struct h5_waveform3CData_struct, nbuff), + vlenDData); + ierr += H5Tinsert(dataType, "EastPrecisePointPosition\0", + HOFFSET(struct h5_waveform3CData_struct, ebuff), + vlenDData); + ierr += H5Tinsert(dataType, "EpochalTimes\0", + HOFFSET(struct h5_waveform3CData_struct, tbuff), + vlenDData); + ierr += H5Tinsert(dataType, "gain\0", + HOFFSET(struct h5_waveform3CData_struct, gain), + vlenDData); + ierr += H5Tinsert(dataType, "samplingPeriod\0", + HOFFSET(struct h5_waveform3CData_struct, dt), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "stationLatitude\0", + HOFFSET(struct h5_waveform3CData_struct, sta_lat), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "stationLongitude\0", + HOFFSET(struct h5_waveform3CData_struct, sta_lon), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "stationElevation\0", + HOFFSET(struct h5_waveform3CData_struct, sta_alt), + H5T_NATIVE_DOUBLE); + ierr += H5Tinsert(dataType, "maxNumberOfPoints\0", + HOFFSET(struct h5_waveform3CData_struct, maxpts), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "numberOfPoints\0", + HOFFSET(struct h5_waveform3CData_struct, npts), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "lskipPGD\0", + HOFFSET(struct h5_waveform3CData_struct, lskip_pgd), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "lskipCMT\0", + HOFFSET(struct h5_waveform3CData_struct, lskip_cmt), + H5T_NATIVE_INT); + ierr += H5Tinsert(dataType, "lskipFF\0", + HOFFSET(struct h5_waveform3CData_struct, lskip_ff), + H5T_NATIVE_INT); + // Commit it + ierr = H5Tcommit2(group_id, "waveform3CDataStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr < 0) + { + LOG_ERRMSG("%s", "Failed to create 3C data structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(vlenCData); + ierr += H5Tclose(vlenDData); + ierr += H5Tclose(string64Type); + return ierr; +} +//============================================================================// +/*! + * @brief Creates the GFAST data structure + * + * @param[in] group_id HDF5 group_id handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +herr_t hdf5_createType_gpsData(hid_t group_id) +{ + hid_t dataType, threeCdataType, vlen3CData; + herr_t ierr = 0; + //------------------------------------------------------------------------// + // + // Nothing to do + if (H5Lexists(group_id, "gpsDataStructure\0", H5P_DEFAULT) != 0) + { + return ierr; + } + if (H5Lexists(group_id, "waveform3CDataStructure\0", H5P_DEFAULT) == 0) + { + LOG_WARNMSG("%s", "Making 3C data structure"); + ierr = GFAST_hdf5_createType_waveform3CData(group_id); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error making 3C data structure"); + return ierr; + } + } + threeCdataType = H5Topen(group_id, "waveform3CDataStructure\0", + H5P_DEFAULT); + vlen3CData = H5Tvlen_create(threeCdataType); + // Build the data structure + dataType = H5Tcreate(H5T_COMPOUND, + sizeof(struct h5_gpsData_struct)); + ierr += H5Tinsert(dataType, "threeComponentDataStreams\0", + HOFFSET(struct h5_gpsData_struct, data), + vlen3CData); + ierr += H5Tinsert(dataType, "numberOfSites\0", + HOFFSET(struct h5_gpsData_struct, stream_length), + H5T_NATIVE_INT); + // Commit it + ierr = H5Tcommit2(group_id, "gpsDataStructure\0", dataType, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (ierr < 0) + { + LOG_ERRMSG("%s", "Failed to create gpsData structure"); + return ierr; + } + ierr += H5Tclose(dataType); + ierr += H5Tclose(vlen3CData); + ierr += H5Tclose(threeCdataType); + return ierr; +} diff --git a/src/hdf5/getMaxGroupNumber.c b/src/hdf5/getMaxGroupNumber.c new file mode 100644 index 00000000..74d79ccd --- /dev/null +++ b/src/hdf5/getMaxGroupNumber.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include "gfast_hdf5.h" +#include "gfast_core.h" + +#define MAX_GROUP 10000000 +/*! + * @brief Determines the max inversion group number present in the archive + * file. + * + * @param[in] h5fl handle to HDF5 file + * + * @result the max group number (starts counting at 0). + * if negative then there are no groups present in the archive + * file. + * + * @author Ben Baker (ISTI) + * + */ +int hdf5_getMaxGroupNumber(const hid_t h5fl) +{ + char groupName[512]; + int kg, kgroup; + kgroup =-1; + for (kg=0; kg +#include +#include +#include +#include "gfast_hdf5.h" +#include "gfast_core.h" +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "iscl/os/os.h" + +/*! + * @brief Opens an HDF5 file and returns handle for reading only + * + * @param[in] flname name of HDF5 file to open (NULL terminated) + * + * @result file handle + * + * @author Ben Baker, ISTI + * + */ +hid_t h5_open_rdonly(const char *flname) +{ + hid_t file_id; + if (!os_path_isfile(flname)) + { + LOG_ERRMSG("HDF5 file %s does not exist!\n", flname); + } + file_id = H5Fopen(flname, H5F_ACC_RDONLY, H5P_DEFAULT); + return file_id; +} +//============================================================================// +/*! + * @brief Opens an HDF5 file and returns handle for reading and writing + * + * @param[in] flname name of HDF5 file to open (NULL terminated) + * + * @result file handle + * + * @author Ben Baker, ISTI + * + */ +hid_t h5_open_rdwt(const char *flname) +{ + hid_t file_id; + file_id = H5Fopen(flname, H5F_ACC_RDWR, H5P_DEFAULT); + return file_id; +} +//============================================================================// +/*! + * @brief Closes an HDF5 file + * + * @param[in] file_id HDF5 file handle + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_close(const hid_t file_id) +{ + int ierr; + ierr = (int) (H5Fclose(file_id)); + return ierr; +} +//============================================================================// +/*! + * @brief Writes a float array to HDF5 + * + * @param[in] dset_name name of dataset to write + * @param[in] file_id HDF5 file handle + * @param[in] n size of dataset to write + * @param[in] x dataset to write + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_write_array__float(const char *dset_name, const hid_t file_id, + const int n, const float *x) +{ + char *citem = (char *)calloc(strlen(dset_name)+1, sizeof(char)); + hid_t flt_dataspace_id, flt_dataset_id; + hsize_t dims[1]; + herr_t status; + //------------------------------------------------------------------------// + // + // Copy file handle and name + strcpy(citem,dset_name); + // Create dataspace + dims[0] = (hsize_t) n; + flt_dataspace_id = H5Screate_simple(1, dims, NULL); + // Create dataset + flt_dataset_id = H5Dcreate2(file_id, citem, H5T_NATIVE_FLOAT, + flt_dataspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + // Write data + status = H5Dwrite(flt_dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, x); + if (status != 0) + { + LOG_ERRMSG("%s", "Write error"); + return -1; + } + // Close the dataspace + status = H5Sclose(flt_dataspace_id); + status += H5Dclose(flt_dataset_id); + if (status != 0) + { + LOG_ERRMSG("%s", "Close error"); + } + free(citem); + return status; +} +//============================================================================// +/*! + * @brief Writes a double array to HDF5 + * + * @param[in] dset_name name of dataset to write + * @param[in] file_id HDF5 file handle + * @param[in] n size of dataset to write + * @param[in] x dataset to write + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_write_array__double(const char *dset_name, const hid_t file_id, + const int n, const double *x) +{ + char *citem = (char *)calloc(strlen(dset_name)+1, sizeof(char)); + hid_t dbl_dataspace_id, dbl_dataset_id; + hsize_t dims[1]; + herr_t status; + //------------------------------------------------------------------------// + // + // Copy file handle and name + strcpy(citem, dset_name); + // Create dataspace + dims[0] = (hsize_t) n; + dbl_dataspace_id = H5Screate_simple(1, dims, NULL); + // Create dataset + dbl_dataset_id = H5Dcreate2(file_id, citem, H5T_NATIVE_DOUBLE, + dbl_dataspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + // Write data + status = H5Dwrite(dbl_dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, x); + if (status != 0) + { + LOG_ERRMSG("%s", "Write error"); + return -1; + } + // Close the dataspace + status = H5Sclose(dbl_dataspace_id); + status += H5Dclose(dbl_dataset_id); + if (status != 0) + { + LOG_ERRMSG("%s", "Close error"); + } + free(citem); + return status; +} +//============================================================================// +/*! + * @brief Writes an int array to HDF5 + * + * @param[in] dset_name name of dataset to write + * @param[in] file_id HDF5 file handle + * @param[in] n size of dataset to write + * @param[in] x dataset to write + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_write_array__int(const char *dset_name, const hid_t file_id, + const int n, const int *x) +{ + char *citem = (char *)calloc(strlen(dset_name)+1, sizeof(char)); + hid_t int_dataspace_id, int_dataset_id; + hsize_t dims[1]; + herr_t status; + //------------------------------------------------------------------------// + // Copy file handle and name + strcpy(citem, dset_name); + // Create dataspace + dims[0] = (hsize_t) n; + int_dataspace_id = H5Screate_simple(1, dims, NULL); + // Create dataset + int_dataset_id = H5Dcreate2(file_id, citem, H5T_NATIVE_INT, + int_dataspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + // Write data + status = H5Dwrite(int_dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, x); + if (status != 0) + { + LOG_ERRMSG("%s", "Write error"); + return -1; + } + // Close the dataspace + status = H5Sclose(int_dataspace_id); + status += H5Dclose(int_dataset_id); + if (status != 0) + { + LOG_ERRMSG("%s", "Close error"); + } + free(citem); + return status; +} +//============================================================================// +/*! + * @brief Writes a char ** array to HDF5 + * + * @param[in] citem_chr name of char** dataset + * @param[in] file_id HDF5 file handle + * @param[in] n number of items in c + * @param[in] c char** dataset to write [n] + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + * TODO: This needs to be a const char **c. + * + */ +int h5_write_array__chars(const char *citem_chr, const hid_t file_id, + const int n, char **c) +{ + char **cout, *citem_hdf5; + size_t len_item = strlen(citem_chr); + hid_t chr_dataset_id, chr_dataspace_id, cftype, cmtype; + hsize_t dims[1]; + herr_t status; + int i, lens; + //------------------------------------------------------------------------// + // + // Set the name of the attribute while remembering a null terminator + citem_hdf5 = (char *)calloc(len_item+1, sizeof(char)); + strncpy(citem_hdf5, citem_chr, len_item); + // Create dataspace + dims[0] = (hsize_t) n; + chr_dataspace_id = H5Screate_simple(1, dims, NULL); + // Create file and memory types + cftype = H5Tcopy(H5T_C_S1); + status = H5Tset_size(cftype, H5T_VARIABLE); + if (status < 0) + { + LOG_ERRMSG("%s", "Error setting space"); + return -1; + } + cmtype = H5Tcopy(H5T_C_S1); + status = H5Tset_size(cmtype, H5T_VARIABLE); + if (status < 0) + { + LOG_ERRMSG("%s", "Error setting memory space"); + return -1; + } + // Create the dataset + chr_dataset_id = H5Dcreate2(file_id, citem_hdf5, cftype, + chr_dataspace_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + // Create output + cout = (char **)calloc((size_t) n, sizeof(char *)); + for (i=0; i nref) + { + LOG_ERRMSG("%s", "Insufficient space!"); + return -1; + } + // Get properties handle + cparms = H5Dget_create_plist(dbl_dataset); + // Define memory space + memspace = H5Screate_simple(1, dims, NULL); + // Load data + status = H5Dread(dbl_dataset, H5T_NATIVE_DOUBLE, memspace, dbl_dataspace, + H5P_DEFAULT, x); + if (status != 0) + { + LOG_ERRMSG("%s", "Error loading data"); + return -1; + } + // Close it up + status = H5Pclose(cparms); + status += H5Sclose(dbl_dataspace); + status += H5Sclose(memspace); + status += H5Dclose(dbl_dataset); + if (status != 0) + { + LOG_ERRMSG("%s", "Error closing space"); + } + free(citem); + free(dims); + return status; +} +//============================================================================// +/*! + * @brief Reads a float array from HDF5 + * + * @param[in] dset_name name of dataset to read + * @param[in] file_id HDF5 file handle + * @param[in] nref size of dataset to read + * + * @param[out] x dataset read from disk + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_read_array__float(const char *dset_name, const hid_t file_id, + const int nref, float *x) +{ + char *citem = (char *)calloc(strlen(dset_name)+1, sizeof(char)); + hid_t memspace, flt_dataspace, flt_dataset, cparms; + hsize_t *dims; + herr_t status; + int nwork, rank, i; + //------------------------------------------------------------------------// + // + // Copy file hand and name + strcpy(citem,dset_name); + // Open dataset + flt_dataset = H5Dopen(file_id,citem, H5P_DEFAULT); + // Create dataspace + flt_dataspace = H5Dget_space(flt_dataset); + // Get size of dimensions + rank = H5Sget_simple_extent_ndims(flt_dataspace); + dims = (hsize_t *)calloc((size_t) rank, sizeof(hsize_t)); + status = H5Sget_simple_extent_dims(flt_dataspace, dims, NULL); + nwork = 1; + for (i=0; i nref) + { + LOG_ERRMSG("%s", "Insufficient space!"); + return -1; + } + // Get properties handle + cparms = H5Dget_create_plist(flt_dataset); + // Define memory space + memspace = H5Screate_simple(1, dims, NULL); + // Load data + status = H5Dread(flt_dataset, H5T_NATIVE_FLOAT, memspace, flt_dataspace, + H5P_DEFAULT, x); + if (status != 0) + { + LOG_ERRMSG("%s", "Error loading data"); + return -1; + } + // Close it up + status = H5Pclose(cparms); + status += H5Sclose(flt_dataspace); + status += H5Sclose(memspace); + status += H5Dclose(flt_dataset); + if (status != 0) + { + LOG_ERRMSG("%s", "Error closing space"); + } + free(citem); + free(dims); + return status; +} +//============================================================================// +/*! + * @brief Reads an integer array from HDF5 + * + * @param[in] dset_name name of dataset to read + * @param[in] file_id HDF5 file handle + * @param[in] nref size of dataset to read + * + * @param[out] x dataset read from disk + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_read_array__int(const char *dset_name, const hid_t file_id, + const int nref, int *x) +{ + char *citem = (char *)calloc(strlen(dset_name)+1,sizeof(char)); + hid_t memspace, int_dataspace, int_dataset, cparms; + hsize_t *dims; + herr_t status; + int nwork, rank, i; + //------------------------------------------------------------------------// + // + // Copy file hand and name + strcpy(citem,dset_name); + // Open dataset + int_dataset = H5Dopen(file_id,citem,H5P_DEFAULT); + // Create dataspace + int_dataspace = H5Dget_space(int_dataset); + // Get size of dimensions + rank = H5Sget_simple_extent_ndims(int_dataspace); + dims = (hsize_t *)calloc((size_t) rank, sizeof(hsize_t)); + status = H5Sget_simple_extent_dims(int_dataspace, dims, NULL); + nwork = 1; + for (i=0; i nref){ + LOG_ERRMSG("%s", "Insufficient space!"); + return -1; + } + // Get properties handle + cparms = H5Dget_create_plist(int_dataset); + // Define memory space + memspace = H5Screate_simple(1, dims, NULL); + // Load data + status = H5Dread(int_dataset, H5T_NATIVE_INT, memspace, int_dataspace, + H5P_DEFAULT, x); + if (status != 0) + { + LOG_ERRMSG("%s", "Error reading data"); + return -1; + } + // Close it up + status = H5Pclose(cparms); + status += H5Sclose(int_dataspace); + status += H5Sclose(memspace); + status += H5Dclose(int_dataset); + if (status != 0) + { + LOG_ERRMSG("%s", "Error closing h5"); + } + free(citem); + free(dims); + return status; +} +//============================================================================// +/*! + * @brief Writes double attributes to an HDF5 dataset + * + * @param[in] citem attribute name + * @param[in] hdf5_id HDF5 dataset handle + * @param[in] n number of attributes + * @param[in] attr_data double attributes [n] + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_write_attribute__double(const char *citem, const hid_t hdf5_id, + const int n, const double *attr_data) +{ + char *citem_hdf5; + size_t len_item = strlen(citem); + hid_t attr_dataspace_id, attribute_id; + hsize_t dims[1]; + herr_t status; + //------------------------------------------------------------------------// + // + // Set item name + citem_hdf5 = (char *) calloc(len_item+1, sizeof(char)); + strncpy(citem_hdf5, citem, len_item); + // Create a dataspace for the attribute + dims[0] = (hsize_t) n; + attr_dataspace_id = H5Screate_simple(1, dims, NULL); + // Create dataset id for the attribute + attribute_id = H5Acreate2(hdf5_id, citem_hdf5, H5T_NATIVE_DOUBLE, + attr_dataspace_id, H5P_DEFAULT, H5P_DEFAULT); + // Write the attribute data + status = H5Awrite(attribute_id, H5T_NATIVE_DOUBLE, attr_data); + status += H5Aclose(attribute_id); + status += H5Sclose(attr_dataspace_id); + if (status != 0) + { + LOG_ERRMSG("%s", "Error writing attributes"); + } + // Free space + free(citem_hdf5); + citem_hdf5 = NULL; + return status; +} +//============================================================================// +/*! + * @brief Writes integer attributes to an HDF5 dataset + * + * @param[in] citem attribute name + * @param[in] hdf5_id HDF5 dataset handle + * @param[in] n number of attributes + * @param[in] attr_data integer attributes [n] + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_write_attribute__int(const char *citem, const hid_t hdf5_id, + const int n, const int *attr_data) +{ + char *citem_hdf5; + size_t len_item = strlen(citem); + hid_t attr_dataspace_id, attribute_id; + hsize_t dims[1]; + herr_t status; + //------------------------------------------------------------------------// + // + // Set item name + citem_hdf5 = (char *) calloc(len_item+1, sizeof(char)); + strncpy(citem_hdf5, citem, len_item); + // Create a dataspace for the attribute + dims[0] = (hsize_t) n; + attr_dataspace_id = H5Screate_simple(1, dims, NULL); + // Create dataset id for the attribute + attribute_id = H5Acreate2(hdf5_id, citem_hdf5, H5T_NATIVE_INT, + attr_dataspace_id, H5P_DEFAULT, H5P_DEFAULT); + // Write the attribute data + status = H5Awrite(attribute_id, H5T_NATIVE_INT, attr_data); + status += H5Aclose(attribute_id); + status += H5Sclose(attr_dataspace_id); + if (status != 0) + { + LOG_ERRMSG("%s", "Error writing attributes"); + } + // Free space + free(citem_hdf5); + citem_hdf5 = NULL; + return status; +} +//============================================================================// +/*! + * @brief Writes character attributes to an HDF5 dataset + * + * @param[in] citem attribute name + * @param[in] hdf5_id HDF5 dataset handle + * @param[in] n number of attributes + * @param[in] cattr charater attributes [n] + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int h5_write_attribute__char(const char *citem, const hid_t hdf5_id, + const int n, const char **cattr) +{ + char **cout, *citem_hdf5; + size_t len_item = strlen(citem); + int i, lens; + hid_t attr_dataspace_id, attribute_id, cftype, cmtype; + hsize_t dims[1]; + herr_t status; + //------------------------------------------------------------------------// + // + // Set item name + citem_hdf5 = (char *)calloc(len_item+1, sizeof(char)); + strncpy(citem_hdf5, citem, len_item); + // Create a dataspace + dims[0] = (hsize_t) n; + attr_dataspace_id = H5Screate_simple(1, dims, NULL); + // Create the datatypes + cftype = H5Tcopy(H5T_C_S1); + status = H5Tset_size(cftype, H5T_VARIABLE); + if (status < 0) + { + LOG_ERRMSG("%s", "Error setting space!"); + return -1; + } + cmtype = H5Tcopy(H5T_C_S1); + status = H5Tset_size(cmtype, H5T_VARIABLE); + if (status < 0) + { + LOG_ERRMSG("%s", "Error setting memory space"); + return -1; + } + // Create dataset for attribute + attribute_id = H5Acreate2(hdf5_id, citem_hdf5, cftype, + attr_dataspace_id, H5P_DEFAULT, H5P_DEFAULT); + // Create output + cout = (char **)calloc((size_t) n, sizeof(char *)); + for (i=0; i +#include +#include +#include +#include +#include "gfast_hdf5.h" +#include "gfast_core.h" +#include "iscl/os/os.h" + +static void obscureVariable(char *buffer, const char *variable); + +/*! + * @brief Initializes the archive for the given event + * + * @param[in] adir HDF5 archive directory. if NULL then the archive + * will be in the current working directory + * @param[in] evid event ID + * @param[in] propfilename name of GFAST properties file + * + * @result 0 indicates success + * + */ +int hdf5_initialize(const char *adir, + const char *evid, + const char *propfilename) +{ + FILE *ifl; + char *bufout[1]; + char fname[PATH_MAX], *buffer; + hid_t fileID, groupID; + int ierr; + size_t lsize, nread; + //------------------------------------------------------------------------// + // + // Set the filename + ierr = 0; + ierr = GFAST_hdf5_setFileName(adir, evid, fname); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting filename"); + return -1; + } + // If file exists then let user know it is about to be deleted + if (os_path_isfile(fname)) + { + LOG_WARNMSG("H5 archive file %s will be overwritten", fname); + } + // Set the filename and open it + fileID = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + // Create a directory for the types and write them + ierr = ierr + h5_create_group(fileID, "/DataStructures\0"); + groupID = H5Gopen2(fileID, "/DataStructures\0", H5P_DEFAULT); + ierr = ierr + GFAST_hdf5_createType_peakDisplacementData(groupID); + ierr = ierr + GFAST_hdf5_createType_pgdResults(groupID); + ierr = ierr + GFAST_hdf5_createType_cmtResults(groupID); + ierr = ierr + GFAST_hdf5_createType_faultPlane(groupID); + ierr = ierr + GFAST_hdf5_createType_ffResults(groupID); + ierr = ierr + GFAST_hdf5_createType_hypocenter(groupID); + ierr = ierr + GFAST_hdf5_createType_offsetData(groupID); + ierr = ierr + GFAST_hdf5_createType_waveform3CData(groupID); + ierr = ierr + GFAST_hdf5_createType_gpsData(groupID); + ierr = ierr + H5Gclose(groupID); + // Save the ini file + ierr = ierr + h5_create_group(fileID, "/InitializationFile\0"); + if (os_path_isfile(propfilename)) + { + ifl = fopen(propfilename, "rb"); + fseek(ifl, 0L, SEEK_END); + lsize = (size_t) (ftell(ifl)); + rewind(ifl); + buffer = (char *)calloc(1, (lsize+1)*sizeof(char)); + nread = fread(buffer, lsize, 1, ifl); + if (nread < 1) + { + LOG_ERRMSG("%s", "Failed to read text file!"); + } + fclose(ifl); + if (nread > 0 && buffer != NULL) + { + obscureVariable(buffer, "user\0"); + obscureVariable(buffer, "password\0"); + bufout[0] = buffer; + ierr = ierr + h5_write_array__chars("/InitializationFile/IniFile\0", + fileID, 1, bufout); + } + free(buffer); + } + // Create the directory which will hold the history + ierr = ierr + h5_create_group(fileID, "/GFAST_History\0"); + + // Create the directory which will hold the summary XML messages + ierr = ierr + h5_create_group(fileID, "/Summary\0"); + + // Close the archive + ierr = ierr + H5Fclose(fileID); + return ierr; +} + +static void obscureVariable(char *buffer, const char *variable) +{ + char *temp; + bool *ldel; + size_t i, j, k, len, lenv; + if (variable == NULL){return;} + len = strlen(buffer); + if (len == 0){return;} + ldel = (bool *) calloc(len, sizeof(bool)); + lenv = strlen(variable); + for (i=0; i +#include +#include +#include "gfast_hdf5.h" + +int hdf5_memory_freePGDResults(struct h5_pgdResults_struct *pgd) +{ + if (pgd->mpgd.p != NULL){free(pgd->mpgd.p);} + if (pgd->mpgd_vr.p != NULL){free(pgd->mpgd_vr.p);} + if (pgd->dep_vr_pgd.p != NULL){free(pgd->dep_vr_pgd.p);} + if (pgd->UP.p != NULL){free(pgd->UP.p);} + if (pgd->UPinp.p != NULL){free(pgd->UPinp.p);} + if (pgd->srcDepths.p != NULL){free(pgd->srcDepths.p);} + if (pgd->srdist.p != NULL){free(pgd->srdist.p);} + if (pgd->iqr.p != NULL){free(pgd->iqr.p);} + if (pgd->lsiteUsed.p != NULL){free(pgd->lsiteUsed.p);} + memset(pgd, 0, sizeof(struct h5_pgdResults_struct)); + return 0; +} + +int hdf5_memory_freeCMTResults(struct h5_cmtResults_struct *cmt) +{ + if (cmt->l2.p != NULL){free(cmt->l2.p);} + if (cmt->pct_dc.p != NULL){free(cmt->pct_dc.p);} + if (cmt->objfn.p != NULL){free(cmt->objfn.p);} + if (cmt->mts.p != NULL){free(cmt->mts.p);} + if (cmt->str1.p != NULL){free(cmt->str1.p);} + if (cmt->str2.p != NULL){free(cmt->str2.p);} + if (cmt->dip1.p != NULL){free(cmt->dip1.p);} + if (cmt->dip2.p != NULL){free(cmt->dip2.p);} + if (cmt->rak1.p != NULL){free(cmt->rak1.p);} + if (cmt->rak2.p != NULL){free(cmt->rak2.p);} + if (cmt->Mw.p != NULL){free(cmt->Mw.p);} + if (cmt->srcDepths.p != NULL){free(cmt->srcDepths.p);} + if (cmt->EN.p != NULL){free(cmt->EN.p);} + if (cmt->NN.p != NULL){free(cmt->NN.p);} + if (cmt->UN.p != NULL){free(cmt->UN.p);} + if (cmt->Einp.p != NULL){free(cmt->Einp.p);} + if (cmt->Ninp.p != NULL){free(cmt->Ninp.p);} + if (cmt->Uinp.p != NULL){free(cmt->Uinp.p);} + if (cmt->lsiteUsed.p != NULL){free(cmt->lsiteUsed.p);} + memset(cmt, 0, sizeof(struct h5_cmtResults_struct)); + return 0; +} + +int hdf5_memory_freeFaultPlane(struct h5_faultPlane_struct *fp) +{ + if (fp->lon_vtx.p != NULL){free(fp->lon_vtx.p);} + if (fp->lat_vtx.p != NULL){free(fp->lat_vtx.p);} + if (fp->dep_vtx.p != NULL){free(fp->dep_vtx.p);} + if (fp->fault_xutm.p != NULL){free(fp->fault_xutm.p);} + if (fp->fault_yutm.p != NULL){free(fp->fault_yutm.p);} + if (fp->fault_alt.p != NULL){free(fp->fault_alt.p);} + if (fp->strike.p != NULL){free(fp->strike.p);} + if (fp->dip.p != NULL){free(fp->dip.p);} + if (fp->length.p != NULL){free(fp->length.p);} + if (fp->width.p != NULL){free(fp->width.p);} + if (fp->sslip.p != NULL){free(fp->sslip.p);} + if (fp->dslip.p != NULL){free(fp->dslip.p);} + if (fp->sslip_unc.p != NULL){free(fp->sslip_unc.p);} + if (fp->dslip_unc.p != NULL){free(fp->dslip_unc.p);} + if (fp->EN.p != NULL){free(fp->EN.p);} + if (fp->NN.p != NULL){free(fp->NN.p);} + if (fp->UN.p != NULL){free(fp->UN.p);} + if (fp->Einp.p != NULL){free(fp->Einp.p);} + if (fp->Ninp.p != NULL){free(fp->Ninp.p);} + if (fp->Uinp.p != NULL){free(fp->Uinp.p);} + if (fp->fault_ptr.p != NULL){free(fp->fault_ptr.p);} + memset(fp, 0, sizeof(struct h5_faultPlane_struct)); + return 0; +} + +int hdf5_memory_freeFFResults(struct h5_ffResults_struct *ff) +{ + struct h5_faultPlane_struct *fp = NULL; + int i; + if (ff->fp.p != NULL) + { + fp = (struct h5_faultPlane_struct *) ff->fp.p; + for (i=0; i<(int) ff->fp.len; i++) + { + GFAST_hdf5_memory_freeFaultPlane(&fp[i]); + } + free(ff->fp.p); + fp = NULL; + } + if (ff->vr.p != NULL){free(ff->vr.p);} + if (ff->Mw.p != NULL){free(ff->Mw.p);} + if (ff->str.p != NULL){free(ff->str.p);} + if (ff->dip.p != NULL){free(ff->dip.p);} + memset(ff, 0, sizeof(struct h5_ffResults_struct)); + return 0; +} + +int hdf5_memory_freePGDData( + struct h5_peakDisplacementData_struct *h5_pgd_data) +{ + if (h5_pgd_data->pd.p != NULL){free(h5_pgd_data->pd.p);} + if (h5_pgd_data->wt.p != NULL){free(h5_pgd_data->wt.p);} + if (h5_pgd_data->sta_lat.p != NULL){free(h5_pgd_data->sta_lat.p);} + if (h5_pgd_data->sta_lon.p != NULL){free(h5_pgd_data->sta_lon.p);} + if (h5_pgd_data->sta_alt.p != NULL){free(h5_pgd_data->sta_alt.p);} + if (h5_pgd_data->stnm.p != NULL){free(h5_pgd_data->stnm.p);} + if (h5_pgd_data->lactive.p != NULL){free(h5_pgd_data->lactive.p);} + if (h5_pgd_data->lmask.p != NULL){free(h5_pgd_data->lmask.p);} + memset(h5_pgd_data, 0, sizeof(struct h5_peakDisplacementData_struct)); + return 0; +} + +int hdf5_memory_freeOffsetData( + struct h5_offsetData_struct *h5_offset_data) +{ + if (h5_offset_data->ubuff.p != NULL){free(h5_offset_data->ubuff.p);} + if (h5_offset_data->nbuff.p != NULL){free(h5_offset_data->nbuff.p);} + if (h5_offset_data->ebuff.p != NULL){free(h5_offset_data->ebuff.p);} + if (h5_offset_data->wtu.p != NULL){free(h5_offset_data->wtu.p);} + if (h5_offset_data->wtn.p != NULL){free(h5_offset_data->wtn.p);} + if (h5_offset_data->wte.p != NULL){free(h5_offset_data->wte.p);} + if (h5_offset_data->sta_lat.p != NULL){free(h5_offset_data->sta_lat.p);} + if (h5_offset_data->sta_lon.p != NULL){free(h5_offset_data->sta_lon.p);} + if (h5_offset_data->sta_alt.p != NULL){free(h5_offset_data->sta_alt.p);} + if (h5_offset_data->stnm.p != NULL){free(h5_offset_data->stnm.p);} + if (h5_offset_data->lactive.p != NULL){free(h5_offset_data->lactive.p);} + if (h5_offset_data->lmask.p != NULL){free(h5_offset_data->lmask.p);} + memset(h5_offset_data, 0, sizeof(struct h5_offsetData_struct)); + return 0; +} + +int hdf5_memory_freeWaveform3CData(struct h5_waveform3CData_struct *data) +{ + if (data->netw.p != NULL){free(data->netw.p);} + if (data->stnm.p != NULL){free(data->stnm.p);} + if (data->chan.p != NULL){free(data->chan.p);} + if (data->loc.p != NULL){free(data->loc.p);} + if (data->ubuff.p != NULL){free(data->ubuff.p);} + if (data->nbuff.p != NULL){free(data->nbuff.p);} + if (data->ebuff.p != NULL){free(data->ebuff.p);} + if (data->tbuff.p != NULL){free(data->tbuff.p);} + if (data->gain.p != NULL){free(data->gain.p);} + memset(data, 0, sizeof(struct h5_waveform3CData_struct)); + return 0; +} + +int hdf5_memory_freeGPSData(struct h5_gpsData_struct *gpsData) +{ + struct h5_waveform3CData_struct *data; + int k; + data = (struct h5_waveform3CData_struct *)gpsData->data.p; + if (data != NULL) + { + for (k=0; kstream_length; k++) + { + GFAST_hdf5_memory_freeWaveform3CData(&data[k]); + } + free(data); + } + memset(gpsData, 0, sizeof(struct h5_gpsData_struct)); + return 0; +} diff --git a/src/hdf5/setFileName.c b/src/hdf5/setFileName.c new file mode 100644 index 00000000..ef5e9555 --- /dev/null +++ b/src/hdf5/setFileName.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include +#include "gfast_hdf5.h" +#include "gfast_core.h" +#include "iscl/os/os.h" + +/*! + * @brief Sets the HDF5 archive filename + * + * @param[in] adir archive directory. if NULL then the archive will be + * written to the current working directory + * @param[in] evid event ID + * + * @param[out] fname name of HDF5 archive file + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int hdf5_setFileName(const char *adir, + const char *evid, + char fname[PATH_MAX]) +{ + int ierr; + size_t lenos; + ierr = 0; + memset(fname, 0, PATH_MAX*sizeof(char)); + if (evid == NULL) + { + LOG_ERRMSG("%s", "Error event ID cannot be NULL"); + return -1; + } + if (strlen(evid) == 0) + { + LOG_ERRMSG("%s", "Error evid is not defined"); + return -1; + } + // Set the archive directory + if (adir == NULL) + { + strcpy(fname, "./\0"); + } + else + { + lenos = strlen(adir); + if (lenos == 0) + { + strcpy(fname, "./\0"); + } + else + { + // Require the directory exists - if not make it + if (!os_path_isdir(adir)) + { + ierr = mkdir(adir,0755); + if (ierr != 0) + { + LOG_ERRMSG("Failed making directory %s\n", adir); + return -1; + } + } + strcpy(fname, adir); + lenos = strlen(fname); + // Add a slash + if (fname[lenos-1] != '/'){strcat(fname, "/\0");} + } + } + // Add the event id + strcat(fname, evid); + // Add the file name + strcat(fname, "_archive.h5\0"); + return 0; +} diff --git a/src/hdf5/update.c b/src/hdf5/update.c new file mode 100644 index 00000000..164ce961 --- /dev/null +++ b/src/hdf5/update.c @@ -0,0 +1,614 @@ +#include +#include +#include +#include +#include "gfast_hdf5.h" +#include "gfast_core.h" +#include "iscl/os/os.h" + +/*! + * @brief Initializes the current directory for this GFAST iteration. + * + * @param[in] adir Archive directory. If NULL then the current working + * directory will be used. + * @param[in] evid Event ID. + * @param[in] epoch The current time for this iteration. + * + * @retval If -1 an error occurred. + * @retval Otherwise, this is the is iteration number for writing GFAST's + * history. + * + * @author Ben Baker, ISTI + * + */ +int hdf5_updateGetIteration(const char *adir, + const char *evid, + const double epoch) +{ + const char *group_root = "/GFAST_History\0"; + const char *item_root = "/GFAST_History/Iteration\0"; + char h5fl[PATH_MAX], iterGroup[256]; + hid_t fileID, groupID; + herr_t status; + int ierr, k; + //------------------------------------------------------------------------// + // + // Open the old HDF5 file + ierr = GFAST_hdf5_setFileName(adir, evid, h5fl); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting filename"); + return -1; + } + if (!os_path_isfile(h5fl)) + { + LOG_ERRMSG("Error file %s does not exist!", h5fl); + return -1; + } + fileID = h5_open_rdwt(h5fl); + // Have HDF5 count the group members as to compute the iteration number + k = h5_n_group_members(group_root, fileID) + 1; + memset(iterGroup, 0, sizeof(iterGroup)); + sprintf(iterGroup, "%s_%d", item_root, k); + if (h5_item_exists(fileID, iterGroup)) + { + LOG_ERRMSG("%s", "Error group shouldn't exist"); + ierr = h5_close(fileID); + return ierr; + } + ierr = h5_create_group(fileID, iterGroup); + // Write the epochal time as an attribute + groupID = H5Gopen2(fileID, iterGroup, H5P_DEFAULT); + status = h5_write_attribute__double("epoch\0", groupID, 1, &epoch); + if (status < 0) + { + LOG_ERRMSG("%s", "Error writing attribute"); + } + status = H5Gclose(groupID); + status = h5_close(fileID); + return k; +} +//============================================================================// +/*! + * @brief Writes the triggering hypocenter for the next iteration of GFAST + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int hdf5_updateHypocenter(const char *adir, + const char *evid, + const int h5k, + struct GFAST_shakeAlert_struct hypo) +{ + const char *item_root = "/GFAST_History/Iteration\0"; + char h5fl[PATH_MAX]; + struct h5_hypocenter_struct h5_hypo; + hid_t dataSet, dataSpace, dataType, fileID, groupID; + char hypoGroup[256]; + int ierr; + hsize_t dimInfo[1] = {1}; + const int rank = {1}; + //------------------------------------------------------------------------// + // + // Initialize + memset(&h5_hypo, 0, sizeof(struct h5_hypocenter_struct)); + // Open the old HDF5 file + ierr = GFAST_hdf5_setFileName(adir, evid, h5fl); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting filename"); + return -1; + } + if (!os_path_isfile(h5fl)) + { + LOG_ERRMSG("Error file %s does not exist!", h5fl); + return -1; + } + fileID = h5_open_rdwt(h5fl); + // Verify iteration group exists + memset(hypoGroup, 0, sizeof(hypoGroup)); + sprintf(hypoGroup, "%s_%d", item_root, h5k); + if (!h5_item_exists(fileID, hypoGroup)) + { + LOG_ERRMSG("%s", "Error group should exist"); + ierr = h5_close(fileID); + return ierr; + } + // Open the group for writing + groupID = H5Gopen2(fileID, hypoGroup, H5P_DEFAULT); + // Copy and write the data + ierr = ierr + GFAST_hdf5_copyHypocenter(COPY_DATA_TO_H5, + &hypo, + &h5_hypo); + dataType = H5Topen(groupID, "/DataStructures/hypocenterStructure\0", + H5P_DEFAULT); + dataSpace = H5Screate_simple(rank, dimInfo, NULL); + dataSet = H5Dcreate(groupID, "triggeringHypocenter\0", dataType, + dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ierr = H5Dwrite(dataSet, dataType, H5S_ALL, H5S_ALL, + H5P_DEFAULT, &h5_hypo); + ierr = H5Dclose(dataSet); + ierr = ierr + H5Sclose(dataSpace); + ierr = ierr + H5Tclose(dataType); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing hypocenter"); + } + // Close the group and file + ierr = ierr + H5Gclose(groupID); + ierr = h5_close(fileID); + return ierr; +} +//============================================================================// +/*! + * @brief Writes the next iteration of the PGD estimation for the given event. + * + * @param[in] adir Archive directory. If NULL then this will use the + * current working directory. + * @param[in] evid Event ID. + * @param[in] h5k Iteration number. This can be obtained from: + * hdf5_updateGetIteration. + * @param[in] pgd_data Peak ground displacement data used in this iteration + * to archive. + * @param[in] pgd PGD results from this iteration to archive. + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int hdf5_updatePGD(const char *adir, + const char *evid, + const int h5k, + struct GFAST_peakDisplacementData_struct pgd_data, + struct GFAST_pgdResults_struct pgd) +{ + const char *item_root = "/GFAST_History/Iteration\0"; + char h5fl[PATH_MAX]; + struct h5_peakDisplacementData_struct h5_pgd_data; + struct h5_pgdResults_struct h5_pgd; + hid_t dataSet, dataSpace, dataType, fileID, groupID; + char pgdGroup[256]; + int ierr; + hsize_t dimInfo[1] = {1}; + const int rank = {1}; + //------------------------------------------------------------------------// + // + // Initialize + memset(&h5_pgd_data, 0, sizeof(struct h5_peakDisplacementData_struct)); + memset(&h5_pgd, 0, sizeof(struct h5_pgdResults_struct)); + // Open the old HDF5 file + ierr = GFAST_hdf5_setFileName(adir, evid, h5fl); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting filename"); + return -1; + } + if (!os_path_isfile(h5fl)) + { + LOG_ERRMSG("Error file %s does not exist!", h5fl); + return -1; + } + fileID = h5_open_rdwt(h5fl); + // Have HDF5 count the group members as to compute the iteration number + memset(pgdGroup, 0, 256*sizeof(char)); + sprintf(pgdGroup, "%s_%d", item_root, h5k); + if (!h5_item_exists(fileID, pgdGroup)) + { + LOG_ERRMSG("%s", "Error group should exist"); + ierr = h5_close(fileID); + return ierr; + } + // Open the group for writing + groupID = H5Gopen2(fileID, pgdGroup, H5P_DEFAULT); + // Copy and write the data + ierr = ierr + GFAST_hdf5_copyPeakDisplacementData(COPY_DATA_TO_H5, + &pgd_data, + &h5_pgd_data); + dataType = H5Topen(groupID, + "/DataStructures/peakDisplacementDataStructure\0", + H5P_DEFAULT); + dataSpace = H5Screate_simple(rank, dimInfo, NULL); + dataSet = H5Dcreate(groupID, "pgdData\0", dataType, + dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ierr = H5Dwrite(dataSet, dataType, H5S_ALL, H5S_ALL, + H5P_DEFAULT, &h5_pgd_data); + ierr = H5Dclose(dataSet); + ierr = ierr + H5Sclose(dataSpace); + ierr = ierr + H5Tclose(dataType); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing PGD data"); + } + // Copy and write the results + ierr = ierr + GFAST_hdf5_copyPGDResults(COPY_DATA_TO_H5, + &pgd, &h5_pgd); + dataType = H5Topen(groupID, "/DataStructures/pgdResultsStructure\0", + H5P_DEFAULT); + dataSpace = H5Screate_simple(rank, dimInfo, NULL); + dataSet = H5Dcreate(groupID, "pgdResults\0", dataType, + dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ierr = H5Dwrite(dataSet, dataType, H5S_ALL, H5S_ALL, + H5P_DEFAULT, &h5_pgd); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing PGD results"); + } + ierr = H5Dclose(dataSet); + ierr = ierr + H5Sclose(dataSpace); + ierr = ierr + H5Tclose(dataType); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error closing HDF5 data items"); + } + // Free the space + ierr = GFAST_hdf5_memory_freePGDData(&h5_pgd_data); + ierr = GFAST_hdf5_memory_freePGDResults(&h5_pgd); + // Close the group and file + ierr = ierr + H5Gclose(groupID); + ierr = h5_close(fileID); + return ierr; +} +//============================================================================// +/*! + * @brief Writes the next iteration of the CMT estimation for the given event. + * + * @param[in] adir Archive directory. If NULL then this will use the + * current working directory. + * @param[in] evid Event ID. + * @param[in] h5k Iteration number. This can be obtained from: + * hdf5_updateGetIteration. + * @param[in] cmt_data Offset data used in this iteration to archive. + * @param[in] cmt CMT results from this iteration to archive. + * + * @result 0 indicates success + * + * @author Ben Baker, ISTI + * + */ +int hdf5_updateCMT(const char *adir, + const char *evid, + const int h5k, + struct GFAST_offsetData_struct cmt_data, + struct GFAST_cmtResults_struct cmt) +{ + const char *item_root = "/GFAST_History/Iteration\0"; + char h5fl[PATH_MAX]; + struct h5_offsetData_struct h5_cmt_data; + struct h5_cmtResults_struct h5_cmt; + hid_t dataSet, dataSpace, dataType, fileID, groupID; + char cmtGroup[256]; + int ierr; + hsize_t dimInfo[1] = {1}; + const int rank = {1}; + //------------------------------------------------------------------------// + // + // Initialize + memset(&h5_cmt_data, 0, sizeof(struct h5_offsetData_struct)); + memset(&h5_cmt, 0, sizeof(struct h5_cmtResults_struct)); + // Open the old HDF5 file + ierr = GFAST_hdf5_setFileName(adir, evid, h5fl); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting filename"); + return -1; + } + if (!os_path_isfile(h5fl)) + { + LOG_ERRMSG("Error file %s does not exist!", h5fl); + return -1; + } + fileID = h5_open_rdwt(h5fl); + // Have HDF5 count the group members as to compute the iteration number + memset(cmtGroup, 0, 256*sizeof(char)); + sprintf(cmtGroup, "%s_%d", item_root, h5k); + if (!h5_item_exists(fileID, cmtGroup)) + { + LOG_ERRMSG("%s", "Error group should exist"); + ierr = h5_close(fileID); + return ierr; + } + // Open the group for writing + groupID = H5Gopen2(fileID, cmtGroup, H5P_DEFAULT); + // Copy and write the data + ierr = ierr + GFAST_hdf5_copyOffsetData(COPY_DATA_TO_H5, + &cmt_data, + &h5_cmt_data); + dataType = H5Topen(groupID, "/DataStructures/offsetDataStructure\0", + H5P_DEFAULT); + dataSpace = H5Screate_simple(rank, dimInfo, NULL); + dataSet = H5Dcreate(groupID, "cmtData\0", dataType, + dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ierr = H5Dwrite(dataSet, dataType, H5S_ALL, H5S_ALL, + H5P_DEFAULT, &h5_cmt_data); + ierr = H5Dclose(dataSet); + ierr = ierr + H5Sclose(dataSpace); + ierr = ierr + H5Tclose(dataType); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing CMT data"); + } + // Copy and write the results + ierr = ierr + GFAST_hdf5_copyCMTResults(COPY_DATA_TO_H5, + &cmt, &h5_cmt); + dataType = H5Topen(groupID, "/DataStructures/cmtResultsStructure\0", + H5P_DEFAULT); + dataSpace = H5Screate_simple(rank, dimInfo, NULL); + dataSet = H5Dcreate(groupID, "cmtResults\0", dataType, + dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ierr = H5Dwrite(dataSet, dataType, H5S_ALL, H5S_ALL, + H5P_DEFAULT, &h5_cmt); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing Greens functions"); + } + ierr = H5Dclose(dataSet); + ierr = ierr + H5Sclose(dataSpace); + ierr = ierr + H5Tclose(dataType); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error closing HDF5 data items"); + } + // Free the space + ierr = GFAST_hdf5_memory_freeOffsetData(&h5_cmt_data); + ierr = GFAST_hdf5_memory_freeCMTResults(&h5_cmt); + // Close the group and file + ierr = ierr + H5Gclose(groupID); + ierr = h5_close(fileID); + return ierr; +} +//============================================================================// +int hdf5_updateXMLMessage(const char *adir, + const char *evid, + const int h5k, + const char *messageName, char *message) +{ + const char *item_root = "/GFAST_History/Iteration\0"; + char h5fl[PATH_MAX], msgGroup[256]; + hid_t fileID, groupID; + int ierr; + // There's nothing to do + if (message == NULL){return 0;} + if (strlen(message) < 1) + { + LOG_ERRMSG("%s", "Message is empty"); + return -1; + } + if (messageName == NULL) + { + LOG_ERRMSG("%s", "Message name cannot be NULL"); + return -1; + } + if (strlen(messageName) < 1) + { + LOG_ERRMSG("%s", "Message name cannot be blank"); + return -1; + } + // Open the old HDF5 file + ierr = GFAST_hdf5_setFileName(adir, evid, h5fl); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting filename"); + return -1; + } + if (!os_path_isfile(h5fl)) + { + LOG_ERRMSG("Error file %s does not exist!\n", h5fl); + return -1; + } + fileID = h5_open_rdwt(h5fl); + // Have HDF5 count the group members as to compute the iteration number + memset(msgGroup, 0, 256*sizeof(char)); + sprintf(msgGroup, "%s_%d", item_root, h5k); + if (!h5_item_exists(fileID, msgGroup)) + { + LOG_ERRMSG("%s", "Error group should exist"); + ierr = h5_close(fileID); + return ierr; + } + // Open the group for writing + groupID = H5Gopen2(fileID, msgGroup, H5P_DEFAULT); + if (h5_item_exists(groupID, messageName)) + { + LOG_ERRMSG("%s exists; skipping", messageName); + ierr = 1; + goto ERROR; + } + ierr = h5_write_array__chars(messageName, groupID, 1, &message); + if (ierr != 0) + { + LOG_ERRMSG("Error writing %s", messageName); + ierr =-1; + } + // Close the group and file +ERROR:; + ierr = ierr + H5Gclose(groupID); + ierr = h5_close(fileID); + return ierr; +} +//============================================================================// +int hdf5_updateFF(const char *adir, + const char *evid, + const int h5k, + struct GFAST_ffResults_struct ff) +{ + const char *item_root = "/GFAST_History/Iteration\0"; + char h5fl[PATH_MAX], dataName[256]; + struct h5_offsetData_struct h5_ff_data; + struct h5_ffResults_struct h5_ff; + struct h5_faultPlane_struct h5_fp; + hid_t dataSet, dataSpace, dataType, fileID, groupID; + char ffGroup[256]; + int i, ierr; + hsize_t dimInfo[1] = {1}; + const int rank = {1}; + //------------------------------------------------------------------------// + // + // Initialize + memset(&h5_ff_data, 0, sizeof(struct h5_offsetData_struct)); + memset(&h5_ff, 0, sizeof(struct h5_ffResults_struct)); + // Open the old HDF5 file + ierr = GFAST_hdf5_setFileName(adir, evid, h5fl); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting filename"); + return -1; + } + if (!os_path_isfile(h5fl)) + { + LOG_ERRMSG("Error file %s does not exist!\n", h5fl); + return -1; + } + fileID = h5_open_rdwt(h5fl); + // Have HDF5 count the group members as to compute the iteration number + memset(ffGroup, 0, 256*sizeof(char)); + sprintf(ffGroup, "%s_%d", item_root, h5k); + if (!h5_item_exists(fileID, ffGroup)) + { + LOG_ERRMSG("%s", "Error group should exist"); + ierr = h5_close(fileID); + return ierr; + } + // Open the group for writing + groupID = H5Gopen2(fileID, ffGroup, H5P_DEFAULT); + // Copy and write the results + ierr = ierr + GFAST_hdf5_copyFFResults(COPY_DATA_TO_H5, + &ff, &h5_ff); + dataType = H5Topen(groupID, "/DataStructures/finiteFaultResultsStructure\0", + H5P_DEFAULT); + dataSpace = H5Screate_simple(rank, dimInfo, NULL); + dataSet = H5Dcreate(groupID, "finiteFaultResults\0", dataType, + dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + ierr = H5Dwrite(dataSet, dataType, H5S_ALL, H5S_ALL, + H5P_DEFAULT, &h5_ff); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing Greens functions"); + } + ierr = H5Dclose(dataSet); + ierr = ierr + H5Sclose(dataSpace); + ierr = ierr + H5Tclose(dataType); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error closing HDF5 data items"); + } + // Write the faults individually for h5py + dataType = H5Topen(groupID, "/DataStructures/faultPlaneStructure\0", + H5P_DEFAULT); + dataSpace = H5Screate_simple(rank, dimInfo, NULL); + /* TODO: this is a kludge for h5py - retry with newer version */ + for (i=0; i= 0) { + EXPECT_TRUE(lnorthp); + } else { + EXPECT_FALSE(lnorthp); + } + EXPECT_EQ(utm_zone_ref, utm_unknown_zone); + EXPECT_EQ(utm_zone_ref, utm_zone); + EXPECT_NEAR(utmEastReference, utmEast0, tol); + EXPECT_NEAR(utmEastReference, utmEast1, tol); + EXPECT_NEAR(utmNorthReference, utmNorth0, tol); + EXPECT_NEAR(utmNorthReference, utmNorth1, tol); + + // Now try the opposite + GFAST_core_coordtools_utm2ll(utm_zone, lnorthp, utmNorth0, utmEast0, + &lat0, &lon0); + + EXPECT_NEAR(lat, lat0, 1.e-5); + EXPECT_TRUE((fabs(lon0 - lon) < 1.e-5) || (fabs(lon0 - 360 - lon) < 1.e-5)); + +} + +TEST(CoreCoord, testCoordSeattle) { + double lat, lon, utmEastReference, utmNorthReference; + int utm_unknown_zone, utm_zone, utm_zone_ref; + // bool lnorthp = true; + + lat = 47.6062; + lon = -122.3321; + utmEastReference = 550200.2133598323; //550200.21; + utmNorthReference = 5272748.591307523; //5272748.59; + utm_zone_ref = 10; + utm_zone = 10; + utm_unknown_zone =-1; + + doCoordTest(lat, lon, utmEastReference, utmNorthReference, utm_unknown_zone, utm_zone, utm_zone_ref); +} + +TEST(CoreCoord, testCoordSantiago) { + double lat, lon, utmEastReference, utmNorthReference; + int utm_unknown_zone, utm_zone, utm_zone_ref; + + lat = -33.4489; + lon = -70.6693; + utmEastReference = 344846.7203081217; //344846.72 + utmNorthReference = 6297700.155849966; //6297700.16 + utm_zone_ref = 19; + utm_zone = 19; + utm_unknown_zone =-1; + + doCoordTest(lat, lon, utmEastReference, utmNorthReference, utm_unknown_zone, utm_zone, utm_zone_ref); +} + diff --git a/src/tests/CoreDataUT.cc b/src/tests/CoreDataUT.cc new file mode 100644 index 00000000..55e0d8d0 --- /dev/null +++ b/src/tests/CoreDataUT.cc @@ -0,0 +1,114 @@ +/** + * @file CoreDataUT.cc + * @author Carl Ulberg, University of Washington (ulbergc@uw.edu) + * @brief This tests files in the core/data directory. + */ + +#include "gtest/gtest.h" +#include "ut_log_init.h" +#include "ut_main.h" + +#include "gfast.h" + +// test finalize, initialize, readMetaDataFile, readSiteMaskFile + +TEST(CoreData, testReadMetaDataFileBasic) { + const char *metaDataFile; + char **metaDataNetworks; + int n_networks, ierr; + struct GFAST_data_struct gps_data; + + // initialize + metaDataFile = "data/merged_chanfile_coord.dat\0"; + metaDataNetworks = NULL; + n_networks = 0; + memset(&gps_data, 0, sizeof(struct GFAST_data_struct)); + + ierr = core_data_readMetaDataFile(metaDataFile, + metaDataNetworks, + n_networks, + &gps_data); + EXPECT_EQ(0, ierr) << "Error reading sites file"; + EXPECT_EQ(492, gps_data.stream_length); + + // Gains should be equal on the channels. + // This also indirectly verifies that the data array is filled. + for (int i = 0; i < gps_data.stream_length; i++) { + EXPECT_EQ(gps_data.data[i].gain[0], gps_data.data[i].gain[1]); + EXPECT_EQ(gps_data.data[i].gain[0], gps_data.data[i].gain[2]); + } + + core_data_finalize(&gps_data); +} + +TEST(CoreData, testReadMetaDataFileWithMetaDataNetworks) { + const char *metaDataFile; + char **metaDataNetworks; + int n_networks, ierr; + struct GFAST_data_struct gps_data; + + // initialize + metaDataFile = "data/merged_chanfile_coord.dat\0"; + memset(&gps_data, 0, sizeof(struct GFAST_data_struct)); + + // metaDataNetworks = NULL; + n_networks = 1; + metaDataNetworks = (char **)malloc(sizeof(char *) * 1); + metaDataNetworks[0] = (char *)malloc(sizeof(char) * 3); + strcpy(metaDataNetworks[0], "CI\0"); + + ierr = core_data_readMetaDataFile(metaDataFile, + metaDataNetworks, + n_networks, + &gps_data); + EXPECT_EQ(0, ierr) << "Error reading sites file"; + EXPECT_EQ(461, gps_data.stream_length); + + // Gains should be equal on the channels. + // This also indirectly verifies that the data array is filled. + for (int i = 0; i < gps_data.stream_length; i++) { + EXPECT_EQ(gps_data.data[i].gain[0], gps_data.data[i].gain[1]); + EXPECT_EQ(gps_data.data[i].gain[0], gps_data.data[i].gain[2]); + } + + core_data_finalize(&gps_data); + free(metaDataNetworks[0]); + free(metaDataNetworks); +} + +TEST(CoreData, testInitialize) { + char propfilename[1024]; + int ierr, i; + struct GFAST_props_struct props; + struct GFAST_data_struct gps_data; + const enum opmode_type opmode = REAL_TIME_EEW; + + // initialize + strncpy(propfilename, + "data/gfast.props", + 1024-1); + ierr = 0; + memset(&props, 0, sizeof(struct GFAST_props_struct)); + memset(&gps_data, 0, sizeof(struct GFAST_data_struct)); + + // First read the properties + ierr = GFAST_core_properties_initialize(propfilename, opmode, &props); + EXPECT_EQ(0, ierr); + + // Now actually test the function in question + ierr = core_data_initialize(props, &gps_data); + EXPECT_EQ(0, ierr); + + for ( i = 0; i < gps_data.stream_length; i++ ) { + EXPECT_GT(gps_data.data[i].maxpts, 0); + EXPECT_NE(gps_data.data[i].ubuff, nullptr); + EXPECT_NE(gps_data.data[i].nbuff, nullptr); + EXPECT_NE(gps_data.data[i].ebuff, nullptr); + EXPECT_NE(gps_data.data[i].tbuff, nullptr); + } + + // finalize + GFAST_core_data_finalize(&gps_data); + GFAST_core_properties_finalize(&props); +} + diff --git a/src/tests/CoreEventsUT.cc b/src/tests/CoreEventsUT.cc new file mode 100644 index 00000000..3b7a5ed4 --- /dev/null +++ b/src/tests/CoreEventsUT.cc @@ -0,0 +1,151 @@ +/** + * @file CoreEventsUT.cc + * @author Carl Ulberg, University of Washington (ulbergc@uw.edu) + * @brief This tests files in the core/events directory. + */ + +#include "gtest/gtest.h" +#include "ut_log_init.h" +#include "ut_main.h" + +#include "gfast.h" + +// test freeEvents, getMinOriginTime, newEvent, printEvent, removeCancelledEvent, +// removeExpiredEvent, removeExpiredEvents, syncXMLStatusWithEvents, updateEvent +void get_SA(GFAST_shakeAlert_struct *SA) { + // Initialize new event + strcpy(SA->eventid, "12345\0"); + strcpy(SA->orig_sys, "gfast\0"); + SA->version = 0; + SA->time = 1663827681; + SA->lat = 36.1947; + SA->lon = 240.5070; + SA->dep = 8.0; + SA->mag = 3.7; +} + +class CoreEventsFixture : public::testing::Test { + protected: + struct GFAST_activeEvents_struct events; + struct GFAST_activeEvents_xml_status xml_status; + struct GFAST_shakeAlert_struct SA; + bool lnewEvent; + + void SetUp() { + memset(&SA, 0, sizeof(struct GFAST_shakeAlert_struct)); + memset(&events, 0, sizeof(struct GFAST_activeEvents_struct)); + memset(&xml_status, 0, sizeof(struct GFAST_activeEvents_xml_status)); + + get_SA(&SA); + + EXPECT_EQ(0, events.nev); + EXPECT_EQ(0, xml_status.nev); + } + + void TearDown() {} +}; + +TEST_F(CoreEventsFixture, testNewEventNoPreviousEvents) { + lnewEvent = GFAST_core_events_newEvent(SA, &events, &xml_status); + EXPECT_TRUE(lnewEvent); + + // Check events + ASSERT_EQ(1, events.nev); + EXPECT_STREQ(SA.eventid, events.SA[0].eventid); + EXPECT_STREQ(SA.orig_sys, events.SA[0].orig_sys); + EXPECT_EQ(SA.version, events.SA[0].version); + EXPECT_DOUBLE_EQ(SA.time, events.SA[0].time); + EXPECT_DOUBLE_EQ(SA.lat, events.SA[0].lat); + EXPECT_DOUBLE_EQ(SA.lon, events.SA[0].lon); + EXPECT_DOUBLE_EQ(SA.dep, events.SA[0].dep); + EXPECT_DOUBLE_EQ(SA.mag, events.SA[0].mag); + + // Check xml_status + ASSERT_EQ(1, xml_status.nev); + EXPECT_STREQ(SA.eventid, xml_status.SA_status[0].eventid); +} + +TEST_F(CoreEventsFixture, testNewEventWithPreviousEvents) { + lnewEvent = GFAST_core_events_newEvent(SA, &events, &xml_status); + + ASSERT_EQ(1, events.nev); + ASSERT_EQ(1, xml_status.nev); + + lnewEvent = false; + + // Make new event with different evid, lat + struct GFAST_shakeAlert_struct SA2; + memset(&SA2, 0, sizeof(struct GFAST_shakeAlert_struct)); + + get_SA(&SA2); + strcpy(SA2.eventid, "999\0"); + SA2.lat = 48.0; + + // Now add new event + lnewEvent = GFAST_core_events_newEvent(SA2, &events, &xml_status); + EXPECT_TRUE(lnewEvent); + + // Check events + ASSERT_EQ(2, events.nev); + // Check first is the same + EXPECT_STREQ(SA.eventid, events.SA[0].eventid); + EXPECT_STREQ(SA.orig_sys, events.SA[0].orig_sys); + EXPECT_EQ(SA.version, events.SA[0].version); + EXPECT_DOUBLE_EQ(SA.time, events.SA[0].time); + EXPECT_DOUBLE_EQ(SA.lat, events.SA[0].lat); + EXPECT_DOUBLE_EQ(SA.lon, events.SA[0].lon); + EXPECT_DOUBLE_EQ(SA.dep, events.SA[0].dep); + EXPECT_DOUBLE_EQ(SA.mag, events.SA[0].mag); + // Check the new one is represented + EXPECT_STREQ(SA2.eventid, events.SA[1].eventid); + EXPECT_STREQ(SA2.orig_sys, events.SA[1].orig_sys); + EXPECT_EQ(SA2.version, events.SA[1].version); + EXPECT_DOUBLE_EQ(SA2.time, events.SA[1].time); + EXPECT_DOUBLE_EQ(SA2.lat, events.SA[1].lat); + EXPECT_DOUBLE_EQ(SA2.lon, events.SA[1].lon); + EXPECT_DOUBLE_EQ(SA2.dep, events.SA[1].dep); + EXPECT_DOUBLE_EQ(SA2.mag, events.SA[1].mag); + + // Check xml_status + ASSERT_EQ(2, xml_status.nev); + EXPECT_STREQ(SA.eventid, xml_status.SA_status[0].eventid); + EXPECT_STREQ(SA2.eventid, xml_status.SA_status[1].eventid); +} + +TEST_F(CoreEventsFixture, testNewEventUpdatePreviousEvents) { + lnewEvent = GFAST_core_events_newEvent(SA, &events, &xml_status); + + ASSERT_EQ(1, events.nev); + ASSERT_EQ(1, xml_status.nev); + + lnewEvent = false; + + // Make new event that updates the previous + struct GFAST_shakeAlert_struct SA2; + memset(&SA2, 0, sizeof(struct GFAST_shakeAlert_struct)); + + get_SA(&SA2); + SA2.version = 1; + SA2.mag = 3.9; + + // Now add new event + lnewEvent = GFAST_core_events_newEvent(SA2, &events, &xml_status); + EXPECT_FALSE(lnewEvent); + + // Check events + ASSERT_EQ(1, events.nev); + // Check the new one is represented + EXPECT_STREQ(SA2.eventid, events.SA[0].eventid); + EXPECT_STREQ(SA2.orig_sys, events.SA[0].orig_sys); + EXPECT_EQ(SA2.version, events.SA[0].version); + EXPECT_DOUBLE_EQ(SA2.time, events.SA[0].time); + EXPECT_DOUBLE_EQ(SA2.lat, events.SA[0].lat); + EXPECT_DOUBLE_EQ(SA2.lon, events.SA[0].lon); + EXPECT_DOUBLE_EQ(SA2.dep, events.SA[0].dep); + EXPECT_DOUBLE_EQ(SA2.mag, events.SA[0].mag); + + // Check xml_status + ASSERT_EQ(1, xml_status.nev); + EXPECT_STREQ(SA2.eventid, xml_status.SA_status[0].eventid); + +} diff --git a/src/tests/CoreScalingUT.cc b/src/tests/CoreScalingUT.cc new file mode 100644 index 00000000..6db6d436 --- /dev/null +++ b/src/tests/CoreScalingUT.cc @@ -0,0 +1,200 @@ +/** + * @file CoreScalingUT.cc + * @author Carl Ulberg, University of Washington (ulbergc@uw.edu) + * @brief This tests files in the core/scaling directory. + */ + +#include "gtest/gtest.h" +#include "ut_log_init.h" +#include "ut_main.h" + +#include "gfast.h" + +/** + * Test the pgd scaling function. Based on gfast/unit_tests/pgd.c by Ben Baker + */ +TEST(CoreScaling, testPGDScaling) { + int verbose = 4; + + + // Nisqually? + + double dist_tol = 0.5; + double disp_def = 0.01; + double IQR, M, VR; + double SA_lat = 47.19; + double SA_lon =-122.66; + double SA_dep = 57.0; + // stations: bamf, cabl, chzz, eliz, holb, neah, p058, p159 + int l1 = 9; + double wts[9]; + double stla[9] = { 48.83532872, 42.83609887, 45.48651503, + 49.87305293, 50.64035267, 41.90232489, + 48.29785467, 40.87630594, 40.50478709}; + double stlo[9] = {-125.13510527,-124.56334629,-123.97812400, + -127.12266484,-128.13499899,-120.30283244, + -124.62490719,-124.07537043,-124.28278289}; + double staAlt[9] = {0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0}; + double utmRecvNorthing[9], utmRecvEasting[9], Uest[9*1]; + double d[9] = {4, 7.1, 8, 3, 1, 9, 6, 5.5, 6.5}; + double srdist[9]; + double SA_xutm, SA_yutm, utmSrcEasting, utmSrcNorthing, xutm, yutm; + int zone = 10; + + // Tohoku + // double dist_tol = 0.5; + // double disp_def = 0.01; + // double IQR, M, VR; + // double SA_lat = 38.1882; + // double SA_lon = 142.8821; + // double SA_dep = 9.0; + // // stations: 0550, 0036, 0171, 0175, 0172, 0918, 0549 + // int l1 = 7; + // double wts[7]; + // double stla[7] = { 38.3012, 38.4492, 39.0238, 38.6827, + // 38.9029, 38.5098, 38.4251}; + // double stlo[7] = { 141.5007, 141.4412, 141.7398, 141.4494, + // 141.5726, 141.3044, 141.2129}; + // double staAlt[7] = {0.0, 0.0, 0.0, 0.0, + // 0.0, 0.0, 0.0}; + // double utmRecvNorthing[7], utmRecvEasting[7], Uest[7*1]; + // // see 15:34:13:546 + // double d[7] = {95.702998, 87.900208, 23.212499, 50.531524, + // 29.145128, 55.347474, 46.665574}; + // double srdist[7]; + // double SA_xutm, SA_yutm, utmSrcEasting, utmSrcNorthing, xutm, yutm; + // int zone = 54; + + // Begin unchanged test code + const int ndeps = 1; + bool lnorth; + int i, ierr; + ierr = 0; + // Compute source location + GFAST_core_coordtools_ll2utm(SA_lat, SA_lon, + &SA_yutm, &SA_xutm, + &lnorth, &zone); + utmSrcNorthing = SA_yutm; + utmSrcEasting = SA_xutm; + // Compute station locations + for (i=0; ihashsize, 0); + + core_data_finalize(&gps_data); +} + +class CoreTraceBufferFixture : public::testing::Test { + protected: + struct tb2_hashmap_struct *hashmap; + struct tb2_node *node; + const uint32_t hashsize = 31; + + void SetUp() { + hashmap = (struct tb2_hashmap_struct *) + malloc(sizeof(struct tb2_hashmap_struct)); + + hashmap->hashsize = hashsize; + hashmap->map = (struct tb2_node **) calloc(hashsize, sizeof(struct tb2_node *)); + + // Add one node + traceBuffer_ewrr_hashmap_add(hashmap, "Test1", 1); + } + + void TearDown() { + traceBuffer_ewrr_free_hashmap(hashmap); + // free(node); + } +}; + +TEST_F(CoreTraceBufferFixture, testHashmapAddContains) { + node = traceBuffer_ewrr_hashmap_contains(hashmap, "Test1"); + ASSERT_TRUE(node != NULL); + EXPECT_EQ(1, node->i); + EXPECT_STREQ("Test1", node->name); + + node = traceBuffer_ewrr_hashmap_contains(hashmap, "Test2"); + ASSERT_TRUE(node == NULL); +} + +TEST_F(CoreTraceBufferFixture, testHashmapRemove) { + int ret; + ret = traceBuffer_ewrr_hashmap_remove(hashmap, "Test1"); + EXPECT_EQ(1, ret); + + // Also check via the api + node = traceBuffer_ewrr_hashmap_contains(hashmap, "Test1"); + EXPECT_TRUE(node == NULL); + + // Try to remove it again, nothing happens + ret = traceBuffer_ewrr_hashmap_remove(hashmap, "Test1"); + EXPECT_EQ(0, ret); + + // Try to remove something that isn't there, nothing happens + ret = traceBuffer_ewrr_hashmap_remove(hashmap, "Test12"); + EXPECT_EQ(0, ret); +} + +TEST_F(CoreTraceBufferFixture, testHashmapAddPrintDebug) { + // With a hashsize over 5 these shouldn't collide (using one + // of the simpler hashing algorithms at least) + traceBuffer_ewrr_hashmap_add(hashmap, "Test2", 2); + traceBuffer_ewrr_hashmap_add(hashmap, "Test3", 3); + traceBuffer_ewrr_hashmap_add(hashmap, "Test4", 4); + traceBuffer_ewrr_hashmap_add(hashmap, "Test5", 5); + + traceBuffer_ewrr_print_hashmap(hashmap); + + EXPECT_EQ(0, traceBuffer_ewrr_print_true_collisions(hashmap)); +} \ No newline at end of file diff --git a/src/tests/data/M99.txt b/src/tests/data/M99.txt new file mode 100644 index 00000000..a47b98e8 --- /dev/null +++ b/src/tests/data/M99.txt @@ -0,0 +1,24 @@ +5 15 125 5.33 5.34 0.19 5.65 5.79 +10 30 2120 5.62 5.63 0.22 5.99 6.18 +15 45 5813 5.82 5.83 0.26 6.28 6.45 +20 60 9959 5.98 5.99 0.29 6.46 6.65 +25 75 13173 6.10 6.10 0.31 6.62 6.82 +30 90 15085 6.18 6.19 0.34 6.75 6.97 +35 105 16520 6.25 6.27 0.36 6.88 7.08 +40 120 17629 6.31 6.33 0.38 6.98 7.19 +45 135 18805 6.36 6.39 0.40 7.08 7.32 +50 150 20190 6.42 6.45 0.42 7.18 7.42 +55 165 21529 6.47 6.50 0.44 7.27 7.51 +60 180 22366 6.50 6.54 0.46 7.34 7.58 +65 195 22896 6.52 6.57 0.47 7.40 7.65 +70 210 23240 6.55 6.60 0.49 7.45 7.71 +75 225 23487 6.56 6.62 0.50 7.51 7.76 +80 240 23695 6.58 6.64 0.51 7.55 7.81 +85 255 23907 6.60 6.66 0.52 7.61 7.86 +90 270 24112 6.61 6.68 0.53 7.65 7.92 +95 285 24306 6.62 6.70 0.54 7.70 7.97 +100 300 24484 6.64 6.72 0.55 7.74 8.02 +105 315 24648 6.65 6.73 0.56 7.78 8.05 +110 330 24795 6.66 6.75 0.57 7.82 8.10 +115 345 24933 6.67 6.76 0.58 7.86 8.14 +120 360 25073 6.68 6.78 0.59 7.90 8.18 diff --git a/src/tests/data/final_cmt.maule.txt b/src/tests/data/final_cmt.maule.txt new file mode 100644 index 00000000..d021e716 --- /dev/null +++ b/src/tests/data/final_cmt.maule.txt @@ -0,0 +1,321 @@ +19 100 1 1 19 4 1 3.000000 10.000000 +-35.909000 -72.733000 8.000000 +-30.263224 -71.487204 42.596127 -1.702000e-02 -3.000000e-03 2.589000e-02 +-31.188196 -70.998966 963.648118 1.309000e-02 8.740000e-03 -1.995000e-02 +-31.398221 -71.457958 317.075097 1.454000e-02 -3.100000e-03 6.720000e-02 +-35.330957 -72.412169 39.536171 -3.873500e-01 -4.663460e+00 -3.507300e-01 +-36.843800 -73.025500 180.767000 -6.986200e-01 -2.816430e+00 -4.587000e-02 +-29.101637 -71.409735 134.933269 -1.496000e-02 -1.013000e-02 3.561000e-02 +-31.146675 -71.662660 46.379647 4.032000e-02 3.845000e-02 4.305000e-02 +-29.976583 -70.093592 2141.049155 1.383000e-02 -1.836000e-02 1.295000e-02 +-29.908191 -71.246038 78.776669 -2.449999e-03 1.566000e-02 -2.291000e-02 +-35.809595 -70.821459 1184.689220 1.099300e-01 -9.946800e-01 8.970000e-03 +-30.603746 -71.203896 248.965850 1.582000e-02 -6.330000e-03 4.641000e-02 +-30.838969 -70.689128 970.418855 1.641000e-02 7.110000e-03 3.427000e-02 +-30.674746 -71.635434 207.430373 -7.609999e-03 -3.880000e-03 4.906000e-02 +-33.654415 -71.613479 92.456724 -3.557700e-01 -6.536400e-01 -1.049300e-01 +-32.976449 -71.015068 2230.129075 -1.140200e-01 -1.428300e-01 -1.542000e-02 +-29.254903 -70.738743 2351.347054 -9.900000e-03 -3.363000e-02 -8.800006e-04 +-35.595354 -71.732537 118.946446 2.510100e-01 -2.274730e+00 -4.264000e-01 +-30.169891 -70.806051 2229.920731 3.064000e-02 2.360000e-02 7.900037e-04 +-28.571974 -70.764374 412.146984 -1.709000e-02 9.999999e-05 4.273000e-02 +1.000000 +1.143508e+22 -3.899444e+21 -7.535640e+21 -9.426879e+21 -2.863254e+20 5.299839e+21 +281.745881 55.937094 330.795991 29.130295 66.158693 -142.239944 8.713093 0.082918 +2.000000 +1.139086e+22 -3.769648e+21 -7.621216e+21 -9.354721e+21 -4.955319e+20 5.902173e+21 +281.326833 54.325855 330.544159 29.556198 66.454723 -140.495677 8.716500 0.075949 +3.000000 +1.132482e+22 -3.634543e+21 -7.690278e+21 -9.264536e+21 -7.051882e+20 6.496512e+21 +280.934628 52.784755 330.418072 29.883420 66.849881 -138.869481 8.719841 0.070092 +4.000000 +1.123728e+22 -3.495604e+21 -7.741681e+21 -9.156451e+21 -9.104165e+20 7.077327e+21 +280.560724 51.307000 330.391170 30.118843 67.317170 -137.347235 8.723055 0.065127 +5.000000 +1.112856e+22 -3.355340e+21 -7.773219e+21 -9.030287e+21 -1.106863e+21 7.639722e+21 +280.202346 49.890652 330.447694 30.268332 67.838343 -135.921756 8.726072 0.060880 +6.000000 +1.099894e+22 -3.216999e+21 -7.781941e+21 -8.885664e+21 -1.290927e+21 8.179680e+21 +279.860796 48.535118 330.579909 30.337154 68.401921 -134.588853 8.728816 0.057209 +7.000000 +1.084872e+22 -3.084226e+21 -7.764498e+21 -8.722127e+21 -1.459880e+21 8.694194e+21 +30.330054 69.001731 226.655353 279.539901 47.238888 -29.214095 8.731217 0.054001 +8.000000 +1.067823e+22 -2.960734e+21 -7.717492e+21 -8.539257e+21 -1.611885e+21 9.181293e+21 +30.251106 69.635746 227.816079 279.244670 45.998240 -28.932147 8.733218 0.051167 +9.000000 +1.048778e+22 -2.850023e+21 -7.637756e+21 -8.336772e+21 -1.745934e+21 9.639978e+21 +30.103452 70.305131 228.900778 278.980235 44.806655 -28.569338 8.734776 0.048633 +10.000000 +1.027775e+22 -2.755168e+21 -7.522581e+21 -8.114588e+21 -1.861735e+21 1.007011e+22 +29.889003 71.013455 229.919549 278.751077 43.654661 -28.118993 8.735868 0.047263 +11.000000 +1.004853e+22 -2.678683e+21 -7.369845e+21 -7.872862e+21 -1.959572e+21 1.047224e+22 +29.608147 71.766075 230.885264 278.560532 42.529901 -27.573306 8.736487 0.049425 +12.000000 +9.800532e+21 -2.622445e+21 -7.178087e+21 -7.612002e+21 -2.040161e+21 1.084751e+22 +29.259457 72.569648 231.813606 278.410550 41.417259 -26.923660 8.736644 0.051707 +13.000000 +9.534197e+21 -2.587683e+21 -6.946514e+21 -7.332657e+21 -2.104516e+21 1.119742e+22 +28.839409 73.431761 232.723102 278.301678 40.298950 -26.160691 8.736365 0.054130 +14.000000 +9.249970e+21 -2.574994e+21 -6.674976e+21 -7.035693e+21 -2.153844e+21 1.152378e+22 +28.342113 74.360607 233.635215 278.233274 39.154546 -25.274116 8.735690 0.056711 +15.000000 +8.948305e+21 -2.584400e+21 -6.363905e+21 -6.722166e+21 -2.189446e+21 1.182858e+22 +27.759069 75.364639 234.574469 278.203977 37.960980 -24.252375 8.734672 0.059461 +16.000000 +8.629650e+21 -2.615402e+21 -6.014248e+21 -6.393282e+21 -2.212657e+21 1.211388e+22 +27.079034 76.452092 235.568557 278.212545 36.692615 -23.082107 8.733373 0.062381 +17.000000 +8.294449e+21 -2.667056e+21 -5.627393e+21 -6.050361e+21 -2.224793e+21 1.238178e+22 +26.288105 77.630245 236.648242 278.259215 35.321596 -21.747473 8.731865 0.065453 +18.000000 +7.943133e+21 -2.738042e+21 -5.205091e+21 -5.694807e+21 -2.227121e+21 1.263434e+22 +25.370291 78.904247 237.846797 278.347878 33.818785 -20.229323 8.730229 0.068630 +19.000000 +7.576120e+21 -2.826734e+21 -4.749386e+21 -5.328073e+21 -2.220837e+21 1.287359e+22 +24.308922 80.275347 239.198533 278.489453 32.155748 -18.504176 8.728549 0.071825 +20.000000 +7.193809e+21 -2.931256e+21 -4.262553e+21 -4.951636e+21 -2.207054e+21 1.310146e+22 +23.089379 81.738510 240.735847 278.706907 30.308319 -16.542858 8.726914 0.074894 +21.000000 +6.796584e+21 -3.049551e+21 -3.747033e+21 -4.566971e+21 -2.186799e+21 1.331977e+22 +279.042304 28.262109 345.691549 21.703549 83.279669 -117.515696 8.725418 0.077633 +22.000000 +6.384812e+21 -3.179424e+21 -3.205388e+21 -4.175535e+21 -2.161010e+21 1.353024e+22 +279.565900 26.019662 348.247222 20.155862 84.873539 -115.544233 8.724149 0.079783 +23.000000 +5.958843e+21 -3.318591e+21 -2.640252e+21 -3.778750e+21 -2.130543e+21 1.373448e+22 +280.386653 23.607600 351.189920 18.469593 86.483502 -113.359067 8.723196 0.081069 +24.000000 +5.519015e+21 -3.464721e+21 -2.054294e+21 -3.377987e+21 -2.096169e+21 1.393395e+22 +281.662964 21.080598 354.613848 16.690563 88.065189 -110.995648 8.722639 0.081263 +25.000000 +5.065653e+21 -3.615469e+21 -1.450184e+21 -2.974562e+21 -2.058585e+21 1.413001e+22 +283.612732 18.518930 358.658457 14.884832 89.573937 -108.514199 8.722552 0.080259 +26.000000 +4.599073e+21 -3.768508e+21 -8.305644e+20 -2.569722e+21 -2.018419e+21 1.432390e+22 +286.523022 16.019094 3.530695 193.129098 89.026247 105.990244 8.722993 0.078115 +27.000000 +4.119582e+21 -3.921558e+21 -1.980240e+20 -2.164642e+21 -1.976230e+21 1.451670e+22 +290.758822 13.681603 9.527640 191.496777 87.756262 103.499830 8.724009 0.075042 +28.000000 +3.627483e+21 -4.072402e+21 4.449189e+20 -1.760425e+21 -1.932522e+21 1.470942e+22 +296.759912 11.602277 17.042860 190.045678 86.620757 101.105717 8.725630 0.071336 +29.000000 +3.123076e+21 -4.218912e+21 1.095835e+21 -1.358093e+21 -1.887741e+21 1.490293e+22 +304.983038 9.870209 26.510899 188.811879 85.611724 98.849718 8.727868 0.067303 +30.000000 +2.606660e+21 -4.359059e+21 1.752399e+21 -9.585900e+20 -1.842284e+21 1.509800e+22 +315.697508 8.567608 38.199209 187.810349 84.714040 96.752190 8.730721 0.063198 +31.000000 +2.078533e+21 -4.490928e+21 2.412395e+21 -5.627811e+20 -1.796506e+21 1.529529e+22 +328.581270 7.758359 51.797867 187.039739 83.910374 94.816227 8.734170 0.059207 +32.000000 +1.538995e+21 -4.612727e+21 3.073731e+21 -1.714530e+20 -1.750717e+21 1.549538e+22 +342.426280 7.457314 66.118684 186.488270 83.184309 93.033371 8.738184 0.055445 +33.000000 +9.883527e+20 -4.722794e+21 3.734442e+21 2.146838e+20 -1.705191e+21 1.569873e+22 +355.587392 7.605367 79.539366 186.138788 82.521764 91.388725 8.742721 0.051972 +34.000000 +4.269121e+20 -4.819602e+21 4.392690e+21 5.949940e+20 -1.660170e+21 1.590576e+22 +6.934024 8.089830 90.952134 185.972321 81.911295 89.864670 8.747732 0.048810 +35.000000 +-1.450135e+20 -4.901760e+21 5.046774e+21 9.689140e+20 -1.615863e+21 1.611677e+22 +185.970241 81.343826 88.443200 16.206340 8.794004 100.118268 8.753161 0.045955 +36.000000 +-7.271063e+20 -4.968016e+21 5.695122e+21 1.335950e+21 -1.572454e+21 1.633203e+22 +186.115388 80.812172 87.107211 23.676536 9.628735 107.328661 8.758951 0.048644 +37.000000 +-1.319043e+21 -5.017253e+21 6.336295e+21 1.695672e+21 -1.530100e+21 1.655170e+22 +186.392542 80.310558 85.841106 29.758378 10.536433 113.013181 8.765045 0.051539 +38.000000 +-1.920495e+21 -5.048491e+21 6.968985e+21 2.047717e+21 -1.488937e+21 1.677594e+22 +186.788502 79.834197 84.630995 34.823109 11.483313 117.556704 8.771389 0.054586 +39.000000 +-2.531128e+21 -5.060881e+21 7.592009e+21 2.391778e+21 -1.449080e+21 1.700480e+22 +187.291949 79.378971 83.464684 39.155157 12.450938 121.255081 8.777929 0.057774 +40.000000 +-3.150602e+21 -5.053702e+21 8.204305e+21 2.727605e+21 -1.410626e+21 1.723833e+22 +187.893222 78.941193 82.331571 42.959904 13.430157 124.323224 8.784619 0.061089 +41.000000 +-3.778575e+21 -5.026355e+21 8.804930e+21 3.054999e+21 -1.373658e+21 1.747652e+22 +188.584037 78.517444 81.222510 46.382550 14.417268 126.914303 8.791414 0.064514 +42.000000 +-4.414698e+21 -4.978356e+21 9.393054e+21 3.373810e+21 -1.338240e+21 1.771933e+22 +189.357198 78.104471 80.129689 49.525159 15.411686 129.137123 8.798278 0.068031 +43.000000 +-5.058618e+21 -4.909335e+21 9.967953e+21 3.683935e+21 -1.304429e+21 1.796668e+22 +190.206311 77.699134 79.046531 52.459412 16.414514 131.069195 8.805176 0.071616 +44.000000 +-5.709980e+21 -4.819023e+21 1.052900e+22 3.985311e+21 -1.272266e+21 1.821848e+22 +191.125495 77.298394 77.967626 55.235559 17.427633 132.765996 8.812082 0.075243 +45.000000 +-6.368425e+21 -4.707251e+21 1.107568e+22 4.277913e+21 -1.241784e+21 1.847462e+22 +192.109116 76.899337 76.888696 57.888595 18.453102 134.267450 8.818970 0.078879 +46.000000 +-7.033592e+21 -4.573940e+21 1.160753e+22 4.561752e+21 -1.213008e+21 1.873495e+22 +193.151529 76.499225 75.806576 60.442521 19.492735 135.602470 8.825821 0.082488 +47.000000 +-7.705119e+21 -4.419096e+21 1.212421e+22 4.836870e+21 -1.185953e+21 1.899932e+22 +194.246850 76.095578 74.719223 62.913315 20.547786 136.792202 8.832620 0.086029 +48.000000 +-8.382642e+21 -4.242801e+21 1.262544e+22 5.103341e+21 -1.160629e+21 1.926758e+22 +195.388755 75.686270 73.625706 65.311056 21.618718 137.852386 8.839353 0.089457 +49.000000 +-9.065796e+21 -4.045211e+21 1.311101e+22 5.361262e+21 -1.137040e+21 1.953955e+22 +196.570344 75.269638 72.526197 67.641475 22.705038 138.795106 8.846010 0.092723 +50.000000 +-9.754216e+21 -3.826545e+21 1.358076e+22 5.610755e+21 -1.115184e+21 1.981506e+22 +197.784057 74.844590 71.421927 69.907133 23.805204 139.630099 8.852585 0.095781 +51.000000 +-1.044754e+22 -3.587082e+21 1.403462e+22 5.851963e+21 -1.095056e+21 2.009392e+22 +199.021673 74.410699 70.315098 72.108337 24.916602 140.365729 8.859071 0.098581 +52.000000 +-1.114540e+22 -3.327154e+21 1.447255e+22 6.085049e+21 -1.076646e+21 2.037595e+22 +200.274398 73.968265 69.208752 74.243881 26.035615 141.009692 8.865464 0.101081 +53.000000 +-1.184744e+22 -3.047141e+21 1.489458e+22 6.310190e+21 -1.059942e+21 2.066097e+22 +201.533030 73.518340 68.106584 76.311654 27.157761 141.569494 8.871763 0.103244 +54.000000 +-1.255329e+22 -2.747465e+21 1.530076e+22 6.527580e+21 -1.044929e+21 2.094880e+22 +202.788202 73.062697 67.012724 78.309147 28.277903 142.052729 8.877966 0.105042 +55.000000 +-1.326260e+22 -2.428587e+21 1.569119e+22 6.737424e+21 -1.031589e+21 2.123925e+22 +204.030669 72.603746 65.931484 80.233856 29.390521 142.467195 8.884072 0.106458 +56.000000 +-1.397502e+22 -2.090998e+21 1.606602e+22 6.939941e+21 -1.019904e+21 2.153214e+22 +205.251615 72.144406 64.867110 82.083605 30.490000 142.820879 8.890082 0.107486 +57.000000 +-1.469018e+22 -1.735222e+21 1.642541e+22 7.135355e+21 -1.009852e+21 2.182730e+22 +206.442943 71.687930 63.823555 83.856774 31.570913 143.121840 8.895998 0.108132 +58.000000 +-1.540775e+22 -1.361805e+21 1.676955e+22 7.323902e+21 -1.001412e+21 2.212456e+22 +207.597514 71.237729 62.804294 85.552448 32.628283 143.378048 8.901819 0.108413 +59.000000 +-1.612738e+22 -9.713133e+20 1.709869e+22 7.505820e+21 -9.945617e+20 2.242375e+22 +208.709326 70.797185 61.812189 87.170483 33.657772 143.597195 8.907549 0.108354 +60.000000 +-1.684872e+22 -5.643327e+20 1.741305e+22 7.681357e+21 -9.892775e+20 2.272471e+22 +209.773607 70.369493 60.849422 88.711505 34.655819 143.786522 8.913190 0.107988 +61.000000 +-1.757144e+22 -1.414623e+20 1.771290e+22 7.850762e+21 -9.855357e+20 2.302729e+22 +210.786827 69.957527 59.917484 90.176856 35.619700 143.952677 8.918743 0.107353 +62.000000 +-1.829522e+22 2.966875e+20 1.799853e+22 8.014287e+21 -9.833121e+20 2.333134e+22 +211.746652 69.563754 59.017204 91.568504 36.547527 144.101616 8.924210 0.106487 +63.000000 +-1.901972e+22 7.494976e+20 1.827023e+22 8.172187e+21 -9.825824e+20 2.363671e+22 +212.651837 69.190187 58.148824 92.888929 37.438197 144.238550 8.929594 0.105429 +64.000000 +-1.974464e+22 1.216343e+21 1.852829e+22 8.324718e+21 -9.833223e+20 2.394327e+22 +213.502091 68.838363 57.312088 94.140999 38.291308 144.367933 8.934897 0.104218 +65.000000 +-2.046964e+22 1.696595e+21 1.877305e+22 8.472136e+21 -9.855073e+20 2.425089e+22 +214.297921 68.509365 56.506341 95.327854 39.107050 144.493485 8.940122 0.102889 +66.000000 +-2.119444e+22 2.189623e+21 1.900482e+22 8.614696e+21 -9.891131e+20 2.455945e+22 +215.040480 68.203854 55.730628 96.452798 39.886097 144.618244 8.945270 0.101473 +67.000000 +-2.191873e+22 2.694796e+21 1.922394e+22 8.752654e+21 -9.941156e+20 2.486884e+22 +215.731417 67.922115 54.983781 97.519199 40.629492 144.744625 8.950343 0.100000 +68.000000 +-2.264222e+22 3.211488e+21 1.943074e+22 8.886260e+21 -1.000491e+21 2.517893e+22 +216.372743 67.664116 54.264502 98.530420 41.338552 144.874492 8.955344 0.098492 +69.000000 +-2.336463e+22 3.739074e+21 1.962556e+22 9.015767e+21 -1.008215e+21 2.548964e+22 +216.966721 67.429556 53.571424 99.489753 42.014775 145.009240 8.960275 0.096970 +70.000000 +-2.408568e+22 4.276935e+21 1.980874e+22 9.141422e+21 -1.017265e+21 2.580085e+22 +217.515767 67.217926 52.903165 100.400377 42.659767 145.149856 8.965136 0.095452 +71.000000 +-2.480509e+22 4.824458e+21 1.998063e+22 9.263469e+21 -1.027617e+21 2.611249e+22 +218.022374 67.028547 52.258362 101.265323 43.275187 145.296996 8.969930 0.093950 +72.000000 +-2.552262e+22 5.381040e+21 2.014158e+22 9.382150e+21 -1.039248e+21 2.642447e+22 +102.087459 43.862697 145.451037 218.489051 66.860622 51.635706 8.974658 0.092476 +73.000000 +-2.623801e+22 5.946083e+21 2.029192e+22 9.497700e+21 -1.052136e+21 2.673671e+22 +102.869478 44.423925 145.612136 218.918280 66.713263 51.033953 8.979323 0.091039 +74.000000 +-2.695101e+22 6.519003e+21 2.043201e+22 9.610354e+21 -1.066259e+21 2.704914e+22 +103.613890 44.960448 145.780271 219.312478 66.585526 50.451941 8.983924 0.089644 +75.000000 +-2.766140e+22 7.099225e+21 2.056217e+22 9.720338e+21 -1.081594e+21 2.736168e+22 +104.323030 45.473766 145.955284 219.673977 66.476433 49.888593 8.988464 0.088297 +76.000000 +-2.836894e+22 7.686184e+21 2.068276e+22 9.827876e+21 -1.098121e+21 2.767429e+22 +104.999059 45.965299 146.136909 220.005006 66.384992 49.342921 8.992943 0.087000 +77.000000 +-2.907343e+22 8.279329e+21 2.079410e+22 9.933186e+21 -1.115817e+21 2.798690e+22 +105.643971 46.436374 146.324802 220.307683 66.310213 48.814021 8.997363 0.085757 +78.000000 +-2.977466e+22 8.878122e+21 2.089654e+22 1.003648e+22 -1.134661e+21 2.829947e+22 +106.259609 46.888228 146.518560 220.584006 66.251116 48.301075 9.001725 0.084568 +79.000000 +-3.047242e+22 9.482038e+21 2.099039e+22 1.013797e+22 -1.154634e+21 2.861194e+22 +106.847666 47.322008 146.717743 220.835857 66.206746 47.803338 9.006029 0.083433 +80.000000 +-3.116654e+22 1.009056e+22 2.107598e+22 1.023785e+22 -1.175714e+21 2.892428e+22 +107.409704 47.738771 146.921885 221.064999 66.176173 47.320142 9.010277 0.082353 +81.000000 +-3.185684e+22 1.070321e+22 2.115363e+22 1.033632e+22 -1.197882e+21 2.923645e+22 +107.947160 48.139489 147.130508 221.273080 66.158500 46.850881 9.014469 0.081326 +82.000000 +-3.254313e+22 1.131948e+22 2.122366e+22 1.043357e+22 -1.221117e+21 2.954842e+22 +108.461358 48.525055 147.343128 221.461637 66.152864 46.395010 9.018607 0.080352 +83.000000 +-3.322528e+22 1.193891e+22 2.128637e+22 1.052979e+22 -1.245400e+21 2.986016e+22 +108.953517 48.896287 147.559266 221.632100 66.158441 45.952038 9.022691 0.079430 +84.000000 +-3.390312e+22 1.256106e+22 2.134207e+22 1.062515e+22 -1.270712e+21 3.017164e+22 +109.424764 49.253933 147.778452 221.785801 66.174444 45.521522 9.026721 0.078558 +85.000000 +-3.457652e+22 1.318547e+22 2.139105e+22 1.071983e+22 -1.297034e+21 3.048286e+22 +109.876139 49.598677 148.000227 221.923973 66.200123 45.103060 9.030699 0.077734 +86.000000 +-3.524534e+22 1.381174e+22 2.143361e+22 1.081399e+22 -1.324346e+21 3.079378e+22 +110.308607 49.931145 148.224152 222.047761 66.234768 44.696286 9.034626 0.076957 +87.000000 +-3.590946e+22 1.443944e+22 2.147002e+22 1.090779e+22 -1.352632e+21 3.110440e+22 +110.723058 50.251908 148.449804 222.158228 66.277705 44.300869 9.038501 0.076226 +88.000000 +-3.656877e+22 1.506819e+22 2.150058e+22 1.100139e+22 -1.381872e+21 3.141471e+22 +111.120324 50.561489 148.676782 222.256356 66.328297 43.916505 9.042325 0.075537 +89.000000 +-3.722316e+22 1.569761e+22 2.152555e+22 1.109494e+22 -1.412049e+21 3.172470e+22 +111.501175 50.860367 148.904705 222.343055 66.385942 43.542914 9.046100 0.074890 +90.000000 +-3.787254e+22 1.632734e+22 2.154520e+22 1.118858e+22 -1.443145e+21 3.203437e+22 +111.866332 51.148981 149.133216 222.419165 66.450073 43.179837 9.049825 0.074283 +91.000000 +-3.851681e+22 1.695703e+22 2.155978e+22 1.128244e+22 -1.475143e+21 3.234371e+22 +112.216466 51.427735 149.361980 222.485466 66.520156 42.827033 9.053502 0.073714 +92.000000 +-3.915589e+22 1.758634e+22 2.156956e+22 1.137666e+22 -1.508026e+21 3.265273e+22 +112.552208 51.696997 149.590682 222.542675 66.595687 42.484278 9.057131 0.073181 +93.000000 +-3.978972e+22 1.821495e+22 2.157477e+22 1.147137e+22 -1.541776e+21 3.296143e+22 +112.874148 51.957111 149.819033 222.591459 66.676195 42.151359 9.060712 0.072682 +94.000000 +-4.041822e+22 1.884257e+22 2.157565e+22 1.156667e+22 -1.576378e+21 3.326982e+22 +113.182841 52.208391 150.046763 222.632430 66.761235 41.828075 9.064247 0.072217 +95.000000 +-4.104134e+22 1.946889e+22 2.157245e+22 1.166269e+22 -1.611816e+21 3.357791e+22 +113.478811 52.451128 150.273623 222.666155 66.850392 41.514234 9.067735 0.071783 +96.000000 +-4.165902e+22 2.009365e+22 2.156538e+22 1.175953e+22 -1.648073e+21 3.388570e+22 +113.762552 52.685595 150.499386 222.693159 66.943275 41.209653 9.071178 0.071380 +97.000000 +-4.227122e+22 2.071657e+22 2.155466e+22 1.185729e+22 -1.685135e+21 3.419322e+22 +114.034529 52.912043 150.723843 222.713924 67.039521 40.914154 9.074575 0.071004 +98.000000 +-4.287791e+22 2.133740e+22 2.154051e+22 1.195608e+22 -1.722985e+21 3.450046e+22 +114.295186 53.130708 150.946803 222.728898 67.138788 40.627567 9.077928 0.070657 +99.000000 +-4.347904e+22 2.195590e+22 2.152314e+22 1.205598e+22 -1.761609e+21 3.480745e+22 +114.544941 53.341810 151.168096 222.738491 67.240757 40.349724 9.081238 0.070335 +100.000000 +-4.407459e+22 2.257186e+22 2.150273e+22 1.215708e+22 -1.800992e+21 3.511421e+22 +114.784193 53.545556 151.387566 222.743084 67.345131 40.080463 9.084504 0.070037 diff --git a/src/tests/data/final_ff.maule.txt b/src/tests/data/final_ff.maule.txt new file mode 100644 index 00000000..f5a7d456 --- /dev/null +++ b/src/tests/data/final_ff.maule.txt @@ -0,0 +1,74 @@ +10 5 19 2 4 2.000000 10.000000 10.000000 260.000000 +-35.909000 -72.733000 35.000000 8.753161 +185.970241 16.206340 81.343826 8.794004 +19 +-30.263224 -71.487204 42.596127 -0.017020 -0.003000 0.025890 +-31.188196 -70.998966 963.648118 0.013090 0.008740 -0.019950 +-31.398221 -71.457958 317.075097 0.014540 -0.003100 0.067200 +-35.330957 -72.412169 39.536171 -0.387350 -4.663460 -0.350730 +-36.843800 -73.025500 180.767000 -0.698620 -2.816430 -0.045870 +-29.101637 -71.409735 134.933269 -0.014960 -0.010130 0.035610 +-31.146675 -71.662660 46.379647 0.040320 0.038450 0.043050 +-29.976583 -70.093592 2141.049155 0.013830 -0.018360 0.012950 +-29.908191 -71.246038 78.776669 -0.002450 0.015660 -0.022910 +-35.809595 -70.821459 1184.689220 0.109930 -0.994680 0.008970 +-30.603746 -71.203896 248.965850 0.015820 -0.006330 0.046410 +-30.838969 -70.689128 970.418855 0.016410 0.007110 0.034270 +-30.674746 -71.635434 207.430373 -0.007610 -0.003880 0.049060 +-33.654415 -71.613479 92.456724 -0.355770 -0.653640 -0.104930 +-32.976449 -71.015068 2230.129075 -0.114020 -0.142830 -0.015420 +-29.254903 -70.738743 2351.347054 -0.009900 -0.033630 -0.000880 +-35.595354 -71.732537 118.946446 0.251010 -2.274730 -0.426400 +-30.169891 -70.806051 2229.920731 0.030640 0.023600 0.000790 +-28.571974 -70.764374 412.146984 -0.017090 0.000100 0.042730 +94.735261 99.666209 8.774918 8.709037 +6.981840e-03 -1.756591e-03 3.251968e-04 -4.695707e-04 +6.569306e+00 5.358946e-01 1.691353e+00 -1.498365e+00 +4.812191e+00 8.572422e+00 3.880050e+00 -2.794910e+00 +1.064880e+00 7.525638e+00 5.300903e+00 -3.491894e+00 +2.971526e+00 -1.648211e+01 6.445573e+00 -3.393206e+00 +4.276856e+00 -6.071749e+00 8.849150e+00 -2.961577e+00 +4.041950e+00 8.412001e+00 9.910757e+00 -2.309031e+00 +-6.452249e+00 -8.544879e+00 7.137842e+00 -1.303738e+00 +-4.344372e+00 -7.222986e+00 3.844063e+00 -4.907164e-01 +-1.257687e-03 -3.970343e-03 2.045778e-03 2.724441e-04 +4.328278e-03 9.529795e-04 2.107605e-04 -5.425061e-04 +8.545487e+00 2.184059e+00 2.492862e+00 -2.077899e+00 +6.337225e+00 8.919644e+00 5.841819e+00 -3.949806e+00 +-6.502588e-01 5.357168e+00 7.791870e+00 -5.202714e+00 +1.517284e+00 -1.381498e+01 8.725468e+00 -4.476327e+00 +2.427757e+00 -9.931896e+00 1.176334e+01 -3.653110e+00 +-3.369706e+00 -3.954413e-01 1.374493e+01 -4.195383e+00 +-1.198088e+01 -9.592515e+00 9.795734e+00 -2.642679e+00 +-7.156432e+00 -8.279788e+00 5.220902e+00 -6.650449e-01 +-1.920325e-03 -2.794616e-03 3.073169e-03 8.778254e-05 +2.065962e-03 1.557104e-03 -5.600464e-06 -2.829343e-04 +6.727554e+00 2.673890e+00 2.188651e+00 -1.498811e+00 +5.668906e+00 6.402232e+00 5.353556e+00 -2.813950e+00 +5.864558e-01 2.892369e+00 7.091571e+00 -4.538357e+00 +1.117712e+00 -8.865516e+00 6.385557e+00 -2.456849e+00 +4.053532e-01 -9.250176e+00 7.457588e+00 -7.498799e-01 +-5.654909e+00 -4.995163e+00 9.945847e+00 -5.430323e+00 +-1.092063e+01 -8.170745e+00 7.403087e+00 -3.636582e+00 +-6.523452e+00 -6.364901e+00 4.012666e+00 2.519792e-02 +-1.545248e-03 -1.752607e-03 -4.962197e-04 1.357072e-03 +7.672913e-04 1.143445e-03 -1.611446e-04 4.455567e-05 +3.259032e+00 1.613139e+00 1.182034e+00 -4.934066e-01 +3.063483e+00 3.021855e+00 3.253053e+00 -8.330879e-01 +8.643260e-01 1.152456e+00 4.418793e+00 -1.824225e+00 +7.321471e-01 -3.923177e+00 2.506446e+00 5.473549e-01 +-1.194998e-01 -4.899511e+00 1.469561e+00 2.680126e+00 +-3.349441e+00 -3.588427e+00 3.617048e+00 -4.360118e+00 +-5.594722e+00 -4.291699e+00 3.134868e+00 -2.949152e+00 +-3.359417e+00 -3.106831e+00 2.126178e+00 7.349621e-01 +-5.590144e-04 -7.558101e-04 1.098764e-02 3.213328e-03 +-5.422809e-04 2.624346e-04 -3.881857e-04 1.253331e-04 +2.196575e-03 1.192223e-03 3.474868e-04 7.250193e-05 +2.086303e-03 2.061485e-03 2.219692e-03 5.496965e-04 +5.031023e-04 1.054362e-03 3.658895e-03 -4.919702e-04 +7.748379e-04 -2.379880e-03 1.091501e-03 5.013897e-03 +3.770820e-04 -2.947058e-03 4.270807e-03 1.768619e-02 +-1.949628e-03 -1.954275e-03 6.733083e-03 -1.461450e-02 +-3.518394e-03 -2.600405e-03 1.151630e-03 -5.895620e-03 +-1.849816e-03 -1.946725e-03 2.525124e-03 2.167190e-03 +5.568659e-04 3.263398e-04 5.543150e-03 9.815469e-04 diff --git a/src/tests/data/final_pgd.maule.txt b/src/tests/data/final_pgd.maule.txt new file mode 100644 index 00000000..c01e7402 --- /dev/null +++ b/src/tests/data/final_pgd.maule.txt @@ -0,0 +1,221 @@ +19 100 19 4 6.000000 0.010000 3.000000 +-35.909000 -72.733000 8.000000 +-30.263224 -71.487204 42.596127 0.226871 +-31.188196 -70.998966 963.648118 0.333316 +-31.398221 -71.457958 317.075097 0.309424 +-35.330957 -72.412169 39.536171 5.031876 +-36.843800 -73.025500 180.767000 3.010164 +-29.101637 -71.409735 134.933269 0.188263 +-31.146675 -71.662660 46.379647 0.234143 +-29.976583 -70.093592 2141.049155 0.274013 +-29.908191 -71.246038 78.776669 0.220529 +-35.809595 -70.821459 1184.689220 1.355254 +-30.603746 -71.203896 248.965850 0.259477 +-30.838969 -70.689128 970.418855 0.297185 +-30.674746 -71.635434 207.430373 0.228823 +-33.654415 -71.613479 92.456724 1.186303 +-32.976449 -71.015068 2230.129075 0.625368 +-29.254903 -70.738743 2351.347054 0.234336 +-35.595354 -71.732537 118.946446 2.581428 +-30.169891 -70.806051 2229.920731 0.219736 +-28.571974 -70.764374 412.146984 0.212388 +1.000000 +2.000000 +3.000000 +4.000000 +5.000000 +6.000000 +7.000000 +8.000000 +9.000000 +10.000000 +11.000000 +12.000000 +13.000000 +14.000000 +15.000000 +16.000000 +17.000000 +18.000000 +19.000000 +20.000000 +21.000000 +22.000000 +23.000000 +24.000000 +25.000000 +26.000000 +27.000000 +28.000000 +29.000000 +30.000000 +31.000000 +32.000000 +33.000000 +34.000000 +35.000000 +36.000000 +37.000000 +38.000000 +39.000000 +40.000000 +41.000000 +42.000000 +43.000000 +44.000000 +45.000000 +46.000000 +47.000000 +48.000000 +49.000000 +50.000000 +51.000000 +52.000000 +53.000000 +54.000000 +55.000000 +56.000000 +57.000000 +58.000000 +59.000000 +60.000000 +61.000000 +62.000000 +63.000000 +64.000000 +65.000000 +66.000000 +67.000000 +68.000000 +69.000000 +70.000000 +71.000000 +72.000000 +73.000000 +74.000000 +75.000000 +76.000000 +77.000000 +78.000000 +79.000000 +80.000000 +81.000000 +82.000000 +83.000000 +84.000000 +85.000000 +86.000000 +87.000000 +88.000000 +89.000000 +90.000000 +91.000000 +92.000000 +93.000000 +94.000000 +95.000000 +96.000000 +97.000000 +98.000000 +99.000000 +100.000000 +8.532404 85.792875 0.015832 +8.532535 85.805632 0.015829 +8.532760 85.826227 0.015823 +8.533079 85.854628 0.015815 +8.533492 85.890787 0.015804 +8.533999 85.934644 0.015791 +8.534598 85.986125 0.015775 +8.535290 86.045146 0.015757 +8.536073 86.111608 0.015737 +8.536948 86.185403 0.015714 +8.537913 86.266411 0.015689 +8.538967 86.354500 0.015661 +8.540111 86.449530 0.015632 +8.541342 86.551352 0.015599 +8.542659 86.659806 0.015565 +8.544063 86.774727 0.015528 +8.545551 86.895941 0.015488 +8.547122 87.023268 0.015446 +8.548776 87.156522 0.015402 +8.550510 87.295511 0.015356 +8.552324 87.440041 0.015308 +8.554217 87.589912 0.015257 +8.556186 87.744922 0.015203 +8.558231 87.904868 0.015148 +8.560350 88.069542 0.015090 +8.562541 88.238738 0.015031 +8.564803 88.412248 0.014969 +8.567135 88.589865 0.014904 +8.569536 88.771383 0.014838 +8.572002 88.956597 0.014769 +8.574534 89.145302 0.014699 +8.577129 89.337298 0.014626 +8.579786 89.532385 0.014551 +8.582504 89.730369 0.014474 +8.585280 89.931056 0.014395 +8.588114 90.134258 0.014313 +8.591003 90.339790 0.014230 +8.593946 90.547472 0.014145 +8.596943 90.757128 0.014058 +8.599990 90.694855 0.582767 +8.603087 90.585542 0.579015 +8.606232 90.476594 0.575183 +8.609424 90.368121 0.571273 +8.612661 90.260227 0.567286 +8.615943 90.153014 0.563222 +8.619266 90.046575 0.559081 +8.622631 89.941000 0.554866 +8.626035 89.836371 0.550575 +8.629477 89.732768 0.546211 +8.632957 89.630265 0.541774 +8.636472 89.528928 0.537264 +8.640021 89.428823 0.532683 +8.643604 89.330007 0.528030 +8.647219 89.232535 0.523308 +8.650864 89.136457 0.518515 +8.654539 89.041816 0.513654 +8.658242 88.948655 0.508725 +8.661972 88.857010 0.503728 +8.665729 88.766914 0.498665 +8.669510 88.678396 0.493535 +8.673316 88.591482 0.488340 +8.677144 88.506195 0.477416 +8.680995 88.422552 0.300083 +8.684866 88.340571 0.121639 +8.688758 88.233182 0.011129 +8.692668 88.079250 0.010993 +8.696597 87.926608 0.010855 +8.700543 87.775282 0.010716 +8.704506 87.625292 0.010575 +8.708484 87.476660 0.010432 +8.712476 87.329402 0.010288 +8.716483 87.183533 0.010142 +8.720503 87.039067 0.009995 +8.724536 86.896015 0.009846 +8.728580 86.754385 0.009696 +8.732635 86.614184 0.009544 +8.736700 86.475419 0.009390 +8.740775 86.338093 0.009235 +8.744859 86.202209 0.009079 +8.748952 86.067768 0.008921 +8.753052 85.934770 0.008762 +8.757159 85.803213 0.008601 +8.761273 85.673095 0.008438 +8.765393 85.544413 0.008275 +8.769519 85.417161 0.008110 +8.773649 85.291334 0.007943 +8.777784 85.166927 0.007775 +8.781923 85.043932 0.007605 +8.786065 84.922342 0.007435 +8.790210 84.802147 0.007262 +8.794358 84.683340 0.007089 +8.798508 84.565911 0.006914 +8.802660 84.449849 0.006738 +8.806813 84.335145 0.006560 +8.810967 84.221787 0.006382 +8.815121 84.109748 0.006225 +8.819276 83.999022 0.006043 +8.823430 83.889607 0.005860 +8.827584 83.781493 0.005676 +8.831737 83.674666 0.005490 diff --git a/src/tests/data/gfast.props b/src/tests/data/gfast.props new file mode 100644 index 00000000..e73ffdcd --- /dev/null +++ b/src/tests/data/gfast.props @@ -0,0 +1,180 @@ +################################################################################ +# Global G-FAST properties # +################################################################################ +[general] +# File for log output +logFileName=data/gfast.log +# File with station names +metaDataFile=data/merged_chanfile_coord.dat +#metaDataNetworks=PW +#SA_events_dir=xxxxx +SA_output_dir=data +#output_interval_mins=1,2,3,4,5,10 +#siteMaskFile=xxxxx +# File with station names and sampling periods +#dtfile=GFAST_streams_dt.txt +# ElarmS message file +#eewsfile=ElarmS_messages.txt +# GFAST results file +eewgfile=GFAST_output.txt +# File of all the site locations. The format used is currently from +# the SOPAC SECTOR web service. +siteposfile=site_pos.csv +# Buffer length (s) +bufflen=320. +processing_time=302. +# GFAST operation mode +# 1 -> GFAST is running in `real time' and being data through Earthworm +# 2 -> GFAST is running historical playbacks through Earthworm +# 3 -> GFAST is running offline and is obtaining data purely from files +opmode = 1 +# minimum time for main loop (defaults to 1 second) +#waitTime=1.0 +# The synthetic mode driver file +#syndriver=nisqually_driver.txt +# The synthetic mode output file +#synoutput=nisqually_output.txt +# If working in specific area where the fault may straddle a UTM zone large +# distortions can arise. In this case it may be beneficial to set the UTM +# zone. Otherwise, if utm_zone is set to -12345 or not specified the UTM +# zone will be estimated from the event hpyocenter provided in the ElarmS +# message +utm_zone = 10 +# Mechanism for initializing sampling period +# 1 -> Sets GPS sampling period to default (dt_default) +# 2 -> Obtains the sampling period from the dtfile +# 3 -> Obtains the sampling period from Earthworm +dt_init = 3 +# Default GPS sampling period (s) +dt_default = 1.0 +# Location initialization strategy +# 1 -> Initialize locations from SOPAC SECTOR web service (siteposfile) +# 2 -> Initialize from trace buffer (if running in real-time this will +# happen automatically) +loc_init = 1 +# Controls verbosity: +# 0 -> Try to output nothing +# 1 -> Output errors only +# 2 -> Output errors and generic information (default) +# 3 -> Output errors, generic information, and debug information +verbose=3 + +synthetic_runtime = 0.0 +processing_time = 300.0 +default_event_depth = 8.0 + +h5ArchiveDirectory = data +H5SummaryOnly = 1 + +anssNetwork = UW +anssDomain = anss.org + +################################################################################ +# Earthworm Properties # +################################################################################ +[earthworm] + +gpsRingName = GPS_RING +moduleName = geojson2ew + +################################################################################ +# PGD Properties # +################################################################################ +[PGD] +# PGD source-receiver distance tolerance in km (cannot be negative) +dist_tolerance = 0.6 +# If PGD source-receiver distance tolerance falls below dist_tol this is the +# default PGD distance value given in km (must be positive) +dist_default = 0.01 +#some search variables +deltaLatitude = 0.1 +deltaLongitude = 0.1 +nlats_in_pgd_gridSearch = 1 +nlons_in_pgd_gridSearch = 1 +ndepths_in_pgd_gridSearch = 10 +# These are the defaults: +pgd_window_vel = 3.0 +pgd_min_sites = 4 + +# Message throttling logic and related +sigmaLookupFile = data/M99.txt + +# If defined, don't send xml if pgd_sigma is greater than this value +pgd_sigma_throttle = 0.5 +# Message throttling logic +SA_mag_threshold = -5.0 + +# Minimum and maximum thresholds for using pgd values in inversion, in cm +minimum_pgd_cm = 0.0 +maximum_pgd_cm = 3500.0 +max_assoc_stations = 6 + +################################################################################ +# CMT/Finite Fault Properties # +################################################################################ +[CMT] +#some search variables +deltaLatitude = 0.1 +deltaLongitude = 0.1 +nlats_in_cmt_gridSearch = 1 +nlons_in_cmt_gridSearch = 1 +ndepths_in_cmt_gridSearch = 10 +# These are the defaults: +cmt_window_vel = 2.0 +cmt_min_sites = 4 +# Error window average must be positive +cmt_window_avg = 0.0 +# Error general CMT inversions not yet programmed +ldeviatoric_cmt = 1 + +################################################################################ +# FF/Finite Fault Properties # +################################################################################ +[FF] +ff_number_of_faultplanes = 2 +# Number of fault patches along strike +ff_nstr = 10 +# Number of fault patches down dip +ff_ndip = 5 +# Min number of sites (must be greater than CMT) +ff_min_sites = 4 +# Error window velocity +ff_window_vel = 3.0 +# error window average time +ff_window_avg = 10.0 +ff_flen_pct = 10.0 +ff_fwid_pct = 10.0 + +################################################################################ +# ActiveMQ Properties # +################################################################################ +[ActiveMQ] +# ActiveMQ host:port +### amq_dm openwire 61616 +### amq_wp openwire 62616 +### amq_sa openwire 63616 +#URL for event trigger messages +originURL=tcp://eew-uw-dev1:63616 +#originURL=tcp://eew-uw-int1:63616 +# ActiveMQ topic to read event trigger messages from +originTopic=eew.agg.sa.data +#URL to publish event messages and heartbeats on +destinationURL=tcp://localhost:62616 +# ActiveMQ topic to publish events on. +destinationTopic = eew.alg.gfast.data +# ActiveMQ topic to publish heartbeats on +hbTopic=eew.alg.gfast.hb +# heartbeat interval +hbInterval=5 +# ActiveMQ username to access ElarmS messages +user=glarms +# ActiveMQ password to access ElarmS messages +password=abcdefg + +# connection settings +msReconnect = 500 +maxAttempts = 5 +msWaitForMessage = 0 + +maxMessages=5 + diff --git a/src/tests/data/merged_chanfile_coord.dat b/src/tests/data/merged_chanfile_coord.dat new file mode 100644 index 00000000..db4feae1 --- /dev/null +++ b/src/tests/data/merged_chanfile_coord.dat @@ -0,0 +1,3446 @@ +#generated by /home/gps/bin/merge_chan_coords.sh Fri Sep 9 14:07:56 PDT 2022 on arthur.geo.berkeley.edu +#columns: network station location channel latitude longitude elevation samplerate gain units sensortype +CI 7ODM 20 LYE 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 20 LYN 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 20 LYZ 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 20 LY1 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 20 LY2 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 20 LY3 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 20 LYQ 34.1164 -117.0932 761.9 1 1 - PPP +CI 7ODM 40 LYE 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 40 LYN 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 40 LYZ 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 40 LY1 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 40 LY2 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 40 LY3 34.1164 -117.0932 761.9 1 1e6 DU/M PPP +CI 7ODM 40 LYQ 34.1164 -117.0932 761.9 1 1 - PPP +CI ACSB 20 LYE 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSB 20 LYN 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSB 20 LYZ 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSB 20 LY1 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSB 20 LY2 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSB 20 LY3 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSB 20 LYQ 33.2743 -117.4449 -12.3 1 1 - PPP +CI ACSX 20 LYE 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSX 20 LYN 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSX 20 LYZ 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSX 20 LY1 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSX 20 LY2 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSX 20 LY3 33.2743 -117.4449 -12.3 1 1e6 DU/M PPP +CI ACSX 20 LYQ 33.2743 -117.4449 -12.3 1 1 - PPP +CI AGMT 20 LYE 34.5943 -116.4294 1337.8 1 1e6 DU/M PPP +CI AGMT 20 LYN 34.5943 -116.4294 1337.8 1 1e6 DU/M PPP +CI AGMT 20 LYZ 34.5943 -116.4294 1337.8 1 1e6 DU/M PPP +CI AGMT 20 LY1 34.5943 -116.4294 1337.8 1 1e6 DU/M PPP +CI AGMT 20 LY2 34.5943 -116.4294 1337.8 1 1e6 DU/M PPP +CI AGMT 20 LY3 34.5943 -116.4294 1337.8 1 1e6 DU/M PPP +CI AGMT 20 LYQ 34.5943 -116.4294 1337.8 1 1 - PPP +CI ALPP 20 LYE 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 20 LYN 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 20 LYZ 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 20 LY1 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 20 LY2 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 20 LY3 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 20 LYQ 34.8245 -118.6948 918.0 1 1 - PPP +CI ALPP 30 LYE 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 30 LYN 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 30 LYZ 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 30 LY1 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 30 LY2 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 30 LY3 34.8245 -118.6948 918.0 1 1e6 DU/M PPP +CI ALPP 30 LYQ 34.8245 -118.6948 918.0 1 1 - PPP +CI ANA1 20 LYE 34.0150 -119.3635 22.5 1 1e6 DU/M PPP +CI ANA1 20 LYN 34.0150 -119.3635 22.5 1 1e6 DU/M PPP +CI ANA1 20 LYZ 34.0150 -119.3635 22.5 1 1e6 DU/M PPP +CI ANA1 20 LY1 34.0150 -119.3635 22.5 1 1e6 DU/M PPP +CI ANA1 20 LY2 34.0150 -119.3635 22.5 1 1e6 DU/M PPP +CI ANA1 20 LY3 34.0150 -119.3635 22.5 1 1e6 DU/M PPP +CI ANA1 20 LYQ 34.0150 -119.3635 22.5 1 1 - PPP +CI AR27 20 LYE 33.3418 -117.3249 32.3 1 1e6 DU/M PPP +CI AR27 20 LYN 33.3418 -117.3249 32.3 1 1e6 DU/M PPP +CI AR27 20 LYZ 33.3418 -117.3249 32.3 1 1e6 DU/M PPP +CI AR27 20 LY1 33.3418 -117.3249 32.3 1 1e6 DU/M PPP +CI AR27 20 LY2 33.3418 -117.3249 32.3 1 1e6 DU/M PPP +CI AR27 20 LY3 33.3418 -117.3249 32.3 1 1e6 DU/M PPP +CI AR27 20 LYQ 33.3418 -117.3249 32.3 1 1 - PPP +CI AR53 20 LYE 33.3811 -117.4765 111.0 1 1e6 DU/M PPP +CI AR53 20 LYN 33.3811 -117.4765 111.0 1 1e6 DU/M PPP +CI AR53 20 LYZ 33.3811 -117.4765 111.0 1 1e6 DU/M PPP +CI AR53 20 LY1 33.3811 -117.4765 111.0 1 1e6 DU/M PPP +CI AR53 20 LY2 33.3811 -117.4765 111.0 1 1e6 DU/M PPP +CI AR53 20 LY3 33.3811 -117.4765 111.0 1 1e6 DU/M PPP +CI AR53 20 LYQ 33.3811 -117.4765 111.0 1 1 - PPP +CI ARM1 20 LYE 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 20 LYN 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 20 LYZ 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 20 LY1 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 20 LY2 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 20 LY3 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 20 LYQ 35.2013 -118.9104 76.4 1 1 - PPP +CI ARM1 30 LYE 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 30 LYN 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 30 LYZ 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 30 LY1 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 30 LY2 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 30 LY3 35.2013 -118.9104 76.4 1 1e6 DU/M PPP +CI ARM1 30 LYQ 35.2013 -118.9104 76.4 1 1 - PPP +CI ARM2 20 LYE 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 20 LYN 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 20 LYZ 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 20 LY1 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 20 LY2 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 20 LY3 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 20 LYQ 35.2013 -118.9106 76.3 1 1 - PPP +CI ARM2 30 LYE 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 30 LYN 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 30 LYZ 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 30 LY1 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 30 LY2 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 30 LY3 35.2013 -118.9106 76.3 1 1e6 DU/M PPP +CI ARM2 30 LYQ 35.2013 -118.9106 76.3 1 1 - PPP +CI AVRY 20 LYE 34.4683 -117.1540 888.9 1 1e6 DU/M PPP +CI AVRY 20 LYN 34.4683 -117.1540 888.9 1 1e6 DU/M PPP +CI AVRY 20 LYZ 34.4683 -117.1540 888.9 1 1e6 DU/M PPP +CI AVRY 20 LY1 34.4683 -117.1540 888.9 1 1e6 DU/M PPP +CI AVRY 20 LY2 34.4683 -117.1540 888.9 1 1e6 DU/M PPP +CI AVRY 20 LY3 34.4683 -117.1540 888.9 1 1e6 DU/M PPP +CI AVRY 20 LYQ 34.4683 -117.1540 888.9 1 1 - PPP +CI AZRY 20 LYE 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 20 LYN 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 20 LYZ 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 20 LY1 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 20 LY2 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 20 LY3 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 20 LYQ 33.5401 -116.6297 1265.7 1 1 - PPP +CI AZRY 40 LYE 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 40 LYN 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 40 LYZ 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 40 LY1 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 40 LY2 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 40 LY3 33.5401 -116.6297 1265.7 1 1e6 DU/M PPP +CI AZRY 40 LYQ 33.5401 -116.6297 1265.7 1 1 - PPP +CI AZU1 20 LYE 34.1260 -117.8965 144.7 1 1e6 DU/M PPP +CI AZU1 20 LYN 34.1260 -117.8965 144.7 1 1e6 DU/M PPP +CI AZU1 20 LYZ 34.1260 -117.8965 144.7 1 1e6 DU/M PPP +CI AZU1 20 LY1 34.1260 -117.8965 144.7 1 1e6 DU/M PPP +CI AZU1 20 LY2 34.1260 -117.8965 144.7 1 1e6 DU/M PPP +CI AZU1 20 LY3 34.1260 -117.8965 144.7 1 1e6 DU/M PPP +CI AZU1 20 LYQ 34.1260 -117.8965 144.7 1 1 - PPP +CI BAR1 20 LYE 33.4805 -119.0297 14.8 1 1e6 DU/M PPP +CI BAR1 20 LYN 33.4805 -119.0297 14.8 1 1e6 DU/M PPP +CI BAR1 20 LYZ 33.4805 -119.0297 14.8 1 1e6 DU/M PPP +CI BAR1 20 LY1 33.4805 -119.0297 14.8 1 1e6 DU/M PPP +CI BAR1 20 LY2 33.4805 -119.0297 14.8 1 1e6 DU/M PPP +CI BAR1 20 LY3 33.4805 -119.0297 14.8 1 1e6 DU/M PPP +CI BAR1 20 LYQ 33.4805 -119.0297 14.8 1 1 - PPP +CI BBDM 20 LYE 34.5822 -119.9815 204.9 1 1e6 DU/M PPP +CI BBDM 20 LYN 34.5822 -119.9815 204.9 1 1e6 DU/M PPP +CI BBDM 20 LYZ 34.5822 -119.9815 204.9 1 1e6 DU/M PPP +CI BBDM 20 LY1 34.5822 -119.9815 204.9 1 1e6 DU/M PPP +CI BBDM 20 LY2 34.5822 -119.9815 204.9 1 1e6 DU/M PPP +CI BBDM 20 LY3 34.5822 -119.9815 204.9 1 1e6 DU/M PPP +CI BBDM 20 LYQ 34.5822 -119.9815 204.9 1 1 - PPP +CI BBRY 20 LYE 34.2643 -116.8842 2051.0 1 1e6 DU/M PPP +CI BBRY 20 LYN 34.2643 -116.8842 2051.0 1 1e6 DU/M PPP +CI BBRY 20 LYZ 34.2643 -116.8842 2051.0 1 1e6 DU/M PPP +CI BBRY 20 LY1 34.2643 -116.8842 2051.0 1 1e6 DU/M PPP +CI BBRY 20 LY2 34.2643 -116.8842 2051.0 1 1e6 DU/M PPP +CI BBRY 20 LY3 34.2643 -116.8842 2051.0 1 1e6 DU/M PPP +CI BBRY 20 LYQ 34.2643 -116.8842 2051.0 1 1 - PPP +CI BCWR 20 LYE 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 20 LYN 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 20 LYZ 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 20 LY1 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 20 LY2 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 20 LY3 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 20 LYQ 34.9205 -119.4059 1332.9 1 1 - PPP +CI BCWR 40 LYE 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 40 LYN 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 40 LYZ 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 40 LY1 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 40 LY2 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 40 LY3 34.9205 -119.4059 1332.9 1 1e6 DU/M PPP +CI BCWR 40 LYQ 34.9205 -119.4059 1332.9 1 1 - PPP +CI BEMT 20 LYE 34.0005 -115.9982 1373.6 1 1e6 DU/M PPP +CI BEMT 20 LYN 34.0005 -115.9982 1373.6 1 1e6 DU/M PPP +CI BEMT 20 LYZ 34.0005 -115.9982 1373.6 1 1e6 DU/M PPP +CI BEMT 20 LY1 34.0005 -115.9982 1373.6 1 1e6 DU/M PPP +CI BEMT 20 LY2 34.0005 -115.9982 1373.6 1 1e6 DU/M PPP +CI BEMT 20 LY3 34.0005 -115.9982 1373.6 1 1e6 DU/M PPP +CI BEMT 20 LYQ 34.0005 -115.9982 1373.6 1 1 - PPP +CI BGIS 20 LYE 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 20 LYN 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 20 LYZ 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 20 LY1 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 20 LY2 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 20 LY3 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 20 LYQ 33.9671 -118.1597 2.7 1 1 - PPP +CI BGIS 30 LYE 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 30 LYN 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 30 LYZ 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 30 LY1 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 30 LY2 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 30 LY3 33.9671 -118.1597 2.7 1 1e6 DU/M PPP +CI BGIS 30 LYQ 33.9671 -118.1597 2.7 1 1 - PPP +CI BILL 20 LYE 33.5782 -117.0646 470.0 1 1e6 DU/M PPP +CI BILL 20 LYN 33.5782 -117.0646 470.0 1 1e6 DU/M PPP +CI BILL 20 LYZ 33.5782 -117.0646 470.0 1 1e6 DU/M PPP +CI BILL 20 LY1 33.5782 -117.0646 470.0 1 1e6 DU/M PPP +CI BILL 20 LY2 33.5782 -117.0646 470.0 1 1e6 DU/M PPP +CI BILL 20 LY3 33.5782 -117.0646 470.0 1 1e6 DU/M PPP +CI BILL 20 LYQ 33.5782 -117.0646 470.0 1 1 - PPP +CI BKMS 20 LYE 33.9623 -118.0947 11.0 1 1e6 DU/M PPP +CI BKMS 20 LYN 33.9623 -118.0947 11.0 1 1e6 DU/M PPP +CI BKMS 20 LYZ 33.9623 -118.0947 11.0 1 1e6 DU/M PPP +CI BKMS 20 LY1 33.9623 -118.0947 11.0 1 1e6 DU/M PPP +CI BKMS 20 LY2 33.9623 -118.0947 11.0 1 1e6 DU/M PPP +CI BKMS 20 LY3 33.9623 -118.0947 11.0 1 1e6 DU/M PPP +CI BKMS 20 LYQ 33.9623 -118.0947 11.0 1 1 - PPP +CI BLSA 20 LYE 33.7995 -118.0287 -23.2 1 1e6 DU/M PPP +CI BLSA 20 LYN 33.7995 -118.0287 -23.2 1 1e6 DU/M PPP +CI BLSA 20 LYZ 33.7995 -118.0287 -23.2 1 1e6 DU/M PPP +CI BLSA 20 LY1 33.7995 -118.0287 -23.2 1 1e6 DU/M PPP +CI BLSA 20 LY2 33.7995 -118.0287 -23.2 1 1e6 DU/M PPP +CI BLSA 20 LY3 33.7995 -118.0287 -23.2 1 1e6 DU/M PPP +CI BLSA 20 LYQ 33.7995 -118.0287 -23.2 1 1 - PPP +CI BLYT 20 LYE 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 20 LYN 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 20 LYZ 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 20 LY1 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 20 LY2 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 20 LY3 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 20 LYQ 33.6104 -114.7149 85.9 1 1 - PPP +CI BLYT 30 LYE 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 30 LYN 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 30 LYZ 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 30 LY1 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 30 LY2 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 30 LY3 33.6104 -114.7149 85.9 1 1e6 DU/M PPP +CI BLYT 30 LYQ 33.6104 -114.7149 85.9 1 1 - PPP +CI BMHL 20 LYE 34.2514 -116.0530 722.6 1 1e6 DU/M PPP +CI BMHL 20 LYN 34.2514 -116.0530 722.6 1 1e6 DU/M PPP +CI BMHL 20 LYZ 34.2514 -116.0530 722.6 1 1e6 DU/M PPP +CI BMHL 20 LY1 34.2514 -116.0530 722.6 1 1e6 DU/M PPP +CI BMHL 20 LY2 34.2514 -116.0530 722.6 1 1e6 DU/M PPP +CI BMHL 20 LY3 34.2514 -116.0530 722.6 1 1e6 DU/M PPP +CI BMHL 20 LYQ 34.2514 -116.0530 722.6 1 1 - PPP +CI BOMG 20 LYE 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 20 LYN 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 20 LYZ 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 20 LY1 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 20 LY2 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 20 LY3 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 20 LYQ 33.3646 -115.7297 -84.2 1 1 - PPP +CI BOMG 40 LYE 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 40 LYN 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 40 LYZ 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 40 LY1 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 40 LY2 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 40 LY3 33.3646 -115.7297 -84.2 1 1e6 DU/M PPP +CI BOMG 40 LYQ 33.3646 -115.7297 -84.2 1 1 - PPP +CI BRAN 20 LYE 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 20 LYN 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 20 LYZ 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 20 LY1 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 20 LY2 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 20 LY3 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 20 LYQ 34.1849 -118.2771 246.2 1 1 - PPP +CI BRAN 30 LYE 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 30 LYN 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 30 LYZ 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 30 LY1 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 30 LY2 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 30 LY3 34.1849 -118.2771 246.2 1 1e6 DU/M PPP +CI BRAN 30 LYQ 34.1849 -118.2771 246.2 1 1 - PPP +BK BRI2 30 LYN 37.9195 -122.1525 265.1 1 1e6 DU/M PPP +BK BRI2 30 LYE 37.9195 -122.1525 265.1 1 1e6 DU/M PPP +BK BRI2 30 LYZ 37.9195 -122.1525 265.1 1 1e6 DU/M PPP +BK BRI2 30 LYQ 37.9195 -122.1525 265.1 1 1 - PPP +BK BRI2 30 LY1 37.9195 -122.1525 265.1 1 1e6 DU/M PPP +BK BRI2 30 LY2 37.9195 -122.1525 265.1 1 1e6 DU/M PPP +BK BRI2 30 LY3 37.9195 -122.1525 265.1 1 1e6 DU/M PPP +CI BSRY 20 LYE 34.9186 -117.0120 613.5 1 1e6 DU/M PPP +CI BSRY 20 LYN 34.9186 -117.0120 613.5 1 1e6 DU/M PPP +CI BSRY 20 LYZ 34.9186 -117.0120 613.5 1 1e6 DU/M PPP +CI BSRY 20 LY1 34.9186 -117.0120 613.5 1 1e6 DU/M PPP +CI BSRY 20 LY2 34.9186 -117.0120 613.5 1 1e6 DU/M PPP +CI BSRY 20 LY3 34.9186 -117.0120 613.5 1 1e6 DU/M PPP +CI BSRY 20 LYQ 34.9186 -117.0120 613.5 1 1 - PPP +CI BUEG 20 LYE 34.6129 -120.1964 74.7 1 1e6 DU/M PPP +CI BUEG 20 LYN 34.6129 -120.1964 74.7 1 1e6 DU/M PPP +CI BUEG 20 LYZ 34.6129 -120.1964 74.7 1 1e6 DU/M PPP +CI BUEG 20 LY1 34.6129 -120.1964 74.7 1 1e6 DU/M PPP +CI BUEG 20 LY2 34.6129 -120.1964 74.7 1 1e6 DU/M PPP +CI BUEG 20 LY3 34.6129 -120.1964 74.7 1 1e6 DU/M PPP +CI BUEG 20 LYQ 34.6129 -120.1964 74.7 1 1 - PPP +CI CACT 20 LYE 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 20 LYN 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 20 LYZ 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 20 LY1 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 20 LY2 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 20 LY3 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 20 LYQ 33.6551 -115.9900 518.4 1 1 - PPP +CI CACT 40 LYE 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 40 LYN 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 40 LYZ 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 40 LY1 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 40 LY2 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 40 LY3 33.6551 -115.9900 518.4 1 1e6 DU/M PPP +CI CACT 40 LYQ 33.6551 -115.9900 518.4 1 1 - PPP +CI CASE 20 LYE 33.4554 -117.4040 776.5 1 1e6 DU/M PPP +CI CASE 20 LYN 33.4554 -117.4040 776.5 1 1e6 DU/M PPP +CI CASE 20 LYZ 33.4554 -117.4040 776.5 1 1e6 DU/M PPP +CI CASE 20 LY1 33.4554 -117.4040 776.5 1 1e6 DU/M PPP +CI CASE 20 LY2 33.4554 -117.4040 776.5 1 1e6 DU/M PPP +CI CASE 20 LY3 33.4554 -117.4040 776.5 1 1e6 DU/M PPP +CI CASE 20 LYQ 33.4554 -117.4040 776.5 1 1 - PPP +CI CAT2 20 LYE 33.3116 -118.3338 477.2 1 1e6 DU/M PPP +CI CAT2 20 LYN 33.3116 -118.3338 477.2 1 1e6 DU/M PPP +CI CAT2 20 LYZ 33.3116 -118.3338 477.2 1 1e6 DU/M PPP +CI CAT2 20 LY1 33.3116 -118.3338 477.2 1 1e6 DU/M PPP +CI CAT2 20 LY2 33.3116 -118.3338 477.2 1 1e6 DU/M PPP +CI CAT2 20 LY3 33.3116 -118.3338 477.2 1 1e6 DU/M PPP +CI CAT2 20 LYQ 33.3116 -118.3338 477.2 1 1 - PPP +CI CAT3 20 LYE 33.4458 -118.4830 5.1 1 1e6 DU/M PPP +CI CAT3 20 LYN 33.4458 -118.4830 5.1 1 1e6 DU/M PPP +CI CAT3 20 LYZ 33.4458 -118.4830 5.1 1 1e6 DU/M PPP +CI CAT3 20 LY1 33.4458 -118.4830 5.1 1 1e6 DU/M PPP +CI CAT3 20 LY2 33.4458 -118.4830 5.1 1 1e6 DU/M PPP +CI CAT3 20 LY3 33.4458 -118.4830 5.1 1 1e6 DU/M PPP +CI CAT3 20 LYQ 33.4458 -118.4830 5.1 1 1 - PPP +CI CBHS 20 LYE 34.1386 -118.6298 284.6 1 1e6 DU/M PPP +CI CBHS 20 LYN 34.1386 -118.6298 284.6 1 1e6 DU/M PPP +CI CBHS 20 LYZ 34.1386 -118.6298 284.6 1 1e6 DU/M PPP +CI CBHS 20 LY1 34.1386 -118.6298 284.6 1 1e6 DU/M PPP +CI CBHS 20 LY2 34.1386 -118.6298 284.6 1 1e6 DU/M PPP +CI CBHS 20 LY3 34.1386 -118.6298 284.6 1 1e6 DU/M PPP +CI CBHS 20 LYQ 34.1386 -118.6298 284.6 1 1 - PPP +CI CCCS 20 LYE 33.8627 -117.8649 31.8 1 1e6 DU/M PPP +CI CCCS 20 LYN 33.8627 -117.8649 31.8 1 1e6 DU/M PPP +CI CCCS 20 LYZ 33.8627 -117.8649 31.8 1 1e6 DU/M PPP +CI CCCS 20 LY1 33.8627 -117.8649 31.8 1 1e6 DU/M PPP +CI CCCS 20 LY2 33.8627 -117.8649 31.8 1 1e6 DU/M PPP +CI CCCS 20 LY3 33.8627 -117.8649 31.8 1 1e6 DU/M PPP +CI CCCS 20 LYQ 33.8627 -117.8649 31.8 1 1 - PPP +CI CDMT 20 LYE 34.8295 -116.3359 936.5 1 1e6 DU/M PPP +CI CDMT 20 LYN 34.8295 -116.3359 936.5 1 1e6 DU/M PPP +CI CDMT 20 LYZ 34.8295 -116.3359 936.5 1 1e6 DU/M PPP +CI CDMT 20 LY1 34.8295 -116.3359 936.5 1 1e6 DU/M PPP +CI CDMT 20 LY2 34.8295 -116.3359 936.5 1 1e6 DU/M PPP +CI CDMT 20 LY3 34.8295 -116.3359 936.5 1 1e6 DU/M PPP +CI CDMT 20 LYQ 34.8295 -116.3359 936.5 1 1 - PPP +CI CGDM 20 LYE 34.2440 -117.9650 704.7 1 1e6 DU/M PPP +CI CGDM 20 LYN 34.2440 -117.9650 704.7 1 1e6 DU/M PPP +CI CGDM 20 LYZ 34.2440 -117.9650 704.7 1 1e6 DU/M PPP +CI CGDM 20 LY1 34.2440 -117.9650 704.7 1 1e6 DU/M PPP +CI CGDM 20 LY2 34.2440 -117.9650 704.7 1 1e6 DU/M PPP +CI CGDM 20 LY3 34.2440 -117.9650 704.7 1 1e6 DU/M PPP +CI CGDM 20 LYQ 34.2440 -117.9650 704.7 1 1 - PPP +CI CHIL 20 LYE 34.3334 -118.0260 1567.4 1 1e6 DU/M PPP +CI CHIL 20 LYN 34.3334 -118.0260 1567.4 1 1e6 DU/M PPP +CI CHIL 20 LYZ 34.3334 -118.0260 1567.4 1 1e6 DU/M PPP +CI CHIL 20 LY1 34.3334 -118.0260 1567.4 1 1e6 DU/M PPP +CI CHIL 20 LY2 34.3334 -118.0260 1567.4 1 1e6 DU/M PPP +CI CHIL 20 LY3 34.3334 -118.0260 1567.4 1 1e6 DU/M PPP +CI CHIL 20 LYQ 34.3334 -118.0260 1567.4 1 1 - PPP +CI CHMS 20 LYE 34.6405 -117.8277 760.4 1 1e6 DU/M PPP +CI CHMS 20 LYN 34.6405 -117.8277 760.4 1 1e6 DU/M PPP +CI CHMS 20 LYZ 34.6405 -117.8277 760.4 1 1e6 DU/M PPP +CI CHMS 20 LY1 34.6405 -117.8277 760.4 1 1e6 DU/M PPP +CI CHMS 20 LY2 34.6405 -117.8277 760.4 1 1e6 DU/M PPP +CI CHMS 20 LY3 34.6405 -117.8277 760.4 1 1e6 DU/M PPP +CI CHMS 20 LYQ 34.6405 -117.8277 760.4 1 1 - PPP +CI CIRX 20 LYE 34.1096 -118.9373 488.2 1 1e6 DU/M PPP +CI CIRX 20 LYN 34.1096 -118.9373 488.2 1 1e6 DU/M PPP +CI CIRX 20 LYZ 34.1096 -118.9373 488.2 1 1e6 DU/M PPP +CI CIRX 20 LY1 34.1096 -118.9373 488.2 1 1e6 DU/M PPP +CI CIRX 20 LY2 34.1096 -118.9373 488.2 1 1e6 DU/M PPP +CI CIRX 20 LY3 34.1096 -118.9373 488.2 1 1e6 DU/M PPP +CI CIRX 20 LYQ 34.1096 -118.9373 488.2 1 1 - PPP +CI CIT1 20 LYE 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 20 LYN 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 20 LYZ 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 20 LY1 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 20 LY2 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 20 LY3 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 20 LYQ 34.1367 -118.1273 215.3 1 1 - PPP +CI CIT1 40 LYE 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 40 LYN 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 40 LYZ 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 40 LY1 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 40 LY2 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 40 LY3 34.1367 -118.1273 215.3 1 1e6 DU/M PPP +CI CIT1 40 LYQ 34.1367 -118.1273 215.3 1 1 - PPP +CI CJMG 20 LYE 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 20 LYN 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 20 LYZ 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 20 LY1 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 20 LY2 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 20 LY3 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 20 LYQ 34.2712 -117.4245 1584.4 1 1 - PPP +CI CJMG 40 LYE 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 40 LYN 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 40 LYZ 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 40 LY1 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 40 LY2 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 40 LY3 34.2712 -117.4245 1584.4 1 1e6 DU/M PPP +CI CJMG 40 LYQ 34.2712 -117.4245 1584.4 1 1 - PPP +CI CJMS 20 LYE 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 20 LYN 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 20 LYZ 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 20 LY1 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 20 LY2 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 20 LY3 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 20 LYQ 34.3138 -117.4794 933.3 1 1 - PPP +CI CJMS 40 LYE 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 40 LYN 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 40 LYZ 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 40 LY1 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 40 LY2 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 40 LY3 34.3138 -117.4794 933.3 1 1e6 DU/M PPP +CI CJMS 40 LYQ 34.3138 -117.4794 933.3 1 1 - PPP +CI CJVG 20 LYE 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 20 LYN 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 20 LYZ 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 20 LY1 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 20 LY2 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 20 LY3 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 20 LYQ 34.5303 -118.1442 1304.8 1 1 - PPP +CI CJVG 40 LYE 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 40 LYN 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 40 LYZ 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 40 LY1 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 40 LY2 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 40 LY3 34.5303 -118.1442 1304.8 1 1e6 DU/M PPP +CI CJVG 40 LYQ 34.5303 -118.1442 1304.8 1 1 - PPP +CI CLAR 20 LYE 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 20 LYN 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 20 LYZ 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 20 LY1 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 20 LY2 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 20 LY3 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 20 LYQ 34.1099 -117.7088 373.6 1 1 - PPP +CI CLAR 30 LYE 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 30 LYN 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 30 LYZ 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 30 LY1 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 30 LY2 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 30 LY3 34.1099 -117.7088 373.6 1 1e6 DU/M PPP +CI CLAR 30 LYQ 34.1099 -117.7088 373.6 1 1 - PPP +CI CLBD 20 LYE 33.1354 -117.3110 20.5 1 1e6 DU/M PPP +CI CLBD 20 LYN 33.1354 -117.3110 20.5 1 1e6 DU/M PPP +CI CLBD 20 LYZ 33.1354 -117.3110 20.5 1 1e6 DU/M PPP +CI CLBD 20 LY1 33.1354 -117.3110 20.5 1 1e6 DU/M PPP +CI CLBD 20 LY2 33.1354 -117.3110 20.5 1 1e6 DU/M PPP +CI CLBD 20 LY3 33.1354 -117.3110 20.5 1 1e6 DU/M PPP +CI CLBD 20 LYQ 33.1354 -117.3110 20.5 1 1 - PPP +BK CMBB 30 LYN 38.0342 -120.3860 695.7 1 1e6 DU/M PPP +BK CMBB 30 LYE 38.0342 -120.3860 695.7 1 1e6 DU/M PPP +BK CMBB 30 LYZ 38.0342 -120.3860 695.7 1 1e6 DU/M PPP +BK CMBB 30 LYQ 38.0342 -120.3860 695.7 1 1 - PPP +BK CMBB 30 LY1 38.0342 -120.3860 695.7 1 1e6 DU/M PPP +BK CMBB 30 LY2 38.0342 -120.3860 695.7 1 1e6 DU/M PPP +BK CMBB 30 LY3 38.0342 -120.3860 695.7 1 1e6 DU/M PPP +CI CMP9 20 LYE 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 20 LYN 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 20 LYZ 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 20 LY1 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 20 LY2 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 20 LY3 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 20 LYQ 34.3532 -118.4114 1137.9 1 1 - PPP +CI CMP9 30 LYE 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 30 LYN 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 30 LYZ 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 30 LY1 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 30 LY2 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 30 LY3 34.3532 -118.4114 1137.9 1 1e6 DU/M PPP +CI CMP9 30 LYQ 34.3532 -118.4114 1137.9 1 1 - PPP +CI CNPP 20 LYE 33.8576 -117.6089 300.2 1 1e6 DU/M PPP +CI CNPP 20 LYN 33.8576 -117.6089 300.2 1 1e6 DU/M PPP +CI CNPP 20 LYZ 33.8576 -117.6089 300.2 1 1e6 DU/M PPP +CI CNPP 20 LY1 33.8576 -117.6089 300.2 1 1e6 DU/M PPP +CI CNPP 20 LY2 33.8576 -117.6089 300.2 1 1e6 DU/M PPP +CI CNPP 20 LY3 33.8576 -117.6089 300.2 1 1e6 DU/M PPP +CI CNPP 20 LYQ 33.8576 -117.6089 300.2 1 1 - PPP +CI COAG 20 LYE 32.8635 -115.1233 3.7 1 1e6 DU/M PPP +CI COAG 20 LYN 32.8635 -115.1233 3.7 1 1e6 DU/M PPP +CI COAG 20 LYZ 32.8635 -115.1233 3.7 1 1e6 DU/M PPP +CI COAG 20 LY1 32.8635 -115.1233 3.7 1 1e6 DU/M PPP +CI COAG 20 LY2 32.8635 -115.1233 3.7 1 1e6 DU/M PPP +CI COAG 20 LY3 32.8635 -115.1233 3.7 1 1e6 DU/M PPP +CI COAG 20 LYQ 32.8635 -115.1233 3.7 1 1 - PPP +CI COKG 20 LYE 32.8505 -115.7285 -47.0 1 1e6 DU/M PPP +CI COKG 20 LYN 32.8505 -115.7285 -47.0 1 1e6 DU/M PPP +CI COKG 20 LYZ 32.8505 -115.7285 -47.0 1 1e6 DU/M PPP +CI COKG 20 LY1 32.8505 -115.7285 -47.0 1 1e6 DU/M PPP +CI COKG 20 LY2 32.8505 -115.7285 -47.0 1 1e6 DU/M PPP +CI COKG 20 LY3 32.8505 -115.7285 -47.0 1 1e6 DU/M PPP +CI COKG 20 LYQ 32.8505 -115.7285 -47.0 1 1 - PPP +CI COPR 20 LYE 34.4149 -119.8795 -22.9 1 1e6 DU/M PPP +CI COPR 20 LYN 34.4149 -119.8795 -22.9 1 1e6 DU/M PPP +CI COPR 20 LYZ 34.4149 -119.8795 -22.9 1 1e6 DU/M PPP +CI COPR 20 LY1 34.4149 -119.8795 -22.9 1 1e6 DU/M PPP +CI COPR 20 LY2 34.4149 -119.8795 -22.9 1 1e6 DU/M PPP +CI COPR 20 LY3 34.4149 -119.8795 -22.9 1 1e6 DU/M PPP +CI COPR 20 LYQ 34.4149 -119.8795 -22.9 1 1 - PPP +CI COSO 20 LYE 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 20 LYN 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 20 LYZ 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 20 LY1 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 20 LY2 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 20 LY3 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 20 LYQ 35.9823 -117.8089 1455.1 1 1 - PPP +CI COSO 30 LYE 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 30 LYN 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 30 LYZ 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 30 LY1 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 30 LY2 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 30 LY3 35.9823 -117.8089 1455.1 1 1e6 DU/M PPP +CI COSO 30 LYQ 35.9823 -117.8089 1455.1 1 1 - PPP +CI COTD 20 LYE 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 20 LYN 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 20 LYZ 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 20 LY1 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 20 LY2 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 20 LY3 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 20 LYQ 33.7325 -116.3869 27.6 1 1 - PPP +CI COTD 40 LYE 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 40 LYN 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 40 LYZ 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 40 LY1 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 40 LY2 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 40 LY3 33.7325 -116.3869 27.6 1 1e6 DU/M PPP +CI COTD 40 LYQ 33.7325 -116.3869 27.6 1 1 - PPP +CI CPBN 20 LYE 35.0717 -117.5730 835.8 1 1e6 DU/M PPP +CI CPBN 20 LYN 35.0717 -117.5730 835.8 1 1e6 DU/M PPP +CI CPBN 20 LYZ 35.0717 -117.5730 835.8 1 1e6 DU/M PPP +CI CPBN 20 LY1 35.0717 -117.5730 835.8 1 1e6 DU/M PPP +CI CPBN 20 LY2 35.0717 -117.5730 835.8 1 1e6 DU/M PPP +CI CPBN 20 LY3 35.0717 -117.5730 835.8 1 1e6 DU/M PPP +CI CPBN 20 LYQ 35.0717 -117.5730 835.8 1 1 - PPP +CI CRFP 20 LYE 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 20 LYN 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 20 LYZ 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 20 LY1 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 20 LY2 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 20 LY3 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 20 LYQ 34.0391 -117.0997 688.8 1 1 - PPP +CI CRFP 40 LYE 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 40 LYN 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 40 LYZ 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 40 LY1 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 40 LY2 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 40 LY3 34.0391 -117.0997 688.8 1 1e6 DU/M PPP +CI CRFP 40 LYQ 34.0391 -117.0997 688.8 1 1 - PPP +CI CRGG 20 LYE 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 20 LYN 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 20 LYZ 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 20 LY1 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 20 LY2 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 20 LY3 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 20 LYQ 35.2421 -119.7248 1173.1 1 1 - PPP +CI CRGG 40 LYE 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 40 LYN 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 40 LYZ 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 40 LY1 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 40 LY2 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 40 LY3 35.2421 -119.7248 1173.1 1 1e6 DU/M PPP +CI CRGG 40 LYQ 35.2421 -119.7248 1173.1 1 1 - PPP +CI CRRS 20 LYE 33.0698 -115.7350 -81.9 1 1e6 DU/M PPP +CI CRRS 20 LYN 33.0698 -115.7350 -81.9 1 1e6 DU/M PPP +CI CRRS 20 LYZ 33.0698 -115.7350 -81.9 1 1e6 DU/M PPP +CI CRRS 20 LY1 33.0698 -115.7350 -81.9 1 1e6 DU/M PPP +CI CRRS 20 LY2 33.0698 -115.7350 -81.9 1 1e6 DU/M PPP +CI CRRS 20 LY3 33.0698 -115.7350 -81.9 1 1e6 DU/M PPP +CI CRRS 20 LYQ 33.0698 -115.7350 -81.9 1 1 - PPP +CI CRU1 20 LYE 34.0293 -119.7848 702.1 1 1e6 DU/M PPP +CI CRU1 20 LYN 34.0293 -119.7848 702.1 1 1e6 DU/M PPP +CI CRU1 20 LYZ 34.0293 -119.7848 702.1 1 1e6 DU/M PPP +CI CRU1 20 LY1 34.0293 -119.7848 702.1 1 1e6 DU/M PPP +CI CRU1 20 LY2 34.0293 -119.7848 702.1 1 1e6 DU/M PPP +CI CRU1 20 LY3 34.0293 -119.7848 702.1 1 1e6 DU/M PPP +CI CRU1 20 LYQ 34.0293 -119.7848 702.1 1 1 - PPP +CI CSCI 20 LYE 34.1684 -119.0390 70.8 1 1e6 DU/M PPP +CI CSCI 20 LYN 34.1684 -119.0390 70.8 1 1e6 DU/M PPP +CI CSCI 20 LYZ 34.1684 -119.0390 70.8 1 1e6 DU/M PPP +CI CSCI 20 LY1 34.1684 -119.0390 70.8 1 1e6 DU/M PPP +CI CSCI 20 LY2 34.1684 -119.0390 70.8 1 1e6 DU/M PPP +CI CSCI 20 LY3 34.1684 -119.0390 70.8 1 1e6 DU/M PPP +CI CSCI 20 LYQ 34.1684 -119.0390 70.8 1 1 - PPP +CI CSDH 20 LYE 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 20 LYN 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 20 LYZ 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 20 LY1 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 20 LY2 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 20 LY3 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 20 LYQ 33.8615 -118.2567 -9.2 1 1 - PPP +CI CSDH 30 LYE 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 30 LYN 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 30 LYZ 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 30 LY1 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 30 LY2 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 30 LY3 33.8615 -118.2567 -9.2 1 1e6 DU/M PPP +CI CSDH 30 LYQ 33.8615 -118.2567 -9.2 1 1 - PPP +CI CSN1 20 LYE 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 20 LYN 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 20 LYZ 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 20 LY1 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 20 LY2 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 20 LY3 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 20 LYQ 34.2536 -118.5238 261.4 1 1 - PPP +CI CSN1 30 LYE 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 30 LYN 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 30 LYZ 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 30 LY1 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 30 LY2 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 30 LY3 34.2536 -118.5238 261.4 1 1e6 DU/M PPP +CI CSN1 30 LYQ 34.2536 -118.5238 261.4 1 1 - PPP +CI CSST 20 LYE 34.4081 -119.3713 162.5 1 1e6 DU/M PPP +CI CSST 20 LYN 34.4081 -119.3713 162.5 1 1e6 DU/M PPP +CI CSST 20 LYZ 34.4081 -119.3713 162.5 1 1e6 DU/M PPP +CI CSST 20 LY1 34.4081 -119.3713 162.5 1 1e6 DU/M PPP +CI CSST 20 LY2 34.4081 -119.3713 162.5 1 1e6 DU/M PPP +CI CSST 20 LY3 34.4081 -119.3713 162.5 1 1e6 DU/M PPP +CI CSST 20 LYQ 34.4081 -119.3713 162.5 1 1 - PPP +CI CTDM 20 LYE 34.5166 -118.6132 406.0 1 1e6 DU/M PPP +CI CTDM 20 LYN 34.5166 -118.6132 406.0 1 1e6 DU/M PPP +CI CTDM 20 LYZ 34.5166 -118.6132 406.0 1 1e6 DU/M PPP +CI CTDM 20 LY1 34.5166 -118.6132 406.0 1 1e6 DU/M PPP +CI CTDM 20 LY2 34.5166 -118.6132 406.0 1 1e6 DU/M PPP +CI CTDM 20 LY3 34.5166 -118.6132 406.0 1 1e6 DU/M PPP +CI CTDM 20 LYQ 34.5166 -118.6132 406.0 1 1 - PPP +CI CTMS 20 LYE 34.1241 -116.3704 966.4 1 1e6 DU/M PPP +CI CTMS 20 LYN 34.1241 -116.3704 966.4 1 1e6 DU/M PPP +CI CTMS 20 LYZ 34.1241 -116.3704 966.4 1 1e6 DU/M PPP +CI CTMS 20 LY1 34.1241 -116.3704 966.4 1 1e6 DU/M PPP +CI CTMS 20 LY2 34.1241 -116.3704 966.4 1 1e6 DU/M PPP +CI CTMS 20 LY3 34.1241 -116.3704 966.4 1 1e6 DU/M PPP +CI CTMS 20 LYQ 34.1241 -116.3704 966.4 1 1 - PPP +CI CUHS 20 LYE 34.9426 -119.6740 634.9 1 1e6 DU/M PPP +CI CUHS 20 LYN 34.9426 -119.6740 634.9 1 1e6 DU/M PPP +CI CUHS 20 LYZ 34.9426 -119.6740 634.9 1 1e6 DU/M PPP +CI CUHS 20 LY1 34.9426 -119.6740 634.9 1 1e6 DU/M PPP +CI CUHS 20 LY2 34.9426 -119.6740 634.9 1 1e6 DU/M PPP +CI CUHS 20 LY3 34.9426 -119.6740 634.9 1 1e6 DU/M PPP +CI CUHS 20 LYQ 34.9426 -119.6740 634.9 1 1 - PPP +CI CVHS 20 LYE 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 20 LYN 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 20 LYZ 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 20 LY1 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 20 LY2 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 20 LY3 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 20 LYQ 34.0820 -117.9017 119.0 1 1 - PPP +CI CVHS 30 LYE 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 30 LYN 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 30 LYZ 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 30 LY1 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 30 LY2 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 30 LY3 34.0820 -117.9017 119.0 1 1e6 DU/M PPP +CI CVHS 30 LYQ 34.0820 -117.9017 119.0 1 1 - PPP +CI DAM2 20 LYE 34.3348 -118.3969 583.4 1 1e6 DU/M PPP +CI DAM2 20 LYN 34.3348 -118.3969 583.4 1 1e6 DU/M PPP +CI DAM2 20 LYZ 34.3348 -118.3969 583.4 1 1e6 DU/M PPP +CI DAM2 20 LY1 34.3348 -118.3969 583.4 1 1e6 DU/M PPP +CI DAM2 20 LY2 34.3348 -118.3969 583.4 1 1e6 DU/M PPP +CI DAM2 20 LY3 34.3348 -118.3969 583.4 1 1e6 DU/M PPP +CI DAM2 20 LYQ 34.3348 -118.3969 583.4 1 1 - PPP +CI DAM3 20 LYE 34.3340 -118.3975 580.1 1 1e6 DU/M PPP +CI DAM3 20 LYN 34.3340 -118.3975 580.1 1 1e6 DU/M PPP +CI DAM3 20 LYZ 34.3340 -118.3975 580.1 1 1e6 DU/M PPP +CI DAM3 20 LY1 34.3340 -118.3975 580.1 1 1e6 DU/M PPP +CI DAM3 20 LY2 34.3340 -118.3975 580.1 1 1e6 DU/M PPP +CI DAM3 20 LY3 34.3340 -118.3975 580.1 1 1e6 DU/M PPP +CI DAM3 20 LYQ 34.3340 -118.3975 580.1 1 1 - PPP +CI DESC 20 LYE 32.8299 -116.6418 957.3 1 1e6 DU/M PPP +CI DESC 20 LYN 32.8299 -116.6418 957.3 1 1e6 DU/M PPP +CI DESC 20 LYZ 32.8299 -116.6418 957.3 1 1e6 DU/M PPP +CI DESC 20 LY1 32.8299 -116.6418 957.3 1 1e6 DU/M PPP +CI DESC 20 LY2 32.8299 -116.6418 957.3 1 1e6 DU/M PPP +CI DESC 20 LY3 32.8299 -116.6418 957.3 1 1e6 DU/M PPP +CI DESC 20 LYQ 32.8299 -116.6418 957.3 1 1 - PPP +CI DHLG 20 LYE 33.3898 -115.7880 -83.1 1 1e6 DU/M PPP +CI DHLG 20 LYN 33.3898 -115.7880 -83.1 1 1e6 DU/M PPP +CI DHLG 20 LYZ 33.3898 -115.7880 -83.1 1 1e6 DU/M PPP +CI DHLG 20 LY1 33.3898 -115.7880 -83.1 1 1e6 DU/M PPP +CI DHLG 20 LY2 33.3898 -115.7880 -83.1 1 1e6 DU/M PPP +CI DHLG 20 LY3 33.3898 -115.7880 -83.1 1 1e6 DU/M PPP +CI DHLG 20 LYQ 33.3898 -115.7880 -83.1 1 1 - PPP +BK DIAB 30 LYN 37.8786 -121.9156 990.3 1 1e6 DU/M PPP +BK DIAB 30 LYE 37.8786 -121.9156 990.3 1 1e6 DU/M PPP +BK DIAB 30 LYZ 37.8786 -121.9156 990.3 1 1e6 DU/M PPP +BK DIAB 30 LYQ 37.8786 -121.9156 990.3 1 1 - PPP +BK DIAB 30 LY1 37.8786 -121.9156 990.3 1 1e6 DU/M PPP +BK DIAB 30 LY2 37.8786 -121.9156 990.3 1 1e6 DU/M PPP +BK DIAB 30 LY3 37.8786 -121.9156 990.3 1 1e6 DU/M PPP +CI DLNO 20 LYE 35.7500 -119.2431 63.2 1 1e6 DU/M PPP +CI DLNO 20 LYN 35.7500 -119.2431 63.2 1 1e6 DU/M PPP +CI DLNO 20 LYZ 35.7500 -119.2431 63.2 1 1e6 DU/M PPP +CI DLNO 20 LY1 35.7500 -119.2431 63.2 1 1e6 DU/M PPP +CI DLNO 20 LY2 35.7500 -119.2431 63.2 1 1e6 DU/M PPP +CI DLNO 20 LY3 35.7500 -119.2431 63.2 1 1e6 DU/M PPP +CI DLNO 20 LYQ 35.7500 -119.2431 63.2 1 1 - PPP +CI DLUZ 20 LYE 33.4306 -117.3072 212.7 1 1e6 DU/M PPP +CI DLUZ 20 LYN 33.4306 -117.3072 212.7 1 1e6 DU/M PPP +CI DLUZ 20 LYZ 33.4306 -117.3072 212.7 1 1e6 DU/M PPP +CI DLUZ 20 LY1 33.4306 -117.3072 212.7 1 1e6 DU/M PPP +CI DLUZ 20 LY2 33.4306 -117.3072 212.7 1 1e6 DU/M PPP +CI DLUZ 20 LY3 33.4306 -117.3072 212.7 1 1e6 DU/M PPP +CI DLUZ 20 LYQ 33.4306 -117.3072 212.7 1 1 - PPP +CI DSME 20 LYE 33.0365 -117.2495 56.1 1 1e6 DU/M PPP +CI DSME 20 LYN 33.0365 -117.2495 56.1 1 1e6 DU/M PPP +CI DSME 20 LYZ 33.0365 -117.2495 56.1 1 1e6 DU/M PPP +CI DSME 20 LY1 33.0365 -117.2495 56.1 1 1e6 DU/M PPP +CI DSME 20 LY2 33.0365 -117.2495 56.1 1 1e6 DU/M PPP +CI DSME 20 LY3 33.0365 -117.2495 56.1 1 1e6 DU/M PPP +CI DSME 20 LYQ 33.0365 -117.2495 56.1 1 1 - PPP +CI DSSC 20 LYE 33.7333 -116.7121 1660.8 1 1e6 DU/M PPP +CI DSSC 20 LYN 33.7333 -116.7121 1660.8 1 1e6 DU/M PPP +CI DSSC 20 LYZ 33.7333 -116.7121 1660.8 1 1e6 DU/M PPP +CI DSSC 20 LY1 33.7333 -116.7121 1660.8 1 1e6 DU/M PPP +CI DSSC 20 LY2 33.7333 -116.7121 1660.8 1 1e6 DU/M PPP +CI DSSC 20 LY3 33.7333 -116.7121 1660.8 1 1e6 DU/M PPP +CI DSSC 20 LYQ 33.7333 -116.7121 1660.8 1 1 - PPP +CI DTPG 20 LYE 35.2675 -117.8459 910.2 1 1e6 DU/M PPP +CI DTPG 20 LYN 35.2675 -117.8459 910.2 1 1e6 DU/M PPP +CI DTPG 20 LYZ 35.2675 -117.8459 910.2 1 1e6 DU/M PPP +CI DTPG 20 LY1 35.2675 -117.8459 910.2 1 1e6 DU/M PPP +CI DTPG 20 LY2 35.2675 -117.8459 910.2 1 1e6 DU/M PPP +CI DTPG 20 LY3 35.2675 -117.8459 910.2 1 1e6 DU/M PPP +CI DTPG 20 LYQ 35.2675 -117.8459 910.2 1 1 - PPP +CI DVPB 20 LYE 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 20 LYN 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 20 LYZ 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 20 LY1 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 20 LY2 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 20 LY3 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 20 LYQ 34.4134 -117.8601 1430.8 1 1 - PPP +CI DVPB 30 LYE 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 30 LYN 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 30 LYZ 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 30 LY1 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 30 LY2 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 30 LY3 34.4134 -117.8601 1430.8 1 1e6 DU/M PPP +CI DVPB 30 LYQ 34.4134 -117.8601 1430.8 1 1 - PPP +CI DYH2 20 LYE 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 20 LYN 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 20 LYZ 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 20 LY1 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 20 LY2 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 20 LY3 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 20 LYQ 33.9383 -118.1275 10.8 1 1 - PPP +CI DYH2 30 LYE 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 30 LYN 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 30 LYZ 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 30 LY1 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 30 LY2 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 30 LY3 33.9383 -118.1275 10.8 1 1e6 DU/M PPP +CI DYH2 30 LYQ 33.9383 -118.1275 10.8 1 1 - PPP +BK EBMD 30 LYN 37.8150 -122.2838 -15.8 1 1e6 DU/M PPP +BK EBMD 30 LYE 37.8150 -122.2838 -15.8 1 1e6 DU/M PPP +BK EBMD 30 LYZ 37.8150 -122.2838 -15.8 1 1e6 DU/M PPP +BK EBMD 30 LYQ 37.8150 -122.2838 -15.8 1 1 - PPP +BK EBMD 30 LY1 37.8150 -122.2838 -15.8 1 1e6 DU/M PPP +BK EBMD 30 LY2 37.8150 -122.2838 -15.8 1 1e6 DU/M PPP +BK EBMD 30 LY3 37.8150 -122.2838 -15.8 1 1e6 DU/M PPP +CI ECFS 20 LYE 33.6477 -117.4117 801.4 1 1e6 DU/M PPP +CI ECFS 20 LYN 33.6477 -117.4117 801.4 1 1e6 DU/M PPP +CI ECFS 20 LYZ 33.6477 -117.4117 801.4 1 1e6 DU/M PPP +CI ECFS 20 LY1 33.6477 -117.4117 801.4 1 1e6 DU/M PPP +CI ECFS 20 LY2 33.6477 -117.4117 801.4 1 1e6 DU/M PPP +CI ECFS 20 LY3 33.6477 -117.4117 801.4 1 1e6 DU/M PPP +CI ECFS 20 LYQ 33.6477 -117.4117 801.4 1 1 - PPP +CI EDPP 20 LYE 34.9462 -118.8304 379.8 1 1e6 DU/M PPP +CI EDPP 20 LYN 34.9462 -118.8304 379.8 1 1e6 DU/M PPP +CI EDPP 20 LYZ 34.9462 -118.8304 379.8 1 1e6 DU/M PPP +CI EDPP 20 LY1 34.9462 -118.8304 379.8 1 1e6 DU/M PPP +CI EDPP 20 LY2 34.9462 -118.8304 379.8 1 1e6 DU/M PPP +CI EDPP 20 LY3 34.9462 -118.8304 379.8 1 1e6 DU/M PPP +CI EDPP 20 LYQ 34.9462 -118.8304 379.8 1 1 - PPP +CI ELLY 20 LYE 33.5835 -118.1288 -2.9 1 1e6 DU/M PPP +CI ELLY 20 LYN 33.5835 -118.1288 -2.9 1 1e6 DU/M PPP +CI ELLY 20 LYZ 33.5835 -118.1288 -2.9 1 1e6 DU/M PPP +CI ELLY 20 LY1 33.5835 -118.1288 -2.9 1 1e6 DU/M PPP +CI ELLY 20 LY2 33.5835 -118.1288 -2.9 1 1e6 DU/M PPP +CI ELLY 20 LY3 33.5835 -118.1288 -2.9 1 1e6 DU/M PPP +CI ELLY 20 LYQ 33.5835 -118.1288 -2.9 1 1 - PPP +CI ELSC 20 LYE 34.0297 -118.2084 61.1 1 1e6 DU/M PPP +CI ELSC 20 LYN 34.0297 -118.2084 61.1 1 1e6 DU/M PPP +CI ELSC 20 LYZ 34.0297 -118.2084 61.1 1 1e6 DU/M PPP +CI ELSC 20 LY1 34.0297 -118.2084 61.1 1 1e6 DU/M PPP +CI ELSC 20 LY2 34.0297 -118.2084 61.1 1 1e6 DU/M PPP +CI ELSC 20 LY3 34.0297 -118.2084 61.1 1 1e6 DU/M PPP +CI ELSC 20 LYQ 34.0297 -118.2084 61.1 1 1 - PPP +CI ELSG 20 LYE 33.6491 -117.4260 811.3 1 1e6 DU/M PPP +CI ELSG 20 LYN 33.6491 -117.4260 811.3 1 1e6 DU/M PPP +CI ELSG 20 LYZ 33.6491 -117.4260 811.3 1 1e6 DU/M PPP +CI ELSG 20 LY1 33.6491 -117.4260 811.3 1 1e6 DU/M PPP +CI ELSG 20 LY2 33.6491 -117.4260 811.3 1 1e6 DU/M PPP +CI ELSG 20 LY3 33.6491 -117.4260 811.3 1 1e6 DU/M PPP +CI ELSG 20 LYQ 33.6491 -117.4260 811.3 1 1 - PPP +CI ELTN 20 LYE 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 20 LYN 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 20 LYZ 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 20 LY1 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 20 LY2 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 20 LY3 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 20 LYQ 34.7031 -118.4257 916.5 1 1 - PPP +CI ELTN 40 LYE 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 40 LYN 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 40 LYZ 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 40 LY1 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 40 LY2 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 40 LY3 34.7031 -118.4257 916.5 1 1e6 DU/M PPP +CI ELTN 40 LYQ 34.7031 -118.4257 916.5 1 1 - PPP +CI EOCG 20 LYE 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 20 LYN 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 20 LYZ 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 20 LY1 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 20 LY2 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 20 LY3 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 20 LYQ 34.4508 -119.7698 42.4 1 1 - PPP +CI EOCG 40 LYE 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 40 LYN 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 40 LYZ 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 40 LY1 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 40 LY2 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 40 LY3 34.4508 -119.7698 42.4 1 1e6 DU/M PPP +CI EOCG 40 LYQ 34.4508 -119.7698 42.4 1 1 - PPP +CI ERRG 20 LYE 33.1164 -115.8227 -92.4 1 1e6 DU/M PPP +CI ERRG 20 LYN 33.1164 -115.8227 -92.4 1 1e6 DU/M PPP +CI ERRG 20 LYZ 33.1164 -115.8227 -92.4 1 1e6 DU/M PPP +CI ERRG 20 LY1 33.1164 -115.8227 -92.4 1 1e6 DU/M PPP +CI ERRG 20 LY2 33.1164 -115.8227 -92.4 1 1e6 DU/M PPP +CI ERRG 20 LY3 33.1164 -115.8227 -92.4 1 1e6 DU/M PPP +CI ERRG 20 LYQ 33.1164 -115.8227 -92.4 1 1 - PPP +CI EWPP 20 LYE 34.1042 -117.5256 330.4 1 1e6 DU/M PPP +CI EWPP 20 LYN 34.1042 -117.5256 330.4 1 1e6 DU/M PPP +CI EWPP 20 LYZ 34.1042 -117.5256 330.4 1 1e6 DU/M PPP +CI EWPP 20 LY1 34.1042 -117.5256 330.4 1 1e6 DU/M PPP +CI EWPP 20 LY2 34.1042 -117.5256 330.4 1 1e6 DU/M PPP +CI EWPP 20 LY3 34.1042 -117.5256 330.4 1 1e6 DU/M PPP +CI EWPP 20 LYQ 34.1042 -117.5256 330.4 1 1 - PPP +BK FARB 30 LYN 37.6972 -123.0008 -21.8 1 1e6 DU/M PPP +BK FARB 30 LYE 37.6972 -123.0008 -21.8 1 1e6 DU/M PPP +BK FARB 30 LYZ 37.6972 -123.0008 -21.8 1 1e6 DU/M PPP +BK FARB 30 LYQ 37.6972 -123.0008 -21.8 1 1 - PPP +BK FARB 30 LY1 37.6972 -123.0008 -21.8 1 1e6 DU/M PPP +BK FARB 30 LY2 37.6972 -123.0008 -21.8 1 1e6 DU/M PPP +BK FARB 30 LY3 37.6972 -123.0008 -21.8 1 1e6 DU/M PPP +CI FCTF 20 LYE 34.0666 -118.4421 149.7 1 1e6 DU/M PPP +CI FCTF 20 LYN 34.0666 -118.4421 149.7 1 1e6 DU/M PPP +CI FCTF 20 LYZ 34.0666 -118.4421 149.7 1 1e6 DU/M PPP +CI FCTF 20 LY1 34.0666 -118.4421 149.7 1 1e6 DU/M PPP +CI FCTF 20 LY2 34.0666 -118.4421 149.7 1 1e6 DU/M PPP +CI FCTF 20 LY3 34.0666 -118.4421 149.7 1 1e6 DU/M PPP +CI FCTF 20 LYQ 34.0666 -118.4421 149.7 1 1 - PPP +CI FGST 20 LYE 34.7330 -120.0094 904.0 1 1e6 DU/M PPP +CI FGST 20 LYN 34.7330 -120.0094 904.0 1 1e6 DU/M PPP +CI FGST 20 LYZ 34.7330 -120.0094 904.0 1 1e6 DU/M PPP +CI FGST 20 LY1 34.7330 -120.0094 904.0 1 1e6 DU/M PPP +CI FGST 20 LY2 34.7330 -120.0094 904.0 1 1e6 DU/M PPP +CI FGST 20 LY3 34.7330 -120.0094 904.0 1 1e6 DU/M PPP +CI FGST 20 LYQ 34.7330 -120.0094 904.0 1 1 - PPP +CI FHOG 20 LYE 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 20 LYN 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 20 LYZ 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 20 LY1 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 20 LY2 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 20 LY3 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 20 LYQ 34.0935 -116.9359 1588.7 1 1 - PPP +CI FHOG 40 LYE 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 40 LYN 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 40 LYZ 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 40 LY1 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 40 LY2 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 40 LY3 34.0935 -116.9359 1588.7 1 1e6 DU/M PPP +CI FHOG 40 LYQ 34.0935 -116.9359 1588.7 1 1 - PPP +CI FMTP 20 LYE 34.4099 -118.8941 362.7 1 1e6 DU/M PPP +CI FMTP 20 LYN 34.4099 -118.8941 362.7 1 1e6 DU/M PPP +CI FMTP 20 LYZ 34.4099 -118.8941 362.7 1 1e6 DU/M PPP +CI FMTP 20 LY1 34.4099 -118.8941 362.7 1 1e6 DU/M PPP +CI FMTP 20 LY2 34.4099 -118.8941 362.7 1 1e6 DU/M PPP +CI FMTP 20 LY3 34.4099 -118.8941 362.7 1 1e6 DU/M PPP +CI FMTP 20 LYQ 34.4099 -118.8941 362.7 1 1 - PPP +CI FMVT 20 LYE 34.3563 -118.8840 616.9 1 1e6 DU/M PPP +CI FMVT 20 LYN 34.3563 -118.8840 616.9 1 1e6 DU/M PPP +CI FMVT 20 LYZ 34.3563 -118.8840 616.9 1 1e6 DU/M PPP +CI FMVT 20 LY1 34.3563 -118.8840 616.9 1 1e6 DU/M PPP +CI FMVT 20 LY2 34.3563 -118.8840 616.9 1 1e6 DU/M PPP +CI FMVT 20 LY3 34.3563 -118.8840 616.9 1 1e6 DU/M PPP +CI FMVT 20 LYQ 34.3563 -118.8840 616.9 1 1 - PPP +CI FOXG 20 LYE 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 20 LYN 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 20 LYZ 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 20 LY1 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 20 LY2 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 20 LY3 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 20 LYQ 34.7339 -118.2405 688.8 1 1 - PPP +CI FOXG 30 LYE 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 30 LYN 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 30 LYZ 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 30 LY1 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 30 LY2 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 30 LY3 34.7339 -118.2405 688.8 1 1e6 DU/M PPP +CI FOXG 30 LYQ 34.7339 -118.2405 688.8 1 1 - PPP +CI FSHB 20 LYE 32.9450 -115.7999 135.0 1 1e6 DU/M PPP +CI FSHB 20 LYN 32.9450 -115.7999 135.0 1 1e6 DU/M PPP +CI FSHB 20 LYZ 32.9450 -115.7999 135.0 1 1e6 DU/M PPP +CI FSHB 20 LY1 32.9450 -115.7999 135.0 1 1e6 DU/M PPP +CI FSHB 20 LY2 32.9450 -115.7999 135.0 1 1e6 DU/M PPP +CI FSHB 20 LY3 32.9450 -115.7999 135.0 1 1e6 DU/M PPP +CI FSHB 20 LYQ 32.9450 -115.7999 135.0 1 1 - PPP +CI FVPK 20 LYE 33.6623 -117.9357 -11.6 1 1e6 DU/M PPP +CI FVPK 20 LYN 33.6623 -117.9357 -11.6 1 1e6 DU/M PPP +CI FVPK 20 LYZ 33.6623 -117.9357 -11.6 1 1e6 DU/M PPP +CI FVPK 20 LY1 33.6623 -117.9357 -11.6 1 1e6 DU/M PPP +CI FVPK 20 LY2 33.6623 -117.9357 -11.6 1 1e6 DU/M PPP +CI FVPK 20 LY3 33.6623 -117.9357 -11.6 1 1e6 DU/M PPP +CI FVPK 20 LYQ 33.6623 -117.9357 -11.6 1 1 - PPP +CI FZHS 20 LYE 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 20 LYN 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 20 LYZ 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 20 LY1 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 20 LY2 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 20 LY3 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 20 LYQ 34.8002 -118.8934 1273.7 1 1 - PPP +CI FZHS 40 LYE 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 40 LYN 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 40 LYZ 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 40 LY1 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 40 LY2 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 40 LY3 34.8002 -118.8934 1273.7 1 1e6 DU/M PPP +CI FZHS 40 LYQ 34.8002 -118.8934 1273.7 1 1 - PPP +CI GDEC 20 LYE 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 20 LYN 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 20 LYZ 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 20 LY1 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 20 LY2 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 20 LY3 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 20 LYQ 35.1894 -119.8637 566.2 1 1 - PPP +CI GDEC 40 LYE 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 40 LYN 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 40 LYZ 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 40 LY1 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 40 LY2 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 40 LY3 35.1894 -119.8637 566.2 1 1e6 DU/M PPP +CI GDEC 40 LYQ 35.1894 -119.8637 566.2 1 1 - PPP +CI GHRP 20 LYE 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 20 LYN 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 20 LYZ 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 20 LY1 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 20 LY2 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 20 LY3 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 20 LYQ 34.2039 -117.3979 628.6 1 1 - PPP +CI GHRP 40 LYE 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 40 LYN 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 40 LYZ 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 40 LY1 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 40 LY2 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 40 LY3 34.2039 -117.3979 628.6 1 1e6 DU/M PPP +CI GHRP 40 LYQ 34.2039 -117.3979 628.6 1 1 - PPP +CI GLRS 20 LYE 33.2748 -115.5214 -48.6 1 1e6 DU/M PPP +CI GLRS 20 LYN 33.2748 -115.5214 -48.6 1 1e6 DU/M PPP +CI GLRS 20 LYZ 33.2748 -115.5214 -48.6 1 1e6 DU/M PPP +CI GLRS 20 LY1 33.2748 -115.5214 -48.6 1 1e6 DU/M PPP +CI GLRS 20 LY2 33.2748 -115.5214 -48.6 1 1e6 DU/M PPP +CI GLRS 20 LY3 33.2748 -115.5214 -48.6 1 1e6 DU/M PPP +CI GLRS 20 LYQ 33.2748 -115.5214 -48.6 1 1 - PPP +CI GMAG 20 LYE 34.2914 -116.3826 866.7 1 1e6 DU/M PPP +CI GMAG 20 LYN 34.2914 -116.3826 866.7 1 1e6 DU/M PPP +CI GMAG 20 LYZ 34.2914 -116.3826 866.7 1 1e6 DU/M PPP +CI GMAG 20 LY1 34.2914 -116.3826 866.7 1 1e6 DU/M PPP +CI GMAG 20 LY2 34.2914 -116.3826 866.7 1 1e6 DU/M PPP +CI GMAG 20 LY3 34.2914 -116.3826 866.7 1 1e6 DU/M PPP +CI GMAG 20 LYQ 34.2914 -116.3826 866.7 1 1 - PPP +CI GMPK 20 LYE 33.0511 -114.8273 591.2 1 1e6 DU/M PPP +CI GMPK 20 LYN 33.0511 -114.8273 591.2 1 1e6 DU/M PPP +CI GMPK 20 LYZ 33.0511 -114.8273 591.2 1 1e6 DU/M PPP +CI GMPK 20 LY1 33.0511 -114.8273 591.2 1 1e6 DU/M PPP +CI GMPK 20 LY2 33.0511 -114.8273 591.2 1 1e6 DU/M PPP +CI GMPK 20 LY3 33.0511 -114.8273 591.2 1 1e6 DU/M PPP +CI GMPK 20 LYQ 33.0511 -114.8273 591.2 1 1 - PPP +CI GMRC 20 LYE 34.7840 -115.6602 1298.2 1 1e6 DU/M PPP +CI GMRC 20 LYN 34.7840 -115.6602 1298.2 1 1e6 DU/M PPP +CI GMRC 20 LYZ 34.7840 -115.6602 1298.2 1 1e6 DU/M PPP +CI GMRC 20 LY1 34.7840 -115.6602 1298.2 1 1e6 DU/M PPP +CI GMRC 20 LY2 34.7840 -115.6602 1298.2 1 1e6 DU/M PPP +CI GMRC 20 LY3 34.7840 -115.6602 1298.2 1 1e6 DU/M PPP +CI GMRC 20 LYQ 34.7840 -115.6602 1298.2 1 1 - PPP +CI GNPS 20 LYE 34.3086 -114.1895 232.3 1 1e6 DU/M PPP +CI GNPS 20 LYN 34.3086 -114.1895 232.3 1 1e6 DU/M PPP +CI GNPS 20 LYZ 34.3086 -114.1895 232.3 1 1e6 DU/M PPP +CI GNPS 20 LY1 34.3086 -114.1895 232.3 1 1e6 DU/M PPP +CI GNPS 20 LY2 34.3086 -114.1895 232.3 1 1e6 DU/M PPP +CI GNPS 20 LY3 34.3086 -114.1895 232.3 1 1e6 DU/M PPP +CI GNPS 20 LYQ 34.3086 -114.1895 232.3 1 1 - PPP +CI GVRS 20 LYE 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 20 LYN 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 20 LYZ 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 20 LY1 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 20 LY2 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 20 LY3 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 20 LYQ 34.0474 -118.1129 154.5 1 1 - PPP +CI GVRS 30 LYE 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 30 LYN 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 30 LYZ 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 30 LY1 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 30 LY2 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 30 LY3 34.0474 -118.1129 154.5 1 1e6 DU/M PPP +CI GVRS 30 LYQ 34.0474 -118.1129 154.5 1 1 - PPP +CI HAR7 20 LYE 35.0115 -117.2992 590.3 1 1e6 DU/M PPP +CI HAR7 20 LYN 35.0115 -117.2992 590.3 1 1e6 DU/M PPP +CI HAR7 20 LYZ 35.0115 -117.2992 590.3 1 1e6 DU/M PPP +CI HAR7 20 LY1 35.0115 -117.2992 590.3 1 1e6 DU/M PPP +CI HAR7 20 LY2 35.0115 -117.2992 590.3 1 1e6 DU/M PPP +CI HAR7 20 LY3 35.0115 -117.2992 590.3 1 1e6 DU/M PPP +CI HAR7 20 LYQ 35.0115 -117.2992 590.3 1 1 - PPP +CI HBCO 20 LYE 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 20 LYN 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 20 LYZ 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 20 LY1 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 20 LY2 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 20 LY3 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 20 LYQ 33.7836 -118.2858 -26.9 1 1 - PPP +CI HBCO 30 LYE 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 30 LYN 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 30 LYZ 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 30 LY1 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 30 LY2 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 30 LY3 33.7836 -118.2858 -26.9 1 1e6 DU/M PPP +CI HBCO 30 LYQ 33.7836 -118.2858 -26.9 1 1 - PPP +CI HCMN 20 LYE 34.7548 -116.4301 568.7 1 1e6 DU/M PPP +CI HCMN 20 LYN 34.7548 -116.4301 568.7 1 1e6 DU/M PPP +CI HCMN 20 LYZ 34.7548 -116.4301 568.7 1 1e6 DU/M PPP +CI HCMN 20 LY1 34.7548 -116.4301 568.7 1 1e6 DU/M PPP +CI HCMN 20 LY2 34.7548 -116.4301 568.7 1 1e6 DU/M PPP +CI HCMN 20 LY3 34.7548 -116.4301 568.7 1 1e6 DU/M PPP +CI HCMN 20 LYQ 34.7548 -116.4301 568.7 1 1 - PPP +BK HELP 30 LYN 36.6802 -119.0228 1120.4 1 1e6 DU/M PPP +BK HELP 30 LYE 36.6802 -119.0228 1120.4 1 1e6 DU/M PPP +BK HELP 30 LYZ 36.6802 -119.0228 1120.4 1 1e6 DU/M PPP +BK HELP 30 LYQ 36.6802 -119.0228 1120.4 1 1 - PPP +BK HELP 30 LY1 36.6802 -119.0228 1120.4 1 1e6 DU/M PPP +BK HELP 30 LY2 36.6802 -119.0228 1120.4 1 1e6 DU/M PPP +BK HELP 30 LY3 36.6802 -119.0228 1120.4 1 1e6 DU/M PPP +CI HIVI 20 LYE 34.7599 -117.7995 930.8 1 1e6 DU/M PPP +CI HIVI 20 LYN 34.7599 -117.7995 930.8 1 1e6 DU/M PPP +CI HIVI 20 LYZ 34.7599 -117.7995 930.8 1 1e6 DU/M PPP +CI HIVI 20 LY1 34.7599 -117.7995 930.8 1 1e6 DU/M PPP +CI HIVI 20 LY2 34.7599 -117.7995 930.8 1 1e6 DU/M PPP +CI HIVI 20 LY3 34.7599 -117.7995 930.8 1 1e6 DU/M PPP +CI HIVI 20 LYQ 34.7599 -117.7995 930.8 1 1 - PPP +CI HMTG 20 LYE 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 20 LYN 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 20 LYZ 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 20 LY1 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 20 LY2 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 20 LY3 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 20 LYQ 33.7081 -117.0015 577.0 1 1 - PPP +CI HMTG 30 LYE 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 30 LYN 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 30 LYZ 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 30 LY1 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 30 LY2 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 30 LY3 33.7081 -117.0015 577.0 1 1e6 DU/M PPP +CI HMTG 30 LYQ 33.7081 -117.0015 577.0 1 1 - PPP +CI HNPS 20 LYE 33.7050 -115.6353 393.9 1 1e6 DU/M PPP +CI HNPS 20 LYN 33.7050 -115.6353 393.9 1 1e6 DU/M PPP +CI HNPS 20 LYZ 33.7050 -115.6353 393.9 1 1e6 DU/M PPP +CI HNPS 20 LY1 33.7050 -115.6353 393.9 1 1e6 DU/M PPP +CI HNPS 20 LY2 33.7050 -115.6353 393.9 1 1e6 DU/M PPP +CI HNPS 20 LY3 33.7050 -115.6353 393.9 1 1e6 DU/M PPP +CI HNPS 20 LYQ 33.7050 -115.6353 393.9 1 1 - PPP +CI HOL3 20 LYE 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 20 LYN 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 20 LYZ 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 20 LY1 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 20 LY2 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 20 LY3 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 20 LYQ 34.4582 -117.8451 1239.4 1 1 - PPP +CI HOL3 30 LYE 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 30 LYN 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 30 LYZ 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 30 LY1 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 30 LY2 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 30 LY3 34.4582 -117.8451 1239.4 1 1e6 DU/M PPP +CI HOL3 30 LYQ 34.4582 -117.8451 1239.4 1 1 - PPP +CI HOLP 20 LYE 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 20 LYN 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 20 LYZ 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 20 LY1 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 20 LY2 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 20 LY3 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 20 LYQ 33.9245 -118.1682 -6.9 1 1 - PPP +CI HOLP 30 LYE 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 30 LYN 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 30 LYZ 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 30 LY1 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 30 LY2 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 30 LY3 33.9245 -118.1682 -6.9 1 1e6 DU/M PPP +CI HOLP 30 LYQ 33.9245 -118.1682 -6.9 1 1 - PPP +BK HOPB 30 LYN 38.9952 -123.0747 353.2 1 1e6 DU/M PPP +BK HOPB 30 LYE 38.9952 -123.0747 353.2 1 1e6 DU/M PPP +BK HOPB 30 LYZ 38.9952 -123.0747 353.2 1 1e6 DU/M PPP +BK HOPB 30 LYQ 38.9952 -123.0747 353.2 1 1 - PPP +BK HOPB 30 LY1 38.9952 -123.0747 353.2 1 1e6 DU/M PPP +BK HOPB 30 LY2 38.9952 -123.0747 353.2 1 1e6 DU/M PPP +BK HOPB 30 LY3 38.9952 -123.0747 353.2 1 1e6 DU/M PPP +CI HVYS 20 LYE 34.4412 -119.1875 373.9 1 1e6 DU/M PPP +CI HVYS 20 LYN 34.4412 -119.1875 373.9 1 1e6 DU/M PPP +CI HVYS 20 LYZ 34.4412 -119.1875 373.9 1 1e6 DU/M PPP +CI HVYS 20 LY1 34.4412 -119.1875 373.9 1 1e6 DU/M PPP +CI HVYS 20 LY2 34.4412 -119.1875 373.9 1 1e6 DU/M PPP +CI HVYS 20 LY3 34.4412 -119.1875 373.9 1 1e6 DU/M PPP +CI HVYS 20 LYQ 34.4412 -119.1875 373.9 1 1 - PPP +CI I40A 20 LYE 34.7273 -115.9115 765.2 1 1e6 DU/M PPP +CI I40A 20 LYN 34.7273 -115.9115 765.2 1 1e6 DU/M PPP +CI I40A 20 LYZ 34.7273 -115.9115 765.2 1 1e6 DU/M PPP +CI I40A 20 LY1 34.7273 -115.9115 765.2 1 1e6 DU/M PPP +CI I40A 20 LY2 34.7273 -115.9115 765.2 1 1e6 DU/M PPP +CI I40A 20 LY3 34.7273 -115.9115 765.2 1 1e6 DU/M PPP +CI I40A 20 LYQ 34.7273 -115.9115 765.2 1 1 - PPP +CI IDOG 20 LYE 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 20 LYN 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 20 LYZ 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 20 LY1 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 20 LY2 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 20 LY3 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 20 LYQ 33.7968 -116.2215 434.9 1 1 - PPP +CI IDOG 40 LYE 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 40 LYN 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 40 LYZ 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 40 LY1 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 40 LY2 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 40 LY3 33.7968 -116.2215 434.9 1 1e6 DU/M PPP +CI IDOG 40 LYQ 33.7968 -116.2215 434.9 1 1 - PPP +CI IDQG 20 LYE 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 20 LYN 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 20 LYZ 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 20 LY1 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 20 LY2 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 20 LY3 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 20 LYQ 33.7680 -116.2390 -1.3 1 1 - PPP +CI IDQG 40 LYE 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 40 LYN 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 40 LYZ 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 40 LY1 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 40 LY2 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 40 LY3 33.7680 -116.2390 -1.3 1 1e6 DU/M PPP +CI IDQG 40 LYQ 33.7680 -116.2390 -1.3 1 1 - PPP +CI IID2 20 LYE 32.7062 -115.0318 9.7 1 1e6 DU/M PPP +CI IID2 20 LYN 32.7062 -115.0318 9.7 1 1e6 DU/M PPP +CI IID2 20 LYZ 32.7062 -115.0318 9.7 1 1e6 DU/M PPP +CI IID2 20 LY1 32.7062 -115.0318 9.7 1 1e6 DU/M PPP +CI IID2 20 LY2 32.7062 -115.0318 9.7 1 1e6 DU/M PPP +CI IID2 20 LY3 32.7062 -115.0318 9.7 1 1e6 DU/M PPP +CI IID2 20 LYQ 32.7062 -115.0318 9.7 1 1 - PPP +CI IMPS 20 LYE 34.1576 -115.1451 563.2 1 1e6 DU/M PPP +CI IMPS 20 LYN 34.1576 -115.1451 563.2 1 1e6 DU/M PPP +CI IMPS 20 LYZ 34.1576 -115.1451 563.2 1 1e6 DU/M PPP +CI IMPS 20 LY1 34.1576 -115.1451 563.2 1 1e6 DU/M PPP +CI IMPS 20 LY2 34.1576 -115.1451 563.2 1 1e6 DU/M PPP +CI IMPS 20 LY3 34.1576 -115.1451 563.2 1 1e6 DU/M PPP +CI IMPS 20 LYQ 34.1576 -115.1451 563.2 1 1 - PPP +CI JAS1 20 LYE 32.8279 -116.9881 97.5 1 1e6 DU/M PPP +CI JAS1 20 LYN 32.8279 -116.9881 97.5 1 1e6 DU/M PPP +CI JAS1 20 LYZ 32.8279 -116.9881 97.5 1 1e6 DU/M PPP +CI JAS1 20 LY1 32.8279 -116.9881 97.5 1 1e6 DU/M PPP +CI JAS1 20 LY2 32.8279 -116.9881 97.5 1 1e6 DU/M PPP +CI JAS1 20 LY3 32.8279 -116.9881 97.5 1 1e6 DU/M PPP +CI JAS1 20 LYQ 32.8279 -116.9881 97.5 1 1 - PPP +CI JNHG 20 LYE 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 20 LYN 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 20 LYZ 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 20 LY1 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 20 LY2 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 20 LY3 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 20 LYQ 34.4491 -117.9554 1276.2 1 1 - PPP +CI JNHG 40 LYE 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 40 LYN 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 40 LYZ 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 40 LY1 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 40 LY2 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 40 LY3 34.4491 -117.9554 1276.2 1 1e6 DU/M PPP +CI JNHG 40 LYQ 34.4491 -117.9554 1276.2 1 1 - PPP +BK JRSC 30 LYN 37.4062 -122.2274 144.3 1 1e6 DU/M PPP +BK JRSC 30 LYE 37.4062 -122.2274 144.3 1 1e6 DU/M PPP +BK JRSC 30 LYZ 37.4062 -122.2274 144.3 1 1e6 DU/M PPP +BK JRSC 30 LYQ 37.4062 -122.2274 144.3 1 1 - PPP +BK JRSC 30 LY1 37.4062 -122.2274 144.3 1 1e6 DU/M PPP +BK JRSC 30 LY2 37.4062 -122.2274 144.3 1 1e6 DU/M PPP +BK JRSC 30 LY3 37.4062 -122.2274 144.3 1 1e6 DU/M PPP +CI KBRC 20 LYE 34.3985 -119.0082 370.5 1 1e6 DU/M PPP +CI KBRC 20 LYN 34.3985 -119.0082 370.5 1 1e6 DU/M PPP +CI KBRC 20 LYZ 34.3985 -119.0082 370.5 1 1e6 DU/M PPP +CI KBRC 20 LY1 34.3985 -119.0082 370.5 1 1e6 DU/M PPP +CI KBRC 20 LY2 34.3985 -119.0082 370.5 1 1e6 DU/M PPP +CI KBRC 20 LY3 34.3985 -119.0082 370.5 1 1e6 DU/M PPP +CI KBRC 20 LYQ 34.3985 -119.0082 370.5 1 1 - PPP +CI KYVW 20 LYE 33.9254 -116.1734 1498.2 1 1e6 DU/M PPP +CI KYVW 20 LYN 33.9254 -116.1734 1498.2 1 1e6 DU/M PPP +CI KYVW 20 LYZ 33.9254 -116.1734 1498.2 1 1e6 DU/M PPP +CI KYVW 20 LY1 33.9254 -116.1734 1498.2 1 1e6 DU/M PPP +CI KYVW 20 LY2 33.9254 -116.1734 1498.2 1 1e6 DU/M PPP +CI KYVW 20 LY3 33.9254 -116.1734 1498.2 1 1e6 DU/M PPP +CI KYVW 20 LYQ 33.9254 -116.1734 1498.2 1 1 - PPP +CI LAPC 20 LYE 34.1819 -118.5747 207.8 1 1e6 DU/M PPP +CI LAPC 20 LYN 34.1819 -118.5747 207.8 1 1e6 DU/M PPP +CI LAPC 20 LYZ 34.1819 -118.5747 207.8 1 1e6 DU/M PPP +CI LAPC 20 LY1 34.1819 -118.5747 207.8 1 1e6 DU/M PPP +CI LAPC 20 LY2 34.1819 -118.5747 207.8 1 1e6 DU/M PPP +CI LAPC 20 LY3 34.1819 -118.5747 207.8 1 1e6 DU/M PPP +CI LAPC 20 LYQ 34.1819 -118.5747 207.8 1 1 - PPP +CI LBC1 20 LYE 33.8321 -118.1372 -22.1 1 1e6 DU/M PPP +CI LBC1 20 LYN 33.8321 -118.1372 -22.1 1 1e6 DU/M PPP +CI LBC1 20 LYZ 33.8321 -118.1372 -22.1 1 1e6 DU/M PPP +CI LBC1 20 LY1 33.8321 -118.1372 -22.1 1 1e6 DU/M PPP +CI LBC1 20 LY2 33.8321 -118.1372 -22.1 1 1e6 DU/M PPP +CI LBC1 20 LY3 33.8321 -118.1372 -22.1 1 1e6 DU/M PPP +CI LBC1 20 LYQ 33.8321 -118.1372 -22.1 1 1 - PPP +CI LBC2 20 LYE 33.7916 -118.1732 -28.4 1 1e6 DU/M PPP +CI LBC2 20 LYN 33.7916 -118.1732 -28.4 1 1e6 DU/M PPP +CI LBC2 20 LYZ 33.7916 -118.1732 -28.4 1 1e6 DU/M PPP +CI LBC2 20 LY1 33.7916 -118.1732 -28.4 1 1e6 DU/M PPP +CI LBC2 20 LY2 33.7916 -118.1732 -28.4 1 1e6 DU/M PPP +CI LBC2 20 LY3 33.7916 -118.1732 -28.4 1 1e6 DU/M PPP +CI LBC2 20 LYQ 33.7916 -118.1732 -28.4 1 1 - PPP +CI LBCH 20 LYE 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 20 LYN 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 20 LYZ 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 20 LY1 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 20 LY2 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 20 LY3 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 20 LYQ 33.7878 -118.2033 -27.6 1 1 - PPP +CI LBCH 30 LYE 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 30 LYN 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 30 LYZ 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 30 LY1 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 30 LY2 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 30 LY3 33.7878 -118.2033 -27.6 1 1e6 DU/M PPP +CI LBCH 30 LYQ 33.7878 -118.2033 -27.6 1 1 - PPP +CI LDES 20 LYE 34.2673 -116.4328 978.0 1 1e6 DU/M PPP +CI LDES 20 LYN 34.2673 -116.4328 978.0 1 1e6 DU/M PPP +CI LDES 20 LYZ 34.2673 -116.4328 978.0 1 1e6 DU/M PPP +CI LDES 20 LY1 34.2673 -116.4328 978.0 1 1e6 DU/M PPP +CI LDES 20 LY2 34.2673 -116.4328 978.0 1 1e6 DU/M PPP +CI LDES 20 LY3 34.2673 -116.4328 978.0 1 1e6 DU/M PPP +CI LDES 20 LYQ 34.2673 -116.4328 978.0 1 1 - PPP +CI LDSW 20 LYE 34.6994 -116.2091 640.9 1 1e6 DU/M PPP +CI LDSW 20 LYN 34.6994 -116.2091 640.9 1 1e6 DU/M PPP +CI LDSW 20 LYZ 34.6994 -116.2091 640.9 1 1e6 DU/M PPP +CI LDSW 20 LY1 34.6994 -116.2091 640.9 1 1e6 DU/M PPP +CI LDSW 20 LY2 34.6994 -116.2091 640.9 1 1e6 DU/M PPP +CI LDSW 20 LY3 34.6994 -116.2091 640.9 1 1e6 DU/M PPP +CI LDSW 20 LYQ 34.6994 -116.2091 640.9 1 1 - PPP +CI LEE2 20 LYE 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 20 LYN 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 20 LYZ 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 20 LY1 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 20 LY2 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 20 LY3 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 20 LYQ 34.1346 -118.3218 484.8 1 1 - PPP +CI LEE2 30 LYE 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 30 LYN 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 30 LYZ 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 30 LY1 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 30 LY2 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 30 LY3 34.1346 -118.3218 484.8 1 1e6 DU/M PPP +CI LEE2 30 LYQ 34.1346 -118.3218 484.8 1 1 - PPP +CI LFRS 20 LYE 34.0951 -118.4128 146.9 1 1e6 DU/M PPP +CI LFRS 20 LYN 34.0951 -118.4128 146.9 1 1e6 DU/M PPP +CI LFRS 20 LYZ 34.0951 -118.4128 146.9 1 1e6 DU/M PPP +CI LFRS 20 LY1 34.0951 -118.4128 146.9 1 1e6 DU/M PPP +CI LFRS 20 LY2 34.0951 -118.4128 146.9 1 1e6 DU/M PPP +CI LFRS 20 LY3 34.0951 -118.4128 146.9 1 1e6 DU/M PPP +CI LFRS 20 LYQ 34.0951 -118.4128 146.9 1 1 - PPP +CI LGWD 20 LYE 33.6406 -117.7645 88.6 1 1e6 DU/M PPP +CI LGWD 20 LYN 33.6406 -117.7645 88.6 1 1e6 DU/M PPP +CI LGWD 20 LYZ 33.6406 -117.7645 88.6 1 1e6 DU/M PPP +CI LGWD 20 LY1 33.6406 -117.7645 88.6 1 1e6 DU/M PPP +CI LGWD 20 LY2 33.6406 -117.7645 88.6 1 1e6 DU/M PPP +CI LGWD 20 LY3 33.6406 -117.7645 88.6 1 1e6 DU/M PPP +CI LGWD 20 LYQ 33.6406 -117.7645 88.6 1 1 - PPP +CI LINJ 20 LYE 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 20 LYN 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 20 LYZ 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 20 LY1 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 20 LY2 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 20 LY3 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 20 LYQ 34.6620 -118.1392 721.2 1 1 - PPP +CI LINJ 40 LYE 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 40 LYN 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 40 LYZ 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 40 LY1 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 40 LY2 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 40 LY3 34.6620 -118.1392 721.2 1 1e6 DU/M PPP +CI LINJ 40 LYQ 34.6620 -118.1392 721.2 1 1 - PPP +CI LJRN 20 LYE 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 20 LYN 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 20 LYZ 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 20 LY1 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 20 LY2 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 20 LY3 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 20 LYQ 34.8075 -118.8677 1422.5 1 1 - PPP +CI LJRN 40 LYE 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 40 LYN 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 40 LYZ 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 40 LY1 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 40 LY2 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 40 LY3 34.8075 -118.8677 1422.5 1 1e6 DU/M PPP +CI LJRN 40 LYQ 34.8075 -118.8677 1422.5 1 1 - PPP +CI LKHG 20 LYE 33.2360 -116.7588 823.3 1 1e6 DU/M PPP +CI LKHG 20 LYN 33.2360 -116.7588 823.3 1 1e6 DU/M PPP +CI LKHG 20 LYZ 33.2360 -116.7588 823.3 1 1e6 DU/M PPP +CI LKHG 20 LY1 33.2360 -116.7588 823.3 1 1e6 DU/M PPP +CI LKHG 20 LY2 33.2360 -116.7588 823.3 1 1e6 DU/M PPP +CI LKHG 20 LY3 33.2360 -116.7588 823.3 1 1e6 DU/M PPP +CI LKHG 20 LYQ 33.2360 -116.7588 823.3 1 1 - PPP +CI LL01 20 LYE 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 20 LYN 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 20 LYZ 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 20 LY1 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 20 LY2 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 20 LY3 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 20 LYQ 34.4855 -117.8350 1005.3 1 1 - PPP +CI LL01 40 LYE 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 40 LYN 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 40 LYZ 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 40 LY1 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 40 LY2 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 40 LY3 34.4855 -117.8350 1005.3 1 1e6 DU/M PPP +CI LL01 40 LYQ 34.4855 -117.8350 1005.3 1 1 - PPP +CI LLAS 20 LYE 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 20 LYN 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 20 LYZ 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 20 LY1 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 20 LY2 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 20 LY3 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 20 LYQ 34.5860 -117.8379 812.5 1 1 - PPP +CI LLAS 30 LYE 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 30 LYN 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 30 LYZ 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 30 LY1 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 30 LY2 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 30 LY3 34.5860 -117.8379 812.5 1 1e6 DU/M PPP +CI LLAS 30 LYQ 34.5860 -117.8379 812.5 1 1 - PPP +CI LMHG 20 LYE 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 20 LYN 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 20 LYZ 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 20 LY1 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 20 LY2 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 20 LY3 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 20 LYQ 33.7442 -117.3913 464.5 1 1 - PPP +CI LMHG 40 LYE 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 40 LYN 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 40 LYZ 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 40 LY1 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 40 LY2 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 40 LY3 33.7442 -117.3913 464.5 1 1e6 DU/M PPP +CI LMHG 40 LYQ 33.7442 -117.3913 464.5 1 1 - PPP +CI LMSG 20 LYE 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 20 LYN 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 20 LYZ 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 20 LY1 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 20 LY2 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 20 LY3 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 20 LYQ 33.8174 -117.4451 413.1 1 1 - PPP +CI LMSG 30 LYE 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 30 LYN 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 30 LYZ 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 30 LY1 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 30 LY2 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 30 LY3 33.8174 -117.4451 413.1 1 1e6 DU/M PPP +CI LMSG 30 LYQ 33.8174 -117.4451 413.1 1 1 - PPP +CI LNMT 20 LYE 35.0902 -116.9397 1345.3 1 1e6 DU/M PPP +CI LNMT 20 LYN 35.0902 -116.9397 1345.3 1 1e6 DU/M PPP +CI LNMT 20 LYZ 35.0902 -116.9397 1345.3 1 1e6 DU/M PPP +CI LNMT 20 LY1 35.0902 -116.9397 1345.3 1 1e6 DU/M PPP +CI LNMT 20 LY2 35.0902 -116.9397 1345.3 1 1e6 DU/M PPP +CI LNMT 20 LY3 35.0902 -116.9397 1345.3 1 1e6 DU/M PPP +CI LNMT 20 LYQ 35.0902 -116.9397 1345.3 1 1 - PPP +CI LOMP 20 LYE 34.6909 -120.4466 63.5 1 1e6 DU/M PPP +CI LOMP 20 LYN 34.6909 -120.4466 63.5 1 1e6 DU/M PPP +CI LOMP 20 LYZ 34.6909 -120.4466 63.5 1 1e6 DU/M PPP +CI LOMP 20 LY1 34.6909 -120.4466 63.5 1 1e6 DU/M PPP +CI LOMP 20 LY2 34.6909 -120.4466 63.5 1 1e6 DU/M PPP +CI LOMP 20 LY3 34.6909 -120.4466 63.5 1 1e6 DU/M PPP +CI LOMP 20 LYQ 34.6909 -120.4466 63.5 1 1 - PPP +CI LONG 20 LYE 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 20 LYN 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 20 LYZ 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 20 LY1 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 20 LY2 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 20 LY3 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 20 LYQ 34.1119 -118.0034 74.3 1 1 - PPP +CI LONG 30 LYE 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 30 LYN 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 30 LYZ 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 30 LY1 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 30 LY2 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 30 LY3 34.1119 -118.0034 74.3 1 1e6 DU/M PPP +CI LONG 30 LYQ 34.1119 -118.0034 74.3 1 1 - PPP +CI LORS 20 LYE 34.1333 -117.7541 448.9 1 1e6 DU/M PPP +CI LORS 20 LYN 34.1333 -117.7541 448.9 1 1e6 DU/M PPP +CI LORS 20 LYZ 34.1333 -117.7541 448.9 1 1e6 DU/M PPP +CI LORS 20 LY1 34.1333 -117.7541 448.9 1 1e6 DU/M PPP +CI LORS 20 LY2 34.1333 -117.7541 448.9 1 1e6 DU/M PPP +CI LORS 20 LY3 34.1333 -117.7541 448.9 1 1e6 DU/M PPP +CI LORS 20 LYQ 34.1333 -117.7541 448.9 1 1 - PPP +CI LPCG 20 LYE 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 20 LYN 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 20 LYZ 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 20 LY1 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 20 LY2 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 20 LY3 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 20 LYQ 34.3149 -117.5464 1315.3 1 1 - PPP +CI LPCG 40 LYE 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 40 LYN 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 40 LYZ 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 40 LY1 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 40 LY2 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 40 LY3 34.3149 -117.5464 1315.3 1 1e6 DU/M PPP +CI LPCG 40 LYQ 34.3149 -117.5464 1315.3 1 1 - PPP +CI LPHS 20 LYE 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 20 LYN 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 20 LYZ 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 20 LY1 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 20 LY2 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 20 LY3 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 20 LYQ 34.0268 -117.9567 68.5 1 1 - PPP +CI LPHS 30 LYE 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 30 LYN 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 30 LYZ 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 30 LY1 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 30 LY2 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 30 LY3 34.0268 -117.9567 68.5 1 1e6 DU/M PPP +CI LPHS 30 LYQ 34.0268 -117.9567 68.5 1 1 - PPP +CI LRRG 20 LYE 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 20 LYN 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 20 LYZ 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 20 LY1 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 20 LY2 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 20 LY3 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 20 LYQ 34.5271 -118.0300 875.0 1 1 - PPP +CI LRRG 40 LYE 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 40 LYN 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 40 LYZ 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 40 LY1 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 40 LY2 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 40 LY3 34.5271 -118.0300 875.0 1 1e6 DU/M PPP +CI LRRG 40 LYQ 34.5271 -118.0300 875.0 1 1 - PPP +BK LUTZ 30 LYN 37.2869 -121.8652 95.0 1 1e6 DU/M PPP +BK LUTZ 30 LYE 37.2869 -121.8652 95.0 1 1e6 DU/M PPP +BK LUTZ 30 LYZ 37.2869 -121.8652 95.0 1 1e6 DU/M PPP +BK LUTZ 30 LYQ 37.2869 -121.8652 95.0 1 1 - PPP +BK LUTZ 30 LY1 37.2869 -121.8652 95.0 1 1e6 DU/M PPP +BK LUTZ 30 LY2 37.2869 -121.8652 95.0 1 1e6 DU/M PPP +BK LUTZ 30 LY3 37.2869 -121.8652 95.0 1 1e6 DU/M PPP +CI LVMS 20 LYE 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 20 LYN 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 20 LYZ 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 20 LY1 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 20 LY2 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 20 LY3 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 20 LYQ 34.7336 -119.1037 1543.1 1 1 - PPP +CI LVMS 40 LYE 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 40 LYN 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 40 LYZ 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 40 LY1 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 40 LY2 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 40 LY3 34.7336 -119.1037 1543.1 1 1e6 DU/M PPP +CI LVMS 40 LYQ 34.7336 -119.1037 1543.1 1 1 - PPP +CI MAT2 20 LYE 33.8568 -117.4367 398.3 1 1e6 DU/M PPP +CI MAT2 20 LYN 33.8568 -117.4367 398.3 1 1e6 DU/M PPP +CI MAT2 20 LYZ 33.8568 -117.4367 398.3 1 1e6 DU/M PPP +CI MAT2 20 LY1 33.8568 -117.4367 398.3 1 1e6 DU/M PPP +CI MAT2 20 LY2 33.8568 -117.4367 398.3 1 1e6 DU/M PPP +CI MAT2 20 LY3 33.8568 -117.4367 398.3 1 1e6 DU/M PPP +CI MAT2 20 LYQ 33.8568 -117.4367 398.3 1 1 - PPP +BK MCCM 30 LYN 38.1448 -122.8802 -3.8 1 1e6 DU/M PPP +BK MCCM 30 LYE 38.1448 -122.8802 -3.8 1 1e6 DU/M PPP +BK MCCM 30 LYZ 38.1448 -122.8802 -3.8 1 1e6 DU/M PPP +BK MCCM 30 LYQ 38.1448 -122.8802 -3.8 1 1 - PPP +BK MCCM 30 LY1 38.1448 -122.8802 -3.8 1 1e6 DU/M PPP +BK MCCM 30 LY2 38.1448 -122.8802 -3.8 1 1e6 DU/M PPP +BK MCCM 30 LY3 38.1448 -122.8802 -3.8 1 1e6 DU/M PPP +BK MHCB 30 LYN 37.3415 -121.6426 1261.8 1 1e6 DU/M PPP +BK MHCB 30 LYE 37.3415 -121.6426 1261.8 1 1e6 DU/M PPP +BK MHCB 30 LYZ 37.3415 -121.6426 1261.8 1 1e6 DU/M PPP +BK MHCB 30 LYQ 37.3415 -121.6426 1261.8 1 1 - PPP +BK MHCB 30 LY1 37.3415 -121.6426 1261.8 1 1e6 DU/M PPP +BK MHCB 30 LY2 37.3415 -121.6426 1261.8 1 1e6 DU/M PPP +BK MHCB 30 LY3 37.3415 -121.6426 1261.8 1 1e6 DU/M PPP +BK MHDL 30 LYN 37.8423 -122.4943 65.9 1 1e6 DU/M PPP +BK MHDL 30 LYE 37.8423 -122.4943 65.9 1 1e6 DU/M PPP +BK MHDL 30 LYZ 37.8423 -122.4943 65.9 1 1e6 DU/M PPP +BK MHDL 30 LYQ 37.8423 -122.4943 65.9 1 1 - PPP +BK MHDL 30 LY1 37.8423 -122.4943 65.9 1 1e6 DU/M PPP +BK MHDL 30 LY2 37.8423 -122.4943 65.9 1 1e6 DU/M PPP +BK MHDL 30 LY3 37.8423 -122.4943 65.9 1 1e6 DU/M PPP +CI MHMS 20 LYE 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 20 LYN 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 20 LYZ 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 20 LY1 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 20 LY2 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 20 LY3 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 20 LYQ 33.9391 -118.2441 -2.5 1 1 - PPP +CI MHMS 30 LYE 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 30 LYN 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 30 LYZ 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 30 LY1 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 30 LY2 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 30 LY3 33.9391 -118.2441 -2.5 1 1e6 DU/M PPP +CI MHMS 30 LYQ 33.9391 -118.2441 -2.5 1 1 - PPP +CI MIG1 20 LYE 34.0383 -120.3514 130.9 1 1e6 DU/M PPP +CI MIG1 20 LYN 34.0383 -120.3514 130.9 1 1e6 DU/M PPP +CI MIG1 20 LYZ 34.0383 -120.3514 130.9 1 1e6 DU/M PPP +CI MIG1 20 LY1 34.0383 -120.3514 130.9 1 1e6 DU/M PPP +CI MIG1 20 LY2 34.0383 -120.3514 130.9 1 1e6 DU/M PPP +CI MIG1 20 LY3 34.0383 -120.3514 130.9 1 1e6 DU/M PPP +CI MIG1 20 LYQ 34.0383 -120.3514 130.9 1 1 - PPP +CI MILK 20 LYE 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 20 LYN 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 20 LYZ 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 20 LY1 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 20 LY2 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 20 LY3 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 20 LYQ 34.1368 -118.1263 243.3 1 1 - PPP +CI MILK 30 LYE 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 30 LYN 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 30 LYZ 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 30 LY1 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 30 LY2 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 30 LY3 34.1368 -118.1263 243.3 1 1e6 DU/M PPP +CI MILK 30 LYQ 34.1368 -118.1263 243.3 1 1 - PPP +CI MJPK 20 LYE 33.7145 -117.5505 1528.0 1 1e6 DU/M PPP +CI MJPK 20 LYN 33.7145 -117.5505 1528.0 1 1e6 DU/M PPP +CI MJPK 20 LYZ 33.7145 -117.5505 1528.0 1 1e6 DU/M PPP +CI MJPK 20 LY1 33.7145 -117.5505 1528.0 1 1e6 DU/M PPP +CI MJPK 20 LY2 33.7145 -117.5505 1528.0 1 1e6 DU/M PPP +CI MJPK 20 LY3 33.7145 -117.5505 1528.0 1 1e6 DU/M PPP +CI MJPK 20 LYQ 33.7145 -117.5505 1528.0 1 1 - PPP +CI MLFP 20 LYE 33.9184 -117.3180 472.9 1 1e6 DU/M PPP +CI MLFP 20 LYN 33.9184 -117.3180 472.9 1 1e6 DU/M PPP +CI MLFP 20 LYZ 33.9184 -117.3180 472.9 1 1e6 DU/M PPP +CI MLFP 20 LY1 33.9184 -117.3180 472.9 1 1e6 DU/M PPP +CI MLFP 20 LY2 33.9184 -117.3180 472.9 1 1e6 DU/M PPP +CI MLFP 20 LY3 33.9184 -117.3180 472.9 1 1e6 DU/M PPP +CI MLFP 20 LYQ 33.9184 -117.3180 472.9 1 1 - PPP +BK MNRC 30 LYN 38.8787 -122.4428 707.8 1 1e6 DU/M PPP +BK MNRC 30 LYE 38.8787 -122.4428 707.8 1 1e6 DU/M PPP +BK MNRC 30 LYZ 38.8787 -122.4428 707.8 1 1e6 DU/M PPP +BK MNRC 30 LYQ 38.8787 -122.4428 707.8 1 1 - PPP +BK MNRC 30 LY1 38.8787 -122.4428 707.8 1 1e6 DU/M PPP +BK MNRC 30 LY2 38.8787 -122.4428 707.8 1 1e6 DU/M PPP +BK MNRC 30 LY3 38.8787 -122.4428 707.8 1 1e6 DU/M PPP +BK MODB 30 LYN 41.9023 -120.3028 1567.2 1 1e6 DU/M PPP +BK MODB 30 LYE 41.9023 -120.3028 1567.2 1 1e6 DU/M PPP +BK MODB 30 LYZ 41.9023 -120.3028 1567.2 1 1e6 DU/M PPP +BK MODB 30 LYQ 41.9023 -120.3028 1567.2 1 1 - PPP +BK MODB 30 LY1 41.9023 -120.3028 1567.2 1 1e6 DU/M PPP +BK MODB 30 LY2 41.9023 -120.3028 1567.2 1 1e6 DU/M PPP +BK MODB 30 LY3 41.9023 -120.3028 1567.2 1 1e6 DU/M PPP +CI MONP 20 LYE 32.8919 -116.4224 1842.5 1 1e6 DU/M PPP +CI MONP 20 LYN 32.8919 -116.4224 1842.5 1 1e6 DU/M PPP +CI MONP 20 LYZ 32.8919 -116.4224 1842.5 1 1e6 DU/M PPP +CI MONP 20 LY1 32.8919 -116.4224 1842.5 1 1e6 DU/M PPP +CI MONP 20 LY2 32.8919 -116.4224 1842.5 1 1e6 DU/M PPP +CI MONP 20 LY3 32.8919 -116.4224 1842.5 1 1e6 DU/M PPP +CI MONP 20 LYQ 32.8919 -116.4224 1842.5 1 1 - PPP +CI MPWD 20 LYE 34.2955 -118.8780 190.2 1 1e6 DU/M PPP +CI MPWD 20 LYN 34.2955 -118.8780 190.2 1 1e6 DU/M PPP +CI MPWD 20 LYZ 34.2955 -118.8780 190.2 1 1e6 DU/M PPP +CI MPWD 20 LY1 34.2955 -118.8780 190.2 1 1e6 DU/M PPP +CI MPWD 20 LY2 34.2955 -118.8780 190.2 1 1e6 DU/M PPP +CI MPWD 20 LY3 34.2955 -118.8780 190.2 1 1e6 DU/M PPP +CI MPWD 20 LYQ 34.2955 -118.8780 190.2 1 1 - PPP +CI MSCG 20 LYE 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 20 LYN 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 20 LYZ 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 20 LY1 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 20 LY2 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 20 LY3 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 20 LYQ 34.0385 -116.6480 913.1 1 1 - PPP +CI MSCG 40 LYE 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 40 LYN 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 40 LYZ 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 40 LY1 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 40 LY2 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 40 LY3 34.0385 -116.6480 913.1 1 1e6 DU/M PPP +CI MSCG 40 LYQ 34.0385 -116.6480 913.1 1 1 - PPP +CI MSOB 20 LYE 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 20 LYN 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 20 LYZ 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 20 LY1 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 20 LY2 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 20 LY3 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 20 LYQ 34.2308 -117.2101 1733.2 1 1 - PPP +CI MSOB 30 LYE 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 30 LYN 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 30 LYZ 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 30 LY1 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 30 LY2 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 30 LY3 34.2308 -117.2101 1733.2 1 1e6 DU/M PPP +CI MSOB 30 LYQ 34.2308 -117.2101 1733.2 1 1 - PPP +CI MTA1 20 LYE 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 20 LYN 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 20 LYZ 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 20 LY1 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 20 LY2 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 20 LY3 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 20 LYQ 34.0552 -118.2455 72.6 1 1 - PPP +CI MTA1 30 LYE 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 30 LYN 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 30 LYZ 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 30 LY1 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 30 LY2 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 30 LY3 34.0552 -118.2455 72.6 1 1e6 DU/M PPP +CI MTA1 30 LYQ 34.0552 -118.2455 72.6 1 1 - PPP +CI MTGG 20 LYE 33.1992 -116.6472 1066.7 1 1e6 DU/M PPP +CI MTGG 20 LYN 33.1992 -116.6472 1066.7 1 1e6 DU/M PPP +CI MTGG 20 LYZ 33.1992 -116.6472 1066.7 1 1e6 DU/M PPP +CI MTGG 20 LY1 33.1992 -116.6472 1066.7 1 1e6 DU/M PPP +CI MTGG 20 LY2 33.1992 -116.6472 1066.7 1 1e6 DU/M PPP +CI MTGG 20 LY3 33.1992 -116.6472 1066.7 1 1e6 DU/M PPP +CI MTGG 20 LYQ 33.1992 -116.6472 1066.7 1 1 - PPP +BK MTPK 30 LYN 37.4853 -121.8669 750.3 1 1e6 DU/M PPP +BK MTPK 30 LYE 37.4853 -121.8669 750.3 1 1e6 DU/M PPP +BK MTPK 30 LYZ 37.4853 -121.8669 750.3 1 1e6 DU/M PPP +BK MTPK 30 LYQ 37.4853 -121.8669 750.3 1 1 - PPP +BK MTPK 30 LY1 37.4853 -121.8669 750.3 1 1e6 DU/M PPP +BK MTPK 30 LY2 37.4853 -121.8669 750.3 1 1e6 DU/M PPP +BK MTPK 30 LY3 37.4853 -121.8669 750.3 1 1e6 DU/M PPP +CI MVFD 20 LYE 33.2109 -116.5253 1190.1 1 1e6 DU/M PPP +CI MVFD 20 LYN 33.2109 -116.5253 1190.1 1 1e6 DU/M PPP +CI MVFD 20 LYZ 33.2109 -116.5253 1190.1 1 1e6 DU/M PPP +CI MVFD 20 LY1 33.2109 -116.5253 1190.1 1 1e6 DU/M PPP +CI MVFD 20 LY2 33.2109 -116.5253 1190.1 1 1e6 DU/M PPP +CI MVFD 20 LY3 33.2109 -116.5253 1190.1 1 1e6 DU/M PPP +CI MVFD 20 LYQ 33.2109 -116.5253 1190.1 1 1 - PPP +CI NDAP 20 LYE 34.7677 -114.6186 241.3 1 1e6 DU/M PPP +CI NDAP 20 LYN 34.7677 -114.6186 241.3 1 1e6 DU/M PPP +CI NDAP 20 LYZ 34.7677 -114.6186 241.3 1 1e6 DU/M PPP +CI NDAP 20 LY1 34.7677 -114.6186 241.3 1 1e6 DU/M PPP +CI NDAP 20 LY2 34.7677 -114.6186 241.3 1 1e6 DU/M PPP +CI NDAP 20 LY3 34.7677 -114.6186 241.3 1 1e6 DU/M PPP +CI NDAP 20 LYQ 34.7677 -114.6186 241.3 1 1 - PPP +CI NHRG 20 LYE 34.4987 -119.1413 1648.7 1 1e6 DU/M PPP +CI NHRG 20 LYN 34.4987 -119.1413 1648.7 1 1e6 DU/M PPP +CI NHRG 20 LYZ 34.4987 -119.1413 1648.7 1 1e6 DU/M PPP +CI NHRG 20 LY1 34.4987 -119.1413 1648.7 1 1e6 DU/M PPP +CI NHRG 20 LY2 34.4987 -119.1413 1648.7 1 1e6 DU/M PPP +CI NHRG 20 LY3 34.4987 -119.1413 1648.7 1 1e6 DU/M PPP +CI NHRG 20 LYQ 34.4987 -119.1413 1648.7 1 1 - PPP +CI NOCO 20 LYE 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 20 LYN 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 20 LYZ 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 20 LY1 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 20 LY2 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 20 LY3 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 20 LYQ 33.9197 -117.5696 186.8 1 1 - PPP +CI NOCO 30 LYE 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 30 LYN 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 30 LYZ 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 30 LY1 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 30 LY2 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 30 LY3 33.9197 -117.5696 186.8 1 1e6 DU/M PPP +CI NOCO 30 LYQ 33.9197 -117.5696 186.8 1 1 - PPP +CI NOPK 20 LYE 33.9797 -118.3480 33.1 1 1e6 DU/M PPP +CI NOPK 20 LYN 33.9797 -118.3480 33.1 1 1e6 DU/M PPP +CI NOPK 20 LYZ 33.9797 -118.3480 33.1 1 1e6 DU/M PPP +CI NOPK 20 LY1 33.9797 -118.3480 33.1 1 1e6 DU/M PPP +CI NOPK 20 LY2 33.9797 -118.3480 33.1 1 1e6 DU/M PPP +CI NOPK 20 LY3 33.9797 -118.3480 33.1 1 1e6 DU/M PPP +CI NOPK 20 LYQ 33.9797 -118.3480 33.1 1 1 - PPP +CI NSSS 20 LYE 32.5793 -116.9727 123.6 1 1e6 DU/M PPP +CI NSSS 20 LYN 32.5793 -116.9727 123.6 1 1e6 DU/M PPP +CI NSSS 20 LYZ 32.5793 -116.9727 123.6 1 1e6 DU/M PPP +CI NSSS 20 LY1 32.5793 -116.9727 123.6 1 1e6 DU/M PPP +CI NSSS 20 LY2 32.5793 -116.9727 123.6 1 1e6 DU/M PPP +CI NSSS 20 LY3 32.5793 -116.9727 123.6 1 1e6 DU/M PPP +CI NSSS 20 LYQ 32.5793 -116.9727 123.6 1 1 - PPP +CI OAES 20 LYE 34.1410 -116.0677 604.8 1 1e6 DU/M PPP +CI OAES 20 LYN 34.1410 -116.0677 604.8 1 1e6 DU/M PPP +CI OAES 20 LYZ 34.1410 -116.0677 604.8 1 1e6 DU/M PPP +CI OAES 20 LY1 34.1410 -116.0677 604.8 1 1e6 DU/M PPP +CI OAES 20 LY2 34.1410 -116.0677 604.8 1 1e6 DU/M PPP +CI OAES 20 LY3 34.1410 -116.0677 604.8 1 1e6 DU/M PPP +CI OAES 20 LYQ 34.1410 -116.0677 604.8 1 1 - PPP +CI OCSD 20 LYE 33.2407 -117.3467 42.9 1 1e6 DU/M PPP +CI OCSD 20 LYN 33.2407 -117.3467 42.9 1 1e6 DU/M PPP +CI OCSD 20 LYZ 33.2407 -117.3467 42.9 1 1e6 DU/M PPP +CI OCSD 20 LY1 33.2407 -117.3467 42.9 1 1e6 DU/M PPP +CI OCSD 20 LY2 33.2407 -117.3467 42.9 1 1e6 DU/M PPP +CI OCSD 20 LY3 33.2407 -117.3467 42.9 1 1e6 DU/M PPP +CI OCSD 20 LYQ 33.2407 -117.3467 42.9 1 1 - PPP +CI OEOC 20 LYE 33.7659 -117.7441 358.6 1 1e6 DU/M PPP +CI OEOC 20 LYN 33.7659 -117.7441 358.6 1 1e6 DU/M PPP +CI OEOC 20 LYZ 33.7659 -117.7441 358.6 1 1e6 DU/M PPP +CI OEOC 20 LY1 33.7659 -117.7441 358.6 1 1e6 DU/M PPP +CI OEOC 20 LY2 33.7659 -117.7441 358.6 1 1e6 DU/M PPP +CI OEOC 20 LY3 33.7659 -117.7441 358.6 1 1e6 DU/M PPP +CI OEOC 20 LYQ 33.7659 -117.7441 358.6 1 1 - PPP +BK OHLN 30 LYN 38.0063 -122.2730 -0.6 1 1e6 DU/M PPP +BK OHLN 30 LYE 38.0063 -122.2730 -0.6 1 1e6 DU/M PPP +BK OHLN 30 LYZ 38.0063 -122.2730 -0.6 1 1e6 DU/M PPP +BK OHLN 30 LYQ 38.0063 -122.2730 -0.6 1 1 - PPP +BK OHLN 30 LY1 38.0063 -122.2730 -0.6 1 1e6 DU/M PPP +BK OHLN 30 LY2 38.0063 -122.2730 -0.6 1 1e6 DU/M PPP +BK OHLN 30 LY3 38.0063 -122.2730 -0.6 1 1e6 DU/M PPP +CI OPBL 20 LYE 34.3699 -115.9181 1226.5 1 1e6 DU/M PPP +CI OPBL 20 LYN 34.3699 -115.9181 1226.5 1 1e6 DU/M PPP +CI OPBL 20 LYZ 34.3699 -115.9181 1226.5 1 1e6 DU/M PPP +CI OPBL 20 LY1 34.3699 -115.9181 1226.5 1 1e6 DU/M PPP +CI OPBL 20 LY2 34.3699 -115.9181 1226.5 1 1e6 DU/M PPP +CI OPBL 20 LY3 34.3699 -115.9181 1226.5 1 1e6 DU/M PPP +CI OPBL 20 LYQ 34.3699 -115.9181 1226.5 1 1 - PPP +CI OPCL 20 LYE 34.4277 -116.3055 1312.8 1 1e6 DU/M PPP +CI OPCL 20 LYN 34.4277 -116.3055 1312.8 1 1e6 DU/M PPP +CI OPCL 20 LYZ 34.4277 -116.3055 1312.8 1 1e6 DU/M PPP +CI OPCL 20 LY1 34.4277 -116.3055 1312.8 1 1e6 DU/M PPP +CI OPCL 20 LY2 34.4277 -116.3055 1312.8 1 1e6 DU/M PPP +CI OPCL 20 LY3 34.4277 -116.3055 1312.8 1 1e6 DU/M PPP +CI OPCL 20 LYQ 34.4277 -116.3055 1312.8 1 1 - PPP +CI OPCP 20 LYE 34.3671 -116.0834 1096.7 1 1e6 DU/M PPP +CI OPCP 20 LYN 34.3671 -116.0834 1096.7 1 1e6 DU/M PPP +CI OPCP 20 LYZ 34.3671 -116.0834 1096.7 1 1e6 DU/M PPP +CI OPCP 20 LY1 34.3671 -116.0834 1096.7 1 1e6 DU/M PPP +CI OPCP 20 LY2 34.3671 -116.0834 1096.7 1 1e6 DU/M PPP +CI OPCP 20 LY3 34.3671 -116.0834 1096.7 1 1e6 DU/M PPP +CI OPCP 20 LYQ 34.3671 -116.0834 1096.7 1 1 - PPP +CI OPCX 20 LYE 34.4301 -116.1495 1133.8 1 1e6 DU/M PPP +CI OPCX 20 LYN 34.4301 -116.1495 1133.8 1 1e6 DU/M PPP +CI OPCX 20 LYZ 34.4301 -116.1495 1133.8 1 1e6 DU/M PPP +CI OPCX 20 LY1 34.4301 -116.1495 1133.8 1 1e6 DU/M PPP +CI OPCX 20 LY2 34.4301 -116.1495 1133.8 1 1e6 DU/M PPP +CI OPCX 20 LY3 34.4301 -116.1495 1133.8 1 1e6 DU/M PPP +CI OPCX 20 LYQ 34.4301 -116.1495 1133.8 1 1 - PPP +CI OPRD 20 LYE 34.5330 -116.2923 1400.2 1 1e6 DU/M PPP +CI OPRD 20 LYN 34.5330 -116.2923 1400.2 1 1e6 DU/M PPP +CI OPRD 20 LYZ 34.5330 -116.2923 1400.2 1 1e6 DU/M PPP +CI OPRD 20 LY1 34.5330 -116.2923 1400.2 1 1e6 DU/M PPP +CI OPRD 20 LY2 34.5330 -116.2923 1400.2 1 1e6 DU/M PPP +CI OPRD 20 LY3 34.5330 -116.2923 1400.2 1 1e6 DU/M PPP +CI OPRD 20 LYQ 34.5330 -116.2923 1400.2 1 1 - PPP +CI ORES 20 LYE 34.7391 -120.2786 143.6 1 1e6 DU/M PPP +CI ORES 20 LYN 34.7391 -120.2786 143.6 1 1e6 DU/M PPP +CI ORES 20 LYZ 34.7391 -120.2786 143.6 1 1e6 DU/M PPP +CI ORES 20 LY1 34.7391 -120.2786 143.6 1 1e6 DU/M PPP +CI ORES 20 LY2 34.7391 -120.2786 143.6 1 1e6 DU/M PPP +CI ORES 20 LY3 34.7391 -120.2786 143.6 1 1e6 DU/M PPP +CI ORES 20 LYQ 34.7391 -120.2786 143.6 1 1 - PPP +CI ORMT 20 LYE 34.6749 -116.8151 1893.3 1 1e6 DU/M PPP +CI ORMT 20 LYN 34.6749 -116.8151 1893.3 1 1e6 DU/M PPP +CI ORMT 20 LYZ 34.6749 -116.8151 1893.3 1 1e6 DU/M PPP +CI ORMT 20 LY1 34.6749 -116.8151 1893.3 1 1e6 DU/M PPP +CI ORMT 20 LY2 34.6749 -116.8151 1893.3 1 1e6 DU/M PPP +CI ORMT 20 LY3 34.6749 -116.8151 1893.3 1 1e6 DU/M PPP +CI ORMT 20 LYQ 34.6749 -116.8151 1893.3 1 1 - PPP +BK ORVB 30 LYN 39.5546 -121.5003 340.0 1 1e6 DU/M PPP +BK ORVB 30 LYE 39.5546 -121.5003 340.0 1 1e6 DU/M PPP +BK ORVB 30 LYZ 39.5546 -121.5003 340.0 1 1e6 DU/M PPP +BK ORVB 30 LYQ 39.5546 -121.5003 340.0 1 1 - PPP +BK ORVB 30 LY1 39.5546 -121.5003 340.0 1 1e6 DU/M PPP +BK ORVB 30 LY2 39.5546 -121.5003 340.0 1 1e6 DU/M PPP +BK ORVB 30 LY3 39.5546 -121.5003 340.0 1 1e6 DU/M PPP +CI OVLS 20 LYE 34.3274 -119.1420 69.1 1 1e6 DU/M PPP +CI OVLS 20 LYN 34.3274 -119.1420 69.1 1 1e6 DU/M PPP +CI OVLS 20 LYZ 34.3274 -119.1420 69.1 1 1e6 DU/M PPP +CI OVLS 20 LY1 34.3274 -119.1420 69.1 1 1e6 DU/M PPP +CI OVLS 20 LY2 34.3274 -119.1420 69.1 1 1e6 DU/M PPP +CI OVLS 20 LY3 34.3274 -119.1420 69.1 1 1e6 DU/M PPP +CI OVLS 20 LYQ 34.3274 -119.1420 69.1 1 1 - PPP +BK OXMT 30 LYN 37.4994 -122.4243 209.1 1 1e6 DU/M PPP +BK OXMT 30 LYE 37.4994 -122.4243 209.1 1 1e6 DU/M PPP +BK OXMT 30 LYZ 37.4994 -122.4243 209.1 1 1e6 DU/M PPP +BK OXMT 30 LYQ 37.4994 -122.4243 209.1 1 1 - PPP +BK OXMT 30 LY1 37.4994 -122.4243 209.1 1 1e6 DU/M PPP +BK OXMT 30 LY2 37.4994 -122.4243 209.1 1 1e6 DU/M PPP +BK OXMT 30 LY3 37.4994 -122.4243 209.1 1 1e6 DU/M PPP +CI OZST 20 LYE 34.6834 -119.3534 1059.2 1 1e6 DU/M PPP +CI OZST 20 LYN 34.6834 -119.3534 1059.2 1 1e6 DU/M PPP +CI OZST 20 LYZ 34.6834 -119.3534 1059.2 1 1e6 DU/M PPP +CI OZST 20 LY1 34.6834 -119.3534 1059.2 1 1e6 DU/M PPP +CI OZST 20 LY2 34.6834 -119.3534 1059.2 1 1e6 DU/M PPP +CI OZST 20 LY3 34.6834 -119.3534 1059.2 1 1e6 DU/M PPP +CI OZST 20 LYQ 34.6834 -119.3534 1059.2 1 1 - PPP +CI P066 20 LYE 32.6165 -116.1698 822.8 1 1e6 DU/M PPP +CI P066 20 LYN 32.6165 -116.1698 822.8 1 1e6 DU/M PPP +CI P066 20 LYZ 32.6165 -116.1698 822.8 1 1e6 DU/M PPP +CI P066 20 LY1 32.6165 -116.1698 822.8 1 1e6 DU/M PPP +CI P066 20 LY2 32.6165 -116.1698 822.8 1 1e6 DU/M PPP +CI P066 20 LY3 32.6165 -116.1698 822.8 1 1e6 DU/M PPP +CI P066 20 LYQ 32.6165 -116.1698 822.8 1 1 - PPP +CI P470 20 LYE 34.4624 -117.3939 991.4 1 1e6 DU/M PPP +CI P470 20 LYN 34.4624 -117.3939 991.4 1 1e6 DU/M PPP +CI P470 20 LYZ 34.4624 -117.3939 991.4 1 1e6 DU/M PPP +CI P470 20 LY1 34.4624 -117.3939 991.4 1 1e6 DU/M PPP +CI P470 20 LY2 34.4624 -117.3939 991.4 1 1e6 DU/M PPP +CI P470 20 LY3 34.4624 -117.3939 991.4 1 1e6 DU/M PPP +CI P470 20 LYQ 34.4624 -117.3939 991.4 1 1 - PPP +CI P471 20 LYE 33.5621 -117.5409 174.7 1 1e6 DU/M PPP +CI P471 20 LYN 33.5621 -117.5409 174.7 1 1e6 DU/M PPP +CI P471 20 LYZ 33.5621 -117.5409 174.7 1 1e6 DU/M PPP +CI P471 20 LY1 33.5621 -117.5409 174.7 1 1e6 DU/M PPP +CI P471 20 LY2 33.5621 -117.5409 174.7 1 1e6 DU/M PPP +CI P471 20 LY3 33.5621 -117.5409 174.7 1 1e6 DU/M PPP +CI P471 20 LYQ 33.5621 -117.5409 174.7 1 1 - PPP +CI P472 20 LYE 32.8892 -117.1047 137.7 1 1e6 DU/M PPP +CI P472 20 LYN 32.8892 -117.1047 137.7 1 1e6 DU/M PPP +CI P472 20 LYZ 32.8892 -117.1047 137.7 1 1e6 DU/M PPP +CI P472 20 LY1 32.8892 -117.1047 137.7 1 1e6 DU/M PPP +CI P472 20 LY2 32.8892 -117.1047 137.7 1 1e6 DU/M PPP +CI P472 20 LY3 32.8892 -117.1047 137.7 1 1e6 DU/M PPP +CI P472 20 LYQ 32.8892 -117.1047 137.7 1 1 - PPP +CI P473 20 LYE 32.7338 -116.9495 188.5 1 1e6 DU/M PPP +CI P473 20 LYN 32.7338 -116.9495 188.5 1 1e6 DU/M PPP +CI P473 20 LYZ 32.7338 -116.9495 188.5 1 1e6 DU/M PPP +CI P473 20 LY1 32.7338 -116.9495 188.5 1 1e6 DU/M PPP +CI P473 20 LY2 32.7338 -116.9495 188.5 1 1e6 DU/M PPP +CI P473 20 LY3 32.7338 -116.9495 188.5 1 1e6 DU/M PPP +CI P473 20 LYQ 32.7338 -116.9495 188.5 1 1 - PPP +CI P474 20 LYE 33.3552 -117.2487 182.8 1 1e6 DU/M PPP +CI P474 20 LYN 33.3552 -117.2487 182.8 1 1e6 DU/M PPP +CI P474 20 LYZ 33.3552 -117.2487 182.8 1 1e6 DU/M PPP +CI P474 20 LY1 33.3552 -117.2487 182.8 1 1e6 DU/M PPP +CI P474 20 LY2 33.3552 -117.2487 182.8 1 1e6 DU/M PPP +CI P474 20 LY3 33.3552 -117.2487 182.8 1 1e6 DU/M PPP +CI P474 20 LYQ 33.3552 -117.2487 182.8 1 1 - PPP +CI P475 20 LYE 32.6664 -117.2439 -25.1 1 1e6 DU/M PPP +CI P475 20 LYN 32.6664 -117.2439 -25.1 1 1e6 DU/M PPP +CI P475 20 LYZ 32.6664 -117.2439 -25.1 1 1e6 DU/M PPP +CI P475 20 LY1 32.6664 -117.2439 -25.1 1 1e6 DU/M PPP +CI P475 20 LY2 32.6664 -117.2439 -25.1 1 1e6 DU/M PPP +CI P475 20 LY3 32.6664 -117.2439 -25.1 1 1e6 DU/M PPP +CI P475 20 LYQ 32.6664 -117.2439 -25.1 1 1 - PPP +CI P476 20 LYE 33.4397 -117.1897 309.6 1 1e6 DU/M PPP +CI P476 20 LYN 33.4397 -117.1897 309.6 1 1e6 DU/M PPP +CI P476 20 LYZ 33.4397 -117.1897 309.6 1 1e6 DU/M PPP +CI P476 20 LY1 33.4397 -117.1897 309.6 1 1e6 DU/M PPP +CI P476 20 LY2 33.4397 -117.1897 309.6 1 1e6 DU/M PPP +CI P476 20 LY3 33.4397 -117.1897 309.6 1 1e6 DU/M PPP +CI P476 20 LYQ 33.4397 -117.1897 309.6 1 1 - PPP +CI P477 20 LYE 33.5028 -117.1134 334.5 1 1e6 DU/M PPP +CI P477 20 LYN 33.5028 -117.1134 334.5 1 1e6 DU/M PPP +CI P477 20 LYZ 33.5028 -117.1134 334.5 1 1e6 DU/M PPP +CI P477 20 LY1 33.5028 -117.1134 334.5 1 1e6 DU/M PPP +CI P477 20 LY2 33.5028 -117.1134 334.5 1 1e6 DU/M PPP +CI P477 20 LY3 33.5028 -117.1134 334.5 1 1e6 DU/M PPP +CI P477 20 LYQ 33.5028 -117.1134 334.5 1 1 - PPP +CI P478 20 LYE 33.2357 -117.0716 371.4 1 1e6 DU/M PPP +CI P478 20 LYN 33.2357 -117.0716 371.4 1 1e6 DU/M PPP +CI P478 20 LYZ 33.2357 -117.0716 371.4 1 1e6 DU/M PPP +CI P478 20 LY1 33.2357 -117.0716 371.4 1 1e6 DU/M PPP +CI P478 20 LY2 33.2357 -117.0716 371.4 1 1e6 DU/M PPP +CI P478 20 LY3 33.2357 -117.0716 371.4 1 1e6 DU/M PPP +CI P478 20 LYQ 33.2357 -117.0716 371.4 1 1 - PPP +CI P479 20 LYE 33.4933 -116.7829 1093.8 1 1e6 DU/M PPP +CI P479 20 LYN 33.4933 -116.7829 1093.8 1 1e6 DU/M PPP +CI P479 20 LYZ 33.4933 -116.7829 1093.8 1 1e6 DU/M PPP +CI P479 20 LY1 33.4933 -116.7829 1093.8 1 1e6 DU/M PPP +CI P479 20 LY2 33.4933 -116.7829 1093.8 1 1e6 DU/M PPP +CI P479 20 LY3 33.4933 -116.7829 1093.8 1 1e6 DU/M PPP +CI P479 20 LYQ 33.4933 -116.7829 1093.8 1 1 - PPP +CI P480 20 LYE 32.9760 -116.3485 435.9 1 1e6 DU/M PPP +CI P480 20 LYN 32.9760 -116.3485 435.9 1 1e6 DU/M PPP +CI P480 20 LYZ 32.9760 -116.3485 435.9 1 1e6 DU/M PPP +CI P480 20 LY1 32.9760 -116.3485 435.9 1 1e6 DU/M PPP +CI P480 20 LY2 32.9760 -116.3485 435.9 1 1e6 DU/M PPP +CI P480 20 LY3 32.9760 -116.3485 435.9 1 1e6 DU/M PPP +CI P480 20 LYQ 32.9760 -116.3485 435.9 1 1 - PPP +CI P481 20 LYE 32.8222 -116.0108 610.9 1 1e6 DU/M PPP +CI P481 20 LYN 32.8222 -116.0108 610.9 1 1e6 DU/M PPP +CI P481 20 LYZ 32.8222 -116.0108 610.9 1 1e6 DU/M PPP +CI P481 20 LY1 32.8222 -116.0108 610.9 1 1e6 DU/M PPP +CI P481 20 LY2 32.8222 -116.0108 610.9 1 1e6 DU/M PPP +CI P481 20 LY3 32.8222 -116.0108 610.9 1 1e6 DU/M PPP +CI P481 20 LYQ 32.8222 -116.0108 610.9 1 1 - PPP +CI P482 20 LYE 33.2402 -116.6714 878.5 1 1e6 DU/M PPP +CI P482 20 LYN 33.2402 -116.6714 878.5 1 1e6 DU/M PPP +CI P482 20 LYZ 33.2402 -116.6714 878.5 1 1e6 DU/M PPP +CI P482 20 LY1 33.2402 -116.6714 878.5 1 1e6 DU/M PPP +CI P482 20 LY2 33.2402 -116.6714 878.5 1 1e6 DU/M PPP +CI P482 20 LY3 33.2402 -116.6714 878.5 1 1e6 DU/M PPP +CI P482 20 LYQ 33.2402 -116.6714 878.5 1 1 - PPP +CI P483 20 LYE 33.0592 -116.5693 1375.4 1 1e6 DU/M PPP +CI P483 20 LYN 33.0592 -116.5693 1375.4 1 1e6 DU/M PPP +CI P483 20 LYZ 33.0592 -116.5693 1375.4 1 1e6 DU/M PPP +CI P483 20 LY1 33.0592 -116.5693 1375.4 1 1e6 DU/M PPP +CI P483 20 LY2 33.0592 -116.5693 1375.4 1 1e6 DU/M PPP +CI P483 20 LY3 33.0592 -116.5693 1375.4 1 1e6 DU/M PPP +CI P483 20 LYQ 33.0592 -116.5693 1375.4 1 1 - PPP +CI P484 20 LYE 33.3756 -116.6208 1382.3 1 1e6 DU/M PPP +CI P484 20 LYN 33.3756 -116.6208 1382.3 1 1e6 DU/M PPP +CI P484 20 LYZ 33.3756 -116.6208 1382.3 1 1e6 DU/M PPP +CI P484 20 LY1 33.3756 -116.6208 1382.3 1 1e6 DU/M PPP +CI P484 20 LY2 33.3756 -116.6208 1382.3 1 1e6 DU/M PPP +CI P484 20 LY3 33.3756 -116.6208 1382.3 1 1e6 DU/M PPP +CI P484 20 LYQ 33.3756 -116.6208 1382.3 1 1 - PPP +CI P485 20 LYE 33.2102 -116.4090 372.1 1 1e6 DU/M PPP +CI P485 20 LYN 33.2102 -116.4090 372.1 1 1e6 DU/M PPP +CI P485 20 LYZ 33.2102 -116.4090 372.1 1 1e6 DU/M PPP +CI P485 20 LY1 33.2102 -116.4090 372.1 1 1e6 DU/M PPP +CI P485 20 LY2 33.2102 -116.4090 372.1 1 1e6 DU/M PPP +CI P485 20 LY3 33.2102 -116.4090 372.1 1 1e6 DU/M PPP +CI P485 20 LYQ 33.2102 -116.4090 372.1 1 1 - PPP +CI P486 20 LYE 33.2602 -116.3223 126.3 1 1e6 DU/M PPP +CI P486 20 LYN 33.2602 -116.3223 126.3 1 1e6 DU/M PPP +CI P486 20 LYZ 33.2602 -116.3223 126.3 1 1e6 DU/M PPP +CI P486 20 LY1 33.2602 -116.3223 126.3 1 1e6 DU/M PPP +CI P486 20 LY2 33.2602 -116.3223 126.3 1 1e6 DU/M PPP +CI P486 20 LY3 33.2602 -116.3223 126.3 1 1e6 DU/M PPP +CI P486 20 LYQ 33.2602 -116.3223 126.3 1 1 - PPP +CI P487 20 LYE 33.2135 -116.1831 90.2 1 1e6 DU/M PPP +CI P487 20 LYN 33.2135 -116.1831 90.2 1 1e6 DU/M PPP +CI P487 20 LYZ 33.2135 -116.1831 90.2 1 1e6 DU/M PPP +CI P487 20 LY1 33.2135 -116.1831 90.2 1 1e6 DU/M PPP +CI P487 20 LY2 33.2135 -116.1831 90.2 1 1e6 DU/M PPP +CI P487 20 LY3 33.2135 -116.1831 90.2 1 1e6 DU/M PPP +CI P487 20 LYQ 33.2135 -116.1831 90.2 1 1 - PPP +CI P488 20 LYE 33.2010 -116.0788 61.7 1 1e6 DU/M PPP +CI P488 20 LYN 33.2010 -116.0788 61.7 1 1e6 DU/M PPP +CI P488 20 LYZ 33.2010 -116.0788 61.7 1 1e6 DU/M PPP +CI P488 20 LY1 33.2010 -116.0788 61.7 1 1e6 DU/M PPP +CI P488 20 LY2 33.2010 -116.0788 61.7 1 1e6 DU/M PPP +CI P488 20 LY3 33.2010 -116.0788 61.7 1 1e6 DU/M PPP +CI P488 20 LYQ 33.2010 -116.0788 61.7 1 1 - PPP +CI P489 20 LYE 33.2962 -116.1116 290.3 1 1e6 DU/M PPP +CI P489 20 LYN 33.2962 -116.1116 290.3 1 1e6 DU/M PPP +CI P489 20 LYZ 33.2962 -116.1116 290.3 1 1e6 DU/M PPP +CI P489 20 LY1 33.2962 -116.1116 290.3 1 1e6 DU/M PPP +CI P489 20 LY2 33.2962 -116.1116 290.3 1 1e6 DU/M PPP +CI P489 20 LY3 33.2962 -116.1116 290.3 1 1e6 DU/M PPP +CI P489 20 LYQ 33.2962 -116.1116 290.3 1 1 - PPP +CI P490 20 LYE 33.5235 -116.4259 2622.4 1 1e6 DU/M PPP +CI P490 20 LYN 33.5235 -116.4259 2622.4 1 1e6 DU/M PPP +CI P490 20 LYZ 33.5235 -116.4259 2622.4 1 1e6 DU/M PPP +CI P490 20 LY1 33.5235 -116.4259 2622.4 1 1e6 DU/M PPP +CI P490 20 LY2 33.5235 -116.4259 2622.4 1 1e6 DU/M PPP +CI P490 20 LY3 33.5235 -116.4259 2622.4 1 1e6 DU/M PPP +CI P490 20 LYQ 33.5235 -116.4259 2622.4 1 1 - PPP +CI P491 20 LYE 33.5747 -116.2268 4.2 1 1e6 DU/M PPP +CI P491 20 LYN 33.5747 -116.2268 4.2 1 1e6 DU/M PPP +CI P491 20 LYZ 33.5747 -116.2268 4.2 1 1e6 DU/M PPP +CI P491 20 LY1 33.5747 -116.2268 4.2 1 1e6 DU/M PPP +CI P491 20 LY2 33.5747 -116.2268 4.2 1 1e6 DU/M PPP +CI P491 20 LY3 33.5747 -116.2268 4.2 1 1e6 DU/M PPP +CI P491 20 LYQ 33.5747 -116.2268 4.2 1 1 - PPP +CI P492 20 LYE 32.8870 -115.9695 68.8 1 1e6 DU/M PPP +CI P492 20 LYN 32.8870 -115.9695 68.8 1 1e6 DU/M PPP +CI P492 20 LYZ 32.8870 -115.9695 68.8 1 1e6 DU/M PPP +CI P492 20 LY1 32.8870 -115.9695 68.8 1 1e6 DU/M PPP +CI P492 20 LY2 32.8870 -115.9695 68.8 1 1e6 DU/M PPP +CI P492 20 LY3 32.8870 -115.9695 68.8 1 1e6 DU/M PPP +CI P492 20 LYQ 32.8870 -115.9695 68.8 1 1 - PPP +CI P493 20 LYE 32.9547 -115.8249 197.5 1 1e6 DU/M PPP +CI P493 20 LYN 32.9547 -115.8249 197.5 1 1e6 DU/M PPP +CI P493 20 LYZ 32.9547 -115.8249 197.5 1 1e6 DU/M PPP +CI P493 20 LY1 32.9547 -115.8249 197.5 1 1e6 DU/M PPP +CI P493 20 LY2 32.9547 -115.8249 197.5 1 1e6 DU/M PPP +CI P493 20 LY3 32.9547 -115.8249 197.5 1 1e6 DU/M PPP +CI P493 20 LYQ 32.9547 -115.8249 197.5 1 1 - PPP +CI P494 20 LYE 32.7597 -115.7321 -44.3 1 1e6 DU/M PPP +CI P494 20 LYN 32.7597 -115.7321 -44.3 1 1e6 DU/M PPP +CI P494 20 LYZ 32.7597 -115.7321 -44.3 1 1e6 DU/M PPP +CI P494 20 LY1 32.7597 -115.7321 -44.3 1 1e6 DU/M PPP +CI P494 20 LY2 32.7597 -115.7321 -44.3 1 1e6 DU/M PPP +CI P494 20 LY3 32.7597 -115.7321 -44.3 1 1e6 DU/M PPP +CI P494 20 LYQ 32.7597 -115.7321 -44.3 1 1 - PPP +CI P495 20 LYE 33.0450 -115.6284 -84.1 1 1e6 DU/M PPP +CI P495 20 LYN 33.0450 -115.6284 -84.1 1 1e6 DU/M PPP +CI P495 20 LYZ 33.0450 -115.6284 -84.1 1 1e6 DU/M PPP +CI P495 20 LY1 33.0450 -115.6284 -84.1 1 1e6 DU/M PPP +CI P495 20 LY2 33.0450 -115.6284 -84.1 1 1e6 DU/M PPP +CI P495 20 LY3 33.0450 -115.6284 -84.1 1 1e6 DU/M PPP +CI P495 20 LYQ 33.0450 -115.6284 -84.1 1 1 - PPP +CI P496 20 LYE 32.7506 -115.5960 -40.1 1 1e6 DU/M PPP +CI P496 20 LYN 32.7506 -115.5960 -40.1 1 1e6 DU/M PPP +CI P496 20 LYZ 32.7506 -115.5960 -40.1 1 1e6 DU/M PPP +CI P496 20 LY1 32.7506 -115.5960 -40.1 1 1e6 DU/M PPP +CI P496 20 LY2 32.7506 -115.5960 -40.1 1 1e6 DU/M PPP +CI P496 20 LY3 32.7506 -115.5960 -40.1 1 1e6 DU/M PPP +CI P496 20 LYQ 32.7506 -115.5960 -40.1 1 1 - PPP +CI P497 20 LYE 32.8347 -115.5770 -50.9 1 1e6 DU/M PPP +CI P497 20 LYN 32.8347 -115.5770 -50.9 1 1e6 DU/M PPP +CI P497 20 LYZ 32.8347 -115.5770 -50.9 1 1e6 DU/M PPP +CI P497 20 LY1 32.8347 -115.5770 -50.9 1 1e6 DU/M PPP +CI P497 20 LY2 32.8347 -115.5770 -50.9 1 1e6 DU/M PPP +CI P497 20 LY3 32.8347 -115.5770 -50.9 1 1e6 DU/M PPP +CI P497 20 LYQ 32.8347 -115.5770 -50.9 1 1 - PPP +CI P498 20 LYE 32.8984 -115.5696 -58.1 1 1e6 DU/M PPP +CI P498 20 LYN 32.8984 -115.5696 -58.1 1 1e6 DU/M PPP +CI P498 20 LYZ 32.8984 -115.5696 -58.1 1 1e6 DU/M PPP +CI P498 20 LY1 32.8984 -115.5696 -58.1 1 1e6 DU/M PPP +CI P498 20 LY2 32.8984 -115.5696 -58.1 1 1e6 DU/M PPP +CI P498 20 LY3 32.8984 -115.5696 -58.1 1 1e6 DU/M PPP +CI P498 20 LYQ 32.8984 -115.5696 -58.1 1 1 - PPP +CI P499 20 LYE 32.9796 -115.4879 -74.3 1 1e6 DU/M PPP +CI P499 20 LYN 32.9796 -115.4879 -74.3 1 1e6 DU/M PPP +CI P499 20 LYZ 32.9796 -115.4879 -74.3 1 1e6 DU/M PPP +CI P499 20 LY1 32.9796 -115.4879 -74.3 1 1e6 DU/M PPP +CI P499 20 LY2 32.9796 -115.4879 -74.3 1 1e6 DU/M PPP +CI P499 20 LY3 32.9796 -115.4879 -74.3 1 1e6 DU/M PPP +CI P499 20 LYQ 32.9796 -115.4879 -74.3 1 1 - PPP +CI P500 20 LYE 32.6900 -115.2999 -20.9 1 1e6 DU/M PPP +CI P500 20 LYN 32.6900 -115.2999 -20.9 1 1e6 DU/M PPP +CI P500 20 LYZ 32.6900 -115.2999 -20.9 1 1e6 DU/M PPP +CI P500 20 LY1 32.6900 -115.2999 -20.9 1 1e6 DU/M PPP +CI P500 20 LY2 32.6900 -115.2999 -20.9 1 1e6 DU/M PPP +CI P500 20 LY3 32.6900 -115.2999 -20.9 1 1e6 DU/M PPP +CI P500 20 LYQ 32.6900 -115.2999 -20.9 1 1 - PPP +CI P501 20 LYE 32.8758 -115.3979 -55.7 1 1e6 DU/M PPP +CI P501 20 LYN 32.8758 -115.3979 -55.7 1 1e6 DU/M PPP +CI P501 20 LYZ 32.8758 -115.3979 -55.7 1 1e6 DU/M PPP +CI P501 20 LY1 32.8758 -115.3979 -55.7 1 1e6 DU/M PPP +CI P501 20 LY2 32.8758 -115.3979 -55.7 1 1e6 DU/M PPP +CI P501 20 LY3 32.8758 -115.3979 -55.7 1 1e6 DU/M PPP +CI P501 20 LYQ 32.8758 -115.3979 -55.7 1 1 - PPP +CI P502 20 LYE 32.9824 -115.4219 -66.0 1 1e6 DU/M PPP +CI P502 20 LYN 32.9824 -115.4219 -66.0 1 1e6 DU/M PPP +CI P502 20 LYZ 32.9824 -115.4219 -66.0 1 1e6 DU/M PPP +CI P502 20 LY1 32.9824 -115.4219 -66.0 1 1e6 DU/M PPP +CI P502 20 LY2 32.9824 -115.4219 -66.0 1 1e6 DU/M PPP +CI P502 20 LY3 32.9824 -115.4219 -66.0 1 1e6 DU/M PPP +CI P502 20 LYQ 32.9824 -115.4219 -66.0 1 1 - PPP +CI P503 20 LYE 32.9489 -115.7202 6.1 1 1e6 DU/M PPP +CI P503 20 LYN 32.9489 -115.7202 6.1 1 1e6 DU/M PPP +CI P503 20 LYZ 32.9489 -115.7202 6.1 1 1e6 DU/M PPP +CI P503 20 LY1 32.9489 -115.7202 6.1 1 1e6 DU/M PPP +CI P503 20 LY2 32.9489 -115.7202 6.1 1 1e6 DU/M PPP +CI P503 20 LY3 32.9489 -115.7202 6.1 1 1e6 DU/M PPP +CI P503 20 LYQ 32.9489 -115.7202 6.1 1 1 - PPP +CI P504 20 LYE 33.5164 -115.7659 84.0 1 1e6 DU/M PPP +CI P504 20 LYN 33.5164 -115.7659 84.0 1 1e6 DU/M PPP +CI P504 20 LYZ 33.5164 -115.7659 84.0 1 1e6 DU/M PPP +CI P504 20 LY1 33.5164 -115.7659 84.0 1 1e6 DU/M PPP +CI P504 20 LY2 33.5164 -115.7659 84.0 1 1e6 DU/M PPP +CI P504 20 LY3 33.5164 -115.7659 84.0 1 1e6 DU/M PPP +CI P504 20 LYQ 33.5164 -115.7659 84.0 1 1 - PPP +CI P505 20 LYE 33.4239 -115.6870 -57.8 1 1e6 DU/M PPP +CI P505 20 LYN 33.4239 -115.6870 -57.8 1 1e6 DU/M PPP +CI P505 20 LYZ 33.4239 -115.6870 -57.8 1 1e6 DU/M PPP +CI P505 20 LY1 33.4239 -115.6870 -57.8 1 1e6 DU/M PPP +CI P505 20 LY2 33.4239 -115.6870 -57.8 1 1e6 DU/M PPP +CI P505 20 LY3 33.4239 -115.6870 -57.8 1 1e6 DU/M PPP +CI P505 20 LYQ 33.4239 -115.6870 -57.8 1 1 - PPP +CI P506 20 LYE 33.0814 -115.5102 -83.4 1 1e6 DU/M PPP +CI P506 20 LYN 33.0814 -115.5102 -83.4 1 1e6 DU/M PPP +CI P506 20 LYZ 33.0814 -115.5102 -83.4 1 1e6 DU/M PPP +CI P506 20 LY1 33.0814 -115.5102 -83.4 1 1e6 DU/M PPP +CI P506 20 LY2 33.0814 -115.5102 -83.4 1 1e6 DU/M PPP +CI P506 20 LY3 33.0814 -115.5102 -83.4 1 1e6 DU/M PPP +CI P506 20 LYQ 33.0814 -115.5102 -83.4 1 1 - PPP +CI P507 20 LYE 33.2000 -115.6124 -78.6 1 1e6 DU/M PPP +CI P507 20 LYN 33.2000 -115.6124 -78.6 1 1e6 DU/M PPP +CI P507 20 LYZ 33.2000 -115.6124 -78.6 1 1e6 DU/M PPP +CI P507 20 LY1 33.2000 -115.6124 -78.6 1 1e6 DU/M PPP +CI P507 20 LY2 33.2000 -115.6124 -78.6 1 1e6 DU/M PPP +CI P507 20 LY3 33.2000 -115.6124 -78.6 1 1e6 DU/M PPP +CI P507 20 LYQ 33.2000 -115.6124 -78.6 1 1 - PPP +CI P508 20 LYE 33.2478 -115.4287 10.8 1 1e6 DU/M PPP +CI P508 20 LYN 33.2478 -115.4287 10.8 1 1e6 DU/M PPP +CI P508 20 LYZ 33.2478 -115.4287 10.8 1 1e6 DU/M PPP +CI P508 20 LY1 33.2478 -115.4287 10.8 1 1e6 DU/M PPP +CI P508 20 LY2 33.2478 -115.4287 10.8 1 1e6 DU/M PPP +CI P508 20 LY3 33.2478 -115.4287 10.8 1 1e6 DU/M PPP +CI P508 20 LYQ 33.2478 -115.4287 10.8 1 1 - PPP +CI P509 20 LYE 32.8907 -115.2939 -29.6 1 1e6 DU/M PPP +CI P509 20 LYN 32.8907 -115.2939 -29.6 1 1e6 DU/M PPP +CI P509 20 LYZ 32.8907 -115.2939 -29.6 1 1e6 DU/M PPP +CI P509 20 LY1 32.8907 -115.2939 -29.6 1 1e6 DU/M PPP +CI P509 20 LY2 32.8907 -115.2939 -29.6 1 1e6 DU/M PPP +CI P509 20 LY3 32.8907 -115.2939 -29.6 1 1e6 DU/M PPP +CI P509 20 LYQ 32.8907 -115.2939 -29.6 1 1 - PPP +CI P510 20 LYE 33.1436 -115.3433 1.6 1 1e6 DU/M PPP +CI P510 20 LYN 33.1436 -115.3433 1.6 1 1e6 DU/M PPP +CI P510 20 LYZ 33.1436 -115.3433 1.6 1 1e6 DU/M PPP +CI P510 20 LY1 33.1436 -115.3433 1.6 1 1e6 DU/M PPP +CI P510 20 LY2 33.1436 -115.3433 1.6 1 1e6 DU/M PPP +CI P510 20 LY3 33.1436 -115.3433 1.6 1 1e6 DU/M PPP +CI P510 20 LYQ 33.1436 -115.3433 1.6 1 1 - PPP +CI P511 20 LYE 33.8869 -115.2961 273.3 1 1e6 DU/M PPP +CI P511 20 LYN 33.8869 -115.2961 273.3 1 1e6 DU/M PPP +CI P511 20 LYZ 33.8869 -115.2961 273.3 1 1e6 DU/M PPP +CI P511 20 LY1 33.8869 -115.2961 273.3 1 1e6 DU/M PPP +CI P511 20 LY2 33.8869 -115.2961 273.3 1 1e6 DU/M PPP +CI P511 20 LY3 33.8869 -115.2961 273.3 1 1e6 DU/M PPP +CI P511 20 LYQ 33.8869 -115.2961 273.3 1 1 - PPP +CI P513 20 LYE 34.9073 -120.6502 284.6 1 1e6 DU/M PPP +CI P513 20 LYN 34.9073 -120.6502 284.6 1 1e6 DU/M PPP +CI P513 20 LYZ 34.9073 -120.6502 284.6 1 1e6 DU/M PPP +CI P513 20 LY1 34.9073 -120.6502 284.6 1 1e6 DU/M PPP +CI P513 20 LY2 34.9073 -120.6502 284.6 1 1e6 DU/M PPP +CI P513 20 LY3 34.9073 -120.6502 284.6 1 1e6 DU/M PPP +CI P513 20 LYQ 34.9073 -120.6502 284.6 1 1 - PPP +CI P514 20 LYE 35.0107 -120.4098 140.9 1 1e6 DU/M PPP +CI P514 20 LYN 35.0107 -120.4098 140.9 1 1e6 DU/M PPP +CI P514 20 LYZ 35.0107 -120.4098 140.9 1 1e6 DU/M PPP +CI P514 20 LY1 35.0107 -120.4098 140.9 1 1e6 DU/M PPP +CI P514 20 LY2 35.0107 -120.4098 140.9 1 1e6 DU/M PPP +CI P514 20 LY3 35.0107 -120.4098 140.9 1 1e6 DU/M PPP +CI P514 20 LYQ 35.0107 -120.4098 140.9 1 1 - PPP +CI P515 20 LYE 34.8706 -120.2399 290.6 1 1e6 DU/M PPP +CI P515 20 LYN 34.8706 -120.2399 290.6 1 1e6 DU/M PPP +CI P515 20 LYZ 34.8706 -120.2399 290.6 1 1e6 DU/M PPP +CI P515 20 LY1 34.8706 -120.2399 290.6 1 1e6 DU/M PPP +CI P515 20 LY2 34.8706 -120.2399 290.6 1 1e6 DU/M PPP +CI P515 20 LY3 34.8706 -120.2399 290.6 1 1e6 DU/M PPP +CI P515 20 LYQ 34.8706 -120.2399 290.6 1 1 - PPP +CI P516 20 LYE 35.1062 -120.3834 263.0 1 1e6 DU/M PPP +CI P516 20 LYN 35.1062 -120.3834 263.0 1 1e6 DU/M PPP +CI P516 20 LYZ 35.1062 -120.3834 263.0 1 1e6 DU/M PPP +CI P516 20 LY1 35.1062 -120.3834 263.0 1 1e6 DU/M PPP +CI P516 20 LY2 35.1062 -120.3834 263.0 1 1e6 DU/M PPP +CI P516 20 LY3 35.1062 -120.3834 263.0 1 1e6 DU/M PPP +CI P516 20 LYQ 35.1062 -120.3834 263.0 1 1 - PPP +CI P517 20 LYE 34.3764 -118.1776 1959.1 1 1e6 DU/M PPP +CI P517 20 LYN 34.3764 -118.1776 1959.1 1 1e6 DU/M PPP +CI P517 20 LYZ 34.3764 -118.1776 1959.1 1 1e6 DU/M PPP +CI P517 20 LY1 34.3764 -118.1776 1959.1 1 1e6 DU/M PPP +CI P517 20 LY2 34.3764 -118.1776 1959.1 1 1e6 DU/M PPP +CI P517 20 LY3 34.3764 -118.1776 1959.1 1 1e6 DU/M PPP +CI P517 20 LYQ 34.3764 -118.1776 1959.1 1 1 - PPP +CI P518 20 LYE 35.0200 -120.0753 1101.8 1 1e6 DU/M PPP +CI P518 20 LYN 35.0200 -120.0753 1101.8 1 1e6 DU/M PPP +CI P518 20 LYZ 35.0200 -120.0753 1101.8 1 1e6 DU/M PPP +CI P518 20 LY1 35.0200 -120.0753 1101.8 1 1e6 DU/M PPP +CI P518 20 LY2 35.0200 -120.0753 1101.8 1 1e6 DU/M PPP +CI P518 20 LY3 35.0200 -120.0753 1101.8 1 1e6 DU/M PPP +CI P518 20 LYQ 35.0200 -120.0753 1101.8 1 1 - PPP +CI P519 20 LYE 34.5078 -119.7924 810.9 1 1e6 DU/M PPP +CI P519 20 LYN 34.5078 -119.7924 810.9 1 1e6 DU/M PPP +CI P519 20 LYZ 34.5078 -119.7924 810.9 1 1e6 DU/M PPP +CI P519 20 LY1 34.5078 -119.7924 810.9 1 1e6 DU/M PPP +CI P519 20 LY2 34.5078 -119.7924 810.9 1 1e6 DU/M PPP +CI P519 20 LY3 34.5078 -119.7924 810.9 1 1e6 DU/M PPP +CI P519 20 LYQ 34.5078 -119.7924 810.9 1 1 - PPP +CI P520 20 LYE 34.6305 -119.6164 1250.8 1 1e6 DU/M PPP +CI P520 20 LYN 34.6305 -119.6164 1250.8 1 1e6 DU/M PPP +CI P520 20 LYZ 34.6305 -119.6164 1250.8 1 1e6 DU/M PPP +CI P520 20 LY1 34.6305 -119.6164 1250.8 1 1e6 DU/M PPP +CI P520 20 LY2 34.6305 -119.6164 1250.8 1 1e6 DU/M PPP +CI P520 20 LY3 34.6305 -119.6164 1250.8 1 1e6 DU/M PPP +CI P520 20 LYQ 34.6305 -119.6164 1250.8 1 1 - PPP +CI P521 20 LYE 34.8886 -119.8154 1709.1 1 1e6 DU/M PPP +CI P521 20 LYN 34.8886 -119.8154 1709.1 1 1e6 DU/M PPP +CI P521 20 LYZ 34.8886 -119.8154 1709.1 1 1e6 DU/M PPP +CI P521 20 LY1 34.8886 -119.8154 1709.1 1 1e6 DU/M PPP +CI P521 20 LY2 34.8886 -119.8154 1709.1 1 1e6 DU/M PPP +CI P521 20 LY3 34.8886 -119.8154 1709.1 1 1e6 DU/M PPP +CI P521 20 LYQ 34.8886 -119.8154 1709.1 1 1 - PPP +CI P522 20 LYE 35.0866 -119.5361 991.1 1 1e6 DU/M PPP +CI P522 20 LYN 35.0866 -119.5361 991.1 1 1e6 DU/M PPP +CI P522 20 LYZ 35.0866 -119.5361 991.1 1 1e6 DU/M PPP +CI P522 20 LY1 35.0866 -119.5361 991.1 1 1e6 DU/M PPP +CI P522 20 LY2 35.0866 -119.5361 991.1 1 1e6 DU/M PPP +CI P522 20 LY3 35.0866 -119.5361 991.1 1 1e6 DU/M PPP +CI P522 20 LYQ 35.0866 -119.5361 991.1 1 1 - PPP +CI P548 20 LYE 34.4668 -119.5040 1134.8 1 1e6 DU/M PPP +CI P548 20 LYN 34.4668 -119.5040 1134.8 1 1e6 DU/M PPP +CI P548 20 LYZ 34.4668 -119.5040 1134.8 1 1e6 DU/M PPP +CI P548 20 LY1 34.4668 -119.5040 1134.8 1 1e6 DU/M PPP +CI P548 20 LY2 34.4668 -119.5040 1134.8 1 1e6 DU/M PPP +CI P548 20 LY3 34.4668 -119.5040 1134.8 1 1e6 DU/M PPP +CI P548 20 LYQ 34.4668 -119.5040 1134.8 1 1 - PPP +CI P551 20 LYE 34.8562 -119.1546 1550.3 1 1e6 DU/M PPP +CI P551 20 LYN 34.8562 -119.1546 1550.3 1 1e6 DU/M PPP +CI P551 20 LYZ 34.8562 -119.1546 1550.3 1 1e6 DU/M PPP +CI P551 20 LY1 34.8562 -119.1546 1550.3 1 1e6 DU/M PPP +CI P551 20 LY2 34.8562 -119.1546 1550.3 1 1e6 DU/M PPP +CI P551 20 LY3 34.8562 -119.1546 1550.3 1 1e6 DU/M PPP +CI P551 20 LYQ 34.8562 -119.1546 1550.3 1 1 - PPP +CI P553 20 LYE 34.8351 -118.8790 1335.7 1 1e6 DU/M PPP +CI P553 20 LYN 34.8351 -118.8790 1335.7 1 1e6 DU/M PPP +CI P553 20 LYZ 34.8351 -118.8790 1335.7 1 1e6 DU/M PPP +CI P553 20 LY1 34.8351 -118.8790 1335.7 1 1e6 DU/M PPP +CI P553 20 LY2 34.8351 -118.8790 1335.7 1 1e6 DU/M PPP +CI P553 20 LY3 34.8351 -118.8790 1335.7 1 1e6 DU/M PPP +CI P553 20 LYQ 34.8351 -118.8790 1335.7 1 1 - PPP +CI P554 20 LYE 34.7923 -118.8480 1170.1 1 1e6 DU/M PPP +CI P554 20 LYN 34.7923 -118.8480 1170.1 1 1e6 DU/M PPP +CI P554 20 LYZ 34.7923 -118.8480 1170.1 1 1e6 DU/M PPP +CI P554 20 LY1 34.7923 -118.8480 1170.1 1 1e6 DU/M PPP +CI P554 20 LY2 34.7923 -118.8480 1170.1 1 1e6 DU/M PPP +CI P554 20 LY3 34.7923 -118.8480 1170.1 1 1e6 DU/M PPP +CI P554 20 LYQ 34.7923 -118.8480 1170.1 1 1 - PPP +CI P555 20 LYE 34.6950 -118.6694 1096.0 1 1e6 DU/M PPP +CI P555 20 LYN 34.6950 -118.6694 1096.0 1 1e6 DU/M PPP +CI P555 20 LYZ 34.6950 -118.6694 1096.0 1 1e6 DU/M PPP +CI P555 20 LY1 34.6950 -118.6694 1096.0 1 1e6 DU/M PPP +CI P555 20 LY2 34.6950 -118.6694 1096.0 1 1e6 DU/M PPP +CI P555 20 LY3 34.6950 -118.6694 1096.0 1 1e6 DU/M PPP +CI P555 20 LYQ 34.6950 -118.6694 1096.0 1 1 - PPP +CI P556 20 LYE 34.7711 -118.5455 852.6 1 1e6 DU/M PPP +CI P556 20 LYN 34.7711 -118.5455 852.6 1 1e6 DU/M PPP +CI P556 20 LYZ 34.7711 -118.5455 852.6 1 1e6 DU/M PPP +CI P556 20 LY1 34.7711 -118.5455 852.6 1 1e6 DU/M PPP +CI P556 20 LY2 34.7711 -118.5455 852.6 1 1e6 DU/M PPP +CI P556 20 LY3 34.7711 -118.5455 852.6 1 1e6 DU/M PPP +CI P556 20 LYQ 34.7711 -118.5455 852.6 1 1 - PPP +CI P557 20 LYE 34.9444 -118.6556 1818.2 1 1e6 DU/M PPP +CI P557 20 LYN 34.9444 -118.6556 1818.2 1 1e6 DU/M PPP +CI P557 20 LYZ 34.9444 -118.6556 1818.2 1 1e6 DU/M PPP +CI P557 20 LY1 34.9444 -118.6556 1818.2 1 1e6 DU/M PPP +CI P557 20 LY2 34.9444 -118.6556 1818.2 1 1e6 DU/M PPP +CI P557 20 LY3 34.9444 -118.6556 1818.2 1 1e6 DU/M PPP +CI P557 20 LYQ 34.9444 -118.6556 1818.2 1 1 - PPP +CI P558 20 LYE 35.1386 -118.6117 1411.4 1 1e6 DU/M PPP +CI P558 20 LYN 35.1386 -118.6117 1411.4 1 1e6 DU/M PPP +CI P558 20 LYZ 35.1386 -118.6117 1411.4 1 1e6 DU/M PPP +CI P558 20 LY1 35.1386 -118.6117 1411.4 1 1e6 DU/M PPP +CI P558 20 LY2 35.1386 -118.6117 1411.4 1 1e6 DU/M PPP +CI P558 20 LY3 35.1386 -118.6117 1411.4 1 1e6 DU/M PPP +CI P558 20 LYQ 35.1386 -118.6117 1411.4 1 1 - PPP +CI P560 20 LYE 34.8218 -118.5409 838.3 1 1e6 DU/M PPP +CI P560 20 LYN 34.8218 -118.5409 838.3 1 1e6 DU/M PPP +CI P560 20 LYZ 34.8218 -118.5409 838.3 1 1e6 DU/M PPP +CI P560 20 LY1 34.8218 -118.5409 838.3 1 1e6 DU/M PPP +CI P560 20 LY2 34.8218 -118.5409 838.3 1 1e6 DU/M PPP +CI P560 20 LY3 34.8218 -118.5409 838.3 1 1e6 DU/M PPP +CI P560 20 LYQ 34.8218 -118.5409 838.3 1 1 - PPP +CI P561 20 LYE 34.6185 -118.3991 974.4 1 1e6 DU/M PPP +CI P561 20 LYN 34.6185 -118.3991 974.4 1 1e6 DU/M PPP +CI P561 20 LYZ 34.6185 -118.3991 974.4 1 1e6 DU/M PPP +CI P561 20 LY1 34.6185 -118.3991 974.4 1 1e6 DU/M PPP +CI P561 20 LY2 34.6185 -118.3991 974.4 1 1e6 DU/M PPP +CI P561 20 LY3 34.6185 -118.3991 974.4 1 1e6 DU/M PPP +CI P561 20 LYQ 34.6185 -118.3991 974.4 1 1 - PPP +CI P574 20 LYE 34.2868 -117.6339 2873.8 1 1e6 DU/M PPP +CI P574 20 LYN 34.2868 -117.6339 2873.8 1 1e6 DU/M PPP +CI P574 20 LYZ 34.2868 -117.6339 2873.8 1 1e6 DU/M PPP +CI P574 20 LY1 34.2868 -117.6339 2873.8 1 1e6 DU/M PPP +CI P574 20 LY2 34.2868 -117.6339 2873.8 1 1e6 DU/M PPP +CI P574 20 LY3 34.2868 -117.6339 2873.8 1 1e6 DU/M PPP +CI P574 20 LYQ 34.2868 -117.6339 2873.8 1 1 - PPP +CI P575 20 LYE 34.2155 -117.5422 1928.4 1 1e6 DU/M PPP +CI P575 20 LYN 34.2155 -117.5422 1928.4 1 1e6 DU/M PPP +CI P575 20 LYZ 34.2155 -117.5422 1928.4 1 1e6 DU/M PPP +CI P575 20 LY1 34.2155 -117.5422 1928.4 1 1e6 DU/M PPP +CI P575 20 LY2 34.2155 -117.5422 1928.4 1 1e6 DU/M PPP +CI P575 20 LY3 34.2155 -117.5422 1928.4 1 1e6 DU/M PPP +CI P575 20 LYQ 34.2155 -117.5422 1928.4 1 1 - PPP +CI P577 20 LYE 34.3046 -117.3189 999.4 1 1e6 DU/M PPP +CI P577 20 LYN 34.3046 -117.3189 999.4 1 1e6 DU/M PPP +CI P577 20 LYZ 34.3046 -117.3189 999.4 1 1e6 DU/M PPP +CI P577 20 LY1 34.3046 -117.3189 999.4 1 1e6 DU/M PPP +CI P577 20 LY2 34.3046 -117.3189 999.4 1 1e6 DU/M PPP +CI P577 20 LY3 34.3046 -117.3189 999.4 1 1e6 DU/M PPP +CI P577 20 LYQ 34.3046 -117.3189 999.4 1 1 - PPP +CI P579 20 LYE 35.0388 -118.0058 834.2 1 1e6 DU/M PPP +CI P579 20 LYN 35.0388 -118.0058 834.2 1 1e6 DU/M PPP +CI P579 20 LYZ 35.0388 -118.0058 834.2 1 1e6 DU/M PPP +CI P579 20 LY1 35.0388 -118.0058 834.2 1 1e6 DU/M PPP +CI P579 20 LY2 35.0388 -118.0058 834.2 1 1e6 DU/M PPP +CI P579 20 LY3 35.0388 -118.0058 834.2 1 1e6 DU/M PPP +CI P579 20 LYQ 35.0388 -118.0058 834.2 1 1 - PPP +CI P581 20 LYE 34.5097 -117.7290 972.8 1 1e6 DU/M PPP +CI P581 20 LYN 34.5097 -117.7290 972.8 1 1e6 DU/M PPP +CI P581 20 LYZ 34.5097 -117.7290 972.8 1 1e6 DU/M PPP +CI P581 20 LY1 34.5097 -117.7290 972.8 1 1e6 DU/M PPP +CI P581 20 LY2 34.5097 -117.7290 972.8 1 1e6 DU/M PPP +CI P581 20 LY3 34.5097 -117.7290 972.8 1 1e6 DU/M PPP +CI P581 20 LYQ 34.5097 -117.7290 972.8 1 1 - PPP +CI P582 20 LYE 34.6343 -117.5489 848.0 1 1e6 DU/M PPP +CI P582 20 LYN 34.6343 -117.5489 848.0 1 1e6 DU/M PPP +CI P582 20 LYZ 34.6343 -117.5489 848.0 1 1e6 DU/M PPP +CI P582 20 LY1 34.6343 -117.5489 848.0 1 1e6 DU/M PPP +CI P582 20 LY2 34.6343 -117.5489 848.0 1 1e6 DU/M PPP +CI P582 20 LY3 34.6343 -117.5489 848.0 1 1e6 DU/M PPP +CI P582 20 LYQ 34.6343 -117.5489 848.0 1 1 - PPP +CI P583 20 LYE 34.9870 -117.5434 730.8 1 1e6 DU/M PPP +CI P583 20 LYN 34.9870 -117.5434 730.8 1 1e6 DU/M PPP +CI P583 20 LYZ 34.9870 -117.5434 730.8 1 1e6 DU/M PPP +CI P583 20 LY1 34.9870 -117.5434 730.8 1 1e6 DU/M PPP +CI P583 20 LY2 34.9870 -117.5434 730.8 1 1e6 DU/M PPP +CI P583 20 LY3 34.9870 -117.5434 730.8 1 1e6 DU/M PPP +CI P583 20 LYQ 34.9870 -117.5434 730.8 1 1 - PPP +CI P584 20 LYE 33.8926 -116.9516 738.6 1 1e6 DU/M PPP +CI P584 20 LYN 33.8926 -116.9516 738.6 1 1e6 DU/M PPP +CI P584 20 LYZ 33.8926 -116.9516 738.6 1 1e6 DU/M PPP +CI P584 20 LY1 33.8926 -116.9516 738.6 1 1e6 DU/M PPP +CI P584 20 LY2 33.8926 -116.9516 738.6 1 1e6 DU/M PPP +CI P584 20 LY3 33.8926 -116.9516 738.6 1 1e6 DU/M PPP +CI P584 20 LYQ 33.8926 -116.9516 738.6 1 1 - PPP +CI P585 20 LYE 34.0193 -116.5457 958.1 1 1e6 DU/M PPP +CI P585 20 LYN 34.0193 -116.5457 958.1 1 1e6 DU/M PPP +CI P585 20 LYZ 34.0193 -116.5457 958.1 1 1e6 DU/M PPP +CI P585 20 LY1 34.0193 -116.5457 958.1 1 1e6 DU/M PPP +CI P585 20 LY2 34.0193 -116.5457 958.1 1 1e6 DU/M PPP +CI P585 20 LY3 34.0193 -116.5457 958.1 1 1e6 DU/M PPP +CI P585 20 LYQ 34.0193 -116.5457 958.1 1 1 - PPP +CI P586 20 LYE 34.5348 -117.2805 809.4 1 1e6 DU/M PPP +CI P586 20 LYN 34.5348 -117.2805 809.4 1 1e6 DU/M PPP +CI P586 20 LYZ 34.5348 -117.2805 809.4 1 1e6 DU/M PPP +CI P586 20 LY1 34.5348 -117.2805 809.4 1 1e6 DU/M PPP +CI P586 20 LY2 34.5348 -117.2805 809.4 1 1e6 DU/M PPP +CI P586 20 LY3 34.5348 -117.2805 809.4 1 1e6 DU/M PPP +CI P586 20 LYQ 34.5348 -117.2805 809.4 1 1 - PPP +CI P587 20 LYE 34.3322 -118.0313 1600.8 1 1e6 DU/M PPP +CI P587 20 LYN 34.3322 -118.0313 1600.8 1 1e6 DU/M PPP +CI P587 20 LYZ 34.3322 -118.0313 1600.8 1 1e6 DU/M PPP +CI P587 20 LY1 34.3322 -118.0313 1600.8 1 1e6 DU/M PPP +CI P587 20 LY2 34.3322 -118.0313 1600.8 1 1e6 DU/M PPP +CI P587 20 LY3 34.3322 -118.0313 1600.8 1 1e6 DU/M PPP +CI P587 20 LYQ 34.3322 -118.0313 1600.8 1 1 - PPP +CI P589 20 LYE 34.6207 -117.1102 1148.0 1 1e6 DU/M PPP +CI P589 20 LYN 34.6207 -117.1102 1148.0 1 1e6 DU/M PPP +CI P589 20 LYZ 34.6207 -117.1102 1148.0 1 1e6 DU/M PPP +CI P589 20 LY1 34.6207 -117.1102 1148.0 1 1e6 DU/M PPP +CI P589 20 LY2 34.6207 -117.1102 1148.0 1 1e6 DU/M PPP +CI P589 20 LY3 34.6207 -117.1102 1148.0 1 1e6 DU/M PPP +CI P589 20 LYQ 34.6207 -117.1102 1148.0 1 1 - PPP +CI P590 20 LYE 35.1168 -117.3648 678.5 1 1e6 DU/M PPP +CI P590 20 LYN 35.1168 -117.3648 678.5 1 1e6 DU/M PPP +CI P590 20 LYZ 35.1168 -117.3648 678.5 1 1e6 DU/M PPP +CI P590 20 LY1 35.1168 -117.3648 678.5 1 1e6 DU/M PPP +CI P590 20 LY2 35.1168 -117.3648 678.5 1 1e6 DU/M PPP +CI P590 20 LY3 35.1168 -117.3648 678.5 1 1e6 DU/M PPP +CI P590 20 LYQ 35.1168 -117.3648 678.5 1 1 - PPP +CI P591 20 LYE 35.1524 -118.0165 708.8 1 1e6 DU/M PPP +CI P591 20 LYN 35.1524 -118.0165 708.8 1 1e6 DU/M PPP +CI P591 20 LYZ 35.1524 -118.0165 708.8 1 1e6 DU/M PPP +CI P591 20 LY1 35.1524 -118.0165 708.8 1 1e6 DU/M PPP +CI P591 20 LY2 35.1524 -118.0165 708.8 1 1e6 DU/M PPP +CI P591 20 LY3 35.1524 -118.0165 708.8 1 1e6 DU/M PPP +CI P591 20 LYQ 35.1524 -118.0165 708.8 1 1 - PPP +CI P598 20 LYE 34.1925 -116.7103 2746.5 1 1e6 DU/M PPP +CI P598 20 LYN 34.1925 -116.7103 2746.5 1 1e6 DU/M PPP +CI P598 20 LYZ 34.1925 -116.7103 2746.5 1 1e6 DU/M PPP +CI P598 20 LY1 34.1925 -116.7103 2746.5 1 1e6 DU/M PPP +CI P598 20 LY2 34.1925 -116.7103 2746.5 1 1e6 DU/M PPP +CI P598 20 LY3 34.1925 -116.7103 2746.5 1 1e6 DU/M PPP +CI P598 20 LYQ 34.1925 -116.7103 2746.5 1 1 - PPP +CI P599 20 LYE 34.2172 -116.5375 1323.8 1 1e6 DU/M PPP +CI P599 20 LYN 34.2172 -116.5375 1323.8 1 1e6 DU/M PPP +CI P599 20 LYZ 34.2172 -116.5375 1323.8 1 1e6 DU/M PPP +CI P599 20 LY1 34.2172 -116.5375 1323.8 1 1e6 DU/M PPP +CI P599 20 LY2 34.2172 -116.5375 1323.8 1 1e6 DU/M PPP +CI P599 20 LY3 34.2172 -116.5375 1323.8 1 1e6 DU/M PPP +CI P599 20 LYQ 34.2172 -116.5375 1323.8 1 1 - PPP +CI P600 20 LYE 33.8658 -116.2119 792.0 1 1e6 DU/M PPP +CI P600 20 LYN 33.8658 -116.2119 792.0 1 1e6 DU/M PPP +CI P600 20 LYZ 33.8658 -116.2119 792.0 1 1e6 DU/M PPP +CI P600 20 LY1 33.8658 -116.2119 792.0 1 1e6 DU/M PPP +CI P600 20 LY2 33.8658 -116.2119 792.0 1 1e6 DU/M PPP +CI P600 20 LY3 33.8658 -116.2119 792.0 1 1e6 DU/M PPP +CI P600 20 LYQ 33.8658 -116.2119 792.0 1 1 - PPP +CI P601 20 LYE 33.9593 -116.0802 1242.5 1 1e6 DU/M PPP +CI P601 20 LYN 33.9593 -116.0802 1242.5 1 1e6 DU/M PPP +CI P601 20 LYZ 33.9593 -116.0802 1242.5 1 1e6 DU/M PPP +CI P601 20 LY1 33.9593 -116.0802 1242.5 1 1e6 DU/M PPP +CI P601 20 LY2 33.9593 -116.0802 1242.5 1 1e6 DU/M PPP +CI P601 20 LY3 33.9593 -116.0802 1242.5 1 1e6 DU/M PPP +CI P601 20 LYQ 33.9593 -116.0802 1242.5 1 1 - PPP +CI P603 20 LYE 34.7169 -116.0295 624.7 1 1e6 DU/M PPP +CI P603 20 LYN 34.7169 -116.0295 624.7 1 1e6 DU/M PPP +CI P603 20 LYZ 34.7169 -116.0295 624.7 1 1e6 DU/M PPP +CI P603 20 LY1 34.7169 -116.0295 624.7 1 1e6 DU/M PPP +CI P603 20 LY2 34.7169 -116.0295 624.7 1 1e6 DU/M PPP +CI P603 20 LY3 34.7169 -116.0295 624.7 1 1e6 DU/M PPP +CI P603 20 LYQ 34.7169 -116.0295 624.7 1 1 - PPP +CI P604 20 LYE 34.9368 -116.6715 588.4 1 1e6 DU/M PPP +CI P604 20 LYN 34.9368 -116.6715 588.4 1 1e6 DU/M PPP +CI P604 20 LYZ 34.9368 -116.6715 588.4 1 1e6 DU/M PPP +CI P604 20 LY1 34.9368 -116.6715 588.4 1 1e6 DU/M PPP +CI P604 20 LY2 34.9368 -116.6715 588.4 1 1e6 DU/M PPP +CI P604 20 LY3 34.9368 -116.6715 588.4 1 1e6 DU/M PPP +CI P604 20 LYQ 34.9368 -116.6715 588.4 1 1 - PPP +CI P606 20 LYE 34.4621 -116.8796 863.3 1 1e6 DU/M PPP +CI P606 20 LYN 34.4621 -116.8796 863.3 1 1e6 DU/M PPP +CI P606 20 LYZ 34.4621 -116.8796 863.3 1 1e6 DU/M PPP +CI P606 20 LY1 34.4621 -116.8796 863.3 1 1e6 DU/M PPP +CI P606 20 LY2 34.4621 -116.8796 863.3 1 1e6 DU/M PPP +CI P606 20 LY3 34.4621 -116.8796 863.3 1 1e6 DU/M PPP +CI P606 20 LYQ 34.4621 -116.8796 863.3 1 1 - PPP +CI P607 20 LYE 33.7410 -115.8207 958.7 1 1e6 DU/M PPP +CI P607 20 LYN 33.7410 -115.8207 958.7 1 1e6 DU/M PPP +CI P607 20 LYZ 33.7410 -115.8207 958.7 1 1e6 DU/M PPP +CI P607 20 LY1 33.7410 -115.8207 958.7 1 1e6 DU/M PPP +CI P607 20 LY2 33.7410 -115.8207 958.7 1 1e6 DU/M PPP +CI P607 20 LY3 33.7410 -115.8207 958.7 1 1e6 DU/M PPP +CI P607 20 LYQ 33.7410 -115.8207 958.7 1 1 - PPP +CI P608 20 LYE 33.9941 -115.6866 632.3 1 1e6 DU/M PPP +CI P608 20 LYN 33.9941 -115.6866 632.3 1 1e6 DU/M PPP +CI P608 20 LYZ 33.9941 -115.6866 632.3 1 1e6 DU/M PPP +CI P608 20 LY1 33.9941 -115.6866 632.3 1 1e6 DU/M PPP +CI P608 20 LY2 33.9941 -115.6866 632.3 1 1e6 DU/M PPP +CI P608 20 LY3 33.9941 -115.6866 632.3 1 1e6 DU/M PPP +CI P608 20 LYQ 33.9941 -115.6866 632.3 1 1 - PPP +CI P609 20 LYE 34.0627 -116.8928 2721.2 1 1e6 DU/M PPP +CI P609 20 LYN 34.0627 -116.8928 2721.2 1 1e6 DU/M PPP +CI P609 20 LYZ 34.0627 -116.8928 2721.2 1 1e6 DU/M PPP +CI P609 20 LY1 34.0627 -116.8928 2721.2 1 1e6 DU/M PPP +CI P609 20 LY2 34.0627 -116.8928 2721.2 1 1e6 DU/M PPP +CI P609 20 LY3 34.0627 -116.8928 2721.2 1 1e6 DU/M PPP +CI P609 20 LYQ 34.0627 -116.8928 2721.2 1 1 - PPP +CI P610 20 LYE 34.4257 -115.7637 343.9 1 1e6 DU/M PPP +CI P610 20 LYN 34.4257 -115.7637 343.9 1 1e6 DU/M PPP +CI P610 20 LYZ 34.4257 -115.7637 343.9 1 1e6 DU/M PPP +CI P610 20 LY1 34.4257 -115.7637 343.9 1 1e6 DU/M PPP +CI P610 20 LY2 34.4257 -115.7637 343.9 1 1e6 DU/M PPP +CI P610 20 LY3 34.4257 -115.7637 343.9 1 1e6 DU/M PPP +CI P610 20 LYQ 34.4257 -115.7637 343.9 1 1 - PPP +CI P612 20 LYE 34.1874 -117.3155 531.7 1 1e6 DU/M PPP +CI P612 20 LYN 34.1874 -117.3155 531.7 1 1e6 DU/M PPP +CI P612 20 LYZ 34.1874 -117.3155 531.7 1 1e6 DU/M PPP +CI P612 20 LY1 34.1874 -117.3155 531.7 1 1e6 DU/M PPP +CI P612 20 LY2 34.1874 -117.3155 531.7 1 1e6 DU/M PPP +CI P612 20 LY3 34.1874 -117.3155 531.7 1 1e6 DU/M PPP +CI P612 20 LYQ 34.1874 -117.3155 531.7 1 1 - PPP +CI P613 20 LYE 34.1962 -117.0500 2355.2 1 1e6 DU/M PPP +CI P613 20 LYN 34.1962 -117.0500 2355.2 1 1e6 DU/M PPP +CI P613 20 LYZ 34.1962 -117.0500 2355.2 1 1e6 DU/M PPP +CI P613 20 LY1 34.1962 -117.0500 2355.2 1 1e6 DU/M PPP +CI P613 20 LY2 34.1962 -117.0500 2355.2 1 1e6 DU/M PPP +CI P613 20 LY3 34.1962 -117.0500 2355.2 1 1e6 DU/M PPP +CI P613 20 LYQ 34.1962 -117.0500 2355.2 1 1 - PPP +CI P614 20 LYE 34.7318 -115.2503 491.0 1 1e6 DU/M PPP +CI P614 20 LYN 34.7318 -115.2503 491.0 1 1e6 DU/M PPP +CI P614 20 LYZ 34.7318 -115.2503 491.0 1 1e6 DU/M PPP +CI P614 20 LY1 34.7318 -115.2503 491.0 1 1e6 DU/M PPP +CI P614 20 LY2 34.7318 -115.2503 491.0 1 1e6 DU/M PPP +CI P614 20 LY3 34.7318 -115.2503 491.0 1 1e6 DU/M PPP +CI P614 20 LYQ 34.7318 -115.2503 491.0 1 1 - PPP +CI P618 20 LYE 35.1419 -116.1039 263.3 1 1e6 DU/M PPP +CI P618 20 LYN 35.1419 -116.1039 263.3 1 1e6 DU/M PPP +CI P618 20 LYZ 35.1419 -116.1039 263.3 1 1e6 DU/M PPP +CI P618 20 LY1 35.1419 -116.1039 263.3 1 1e6 DU/M PPP +CI P618 20 LY2 35.1419 -116.1039 263.3 1 1e6 DU/M PPP +CI P618 20 LY3 35.1419 -116.1039 263.3 1 1e6 DU/M PPP +CI P618 20 LYQ 35.1419 -116.1039 263.3 1 1 - PPP +CI P623 20 LYE 34.1889 -114.5994 267.7 1 1e6 DU/M PPP +CI P623 20 LYN 34.1889 -114.5994 267.7 1 1e6 DU/M PPP +CI P623 20 LYZ 34.1889 -114.5994 267.7 1 1e6 DU/M PPP +CI P623 20 LY1 34.1889 -114.5994 267.7 1 1e6 DU/M PPP +CI P623 20 LY2 34.1889 -114.5994 267.7 1 1e6 DU/M PPP +CI P623 20 LY3 34.1889 -114.5994 267.7 1 1e6 DU/M PPP +CI P623 20 LYQ 34.1889 -114.5994 267.7 1 1 - PPP +CI P625 20 LYE 34.8444 -114.9651 606.8 1 1e6 DU/M PPP +CI P625 20 LYN 34.8444 -114.9651 606.8 1 1e6 DU/M PPP +CI P625 20 LYZ 34.8444 -114.9651 606.8 1 1e6 DU/M PPP +CI P625 20 LY1 34.8444 -114.9651 606.8 1 1e6 DU/M PPP +CI P625 20 LY2 34.8444 -114.9651 606.8 1 1e6 DU/M PPP +CI P625 20 LY3 34.8444 -114.9651 606.8 1 1e6 DU/M PPP +CI P625 20 LYQ 34.8444 -114.9651 606.8 1 1 - PPP +CI P729 20 LYE 34.2631 -119.0961 35.9 1 1e6 DU/M PPP +CI P729 20 LYN 34.2631 -119.0961 35.9 1 1e6 DU/M PPP +CI P729 20 LYZ 34.2631 -119.0961 35.9 1 1e6 DU/M PPP +CI P729 20 LY1 34.2631 -119.0961 35.9 1 1e6 DU/M PPP +CI P729 20 LY2 34.2631 -119.0961 35.9 1 1e6 DU/M PPP +CI P729 20 LY3 34.2631 -119.0961 35.9 1 1e6 DU/M PPP +CI P729 20 LYQ 34.2631 -119.0961 35.9 1 1 - PPP +CI P740 20 LYE 33.5982 -116.5960 1372.1 1 1e6 DU/M PPP +CI P740 20 LYN 33.5982 -116.5960 1372.1 1 1e6 DU/M PPP +CI P740 20 LYZ 33.5982 -116.5960 1372.1 1 1e6 DU/M PPP +CI P740 20 LY1 33.5982 -116.5960 1372.1 1 1e6 DU/M PPP +CI P740 20 LY2 33.5982 -116.5960 1372.1 1 1e6 DU/M PPP +CI P740 20 LY3 33.5982 -116.5960 1372.1 1 1e6 DU/M PPP +CI P740 20 LYQ 33.5982 -116.5960 1372.1 1 1 - PPP +CI P741 20 LYE 33.5575 -116.5310 1371.3 1 1e6 DU/M PPP +CI P741 20 LYN 33.5575 -116.5310 1371.3 1 1e6 DU/M PPP +CI P741 20 LYZ 33.5575 -116.5310 1371.3 1 1e6 DU/M PPP +CI P741 20 LY1 33.5575 -116.5310 1371.3 1 1e6 DU/M PPP +CI P741 20 LY2 33.5575 -116.5310 1371.3 1 1e6 DU/M PPP +CI P741 20 LY3 33.5575 -116.5310 1371.3 1 1e6 DU/M PPP +CI P741 20 LYQ 33.5575 -116.5310 1371.3 1 1 - PPP +CI P742 20 LYE 33.4955 -116.6026 1142.6 1 1e6 DU/M PPP +CI P742 20 LYN 33.4955 -116.6026 1142.6 1 1e6 DU/M PPP +CI P742 20 LYZ 33.4955 -116.6026 1142.6 1 1e6 DU/M PPP +CI P742 20 LY1 33.4955 -116.6026 1142.6 1 1e6 DU/M PPP +CI P742 20 LY2 33.4955 -116.6026 1142.6 1 1e6 DU/M PPP +CI P742 20 LY3 33.4955 -116.6026 1142.6 1 1e6 DU/M PPP +CI P742 20 LYQ 33.4955 -116.6026 1142.6 1 1 - PPP +CI P744 20 LYE 32.8294 -115.5084 -52.7 1 1e6 DU/M PPP +CI P744 20 LYN 32.8294 -115.5084 -52.7 1 1e6 DU/M PPP +CI P744 20 LYZ 32.8294 -115.5084 -52.7 1 1e6 DU/M PPP +CI P744 20 LY1 32.8294 -115.5084 -52.7 1 1e6 DU/M PPP +CI P744 20 LY2 32.8294 -115.5084 -52.7 1 1e6 DU/M PPP +CI P744 20 LY3 32.8294 -115.5084 -52.7 1 1e6 DU/M PPP +CI P744 20 LYQ 32.8294 -115.5084 -52.7 1 1 - PPP +CI P795 20 LYE 34.5081 -116.1481 1095.3 1 1e6 DU/M PPP +CI P795 20 LYN 34.5081 -116.1481 1095.3 1 1e6 DU/M PPP +CI P795 20 LYZ 34.5081 -116.1481 1095.3 1 1e6 DU/M PPP +CI P795 20 LY1 34.5081 -116.1481 1095.3 1 1e6 DU/M PPP +CI P795 20 LY2 34.5081 -116.1481 1095.3 1 1e6 DU/M PPP +CI P795 20 LY3 34.5081 -116.1481 1095.3 1 1e6 DU/M PPP +CI P795 20 LYQ 34.5081 -116.1481 1095.3 1 1 - PPP +CI P796 20 LYE 32.4979 -114.7594 10.2 1 1e6 DU/M PPP +CI P796 20 LYN 32.4979 -114.7594 10.2 1 1e6 DU/M PPP +CI P796 20 LYZ 32.4979 -114.7594 10.2 1 1e6 DU/M PPP +CI P796 20 LY1 32.4979 -114.7594 10.2 1 1e6 DU/M PPP +CI P796 20 LY2 32.4979 -114.7594 10.2 1 1e6 DU/M PPP +CI P796 20 LY3 32.4979 -114.7594 10.2 1 1e6 DU/M PPP +CI P796 20 LYQ 32.4979 -114.7594 10.2 1 1 - PPP +CI P797 20 LYE 33.5373 -116.5925 1403.8 1 1e6 DU/M PPP +CI P797 20 LYN 33.5373 -116.5925 1403.8 1 1e6 DU/M PPP +CI P797 20 LYZ 33.5373 -116.5925 1403.8 1 1e6 DU/M PPP +CI P797 20 LY1 33.5373 -116.5925 1403.8 1 1e6 DU/M PPP +CI P797 20 LY2 33.5373 -116.5925 1403.8 1 1e6 DU/M PPP +CI P797 20 LY3 33.5373 -116.5925 1403.8 1 1e6 DU/M PPP +CI P797 20 LYQ 33.5373 -116.5925 1403.8 1 1 - PPP +CI P799 20 LYE 33.9276 -118.3064 24.8 1 1e6 DU/M PPP +CI P799 20 LYN 33.9276 -118.3064 24.8 1 1e6 DU/M PPP +CI P799 20 LYZ 33.9276 -118.3064 24.8 1 1e6 DU/M PPP +CI P799 20 LY1 33.9276 -118.3064 24.8 1 1e6 DU/M PPP +CI P799 20 LY2 33.9276 -118.3064 24.8 1 1e6 DU/M PPP +CI P799 20 LY3 33.9276 -118.3064 24.8 1 1e6 DU/M PPP +CI P799 20 LYQ 33.9276 -118.3064 24.8 1 1 - PPP +CI P800 20 LYE 34.0217 -118.3491 -2.3 1 1e6 DU/M PPP +CI P800 20 LYN 34.0217 -118.3491 -2.3 1 1e6 DU/M PPP +CI P800 20 LYZ 34.0217 -118.3491 -2.3 1 1e6 DU/M PPP +CI P800 20 LY1 34.0217 -118.3491 -2.3 1 1e6 DU/M PPP +CI P800 20 LY2 34.0217 -118.3491 -2.3 1 1e6 DU/M PPP +CI P800 20 LY3 34.0217 -118.3491 -2.3 1 1e6 DU/M PPP +CI P800 20 LYQ 34.0217 -118.3491 -2.3 1 1 - PPP +CI P808 20 LYE 34.8360 -118.6215 914.2 1 1e6 DU/M PPP +CI P808 20 LYN 34.8360 -118.6215 914.2 1 1e6 DU/M PPP +CI P808 20 LYZ 34.8360 -118.6215 914.2 1 1e6 DU/M PPP +CI P808 20 LY1 34.8360 -118.6215 914.2 1 1e6 DU/M PPP +CI P808 20 LY2 34.8360 -118.6215 914.2 1 1e6 DU/M PPP +CI P808 20 LY3 34.8360 -118.6215 914.2 1 1e6 DU/M PPP +CI P808 20 LYQ 34.8360 -118.6215 914.2 1 1 - PPP +CI PALG 20 LYE 33.3890 -117.0318 528.8 1 1e6 DU/M PPP +CI PALG 20 LYN 33.3890 -117.0318 528.8 1 1e6 DU/M PPP +CI PALG 20 LYZ 33.3890 -117.0318 528.8 1 1e6 DU/M PPP +CI PALG 20 LY1 33.3890 -117.0318 528.8 1 1e6 DU/M PPP +CI PALG 20 LY2 33.3890 -117.0318 528.8 1 1e6 DU/M PPP +CI PALG 20 LY3 33.3890 -117.0318 528.8 1 1e6 DU/M PPP +CI PALG 20 LYQ 33.3890 -117.0318 528.8 1 1 - PPP +CI PB1Y 20 LYE 32.6479 -115.6924 1.1 1 1e6 DU/M PPP +CI PB1Y 20 LYN 32.6479 -115.6924 1.1 1 1e6 DU/M PPP +CI PB1Y 20 LYZ 32.6479 -115.6924 1.1 1 1e6 DU/M PPP +CI PB1Y 20 LY1 32.6479 -115.6924 1.1 1 1e6 DU/M PPP +CI PB1Y 20 LY2 32.6479 -115.6924 1.1 1 1e6 DU/M PPP +CI PB1Y 20 LY3 32.6479 -115.6924 1.1 1 1e6 DU/M PPP +CI PB1Y 20 LYQ 32.6479 -115.6924 1.1 1 1 - PPP +CI PBPP 20 LYE 34.5082 -117.9226 902.0 1 1e6 DU/M PPP +CI PBPP 20 LYN 34.5082 -117.9226 902.0 1 1e6 DU/M PPP +CI PBPP 20 LYZ 34.5082 -117.9226 902.0 1 1e6 DU/M PPP +CI PBPP 20 LY1 34.5082 -117.9226 902.0 1 1e6 DU/M PPP +CI PBPP 20 LY2 34.5082 -117.9226 902.0 1 1e6 DU/M PPP +CI PBPP 20 LY3 34.5082 -117.9226 902.0 1 1e6 DU/M PPP +CI PBPP 20 LYQ 34.5082 -117.9226 902.0 1 1 - PPP +CI PIN1 20 LYE 33.6122 -116.4582 1256.2 1 1e6 DU/M PPP +CI PIN1 20 LYN 33.6122 -116.4582 1256.2 1 1e6 DU/M PPP +CI PIN1 20 LYZ 33.6122 -116.4582 1256.2 1 1e6 DU/M PPP +CI PIN1 20 LY1 33.6122 -116.4582 1256.2 1 1e6 DU/M PPP +CI PIN1 20 LY2 33.6122 -116.4582 1256.2 1 1e6 DU/M PPP +CI PIN1 20 LY3 33.6122 -116.4582 1256.2 1 1e6 DU/M PPP +CI PIN1 20 LYQ 33.6122 -116.4582 1256.2 1 1 - PPP +CI PIN2 20 LYE 33.6121 -116.4576 1258.4 1 1e6 DU/M PPP +CI PIN2 20 LYN 33.6121 -116.4576 1258.4 1 1e6 DU/M PPP +CI PIN2 20 LYZ 33.6121 -116.4576 1258.4 1 1e6 DU/M PPP +CI PIN2 20 LY1 33.6121 -116.4576 1258.4 1 1e6 DU/M PPP +CI PIN2 20 LY2 33.6121 -116.4576 1258.4 1 1e6 DU/M PPP +CI PIN2 20 LY3 33.6121 -116.4576 1258.4 1 1e6 DU/M PPP +CI PIN2 20 LYQ 33.6121 -116.4576 1258.4 1 1 - PPP +BK PKDB 30 LYN 35.9452 -120.5416 589.9 1 1e6 DU/M PPP +BK PKDB 30 LYE 35.9452 -120.5416 589.9 1 1e6 DU/M PPP +BK PKDB 30 LYZ 35.9452 -120.5416 589.9 1 1e6 DU/M PPP +BK PKDB 30 LYQ 35.9452 -120.5416 589.9 1 1 - PPP +BK PKDB 30 LY1 35.9452 -120.5416 589.9 1 1e6 DU/M PPP +BK PKDB 30 LY2 35.9452 -120.5416 589.9 1 1e6 DU/M PPP +BK PKDB 30 LY3 35.9452 -120.5416 589.9 1 1e6 DU/M PPP +CI PKRD 20 LYE 34.0716 -118.2329 130.7 1 1e6 DU/M PPP +CI PKRD 20 LYN 34.0716 -118.2329 130.7 1 1e6 DU/M PPP +CI PKRD 20 LYZ 34.0716 -118.2329 130.7 1 1e6 DU/M PPP +CI PKRD 20 LY1 34.0716 -118.2329 130.7 1 1e6 DU/M PPP +CI PKRD 20 LY2 34.0716 -118.2329 130.7 1 1e6 DU/M PPP +CI PKRD 20 LY3 34.0716 -118.2329 130.7 1 1e6 DU/M PPP +CI PKRD 20 LYQ 34.0716 -118.2329 130.7 1 1 - PPP +CI PMOB 20 LYE 33.3572 -116.8596 1662.5 1 1e6 DU/M PPP +CI PMOB 20 LYN 33.3572 -116.8596 1662.5 1 1e6 DU/M PPP +CI PMOB 20 LYZ 33.3572 -116.8596 1662.5 1 1e6 DU/M PPP +CI PMOB 20 LY1 33.3572 -116.8596 1662.5 1 1e6 DU/M PPP +CI PMOB 20 LY2 33.3572 -116.8596 1662.5 1 1e6 DU/M PPP +CI PMOB 20 LY3 33.3572 -116.8596 1662.5 1 1e6 DU/M PPP +CI PMOB 20 LYQ 33.3572 -116.8596 1662.5 1 1 - PPP +CI POBG 20 LYE 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 20 LYN 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 20 LYZ 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 20 LY1 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 20 LY2 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 20 LY3 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 20 LYQ 33.6871 -116.9238 982.2 1 1 - PPP +CI POBG 30 LYE 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 30 LYN 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 30 LYZ 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 30 LY1 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 30 LY2 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 30 LY3 33.6871 -116.9238 982.2 1 1e6 DU/M PPP +CI POBG 30 LYQ 33.6871 -116.9238 982.2 1 1 - PPP +CI POTR 20 LYE 32.6184 -116.5909 730.2 1 1e6 DU/M PPP +CI POTR 20 LYN 32.6184 -116.5909 730.2 1 1e6 DU/M PPP +CI POTR 20 LYZ 32.6184 -116.5909 730.2 1 1e6 DU/M PPP +CI POTR 20 LY1 32.6184 -116.5909 730.2 1 1e6 DU/M PPP +CI POTR 20 LY2 32.6184 -116.5909 730.2 1 1e6 DU/M PPP +CI POTR 20 LY3 32.6184 -116.5909 730.2 1 1e6 DU/M PPP +CI POTR 20 LYQ 32.6184 -116.5909 730.2 1 1 - PPP +CI PPBF 20 LYE 33.8357 -117.1821 428.1 1 1e6 DU/M PPP +CI PPBF 20 LYN 33.8357 -117.1821 428.1 1 1e6 DU/M PPP +CI PPBF 20 LYZ 33.8357 -117.1821 428.1 1 1e6 DU/M PPP +CI PPBF 20 LY1 33.8357 -117.1821 428.1 1 1e6 DU/M PPP +CI PPBF 20 LY2 33.8357 -117.1821 428.1 1 1e6 DU/M PPP +CI PPBF 20 LY3 33.8357 -117.1821 428.1 1 1e6 DU/M PPP +CI PPBF 20 LYQ 33.8357 -117.1821 428.1 1 1 - PPP +CI PSDM 20 LYE 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 20 LYN 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 20 LYZ 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 20 LY1 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 20 LY2 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 20 LY3 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 20 LYQ 34.0918 -117.8071 278.3 1 1 - PPP +CI PSDM 30 LYE 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 30 LYN 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 30 LYZ 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 30 LY1 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 30 LY2 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 30 LY3 34.0918 -117.8071 278.3 1 1e6 DU/M PPP +CI PSDM 30 LYQ 34.0918 -117.8071 278.3 1 1 - PPP +CI PTAX 20 LYE 32.3775 -115.4563 1060.3 1 1e6 DU/M PPP +CI PTAX 20 LYN 32.3775 -115.4563 1060.3 1 1e6 DU/M PPP +CI PTAX 20 LYZ 32.3775 -115.4563 1060.3 1 1e6 DU/M PPP +CI PTAX 20 LY1 32.3775 -115.4563 1060.3 1 1e6 DU/M PPP +CI PTAX 20 LY2 32.3775 -115.4563 1060.3 1 1e6 DU/M PPP +CI PTAX 20 LY3 32.3775 -115.4563 1060.3 1 1e6 DU/M PPP +CI PTAX 20 LYQ 32.3775 -115.4563 1060.3 1 1 - PPP +BK PTRL 30 LYN 37.9962 -123.0187 146.9 1 1e6 DU/M PPP +BK PTRL 30 LYE 37.9962 -123.0187 146.9 1 1e6 DU/M PPP +BK PTRL 30 LYZ 37.9962 -123.0187 146.9 1 1e6 DU/M PPP +BK PTRL 30 LYQ 37.9962 -123.0187 146.9 1 1 - PPP +BK PTRL 30 LY1 37.9962 -123.0187 146.9 1 1e6 DU/M PPP +BK PTRL 30 LY2 37.9962 -123.0187 146.9 1 1e6 DU/M PPP +BK PTRL 30 LY3 37.9962 -123.0187 146.9 1 1e6 DU/M PPP +BK PTRO 30 LYN 38.2095 -121.9442 28.0 1 1e6 DU/M PPP +BK PTRO 30 LYE 38.2095 -121.9442 28.0 1 1e6 DU/M PPP +BK PTRO 30 LYZ 38.2095 -121.9442 28.0 1 1e6 DU/M PPP +BK PTRO 30 LYQ 38.2095 -121.9442 28.0 1 1 - PPP +BK PTRO 30 LY1 38.2095 -121.9442 28.0 1 1e6 DU/M PPP +BK PTRO 30 LY2 38.2095 -121.9442 28.0 1 1e6 DU/M PPP +BK PTRO 30 LY3 38.2095 -121.9442 28.0 1 1e6 DU/M PPP +CI PVE3 20 LYE 33.7433 -118.4043 71.0 1 1e6 DU/M PPP +CI PVE3 20 LYN 33.7433 -118.4043 71.0 1 1e6 DU/M PPP +CI PVE3 20 LYZ 33.7433 -118.4043 71.0 1 1e6 DU/M PPP +CI PVE3 20 LY1 33.7433 -118.4043 71.0 1 1e6 DU/M PPP +CI PVE3 20 LY2 33.7433 -118.4043 71.0 1 1e6 DU/M PPP +CI PVE3 20 LY3 33.7433 -118.4043 71.0 1 1e6 DU/M PPP +CI PVE3 20 LYQ 33.7433 -118.4043 71.0 1 1 - PPP +CI PVHS 20 LYE 33.7795 -118.3722 259.6 1 1e6 DU/M PPP +CI PVHS 20 LYN 33.7795 -118.3722 259.6 1 1e6 DU/M PPP +CI PVHS 20 LYZ 33.7795 -118.3722 259.6 1 1e6 DU/M PPP +CI PVHS 20 LY1 33.7795 -118.3722 259.6 1 1e6 DU/M PPP +CI PVHS 20 LY2 33.7795 -118.3722 259.6 1 1e6 DU/M PPP +CI PVHS 20 LY3 33.7795 -118.3722 259.6 1 1e6 DU/M PPP +CI PVHS 20 LYQ 33.7795 -118.3722 259.6 1 1 - PPP +CI PVRS 20 LYE 33.7739 -118.3206 59.8 1 1e6 DU/M PPP +CI PVRS 20 LYN 33.7739 -118.3206 59.8 1 1e6 DU/M PPP +CI PVRS 20 LYZ 33.7739 -118.3206 59.8 1 1e6 DU/M PPP +CI PVRS 20 LY1 33.7739 -118.3206 59.8 1 1e6 DU/M PPP +CI PVRS 20 LY2 33.7739 -118.3206 59.8 1 1e6 DU/M PPP +CI PVRS 20 LY3 33.7739 -118.3206 59.8 1 1e6 DU/M PPP +CI PVRS 20 LYQ 33.7739 -118.3206 59.8 1 1 - PPP +CI QHTP 20 LYE 34.6287 -118.2448 863.0 1 1e6 DU/M PPP +CI QHTP 20 LYN 34.6287 -118.2448 863.0 1 1e6 DU/M PPP +CI QHTP 20 LYZ 34.6287 -118.2448 863.0 1 1e6 DU/M PPP +CI QHTP 20 LY1 34.6287 -118.2448 863.0 1 1e6 DU/M PPP +CI QHTP 20 LY2 34.6287 -118.2448 863.0 1 1e6 DU/M PPP +CI QHTP 20 LY3 34.6287 -118.2448 863.0 1 1e6 DU/M PPP +CI QHTP 20 LYQ 34.6287 -118.2448 863.0 1 1 - PPP +CI QUEX 20 LYE 32.5492 -115.1532 -16.3 1 1e6 DU/M PPP +CI QUEX 20 LYN 32.5492 -115.1532 -16.3 1 1e6 DU/M PPP +CI QUEX 20 LYZ 32.5492 -115.1532 -16.3 1 1e6 DU/M PPP +CI QUEX 20 LY1 32.5492 -115.1532 -16.3 1 1e6 DU/M PPP +CI QUEX 20 LY2 32.5492 -115.1532 -16.3 1 1e6 DU/M PPP +CI QUEX 20 LY3 32.5492 -115.1532 -16.3 1 1e6 DU/M PPP +CI QUEX 20 LYQ 32.5492 -115.1532 -16.3 1 1 - PPP +CI RAAP 20 LYE 33.0422 -116.9173 395.0 1 1e6 DU/M PPP +CI RAAP 20 LYN 33.0422 -116.9173 395.0 1 1e6 DU/M PPP +CI RAAP 20 LYZ 33.0422 -116.9173 395.0 1 1e6 DU/M PPP +CI RAAP 20 LY1 33.0422 -116.9173 395.0 1 1e6 DU/M PPP +CI RAAP 20 LY2 33.0422 -116.9173 395.0 1 1e6 DU/M PPP +CI RAAP 20 LY3 33.0422 -116.9173 395.0 1 1e6 DU/M PPP +CI RAAP 20 LYQ 33.0422 -116.9173 395.0 1 1 - PPP +CI RAGG 20 LYE 34.6831 -116.1515 729.9 1 1e6 DU/M PPP +CI RAGG 20 LYN 34.6831 -116.1515 729.9 1 1e6 DU/M PPP +CI RAGG 20 LYZ 34.6831 -116.1515 729.9 1 1e6 DU/M PPP +CI RAGG 20 LY1 34.6831 -116.1515 729.9 1 1e6 DU/M PPP +CI RAGG 20 LY2 34.6831 -116.1515 729.9 1 1e6 DU/M PPP +CI RAGG 20 LY3 34.6831 -116.1515 729.9 1 1e6 DU/M PPP +CI RAGG 20 LYQ 34.6831 -116.1515 729.9 1 1 - PPP +CI RCA2 20 LYE 34.5000 -119.7200 1179.1 1 1e6 DU/M PPP +CI RCA2 20 LYN 34.5000 -119.7200 1179.1 1 1e6 DU/M PPP +CI RCA2 20 LYZ 34.5000 -119.7200 1179.1 1 1e6 DU/M PPP +CI RCA2 20 LY1 34.5000 -119.7200 1179.1 1 1e6 DU/M PPP +CI RCA2 20 LY2 34.5000 -119.7200 1179.1 1 1e6 DU/M PPP +CI RCA2 20 LY3 34.5000 -119.7200 1179.1 1 1e6 DU/M PPP +CI RCA2 20 LYQ 34.5000 -119.7200 1179.1 1 1 - PPP +CI RDMT 20 LYE 34.6439 -116.6247 1783.0 1 1e6 DU/M PPP +CI RDMT 20 LYN 34.6439 -116.6247 1783.0 1 1e6 DU/M PPP +CI RDMT 20 LYZ 34.6439 -116.6247 1783.0 1 1e6 DU/M PPP +CI RDMT 20 LY1 34.6439 -116.6247 1783.0 1 1e6 DU/M PPP +CI RDMT 20 LY2 34.6439 -116.6247 1783.0 1 1e6 DU/M PPP +CI RDMT 20 LY3 34.6439 -116.6247 1783.0 1 1e6 DU/M PPP +CI RDMT 20 LYQ 34.6439 -116.6247 1783.0 1 1 - PPP +CI RHCG 20 LYE 34.0009 -118.0134 338.7 1 1e6 DU/M PPP +CI RHCG 20 LYN 34.0009 -118.0134 338.7 1 1e6 DU/M PPP +CI RHCG 20 LYZ 34.0009 -118.0134 338.7 1 1e6 DU/M PPP +CI RHCG 20 LY1 34.0009 -118.0134 338.7 1 1e6 DU/M PPP +CI RHCG 20 LY2 34.0009 -118.0134 338.7 1 1e6 DU/M PPP +CI RHCG 20 LY3 34.0009 -118.0134 338.7 1 1e6 DU/M PPP +CI RHCG 20 LYQ 34.0009 -118.0134 338.7 1 1 - PPP +CI RHCL 20 LYE 34.0191 -118.0262 176.9 1 1e6 DU/M PPP +CI RHCL 20 LYN 34.0191 -118.0262 176.9 1 1e6 DU/M PPP +CI RHCL 20 LYZ 34.0191 -118.0262 176.9 1 1e6 DU/M PPP +CI RHCL 20 LY1 34.0191 -118.0262 176.9 1 1e6 DU/M PPP +CI RHCL 20 LY2 34.0191 -118.0262 176.9 1 1e6 DU/M PPP +CI RHCL 20 LY3 34.0191 -118.0262 176.9 1 1e6 DU/M PPP +CI RHCL 20 LYQ 34.0191 -118.0262 176.9 1 1 - PPP +CI RKMG 20 LYE 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 20 LYN 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 20 LYZ 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 20 LY1 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 20 LY2 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 20 LY3 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 20 LYQ 33.6741 -117.6094 377.6 1 1 - PPP +CI RKMG 30 LYE 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 30 LYN 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 30 LYZ 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 30 LY1 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 30 LY2 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 30 LY3 33.6741 -117.6094 377.6 1 1e6 DU/M PPP +CI RKMG 30 LYQ 33.6741 -117.6094 377.6 1 1 - PPP +CI RMVJ 20 LYE 33.4858 -117.5553 136.4 1 1e6 DU/M PPP +CI RMVJ 20 LYN 33.4858 -117.5553 136.4 1 1e6 DU/M PPP +CI RMVJ 20 LYZ 33.4858 -117.5553 136.4 1 1e6 DU/M PPP +CI RMVJ 20 LY1 33.4858 -117.5553 136.4 1 1e6 DU/M PPP +CI RMVJ 20 LY2 33.4858 -117.5553 136.4 1 1e6 DU/M PPP +CI RMVJ 20 LY3 33.4858 -117.5553 136.4 1 1e6 DU/M PPP +CI RMVJ 20 LYQ 33.4858 -117.5553 136.4 1 1 - PPP +CI ROCK 20 LYE 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 20 LYN 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 20 LYZ 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 20 LY1 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 20 LY2 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 20 LY3 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 20 LYQ 34.2357 -118.6764 553.4 1 1 - PPP +CI ROCK 30 LYE 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 30 LYN 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 30 LYZ 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 30 LY1 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 30 LY2 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 30 LY3 34.2357 -118.6764 553.4 1 1e6 DU/M PPP +CI ROCK 30 LYQ 34.2357 -118.6764 553.4 1 1 - PPP +CI RSTP 20 LYE 34.8751 -118.1929 712.7 1 1e6 DU/M PPP +CI RSTP 20 LYN 34.8751 -118.1929 712.7 1 1e6 DU/M PPP +CI RSTP 20 LYZ 34.8751 -118.1929 712.7 1 1e6 DU/M PPP +CI RSTP 20 LY1 34.8751 -118.1929 712.7 1 1e6 DU/M PPP +CI RSTP 20 LY2 34.8751 -118.1929 712.7 1 1e6 DU/M PPP +CI RSTP 20 LY3 34.8751 -118.1929 712.7 1 1e6 DU/M PPP +CI RSTP 20 LYQ 34.8751 -118.1929 712.7 1 1 - PPP +CI RSVY 20 LYE 34.5415 -119.1844 987.4 1 1e6 DU/M PPP +CI RSVY 20 LYN 34.5415 -119.1844 987.4 1 1e6 DU/M PPP +CI RSVY 20 LYZ 34.5415 -119.1844 987.4 1 1e6 DU/M PPP +CI RSVY 20 LY1 34.5415 -119.1844 987.4 1 1e6 DU/M PPP +CI RSVY 20 LY2 34.5415 -119.1844 987.4 1 1e6 DU/M PPP +CI RSVY 20 LY3 34.5415 -119.1844 987.4 1 1e6 DU/M PPP +CI RSVY 20 LYQ 34.5415 -119.1844 987.4 1 1 - PPP +CI RTHS 20 LYE 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 20 LYN 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 20 LYZ 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 20 LY1 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 20 LY2 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 20 LY3 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 20 LYQ 34.0892 -117.3533 328.7 1 1 - PPP +CI RTHS 40 LYE 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 40 LYN 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 40 LYZ 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 40 LY1 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 40 LY2 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 40 LY3 34.0892 -117.3533 328.7 1 1e6 DU/M PPP +CI RTHS 40 LYQ 34.0892 -117.3533 328.7 1 1 - PPP +CI RUNG 20 LYE 32.9723 -114.9780 119.7 1 1e6 DU/M PPP +CI RUNG 20 LYN 32.9723 -114.9780 119.7 1 1e6 DU/M PPP +CI RUNG 20 LYZ 32.9723 -114.9780 119.7 1 1e6 DU/M PPP +CI RUNG 20 LY1 32.9723 -114.9780 119.7 1 1e6 DU/M PPP +CI RUNG 20 LY2 32.9723 -114.9780 119.7 1 1e6 DU/M PPP +CI RUNG 20 LY3 32.9723 -114.9780 119.7 1 1e6 DU/M PPP +CI RUNG 20 LYQ 32.9723 -114.9780 119.7 1 1 - PPP +CI SACY 20 LYE 33.7432 -117.8956 -11.3 1 1e6 DU/M PPP +CI SACY 20 LYN 33.7432 -117.8956 -11.3 1 1e6 DU/M PPP +CI SACY 20 LYZ 33.7432 -117.8956 -11.3 1 1e6 DU/M PPP +CI SACY 20 LY1 33.7432 -117.8956 -11.3 1 1e6 DU/M PPP +CI SACY 20 LY2 33.7432 -117.8956 -11.3 1 1e6 DU/M PPP +CI SACY 20 LY3 33.7432 -117.8956 -11.3 1 1e6 DU/M PPP +CI SACY 20 LYQ 33.7432 -117.8956 -11.3 1 1 - PPP +BK SAOB 30 LYN 36.7653 -121.4472 360.0 1 1e6 DU/M PPP +BK SAOB 30 LYE 36.7653 -121.4472 360.0 1 1e6 DU/M PPP +BK SAOB 30 LYZ 36.7653 -121.4472 360.0 1 1e6 DU/M PPP +BK SAOB 30 LYQ 36.7653 -121.4472 360.0 1 1 - PPP +BK SAOB 30 LY1 36.7653 -121.4472 360.0 1 1e6 DU/M PPP +BK SAOB 30 LY2 36.7653 -121.4472 360.0 1 1e6 DU/M PPP +BK SAOB 30 LY3 36.7653 -121.4472 360.0 1 1e6 DU/M PPP +CI SBCC 20 LYE 33.5530 -117.6615 88.6 1 1e6 DU/M PPP +CI SBCC 20 LYN 33.5530 -117.6615 88.6 1 1e6 DU/M PPP +CI SBCC 20 LYZ 33.5530 -117.6615 88.6 1 1e6 DU/M PPP +CI SBCC 20 LY1 33.5530 -117.6615 88.6 1 1e6 DU/M PPP +CI SBCC 20 LY2 33.5530 -117.6615 88.6 1 1e6 DU/M PPP +CI SBCC 20 LY3 33.5530 -117.6615 88.6 1 1e6 DU/M PPP +CI SBCC 20 LYQ 33.5530 -117.6615 88.6 1 1 - PPP +BK SBRB 30 LYN 37.6865 -122.4108 -13.2 1 1e6 DU/M PPP +BK SBRB 30 LYE 37.6865 -122.4108 -13.2 1 1e6 DU/M PPP +BK SBRB 30 LYZ 37.6865 -122.4108 -13.2 1 1e6 DU/M PPP +BK SBRB 30 LYQ 37.6865 -122.4108 -13.2 1 1 - PPP +BK SBRB 30 LY1 37.6865 -122.4108 -13.2 1 1e6 DU/M PPP +BK SBRB 30 LY2 37.6865 -122.4108 -13.2 1 1e6 DU/M PPP +BK SBRB 30 LY3 37.6865 -122.4108 -13.2 1 1e6 DU/M PPP +CI SCIA 20 LYE 34.6074 -117.3883 831.4 1 1e6 DU/M PPP +CI SCIA 20 LYN 34.6074 -117.3883 831.4 1 1e6 DU/M PPP +CI SCIA 20 LYZ 34.6074 -117.3883 831.4 1 1e6 DU/M PPP +CI SCIA 20 LY1 34.6074 -117.3883 831.4 1 1e6 DU/M PPP +CI SCIA 20 LY2 34.6074 -117.3883 831.4 1 1e6 DU/M PPP +CI SCIA 20 LY3 34.6074 -117.3883 831.4 1 1e6 DU/M PPP +CI SCIA 20 LYQ 34.6074 -117.3883 831.4 1 1 - PPP +CI SCIP 20 LYE 32.9144 -118.4879 452.8 1 1e6 DU/M PPP +CI SCIP 20 LYN 32.9144 -118.4879 452.8 1 1e6 DU/M PPP +CI SCIP 20 LYZ 32.9144 -118.4879 452.8 1 1e6 DU/M PPP +CI SCIP 20 LY1 32.9144 -118.4879 452.8 1 1e6 DU/M PPP +CI SCIP 20 LY2 32.9144 -118.4879 452.8 1 1e6 DU/M PPP +CI SCIP 20 LY3 32.9144 -118.4879 452.8 1 1e6 DU/M PPP +CI SCIP 20 LYQ 32.9144 -118.4879 452.8 1 1 - PPP +CI SDHL 20 LYE 34.2550 -116.2789 835.0 1 1e6 DU/M PPP +CI SDHL 20 LYN 34.2550 -116.2789 835.0 1 1e6 DU/M PPP +CI SDHL 20 LYZ 34.2550 -116.2789 835.0 1 1e6 DU/M PPP +CI SDHL 20 LY1 34.2550 -116.2789 835.0 1 1e6 DU/M PPP +CI SDHL 20 LY2 34.2550 -116.2789 835.0 1 1e6 DU/M PPP +CI SDHL 20 LY3 34.2550 -116.2789 835.0 1 1e6 DU/M PPP +CI SDHL 20 LYQ 34.2550 -116.2789 835.0 1 1 - PPP +CI SFDM 20 LYE 34.4598 -118.7545 291.5 1 1e6 DU/M PPP +CI SFDM 20 LYN 34.4598 -118.7545 291.5 1 1e6 DU/M PPP +CI SFDM 20 LYZ 34.4598 -118.7545 291.5 1 1e6 DU/M PPP +CI SFDM 20 LY1 34.4598 -118.7545 291.5 1 1e6 DU/M PPP +CI SFDM 20 LY2 34.4598 -118.7545 291.5 1 1e6 DU/M PPP +CI SFDM 20 LY3 34.4598 -118.7545 291.5 1 1e6 DU/M PPP +CI SFDM 20 LYQ 34.4598 -118.7545 291.5 1 1 - PPP +CI SGLG 20 LYE 32.6493 -115.7264 78.3 1 1e6 DU/M PPP +CI SGLG 20 LYN 32.6493 -115.7264 78.3 1 1e6 DU/M PPP +CI SGLG 20 LYZ 32.6493 -115.7264 78.3 1 1e6 DU/M PPP +CI SGLG 20 LY1 32.6493 -115.7264 78.3 1 1e6 DU/M PPP +CI SGLG 20 LY2 32.6493 -115.7264 78.3 1 1e6 DU/M PPP +CI SGLG 20 LY3 32.6493 -115.7264 78.3 1 1e6 DU/M PPP +CI SGLG 20 LYQ 32.6493 -115.7264 78.3 1 1 - PPP +CI SGPS 20 LYE 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 20 LYN 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 20 LYZ 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 20 LY1 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 20 LY2 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 20 LY3 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 20 LYQ 33.9125 -116.6957 476.8 1 1 - PPP +CI SGPS 40 LYE 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 40 LYN 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 40 LYZ 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 40 LY1 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 40 LY2 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 40 LY3 33.9125 -116.6957 476.8 1 1e6 DU/M PPP +CI SGPS 40 LYQ 33.9125 -116.6957 476.8 1 1 - PPP +CI SHP5 20 LYE 35.2686 -120.6713 16.6 1 1e6 DU/M PPP +CI SHP5 20 LYN 35.2686 -120.6713 16.6 1 1e6 DU/M PPP +CI SHP5 20 LYZ 35.2686 -120.6713 16.6 1 1e6 DU/M PPP +CI SHP5 20 LY1 35.2686 -120.6713 16.6 1 1e6 DU/M PPP +CI SHP5 20 LY2 35.2686 -120.6713 16.6 1 1e6 DU/M PPP +CI SHP5 20 LY3 35.2686 -120.6713 16.6 1 1e6 DU/M PPP +CI SHP5 20 LYQ 35.2686 -120.6713 16.6 1 1 - PPP +CI SILK 20 LYE 34.1029 -118.2639 106.2 1 1e6 DU/M PPP +CI SILK 20 LYN 34.1029 -118.2639 106.2 1 1e6 DU/M PPP +CI SILK 20 LYZ 34.1029 -118.2639 106.2 1 1e6 DU/M PPP +CI SILK 20 LY1 34.1029 -118.2639 106.2 1 1e6 DU/M PPP +CI SILK 20 LY2 34.1029 -118.2639 106.2 1 1e6 DU/M PPP +CI SILK 20 LY3 34.1029 -118.2639 106.2 1 1e6 DU/M PPP +CI SILK 20 LYQ 34.1029 -118.2639 106.2 1 1 - PPP +CI SIMM 20 LYE 35.3511 -119.9978 583.5 1 1e6 DU/M PPP +CI SIMM 20 LYN 35.3511 -119.9978 583.5 1 1e6 DU/M PPP +CI SIMM 20 LYZ 35.3511 -119.9978 583.5 1 1e6 DU/M PPP +CI SIMM 20 LY1 35.3511 -119.9978 583.5 1 1e6 DU/M PPP +CI SIMM 20 LY2 35.3511 -119.9978 583.5 1 1e6 DU/M PPP +CI SIMM 20 LY3 35.3511 -119.9978 583.5 1 1e6 DU/M PPP +CI SIMM 20 LYQ 35.3511 -119.9978 583.5 1 1 - PPP +CI SIO5 20 LYE 32.8407 -117.2497 185.5 1 1e6 DU/M PPP +CI SIO5 20 LYN 32.8407 -117.2497 185.5 1 1e6 DU/M PPP +CI SIO5 20 LYZ 32.8407 -117.2497 185.5 1 1e6 DU/M PPP +CI SIO5 20 LY1 32.8407 -117.2497 185.5 1 1e6 DU/M PPP +CI SIO5 20 LY2 32.8407 -117.2497 185.5 1 1e6 DU/M PPP +CI SIO5 20 LY3 32.8407 -117.2497 185.5 1 1e6 DU/M PPP +CI SIO5 20 LYQ 32.8407 -117.2497 185.5 1 1 - PPP +CI SKYB 20 LYE 34.4386 -118.4786 520.1 1 1e6 DU/M PPP +CI SKYB 20 LYN 34.4386 -118.4786 520.1 1 1e6 DU/M PPP +CI SKYB 20 LYZ 34.4386 -118.4786 520.1 1 1e6 DU/M PPP +CI SKYB 20 LY1 34.4386 -118.4786 520.1 1 1e6 DU/M PPP +CI SKYB 20 LY2 34.4386 -118.4786 520.1 1 1e6 DU/M PPP +CI SKYB 20 LY3 34.4386 -118.4786 520.1 1 1e6 DU/M PPP +CI SKYB 20 LYQ 34.4386 -118.4786 520.1 1 1 - PPP +CI SLHG 20 LYE 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 20 LYN 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 20 LYZ 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 20 LY1 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 20 LY2 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 20 LY3 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 20 LYQ 33.1926 -116.2541 177.6 1 1 - PPP +CI SLHG 40 LYE 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 40 LYN 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 40 LYZ 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 40 LY1 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 40 LY2 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 40 LY3 33.1926 -116.2541 177.6 1 1e6 DU/M PPP +CI SLHG 40 LYQ 33.1926 -116.2541 177.6 1 1 - PPP +CI SLMS 20 LYE 33.2922 -115.9778 -46.0 1 1e6 DU/M PPP +CI SLMS 20 LYN 33.2922 -115.9778 -46.0 1 1e6 DU/M PPP +CI SLMS 20 LYZ 33.2922 -115.9778 -46.0 1 1e6 DU/M PPP +CI SLMS 20 LY1 33.2922 -115.9778 -46.0 1 1e6 DU/M PPP +CI SLMS 20 LY2 33.2922 -115.9778 -46.0 1 1e6 DU/M PPP +CI SLMS 20 LY3 33.2922 -115.9778 -46.0 1 1e6 DU/M PPP +CI SLMS 20 LYQ 33.2922 -115.9778 -46.0 1 1 - PPP +CI SNHS 20 LYE 33.9273 -117.9286 66.4 1 1e6 DU/M PPP +CI SNHS 20 LYN 33.9273 -117.9286 66.4 1 1e6 DU/M PPP +CI SNHS 20 LYZ 33.9273 -117.9286 66.4 1 1e6 DU/M PPP +CI SNHS 20 LY1 33.9273 -117.9286 66.4 1 1e6 DU/M PPP +CI SNHS 20 LY2 33.9273 -117.9286 66.4 1 1e6 DU/M PPP +CI SNHS 20 LY3 33.9273 -117.9286 66.4 1 1e6 DU/M PPP +CI SNHS 20 LYQ 33.9273 -117.9286 66.4 1 1 - PPP +CI SNI1 20 LYE 33.2479 -119.5244 239.7 1 1e6 DU/M PPP +CI SNI1 20 LYN 33.2479 -119.5244 239.7 1 1e6 DU/M PPP +CI SNI1 20 LYZ 33.2479 -119.5244 239.7 1 1e6 DU/M PPP +CI SNI1 20 LY1 33.2479 -119.5244 239.7 1 1e6 DU/M PPP +CI SNI1 20 LY2 33.2479 -119.5244 239.7 1 1e6 DU/M PPP +CI SNI1 20 LY3 33.2479 -119.5244 239.7 1 1e6 DU/M PPP +CI SNI1 20 LYQ 33.2479 -119.5244 239.7 1 1 - PPP +CI SNOG 20 LYE 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 20 LYN 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 20 LYZ 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 20 LY1 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 20 LY2 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 20 LY3 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 20 LYQ 34.0352 -116.8078 2314.7 1 1 - PPP +CI SNOG 30 LYE 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 30 LYN 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 30 LYZ 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 30 LY1 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 30 LY2 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 30 LY3 34.0352 -116.8078 2314.7 1 1e6 DU/M PPP +CI SNOG 30 LYQ 34.0352 -116.8078 2314.7 1 1 - PPP +BK SOD2 30 LYN 37.1664 -121.9255 986.8 1 1e6 DU/M PPP +BK SOD2 30 LYE 37.1664 -121.9255 986.8 1 1e6 DU/M PPP +BK SOD2 30 LYZ 37.1664 -121.9255 986.8 1 1e6 DU/M PPP +BK SOD2 30 LYQ 37.1664 -121.9255 986.8 1 1 - PPP +BK SOD2 30 LY1 37.1664 -121.9255 986.8 1 1e6 DU/M PPP +BK SOD2 30 LY2 37.1664 -121.9255 986.8 1 1e6 DU/M PPP +BK SOD2 30 LY3 37.1664 -121.9255 986.8 1 1e6 DU/M PPP +CI SOMT 20 LYE 34.3199 -119.0643 464.2 1 1e6 DU/M PPP +CI SOMT 20 LYN 34.3199 -119.0643 464.2 1 1e6 DU/M PPP +CI SOMT 20 LYZ 34.3199 -119.0643 464.2 1 1e6 DU/M PPP +CI SOMT 20 LY1 34.3199 -119.0643 464.2 1 1e6 DU/M PPP +CI SOMT 20 LY2 34.3199 -119.0643 464.2 1 1e6 DU/M PPP +CI SOMT 20 LY3 34.3199 -119.0643 464.2 1 1e6 DU/M PPP +CI SOMT 20 LYQ 34.3199 -119.0643 464.2 1 1 - PPP +CI SONG 20 LYE 33.3808 -117.5603 -3.0 1 1e6 DU/M PPP +CI SONG 20 LYN 33.3808 -117.5603 -3.0 1 1e6 DU/M PPP +CI SONG 20 LYZ 33.3808 -117.5603 -3.0 1 1e6 DU/M PPP +CI SONG 20 LY1 33.3808 -117.5603 -3.0 1 1e6 DU/M PPP +CI SONG 20 LY2 33.3808 -117.5603 -3.0 1 1e6 DU/M PPP +CI SONG 20 LY3 33.3808 -117.5603 -3.0 1 1e6 DU/M PPP +CI SONG 20 LYQ 33.3808 -117.5603 -3.0 1 1 - PPP +CI SPK1 20 LYE 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 20 LYN 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 20 LYZ 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 20 LY1 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 20 LY2 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 20 LY3 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 20 LYQ 34.0593 -118.6462 440.1 1 1 - PPP +CI SPK1 30 LYE 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 30 LYN 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 30 LYZ 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 30 LY1 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 30 LY2 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 30 LY3 34.0593 -118.6462 440.1 1 1e6 DU/M PPP +CI SPK1 30 LYQ 34.0593 -118.6462 440.1 1 1 - PPP +CI SPMS 20 LYE 33.9927 -117.8488 207.0 1 1e6 DU/M PPP +CI SPMS 20 LYN 33.9927 -117.8488 207.0 1 1e6 DU/M PPP +CI SPMS 20 LYZ 33.9927 -117.8488 207.0 1 1e6 DU/M PPP +CI SPMS 20 LY1 33.9927 -117.8488 207.0 1 1e6 DU/M PPP +CI SPMS 20 LY2 33.9927 -117.8488 207.0 1 1e6 DU/M PPP +CI SPMS 20 LY3 33.9927 -117.8488 207.0 1 1e6 DU/M PPP +CI SPMS 20 LYQ 33.9927 -117.8488 207.0 1 1 - PPP +BK SRB2 30 LYN 37.8744 -122.2670 55.0 1 1e6 DU/M PPP +BK SRB2 30 LYE 37.8744 -122.2670 55.0 1 1e6 DU/M PPP +BK SRB2 30 LYZ 37.8744 -122.2670 55.0 1 1e6 DU/M PPP +BK SRB2 30 LYQ 37.8744 -122.2670 55.0 1 1 - PPP +BK SRB2 30 LY1 37.8744 -122.2670 55.0 1 1e6 DU/M PPP +BK SRB2 30 LY2 37.8744 -122.2670 55.0 1 1e6 DU/M PPP +BK SRB2 30 LY3 37.8744 -122.2670 55.0 1 1e6 DU/M PPP +CI SRS1 20 LYE 34.0043 -120.0652 68.2 1 1e6 DU/M PPP +CI SRS1 20 LYN 34.0043 -120.0652 68.2 1 1e6 DU/M PPP +CI SRS1 20 LYZ 34.0043 -120.0652 68.2 1 1e6 DU/M PPP +CI SRS1 20 LY1 34.0043 -120.0652 68.2 1 1e6 DU/M PPP +CI SRS1 20 LY2 34.0043 -120.0652 68.2 1 1e6 DU/M PPP +CI SRS1 20 LY3 34.0043 -120.0652 68.2 1 1e6 DU/M PPP +CI SRS1 20 LYQ 34.0043 -120.0652 68.2 1 1 - PPP +BK SUTB 30 LYN 39.2058 -121.8206 616.5 1 1e6 DU/M PPP +BK SUTB 30 LYE 39.2058 -121.8206 616.5 1 1e6 DU/M PPP +BK SUTB 30 LYZ 39.2058 -121.8206 616.5 1 1e6 DU/M PPP +BK SUTB 30 LYQ 39.2058 -121.8206 616.5 1 1 - PPP +BK SUTB 30 LY1 39.2058 -121.8206 616.5 1 1e6 DU/M PPP +BK SUTB 30 LY2 39.2058 -121.8206 616.5 1 1e6 DU/M PPP +BK SUTB 30 LY3 39.2058 -121.8206 616.5 1 1e6 DU/M PPP +BK SVIN 30 LYN 38.0332 -122.5263 -27.5 1 1e6 DU/M PPP +BK SVIN 30 LYE 38.0332 -122.5263 -27.5 1 1e6 DU/M PPP +BK SVIN 30 LYZ 38.0332 -122.5263 -27.5 1 1e6 DU/M PPP +BK SVIN 30 LYQ 38.0332 -122.5263 -27.5 1 1 - PPP +BK SVIN 30 LY1 38.0332 -122.5263 -27.5 1 1e6 DU/M PPP +BK SVIN 30 LY2 38.0332 -122.5263 -27.5 1 1e6 DU/M PPP +BK SVIN 30 LY3 38.0332 -122.5263 -27.5 1 1e6 DU/M PPP +CI SYNG 20 LYE 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 20 LYN 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 20 LYZ 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 20 LY1 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 20 LY2 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 20 LY3 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 20 LYQ 34.6072 -120.0696 167.8 1 1 - PPP +CI SYNG 30 LYE 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 30 LYN 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 30 LYZ 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 30 LY1 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 30 LY2 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 30 LY3 34.6072 -120.0696 167.8 1 1e6 DU/M PPP +CI SYNG 30 LYQ 34.6072 -120.0696 167.8 1 1 - PPP +CI TABL 20 LYE 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 20 LYN 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 20 LYZ 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 20 LY1 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 20 LY2 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 20 LY3 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 20 LYQ 34.3818 -117.6783 2228.0 1 1 - PPP +CI TABL 40 LYE 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 40 LYN 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 40 LYZ 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 40 LY1 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 40 LY2 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 40 LY3 34.3818 -117.6783 2228.0 1 1e6 DU/M PPP +CI TABL 40 LYQ 34.3818 -117.6783 2228.0 1 1 - PPP +CI TAFT 20 LYE 35.1565 -119.4852 287.0 1 1e6 DU/M PPP +CI TAFT 20 LYN 35.1565 -119.4852 287.0 1 1e6 DU/M PPP +CI TAFT 20 LYZ 35.1565 -119.4852 287.0 1 1e6 DU/M PPP +CI TAFT 20 LY1 35.1565 -119.4852 287.0 1 1e6 DU/M PPP +CI TAFT 20 LY2 35.1565 -119.4852 287.0 1 1e6 DU/M PPP +CI TAFT 20 LY3 35.1565 -119.4852 287.0 1 1e6 DU/M PPP +CI TAFT 20 LYQ 35.1565 -119.4852 287.0 1 1 - PPP +CI TEHA 20 LYE 35.1431 -118.4698 1174.6 1 1e6 DU/M PPP +CI TEHA 20 LYN 35.1431 -118.4698 1174.6 1 1e6 DU/M PPP +CI TEHA 20 LYZ 35.1431 -118.4698 1174.6 1 1e6 DU/M PPP +CI TEHA 20 LY1 35.1431 -118.4698 1174.6 1 1e6 DU/M PPP +CI TEHA 20 LY2 35.1431 -118.4698 1174.6 1 1e6 DU/M PPP +CI TEHA 20 LY3 35.1431 -118.4698 1174.6 1 1e6 DU/M PPP +CI TEHA 20 LYQ 35.1431 -118.4698 1174.6 1 1 - PPP +CI THM2 20 LYE 33.5495 -117.7668 188.3 1 1e6 DU/M PPP +CI THM2 20 LYN 33.5495 -117.7668 188.3 1 1e6 DU/M PPP +CI THM2 20 LYZ 33.5495 -117.7668 188.3 1 1e6 DU/M PPP +CI THM2 20 LY1 33.5495 -117.7668 188.3 1 1e6 DU/M PPP +CI THM2 20 LY2 33.5495 -117.7668 188.3 1 1e6 DU/M PPP +CI THM2 20 LY3 33.5495 -117.7668 188.3 1 1e6 DU/M PPP +CI THM2 20 LYQ 33.5495 -117.7668 188.3 1 1 - PPP +CI THMG 20 LYE 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 20 LYN 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 20 LYZ 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 20 LY1 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 20 LY2 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 20 LY3 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 20 LYQ 33.6506 -116.0773 33.6 1 1 - PPP +CI THMG 40 LYE 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 40 LYN 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 40 LYZ 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 40 LY1 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 40 LY2 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 40 LY3 33.6506 -116.0773 33.6 1 1e6 DU/M PPP +CI THMG 40 LYQ 33.6506 -116.0773 33.6 1 1 - PPP +BK TIBB 30 LYN 37.8909 -122.4476 -21.1 1 1e6 DU/M PPP +BK TIBB 30 LYE 37.8909 -122.4476 -21.1 1 1e6 DU/M PPP +BK TIBB 30 LYZ 37.8909 -122.4476 -21.1 1 1e6 DU/M PPP +BK TIBB 30 LYQ 37.8909 -122.4476 -21.1 1 1 - PPP +BK TIBB 30 LY1 37.8909 -122.4476 -21.1 1 1e6 DU/M PPP +BK TIBB 30 LY2 37.8909 -122.4476 -21.1 1 1e6 DU/M PPP +BK TIBB 30 LY3 37.8909 -122.4476 -21.1 1 1e6 DU/M PPP +CI TJRN 20 LYE 34.4835 -120.1326 157.1 1 1e6 DU/M PPP +CI TJRN 20 LYN 34.4835 -120.1326 157.1 1 1e6 DU/M PPP +CI TJRN 20 LYZ 34.4835 -120.1326 157.1 1 1e6 DU/M PPP +CI TJRN 20 LY1 34.4835 -120.1326 157.1 1 1e6 DU/M PPP +CI TJRN 20 LY2 34.4835 -120.1326 157.1 1 1e6 DU/M PPP +CI TJRN 20 LY3 34.4835 -120.1326 157.1 1 1e6 DU/M PPP +CI TJRN 20 LYQ 34.4835 -120.1326 157.1 1 1 - PPP +CI TMAP 20 LYE 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 20 LYN 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 20 LYZ 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 20 LY1 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 20 LY2 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 20 LY3 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 20 LYQ 33.6412 -116.1605 -66.9 1 1 - PPP +CI TMAP 40 LYE 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 40 LYN 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 40 LYZ 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 40 LY1 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 40 LY2 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 40 LY3 33.6412 -116.1605 -66.9 1 1e6 DU/M PPP +CI TMAP 40 LYQ 33.6412 -116.1605 -66.9 1 1 - PPP +CI TORP 20 LYE 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 20 LYN 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 20 LYZ 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 20 LY1 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 20 LY2 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 20 LY3 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 20 LYQ 33.7978 -118.3306 -5.2 1 1 - PPP +CI TORP 30 LYE 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 30 LYN 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 30 LYZ 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 30 LY1 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 30 LY2 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 30 LY3 33.7978 -118.3306 -5.2 1 1e6 DU/M PPP +CI TORP 30 LYQ 33.7978 -118.3306 -5.2 1 1 - PPP +CI TOST 20 LYE 34.2480 -118.8367 274.3 1 1e6 DU/M PPP +CI TOST 20 LYN 34.2480 -118.8367 274.3 1 1e6 DU/M PPP +CI TOST 20 LYZ 34.2480 -118.8367 274.3 1 1e6 DU/M PPP +CI TOST 20 LY1 34.2480 -118.8367 274.3 1 1e6 DU/M PPP +CI TOST 20 LY2 34.2480 -118.8367 274.3 1 1e6 DU/M PPP +CI TOST 20 LY3 34.2480 -118.8367 274.3 1 1e6 DU/M PPP +CI TOST 20 LYQ 34.2480 -118.8367 274.3 1 1 - PPP +CI TOWG 20 LYE 35.8086 -117.7649 657.1 1 1e6 DU/M PPP +CI TOWG 20 LYN 35.8086 -117.7649 657.1 1 1e6 DU/M PPP +CI TOWG 20 LYZ 35.8086 -117.7649 657.1 1 1e6 DU/M PPP +CI TOWG 20 LY1 35.8086 -117.7649 657.1 1 1e6 DU/M PPP +CI TOWG 20 LY2 35.8086 -117.7649 657.1 1 1e6 DU/M PPP +CI TOWG 20 LY3 35.8086 -117.7649 657.1 1 1e6 DU/M PPP +CI TOWG 20 LYQ 35.8086 -117.7649 657.1 1 1 - PPP +CI TPOG 20 LYE 34.8789 -118.2286 772.2 1 1e6 DU/M PPP +CI TPOG 20 LYN 34.8789 -118.2286 772.2 1 1e6 DU/M PPP +CI TPOG 20 LYZ 34.8789 -118.2286 772.2 1 1e6 DU/M PPP +CI TPOG 20 LY1 34.8789 -118.2286 772.2 1 1e6 DU/M PPP +CI TPOG 20 LY2 34.8789 -118.2286 772.2 1 1e6 DU/M PPP +CI TPOG 20 LY3 34.8789 -118.2286 772.2 1 1e6 DU/M PPP +CI TPOG 20 LYQ 34.8789 -118.2286 772.2 1 1 - PPP +CI TRAK 20 LYE 33.6179 -117.8034 115.5 1 1e6 DU/M PPP +CI TRAK 20 LYN 33.6179 -117.8034 115.5 1 1e6 DU/M PPP +CI TRAK 20 LYZ 33.6179 -117.8034 115.5 1 1e6 DU/M PPP +CI TRAK 20 LY1 33.6179 -117.8034 115.5 1 1e6 DU/M PPP +CI TRAK 20 LY2 33.6179 -117.8034 115.5 1 1e6 DU/M PPP +CI TRAK 20 LY3 33.6179 -117.8034 115.5 1 1e6 DU/M PPP +CI TRAK 20 LYQ 33.6179 -117.8034 115.5 1 1 - PPP +CI TWMS 20 LYE 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 20 LYN 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 20 LYZ 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 20 LY1 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 20 LY2 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 20 LY3 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 20 LYQ 33.9725 -117.7255 208.0 1 1 - PPP +CI TWMS 30 LYE 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 30 LYN 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 30 LYZ 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 30 LY1 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 30 LY2 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 30 LY3 33.9725 -117.7255 208.0 1 1e6 DU/M PPP +CI TWMS 30 LYQ 33.9725 -117.7255 208.0 1 1 - PPP +BK UCD1 30 LYN 38.5362 -121.7512 -0.5 1 1e6 DU/M PPP +BK UCD1 30 LYE 38.5362 -121.7512 -0.5 1 1e6 DU/M PPP +BK UCD1 30 LYZ 38.5362 -121.7512 -0.5 1 1e6 DU/M PPP +BK UCD1 30 LYQ 38.5362 -121.7512 -0.5 1 1 - PPP +BK UCD1 30 LY1 38.5362 -121.7512 -0.5 1 1e6 DU/M PPP +BK UCD1 30 LY2 38.5362 -121.7512 -0.5 1 1e6 DU/M PPP +BK UCD1 30 LY3 38.5362 -121.7512 -0.5 1 1e6 DU/M PPP +BK UCSF 30 LYN 37.7630 -122.4582 154.6 1 1e6 DU/M PPP +BK UCSF 30 LYE 37.7630 -122.4582 154.6 1 1e6 DU/M PPP +BK UCSF 30 LYZ 37.7630 -122.4582 154.6 1 1e6 DU/M PPP +BK UCSF 30 LYQ 37.7630 -122.4582 154.6 1 1 - PPP +BK UCSF 30 LY1 37.7630 -122.4582 154.6 1 1e6 DU/M PPP +BK UCSF 30 LY2 37.7630 -122.4582 154.6 1 1e6 DU/M PPP +BK UCSF 30 LY3 37.7630 -122.4582 154.6 1 1e6 DU/M PPP +CI USC2 20 LYE 34.0195 -118.2773 55.9 1 1e6 DU/M PPP +CI USC2 20 LYN 34.0195 -118.2773 55.9 1 1e6 DU/M PPP +CI USC2 20 LYZ 34.0195 -118.2773 55.9 1 1e6 DU/M PPP +CI USC2 20 LY1 34.0195 -118.2773 55.9 1 1e6 DU/M PPP +CI USC2 20 LY2 34.0195 -118.2773 55.9 1 1e6 DU/M PPP +CI USC2 20 LY3 34.0195 -118.2773 55.9 1 1e6 DU/M PPP +CI USC2 20 LYQ 34.0195 -118.2773 55.9 1 1 - PPP +CI USGC 20 LYE 33.0301 -116.0853 133.4 1 1e6 DU/M PPP +CI USGC 20 LYN 33.0301 -116.0853 133.4 1 1e6 DU/M PPP +CI USGC 20 LYZ 33.0301 -116.0853 133.4 1 1e6 DU/M PPP +CI USGC 20 LY1 33.0301 -116.0853 133.4 1 1e6 DU/M PPP +CI USGC 20 LY2 33.0301 -116.0853 133.4 1 1e6 DU/M PPP +CI USGC 20 LY3 33.0301 -116.0853 133.4 1 1e6 DU/M PPP +CI USGC 20 LYQ 33.0301 -116.0853 133.4 1 1 - PPP +CI VCST 20 LYE 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 20 LYN 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 20 LYZ 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 20 LY1 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 20 LY2 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 20 LY3 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 20 LYQ 34.8515 -119.4839 809.6 1 1 - PPP +CI VCST 30 LYE 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 30 LYN 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 30 LYZ 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 30 LY1 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 30 LY2 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 30 LY3 34.8515 -119.4839 809.6 1 1e6 DU/M PPP +CI VCST 30 LYQ 34.8515 -119.4839 809.6 1 1 - PPP +CI VDCY 20 LYE 34.1786 -118.2200 318.1 1 1e6 DU/M PPP +CI VDCY 20 LYN 34.1786 -118.2200 318.1 1 1e6 DU/M PPP +CI VDCY 20 LYZ 34.1786 -118.2200 318.1 1 1e6 DU/M PPP +CI VDCY 20 LY1 34.1786 -118.2200 318.1 1 1e6 DU/M PPP +CI VDCY 20 LY2 34.1786 -118.2200 318.1 1 1e6 DU/M PPP +CI VDCY 20 LY3 34.1786 -118.2200 318.1 1 1e6 DU/M PPP +CI VDCY 20 LYQ 34.1786 -118.2200 318.1 1 1 - PPP +CI VIMT 20 LYE 34.1264 -118.5144 553.7 1 1e6 DU/M PPP +CI VIMT 20 LYN 34.1264 -118.5144 553.7 1 1e6 DU/M PPP +CI VIMT 20 LYZ 34.1264 -118.5144 553.7 1 1e6 DU/M PPP +CI VIMT 20 LY1 34.1264 -118.5144 553.7 1 1e6 DU/M PPP +CI VIMT 20 LY2 34.1264 -118.5144 553.7 1 1e6 DU/M PPP +CI VIMT 20 LY3 34.1264 -118.5144 553.7 1 1e6 DU/M PPP +CI VIMT 20 LYQ 34.1264 -118.5144 553.7 1 1 - PPP +CI VNCO 20 LYE 34.2758 -119.2377 25.6 1 1e6 DU/M PPP +CI VNCO 20 LYN 34.2758 -119.2377 25.6 1 1e6 DU/M PPP +CI VNCO 20 LYZ 34.2758 -119.2377 25.6 1 1e6 DU/M PPP +CI VNCO 20 LY1 34.2758 -119.2377 25.6 1 1e6 DU/M PPP +CI VNCO 20 LY2 34.2758 -119.2377 25.6 1 1e6 DU/M PPP +CI VNCO 20 LY3 34.2758 -119.2377 25.6 1 1e6 DU/M PPP +CI VNCO 20 LYQ 34.2758 -119.2377 25.6 1 1 - PPP +CI VNCX 20 LYE 34.2932 -118.4845 328.5 1 1e6 DU/M PPP +CI VNCX 20 LYN 34.2932 -118.4845 328.5 1 1e6 DU/M PPP +CI VNCX 20 LYZ 34.2932 -118.4845 328.5 1 1e6 DU/M PPP +CI VNCX 20 LY1 34.2932 -118.4845 328.5 1 1e6 DU/M PPP +CI VNCX 20 LY2 34.2932 -118.4845 328.5 1 1e6 DU/M PPP +CI VNCX 20 LY3 34.2932 -118.4845 328.5 1 1e6 DU/M PPP +CI VNCX 20 LYQ 34.2932 -118.4845 328.5 1 1 - PPP +CI VNDP 20 LYE 34.5563 -120.6165 -11.6 1 1e6 DU/M PPP +CI VNDP 20 LYN 34.5563 -120.6165 -11.6 1 1e6 DU/M PPP +CI VNDP 20 LYZ 34.5563 -120.6165 -11.6 1 1e6 DU/M PPP +CI VNDP 20 LY1 34.5563 -120.6165 -11.6 1 1e6 DU/M PPP +CI VNDP 20 LY2 34.5563 -120.6165 -11.6 1 1e6 DU/M PPP +CI VNDP 20 LY3 34.5563 -120.6165 -11.6 1 1e6 DU/M PPP +CI VNDP 20 LYQ 34.5563 -120.6165 -11.6 1 1 - PPP +CI VNPS 20 LYE 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 20 LYN 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 20 LYZ 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 20 LY1 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 20 LY2 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 20 LY3 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 20 LYQ 34.5015 -118.1212 961.9 1 1 - PPP +CI VNPS 40 LYE 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 40 LYN 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 40 LYZ 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 40 LY1 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 40 LY2 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 40 LY3 34.5015 -118.1212 961.9 1 1e6 DU/M PPP +CI VNPS 40 LYQ 34.5015 -118.1212 961.9 1 1 - PPP +CI VTIS 20 LYE 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 20 LYN 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 20 LYZ 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 20 LY1 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 20 LY2 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 20 LY3 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 20 LYQ 33.7126 -118.2938 59.5 1 1 - PPP +CI VTIS 30 LYE 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 30 LYN 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 30 LYZ 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 30 LY1 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 30 LY2 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 30 LY3 33.7126 -118.2938 59.5 1 1e6 DU/M PPP +CI VTIS 30 LYQ 33.7126 -118.2938 59.5 1 1 - PPP +CI VTOR 20 LYE 33.2250 -117.1932 379.9 1 1e6 DU/M PPP +CI VTOR 20 LYN 33.2250 -117.1932 379.9 1 1e6 DU/M PPP +CI VTOR 20 LYZ 33.2250 -117.1932 379.9 1 1e6 DU/M PPP +CI VTOR 20 LY1 33.2250 -117.1932 379.9 1 1e6 DU/M PPP +CI VTOR 20 LY2 33.2250 -117.1932 379.9 1 1e6 DU/M PPP +CI VTOR 20 LY3 33.2250 -117.1932 379.9 1 1e6 DU/M PPP +CI VTOR 20 LYQ 33.2250 -117.1932 379.9 1 1 - PPP +CI WASG 20 LYE 35.7384 -118.5570 1834.9 1 1e6 DU/M PPP +CI WASG 20 LYN 35.7384 -118.5570 1834.9 1 1e6 DU/M PPP +CI WASG 20 LYZ 35.7384 -118.5570 1834.9 1 1e6 DU/M PPP +CI WASG 20 LY1 35.7384 -118.5570 1834.9 1 1e6 DU/M PPP +CI WASG 20 LY2 35.7384 -118.5570 1834.9 1 1e6 DU/M PPP +CI WASG 20 LY3 35.7384 -118.5570 1834.9 1 1e6 DU/M PPP +CI WASG 20 LYQ 35.7384 -118.5570 1834.9 1 1 - PPP +CI WCHS 20 LYE 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 20 LYN 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 20 LYZ 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 20 LY1 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 20 LY2 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 20 LY3 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 20 LYQ 34.0619 -117.9111 100.0 1 1 - PPP +CI WCHS 30 LYE 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 30 LYN 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 30 LYZ 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 30 LY1 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 30 LY2 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 30 LY3 34.0619 -117.9111 100.0 1 1e6 DU/M PPP +CI WCHS 30 LYQ 34.0619 -117.9111 100.0 1 1 - PPP +CI WGPP 20 LYE 35.0108 -118.9837 352.0 1 1e6 DU/M PPP +CI WGPP 20 LYN 35.0108 -118.9837 352.0 1 1e6 DU/M PPP +CI WGPP 20 LYZ 35.0108 -118.9837 352.0 1 1e6 DU/M PPP +CI WGPP 20 LY1 35.0108 -118.9837 352.0 1 1e6 DU/M PPP +CI WGPP 20 LY2 35.0108 -118.9837 352.0 1 1e6 DU/M PPP +CI WGPP 20 LY3 35.0108 -118.9837 352.0 1 1e6 DU/M PPP +CI WGPP 20 LYQ 35.0108 -118.9837 352.0 1 1 - PPP +CI WHC1 20 LYE 33.9799 -118.0312 94.2 1 1e6 DU/M PPP +CI WHC1 20 LYN 33.9799 -118.0312 94.2 1 1e6 DU/M PPP +CI WHC1 20 LYZ 33.9799 -118.0312 94.2 1 1e6 DU/M PPP +CI WHC1 20 LY1 33.9799 -118.0312 94.2 1 1e6 DU/M PPP +CI WHC1 20 LY2 33.9799 -118.0312 94.2 1 1e6 DU/M PPP +CI WHC1 20 LY3 33.9799 -118.0312 94.2 1 1e6 DU/M PPP +CI WHC1 20 LYQ 33.9799 -118.0312 94.2 1 1 - PPP +CI WHFG 20 LYE 35.6951 -118.3520 861.9 1 1e6 DU/M PPP +CI WHFG 20 LYN 35.6951 -118.3520 861.9 1 1e6 DU/M PPP +CI WHFG 20 LYZ 35.6951 -118.3520 861.9 1 1e6 DU/M PPP +CI WHFG 20 LY1 35.6951 -118.3520 861.9 1 1e6 DU/M PPP +CI WHFG 20 LY2 35.6951 -118.3520 861.9 1 1e6 DU/M PPP +CI WHFG 20 LY3 35.6951 -118.3520 861.9 1 1e6 DU/M PPP +CI WHFG 20 LYQ 35.6951 -118.3520 861.9 1 1 - PPP +CI WHYT 20 LYE 33.6745 -117.6435 265.4 1 1e6 DU/M PPP +CI WHYT 20 LYN 33.6745 -117.6435 265.4 1 1e6 DU/M PPP +CI WHYT 20 LYZ 33.6745 -117.6435 265.4 1 1e6 DU/M PPP +CI WHYT 20 LY1 33.6745 -117.6435 265.4 1 1e6 DU/M PPP +CI WHYT 20 LY2 33.6745 -117.6435 265.4 1 1e6 DU/M PPP +CI WHYT 20 LY3 33.6745 -117.6435 265.4 1 1e6 DU/M PPP +CI WHYT 20 LYQ 33.6745 -117.6435 265.4 1 1 - PPP +CI WIDC 20 LYE 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 20 LYN 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 20 LYZ 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 20 LY1 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 20 LY2 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 20 LY3 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 20 LYQ 33.9348 -116.3918 445.0 1 1 - PPP +CI WIDC 40 LYE 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 40 LYN 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 40 LYZ 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 40 LY1 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 40 LY2 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 40 LY3 33.9348 -116.3918 445.0 1 1e6 DU/M PPP +CI WIDC 40 LYQ 33.9348 -116.3918 445.0 1 1 - PPP +CI WKPK 20 LYE 34.5685 -118.7415 1208.9 1 1e6 DU/M PPP +CI WKPK 20 LYN 34.5685 -118.7415 1208.9 1 1e6 DU/M PPP +CI WKPK 20 LYZ 34.5685 -118.7415 1208.9 1 1e6 DU/M PPP +CI WKPK 20 LY1 34.5685 -118.7415 1208.9 1 1e6 DU/M PPP +CI WKPK 20 LY2 34.5685 -118.7415 1208.9 1 1e6 DU/M PPP +CI WKPK 20 LY3 34.5685 -118.7415 1208.9 1 1e6 DU/M PPP +CI WKPK 20 LYQ 34.5685 -118.7415 1208.9 1 1 - PPP +CI WLHG 20 LYE 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 20 LYN 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 20 LYZ 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 20 LY1 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 20 LY2 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 20 LY3 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 20 LYQ 36.1521 -118.3131 2646.2 1 1 - PPP +CI WLHG 30 LYE 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 30 LYN 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 30 LYZ 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 30 LY1 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 30 LY2 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 30 LY3 36.1521 -118.3131 2646.2 1 1e6 DU/M PPP +CI WLHG 30 LYQ 36.1521 -118.3131 2646.2 1 1 - PPP +CI WLSN 20 LYE 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 20 LYN 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 20 LYZ 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 20 LY1 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 20 LY2 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 20 LY3 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 20 LYQ 34.2261 -118.0559 1705.3 1 1 - PPP +CI WLSN 30 LYE 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 30 LYN 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 30 LYZ 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 30 LY1 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 30 LY2 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 30 LY3 34.2261 -118.0559 1705.3 1 1e6 DU/M PPP +CI WLSN 30 LYQ 34.2261 -118.0559 1705.3 1 1 - PPP +CI WMAP 20 LYE 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 20 LYN 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 20 LYZ 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 20 LY1 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 20 LY2 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 20 LY3 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 20 LYQ 34.2594 -118.4143 268.0 1 1 - PPP +CI WMAP 30 LYE 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 30 LYN 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 30 LYZ 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 30 LY1 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 30 LY2 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 30 LY3 34.2594 -118.4143 268.0 1 1e6 DU/M PPP +CI WMAP 30 LYQ 34.2594 -118.4143 268.0 1 1 - PPP +CI WMDG 20 LYE 33.0383 -115.5819 -78.5 1 1e6 DU/M PPP +CI WMDG 20 LYN 33.0383 -115.5819 -78.5 1 1e6 DU/M PPP +CI WMDG 20 LYZ 33.0383 -115.5819 -78.5 1 1e6 DU/M PPP +CI WMDG 20 LY1 33.0383 -115.5819 -78.5 1 1e6 DU/M PPP +CI WMDG 20 LY2 33.0383 -115.5819 -78.5 1 1e6 DU/M PPP +CI WMDG 20 LY3 33.0383 -115.5819 -78.5 1 1e6 DU/M PPP +CI WMDG 20 LYQ 33.0383 -115.5819 -78.5 1 1 - PPP +CI WNRA 20 LYE 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 20 LYN 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 20 LYZ 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 20 LY1 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 20 LY2 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 20 LY3 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 20 LYQ 34.0432 -118.0593 40.0 1 1 - PPP +CI WNRA 30 LYE 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 30 LYN 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 30 LYZ 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 30 LY1 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 30 LY2 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 30 LY3 34.0432 -118.0593 40.0 1 1e6 DU/M PPP +CI WNRA 30 LYQ 34.0432 -118.0593 40.0 1 1 - PPP +CI WOMT 20 LYE 34.6690 -116.9317 1353.0 1 1e6 DU/M PPP +CI WOMT 20 LYN 34.6690 -116.9317 1353.0 1 1e6 DU/M PPP +CI WOMT 20 LYZ 34.6690 -116.9317 1353.0 1 1e6 DU/M PPP +CI WOMT 20 LY1 34.6690 -116.9317 1353.0 1 1e6 DU/M PPP +CI WOMT 20 LY2 34.6690 -116.9317 1353.0 1 1e6 DU/M PPP +CI WOMT 20 LY3 34.6690 -116.9317 1353.0 1 1e6 DU/M PPP +CI WOMT 20 LYQ 34.6690 -116.9317 1353.0 1 1 - PPP +CI WORG 20 LYE 35.6956 -118.2424 798.4 1 1e6 DU/M PPP +CI WORG 20 LYN 35.6956 -118.2424 798.4 1 1e6 DU/M PPP +CI WORG 20 LYZ 35.6956 -118.2424 798.4 1 1e6 DU/M PPP +CI WORG 20 LY1 35.6956 -118.2424 798.4 1 1e6 DU/M PPP +CI WORG 20 LY2 35.6956 -118.2424 798.4 1 1e6 DU/M PPP +CI WORG 20 LY3 35.6956 -118.2424 798.4 1 1e6 DU/M PPP +CI WORG 20 LYQ 35.6956 -118.2424 798.4 1 1 - PPP +CI WRHS 20 LYE 33.9582 -118.4276 7.9 1 1e6 DU/M PPP +CI WRHS 20 LYN 33.9582 -118.4276 7.9 1 1e6 DU/M PPP +CI WRHS 20 LYZ 33.9582 -118.4276 7.9 1 1e6 DU/M PPP +CI WRHS 20 LY1 33.9582 -118.4276 7.9 1 1e6 DU/M PPP +CI WRHS 20 LY2 33.9582 -118.4276 7.9 1 1e6 DU/M PPP +CI WRHS 20 LY3 33.9582 -118.4276 7.9 1 1e6 DU/M PPP +CI WRHS 20 LYQ 33.9582 -118.4276 7.9 1 1 - PPP +CI WWFG 20 LYE 33.2788 -115.5788 -93.6 1 1e6 DU/M PPP +CI WWFG 20 LYN 33.2788 -115.5788 -93.6 1 1e6 DU/M PPP +CI WWFG 20 LYZ 33.2788 -115.5788 -93.6 1 1e6 DU/M PPP +CI WWFG 20 LY1 33.2788 -115.5788 -93.6 1 1e6 DU/M PPP +CI WWFG 20 LY2 33.2788 -115.5788 -93.6 1 1e6 DU/M PPP +CI WWFG 20 LY3 33.2788 -115.5788 -93.6 1 1e6 DU/M PPP +CI WWFG 20 LYQ 33.2788 -115.5788 -93.6 1 1 - PPP +CI WWMT 20 LYE 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 20 LYN 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 20 LYZ 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 20 LY1 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 20 LY2 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 20 LY3 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 20 LYQ 33.9553 -116.6539 796.5 1 1 - PPP +CI WWMT 40 LYE 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 40 LYN 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 40 LYZ 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 40 LY1 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 40 LY2 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 40 LY3 33.9553 -116.6539 796.5 1 1e6 DU/M PPP +CI WWMT 40 LYQ 33.9553 -116.6539 796.5 1 1 - PPP +BK YBH2 30 LYN 41.7317 -122.7107 1065.7 1 1e6 DU/M PPP +BK YBH2 30 LYE 41.7317 -122.7107 1065.7 1 1e6 DU/M PPP +BK YBH2 30 LYZ 41.7317 -122.7107 1065.7 1 1e6 DU/M PPP +BK YBH2 30 LYQ 41.7317 -122.7107 1065.7 1 1 - PPP +BK YBH2 30 LY1 41.7317 -122.7107 1065.7 1 1e6 DU/M PPP +BK YBH2 30 LY2 41.7317 -122.7107 1065.7 1 1e6 DU/M PPP +BK YBH2 30 LY3 41.7317 -122.7107 1065.7 1 1e6 DU/M PPP +CI YUHG 20 LYE 32.6476 -115.9222 152.6 1 1e6 DU/M PPP +CI YUHG 20 LYN 32.6476 -115.9222 152.6 1 1e6 DU/M PPP +CI YUHG 20 LYZ 32.6476 -115.9222 152.6 1 1e6 DU/M PPP +CI YUHG 20 LY1 32.6476 -115.9222 152.6 1 1e6 DU/M PPP +CI YUHG 20 LY2 32.6476 -115.9222 152.6 1 1e6 DU/M PPP +CI YUHG 20 LY3 32.6476 -115.9222 152.6 1 1e6 DU/M PPP +CI YUHG 20 LYQ 32.6476 -115.9222 152.6 1 1 - PPP diff --git a/src/tests/data/pgd_threshold_PW.txt b/src/tests/data/pgd_threshold_PW.txt new file mode 100644 index 00000000..2e252604 --- /dev/null +++ b/src/tests/data/pgd_threshold_PW.txt @@ -0,0 +1,4 @@ +0 17.5 3 +25 23 3 +40 41 3 +70.2 95 3 \ No newline at end of file diff --git a/src/tests/data/raw_sigma_threshold_PW.txt b/src/tests/data/raw_sigma_threshold_PW.txt new file mode 100644 index 00000000..19e8dbac --- /dev/null +++ b/src/tests/data/raw_sigma_threshold_PW.txt @@ -0,0 +1 @@ +30 15 12 diff --git a/src/tests/data/sa_message.xml b/src/tests/data/sa_message.xml new file mode 100644 index 00000000..f144f866 --- /dev/null +++ b/src/tests/data/sa_message.xml @@ -0,0 +1,67 @@ + + + + + 2.0021 + 0.3366 + 36.4340 + 0.1000 + -120.8092 + 0.1000 + 8.0000 + 5.0000 + 2022-09-16T08:20:31.233Z + 1.6751 + 0.9256 + 5 + + + + + + + + + + + BBGB.NC.HHZ.-- + 0.0011 + 36.5785 + -121.0396 + + + + + + BABI.BK.HNZ.00 + 0.1890 + 36.5158 + -120.8530 + + + + PBC.NC.HNZ.01 + 0.1142 + 36.3203 + -120.9541 + + + + BBGB.NC.HNZ.-- + 0.0894 + 36.5785 + -121.0396 + + + + BTV.NC.HNZ.01 + 0.0492 + 36.4553 + -121.0580 + + + + + + + diff --git a/src/tests/gfast_ut_utils.h b/src/tests/gfast_ut_utils.h new file mode 100644 index 00000000..5b24cf34 --- /dev/null +++ b/src/tests/gfast_ut_utils.h @@ -0,0 +1,313 @@ +/** + * @file gfast_ut_utils.h + * @author Carl Ulberg, University of Washington (ulbergc@uw.edu) + * @brief Helper functions for GFAST unit tests + */ +#include "gtest/gtest.h" + +#include "gfast.h" +#include "iscl/memory/memory.h" + +// See https://github.com/google/googletest/blob/main/docs/advanced.md#using-a-function-that-returns-an-assertionresult +namespace testing { + +// Returns an AssertionResult object to indicate that an assertion has +// succeeded. +AssertionResult AssertionSuccess(); + +// Returns an AssertionResult object to indicate that an assertion has +// failed. +AssertionResult AssertionFailure(); + +} + +testing::AssertionResult lequal(double a, double b, double tol) +{ + if (a == 0.0 && b == 0.0){return testing::AssertionSuccess();} + if (fabs(a - b)/fabs(a + b) > tol) { + return testing::AssertionFailure() << a << " and " << b << " aren't within " << tol << " sig figs"; + } + return testing::AssertionSuccess() << a << " and " << b << " are within " << tol << " sig figs"; +} + +// Based on gfast/unit_tests/pgd.c by Ben Baker +int read_pgd_results(const char *filenm, + struct GFAST_pgd_props_struct *pgd_props, + struct GFAST_peakDisplacementData_struct *pgd_data, + struct GFAST_pgdResults_struct *pgd, + double *SA_lat, double *SA_lon, double *SA_dep) +{ + FILE *infl; + char cline[128]; + int i, ierr; + //------------------------------------------------------------------------// + ierr = 1; + infl = fopen(filenm, "r"); + // line 1 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%d %d %d %d %lf %lf %lf\n", + &pgd_data->nsites, &pgd_props->ngridSearch_deps, + &pgd_props->utm_zone, &pgd_props->min_sites, + &pgd_props->dist_tol, &pgd_props->disp_def, + &pgd_props->window_vel); + // line 2 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf\n", SA_lat, SA_lon, SA_dep); + // pgd data + pgd_data->pd = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->wt = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->sta_lat = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->sta_lon = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->sta_alt = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->lmask = ISCL_memory_calloc__bool(pgd_data->nsites); + pgd_data->lactive = ISCL_memory_calloc__bool(pgd_data->nsites); + for (i=0; insites; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf\n", + &pgd_data->sta_lat[i], &pgd_data->sta_lon[i], + &pgd_data->sta_alt[i], &pgd_data->pd[i]); + pgd_data->wt[i] = 1.0; + pgd_data->lactive[i] = true; + } + // Results + depths in grid search + pgd->nsites = pgd_data->nsites; + pgd->ndeps = pgd_props->ngridSearch_deps; + pgd->nlats = 1; + pgd->nlons = 1; + pgd->mpgd = ISCL_memory_calloc__double(pgd->ndeps); + pgd->mpgd_vr = ISCL_memory_calloc__double(pgd->ndeps); + pgd->dep_vr_pgd = ISCL_memory_calloc__double(pgd->ndeps); + pgd->iqr = ISCL_memory_calloc__double(pgd->ndeps); + pgd->UP = ISCL_memory_calloc__double(pgd->ndeps*pgd->nsites); + pgd->UPinp = ISCL_memory_calloc__double(pgd->nsites); + pgd->srcDepths = ISCL_memory_calloc__double(pgd->ndeps); + pgd->srdist = ISCL_memory_calloc__double(pgd->ndeps*pgd->nsites); + pgd->lsiteUsed = ISCL_memory_calloc__bool(pgd->nsites); + // (a) depths + for (i=0; indeps; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf\n", &pgd->srcDepths[i]); + } + // (b) results + for (i=0; indeps; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf\n", + &pgd->mpgd[i], &pgd->mpgd_vr[i], &pgd->iqr[i]); + } + fclose(infl); + ierr = 0; +ERROR:; + return ierr; +} + +// Based on gfast/unit_tests/cmt.c by Ben Baker +int read_cmt_results(const char *filenm, + struct GFAST_cmt_props_struct *cmt_props, + struct GFAST_offsetData_struct *cmt_data, + struct GFAST_cmtResults_struct *cmt, + double *SA_lat, double *SA_lon, double *SA_dep) +{ + FILE *infl; + char cline[128]; + double mxx, myy, mzz, mxy, mxz, myz; + int i, idep, ierr, ldevi; + ierr = 1; + infl = fopen(filenm, "r"); + // line 1 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%d %d %d %d %d %d %d %lf %lf\n", + &cmt_data->nsites, &cmt_props->ngridSearch_deps, + &cmt_props->ngridSearch_lats, &cmt_props->ngridSearch_lons, + &cmt_props->utm_zone, &cmt_props->min_sites, + &ldevi, &cmt_props->window_vel, + &cmt_props->window_avg); + cmt_props->ldeviatoric = true; + if (ldevi != 1){cmt_props->ldeviatoric = false;} + // line 2 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf\n", SA_lat, SA_lon, SA_dep); + cmt_data->ubuff = memory_calloc64f(cmt_data->nsites); + cmt_data->ebuff = memory_calloc64f(cmt_data->nsites); + cmt_data->nbuff = memory_calloc64f(cmt_data->nsites); + cmt_data->wtu = memory_calloc64f(cmt_data->nsites); + cmt_data->wte = memory_calloc64f(cmt_data->nsites); + cmt_data->wtn = memory_calloc64f(cmt_data->nsites); + cmt_data->sta_lat = memory_calloc64f(cmt_data->nsites); + cmt_data->sta_lon = memory_calloc64f(cmt_data->nsites); + cmt_data->sta_alt = memory_calloc64f(cmt_data->nsites); + cmt_data->lactive = ISCL_memory_calloc__bool(cmt_data->nsites); + cmt_data->lmask = ISCL_memory_calloc__bool(cmt_data->nsites); + // cmt data + for (i=0; insites; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf\n", + &cmt_data->sta_lat[i], &cmt_data->sta_lon[i], + &cmt_data->sta_alt[i], + &cmt_data->nbuff[i], &cmt_data->ebuff[i], &cmt_data->ubuff[i]); + cmt_data->wtu[i] = 1.0; + cmt_data->wte[i] = 1.0; + cmt_data->wtn[i] = 1.0; + cmt_data->lactive[i] = true; + } + // Results + depths in grid search + cmt->nsites = cmt_data->nsites; + cmt->ndeps = cmt_props->ngridSearch_deps; + cmt->nlats = cmt_props->ngridSearch_lats; + cmt->nlons = cmt_props->ngridSearch_lons; + cmt->l2 = memory_calloc64f(cmt->ndeps); + cmt->pct_dc = memory_calloc64f(cmt->ndeps); + cmt->objfn = memory_calloc64f(cmt->ndeps); + cmt->mts = memory_calloc64f(cmt->ndeps*6); + cmt->str1 = memory_calloc64f(cmt->ndeps); + cmt->str2 = memory_calloc64f(cmt->ndeps); + cmt->dip1 = memory_calloc64f(cmt->ndeps); + cmt->dip2 = memory_calloc64f(cmt->ndeps); + cmt->rak1 = memory_calloc64f(cmt->ndeps); + cmt->rak2 = memory_calloc64f(cmt->ndeps); + cmt->Mw = memory_calloc64f(cmt->ndeps); + cmt->srcDepths = memory_calloc64f(cmt->ndeps); + cmt->EN = memory_calloc64f(cmt->ndeps*cmt_data->nsites); + cmt->NN = memory_calloc64f(cmt->ndeps*cmt_data->nsites); + cmt->UN = memory_calloc64f(cmt->ndeps*cmt_data->nsites); + cmt->Einp = memory_calloc64f(cmt_data->nsites); + cmt->Ninp = memory_calloc64f(cmt_data->nsites); + cmt->Uinp = memory_calloc64f(cmt_data->nsites); + for (idep=0; idepndeps; idep++) + { + // depth + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf\n", &cmt->srcDepths[idep]); + // moment tensor + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf\n", + &mxx, &myy, &mzz, &mxy, &mxz, &myz); + cmt->mts[6*idep+0] = mxx; + cmt->mts[6*idep+1] = myy; + cmt->mts[6*idep+2] = mzz; + cmt->mts[6*idep+3] = mxy; + cmt->mts[6*idep+4] = mxz; + cmt->mts[6*idep+5] = myz; + // rest of information + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf %lf %lf\n", + &cmt->str1[idep], &cmt->dip1[idep], &cmt->rak1[idep], + &cmt->str2[idep], &cmt->dip2[idep], &cmt->rak2[idep], + &cmt->Mw[idep], &cmt->objfn[idep]); + if (cmt->rak1[idep] > 180.0){cmt->rak1[idep] = cmt->rak1[idep] - 360.0;} + if (cmt->rak2[idep] > 180.0){cmt->rak2[idep] = cmt->rak2[idep] - 360.0;} + } + fclose(infl); + ierr = 0; +ERROR:; + return ierr; +} + +// Based on gfast/unit_tests/ff.c by Ben Baker +int read_ff_results(const char *fname, + struct GFAST_ff_props_struct *ff_props, + struct GFAST_offsetData_struct *ff_data, + struct GFAST_ffResults_struct *ff) +{ + FILE *infl; + char cline[128]; + int i, ierr, l2; + ierr = 1; + infl = fopen(fname, "r"); + // line 1 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%d %d %d %d %d %lf %lf %lf %lf\n", + &ff_props->nstr, &ff_props->ndip, &ff_props->utm_zone, + &ff_props->nfp, &ff_props->min_sites, + &ff_props->window_vel, &ff_props->window_avg, + &ff_props->flen_pct, &ff_props->fwid_pct); + l2 = ff_props->nstr*ff_props->ndip; + // line 2 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf\n", &ff->SA_lat, &ff->SA_lon, + &ff->SA_dep, &ff->SA_mag); + // line 3 + ff->nfp = ff_props->nfp; + ff->fp = (struct GFAST_faultPlane_struct *) + calloc((size_t) ff->nfp, sizeof(struct GFAST_faultPlane_struct)); + ff->vr = ISCL_memory_calloc__double(ff->nfp); + ff->Mw = ISCL_memory_calloc__double(ff->nfp); + ff->str = ISCL_memory_calloc__double(ff->nfp); + ff->dip = ISCL_memory_calloc__double(ff->nfp); + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf\n", + &ff->str[0], &ff->str[1], &ff->dip[0], &ff->dip[1]); + // line 4 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%d\n", &ff_data->nsites); + ff_data->ubuff = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->ebuff = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->nbuff = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->wtu = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->wte = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->wtn = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->sta_lat = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->sta_lon = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->sta_alt = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->lactive = ISCL_memory_calloc__bool(ff_data->nsites); + ff_data->lmask = ISCL_memory_calloc__bool(ff_data->nsites); + // ff data + for (i=0; insites; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf\n", + &ff_data->sta_lat[i], &ff_data->sta_lon[i], + &ff_data->sta_alt[i], + &ff_data->nbuff[i], &ff_data->ebuff[i], &ff_data->ubuff[i]); + ff_data->wtu[i] = 1.0; + ff_data->wte[i] = 1.0; + ff_data->wtn[i] = 1.0; + ff_data->lactive[i] = true; + } + // allocate space for fault + for (i=0; infp; i++) + { + ff->fp[i].maxobs = ff_data->nsites; + ff->fp[i].nstr = ff_props->nstr; + ff->fp[i].ndip = ff_props->ndip; + ff->fp[i].sslip = ISCL_memory_calloc__double(l2); + ff->fp[i].dslip = ISCL_memory_calloc__double(l2); + } + // ff results vr + mag + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf\n", + &ff->vr[0], &ff->vr[1], &ff->Mw[0], &ff->Mw[1]); + // ff results slip models + for (i=0; ifp[0].dslip[i], &ff->fp[0].sslip[i], + &ff->fp[1].dslip[i], &ff->fp[1].sslip[i]); + } + fclose(infl); + ierr = 0; +ERROR:; + return ierr; +} diff --git a/src/traceBuffer/Makefile b/src/traceBuffer/Makefile new file mode 100644 index 00000000..4186ee36 --- /dev/null +++ b/src/traceBuffer/Makefile @@ -0,0 +1,99 @@ +# Makefile for GFAST/src/traceBuffer + +EEWDIR = ../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +EW_INCL = -I$(EWDIR)/include + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +DEBUG = -g + +INCL = -I ../../include $(HDF5_INCL) $(EW_INCL) $(CBLAS_INCL) $(ISCL_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +SDIRS = ewrr h5 +LIB = traceBuffer.a +OBJS := $(foreach dir,$(SDIRS),$(dir)/*.o) + +all: $(LIB) +lib: $(LIB) +# %.o: %.c +# $(cc) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +# ids: *.c +# $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +# rm-ids: *.c +# $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +$(LIB): $(SDIRS) + for dir in $(SDIRS) ; do \ + make -C $$dir all ; \ + done + $(AR) $(LIB) $(OBJS) + +ids: $(SDIRS) + for dir in $(SDIRS) ; do \ + make -C $$dir ids ; \ + done + +rm-ids: $(SDIRS) + for dir in $(SDIRS) ; do \ + make -C $$dir rm-ids ; \ + done + +install: + for dir in $(SDIRS) ; do \ + make -C $$dir install ; \ + done + +docs: + doxygen doxygen.conf + +cleandocs: + rm -rf ../docs/epic + +clean: + -rm -f *.o $(LIB) + for dir in $(SDIRS) ; do \ + make -C $$dir clean ; \ + done + +veryclean: cleandocs + for dir in $(SDIRS) ; do \ + make -C $$dir veryclean ; \ + done + +depend: + for dir in $(SDIRS) ; do \ + make -C $$dir depend ; \ + done + +test: # no-op + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + for dir in $(SDIRS) ; do \ + make -C $$dir cleancoverage ; \ + done + +buildcoverage: + for dir in $(SDIRS) ; do \ + make -C $$dir buildcoverage ; \ + done + $(AR) $(LIB) $(OBJS) + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/traceBuffer/ewrr/Makefile b/src/traceBuffer/ewrr/Makefile new file mode 100644 index 00000000..81c93151 --- /dev/null +++ b/src/traceBuffer/ewrr/Makefile @@ -0,0 +1,67 @@ +# Makefile for GFAST/src/traceBuffer/ewrr +# + +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +EW_INCL = -I$(EWDIR)/include + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = classifyRetval.o flushRing.o freetb2Trace.o initialize.o \ +unpackTraceBuf2Messages.o finalize.o freetb2Data.o getMessagesFromRing.o \ +settb2DataFromGFAST.o tb2_hash.o + +DEBUG = -g + +INCL = -I ../../../include $(EW_INCL) $(HDF5_INCL) $(ISCL_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(cc) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_ELARMS_BIN_DIR) + cp $(BIN) $(INSTALL_ELARMS_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: cleancoverage prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/traceBuffer/ewrr/classifyRetval.c b/src/traceBuffer/ewrr/classifyRetval.c new file mode 100644 index 00000000..97a730d7 --- /dev/null +++ b/src/traceBuffer/ewrr/classifyRetval.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +/*! + * @brief Classifies return value from an earthworm get transport activity. + * + * @param[in] retval Earthworm return code to classify. + * + * @retval 1 -> The requested message was received. + * @retval 0 -> There are no more messages. + * @retval -1 -> Messages were received but there may be a loss of + * information. + * @retval -2 -> An error occurred and no messages were received. + * + * @author Ben Baker + * + * @copyright ISTI distribted under Apache 2. + * + */ +int traceBuffer_ewrr_classifyGetRetval(const int retval) +{ + char msg[128]; + // Got a requested message (modid, type, class) + if (retval == GET_OK){return 1;} + // No logos of requested messages in in memory + if (retval == GET_NONE){return 0;} + memset(msg, 0, 128*sizeof(char)); + // Got a message but missed some + if (retval == GET_MISS) + { + sprintf(msg, "%s: Some messages were missed", __func__); + // LOG_MSG("%s", msg); + LOG_WARNMSG("%s", msg); + return -1; + } + // Got a message but ntrack_get was exceeded + if (retval == GET_NOTRACK) + { + sprintf(msg, "%s: Message exceeded NTRACK_GET", __func__); + // LOG_MSG("%s", msg); + LOG_WARNMSG("%s", msg); + return -1; + } + // Message requested exceeded my buffer + if (retval == GET_TOOBIG) + { + sprintf(msg, + "%s: Next message of requested logo(s) is too big", __func__); + // LOG_MSG("%s", msg); + LOG_WARNMSG("%s", msg); + return -2; + } + // Didn't check ring fast enough and missed a message + if (retval == GET_MISS_LAPPED) + { + sprintf(msg, "%s: Some messages were overwritten", __func__); + // LOG_MSG("%s", msg); + LOG_WARNMSG("%s", msg); + return -1; + } + // Message contains a gap + if (retval == GET_MISS_SEQGAP) + { + sprintf(msg, "%s: A gap in messages was detected", __func__); + // LOG_MSG("%s", msg); + LOG_WARNMSG("%s", msg); + return -1; + } + // I don't know + sprintf(msg, "%s: Could not classify return value", __func__); + LOG_MSG("%s", msg); + LOG_WARNMSG("%s", msg); + return -2; +} + diff --git a/src/traceBuffer/ewrr/finalize.c b/src/traceBuffer/ewrr/finalize.c new file mode 100644 index 00000000..2c8e127f --- /dev/null +++ b/src/traceBuffer/ewrr/finalize.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +/*! + * @brief Disconnects from the ring and clears the earthworm ring structure. + * + * @param[in,out] ringInfo On input contains the initialized earthworm ring + * information. + * On output contains the cleared earthworm ring + * information. + * + * @result 0 indicates success. + * + * @author Ben Baker + * + * @copyright ISTI distributed under Apache 2. + * + */ +int traceBuffer_ewrr_finalize(struct ewRing_struct *ringInfo) +{ + if (!ringInfo->linit) + { + LOG_ERRMSG("%s", "Error ewRing_struct was never initialized"); + return -1; + } + if (ringInfo->getLogo != NULL && ringInfo->nlogo > 0) + { + free(ringInfo->getLogo); + } + tport_detach(&ringInfo->region); + memset(ringInfo, 0, sizeof(struct ewRing_struct)); + return 0; +} diff --git a/src/traceBuffer/ewrr/flushRing.c b/src/traceBuffer/ewrr/flushRing.c new file mode 100644 index 00000000..e95cc167 --- /dev/null +++ b/src/traceBuffer/ewrr/flushRing.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +/*! + * @brief Flushes the ring on ringInfo. + * + * @param[in] ringInfo Structure with earthworm ring information to + * flush. + * + * @result 0 indicates success. + * + * @author Ben Baker + * + * @copyright ISTI distributed under Apache 2. + * + */ +int traceBuffer_ewrr_flushRing(struct ewRing_struct *ringInfo) +{ + MSG_LOGO gotLogo; + char msg[MAX_TRACEBUF_SIZ]; + unsigned char sequenceNumber; + long gotSize; + int retval; + //------------------------------------------------------------------------// + // + // Make sure user knows the ring was flushed + if (ringInfo->linit == false) + { + LOG_ERRMSG("%s", "Error the ring was never initialized"); + return -1; + } + // Lift all the messages from the ring + while (true) + { + retval = tport_copyfrom(&ringInfo->region, + ringInfo->getLogo, ringInfo->nlogo, + &gotLogo, &gotSize, msg, MAX_TRACEBUF_SIZ, + &sequenceNumber); + if (retval == GET_NONE){break;} // End of ring + //traceBuffer_ewrr_classifyGetRetval(retval); + } + if (ringInfo->msWait > 0){sleep_ew(ringInfo->msWait);} + return 0; +} diff --git a/src/traceBuffer/ewrr/freetb2Data.c b/src/traceBuffer/ewrr/freetb2Data.c new file mode 100644 index 00000000..7af016c1 --- /dev/null +++ b/src/traceBuffer/ewrr/freetb2Data.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" + +/*! + * @brief Releases memory on the tb2Data_struct data structure. + * + * @param[in,out] tb2data On input the initialized tb2data structure.
+ * On output the structure has been cleared. + * + * @author Ben Baker (ISTI) + * + * @copyright Apache 2 + * + */ +void traceBuffer_ewrr_freetb2Data(struct tb2Data_struct *tb2data) +{ + int i; + if (!tb2data->linit) + { + LOG_WARNMSG("%s", "Structure never set"); + return; + } + if (tb2data->ntraces > 0 && tb2data->traces != NULL) + { + for (i=0; intraces; i++) + { + traceBuffer_ewrr_freetb2Trace(true, &tb2data->traces[i]); + } + free(tb2data->traces); + } + traceBuffer_ewrr_free_hashmap(tb2data->hashmap); + memset(tb2data, 0, sizeof(struct tb2Data_struct)); + return; +} diff --git a/src/traceBuffer/ewrr/freetb2Trace.c b/src/traceBuffer/ewrr/freetb2Trace.c new file mode 100644 index 00000000..52b2f811 --- /dev/null +++ b/src/traceBuffer/ewrr/freetb2Trace.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Clears the memory, and optionally the SNCLs, on the tb2Trace_struct + * struct + * + * @param[in] clearSNCL if true then also clear the SNCL on the trace + * + * @param[out] trace if clearSNCL is true then all memory is freed, counters + * are reset to zero, and the SNCL's are cleared. + * if false then all memory is free and counters are + * cleared. + * + * @author Ben Baker (ISTI) + * + * @copyright Apache 2 + * + */ +void traceBuffer_ewrr_freetb2Trace(const bool clearSNCL, + struct tb2Trace_struct *trace) +{ + memory_free32i(&trace->data); + memory_free64f(&trace->times); + memory_free32i(&trace->chunkPtr); + trace->nchunks = 0; + trace->npts = 0; + trace->dt = 0.0; + if (clearSNCL) + { + memset(trace, 0, sizeof(struct tb2Trace_struct)); + } + return; +} diff --git a/src/traceBuffer/ewrr/getMessagesFromRing.c b/src/traceBuffer/ewrr/getMessagesFromRing.c new file mode 100644 index 00000000..2098b75e --- /dev/null +++ b/src/traceBuffer/ewrr/getMessagesFromRing.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include "transport.h" +#include "trace_buf.h" +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Reads the tracebuffer2 messages from the Earthworm ring specified + * on ringInfo. + * + * @param[in] messageBlock Block allocator size. Instead of reallocating + * memory every loop iteration in the acquisition + * one can allocate in a chunk of messages (e.g. + * 200 messages at a time i.e. messageBlock = 200). + * If this number is too small there will be + * overhead in memory reallocation, if this number + * is too big a lot of unnecessary space will be + * allocated. + * @param[in] showWarnings If true then the print warnings about having read + * maximum number of messages. + * @param[in] ringInfo Earthworm ring reader structure. + * @param[in] hashmap Hashmap of NSLCs we want to keep. + * + * @param[out] nRead Number of traceBuffer2 messages read. + * + * @param[out] ierr 0 Indicates success.
+ * -1 Indicates a terminate signal from the ring.
+ * the user should call traceBuffer_ewrr_finalize + * and quit.
+ * -2 Indicates a read error on the ring.
+ * -3 Indicates the ringInfo structure was not + * initalized.
+ * -4 Indicates tracebuf2 type is unknown. + * + * @result An array of [nRead] traceBuffer2 messages read from the Earthworm + * ring. The k'th message start index (for k=1,2,...,nRead) is given + * by: (k - 1)*MAX_TRACEBUF_SIZE [nRead*MAX_TRACEBUF_SIZE] + * + * @author Ben Baker + * + * @copyright ISTI distribted under Apache 2. + * + */ +char *traceBuffer_ewrr_getMessagesFromRing(const int messageBlock, + const bool showWarnings, + struct ewRing_struct *ringInfo, + struct tb2_hashmap_struct *hashmap, + int *nRead, int *ierr) +{ + MSG_LOGO gotLogo; + TRACE2_HEADER traceHeader; + char *msg, *msgs, *msgWork, *nscl; + unsigned char sequenceNumber; + long gotSize; + int kdx, nblock, ncopy, nwork, retval, maxMessages, maxSpace, ntotal, nskip; + int debug = 0; + //size_t nbytes; //, npcopy; + //------------------------------------------------------------------------// + // + // Make sure this is initialized + *ierr = 0; + *nRead = 0; + msg = NULL; + msgs = NULL; + nscl = NULL; + ntotal = 0; + nskip = 0; + + if (!ringInfo->linit) + { + LOG_ERRMSG("%s", "Error ringInfo not initialized"); + *ierr =-3; + return msgs; + } + // Set some sane limits to avoid a segfault + // arbitrarily set as 0.8 size of int + maxSpace=0.8*INT_MAX; + maxMessages=maxSpace/MAX_TRACEBUF_SIZ; + + if (messageBlock < 1) + { + LOG_ERRMSG("%s", "messageBlock allocator must be positive"); + *ierr =-4; + return msgs; + } + // Set space + memset(&gotLogo, 0, sizeof(MSG_LOGO)); + msgs = memory_calloc8c(MAX_TRACEBUF_SIZ*messageBlock); + msg = memory_calloc8c(MAX_TRACEBUF_SIZ); + nscl = memory_calloc8c(31); + nblock = 1; + // Unpack the ring + while (true) + { + // May have a kill signal from the transport layer + retval = tport_getflag(&ringInfo->region); + if (retval == TERMINATE) { + LOG_ERRMSG("Receiving kill signal from ring %s", ringInfo->ewRingName); + *ierr =-1; + break; + } + // Copy from the memory + retval = tport_copyfrom(&ringInfo->region, ringInfo->getLogo, ringInfo->nlogo, + &gotLogo, &gotSize, msg, MAX_TRACEBUF_SIZ, &sequenceNumber); + // Classify my message + retval = traceBuffer_ewrr_classifyGetRetval(retval); + if (retval ==-2) { + LOG_ERRMSG("%s", "An error was encountered getting message"); + *ierr =-2; + break; + } + + // MTH: This is where we should leave the ring: + if (retval == GET_NONE){ + //printf("MTH: Break out of while loop!\n"); + break; + } + + // Verify i want this message + if (gotLogo.type == ringInfo->traceBuffer2Type) + { + // Get the header + memcpy(&traceHeader, msg, sizeof(TRACE2_HEADER)); + *ierr = WaveMsg2MakeLocal(&traceHeader); + if (*ierr < 0) { + LOG_ERRMSG("%s", "Error flipping bytes"); + *ierr =-2; + break; + } + ntotal += 1; + + memory_free8c(&nscl); + nscl = memory_calloc8c(31); + sprintf(nscl, "%s.%s.%s.%s", + traceHeader.net, traceHeader.sta, traceHeader.chan, traceHeader.loc); + + if (debug){ + LOG_DEBUGMSG("CCC getMsgs: %s time:%f npts:%d", + nscl, traceHeader.starttime, traceHeader.nsamp); + } + + // Skip message if it isn't in the tb2_trace NSLC list + if (traceBuffer_ewrr_hashmap_contains(hashmap, nscl) == NULL) { + if (debug) { + LOG_DEBUGMSG("CCC getMsgs: skipping %s, not in hashmap", nscl); + } + nskip += 1; + continue; + } + + kdx = *nRead*MAX_TRACEBUF_SIZ; + memcpy(&msgs[kdx], msg, MAX_TRACEBUF_SIZ*sizeof(char)); + (*nRead)+=1; + + //check if sane allocation limits reached + if (*nRead+1 >= maxMessages) { + LOG_MSG("XXgetMessagesFromRingXX: nRead=%d nblock=%d messageBlock=%d --> Single-call message limits reached.", + *nRead, nblock, messageBlock); + if (showWarnings) { + LOG_WARNMSG("%s", "Single-call message limits reached"); + } + break; + } + + // Filled current allocation. Reallocate space if possible + //vck should revisit this later and see if we can just use realloc() + if (*nRead >= messageBlock*nblock) + { + LOG_MSG("XXgetMessagesFromRingXX: nRead=%d nblock=%d messageBlock=%d --> Reallocating msgs block", + *nRead, nblock, messageBlock); + if (showWarnings) { + LOG_WARNMSG("%s", "Reallocating msgs block"); + } + ncopy = MAX_TRACEBUF_SIZ*(*nRead); + nblock+=1; + nwork = MAX_TRACEBUF_SIZ*messageBlock*nblock; + //avoid exceeding limits + if (nwork >= maxSpace) { + LOG_MSG("%s: Redundant Single-call message limits check reached. ",__func__); + break; + } + // set workspace and copy old messages + msgWork = memory_calloc8c(ncopy); + memcpy(msgWork, msgs, (size_t) ncopy); + // resize msgs + memory_free8c(&msgs); + msgs = memory_calloc8c(nwork); + // copy back and free workspace + memcpy(msgs, msgWork, (size_t) ncopy); + memory_free8c(&msgWork); + } + } + } // while true + + memory_free8c(&msg); + memory_free8c(&nscl); + + if (ringInfo->msWait > 0){sleep_ew(ringInfo->msWait);} + if (*nRead != ntotal - nskip) { + LOG_WARNMSG("getMessagesFromRing: nRead != ntotal - nskip: %d != %d - %d = %d", + *nRead, ntotal, nskip, ntotal - nskip); + } + LOG_DEBUGMSG("getMessagesFromRing: nRead/ntotal/nskip: %d/%d/%d", + *nRead, ntotal, nskip); + return msgs; +} diff --git a/src/traceBuffer/ewrr/initialize.c b/src/traceBuffer/ewrr/initialize.c new file mode 100644 index 00000000..6908edc0 --- /dev/null +++ b/src/traceBuffer/ewrr/initialize.c @@ -0,0 +1,149 @@ +#ifdef WINNT +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" + + +/*! + * @brief Initializes tracebuf2 ring reader. + * + * @param[in] ewRing Null terminated Earthworm data ring name. + * @param[in] msWait Number of milliseconds to wait after reading + * Earthworm ring. This will be attached to the + * ringInfo structure. + * + * @param[out] ringInfo Requisite information for reading the tracebuf2's + * off the ewRing Earthworm ring. + * + * @result 0 indicates success. + * + * @author Ben Baker + * + * @copyright ISTI distribted under Apache 2. + * + */ +int traceBuffer_ewrr_initialize(const char *ewRing, + const int msWait, + struct ewRing_struct *ringInfo) +{ + // Check the inputs + if (ringInfo == NULL) + { + LOG_ERRMSG("%s", "ewRing_struct cannot be NULL"); + return -1; + } + memset(ringInfo, 0, sizeof(struct ewRing_struct)); + strcpy(ringInfo->ewRingName, ewRing); + if (ewRing == NULL) + { + LOG_ERRMSG("%s", "Error ewRing cannot be NULL"); + return -1; + } + if (strlen(ewRing) == 0) + { + LOG_ERRMSG("%s", "Error ewRing must be specified"); + return -1; + } + ringInfo->msWait = 0; + if (msWait > 0){ringInfo->msWait = (unsigned int) msWait;} + // Attach to the ring + ringInfo->ringKey = GetKey(ringInfo->ewRingName); + if (ringInfo->ringKey ==-1) + { + LOG_ERRMSG("Invalid ring %s", ewRing); + return -1; + } + // Look up installation ID + if (GetLocalInst(&ringInfo->instLocalID) != 0) + { + LOG_ERRMSG("%s", "Error getting local installation id!"); + return -1; + } + if (GetInst("INST_WILDCARD", &ringInfo->instWildcardID ) != 0) + { + LOG_ERRMSG("%s", "Error getting INST_WILDCARD!"); + return -1; + } + // Look up the tracebuffer2 type + if (GetType("TYPE_TRACEBUF2", &ringInfo->traceBuffer2Type) != 0) + { + LOG_ERRMSG("%s", "Error getting TYPE_TRACEBUF2!"); + return -1; + } + // Look up the heartbeat type + if (GetType("TYPE_HEARTBEAT", &ringInfo->heartBeatType) != 0) + { + LOG_ERRMSG("%s", "Error getting TYPE_HEARTBEAT!"); + return -1; + } + // Look up the error type + if (GetType("TYPE_ERROR", &ringInfo->errorType) != 0) + { + LOG_ERRMSG("%s", "Error getting TYPE_ERROR!"); + return -1; + } + if (GetModId( "MOD_WILDCARD", &ringInfo->modWildcardID) != 0 ) + { + LOG_ERRMSG("%s", "MOD_WILDCARD Missing from earthworm(_global).d"); + return -1; + } + // Hook the getLogo's up for reading tracebuffer2s + ringInfo->nlogo = 1; + ringInfo->getLogo = (MSG_LOGO *) calloc((size_t) ringInfo->nlogo, + sizeof(MSG_LOGO)); + ringInfo->getLogo[0].type = ringInfo->traceBuffer2Type; + // Attach to the ring + tport_attach(&ringInfo->region, ringInfo->ringKey); + ringInfo->linit = true; + return 0; +} + +/* +int GetEwh( EWH *Ewh ) +{ + if ( GetLocalInst( &Ewh->MyInstId ) != 0 ) + { + fprintf( stderr, "Theta: Error getting MyInstId.\n" ); + return -1; + } + if ( GetInst( "INST_WILDCARD", &Ewh->GetThisInstId ) != 0 ) + { + fprintf( stderr, "Theta: Error getting GetThisInstId.\n" ); + return -2; + } + if ( GetModId( "MOD_WILDCARD", &Ewh->GetThisModId ) != 0 ) + { + fprintf( stderr, "Theta: Error getting GetThisModId.\n" ); + return -3; + } + if ( GetType( "TYPE_HEARTBEAT", &Ewh->TypeHeartBeat ) != 0 ) + { + fprintf( stderr, "Theta: Error getting TypeHeartbeat.\n" ); + return -4; + } + if ( GetType( "TYPE_ERROR", &Ewh->TypeError ) != 0 ) + { + fprintf( stderr, "Theta: Error getting TypeError.\n" ); + return -5; + } + if ( GetType( "TYPE_TRACEBUF2", &Ewh->TypeWaveform ) != 0 ) + { + fprintf( stderr, "Theta: Error getting TYPE_TRACEBUF2.\n" ); + return -6; + } + if ( GetType( "TYPE_HYPOTWC", &Ewh->TypeHypoTWC ) != 0 ) + { + fprintf( stderr, "Theta: Error getting TYPE_HYPOTWC.\n" ); + return -7; + } + return 0; +} +*/ diff --git a/src/traceBuffer/ewrr/settb2Data.c b/src/traceBuffer/ewrr/settb2Data.c new file mode 100644 index 00000000..eef41d38 --- /dev/null +++ b/src/traceBuffer/ewrr/settb2Data.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" + +/*! + * @brief Initializes the data list which will be retained from a + * ring read operation + * + * @param[in] ntraces number of traces to create in tb2data + * @param[in] nets null terminated list of networks [ntraces] + * @param[in] stats null terminated list of stations [ntraces] + * @param[in] chans null terminated list of channels [ntraces] + * @param[in] locs null terminated list of location codes [ntraces] + * + * @param[out] tb2data on successful output contains the SNCL's to + * copy after each ring read + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + * @copyright Apache 2 + * + */ +int traceBuffer_ewrr_settb2Data(const int ntraces, + const char **nets, + const char **stats, + const char **chans, + const char **locs, + struct tb2Data_struct *tb2data) +{ + int i; + if (ntraces < 1 || nets == NULL || stats == NULL || + chans == NULL || locs == NULL) + { + if (ntraces < 1) + { + LOG_ERRMSG("%s", "No traces to initialize"); + } + if (nets == NULL) + { + LOG_ERRMSG("%s", "Error must define network list"); + } + if (stats == NULL) + { + LOG_ERRMSG("%s", "Error must define station list"); + } + if (chans == NULL) + { + LOG_ERRMSG("%s", "Error must define channel list"); + } + if (locs == NULL) + { + LOG_ERRMSG("%s", "Error must define location list"); + } + return -1; + } + if (tb2data->linit) + { + LOG_ERRMSG("%s", "Error tb2data already initialized"); + return -1; + } + tb2data->traces = (struct tb2Trace_struct *) + calloc( (size_t) ntraces, + sizeof(struct tb2Trace_struct)); + for (i=0; itraces[i].netw, nets[i]); + strcpy(tb2data->traces[i].stnm, stats[i]); + strcpy(tb2data->traces[i].chan, chans[i]); + strcpy(tb2data->traces[i].loc, locs[i]); + } + tb2data->ntraces = ntraces; + tb2data->linit = true; + return 0; +} diff --git a/src/traceBuffer/ewrr/settb2DataFromGFAST.c b/src/traceBuffer/ewrr/settb2DataFromGFAST.c new file mode 100644 index 00000000..1f0b94a2 --- /dev/null +++ b/src/traceBuffer/ewrr/settb2DataFromGFAST.c @@ -0,0 +1,93 @@ +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" + +//============================================================================// +/*! +* @brief Sets the tb2Data structure and desired SNCL's from the input gpsData +* +* @param[in] gpsData holds the GPS SNCL's GFAST is interested in +* +* @param[out] tb2Data on output has space allocated and has a target +* list of SNCL's for message reading from the +* earthworm data ring +* +* @result 0 indicates success +* +* @author Ben Baker (ISTI) +* +*/ +int traceBuffer_ewrr_settb2DataFromGFAST(struct GFAST_data_struct *gpsData, + struct tb2Data_struct *tb2Data) +{ + const char *fcnm = __func__; + char *nscl = NULL; + int i, it, k; + int debug = 0; + if (gpsData->stream_length == 0) { + LOG_ERRMSG("%s: Error no data to copy\n", fcnm); + return -1; + } + if (tb2Data->linit) { + LOG_ERRMSG("%s: Error tb2Data already set\n", fcnm); + return -1; + } + + // Init tb2Data_struct + tb2Data->ntraces = 6 * gpsData->stream_length; + tb2Data->traces = (struct tb2Trace_struct *) + calloc( (size_t) tb2Data->ntraces, sizeof(struct tb2Trace_struct) ); + tb2Data->hashmap = (struct tb2_hashmap_struct *) + malloc(sizeof(struct tb2_hashmap_struct)); + // Random prime, 80021 should have at most 4-5 collisions for a 20k nscl list + const uint32_t hashsize = 80021; + tb2Data->hashmap->hashsize = hashsize; + tb2Data->hashmap->map = (struct tb2_node **) calloc(hashsize, sizeof(struct tb2_node *)); + + // Copy channel names + it = 0; + for (k = 0; k < gpsData->stream_length; k++) { + // Loop over each channel: Z, N, E, 3, 2, 1 + for (i = 0; i < 6; i++) { + strcpy(tb2Data->traces[it].netw, gpsData->data[k].netw); + strcpy(tb2Data->traces[it].stnm, gpsData->data[k].stnm); + strcpy(tb2Data->traces[it].chan, gpsData->data[k].chan[i]); + strcpy(tb2Data->traces[it].loc, gpsData->data[k].loc); + it = it + 1; + } + } + if (debug) { + LOG_DEBUGMSG("Printing %d traces in tb2Data", tb2Data->ntraces); + for (i = 0; i < tb2Data->ntraces; i++) { + LOG_DEBUGMSG("CCC %d: %s.%s.%s.%s", i, + tb2Data->traces[i].netw, + tb2Data->traces[i].stnm, + tb2Data->traces[i].chan, + tb2Data->traces[i].loc); + } + LOG_DEBUGMSG("%s", "Done printing traces in tb2Data"); + } + + // Now add trace names to hashmap + for (i = 0; i < tb2Data->ntraces; i++) { + nscl = (char *) malloc(31 * sizeof(char)); + sprintf(nscl, "%s.%s.%s.%s", + tb2Data->traces[i].netw, + tb2Data->traces[i].stnm, + tb2Data->traces[i].chan, + tb2Data->traces[i].loc); + if (traceBuffer_ewrr_hashmap_add(tb2Data->hashmap, nscl, i) == NULL) { + LOG_ERRMSG("%s: Couldn't add %s to hashmap!", fcnm, nscl); + free(nscl); + return -1; + } + free(nscl); + } + + if (it != tb2Data->ntraces) { + LOG_ERRMSG("%s: Lost count %d %d\n", fcnm, it, tb2Data->ntraces); + return -1; + } + tb2Data->linit = true; + return 0; +} diff --git a/src/traceBuffer/ewrr/tb2_hash.c b/src/traceBuffer/ewrr/tb2_hash.c new file mode 100644 index 00000000..df49a2de --- /dev/null +++ b/src/traceBuffer/ewrr/tb2_hash.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include + +#include "gfast_core.h" +#include "gfast_traceBuffer.h" + + +uint32_t traceBuffer_ewrr_hash(const char *s) { + uint32_t hashval; + // K&R[2]. In testing, 21 collisions with ~20k NSLCs + // for (hashval = 0; *s != '\0'; s++) { + // hashval = *s + 31 * hashval; + // } + + // djb2. In testing, zero collisions with ~20k NSLCs + for (hashval = 5381; *s != '\0'; s++) { + // hashval = *s + 33 * hashval; + hashval = *s + ((hashval << 5) + hashval); + } + + return hashval; +} + +uint32_t traceBuffer_ewrr_make_hash(const char *s, uint32_t hashsize) { + return traceBuffer_ewrr_hash(s) % hashsize; +} + +struct tb2_node *traceBuffer_ewrr_hashmap_contains(struct tb2_hashmap_struct *hashmap, + const char *name) +{ + struct tb2_node *np; + + // Advance through linked list + for (np = hashmap->map[traceBuffer_ewrr_make_hash(name, hashmap->hashsize)]; + np != NULL;np = np->next) + { + if (strcmp(name, np->name) == 0) { + // hashmap contains name + return np; + } + } + return NULL; +} + +int traceBuffer_ewrr_hashmap_remove(struct tb2_hashmap_struct *hashmap, const char *name) { + struct tb2_node *np, *np_prev; + + // Advance through linked list + for (np = hashmap->map[traceBuffer_ewrr_make_hash(name, hashmap->hashsize)], np_prev = NULL; + np != NULL; np = np->next) + { + if (strcmp(name, np->name) == 0) { + // hashmap contains name + if (np_prev != NULL) { + np_prev->next = np->next; + } else { + hashmap->map[traceBuffer_ewrr_make_hash(name, hashmap->hashsize)] = np->next; + } + traceBuffer_ewrr_free_node(np); + return 1; + } + np_prev = np; + } + return 0; +} + +struct tb2_node *traceBuffer_ewrr_hashmap_add(struct tb2_hashmap_struct *hashmap, + const char *name, + int index) +{ + struct tb2_node *np; + uint32_t hashval; + + if ((np = traceBuffer_ewrr_hashmap_contains(hashmap, name)) == NULL) { + // Not found + np = (struct tb2_node *) malloc(sizeof(*np)); + if (np == NULL || (np->name = strdup(name)) == NULL) { + printf("ERROR! No space for %s!\n", name); + return NULL; + } + hashval = traceBuffer_ewrr_make_hash(name, hashmap->hashsize); + np->next = hashmap->map[hashval]; + hashmap->map[hashval] = np; + } else { + np->i = -1; + } + np->i = index; + return np; +} + +void traceBuffer_ewrr_free_node(struct tb2_node *np) { + free(np->name); + free(np); +} + +void traceBuffer_ewrr_free_hashmap(struct tb2_hashmap_struct *hashmap) { + struct tb2_node *np, *np_next; + uint32_t i; + for (i = 0; i < hashmap->hashsize; i++) { + for (np = hashmap->map[i]; np != NULL; np = np_next) { + np_next = np->next; + traceBuffer_ewrr_free_node(np); + } + } + free(hashmap->map); + free(hashmap); +} + +void traceBuffer_ewrr_print_hashmap(struct tb2_hashmap_struct *hashmap) { + unsigned i; + struct tb2_node *np; + int cx, n_nodes, max_nodes = -1; + const int max_nodes_to_print = 250; + double running_sum = 0; + + for (i = 0; i < hashmap->hashsize; i++) { + // First count number of nodes, is it even possible? + for (np = hashmap->map[i], n_nodes = 0; np != NULL; np = np->next, n_nodes++); + running_sum += n_nodes; + if (n_nodes > max_nodes) { + max_nodes = n_nodes; + } + + if (n_nodes > (int)(.9 * max_nodes_to_print)) { + LOG_DEBUGMSG("%5d (#%d) Not printing all, too many nodes in this position (>%d)!", + i, n_nodes, (int)(.9 * max_nodes_to_print)); + continue; + } + + // N characters * max number of stations per hash + int nchar = 24 * max_nodes_to_print + 4; + char str[nchar]; + cx = 0; + cx += snprintf(str + cx, nchar - cx, "%5d (#%5d)", i, n_nodes); + for (np = hashmap->map[i]; np != NULL; np = np->next) { + cx += snprintf(str + cx, nchar - cx, " -> %s(%d)", np->name, np->i); + } + LOG_DEBUGMSG("%s", str); + } + +} + +int traceBuffer_ewrr_print_true_collisions(struct tb2_hashmap_struct *hashmap) { + int n_nodes; + struct tb2_node *np; + uint32_t *hashvals; + char **names; + int i, j, k; + int n_collisions = 0; + + // Loop over list indices + for (i = 0; i < (int)(hashmap->hashsize); i++) { + // Get total nodes at this position + for (np = hashmap->map[i], n_nodes = 0; np != NULL; np = np->next, n_nodes++); + hashvals = (uint32_t *) malloc(n_nodes * sizeof(uint32_t)); + names = (char **) malloc(n_nodes * sizeof(char *)); + + // Loop over linked nodes to get full hash values + for (np = hashmap->map[i], j = 0; np != NULL; np = np->next, j++) { + hashvals[j] = traceBuffer_ewrr_hash(np->name); + names[j] = strdup(np->name); + } + + // Loop over hashvals + for (j = 0; j < n_nodes - 1; j++) { + for (k = j + 1; k < n_nodes; k++) { + if (hashvals[j] == hashvals[k]) { + n_collisions++; + LOG_DEBUGMSG("%d Collision! %s:%u, %s:%u", + i, names[j], hashvals[j], names[k], hashvals[k]); + } + } + } + + // Free stuff + for (j = 0; j < n_nodes; j++) { + free(names[j]); + } + free(names); + free(hashvals); + } + LOG_DEBUGMSG("%d collisions", n_collisions); + + return n_collisions; +} diff --git a/src/traceBuffer/ewrr/unpackTraceBuf2Messages.c b/src/traceBuffer/ewrr/unpackTraceBuf2Messages.c new file mode 100644 index 00000000..990a1729 --- /dev/null +++ b/src/traceBuffer/ewrr/unpackTraceBuf2Messages.c @@ -0,0 +1,593 @@ +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" +#include "iscl/sorting/sorting.h" + +#include "iscl/time/time.h" + +static void fastUnpackI4(const int npts, const int lswap, + const char *__restrict__ msg, + int *__restrict__ resp); +static void fastUnpackI2(const int npts, const int lswap, + const char *__restrict__ msg, + int *__restrict__ resp); +static int fastUnpack(const int npts, const int lswap, + const int type, + const char *__restrict__ msg, + int *__restrict__ resp); + +/*! + * MTH: 2021/05 Rewrite of unpackTraceBuf2Messages.c + * Replace 4 loops/sorts with one sort of record struct + * CWU: 2022/10 Rewrite unpackTraceBuf2Messages.c again + * Add loc to compare fxn, and use a hashmap into tb2data + */ + +/*! + * @brief Unpacks the tracebuf2 messages read from the ring and returns + * the concatenated data for the desired SNCL's in the tb2Data struct + * + * @param[in] nRead number of traces read off the ring + * @param[in] msgs tracebuf2 messages read off ring. the i'th message + * is given by (i-1)*MAX_TRACEBUF_SIZ for + * i=1,2,...,nRead + * + * @param[in,out] tb2Data on input contains the desired SNCL's whose data + * will be unpacked from the header (should it be + * present). + * on output contains the data in the messages for + * the SNCL's defined in this structure (should a + * match be found). + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + * @copyright Apache 2 + * + */ + +struct tb_struct { + char netw[8]; + char stnm[8]; + char chan[8]; + char loc[8]; +}; + +struct string_index { + char logo[15]; + char nscl[15]; + char net[8]; + char sta[8]; + char cha[8]; + char loc[8]; + double time; + int indx; + int nsamps; + //int k; + //float data; +}; +void print_struct(struct string_index *d, int n); +void sort2(struct string_index *vals, int n); + + +int traceBuffer_ewrr_unpackTraceBuf2Messages( + const int nRead, + const char *msgs, + struct tb2Data_struct *tb2Data) +{ + char *msg; + TRACE2_HEADER *trh; + double *times, dt; + int *nsamps; + int *imap, *imapPtr, *imsg, *iperm, *kpts, *nmsg, *resp, + dtype, i, i1, i2, ierr, im, indx, ir, k, kndx, l, j, + lswap, nchunks, nReadPtr, npts, nskip; + struct tb2_node *node; + const int maxpts = MAX_TRACEBUF_SIZ/16; // MAX_TRACEBUF_SIZ/sizeof(int16_t) + const bool clearSNCL = false; + + //char **msg_logos = (char **)malloc(sizeof(char *) * nRead); + //char msg_logos[nRead][15]; + char buf[15]; + char *logo, *nscl; + + int debug = 0; + + int kold; + struct string_index *vals, *tmp; + vals = (struct string_index *) calloc((size_t) nRead, sizeof(struct string_index)); + tmp = (struct string_index *) calloc((size_t) nRead, sizeof(struct string_index)); + + //------------------------------------------------------------------------// + // + // Check the tb2data was initialized + if (!tb2Data->linit) + { + LOG_ERRMSG("%s", "tb2Data never initialized"); + return -1; + } + // Nothing to do + if (tb2Data->ntraces == 0) {return 0;} + if (nRead == 0){return 0;} + + // Set the workspace + msg = memory_calloc8c(MAX_TRACEBUF_SIZ); + imap = memory_calloc32i(nRead+1); + imsg = memory_calloc32i(nRead); + iperm = memory_calloc32i(nRead); + kpts = memory_calloc32i(tb2Data->ntraces); + nmsg = memory_calloc32i(tb2Data->ntraces); + imapPtr = memory_calloc32i(nRead + 1); // worst case size + times = memory_calloc64f(nRead); + resp = memory_calloc32i(maxpts); + nsamps= memory_calloc32i(nRead); + logo = memory_calloc8c(15); + nscl = memory_calloc8c(15); + + for (i=0; intraces + 1;} + + LOG_DEBUGMSG("unpackTB2: Enter nTraces:%d nRead:%d", tb2Data->ntraces, nRead); + + bool dump_tb2Data = false; + bool dump_nRead = false; + bool debug_imap = false; + bool debug_nchunks = false; + + if (dump_tb2Data) { + for (k=0; kntraces; k++){ + LOG_DEBUGMSG("CCC dump_tb2Data: %s.%s.%s.%s", + tb2Data->traces[k].stnm, tb2Data->traces[k].chan, + tb2Data->traces[k].netw, tb2Data->traces[k].loc); + } + //exit(0); + } + + // MTH: load up the msg logos, times and nsamp into records to sort once + for (i=0; ista, trh->chan, trh->net, trh->loc); + sprintf(nscl, "%s.%s.%s.%s", trh->net, trh->sta, trh->chan, trh->loc); + strcpy(vals[i].logo, logo); + strcpy(vals[i].nscl, nscl); + strcpy(vals[i].sta, trh->sta); + strcpy(vals[i].cha, trh->chan); + strcpy(vals[i].net, trh->net); + strcpy(vals[i].loc, trh->loc); + vals[i].indx = i; + vals[i].time = trh->starttime; + vals[i].nsamps = trh->nsamp; + } + if (dump_nRead) { + LOG_DEBUGMSG("%s", "CCC: Dump unsorted structs:"); + print_struct(vals, nRead); + } + + for (i=0; ihashmap, tmp[i].nscl)) == NULL) { + if (debug) { + LOG_DEBUGMSG("unpackTB2: %s is in EW msgs but not in tb2Data!", tmp[i].nscl); + } + nskip++; + } else { + k = node->i; + imap[i] = k; + kpts[k] += vals[j].nsamps; + nmsg[k] += 1; + continue; + } + } + // It's now sorted so that as you step through i: 1, ..., nRead, + // imsg[i] = next msg in sort order, while imap[i] = kth tb2Data scnl msg target + int n_chan_w_data = 0; + for (k = 0; k < tb2Data->ntraces; k++) { + if (nmsg[k] > 0) { + n_chan_w_data++; + } + } + LOG_DEBUGMSG("unpackTB2: skipped %d msgs, %d sncl with data", nskip, n_chan_w_data); + + if (debug_imap) { + LOG_DEBUGMSG("%s", "CCC - show imap"); + for (i = 0; i < nRead; i++){ + k = imap[i]; + LOG_DEBUGMSG("CCC == imap[%d] --> k:%d %s.%s", + i, k, tb2Data->traces[k].stnm, tb2Data->traces[k].chan); + } + } + + // Step through the sorted imap[i]=k and figure out where each new k starts = imap[imapPtr[ir]] + kold = -999; + ir = 0; + for (i = 0; i < nRead; i++) { + k = imap[i]; + if (k != kold) { + if (k > -1) { + imapPtr[ir] = i; + ir += 1; + } + kold = k; + } + } + + nReadPtr = ir; + + LOG_DEBUGMSG("unpackTB2 nRead:%d ntraces:%d nReadPtr:%d", + nRead, tb2Data->ntraces, nReadPtr); + + // Now set the workspace + for (k = 0; k < tb2Data->ntraces; k++) + { + traceBuffer_ewrr_freetb2Trace(clearSNCL, &tb2Data->traces[k]); + if (kpts[k] > 0) + { + tb2Data->traces[k].data = memory_calloc32i(kpts[k]); + tb2Data->traces[k].times = memory_calloc64f(kpts[k]); + tb2Data->traces[k].chunkPtr = memory_calloc32i(nmsg[k] + 1); + tb2Data->traces[k].npts = kpts[k]; + } + } + + // Final loop to load traces + for (ir = 0; ir < nReadPtr; ir++) + { + i1 = imapPtr[ir]; + k = imap[i1]; + i2 = i1 + nmsg[k]; + kndx = 0; + if (1) { + sprintf(buf, "%s.%s.%s.%s", tb2Data->traces[k].netw, tb2Data->traces[k].stnm, + tb2Data->traces[k].chan, tb2Data->traces[k].loc); + } + + tb2Data->traces[k].nchunks = 1; + + // Loop on the messages for this SNCL + for (im = i1; im < i2; im++) + { + i = imsg[im]; + if (i < 0 || i >= nRead) + { + LOG_ERRMSG("Invalid message number %d", i); + continue; + } + indx = i * MAX_TRACEBUF_SIZ; + trh = (TRACE2_HEADER *) &msgs[indx]; + dtype = 4; + lswap = 0; + npts = trh->nsamp; + dt = 1.0/trh->samprate; + tb2Data->traces[k].dt = dt; + + ierr = fastUnpack(npts, lswap, dtype, &msgs[indx], resp); + if (ierr != 0) { + LOG_ERRMSG("%s", "Error unpacking data"); + } + + // Is a new chunk beginning? + if (im > i1) { + if (fabs( (tb2Data->traces[k].times[kndx-1] + dt) - trh->starttime ) > 1.e-6) { + // starttime exceeds dt --> start a new chunk + if (debug) { + LOG_DEBUGMSG("ir:%d i1:%d im:%d k:%d %s kndx:%d npts:%d nchunks:%d start a new chunk", + ir, i1, im, k, buf, kndx, npts, tb2Data->traces[k].nchunks); + } + tb2Data->traces[k].chunkPtr[tb2Data->traces[k].nchunks] = kndx; + tb2Data->traces[k].nchunks += 1; + tb2Data->traces[k].chunkPtr[tb2Data->traces[k].nchunks] = kndx + npts; + } + else { + // starttime is within dt --> simply extend current chunk + if (debug) { + LOG_DEBUGMSG("ir:%d i1:%d im:%d k:%d %s kndx:%d npts:%d nchunks:%d extend current chunk", + ir, i1, im, k, buf, kndx, npts, tb2Data->traces[k].nchunks); + } + tb2Data->traces[k].chunkPtr[tb2Data->traces[k].nchunks] = kndx + npts; + } + } + + // Update the points +#ifdef _OPENMP + #pragma omp simd +#endif + for (l=0; ltraces[k].data[kndx+l] = resp[l]; + tb2Data->traces[k].times[kndx+l] = trh->starttime + (double) l*dt; + + if (debug) { + LOG_DEBUGMSG("unpackTB2 k:%4d scnl:%s time:%.2f val:%d", + k, buf, tb2Data->traces[k].times[kndx+l], tb2Data->traces[k].data[kndx+l]); + } + } + kndx = kndx + npts; + + } // Loop on messages for this SNCL + + // Special case for one message + if (i2 - i1 == 1 && kpts[k] > 0) { + tb2Data->traces[k].nchunks = 1; + tb2Data->traces[k].chunkPtr[tb2Data->traces[k].nchunks] = kpts[k]; + } + if (debug_nchunks) { + LOG_DEBUGMSG("unpackTB2: k:%4d scnl:%s nmsg:%d kpts:%d i1:%d i2:%d nchunks:%d", + k, buf, nmsg[k], kpts[k], i1, i2, tb2Data->traces[k].nchunks); + } + + // Reality check + if (kndx != kpts[k]) + { + LOG_ERRMSG("Lost count %d %d", kndx, kpts[k]); + return -1; + } + if (tb2Data->traces[k].nchunks > 0) + { + nchunks = tb2Data->traces[k].nchunks; + if (tb2Data->traces[k].chunkPtr[nchunks] != tb2Data->traces[k].npts) + { + LOG_ERRMSG("Inconsistent number of points %d %d", + tb2Data->traces[k].chunkPtr[nchunks], + tb2Data->traces[k].npts); + return -1; + } + } + + + if (debug) { + LOG_DEBUGMSG("unpackTB2 k:%4d nchunks:%d chunkPtr[0]:%d chunkPtr[nchunks]:%d total_npts:%d", + k, tb2Data->traces[k].nchunks, tb2Data->traces[k].chunkPtr[0], + tb2Data->traces[k].chunkPtr[nchunks], tb2Data->traces[k].npts); + } + + } // Loop on pointers + + // Free space + memory_free8c(&msg); + memory_free32i(&imap); + memory_free32i(&imsg); + memory_free32i(&iperm); + memory_free32i(&kpts); + memory_free32i(&nmsg); + memory_free32i(&resp); + memory_free64f(×); + memory_free32i(&imapPtr); + memory_free32i(&nsamps); + memory_free8c(&logo); + memory_free8c(&nscl); + free(vals); + free(tmp); + + return 0; +} +//============================================================================// +/*! + * @brief Unpacks a 4 byte integer character data + * + * @param[in] npts number of points to unpack + * @param[in] lswap if 0 then do not byte swap the data. + * if 1 then do byte swap the data. + * @param[in] msg tracebuf2 message to unpack [MAX_TRACEBUF_SIZ] + * + * @param[out] resp response data [npts] + * + * @author Ben Baker (ISTI) + * + * @copyright Apache 2 + * + * @bug This doesn't vectorize. + * + */ +static void fastUnpackI4(const int npts, const int lswap, + const char *__restrict__ msg, + int *__restrict__ resp) +{ + const int ioff = (int) (sizeof(TRACE2_HEADER)); + char c4[4]; + int i, i4; + if (lswap == 0) + { + //#pragma omp simd + for (i=0; i yy.time) { + return 1; + } + else if (xx.time < yy.time) { + return -1; + } + else { + return 0; + } + } + else { // order by {LYZ, LYN, LYE} to match tb2Data + return -1 * icha; + } + } + else { + return iloc; + } + } + else { + return inet; + } + } + else { + return ista; + } +} + +// Function to sort the array +void sort2(struct string_index values[], int n) +{ + // calling qsort function to sort the array + // with the help of Comparator + qsort((void *) values, (size_t) n, sizeof(struct string_index), myCompare2); +} + +void print_struct(struct string_index *d, int n) { + int i; + for (i=0; i +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" + +static int copyTrace(const int npts, + const double *__restrict__ origin, + const int ndest, + double *__restrict__ dest); + +/*! + * @brief Copies the HDF5 trace buffer data onto the GPS data structure + * + * @param[in] traceBuffer contains data from HDF5 file to copy onto + * the GPS data structure. Notice, the trace + * buffer is appropriately queried for times + * [t1, t2] + * + * @param[in,out] gps_data on input contains the requisite space + * to store the data from the traceBuffer. + * on output contains the data from [t1, t2] + * and fills all excess points (up to maxpts) + * with NAN. + * + * @result 0 indicates success + * + * @author Ben Baker + */ +int traceBuffer_h5_copyTraceBufferToGFAST( + struct h5traceBuffer_struct *traceBuffer, + struct GFAST_data_struct *gps_data) +{ + double dt, gain; + int i, ierr, ierr1, j, k, l; + bool *ltInit; + const int ncomp = 6; + int debug = 0; + ierr = 0; + if (traceBuffer->ntraces < 1){return ierr;} // Nothing to do + if (fmod(traceBuffer->ntraces, ncomp) != 0) + { + LOG_WARNMSG("%s", "Expecting multiple of 6 traces"); + } + ltInit = memory_calloc8l((int) (fmax(traceBuffer->ntraces/ncomp, 1))); + // Copy the data back + for (i=0; intraces; i++) + { + j = (int) (fmod(traceBuffer->traces[i].idest, ncomp)); + k = (traceBuffer->traces[i].idest - j)/ncomp; + if (traceBuffer->traces[i].ncopy > gps_data->data[k].maxpts) + { + LOG_ERRMSG("%s", "Invalid copy size"); + ierr = ierr + 1; + continue; + } + dt = traceBuffer->traces[i].dt; + if (j == 0) + { + gps_data->data[k].npts = traceBuffer->traces[i].ncopy; + ierr1 = copyTrace(gps_data->data[k].npts, + traceBuffer->traces[i].data, + gps_data->data[k].maxpts, + gps_data->data[k].ubuff); + memory_free64f(&traceBuffer->traces[i].data); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error copying ubuff"); + ierr = ierr + 1; + } + // Apply the gain + gps_data->data[k].gain[j] = 1.0; // will be applied here + gain = traceBuffer->traces[i].gain; + if (fabs(gain) < 1.e-15) + { + LOG_ERRMSG("%s", "Division by zero"); + ierr = ierr + 1; + } + gain = 1.0/gain; + cblas_dscal(gps_data->data[k].npts, gain, + gps_data->data[k].ubuff, 1); + +#ifdef _OPENMP + #pragma omp simd +#endif + for (l=0; ldata[k].npts; l++) + { + gps_data->data[k].tbuff[l] = traceBuffer->traces[i].t1 + l*dt; + } + } + else if (j == 1) + { + gps_data->data[k].npts = traceBuffer->traces[i].ncopy; + ierr1 = copyTrace(gps_data->data[k].npts, + traceBuffer->traces[i].data, + gps_data->data[k].maxpts, + gps_data->data[k].nbuff); + memory_free64f(&traceBuffer->traces[i].data); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error copying nbuff"); + ierr = ierr + 1; + } + // Apply the gain + gps_data->data[k].gain[j] = 1.0; // will be applied here + gain = traceBuffer->traces[i].gain; + if (gain == 0.0) + { + LOG_ERRMSG("%s", "Division by zero"); + ierr = ierr + 1; + } + gain = 1.0/gain; + cblas_dscal(gps_data->data[k].npts, gain, + gps_data->data[k].nbuff, 1); + } + else if (j == 2) + { + gps_data->data[k].npts = traceBuffer->traces[i].ncopy; + ierr1 = copyTrace(gps_data->data[k].npts, + traceBuffer->traces[i].data, + gps_data->data[k].maxpts, + gps_data->data[k].ebuff); + memory_free64f(&traceBuffer->traces[i].data); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error copying ebuff"); + ierr = ierr + 1; + } + // Apply the gain + gps_data->data[k].gain[j] = 1.0; // will be applied here + gain = traceBuffer->traces[i].gain; + if (gain == 0.0) + { + LOG_ERRMSG("%s", "Division by zero"); + ierr = ierr + 1; + } + gain = 1.0/gain; + cblas_dscal(gps_data->data[k].npts, gain, + gps_data->data[k].ebuff, 1); + } + else if (j == 3) + { + gps_data->data[k].npts = traceBuffer->traces[i].ncopy; + ierr1 = copyTrace(gps_data->data[k].npts, + traceBuffer->traces[i].data, + gps_data->data[k].maxpts, + gps_data->data[k].usigmabuff); + memory_free64f(&traceBuffer->traces[i].data); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error copying usigmabuff"); + ierr = ierr + 1; + } + // Apply the gain + gps_data->data[k].gain[j] = 1.0; // will be applied here + gain = traceBuffer->traces[i].gain; + if (gain == 0.0) + { + LOG_ERRMSG("%s", "Division by zero"); + ierr = ierr + 1; + } + gain = 1.0/gain; + cblas_dscal(gps_data->data[k].npts, gain, + gps_data->data[k].usigmabuff, 1); + } + else if (j == 4) + { + gps_data->data[k].npts = traceBuffer->traces[i].ncopy; + ierr1 = copyTrace(gps_data->data[k].npts, + traceBuffer->traces[i].data, + gps_data->data[k].maxpts, + gps_data->data[k].nsigmabuff); + memory_free64f(&traceBuffer->traces[i].data); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error copying nsigmabuff"); + ierr = ierr + 1; + } + // Apply the gain + gps_data->data[k].gain[j] = 1.0; // will be applied here + gain = traceBuffer->traces[i].gain; + if (gain == 0.0) + { + LOG_ERRMSG("%s", "Division by zero"); + ierr = ierr + 1; + } + gain = 1.0/gain; + cblas_dscal(gps_data->data[k].npts, gain, + gps_data->data[k].nsigmabuff, 1); + } + else if (j == 5) + { + gps_data->data[k].npts = traceBuffer->traces[i].ncopy; + ierr1 = copyTrace(gps_data->data[k].npts, + traceBuffer->traces[i].data, + gps_data->data[k].maxpts, + gps_data->data[k].esigmabuff); + memory_free64f(&traceBuffer->traces[i].data); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error copying esigmabuff"); + ierr = ierr + 1; + } + // Apply the gain + gps_data->data[k].gain[j] = 1.0; // will be applied here + gain = traceBuffer->traces[i].gain; + if (gain == 0.0) + { + LOG_ERRMSG("%s", "Division by zero"); + ierr = ierr + 1; + } + gain = 1.0/gain; + cblas_dscal(gps_data->data[k].npts, gain, + gps_data->data[k].esigmabuff, 1); + } + } + + if (debug) { + int npts; + LOG_DEBUGMSG("copyTB2GFAST data values, ncomp: %d", ncomp); + for (k = 0; k < gps_data->stream_length; k++) { + npts = gps_data->data[k].npts; + LOG_DEBUGMSG("%s.%s.%sNE321.%s: [%f %f %f %f %f %f]", + gps_data->data[k].netw, + gps_data->data[k].stnm, + gps_data->data[k].chan[0], + gps_data->data[k].loc, + gps_data->data[k].ubuff[npts - 1], + gps_data->data[k].nbuff[npts - 1], + gps_data->data[k].ebuff[npts - 1], + gps_data->data[k].usigmabuff[npts - 1], + gps_data->data[k].nsigmabuff[npts - 1], + gps_data->data[k].esigmabuff[npts - 1] + ); + } + } + memory_free8l(<Init); + return ierr; +} +//============================================================================// +/*! + * @brief Convenience function for copying origin to destination and + * filling any leftover poitns with NANs. + * + * @param[in] npts number of points on origin to copy + * @param[in] origin origin array to copy to dest [npts] + * @param[in] ndest number of points in dest (>= npts) + * + * @param[out] dest the first npts contains the data from the origin + * buffer and final [npts:ndest] is filled with NaNs + * + * @result 0 indicates successs + * + * @author Ben Baker (ISTI) + * + */ +static int copyTrace(const int npts, + const double *__restrict__ origin, + const int ndest, + double *__restrict__ dest) +{ + int i, ierr;//, nc; + ierr = 0; + if (npts > ndest) + { + LOG_ERRMSG("npts > ndest %d %d", npts, ndest); + return 1; + } + if (ndest > 0 && dest == NULL) + { + LOG_ERRMSG("%s", "dest is NULL"); + return 1; + } + if (npts > 0 && origin == NULL) + { + LOG_ERRMSG("%s", "origin is NULL"); + return 1; + } +#ifdef _OPENMP + #pragma omp simd +#endif + for (i=0; i +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Closes the HDF5 file on h5trace + * + * @param[in,out] h5trace on input holds the HDF5 file handle and + * h5traceBuffer properties. + * on output h5tracebuffer information is reset + * and the underlying HDF5 file with the traces + * is closed. + * + * @result 0 indicates success + * + */ +int traceBuffer_h5_finalize(struct h5traceBuffer_struct *h5trace) +{ + herr_t status; + int i, ierr; + //------------------------------------------------------------------------// + ierr = 0; + if (!h5trace->linit) + { + LOG_ERRMSG("%s", "Error h5trace never initialized"); + ierr = 1; + return ierr; + } + if (h5trace->ntraces > 0 && h5trace->traces != NULL) + { + for (i=0; intraces; i++) + { + if (h5trace->traces[i].groupName != NULL) + { + free(h5trace->traces[i].groupName); + } + if (h5trace->traces[i].metaGroupName != NULL) + { + free(h5trace->traces[i].metaGroupName); + } + } + free(h5trace->traces); + } + if (h5trace->ndtGroups > 0) + { + for (i=0; indtGroups; i++) + { + free(h5trace->dtGroupName[i]); + } + free(h5trace->dtGroupName); + memory_free32i(&h5trace->dtPtr); + } + status = H5Fclose(h5trace->fileID); + if (status != 0) + { + LOG_ERRMSG("%s", "Error closing file"); + ierr = 1; + } + memset(h5trace, 0, sizeof(struct h5traceBuffer_struct)); + return ierr; +} diff --git a/src/traceBuffer/h5/getData.c b/src/traceBuffer/h5/getData.c new file mode 100644 index 00000000..7b880ad1 --- /dev/null +++ b/src/traceBuffer/h5/getData.c @@ -0,0 +1,192 @@ +#include +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Returns the data on for the stations and channels in the + * h5traceBuffer from epochal times t1 to t2 + * + * @param[in] t1 epochal start time of traces (UTC seconds) + * @param[in] t2 epochal end time of traces (UTC seconds) + * + * @param[in,out] h5traceBuffer on input contains the desired traces (SNCLs) + * to query the HDF5 file. + * on successful exit contains the traces for + * each SNCL from times t1 to t2. any unknown + * data points must be detected by the user as + * they were defined in the HDF5 write step. + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int traceBuffer_h5_getData(const double t1, const double t2, + struct h5traceBuffer_struct *h5traceBuffer) +{ + double *gain, *work, dt, ts1, ts2; + int i1, i2, ibeg, idt, iend, ierr, j1, j2, k, k1, k2, + maxpts, ncopy, ntraces; + int debug = 0; + hid_t groupID; + herr_t status; + //------------------------------------------------------------------------// + for (idt=0; idtndtGroups; idt++) + { + gain = NULL; + work = NULL; + k1 = h5traceBuffer->dtPtr[idt]; + k2 = h5traceBuffer->dtPtr[idt+1]; + ntraces = k2 - k1; + if (debug) { + LOG_DEBUGMSG("getData: ntraces: %d", ntraces); + } + if (ntraces == 0){continue;} + // Open + read the data and attributes for this dataset + groupID = H5Gopen2(h5traceBuffer->fileID, + h5traceBuffer->dtGroupName[idt], H5P_DEFAULT); + gain = memory_calloc64f(ntraces); + work = traceBuffer_h5_readData(groupID, ntraces, + &maxpts, &dt, &ts1, &ts2, gain, &ierr); +//LOG_MSG(" Request: t1:%f - t2:%f", t1, t2); +//LOG_MSG("h5 is buffered to hold: ts1:%f -ts2:%f", ts1, ts2); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading data"); + return -1; + } + // This concludes the fileIO + status = H5Gclose(groupID); + // Check what i just read + if (status < 0) + { + LOG_ERRMSG("Error closing group %s", + h5traceBuffer->dtGroupName[idt]); + return -1; + } + if (dt <= 0.0) + { + LOG_ERRMSG("Invalid sampling period %f", dt); + return -1; + } + if (maxpts < 1) + { + LOG_ERRMSG("Invalid number of points %d", maxpts); + return -1; + } + // Check what I just read + if (t1 > ts2) + { + LOG_ERRMSG("%s", "Start time is too new"); + return -1; + } + if (t2 < ts1) + { + LOG_ERRMSG("%s", "End time is too old"); + return -1; + } + if (t2 > ts1 + (double) (maxpts - 1)*dt) + { + LOG_ERRMSG("%s", "Looking for data that's too current"); + return -1; + } + if (t1 < ts1) + { +// printf("getData: start time is too old\n"); + LOG_ERRMSG("%s", "Error start time is too old"); + //return -1; + } + // Indices in chunk to read from + i1 = (int) ((t1 - ts1)/dt + 0.5); + i2 = (int) ((t2 - ts1)/dt + 0.5); + i1 = MAX(i1, 0); //if (i1 < 0){i1 = 0;} + i2 = MIN(i2, maxpts - 1); //if (i2 > maxpts - 1){i2 = maxpts - 1;} + // Indices to set (if i were more clever i could make this span a + // superset of the times in memory - but then i'd fill it with NaNs + // and risk messing up the offset computation - particularly at the + // beginning where we have to know the position at the origin time) + j1 = i1; + j2 = i2; + j1 = MAX(j1, 0); //if (j1 < 0){j1 = 0;} + j2 = MIN(j2, maxpts - 1); //if (j2 > maxpts - 1){j2 = maxpts - 1;} + if (i2 - i1 > j2 - j1) + { + LOG_ERRMSG("%s", "Error source array larger than dest array"); + return -1; + } + ncopy = (int) ((t2 - t1)/dt + 0.5) + 1; + if (debug) { + LOG_DEBUGMSG("getData: i1:%d, i2:%d, j1:%d, j2:%d, k1:%d, k2:%d, ncopy:%d, t1:%f, t2:%f, maxpts:%d", + i1, i2, j1, j2, k1, k2, ncopy, t1, t2, maxpts); + } + /* + ncopy = (int) ((t2 - t1)/dt + 0.5) + 1; + j1 = 0; + j2 = j1 + ncopy; + */ + // Get the data onto the buffers + for (k=k1; ktraces[k].data); + h5traceBuffer->traces[k].t1 = t1; + h5traceBuffer->traces[k].ncopy = ncopy; + h5traceBuffer->traces[k].gain = gain[k-k1]; + // Set the data to NaN's + h5traceBuffer->traces[k].data + = array_set64f(ncopy, (double) NAN, &ierr); + // copy it + ibeg = h5traceBuffer->traces[k].traceNumber*maxpts + i1; + iend = ibeg + ncopy - 1; //i2; + if (iend - ibeg + 1 != ncopy) + { + LOG_ERRMSG("Inconsistent copy size %d %d %d", + ibeg, iend, ncopy); + return -1; + } + if (iend >= maxpts*ntraces) + { + LOG_ERRMSG("%s", "Critical error - work bounds exceeded"); + return -1; + } + //memcpy(&h5traceBuffer->traces[k].data[j1], &work[ibeg], + // (size_t) (ncopy)*sizeof(double)); + //ierr = array_copy64f_work(ncopy, &work[ibeg], + // &h5traceBuffer->traces[k].data[j1]); + ierr = array_copy64f_work(ncopy, &work[ibeg], + &h5traceBuffer->traces[k].data[0]); + + if (debug) { + LOG_DEBUGMSG("getData: k:%d, %s.%s.%s.%s ibeg:%d iend:%d work[ibeg]:%f work[iend]:%f, traceNumber:%d", + k, + h5traceBuffer->traces[k].stnm, h5traceBuffer->traces[k].chan, + h5traceBuffer->traces[k].netw, h5traceBuffer->traces[k].loc, + ibeg, iend, work[ibeg], work[iend], h5traceBuffer->traces[k].traceNumber) + } + /* + LOG_MSG("%s.%s.%s.%s t1:%f ibeg:%d iend:%d ncopy:%d work[ibeg]:%f work[iend]:%f", + h5traceBuffer->traces[k].stnm, h5traceBuffer->traces[k].chan, + h5traceBuffer->traces[k].netw, h5traceBuffer->traces[k].loc, + h5traceBuffer->traces[k].t1, + ibeg, iend, ncopy, + work[ibeg], + work[iend]); + */ + /* + h5traceBuffer->traces[k].data[ibeg+1], + h5traceBuffer->traces[k].data[iend-1]); + */ + + } // Loop on streams in this group + // Release temporary memory + memory_free64f(&work); + memory_free64f(&gain); + } // Loop on sampling period groups + return 0; +} diff --git a/src/traceBuffer/h5/getDoubleArray.c b/src/traceBuffer/h5/getDoubleArray.c new file mode 100644 index 00000000..9ed204ff --- /dev/null +++ b/src/traceBuffer/h5/getDoubleArray.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" + +int traceBuffer_h5_getDoubleArray(const hid_t groupID, + const int i1, const int i2, + const char *citem, + const double traceNaN, + const int nwork, + double *__restrict__ work) +{ + int i, ierr, ncopy, rank; + hid_t dataSet, dataSpace, memSpace; + hsize_t count[1], dims[1], offset[1]; + herr_t status; + //------------------------------------------------------------------------// + ierr = 0; + ncopy = i2 - i1 + 1; + if (ncopy < 1 || work == NULL || ncopy > nwork) + { + if (ncopy < 1){LOG_ERRMSG("%s", "No data to copy!");} + if (work == NULL){LOG_ERRMSG("%s", "Destination is NULL!");} + if (ncopy > nwork) + { + LOG_ERRMSG("%s", "Insufficient workspace!"); + } + return -1; + } + offset[0] = (hsize_t) i1; + count[0] = (hsize_t) ncopy; + dataSet = H5Dopen(groupID, citem, H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + rank = H5Sget_simple_extent_ndims(dataSpace); + if (rank != 1) + { + LOG_ERRMSG("%s", "Invalid rank for array data"); + return -1; + } + status = H5Sget_simple_extent_dims(dataSpace, dims, NULL); + if (status < 0) + { + LOG_ERRMSG("%s", "Failed getting dimension!"); + return -1; + } + memSpace = H5Screate_simple(rank, dims, NULL); + status = H5Sselect_hyperslab(dataSpace, H5S_SELECT_SET, offset, + NULL, count, NULL); + offset[0] = (hsize_t) i1; + count[0] = (hsize_t) ncopy; + status = H5Sselect_hyperslab(memSpace, H5S_SELECT_SET, offset, + NULL, count, NULL); + status = H5Dread(dataSet, H5T_NATIVE_DOUBLE, memSpace, dataSpace, + H5P_DEFAULT, work); + status += H5Sclose(memSpace); + status += H5Sclose(dataSpace); + status += H5Dclose(dataSet); + if (status != 0) + { + LOG_ERRMSG("%s", "Error reading dataset!"); + ierr = 1; + for (i=0; i +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" + +static double traceBuffer_h5_getDoubleScalar(const hid_t groupID, + const char *citem, + const double scalarNaN, + int *ierr); +static int traceBuffer_h5_getIntegerScalar(const hid_t groupID, + const char *citem, + const int scalarNaN, + int *ierr); +/*! + * @brief Gets the scalar data describing the trace stored in HDF5 + * + * @param[in] groupID HDF5 group ID handle + * @param[in] intNaN NaN if an integer cannot be found + * @param[in] doubleNaN NaN if a double cannot be found + * + * @param[out] maxpts max number of data points per buffer + * @param[out] dt sampling period (s) + * @param[out] gain channel gain + * @param[out] ts1 epochal start time of dataBuffer1 (UTC seconds) + * @param[out] ts2 epochal start time of dataBuffer2 (UTC seconds) + * + * @result 0 indicates success + * + */ +int traceBuffer_h5_getScalars(const hid_t groupID, + const int intNaN, + const double doubleNaN, + int *maxpts, + double *dt, double *gain, + double *ts1, double *ts2) +{ + int ierr, ierr1; + ierr = 0; + *maxpts = traceBuffer_h5_getIntegerScalar(groupID, + "MaxNumberOfPoints\0", + intNaN, &ierr1); + ierr = ierr + ierr1; + *dt = traceBuffer_h5_getDoubleScalar(groupID, + "SamplingPeriod\0", + doubleNaN, &ierr1); + ierr = ierr + ierr1; + *gain = traceBuffer_h5_getDoubleScalar(groupID, + "Gain\0", + doubleNaN, &ierr1); + ierr = ierr + ierr1; + *ts1 = traceBuffer_h5_getDoubleScalar(groupID, + "Buffer1StartTime\0", + doubleNaN, &ierr1); + ierr = ierr + ierr1; + *ts2 = traceBuffer_h5_getDoubleScalar(groupID, + "Buffer2StartTime\0", + doubleNaN, &ierr1); + ierr = ierr + ierr1; + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error getting scalars"); + } + return ierr; +} +//============================================================================// +/*! + * @brief Reads a double scalar dataset in the group in the HDF5 file + * + * @param[in] groupID HDF5 groupID handle + * @param[in] citem name of scalar dataset + * @param[in] scalarNaN default value for double if dataset cannot + * be found or read + * + * @param[out] ierr 0 indicates success + * + * @result on successful exit this is the desired double number otherwise + * it is scalarNaN + * + * @author Ben Baker (ISTI) + * + */ +static double traceBuffer_h5_getDoubleScalar(const hid_t groupID, + const char *citem, + const double scalarNaN, + int *ierr) +{ + double scalar; + hid_t dataSet, dataSpace, memSpace; + herr_t status; + const hsize_t dims[1] = {1}; + *ierr = 0; + status = 0; + scalar = scalarNaN; + dataSet = H5Dopen(groupID, citem, H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + memSpace = H5Screate_simple(1, dims, NULL); + status = H5Dread(dataSet, H5T_NATIVE_DOUBLE, memSpace, dataSpace, + H5P_DEFAULT, &scalar); + if (status != 0) + { + LOG_ERRMSG("%s", "Getting scalar"); + scalar = scalarNaN; + } + status += H5Sclose(memSpace); + status += H5Sclose(dataSpace); + status += H5Dclose(dataSet); + if (status != 0){*ierr = 1;} + return scalar; +} +//============================================================================// +/*! + * @brief Reads an integer scalar dataset in the group in the HDF5 file + * + * @param[in] groupID HDF5 groupID handle + * @param[in] citem name of scalar dataset + * @param[in] scalarNaN default value for integer if dataset cannot + * be found or read + * + * @param[out] ierr 0 indicates success + * + * @result on successful exit this is the desired integer number otherwise + * it is scalarNaN + * + * @author Ben Baker (ISTI) + * + */ +static int traceBuffer_h5_getIntegerScalar(const hid_t groupID, + const char *citem, + const int scalarNaN, + int *ierr) +{ + int scalar; + hid_t dataSet, dataSpace, memSpace; + herr_t status; + const hsize_t dims[1] = {1}; + *ierr = 0; + status = 0; + scalar = scalarNaN; + dataSet = H5Dopen(groupID, citem, H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + memSpace = H5Screate_simple(1, dims, NULL); + status = H5Dread(dataSet, H5T_NATIVE_INT, memSpace, dataSpace, + H5P_DEFAULT, &scalar); + if (status != 0) + { + LOG_ERRMSG("%s", "Getting scalar"); + scalar = scalarNaN; + } + status += H5Sclose(memSpace); + status += H5Sclose(dataSpace); + status += H5Dclose(dataSet); + if (status != 0){*ierr = 1;} + return scalar; +} diff --git a/src/traceBuffer/h5/initialize.c b/src/traceBuffer/h5/initialize.c new file mode 100644 index 00000000..e7747d97 --- /dev/null +++ b/src/traceBuffer/h5/initialize.c @@ -0,0 +1,361 @@ +#include +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "gfast_hdf5.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" +#include "iscl/time/time.h" +#include "iscl/os/os.h" +/*! + * @brief Initializes the HDF5 file for archiving the acquisition or + * reading in playback mode. + * + * @param[in] job If job = 1 then the file will be opened as + * read only. + * If job = 2 then the file will be opened as + * read/write. + * @param[in] linMemory If true then keep the opened file in memory. + * @param[in] h5dir directory where HDF5 file exists + * @param[in] h5file name of the HDF5 file in the directory + * + * @param[in,out] h5traceBuffer On input, contains the names of the HDF5 + * dataset names. + * On output, contains the HDF5 file handle + * from which we'll read and write. + * + * @result 0 indicates success + * + */ +int traceBuffer_h5_initialize(const int job, + const bool linMemory, + const char *h5dir, + const char *h5file, + struct h5traceBuffer_struct *h5traceBuffer) +{ + FILE *fp; + double *work; + char **traceOut, **traces, h5name[PATH_MAX], cwork[512], temp[64]; + herr_t status; + hsize_t dims[2]; + hid_t dataSet, dataSpace, groupID, properties; + double *dts, *selevs, *slats, *slons, tbeg, t1; + int i, ierr, j, k, maxpts, ndtGroups, ntraces; + size_t blockSize; + const bool lsave = true;; + // Make sure there is data + if (h5traceBuffer->traces == NULL || h5traceBuffer->ntraces < 1) + { + LOG_ERRMSG("%s", "Input traces do not exist"); + return -1; + } + // Set the filename + ierr = traceBuffer_h5_setFileName(h5dir, h5file, h5name); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting the HDF5 filename"); + return -1; + } + // In this instance the file is simply opened for reading + if (job == 1) + { + // If scratch file was saved then remove it + if (!os_path_isfile(h5name)) + { + LOG_ERRMSG("Error HDF5 file does %s not exist!", h5name); + return -1; + } + // Get the size of the file + fp = fopen(h5name, "rb\0"); + fseek(fp, 0L, SEEK_END); + blockSize = (size_t) (ftell(fp)); + fclose(fp); + // Open the file + properties = H5Pcreate(H5P_FILE_ACCESS); + if (linMemory) + { + status = H5Pset_fapl_core(properties, blockSize, false); + if (status < 0) + { + LOG_ERRMSG("%s", "Error setting properties list"); + return -1; + } + } + h5traceBuffer->fileID = H5Fopen(h5name, H5F_ACC_RDONLY, properties); + status = H5Pclose(properties); + if (status < 0) + { + LOG_ERRMSG("%s", "Error closing the properties list"); + return -1; + } + // Verify the group is there + for (i=0; indtGroups; i++) + { + if (H5Lexists(h5traceBuffer->fileID, + h5traceBuffer->dtGroupName[i], //traces[i].groupName, + H5P_DEFAULT) != 1) + { + LOG_ERRMSG("Error couldn't find group: %s", + h5traceBuffer->dtGroupName[i]); + return -1; + } + } + // Get the metaData and make a permutation + traces = h5_read_array__string("/MetaData/TraceNames\0", + h5traceBuffer->fileID, &ntraces, &ierr); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Couldn't read traces"); + return -1; + } + if (ntraces != h5traceBuffer->ntraces) + { + LOG_ERRMSG("%s", "metadata size inconsistency"); + return -1; + } + // Match those SNCLs + for (i=0; intraces; i++) + { + memset(temp, 0, sizeof(temp)); + strcpy(temp, h5traceBuffer->traces[i].netw); + strcat(temp, ".\0"); + strcat(temp, h5traceBuffer->traces[i].stnm); + strcat(temp, ".\0"); + strcat(temp, h5traceBuffer->traces[i].chan); + strcat(temp, ".\0"); + strcat(temp, h5traceBuffer->traces[i].loc); + for (j=0; jntraces; j++) + { + if (strcasecmp(traces[j], temp) == 0) + { + h5traceBuffer->traces[i].traceNumber = j; + goto FOUND_TRACE; + } + } + LOG_ERRMSG("%s", "Failed to find trace!"); + return -1; +FOUND_TRACE:; + } + if (ntraces > 0) + { + free(traces[0]); + free(traces); + } + } + // Otherwise the file size must be estimated and opened for writing + else + { + // Set the time to now + tbeg = (double) ((long) (time_timeStamp())); + // If scratch file was saved then remove it + if (os_path_isfile(h5name)) + { + LOG_WARNMSG("Deleting file %s", h5name); + } + // Space estimate + maxpts = 0; + for (i=0; intraces; i++) + { + maxpts = (int) (fmax(h5traceBuffer->traces[i].maxpts, maxpts)); + if (maxpts <= 0) + { + if (maxpts < 0) + { + LOG_WARNMSG("maxpts = %d is negative - setting to 0", + maxpts); + maxpts = 0; + h5traceBuffer->traces[i].maxpts = maxpts; + } + else + { + LOG_WARNMSG("maxpts is 0 for trace %d", i+1); + } + } + } + if (maxpts == 0) + { + LOG_ERRMSG("%s", "There's no data in the buffers"); + return -1; + } + blockSize = (size_t) + (h5traceBuffer->ntraces*(8*maxpts + 4*8 + 64 + 2*8 + 2*4)); + // add a little extra + blockSize = (size_t) ((double) (blockSize*1.1 + 0.5)); + properties = H5Pcreate(H5P_FILE_ACCESS); + if (linMemory) + { + status = H5Pset_fapl_core(properties, blockSize, lsave); + if (status < 0) + { + LOG_ERRMSG("%s", "Error setting properties list"); + return -1; + } + } + h5traceBuffer->fileID = H5Fcreate(h5name, H5F_ACC_TRUNC, + H5P_DEFAULT, properties); + status = H5Pclose(properties); + if (status < 0) + { + LOG_ERRMSG("%s", "Error closing the properties list"); + return -1; + } + // Make the root groups + groupID = H5Gcreate2(h5traceBuffer->fileID, + "/Data\0", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + status = H5Gclose(groupID); + if (status < 0) + { + LOG_ERRMSG("%s", "Error creating /Data group"); + return -1; + } + ndtGroups = 0; + for (i=0; intraces; i++) + { + if (h5traceBuffer->traces[i].dtGroupNumber > ndtGroups) + { + ndtGroups = h5traceBuffer->traces[i].dtGroupNumber; + } + } + if (ndtGroups <= 0) + { + LOG_ERRMSG("%s", "Error no sampling period groups"); + return -1; + } + if (ndtGroups > 1) + { + LOG_WARNMSG("%s", "Multiple dt not tested"); + return -1; + } + for (i=0; idtPtr[i]; + memset(cwork, 0, sizeof(cwork)); + sprintf(cwork, "/Data/SamplingPeriodGroup_%d", i+1); + groupID = H5Gcreate2(h5traceBuffer->fileID, + cwork, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + h5_write_attribute__double("SamplingPeriod\0", groupID, + 1, &h5traceBuffer->traces[k].dt); + status = H5Gclose(groupID); + } + groupID = H5Gcreate2(h5traceBuffer->fileID, + "/MetaData\0", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + status = H5Gclose(groupID); + if (status < 0) + { + LOG_ERRMSG("%s", "Error creating /MetaData group"); + return -1; + } + // Make the data + for (i=0; indtGroups; i++) + { + k = h5traceBuffer->dtPtr[i]; + ntraces = h5traceBuffer->dtPtr[i+1] - h5traceBuffer->dtPtr[i]; + memset(cwork, 0, sizeof(cwork)); + sprintf(cwork, "/Data/SamplingPeriodGroup_%d/Data", i+1); + work = array_set64f(h5traceBuffer->ntraces*maxpts, + (double) NAN, &ierr); + dims[0] = (hsize_t) h5traceBuffer->ntraces; + dims[1] = (hsize_t) maxpts; + dataSpace = H5Screate_simple(2, dims, NULL); + dataSet = H5Dcreate2(h5traceBuffer->fileID, cwork, + H5T_NATIVE_DOUBLE, dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + status = H5Dwrite(dataSet, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, work); + ierr = h5_write_attribute__double("SamplingPeriod\0", dataSet, + 1, &h5traceBuffer->traces[k].dt); + t1 = tbeg - (double) (maxpts - 1)*h5traceBuffer->traces[k].dt; + ierr = h5_write_attribute__double("StartTime\0", dataSet, + 1, &t1); + ierr = h5_write_attribute__int("NumberOfPoints\0", dataSet, + 1, &maxpts); + ierr = h5_write_attribute__int("NumberOfTraces\0", dataSet, + 1, &ntraces); + H5Sclose(dataSpace); + H5Dclose(dataSet); + // Make the gain + dims[0] = (hsize_t) ntraces; + for (k=h5traceBuffer->dtPtr[i]; kdtPtr[i+1]; k++) + { + work[k] = h5traceBuffer->traces[k].gain; + } + dims[0] = (hsize_t) ntraces; + dataSpace = H5Screate_simple(1, dims, NULL); + dataSet = H5Dcreate2(h5traceBuffer->fileID, + "/Data/SamplingPeriodGroup_1/Gain\0", + H5T_NATIVE_DOUBLE, dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + status = H5Dwrite(dataSet, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, work); + status = H5Sclose(dataSpace); + status = H5Dclose(dataSet); + // Make the metadata + slats = memory_calloc64f(ntraces); + slons = memory_calloc64f(ntraces); + selevs = memory_calloc64f(ntraces); + dts = memory_calloc64f(ntraces); + traceOut = (char **) calloc((size_t) ntraces, sizeof(char *)); + for (k=h5traceBuffer->dtPtr[i]; kdtPtr[i+1]; k++) + { + j = k - h5traceBuffer->dtPtr[i]; + h5traceBuffer->traces[k].traceNumber = j; + slats[j] = h5traceBuffer->traces[k].slat; + slons[j] = h5traceBuffer->traces[k].slon; + selevs[j] = h5traceBuffer->traces[k].selev; + dts[j] = h5traceBuffer->traces[k].dt; + traceOut[j] = (char *) calloc(64, sizeof(char)); + strcpy(traceOut[j], h5traceBuffer->traces[k].netw); + strcat(traceOut[j], ".\0"); + strcat(traceOut[j], h5traceBuffer->traces[k].stnm); + strcat(traceOut[j], ".\0"); + strcat(traceOut[j], h5traceBuffer->traces[k].chan); + strcat(traceOut[j], ".\0"); + strcat(traceOut[j], h5traceBuffer->traces[k].loc); + } + memset(cwork, 0, sizeof(cwork)); + strcpy(cwork, "/MetaData/SamplingPeriods\0"); + ierr = h5_write_array__double(cwork, h5traceBuffer->fileID, + ntraces, dts); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing dts"); + return -1; + } + memset(cwork, 0, sizeof(cwork)); + strcpy(cwork, "/MetaData/StationElevations\0"); + ierr = h5_write_array__double(cwork, h5traceBuffer->fileID, + ntraces, selevs); + memset(cwork, 0, sizeof(cwork)); + strcpy(cwork, "/MetaData/StationLatitudes\0"); + ierr = h5_write_array__double(cwork, h5traceBuffer->fileID, + ntraces, slats); + memset(cwork, 0, sizeof(cwork)); + strcpy(cwork, "/MetaData/StationLongitudes\0"); + ierr = h5_write_array__double(cwork, h5traceBuffer->fileID, + ntraces, slons); + memset(cwork, 0, sizeof(cwork)); + strcpy(cwork, "/MetaData/TraceNames\0"); + ierr = h5_write_array__chars(cwork, h5traceBuffer->fileID, + ntraces, traceOut); + // Free workspace + memory_free64f(&dts); + memory_free64f(&selevs); + memory_free64f(&slons); + memory_free64f(&slats); + memory_free64f(&work); + for (j=0; jlinit = true; + return 0; +} diff --git a/src/traceBuffer/h5/readData.c b/src/traceBuffer/h5/readData.c new file mode 100644 index 00000000..2c5be7b8 --- /dev/null +++ b/src/traceBuffer/h5/readData.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Reads the blocked data /Data in the Data group + * + * @param[in] groupID handle for HDF5 group with data + * @param[in] ntraces number of traces I'm expecting to read + * + * @param[out] maxpts number of points in block + * @param[out] dt sampling period (s) + * @param[out] ts1 epochal start time (UTC seconds) of data chunk + * @param[out] ts2 epochal end time (UTC seconds) of data chunk + * @param[out] gain gain for each trace [ntraces] + * @param[out] ierr 0 indicates success + * + * @result data chunk [ntraces x maxpts] with leading dimension maxpts + * + * @author Ben Baker + * + */ +double *traceBuffer_h5_readData(const hid_t groupID, + const int ntraces, + int *maxpts, + double *dt, double *ts1, double *ts2, + double *gain, int *ierr) +{ + double *work; + hid_t attribute, dataSet, dataSpace, memSpace; + hsize_t dims[2]; + herr_t status; + int ntracesIn, nwork, rankIn; + const int rank = 2; + //------------------------------------------------------------------------// + *ierr = 0; + work = NULL; + if (gain == NULL) + { + LOG_ERRMSG("%s", "Error gain cannot be NULL"); + *ierr = 1; + return work; + } + dataSet = H5Dopen2(groupID, "Data\0", H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + rankIn = H5Sget_simple_extent_ndims(dataSpace); + if (rankIn != 2) + { + LOG_ERRMSG("Invalid number of dimensions %d", rankIn); + *ierr = 1; + return work; + } + status = H5Sget_simple_extent_dims(dataSpace, dims, NULL); + nwork = (int) (dims[0]*dims[1]); + memSpace = H5Screate_simple(rank, dims, NULL); + work = memory_calloc64f(nwork); + status = H5Dread(dataSet, H5T_NATIVE_DOUBLE, memSpace, dataSpace, + H5P_DEFAULT, work); + if (status < 0) + { + LOG_ERRMSG("%s", "Error loading data"); + *ierr = 1; + return work; + } + // Pick off the attributes while the dataset is open + attribute = H5Aopen(dataSet, "SamplingPeriod\0", H5P_DEFAULT); + status = H5Aread(attribute, H5T_NATIVE_DOUBLE, dt); + status = H5Aclose(attribute); + attribute = H5Aopen(dataSet, "StartTime\0", H5P_DEFAULT); + status = H5Aread(attribute, H5T_NATIVE_DOUBLE, ts1); + status = H5Aclose(attribute); + attribute = H5Aopen(dataSet, "NumberOfTraces\0", H5P_DEFAULT); + status = H5Aread(attribute, H5T_NATIVE_INT, &ntracesIn); + if (ntracesIn != ntraces) + { + LOG_ERRMSG("Inconsistent number of traces %d %d", ntracesIn, ntraces); + *ierr = 1; + return work; + } + status = H5Aclose(attribute); + attribute = H5Aopen(dataSet, "NumberOfPoints\0", H5P_DEFAULT); + status = H5Aread(attribute, H5T_NATIVE_INT, maxpts); + status = H5Aclose(attribute); + *ts2 = *ts1 + (double) (*maxpts - 1)*(*dt); + // close Data dataset + status = H5Sclose(memSpace); + status += H5Sclose(dataSpace); + status += H5Dclose(dataSet); + if (status < 0) + { + LOG_ERRMSG("%s", "Error closing data dataset"); + *ierr = 1; + return work; + } + // Likewise get the gain for each channel + dataSet = H5Dopen2(groupID, "Gain\0", H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + dims[0] = (hsize_t) ntracesIn; + memSpace = H5Screate_simple(1, dims, NULL); + status = H5Dread(dataSet, H5T_NATIVE_DOUBLE, memSpace, dataSpace, + H5P_DEFAULT, gain); + if (status < 0) + { + LOG_ERRMSG("%s", "Error loading gain"); + *ierr = 1; + return work; + } + // close Gain dataset + status = H5Sclose(memSpace); + status += H5Sclose(dataSpace); + status += H5Dclose(dataSet); + if (status < 0) + { + LOG_ERRMSG("%s", "Error closing data dataset"); + *ierr = 1; + return work; + } + return work; +} diff --git a/src/traceBuffer/h5/setData.c b/src/traceBuffer/h5/setData.c new file mode 100644 index 00000000..2b4c499b --- /dev/null +++ b/src/traceBuffer/h5/setData.c @@ -0,0 +1,310 @@ +#include +#include +#include +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "gfast_hdf5.h" +#include "iscl/array/array.h" +#include "iscl/memory/memory.h" + +/* +static int update_dataSet(const hid_t groupID, + const char *dataSetName, + int i1, int i2, const int npts, + const double *__restrict__ data); +*/ + +/*! + * @brief Sets the data in the HDF5 file from the data on the tb2Data + * buffer. If any data is late then it will be filled with NaN's + * in the HDF5 file. + * + * @param[in] currentTime current time (UTC seconds since epoch) to which to + * update the HDF5 data buffers. + * @param[in] tb2Data holds the tracebuffer2 data to be written to + * disk. the SNCLs on tb2Data should correspond + * to the SNCLs on h5TraceBuffer and the data should + * be in temporal order. + * @param[in] h5traceBuffer holds the HDF5 group names for each trace and + * HDF5 file details + * + * @author Ben Baker (ISTI) + * + * @copyright Apache 2 + */ +int traceBuffer_h5_setData(const double currentTime, + struct tb2Data_struct tb2Data, + struct h5traceBuffer_struct h5traceBuffer) +{ + double *dwork, *gains, *work; + int *map, c1, c2, chunk, i, i1, i2, idt, ierr, ierrAll, + indx, is, ishift, jndx, k, k1, k2, maxpts, nchunks, ncopy, ntraces; + double dt, ts1, ts2; + bool *lhaveData; + hsize_t dims[2]; + hid_t attribute, groupID, dataSet, dataSpace; + herr_t status; + int debug = 0; + //------------------------------------------------------------------------// + // + // Require both items are set + if (debug) { + LOG_DEBUGMSG("%s", "Starting traceBuffer_h5_setData"); + } + ierr = 0; + ierrAll = 0; + if (!tb2Data.linit || !h5traceBuffer.linit) + { + if (!tb2Data.linit){LOG_ERRMSG("%s", "Error tb2Data not set");} + if (!h5traceBuffer.linit){LOG_ERRMSG("%s", "h5traceBuffer not set");} + return -1; + } + // Nothing to do + if (h5traceBuffer.ntraces < 1) + { + return 0; + } + // Not finished yet + if (h5traceBuffer.ndtGroups > 1) + { + LOG_ERRMSG("%s", "Multiple dt groups not yet done"); + return -1; + } + // Make a map from the HDF5 trace buffer to the tracebuffer2 data + if (debug) { + LOG_DEBUGMSG("%s", "Make a map from the HDF5 trace buffer to the tracebuffer2 data"); + } + map = array_set32i(h5traceBuffer.ntraces, -1, &ierr); + lhaveData = memory_calloc8l(h5traceBuffer.ntraces); + for (i=0; i 0) + { + lhaveData[i] = true; + } + goto NEXT_TRACE; + } + } + if (debug) { + LOG_DEBUGMSG("h5traceBuffer and tb2Data didn't match, going hunting (inefficient)! i:%d, %s.%s.%s.%s", + i, + h5traceBuffer.traces[i].netw, + h5traceBuffer.traces[i].stnm, + h5traceBuffer.traces[i].chan, + h5traceBuffer.traces[i].loc) + } + // Hunt through the tracebuffers + for (k=0; k 0) + { + lhaveData[i] = true; + } + goto NEXT_TRACE; + } + } +NEXT_TRACE:; + /* + printf("setData: %s.%s.%s.%s map[%d]=%d\n", + h5traceBuffer.traces[i].netw, + h5traceBuffer.traces[i].stnm, + h5traceBuffer.traces[i].chan, + h5traceBuffer.traces[i].loc, + i, map[i]); + */ + } + + if (debug) { + LOG_DEBUGMSG("%s", "setData: Done making map for HDF5 to tracebuffer2"); + LOG_DEBUGMSG("setData: Looping over %d sampling groups", h5traceBuffer.ndtGroups); + } + + for (idt=0; idt +#include +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "iscl/os/os.h" + +/*! + * @brief Sets the HDF5 trace buffer file name + * + * @param[in] h5dir Name of directory where HDF5 is located or will + * reside. If null then the current working directory + * will be used. + * @param[in] h5file Name of the HDF5 file. This should have the .h5 + * already appended. + * @param[out] h5name Full path name made by concatenating h5dir, h5file + * + * @result the full path to the HDF5 file + * + */ +int traceBuffer_h5_setFileName(const char *h5dir, + const char *h5file, + char h5name[PATH_MAX]) +{ + size_t lend; + memset(h5name, 0, PATH_MAX*sizeof(char)); + if (h5file == NULL) + { + LOG_ERRMSG("%s", "Error h5file cannot be NULL"); + return -1; + } + if (strlen(h5file) == 0) + { + LOG_ERRMSG("%s", "Error h5file cannot be blank"); + return -1; + } + // Set the directory name + if (h5dir == NULL) + { + strcpy(h5name, "./\0"); + } + else + { + lend = strlen(h5dir); + if (lend == 0) + { + strcpy(h5name, "./\0"); + } + else + { + if (!os_path_isdir(h5dir)) + { + LOG_ERRMSG("Directory %s does not exist", h5dir); + return -1; + } + strcpy(h5name, h5dir); + if (h5name[lend-1] != '/'){strcat(h5name, "/\0");} + } + } + // Append the file name + strcat(h5name, h5file); + return 0; +} diff --git a/src/traceBuffer/h5/setScalars.c b/src/traceBuffer/h5/setScalars.c new file mode 100644 index 00000000..dcd5acdd --- /dev/null +++ b/src/traceBuffer/h5/setScalars.c @@ -0,0 +1,127 @@ +#include +#include +#include "gfast_traceBuffer.h" +#include "gfast_core.h" + +/*! + * @brief Sets the integer scalar dataset + * + * @param[in] groupID HDF5 group handle + * @param[in] citem NULL terminated dataset name to be written in group + * @param[in] scalar scalar data to write to a dataset + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int traceBuffer_h5_setIntegerScalar(const hid_t groupID, + const char *citem, + const int scalar) +{ + int scalars[1]; + hid_t dataSetID, dataSpace; + herr_t status; + int ierr; + const hsize_t dims[1] = {1}; + const int rank = 1; + //------------------------------------------------------------------------// + ierr = 0; + if (citem == NULL) + { + LOG_ERRMSG("%s", "Error citem must be defined"); + return -1; + } + if (H5Lexists(groupID, citem, H5P_DEFAULT) == 1){return 0;} // Nothing to do + scalars[0] = scalar; + // Update an existing scalar + if (H5Lexists(groupID, citem, H5P_DEFAULT) == 1) + { + dataSetID = H5Dopen(groupID, citem, H5P_DEFAULT); + dataSpace = H5Dget_space(dataSetID); + } + // Make a brand new scalar + else + { + dataSpace = H5Screate_simple(rank, dims, NULL); + dataSetID = H5Dcreate2(groupID, citem, H5T_NATIVE_INT, + dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + status = H5Dwrite(dataSetID, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, scalars); + if (status < 0) + { + LOG_ERRMSG("%s", "Failed to write dataset"); + ierr = 1; + } + status = H5Sclose(dataSpace); + status += H5Dclose(dataSetID); + if (status < 0) + { + LOG_ERRMSG("%s", "Failed to close dataspace or dataset"); + ierr = 1; + } + return ierr; +} +//============================================================================// +/*! + * @brief Sets the double scalar dataset + * + * @param[in] groupID HDF5 group handle + * @param[in] citem NULL terminated dataset name to be written in group + * @param[in] scalar scalar data to write to a dataset + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int traceBuffer_h5_setDoubleScalar(const hid_t groupID, + const char *citem, + const double scalar) +{ + double scalars[1]; + hid_t dataSetID, dataSpace; + herr_t status; + int ierr; + const hsize_t dims[1] = {1}; + const int rank = 1; + //------------------------------------------------------------------------// + ierr = 0; + if (citem == NULL) + { + LOG_ERRMSG("%s", "Error citem must be defined"); + return -1; + } + scalars[0] = scalar; + // Update an existing scalar + if (H5Lexists(groupID, citem, H5P_DEFAULT) == 1) + { + dataSetID = H5Dopen(groupID, citem, H5P_DEFAULT); + dataSpace = H5Dget_space(dataSetID); + } + // Make a brand new scalar + else + { + dataSpace = H5Screate_simple(rank, dims, NULL); + dataSetID = H5Dcreate2(groupID, citem, H5T_NATIVE_DOUBLE, + dataSpace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + status = H5Dwrite(dataSetID, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, scalars); + if (status < 0) + { + LOG_ERRMSG("%s", "Failed to write dataset"); + ierr = 1; + } + status = H5Sclose(dataSpace); + status += H5Dclose(dataSetID); + if (status < 0) + { + LOG_ERRMSG("%s", "Failed to close dataspace or dataset"); + ierr = 1; + } + return ierr; +} diff --git a/src/traceBuffer/h5/setTraceBufferFromGFAST.c b/src/traceBuffer/h5/setTraceBufferFromGFAST.c new file mode 100644 index 00000000..ed95e4df --- /dev/null +++ b/src/traceBuffer/h5/setTraceBufferFromGFAST.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include "gfast_struct.h" +#include "gfast_traceBuffer.h" +#include "gfast_core.h" +#include "iscl/memory/memory.h" + +/*! + * @brief Sets the HDF5 traceBuffer from the GFAST structure + * + * @param[in] bufflen max time window in h5traceBuffer TODO: should delete + * @param[in] gps_data the GPS streams and basic metadata that will be + * requested + * + * @param[out] traceBuffer contains a map from the GPS data to the data that + * is or will be in the H5 file + * + * @result 0 indicates success + * + */ +int traceBuffer_h5_setTraceBufferFromGFAST( + const double bufflen, + struct GFAST_data_struct gps_data, + struct h5traceBuffer_struct *traceBuffer) +{ + char temp[1024]; + double *dtGroups, dt0, dt; + int *ndtGroups, i, itn, j, k, ng; + int debug = 0; + if (debug) { + LOG_DEBUGMSG("%s", "Entering traceBuffer_h5_setTraceBufferFromGFAST"); + } + // Count the number of traces + traceBuffer->ntraces = 0; + for (k=0; kntraces = traceBuffer->ntraces + 6; // Z, N, E, 3, 2, 1 + } + if (traceBuffer->ntraces < 1) + { + LOG_ERRMSG("%s", "Error no traces to read!"); + return -1; + } + // Set the sampling period group numbers + dtGroups = (double *) + calloc((size_t) gps_data.stream_length, sizeof(double)); + ndtGroups = (int *) + calloc((size_t) gps_data.stream_length, sizeof(int)); + ng = 0; + for (k=0; k 1) + { + LOG_WARNMSG("%s", "Multiple sampling periods is untested"); + LOG_WARNMSG("%s", "argsort the ndtGroups and fill in order"); + } + dt0 = (double) NAN; + traceBuffer->dtPtr = memory_calloc32i(ng + 1); + traceBuffer->dtGroupName = (char **) + calloc((size_t) ng, sizeof(char *)); + traceBuffer->ndtGroups = ng; + traceBuffer->traces = (struct h5trace_struct *) + calloc((size_t) traceBuffer->ntraces, + sizeof(struct h5trace_struct)); + ng = 0; + i = 0; + itn = 0; + for (k=0; ktraces[i].netw, 0, + sizeof(traceBuffer->traces[i].netw)); + memset(traceBuffer->traces[i].stnm, 0, + sizeof(traceBuffer->traces[i].stnm)); + memset(traceBuffer->traces[i].chan, 0, + sizeof(traceBuffer->traces[i].chan)); + memset(traceBuffer->traces[i].loc, 0, + sizeof(traceBuffer->traces[i].loc)); + strcpy(traceBuffer->traces[i].netw, gps_data.data[k].netw); + strcpy(traceBuffer->traces[i].stnm, gps_data.data[k].stnm); + strcpy(traceBuffer->traces[i].chan, gps_data.data[k].chan[j]); + strcpy(traceBuffer->traces[i].loc, gps_data.data[k].loc); + traceBuffer->traces[i].dtGroupNumber = ndtGroups[k]; + traceBuffer->traces[i].idest = k * 6 + j; + + if (debug) { + LOG_DEBUGMSG("setH5: Check traceBuffer->traces[%d].chan = %s", + i, traceBuffer->traces[i].chan) + } + + memset(temp, 0, sizeof(temp)); + strcpy(temp, "/MetaData/\0"); + strcat(temp, gps_data.data[k].netw); + strcat(temp, ".\0"); + strcat(temp, gps_data.data[k].stnm); + strcat(temp, ".\0"); + strcat(temp, gps_data.data[k].chan[j]); + strcat(temp, ".\0"); + strcat(temp, gps_data.data[k].loc); + traceBuffer->traces[i].metaGroupName + = (char *)calloc(strlen(temp)+1, sizeof(char)); + strcpy(traceBuffer->traces[i].metaGroupName, temp); + + memset(temp, 0, sizeof(temp)); + sprintf(temp, "/Data/SamplingPeriodGroup_%d/", + traceBuffer->traces[i].dtGroupNumber); + traceBuffer->traces[i].groupName + = (char *)calloc(strlen(temp)+1, sizeof(char)); + strcpy(traceBuffer->traces[i].groupName, temp); + + if (isnan(dt0)) + { + traceBuffer->dtGroupName[ng] = (char *)calloc(64, sizeof(char)); + sprintf(traceBuffer->dtGroupName[ng], + "/Data/SamplingPeriodGroup_%d/", ng+1); + dt0 = gps_data.data[k].dt; + itn = 0; + ng = ng + 1; + } + if (fabs(dt0 - gps_data.data[k].dt)/dt0 > 1.e-10) + { + LOG_ERRMSG("%s", "Error can't yet handle multirate data"); + return -1; + } + traceBuffer->traces[i].traceNumber = itn; + traceBuffer->traces[i].dt = gps_data.data[k].dt; + traceBuffer->traces[i].slat = gps_data.data[k].sta_lat; + traceBuffer->traces[i].slon = gps_data.data[k].sta_lon; + traceBuffer->traces[i].selev = gps_data.data[k].sta_alt; + traceBuffer->traces[i].maxpts + = (int) (bufflen/traceBuffer->traces[i].dt + 0.5) + 1; + traceBuffer->traces[i].dt = gps_data.data[k].dt; + traceBuffer->traces[i].gain = gps_data.data[k].gain[j]; + + if (debug) { + LOG_DEBUGMSG("setH5: Made trace %d, groupName: %s, dtGroupNumber: %d, idest: %d", + i, + traceBuffer->traces[i].groupName, + traceBuffer->traces[i].dtGroupNumber, + traceBuffer->traces[i].idest) + } + + i = i + 1; + itn = itn + 1; + } + } + traceBuffer->dtPtr[ng] = traceBuffer->ntraces; + + if (debug) { + LOG_DEBUGMSG("setH5: ng: %d, ndtGroups: %d, ntraces: %d", + ng, + traceBuffer->ndtGroups, + traceBuffer->ntraces) + } + + // free space + free(dtGroups); + free(ndtGroups); + return 0; +} diff --git a/src/uw/beachball.c b/src/uw/beachball.c new file mode 100644 index 00000000..0fc63e2e --- /dev/null +++ b/src/uw/beachball.c @@ -0,0 +1,1235 @@ +#include +#include +#include +#include +#include +#include +#include "gfast_config.h" +#ifdef GFAST_USE_INTEL + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Weverything" + #endif + #include + #include + #ifdef __clang__ + #pragma clang diagnostic pop + #endif +#else +#include +#include +#include +#endif +#include +#include "beachball.h" +#include "compearth.h" +//#include "cmopad.h" +//#include "pixmap.h" +//#include "pixmap_png.h" +//#include "pixmap_jpg.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 +#endif +#ifndef MAX +#define MAX(x,y) (((x) > (y)) ? (x) : (y)) +#endif +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) +#endif +#define PIXMAP_COLORS 3 + +static void vecstrd(const double str, const double dip, double r[3]); +static void strdv(const double r[3], double *str, double *dip); +static void crossp(const double *__restrict__ u, + const double *__restrict__ v, + double *__restrict__ n); +static void strdvec(double r[3], double *str, double *dip); +static void rotmat(const int naxis, const double theta, + double *__restrict__ r, + double *__restrict__ rt); +static void isItNear(const double *__restrict__ pt, + double *howClose, + double *__restrict__ ptold); +static double dot3(const double *__restrict__ x, + const double *__restrict__ y); +static void gemv3(const double *__restrict__ A, const double *__restrict__ x, + double *__restrict__ y); +static double transform(const double a, const double b, + const double c, const double d, + const double x); + +int beachball_setMomentTensor(const double m11, const double m22, + const double m33, const double m12, + const double m13, const double m23, + const enum compearthCoordSystem_enum basis, + struct beachballPlot_struct *beachball) +{ + //struct cmopad_struct cmt; + //double mt[3][3]; + double m9[9], eigs[3]; + double m6[6], fp1[3], fp2[3], clvdPct, dcPct, devPct, isoPct, M0, Mw; + int ierr, info; + bool lexplosion, limplosion; + //memset(&cmt, 0, sizeof(struct cmopad_struct)); + memset(beachball->t_axis, 0, 3*sizeof(double)); + memset(beachball->null_axis, 0, 3*sizeof(double)); + memset(beachball->p_axis, 0, 3*sizeof(double)); + // the edge case is for purely isotropic sources + lexplosion = false; + limplosion = false; + m9[0] = m11; + m9[1] = m12; + m9[2] = m13; + m9[3] = m12; + m9[4] = m22; + m9[5] = m23; + m9[6] = m13; + m9[7] = m23; + m9[8] = m33; + info = LAPACKE_dsyev(LAPACK_COL_MAJOR, 'N', 'L', 3, m9, 3, eigs); + if (info != 0) + { + printf("Failed classifying eigenvalues\n"); + } + if ((eigs[0] > 0.0 && eigs[1] > 0.0 && eigs[2] > 0.0)) + { + //printf("Source is pure explosion\n"); + lexplosion = true; + } + if ((eigs[0] < 0.0 && eigs[1] < 0.0 && eigs[2] < 0.0)) + { + printf("Source is pure implosion\n"); + limplosion = true; + } + // perform the decomposition + m6[0] = m11; + m6[1] = m22; + m6[2] = m33; + m6[3] = m12; + m6[4] = m13; + m6[5] = m23; + ierr = compearth_standardDecomposition(1, m6, basis, + &M0, &Mw, fp1, fp2, + beachball->p_axis, + beachball->null_axis, + beachball->t_axis, + &isoPct, &devPct, &dcPct, &clvdPct); +/* + // copy the input moment tensor + mt[0][0] = m11; + mt[1][1] = m22; + mt[2][2] = m33; + mt[0][1] = mt[1][0] = m12; + mt[0][2] = mt[2][0] = m13; + mt[1][2] = mt[2][1] = m23; + ierr = cmopad_basis_transformMatrixM33(mt, basis, NED); + if (ierr != 0) + { + printf("Error transforming matrix\n"); + return -1; + } + // decompose the moment tensor + ierr = cmopad_standardDecomposition(mt, &cmt); + if (ierr != 0) + { + printf("Failed initializing moment tensor from strike, dip, rake\n"); + return -1; + } + // get the principal tension, null, and plunge axes + ierr = cmopad_MT2PrincipalAxisSystem(0, &cmt); + if (ierr != 0) + { + printf("Error computing principal axes\n"); + return -1; + } + if (lexplosion || limplosion) + { + cmt.p_axis[2] = cmt.eigenvalues[0]; + cmt.null_axis[2] = cmt.eigenvalues[1]; + cmt_axis[2] = cmt.eigenvalues[2]; + } + else + { + // Convert pressure, null, and tension principal axes to + // azimuth, plunge, and length + ierr += cmopad_Eigenvector2PrincipalAxis(NED, cmt.eig_pnt[0], + cmt.p_axis, cmt.p_axis); + ierr += cmopad_Eigenvector2PrincipalAxis(NED, cmt.eig_pnt[1], + cmt.null_axis, cmt.null_axis); + ierr += cmopad_Eigenvector2PrincipalAxis(NED, cmt.eig_pnt[2], + cmt.t_axis, cmt.t_axis); + if (ierr != 0) + { + printf("Error converting eigenvector to principal axis!\n"); + return -1; + } + } + memcpy(&beachball->cmt, &cmt, sizeof(struct cmopad_struct)); +*/ + beachball->lhaveMT = true; + return 0; +} + +int beachball_writePNG(const char *fileName, + size_t height, size_t width, unsigned char *bytes) +{ + FILE *file = NULL; + png_structp png = NULL; + png_infop info = NULL; + png_bytepp rows = NULL; + int h; + + file = fopen(fileName, "wb"); + if (file == NULL){printf("failed to open file\n");} + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png == NULL){printf("error making png struct\n");} + info = png_create_info_struct(png); + if (info == NULL){printf("error making png info struct\n");} + png_init_io(png, file); + png_set_IHDR(png, info, width, height, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png, info); + rows = calloc(height, sizeof(png_bytep)); + for (h=0; h<(int) height; h++) + { + rows[h] = bytes + (PIXMAP_COLORS*h*(int) width); + } + png_write_rows(png, rows, height); + png_write_end(png, NULL); //info); + png_destroy_write_struct(&png, &info); + if (rows != NULL){free(rows);} + fclose(file); + return 0; +} + +int beachball_draw(const char *fileName, + struct beachballPlot_struct beachball) +{ + const char *fcnm = "beachball_draw\0"; + struct beachBall_struct beachImage; + unsigned char *image; + double baz, bdp, bev, paz, pdp, pev, taz, tdp, tev, x, xnorm, y; + int i, i1, i2, indx, ix, iy, jy, k; + size_t npixel; + taz = beachball.t_axis[0]; + tdp = beachball.t_axis[1]; + tev = beachball.t_axis[2]; + baz = beachball.null_axis[0]; + bdp = beachball.null_axis[1]; + bev = beachball.null_axis[2]; + paz = beachball.p_axis[0]; + pdp = beachball.p_axis[1]; + pev = beachball.p_axis[2]; + // normalize the moment tensor for my sanity + xnorm = MAX(fabs(tev), MAX(fabs(bev), fabs(pev))); + if (xnorm == 0.0) + { + printf("%s: Error normalization is zero %f %f %f\n", fcnm, tev, bev, pev); + return -1; + } + // compute everything describing the beachball + memset(&beachImage, 0, sizeof(struct beachBall_struct)); + cliffsNodes_beachBallP(beachball.xc, beachball.yc, beachball.rad, + taz, tdp, tev, + baz, bdp, bev, + paz, pdp, pev, + beachball.nNodalLine, + beachball.nFocalSphere, + beachball.nxPixel, beachball.nyPixel, + true, true, true, + &beachImage); + // draw the image + npixel = (size_t) (beachball.nxPixel*beachball.nyPixel); + image = (unsigned char *) + calloc(PIXMAP_COLORS*npixel, sizeof(unsigned char)); + // Set a white background + for (indx=0; indx<3*beachball.nxPixel*beachball.nyPixel; indx++) + { + image[indx] = 255; + } + // Draw the polarity + if (beachball.lwantPolarity) + { + for (i=0; irad = 1.0; + beachball->xc = 1.5; + beachball->yc = 1.5; + beachball->nxPixel = 251; + beachball->nyPixel = 251; + beachball->nNodalLine = 3*beachball->nxPixel; + beachball->nFocalSphere = 4*beachball->nxPixel; + beachball->lwantPolarity = true; + beachball->lwantNodalLines = true; + beachball->lhaveMT = false; + return 0; +} + +static double transform(const double a, const double b, + const double c, const double d, + const double x) +{ + double det, c1, c2, xi; + det = 1.0/(b - a); + c1 = det*(b*c - a*d); + c2 = det*(-c + d); + xi = c1 + x*c2; + return xi; +} +//============================================================================// +int cliffsNodes_plotStations(const double xc, const double yc, const double rad, + const int nstat, + const double *__restrict__ az, + const double *__restrict__ toa, + double *__restrict__ xp, + double *__restrict__ yp); + +/*! + * @brief Computes the station locations for the given azimuth + * and take-off angle on a focal sphere with radius rad + * centered at (xc, yc). This is based on Cliff Frohlich's + * stnPlt but now processes multiple stations and does no plotting. + * + * @param[in] xc x center of focal sphere + * @param[in] yc y center of focal sphere + * @param[in] rad radius of sphere + * @param[in] nstat number of stations + * @param[in] az source station azimuths (degrees) [nstat] + * @param[in] toa take off angle (degrees) from source to stations [nstat] + * + * @param[out] xp station's x location on focal sphere [nstat] + * @param[out] yp station's y location on focal sphere [nstat] + * + * @author Ben Baker + * + * @copyright BSD + * + */ +int cliffsNodes_plotStations(const double xc, const double yc, const double rad, + const int nstat, + const double *__restrict__ az, + const double *__restrict__ toa, + double *__restrict__ xp, + double *__restrict__ yp) +{ + const char *fcnm = "cliffsNodes_plotStations\0"; + double azrad, rp, sign, toaN; + int i; + const double sqrt2 = 1.4142135623730951; + const double degrad = M_PI/180.0; + //------------------------------------------------------------------------// + // + // error handling + if (nstat < 1 || az == NULL || toa == NULL || xp == NULL || yp == NULL) + { + if (nstat < 1){printf("%s: No stations\n", fcnm);} + if (az == NULL){printf("%s: az is NULL\n", fcnm);} + if (toa == NULL){printf("%s: toa is NULL\n", fcnm);} + if (xp == NULL){printf("%s: xp is NULL\n", fcnm);} + if (yp == NULL){printf("%s: yp is NULL\n", fcnm);} + return -1; + } + // compute point on focal shere for each station + for (i=0; i 90.) + { + toaN = 180. - toa[i]; + sign =-1.; + } + rp = sign*rad*sqrt2*sin(0.5*degrad*toaN); + azrad = az[i]*degrad; + xp[i] = xc + rp*sin(azrad); + yp[i] = yc + rp*cos(azrad); + } + return 0; +} +//============================================================================// +/*! + * @brief Given the azimuth and dip of the tension and pressure eigenvectors + * in geographic coordinates along with normalized eigenvalues + * this computes the moment tensort in geographic coordinates as + * well as the rotation and transpose rotation matrices which rotate + * from a system where t=1-axis and p=2-axis. This is based on + * Cliff Frohlich's mtensor. + * + * @param[in] taz tension axis azimuth (degrees) + * @param[in] tdp tension axis dip (degrees) + * @param[in] paz pressure axis azimuth (degrees) + * @param[in] pdp pressure axis dip + * @param[in] tev1 normalized eigenvalue for tension eigenvector + * @param[in] bev1 normalized eigenvalue for null eigenvector + * @param[in] pev1 normalized eigenvalue for pressure eigenvector + * + * @param[out] mt [3 x 3] moment tensor (column major) + * @param[out] rm [3 x 3] rotation matrix as described above (column major) + * @param[out] rmt [3 x 3] transpose rotation matrix described above + * (column major) + * @author Ben Baker + * + * @copyright BSD + * + */ +void cliffsNodes_mtensor(const double taz, const double tdp, + const double paz, const double pdp, + const double tev1, const double bev1, + const double pev1, + double *__restrict__ mt, + double *__restrict__ rm, + double *__restrict__ rmt, + double *ampMax) +{ + double mpt[9], sm1[9], smt1[9], sm2[9], smt2[9], sm3[9], + smt3[9], work[9], p[3], pnew[3], pxt[3], t[3], pang; + const double degrad = M_PI/180.0; + // set up moment tensor in t-p system + memset(mpt, 0, 9*sizeof(double)); + mpt[0] = tev1; + mpt[4] = pev1; + mpt[8] = bev1; + // condition p-axis so that it really is perpendicular to t-axis + vecstrd(taz, tdp, t); + vecstrd(paz, pdp, p); + crossp(p, t, pxt); + crossp(t, pxt, p); + // Step 1: rotate 1-axis about 3-axis so that 1-axis lies along t azimuth + rotmat(3, taz-90., sm1, smt1); + // Step 2: rotate 1-axis about 2-axis so that 1-axis liesalong t + rotmat(2, tdp, sm2, smt2); + cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, + 1.0, sm2, 3, sm1, 3, 0.0, sm3, 3); + cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, + 1.0, smt1, 3, smt2, 3, 0.0, smt3, 3); + // in this system, p should lie in 2-3 plane + cblas_dgemv(CblasColMajor, CblasNoTrans, 3, 3, + 1.0, sm3, 3, p, 1, 0.0, pnew, 1); + // Step 3: rotate about 1 axis so that 2 axis lies along p + pang = atan2(pnew[2], pnew[1])/degrad; //(3.14159/180.) + rotmat(1, -pang, sm1, smt1); + cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, + 1.0, sm1, 3, sm3, 3, 0.0, rm, 3); + cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, + 1.0, smt3, 3, smt1, 3, 0.0, rmt, 3); + // Finally: find moment tensor in space coordinates. + // This is because Mpt=RM*Mspace*RMT, thus Mspace=RMT*Mpt*RM + cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, + 1.0, rmt, 3, mpt, 3, 0.0, work, 3); + cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 3, 3, 3, + 1.0, work, 3, rm, 3, 0.0, mt, 3); + // ampMax is the absolute maximum amplitude + *ampMax = MAX(fabs(pev1), MAX(fabs(tev1), fabs(bev1))); + return; +} +//============================================================================// +/*! + * @brief Computes the lower-hemisphere projection `beachball' diagram for a + * focal mechanism. This is based on Cliff Frohlich's bballP and + * has been translated to C and does no plotting. + * + * @param[in] xc plot coordinates (e.g. pixels) of center of + * beachball + * @param[in] yc plot coordinates (e.g. pixels) of center of + * beachball + * @param[in] rad beachball radius (e.g. pixels) + * @param[in] taz1 azimuth (degrees) of tension eigenvector + * @param[in] tdp1 dip (degrees) of tension eigenvector + * @param[in] tevI eigenvalue corresponding to tension eigenvector + * (e.g. Newton meters) + * @param[in] baz1 azimuth (degrees) of null eigenvector + * @param[in] bdp1 dip (degrees) of null eigenvector + * @param[in] bevI eigenvalue corresponding to null eigenvector + * (e.g. Newton meters) + * @param[in] paz1 azimuth (degrees) of pressure eigenvector + * @param[in] pdp1 dip (degrees) of pressure eigenvector + * @param[in] pevI eigenvalue corresponding to pressure eigenvector + * (e.g. Newton meters) + * @param[in] nNodalLine number of points to draw in nodal line. + * @param[in] nFocalSphere number of points to draw in focal sphere. + * @param[in] nxPixel number of pixels in x when drawing polarity + * @param[in] nyPixel number of pixels in y when drawing polairty + * @param[in] lwantNodalLines if true then compute the nodal lines. + * @param[in] lwantPTBAxes if true then compute the PTB axis points. + * @param[in] lwantPolarity if true then compute the polarity. + * + * @param[out] beachBall container for the pressure, tension and null axes, + * the nodal lines, and the polarity + * + * @author Ben Baker + * + * @copyright BSD + * + * @bug this routine fails if rad is not = 1. + * + */ +void cliffsNodes_beachBallP(const double xc, const double yc, const double rad, + const double taz1, const double tdp1, + const double tevI, + const double baz1, const double bdp1, + const double bevI, + const double paz1, const double pdp1, + const double pevI, + const int nNodalLine, + const int nFocalSphere, + const int nxPixel, const int nyPixel, + const bool lwantNodalLines, + const bool lwantPTBAxes, + const bool lwantPolarity, + struct beachBall_struct *beachBall) +{ + double *xw1, *xw2, *yw1, *yw2; + double rm[9] __attribute__ ((aligned(64))); + double rmt[9] __attribute__ ((aligned(64))); + double tm[9] __attribute__ ((aligned(64))); + double pt[3] __attribute__ ((aligned(64))); + double ptnew[3] __attribute__ ((aligned(64))); + double ax1[3] __attribute__ ((aligned(64))); + double ax2[3] __attribute__ ((aligned(64))); + double ax3[3] __attribute__ ((aligned(64))); + double ptLine1[3] __attribute__ ((aligned(64))); + double ptLine2[3] __attribute__ ((aligned(64))); + double ptLine1Old[3] __attribute__ ((aligned(64))); + double ptLine2Old[3] __attribute__ ((aligned(64))); + double ampMax, az, baz, bdp, bev, cosPsi, cosTheta, + dip, dp, dpsi, dx, dy, evI, fclvd, fIso, howClose, rad2, + rb, rp, rpt, rpt2, rt, paz, pdp, pev, plusMin, psi, + sinsq, sinPsi, sinTheta, str, + taz, tdp, tev, theta, x, x0, xpt, y, y0, ypt; + int *pn1, *pn2, ix, ixy, iy, k, nlines, nnl1, nnl2, npts, nseg, + nx, ny, penDown, psave1, psave2; + size_t nwork; + const double sqrt2 = 1.4142135623730951; + const double sqrt2i = 1.0/sqrt2; + const double degrad = M_PI/180.0; + const double degradi = 180.0/M_PI; + const double third = 1.0/3.0; + const double tol = 0.95; + // null out result + memset(beachBall, 0, sizeof(struct beachBall_struct)); + // Avoid overwriting memory + taz = taz1; + tdp = tdp1; + baz = baz1; + bdp = bdp1; + paz = paz1; + pdp = pdp1; + // Step 1: set up axes: + // - D axis ('dominant' 1-axis - with largest absolute eigenvalue) + // - M axis ('minor' 3-axis) + // - B axis ( 2-axis) + evI = (tevI + bevI + pevI)*third; + tev = tevI - evI; + bev = bevI - evI; + pev = pevI - evI; + vecstrd(paz, pdp, ax1); + vecstrd(taz, tdp, ax3); + fclvd = fabs(bev/pev); + fIso = evI/pev; + if (fabs(tev) > fabs(pev)) + { + vecstrd(taz, tdp, ax1); + vecstrd(paz, pdp, ax3); + fclvd = fabs(bev/tev); + fIso = evI/tev; + } + //if (fabs(evI) > .03) + //{ + // write(6,901) evI + //} + crossp(ax1, ax3, ax2); + strdvec(ax2, &baz, &bdp); + cliffsNodes_mtensor(taz, tdp, paz, pdp, tevI, bevI, pevI, + tm, rm, rmt, &Max); + // Step 2: Now: plot upper half nodal line: + // point on nodal line is represented by vector pt; + // pt is defined by two angles + // - psi is azimuth with respect to 3-axis (M-axis) + // in 2-3 plane (in B-M plane) + // - theta is angle with respect to 1 axis. + // It can be shown (i. e., cliff did it once) that: + // sin(theta)**2=(2+2*fIso)/(3+(1-2*f)*cos(2*psi)) + // Additionally, a constraint corresponding to Cliff's Rule 1 + // for existance of P nodal planes is applied + //psi = 0.; + //dpsi = 2.; + //npts = nNodalLine1; //1 + (int)(360.0/dpsi + 0.5); //nint((360./dpsi)) + //dpsi = dpsi*degrad; + psave1 =-1; + psave2 =-1; + memset(ptLine1Old, 0, 3*sizeof(double)); + memset(ptLine2Old, 0, 3*sizeof(double)); + if (lwantNodalLines && nNodalLine > 1 && + !(tevI > 0.0 && bevI > 0.0 && pevI > 0.0) && + !(tevI < 0.0 && bevI < 0.0 && pevI < 0.0)) + { + npts = nNodalLine; + psi = 0.0; + dpsi = 360.0/(double) (nNodalLine - 1); + dpsi = dpsi*degrad; + xw1 = (double *) calloc((size_t) npts, sizeof(double)); + yw1 = (double *) calloc((size_t) npts, sizeof(double)); + pn1 = (int *) calloc((size_t) npts+1, sizeof(int)); + xw2 = (double *) calloc((size_t) npts, sizeof(double)); + yw2 = (double *) calloc((size_t) npts, sizeof(double)); + pn2 = (int *) calloc((size_t) npts+1, sizeof(int)); + nnl1 = 0; + nnl2 = 0; + for (k=0; k 0 && sinsq <= 1.0) + { + theta = asin(sqrt(sinsq)); + cosTheta = cos(theta); + sinTheta = sin(theta); + cosPsi = cos(psi); + sinPsi = sin(psi); + // upper half nodal line + ptLine1[0] = cosTheta*ax1[0] + + sinTheta*(sinPsi*ax2[0] + cosPsi*ax3[0]); + ptLine1[1] = cosTheta*ax1[1] + + sinTheta*(sinPsi*ax2[1] + cosPsi*ax3[1]); + ptLine1[2] = cosTheta*ax1[2] + + sinTheta*(sinPsi*ax2[2] + cosPsi*ax3[2]); + // lower half nodal line + ptLine2[0] =-cosTheta*ax1[0] + - sinTheta*(sinPsi*ax2[0] + cosPsi*ax3[0]); + ptLine2[1] =-cosTheta*ax1[1] + - sinTheta*(sinPsi*ax2[1] + cosPsi*ax3[1]); + ptLine2[2] =-cosTheta*ax1[2] + - sinTheta*(sinPsi*ax2[2] + cosPsi*ax3[2]); + isItNear(ptLine1, &howClose, ptLine1Old); + // upper half nodal line + penDown =-1; + if (ptLine1[2] < 0.0){penDown = 1;} + if (howClose < tol){penDown =-1;} + strdv(ptLine1, &str, &dip); + rpt = rad*sqrt2*sin(0.5*degrad*(90.-dip)); + xpt = xc + rpt*sin(str*degrad); + ypt = yc + rpt*cos(str*degrad); + xw1[k] = xpt; + yw1[k] = ypt; + if (k == 0){pn1[k] = 3;} + if (penDown == 1 && psave1 == 1) + { + pn1[k] = 2; + //printf("%f %f\n", xpt, ypt); + } + if (penDown ==-1){pn1[k] = 3;} + nnl1 = nnl1 + 1; + psave1 = penDown; + // lower half nodal line + penDown =-1; + if (ptLine2[2] < 0.0){penDown = 1;} + if (howClose < tol){penDown =-1;} + strdv(ptLine2, &str, &dip); + rpt = rad*sqrt2*sin(0.5*degrad*(90.-dip)); + xpt = xc + rpt*sin(str*degrad); + ypt = yc + rpt*cos(str*degrad); + xw2[k] = xpt; + yw2[k] = ypt; + if (k == 0){pn2[k] = 3;} // pen down + if (penDown == 1 && psave2 == 1) + { + pn2[k] = 2; + //xptsLine2[k] = xpt; + //yptsLine2[k] = ypt; + //penLine2[k] = penDwn; + } + if (penDown ==-1){pn2[k] = 3;} + nnl2 = nnl2 + 1; + psave2 = penDown; + } + } // loop on points + nwork = (size_t) (MAX(2, 2*nnl1)); + beachBall->xNodalLine1 = (double *) calloc(nwork, sizeof(double)); + beachBall->yNodalLine1 = (double *) calloc(nwork, sizeof(double)); + nwork = (size_t) (nnl1 + 1); + beachBall->nodalLine1Ptr = (int *) calloc(nwork, sizeof(int)); + nwork = (size_t) (MAX(2, 2*nnl2)); + beachBall->xNodalLine2 = (double *) calloc(nwork, sizeof(double)); + beachBall->yNodalLine2 = (double *) calloc(nwork, sizeof(double)); + nwork = (size_t) (nnl2 + 1); + beachBall->nodalLine2Ptr = (int *) calloc(nwork, sizeof(int)); + // make sure the lines end + pn1[nnl1] = 3; + pn2[nnl2] = 3; + // compute the nodal line 1 line segments + nlines = 0; + nseg = 0; + for (k=0; kxNodalLine1[2*nlines ] = xw1[k]; + beachBall->xNodalLine1[2*nlines+1] = xw1[k+1]; + beachBall->yNodalLine1[2*nlines ] = yw1[k]; + beachBall->yNodalLine1[2*nlines+1] = yw1[k+1]; + nlines = nlines + 1; + } + // line continues + if (pn1[k] == 2 && pn1[k+1] == 2) + { + beachBall->xNodalLine1[2*nlines ] = xw1[k]; + beachBall->xNodalLine1[2*nlines+1] = xw1[k+1]; + beachBall->yNodalLine1[2*nlines ] = yw1[k]; + beachBall->yNodalLine1[2*nlines+1] = yw1[k+1]; + nlines = nlines + 1; + } + // line ends + if (pn1[k] == 2 && pn1[k+1] == 3) + { +/* + beachBall->xNodalLine1[2*nlines ] = xw1[k]; + beachBall->xNodalLine1[2*nlines+1] = xw1[k+1]; + beachBall->yNodalLine1[2*nlines ] = yw1[k]; + beachBall->yNodalLine1[2*nlines+1] = yw1[k+1]; + nlines = nlines + 1; +*/ + nseg = nseg + 1; + beachBall->nodalLine1Ptr[nseg] = nlines; + } + } + beachBall->nNodalLineSegs1 = nseg; + // compute the nodal line 2 line segments + nlines = 0; + nseg = 0; + for (k=0; kxNodalLine2[2*nlines ] = xw2[k]; + beachBall->xNodalLine2[2*nlines+1] = xw2[k+1]; + beachBall->yNodalLine2[2*nlines ] = yw2[k]; + beachBall->yNodalLine2[2*nlines+1] = yw2[k+1]; + nlines = nlines + 1; + } + // line continues + if (pn2[k] == 2 && pn2[k+1] == 2) + { + beachBall->xNodalLine2[2*nlines ] = xw2[k]; + beachBall->xNodalLine2[2*nlines+1] = xw2[k+1]; + beachBall->yNodalLine2[2*nlines ] = yw2[k]; + beachBall->yNodalLine2[2*nlines+1] = yw2[k+1]; + nlines = nlines + 1; + } + // line ends + if (pn2[k] == 2 && pn2[k+1] == 3) + { + beachBall->xNodalLine2[2*nlines ] = xw2[k]; + beachBall->xNodalLine2[2*nlines+1] = xw2[k+1]; + beachBall->yNodalLine2[2*nlines ] = yw2[k]; + beachBall->yNodalLine2[2*nlines+1] = yw2[k+1]; + nlines = nlines + 1; + nseg = nseg + 1; + beachBall->nodalLine2Ptr[nseg] = nlines; + } + } + beachBall->nNodalLineSegs2 = nseg; +//printf("%d %d\n", nlines, nseg); + free(pn1); + free(pn2); + free(xw1); + free(xw2); + free(yw1); + free(yw2); + } + // Step 4: Plot the, P, T, and B axes + if (lwantPTBAxes) + { + rp = rad*sqrt2*sin(0.5*degrad*(90.-pdp)); + rt = rad*sqrt2*sin(0.5*degrad*(90.-tdp)); + rb = rad*sqrt2*sin(0.5*degrad*(90.-bdp)); + beachBall->xp = xc + rp*sin(paz*degrad); + beachBall->yp = yc + rp*cos(paz*degrad); + beachBall->xt = xc + rt*sin(taz*degrad); + beachBall->yt = yc + rt*cos(taz*degrad); + beachBall->xb = xc + rb*sin(baz*degrad); + beachBall->yb = yc + rb*cos(baz*degrad); + } + // Step 5: Plot the focal sphere + if (nFocalSphere > 1) + { + beachBall->nFocalSphere = nFocalSphere; + beachBall->xFocalSphere = (double *) + calloc((size_t) nFocalSphere, sizeof(double)); + beachBall->yFocalSphere = (double *) + calloc((size_t) nFocalSphere, sizeof(double)); + dpsi = 2.0*M_PI/(double) (nFocalSphere - 1); +#ifdef _OPENMP + #pragma omp simd +#endif + for (k=0; kxFocalSphere[k] = xc + rad*sin(psi); + beachBall->yFocalSphere[k] = yc + rad*cos(psi); + } + } + // Step 6: Plot the + and - + if (lwantPolarity && nxPixel > 0 && nyPixel > 0) + { + // begin in lower left corner + nx = nxPixel; + ny = nyPixel; + dx = 2.0*rad/(double) (nx - 1); + dy = 2.0*rad/(double) (ny - 1); + x0 = xc - rad; + y0 = yc - rad; + rad2 = rad*rad; // saves a sqrt computation when comparing distances + xw1 = (double *)calloc((size_t) (nx*ny), sizeof(double)); + yw1 = (double *)calloc((size_t) (nx*ny), sizeof(double)); + pn1 = (int *)calloc((size_t) (nx*ny), sizeof(int)); + nwork = 0; + // loop on pixel grid + for (iy=0; iy 100.0*DBL_EPSILON*ampMax){pn1[k] = 1;} + } // end check on location + } // loop on x + } // loop on y + // Copy the points to be plotted + if (nwork > 0) + { + beachBall->npolarity = (int) nwork; + beachBall->xPolarity = (double *) + calloc((size_t) nwork, sizeof(double)); + beachBall->yPolarity = (double *) + calloc((size_t) nwork, sizeof(double)); + beachBall->polarity = (int *) + calloc((size_t) nwork, sizeof(double)); + k = 0; + for (ixy=0; ixyxPolarity[k] = xw1[ixy]; + beachBall->yPolarity[k] = yw1[ixy]; + beachBall->polarity[k] = pn1[ixy]; + k = k + 1; + } + } + } + free(pn1); + free(xw1); + free(yw1); + } + return; +} + +void cliffsNodes_free(struct beachBall_struct *beachBall) +{ + if (beachBall->xNodalLine1 != NULL){free(beachBall->xNodalLine1);} + if (beachBall->yNodalLine1 != NULL){free(beachBall->yNodalLine1);} + if (beachBall->xNodalLine2 != NULL){free(beachBall->xNodalLine2);} + if (beachBall->yNodalLine2 != NULL){free(beachBall->yNodalLine2);} + if (beachBall->xFocalSphere != NULL){free(beachBall->xFocalSphere);} + if (beachBall->yFocalSphere != NULL){free(beachBall->yFocalSphere);} + if (beachBall->xPolarity != NULL){free(beachBall->xPolarity);} + if (beachBall->yPolarity != NULL){free(beachBall->yPolarity);} + if (beachBall->polarity != NULL){free(beachBall->polarity);} + if (beachBall->nodalLine1Ptr != NULL){free(beachBall->nodalLine1Ptr);} + if (beachBall->nodalLine2Ptr != NULL){free(beachBall->nodalLine2Ptr);} + memset(beachBall, 0, sizeof(struct beachBall_struct)); + return; +} +//============================================================================// +/*! + * @brief Finds simple rotation matrix R and transpose R^T for rotation + * of a vector by angle theta about x, y, or z. This is based on + * Cliff Rohlich's rotmat. + * + * @param[in] naxis rotation axis. if 1 then x. if 2 then y. if 3 then z. + * @param[in] theta rotation angle (degrees) + * @param[out] r rotation matrix [3 x 3] in column major format. + * @param[out] rt tranpsose rotation matrix [3 x 3] in column major format. + * + * @author Ben Baker + * + * @copyright BSD + * + */ +static void rotmat(const int naxis, const double theta, + double *__restrict__ r, + double *__restrict__ rt) +{ + double cosThetar, sinThetar, thetar; + int i, j; + const double degrad = M_PI/180.0; + memset(r, 0, 9*sizeof(double)); + thetar = theta*degrad; + cosThetar = cos(thetar); + sinThetar = sin(thetar); + r[0] = cosThetar; + r[4] = cosThetar; + r[8] = cosThetar; + // naxis = x + if (naxis == 1) + { + r[0] = 1.0; // (1, 1) + r[5] = sinThetar; // (3, 2) + r[7] =-sinThetar; // (2, 3) + } + // naxis = y + else if (naxis == 2) + { + r[2] = sinThetar; // (3, 1) + r[4] = 1.0; // (2, 2) + r[6] =-sinThetar; // (1, 3) + } + // naxis = z + else if (naxis == 3) + { + r[1] = sinThetar; // (2, 1) + r[3] =-sinThetar; // (1, 2) + r[8] = 1.0; // (3, 3) + } + // Compute the transpose + for (i=0; i<3; i++) + { + for (j=0; j<3; j++) + { + rt[3*i+j] = r[3*j+i]; + } + } + return; +} +//============================================================================// +/*! + * @brief Find components of downward pointing unit vector pole from the + * strike and dip angles. This is based on Cliff Frolich's vecstrd. + * + * @param[in] str strike angle of pole (degrees) + * @param[in] dip dip angle of pole (degrees) + * + * @param[out] r corresponding unit vector pole (3) + * + * @author Ben Baker + * + * @copyright BSD + * + */ +static void vecstrd(const double str, const double dip, double r[3]) +{ + double cosdip, cosstr, diprad, sindip, sinstr, strrad; + const double degrad = M_PI/180.0; + // convert to radians + strrad = str*degrad; + diprad = dip*degrad; + // compute cosines and sines + sinstr = sin(strrad); + cosstr = cos(strrad); + cosdip = cos(diprad); + sindip = sin(diprad); + // compute (x,y,z) from strike and dip for unit radius + r[0] = sinstr*cosdip; + r[1] = cosstr*cosdip; + r[2] =-sindip; + return; +} +//============================================================================// +static void isItNear(const double *__restrict__ pt, + double *howClose, + double *__restrict__ ptold) +{ + *howClose = dot3(ptold, pt); //cblas_ddot(3, ptold, 1, pt, 1); + ptold[0] = pt[0]; + ptold[1] = pt[1]; + ptold[2] = pt[2]; + return; +} +/*! + * @brief Finds the strike and dip of downward pointing unit vector. This + * is based on Cliff Frolich's strdvec. + * + * @param[in,out] r on input contains the downward pointing unit + * vector. + * if r[2] is > 0 then the unit vector is pointing + * updward. in this case then on output r3 will + * be negated. + * + * @param[out] str strike angle (degrees) \f$ s.t. \phi \in [0,360] \f$. + * @param[out] dip dip angle (degrees) + * + * @author Ben Baker + * + * @copyright BSD + * + */ +static void strdvec(double r[3], double *str, double *dip) +{ + double rs; + const double degradi = 180.0/M_PI; + if (r[2] > 0.0) + { + r[0] =-r[0]; + r[1] =-r[1]; + r[2] =-r[2]; + } + *str = atan2(r[0], r[1])*degradi; + if (*str < 0.){*str = *str + 360.;} + rs = sqrt(r[0]*r[0] + r[1]*r[1]); + *dip=atan2(-r[2], rs)*degradi; + return; +} +/*! + * @brief Cross product of 2 length 3 vectors u and v. Returns normal vector n. + * + * @param[in] u first vector in cross product u x v [3] + * @param[in] v second vector in cross product u x v [3] + * + * @param[out] n normal vector n = u x v [3] + * + * @author Ben Baker + * + * @copyright BSD + * + */ +static void crossp(const double *__restrict__ u, + const double *__restrict__ v, + double *__restrict__ n) +{ + n[0] = u[1]*v[2] - u[2]*v[1]; + n[1] = u[2]*v[0] - u[0]*v[2]; + n[2] = u[0]*v[1] - u[1]*v[0]; + return; +} +/*! + * @brief Finds strike and dip given components of unit vector. This is + * based on Cliff Frohlich's strdv. + * + * @param[in] r unit vector + * @param[out] str strike angle (degrees) + * @param[out] dip dip angle (degrees) s.t. dip down is positive + * + * @author Ben Baker + * + * @copyright BSD + * + */ +static void strdv(const double r[3], double *str, double *dip) +{ + double rs; + const double degradi = 180.0/M_PI; + *str = atan2(r[0], r[1])*degradi; + rs = sqrt(r[0]*r[0] + r[1]*r[1]); + *dip = atan2(-r[2], rs)*degradi; + return; +} + +/*! + * @brief Utility function for computing dot product of length 3 vector + */ +static double dot3(const double *__restrict__ x, + const double *__restrict__ y) +{ + double dot; + dot = x[0]*y[0] + x[1]*y[1] + x[2]*y[2]; + return dot; +} + +/*! + * @brief Utility function for computing y = Ax for 3 x 3 matrix. + */ +static void gemv3(const double *__restrict__ A, const double *__restrict__ x, + double *__restrict__ y) +{ + y[0] = A[0]*x[0] + A[3]*x[1] + A[6]*x[2]; + y[1] = A[1]*x[0] + A[4]*x[1] + A[7]*x[2]; + y[2] = A[2]*x[0] + A[5]*x[1] + A[8]*x[2]; + return; +} diff --git a/src/uw/beachball.h b/src/uw/beachball.h new file mode 100644 index 00000000..114ab822 --- /dev/null +++ b/src/uw/beachball.h @@ -0,0 +1,101 @@ +#ifndef BEACHBALL_H_ +#define BEACHBALL_H_ 1 +#include +#include "compearth.h" + +struct beachBall_struct +{ + double *xNodalLine1; /*!< x points comprising nodal line 1 */ + double *yNodalLine1; /*!< y points comprising nodal line 1 */ + double *xNodalLine2; /*!< x points comprising nodal line 2 */ + double *yNodalLine2; /*!< y points comprising nodal line 2 */ + double *xFocalSphere; /*!< x locations defining focal sphere */ + double *yFocalSphere; /*!< y locations defining focal sphere */ + double *xPolarity; /*!< x locations where polarities are computed */ + double *yPolarity; /*!< y locations where polarities are computed */ + int *polarity; /*!< if 1 then the polarity is up. if -1 then the + polarity is down */ + int *nodalLine1Ptr; /*!< Points to start and end of line segments + making up first nodal line [nNodalLine1+1] */ + int *nodalLine2Ptr; /*!< Points to start and end of line segments + making up second nodal line [nNodalLine2+1] */ + double xp; /*!< x location of pressure dot */ + double yp; /*!< y location of pressure dot */ + double xb; /*!< x location of null dot */ + double yb; /*!< y location of null dot */ + double xt; /*!< x location of tension dot */ + double yt; /*!< y location of tension dot */ + int nNodalLineSegs1; /*!< Number of nodal lines segments comprising + nodal line */ + int nNodalLineSegs2; /*!< Number of nodal line segents comprising second + nodal line */ + int nFocalSphere; /*!< Number of points in focal sphere. if 0 then + the focal sphere is not defined */ + int npolarity; /*!< Number of polarity points */ + bool lhavePTBAxes; /*!< If true then the PTB axes are defined */ + char pad[7]; +}; + +struct beachballPlot_struct +{ + double t_axis[3], null_axis[3], p_axis[3]; + double rad; + double xc; + double yc; + int nxPixel; + int nyPixel; + int nNodalLine; + int nFocalSphere; + bool lwantPolarity; + bool lwantNodalLines; + bool lhaveMT; + char pad[7]; +}; + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +int beachball_writePNG(const char *fileName, + size_t height, size_t width, unsigned char *pixels); +int beachball_draw(const char *fileName, + struct beachballPlot_struct beachball); +int beachball_plotDefaults(struct beachballPlot_struct *beachball); +int beachball_setMomentTensor(const double m11, const double m22, + const double m33, const double m12, + const double m13, const double m23, + enum compearthCoordSystem_enum basis, + struct beachballPlot_struct *beachball); + +void cliffsNodes_mtensor(const double taz, const double tdp, + const double paz, const double pdp, + const double tev1, const double bev1, + const double pev1, + double *__restrict__ mt, + double *__restrict__ rm, + double *__restrict__ rmt, + double *ampMax); +void cliffsNodes_beachBallP(const double xc, const double yc, const double rad, + const double taz1, const double tdp1, + const double tevI, + const double baz1, const double bdp1, + const double bevI, + const double paz1, const double pdp1, + const double pevI, + const int nNodalLine, + const int nFocalSphere, + const int nxPixel, const int nyPixel, + const bool lwantNodalLines, + const bool lwantPTBAxes, + const bool lwantPolarity, + struct beachBall_struct *beachBall); +void cliffsNodes_free(struct beachBall_struct *beachBall); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/uw/gfast2web.c b/src/uw/gfast2web.c new file mode 100644 index 00000000..faa7666a --- /dev/null +++ b/src/uw/gfast2web.c @@ -0,0 +1,485 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "gfast.h" +#include "gfast_activeMQ.h" +#include "beachball.h" +#include "compearth.h" +//#include "gfast2json.h" +#include "iscl/array/array.h" +#include "iscl/iscl/iscl.h" +#include "iscl/memory/memory.h" +#include "iscl/os/os.h" +#include "iscl/time/time.h" + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +#endif + +#define HYPO_STRUCT "/DataStructures/hypocenterStructure" +#define PGD_STRUCT "/DataStructures/pgdResultsStructure" +#define CMT_STRUCT "/DataStructures/cmtResultsStructure" +#define FF_STRUCT "/DataStructures/finiteFaultResultsStructure" +#define TRIGGER_HYPO "triggeringHypocenter" +#define CMT_RES "cmtResults" +#define FF_RES "finiteFaultResults" +#define PGD_RES "pgdResults" + +//int getEventIndex(const char *evid, const struct eventList_struct events); + +static void getCMTopt(const struct GFAST_cmtResults_struct cmt, + int *iopt, int *depOpt, int *latOpt, int *lonOpt); + +const char *fcnm = "gfast2web\0"; + +void usage(void) +{ + printf("Usage:\n"); + printf(" %s --filename
\n", fcnm); + printf(" -i // Default = last interval\n"); + printf(" -a //Output all intervals\n"); + exit (8); +} + +int main(int argc, char *argv[]) +{ + struct GFAST_shakeAlert_struct SA; + //struct eventList_struct events; + char message[PATH_MAX]; + char evid[128]="1111"; + char archiveFile[PATH_MAX]; + + double lastPublished, t0; + int ierr, iev, i, j, k; + bool lhaveEvent, leventExists; + hid_t h5fl; + char *cm; + struct beachballPlot_struct beachball; + + char cmtFile[PATH_MAX]; + int bogusID; + void *consumer; + void *webProduct; + iscl_init(); + int output_interval; + bool output_all = false; + char temp[64]; + + int indx0; + double u0, n0, e0, peakDisplacement_i; + + if (argc < 3){ + usage(); + } + + //while ((argc > 1) && (argv[argc][0] == '-')) + for (i=0; i 0){ + printf("Extract Interval:%d\n", output_interval); + igroup = output_interval; + } + else { + printf("Default: Get Last Interval:%d\n", kgroup); + igroup = kgroup; + } + + memset(groupName, 0, 512*sizeof(char)); + sprintf(groupName, "/GFAST_History/Iteration_%d", igroup); + groupID = H5Gopen2(h5fl, groupName, H5P_DEFAULT); + + hid_t attr; + double epoch; + attr=H5Aopen(groupID, "epoch", H5P_DEFAULT); + H5Aread(attr, H5T_IEEE_F64LE, &epoch); + H5Aclose(attr); + + // hypocenter + memset(&h5hypo, 0, sizeof(struct h5_hypocenter_struct)); + memset(&hypo, 0, sizeof(struct GFAST_shakeAlert_struct)); + dataType = H5Topen(h5fl, HYPO_STRUCT, H5P_DEFAULT); + dataSet = H5Dopen(groupID, TRIGGER_HYPO, H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + memSpace = H5Screate_simple(1, dims, NULL); + H5Dread(dataSet, dataType, memSpace, dataSpace, H5P_DEFAULT, &h5hypo); + hdf5_copyHypocenter(COPY_H5_TO_DATA, &hypo, &h5hypo); + + double age; + age = epoch - hypo.time; + printf("igroup:%d epoch:%.2f age:%.2f eventid:%s lat:%.2f lon:%.2f dep:%.2f mag:%.2f otime:%.2f\n", + igroup, epoch, age, hypo.eventid, hypo.lat, hypo.lon, hypo.dep, hypo.mag, hypo.time); + + H5Sclose(memSpace); + H5Sclose(dataSpace); + H5Dclose(dataSet); + H5Tclose(dataType); + + + // pgdResults + if (H5Lexists(groupID, PGD_STRUCT, H5P_DEFAULT) > 0) { + memset(&h5pgd, 0, sizeof(struct h5_pgdResults_struct)); + memset(&pgd, 0, sizeof(struct GFAST_pgdResults_struct)); + dataType = H5Topen(h5fl, PGD_STRUCT, H5P_DEFAULT); + dataSet = H5Dopen(groupID, PGD_RES, H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + memSpace = H5Screate_simple(1, dims, NULL); + H5Dread(dataSet, dataType, memSpace, dataSpace, H5P_DEFAULT, &h5pgd); + hdf5_copyPGDResults(COPY_H5_TO_DATA, &pgd, &h5pgd); + + //printf("MTH: pgdResults.nsites:%d ndeps:%d\n", pgd.nsites, pgd.ndeps); + int imin = -9; + float vrmin = 0; + for (i=0; i vrmin) { + imin = i; + vrmin = pgd.mpgd_vr[i]; + } + //printf("mpgd[%d]:%.2f vr:%f\n", i, pgd.mpgd[i], pgd.mpgd_vr[i]); + } + printf("PGD_Mw:%.2f vr:%.2f imin_dep:%d ndeps:%d\n", pgd.mpgd[imin], pgd.mpgd_vr[imin], imin, pgd.ndeps); + //cpgd = gfast2json_packPGD(evid, gpsData, pgd); + hdf5_memory_freePGDResults(&h5pgd); + H5Sclose(memSpace); + H5Sclose(dataSpace); + H5Dclose(dataSet); + H5Tclose(dataType); + } + + + // cmt + if (H5Lexists(groupID, CMT_RES, H5P_DEFAULT) < 1) + { + LOG_WARNMSG("%s", "cmt not yet computed"); + } + else { + memset(&h5cmt, 0, sizeof(struct h5_cmtResults_struct)); + memset(&cmt, 0, sizeof(struct GFAST_cmtResults_struct)); + dataType = H5Topen(h5fl, CMT_STRUCT, H5P_DEFAULT); + dataSet = H5Dopen(groupID, CMT_RES, H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + memSpace = H5Screate_simple(1, dims, NULL); + H5Dread(dataSet, dataType, memSpace, dataSpace, H5P_DEFAULT, &h5cmt); + hdf5_copyCMTResults(COPY_H5_TO_DATA, &cmt, &h5cmt); + + iopt = array_argmin64f(cmt.nlats*cmt.nlons*cmt.ndeps, cmt.objfn, &ierr); + idep =-1; + getCMTopt(cmt, &iopt, &idep, &latOpt, &lonOpt); + printf("Mw:%.2f plane1: (%.1f, %.1f, %.1f) plane2: (%.1f, %.1f, %.1f) nsites:%d\n", + cmt.Mw[iopt], cmt.str1[iopt], cmt.dip1[iopt], cmt.rak1[iopt], + cmt.str2[iopt], cmt.dip2[iopt], cmt.rak2[iopt], cmt.nsites); + } + + + // gps data + if (H5Lexists(groupID, "gpsData\0", H5P_DEFAULT) < 1) + { + LOG_WARNMSG("%s", "gpsData does not exists"); + } + memset(&wdata, 0, sizeof(struct GFAST_waveform3CData_struct)); + memset(&gpsData, 0, sizeof(struct GFAST_data_struct)); + memset(&h5gpsData, 0, sizeof(struct h5_gpsData_struct)); + dataType = H5Topen(h5fl, "/DataStructures/gpsDataStructure\0", H5P_DEFAULT); + dataSet = H5Dopen(groupID, "gpsData\0", H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + memSpace = H5Screate_simple(1, dims, NULL); + H5Dread(dataSet, dataType, memSpace, dataSpace, H5P_DEFAULT, &h5gpsData); + hdf5_copyGPSData(COPY_H5_TO_DATA, &gpsData, &h5gpsData); + + hdf5_memory_freeGPSData(&h5gpsData); + H5Sclose(memSpace); + H5Sclose(dataSpace); + H5Dclose(dataSet); + H5Tclose(dataType); + + + // peakDisplacementData + int npgd_used = 0; + if (H5Lexists(groupID, "pgdData", H5P_DEFAULT) > 0) + { + dataType = H5Topen(h5fl, "/DataStructures/peakDisplacementDataStructure\0", H5P_DEFAULT); + dataSet = H5Dopen(groupID, "pgdData", H5P_DEFAULT); + dataSpace = H5Dget_space(dataSet); + memSpace = H5Screate_simple(1, dims, NULL); + H5Dread(dataSet, dataType, memSpace, dataSpace, H5P_DEFAULT, &h5pgd_data); + hdf5_copyPeakDisplacementData(COPY_H5_TO_DATA, &pgd_data, &h5pgd_data); + + //printf("pgd_data.nsites:%d\n", pgd_data.nsites); + + // Print out raw GPS data for PGD active sites + for (i=0; i +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +int xml_quakeML_writeDepth(const double depth, + const enum alert_units_enum depth_units, + const bool lhaveDepth, + const double depthUncer, + const enum alert_units_enum depthUncer_units, + const bool lhaveDepthUncer, + const double confidence, + const bool lhaveConfidence, + void *xml_writer) +{ + xmlTextWriterPtr writer; + char units[128]; + int rc; + //------------------------------------------------------------------------// + // + // nothing to do + if (!lhaveDepth && !lhaveDepthUncer && !lhaveConfidence){return 0;} + // get writer + rc = 0; + writer = (xmlTextWriterPtr) xml_writer; + // Begin + rc += xmlTextWriterStartElement(writer, BAD_CAST "depth\0"); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error starting element"); + return -1; + } + if (lhaveDepth) + { + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", depth); + __xml_units__enum2string(depth_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + if (lhaveDepthUncer) + { + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "uncertainty\0", + "%f", depthUncer); + __xml_units__enum2string(depthUncer_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + if (lhaveConfidence) + { + rc += xmlTextWriterWriteFormatElement(writer, + BAD_CAST "confidenceLevel\0", + "%f", confidence); + } + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing depth"); + return -1; + } + return 0; +} diff --git a/src/xml/quakeML/epoch2string.c b/src/xml/quakeML/epoch2string.c new file mode 100644 index 00000000..bcd3fcf0 --- /dev/null +++ b/src/xml/quakeML/epoch2string.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include "gfast_xml.h" +#include "gfast_core.h" +#include "iscl/iscl/iscl_enum.h" +#include "iscl/time/time.h" +/*! + * @brief Converts the epochal time (s) to YYYY-MM-DDThh:mm:ss.sssZ + * format. + * + * @param[in] epoch Epochal time (UTC seconds) to convert to string format. + * + * @param[out] cepoch Corresponding string formatted time. + * + * @result 0 indicates success. + * + * @author Ben Baker (ISTI) + * + */ +int xml_epoch2string(double epoch, char cepoch[128]) +{ + double sec; + int ierr, mday, month, nzhour, nzjday, nzmin, nzmusec, nzsec, nzyear; + memset(cepoch, 0, 128*sizeof(char)); + ierr = time_epoch2calendar(epoch, + &nzyear, &nzjday, &month, &mday, + &nzhour, &nzmin, &nzsec, &nzmusec); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error converting epochal time"); + return -1; + } + sec = (double) nzsec + (double) nzmusec*1.e-6; + sprintf(cepoch, + "%04d-%02d-%02dT%02d:%02d:%04.3fZ", + nzyear, month, mday, nzhour, nzmin, sec); + return 0; +} diff --git a/src/xml/quakeML/focalMechanism.c b/src/xml/quakeML/focalMechanism.c new file mode 100644 index 00000000..92f0ea2d --- /dev/null +++ b/src/xml/quakeML/focalMechanism.c @@ -0,0 +1,194 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "compearth.h" +#include "gfast_xml.h" +#include "gfast_core.h" +//#include "cmopad.h" + +/*! + * @brief Writes the focal mechanism and derived quantities such as the + * scalar moment, double couple and CLVD percentage, nodal planes, + * and principal axes to QuakeML. + * + * @param[in] publicIDroot QuakeML public ID root + * (e.g. quakeml:us.anss.org/). + * @param[in] evid Event ID. + * @param[in] method Method by which the focal mechanism was + * computed (for this project use gps). + * @param[in] mt Moment tensor in NED format with units of + * Newton-meters. The moment tensor is packed + * \f$ \{ m_{xx}, m_{yy}, m_{zz}, + * m_{xy}, m_{xz}, m_{yz} \} \f$. + * + * @param[in,out] xml_writer On input this is a pointer to the + * xmlTextWriterPtr. + * On successful output the focal mechanism has been + * appended to the xml_writer as a QuakeML + * focal mechanism. + * + * @result 0 indicates success. + * + * @author Ben Baker (ISTI) + * + */ +int xml_quakeML_writeFocalMechanism(const char *publicIDroot, + const char *evid, + const char *method, + const double mt[6], + void *xml_writer) +{ + xmlTextWriterPtr writer; + char publicID[512]; + //struct cmopad_struct src; + //double M_ned[3][3]; + double M_use[6], naxis[3], paxis[3], taxis[3], fp1[3], fp2[3]; + double clvdPct, dcPct, devPct, isoPct, M0, Mw; + int ierr, rc; + size_t lenos; + //------------------------------------------------------------------------// + // + // Initialize + rc = 0; + ierr = 0; + writer = (xmlTextWriterPtr ) xml_writer; + // Set the publicID + memset(publicID, 0, 512*sizeof(char)); + if (publicIDroot != NULL){strcat(publicID, publicIDroot);} + lenos = strlen(publicID); + if (lenos > 0) + { + if (publicID[lenos - 1] != '/'){strcat(publicID, "/\0");} + } + strcat(publicID, "focalmechanism/\0"); + if (evid != NULL) + { + strcat(publicID, evid); + strcat(publicID, "/\0"); + } + if (method != NULL){strcat(publicID, method);} + // Do the decomposition + ierr = compearth_standardDecomposition(1, mt, CE_NED, + &M0, &Mw, fp1, fp2, + paxis, naxis, taxis, + &isoPct, &devPct, &dcPct, &clvdPct); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error computing standard decomposition"); + return -1; + } +/* + // This is the moment tensor to be decomposed + M_ned[0][0] = mt[0]; // mxx + M_ned[1][1] = mt[1]; // myy + M_ned[2][2] = mt[2]; // mzz + M_ned[0][1] = M_ned[1][0] = mt[3]; // mxy + M_ned[0][2] = M_ned[2][0] = mt[4]; // mxz + M_ned[1][2] = M_ned[2][1] = mt[5]; // myz + // Do the decomposition + ierr = cmopad_standardDecomposition(M_ned, &src); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error computing standard decomposition"); + return -1; + } + ierr = cmopad_MT2PrincipalAxisSystem(0, &src); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error computing principal axes"); + return -1; + } + // Convert pressure, null, and tension principal axes to az, plunge, length + ierr += cmopad_Eigenvector2PrincipalAxis(NED, src.eig_pnt[0], + src.p_axis, paxis); + ierr += cmopad_Eigenvector2PrincipalAxis(NED, src.eig_pnt[1], + src.null_axis, naxis); + ierr += cmopad_Eigenvector2PrincipalAxis(NED, src.eig_pnt[2], + src.t_axis, taxis); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error converting eigenvector to principal axis!"); + return -1; + } + // Switch basis from NED to USE + cmopad_basis_transformVector(paxis, NED, USE); + cmopad_basis_transformVector(naxis, NED, USE); + cmopad_basis_transformVector(taxis, NED, USE); + // From the NED mt get the moment tensor in USE to write to QuakeML + memcpy(M_use, mt, 6*sizeof(double)); + ierr = cmopad_basis_transformMatrixM6(M_use, NED, USE); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error converting NED to USE moment tensor"); + return -1; + } +*/ + compearth_convertMT(1, CE_NED, CE_USE, mt, M_use); + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "focalMechanism\0"); + // Write the moment tensor + ierr = xml_quakeML_writeMomentTensor(publicIDroot, + evid, + method, + M_use, + M0, //src.seismic_moment, + dcPct, //src.DC_percentage, + clvdPct, //src.CLVD_percentage, + (void *) xml_writer); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing momentTensor!"); + return -1; + } + // Write the nodal planes + ierr = xml_quakeML_writeNodalPlanes(fp1, fp2, + (void *) writer); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing nodal planes"); + return -1; + } + // Write the principal axes + ierr = xml_quakeML_writePrincipalAxes(taxis, + paxis, + naxis, + (void *) writer); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing principal axes"); + return -1; + } + // + rc += xmlTextWriterEndElement(writer); // + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing focalMechanism!"); + return -1; + } + return 0; +} +//============================================================================// +/*! + * @brief Reads a focal mechanism + * + * @bug This isn't yet programmed + * + */ +/* +int xml_quakeML_readFocalMechanism() +{ + const char *fcnm = "xml_quakeML_readFocalMechanism\0"; + LOG_ERRMSG("%s", "Error not yet programmed"); + return -1; +} +*/ diff --git a/src/xml/quakeML/latitude.c b/src/xml/quakeML/latitude.c new file mode 100644 index 00000000..6989550f --- /dev/null +++ b/src/xml/quakeML/latitude.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +int xml_quakeML_writeLatitude(const double latitude, + const enum alert_units_enum lat_units, + const bool lhaveLat, + const double latUncer, + const enum alert_units_enum latUncer_units, + const bool lhaveLatUncer, + const double confidence, + const bool lhaveConfidence, + void *xml_writer) +{ + xmlTextWriterPtr writer; + char units[128]; + int rc; + //------------------------------------------------------------------------// + // + // nothing to do + if (!lhaveLat && !lhaveLatUncer && !lhaveConfidence){return 0;} + // get writer + rc = 0; + writer = (xmlTextWriterPtr) xml_writer; + // Begin + rc += xmlTextWriterStartElement(writer, BAD_CAST "latitude\0"); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error starting element"); + return -1; + } + if (lhaveLat) + { + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", latitude); + __xml_units__enum2string(lat_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + if (lhaveLatUncer) + { + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "uncertainty\0", + "%f", latUncer); + __xml_units__enum2string(latUncer_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + if (lhaveConfidence) + { + rc += xmlTextWriterWriteFormatElement(writer, + BAD_CAST "confidenceLevel\0", + "%f", confidence); + } + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing latitude"); + return -1; + } + return 0; +} diff --git a/src/xml/quakeML/longitude.c b/src/xml/quakeML/longitude.c new file mode 100644 index 00000000..7ea3a927 --- /dev/null +++ b/src/xml/quakeML/longitude.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +int xml_quakeML_writeLongitude(const double longitude, + const enum alert_units_enum lon_units, + const bool lhaveLon, + const double lonUncer, + const enum alert_units_enum lonUncer_units, + const bool lhaveLonUncer, + const double confidence, + const bool lhaveConfidence, + void *xml_writer) +{ + xmlTextWriterPtr writer; + char units[128]; + int rc; + //------------------------------------------------------------------------// + // + // nothing to do + if (!lhaveLon && !lhaveLonUncer && !lhaveConfidence){return 0;} + // get writer + rc = 0; + writer = (xmlTextWriterPtr) xml_writer; + // Begin + rc += xmlTextWriterStartElement(writer, BAD_CAST "longitude\0"); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error starting element"); + return -1; + } + if (lhaveLon) + { + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", longitude); + __xml_units__enum2string(lon_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + if (lhaveLonUncer) + { + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "uncertainty\0", + "%f", lonUncer); + __xml_units__enum2string(lonUncer_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + if (lhaveConfidence) + { + rc += xmlTextWriterWriteFormatElement(writer, + BAD_CAST "confidenceLevel\0", + "%f", confidence); + } + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing longitude"); + return -1; + } + return 0; +} diff --git a/src/xml/quakeML/magnitude.c b/src/xml/quakeML/magnitude.c new file mode 100644 index 00000000..378bdcc6 --- /dev/null +++ b/src/xml/quakeML/magnitude.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +/*! + * TODO: need to make a write mag function because this is all wrong + */ +int xml_quakeML_writeMagnitude(const double magnitude, + const bool lhaveMag, + const double magUncer, + const bool lhaveMagUncer, + const char *type, + const bool lhaveType, + void *xml_writer) +{ + xmlTextWriterPtr writer; + int rc; + //------------------------------------------------------------------------// + // + // nothing to do + if (!lhaveMag && !lhaveMagUncer && !lhaveType){return 0;} + // get writer + rc = 0; + writer = (xmlTextWriterPtr) xml_writer; + // Begin + rc += xmlTextWriterStartElement(writer, BAD_CAST "magnitude\0"); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error starting element"); + return -1; + } + if (lhaveMag) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "mag\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", magnitude); + rc += xmlTextWriterEndElement(writer); // + } + if (lhaveMagUncer) + { + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "uncertainty\0", + "%e", magUncer); + } + if (lhaveType) + { + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "type\0", + "%s", type); + } + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing latitude"); + return -1; + } + return 0; +} diff --git a/src/xml/quakeML/momentTensor.c b/src/xml/quakeML/momentTensor.c new file mode 100644 index 00000000..9519f62c --- /dev/null +++ b/src/xml/quakeML/momentTensor.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" +/*! + * @brief Writes the moment tensor, scalar moment, double couple percentage, + * and CLVD percentage. + * + * @param[in] publicIDroot QuakeML public ID root + * (e.g. quakeml:us.anss.org/) + * @param[in] evid Event ID. + * @param[in] method Method by which the moment tensor was computed + * (for this project use gps). + * @param[in] M_use The moment tensor terms (Nm) in USE coordinates + * packed: + * \f$ \{ m_{rr}, + * m_{\theta \theta}, + * m_{\phi \phi}, + * m_{r \theta}, m_{r \phi}, + * m_{\theta \phi} \} \f$. + * @param[in] M0 Scalar moment (Nm). + * @param[in] dc_pct Percent double couple [0,100]. + * @param[in] clvd_pct Percent CLVD [0,100]. + * + * @param[in,out] xml_writer On input this is a pointer to the + * xmlTextWriterPtr. + * On successful output the moment tensor has been + * appended to the xml_writer as a QuakeML moment + * tensor. + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int xml_quakeML_writeMomentTensor(const char *publicIDroot, + const char *evid, + const char *method, + const double M_use[6], + const double M0, + const double dc_pct, + const double clvd_pct, + void *xml_writer) +{ + xmlTextWriterPtr writer; + char publicID[512]; + double Mrr, Mtt, Mpp, Mrt, Mrp, Mtp; + int ierr, rc; + size_t lenos; + //------------------------------------------------------------------------// + // + rc = 0; + writer = (xmlTextWriterPtr ) xml_writer; + // Set the publicID + memset(publicID, 0, 512*sizeof(char)); + if (publicIDroot != NULL){strcat(publicID, publicIDroot);} + lenos = strlen(publicID); + if (lenos > 0) + { + if (publicID[lenos - 1] != '/'){strcat(publicID, "/\0");} + } + strcat(publicID, "momenttensor/\0"); + if (evid != NULL){ + strcat(publicID, evid); + strcat(publicID, "/\0"); + } + if (method != NULL){strcat(publicID, method);} + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "momentTensor\0"); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "publicID\0", + BAD_CAST publicID); + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "scalarMoment\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", M0); + rc += xmlTextWriterEndElement(writer); // + // Write the tensor + Mrr = M_use[0]; + Mtt = M_use[1]; + Mpp = M_use[2]; + Mrt = M_use[3]; + Mrp = M_use[4]; + Mtp = M_use[5]; + ierr = xml_quakeML_writeTensor(Mrr, Mtt, Mpp, + Mrt, Mrp, Mtp, + (void *) writer); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing tensor"); + return -1; + } + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "doubleCouple\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", dc_pct/100.0); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "clvd\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", clvd_pct/100.0); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing momentTensor"); + return -1; + } + return 0; +} diff --git a/src/xml/quakeML/nodalPlanes.c b/src/xml/quakeML/nodalPlanes.c new file mode 100644 index 00000000..087e0a66 --- /dev/null +++ b/src/xml/quakeML/nodalPlanes.c @@ -0,0 +1,114 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" +/*! + * @brief Writes the nodal planes defined by their strike, dip, and rake. + * The strike is measured clockwise north [0,360]. The dip is + * measured positive down from horizontal [0,90], and rake + * represents the angle between the strike and slip direction + * [-180,180]. For further details see Aki and Richards + * Quantitative Seismology Ed. 2 pg 101. + * + * @param[in] np1 first nodal plane defined by its strike, dip, + * and rake respectively (degrees) [3] + * @param[in] np2 second nodal plane defined by its strike, dip, + * and rake respectively (degrees) [3] + * + * @param[in,out] xml_writer handle of XML writer to which the nodal planes + * will be written + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int xml_quakeML_writeNodalPlanes(const double np1[3], + const double np2[3], + void *xml_writer) +{ + xmlTextWriterPtr writer; + int rc; + //------------------------------------------------------------------------// + rc = 0; + writer = (xmlTextWriterPtr ) xml_writer; + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "nodalPlanes\0"); + //---------------------------nodal plane 1--------------------------------// + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "nodalPlane1\0"); + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "strike\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", np1[0]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "dip\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", np1[1]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "rake\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", np1[2]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + //---------------------------nodal plane 2--------------------------------// + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "nodalPlane2\0"); + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "strike\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", np2[0]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "dip\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", np2[1]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "rake\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", np2[2]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing nodal planes"); + return -1; + } + return 0; +} +//============================================================================// +/*! + * @brief Reads the nodal planes + * + * @bug This is not yet programmed + * + */ +/* +int xml_quakeML_readNodalPlanes(const void *xml_reader, + const double NP_NAN, + double strike[2], + double rake[2], + double dip[2]) +{ + LOG_ERRMSG("%s", "Error this isn't programmed yet"); + return -1; +} +*/ diff --git a/src/xml/quakeML/origin.c b/src/xml/quakeML/origin.c new file mode 100644 index 00000000..00eae19d --- /dev/null +++ b/src/xml/quakeML/origin.c @@ -0,0 +1,170 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +/*! + * @brief Writes an origin to the xml_writer + * + * @param[in] publicIDroot QuakeML public ID root + * (e.g. quakeml:us.anss.org/). + * @param[in] evid Event ID. + * @param[in] method Method by which the origin was computed. + * @param[in] origin Contains the event origin information. + * + * @param[in,out] xml_writer On input this is a pointer to the + * xmlTextWriterPtr. + * On successful output the origin has been + * appended to the xml_writer as a QuakeML origin. + * @result 0 indicates success. + * + * @author Ben Baker, ISTI + * + */ +int xml_quakeML_writeOrigin(const char *publicIDroot, + const char *evid, + const char *method, + struct qmlOrigin_struct origin, + void *xml_writer) +{ + xmlTextWriterPtr writer; + char publicID[512]; + int ierr, rc; + size_t lenos; + //------------------------------------------------------------------------// + // + // Nothing to do + if (!origin.lhaveEllipse && + !origin.lhaveOriUnc && + !origin.lhaveLatitude && + !origin.lhaveLongitude && + !origin.lhaveDepth && + !origin.lhaveOriginTime) + { + return 0; + } + // Initialize + rc = 0; + ierr = 0; + writer = (xmlTextWriterPtr ) xml_writer; + // Set the publicID + memset(publicID, 0, 512*sizeof(char)); + if (publicIDroot != NULL){strcat(publicID, publicIDroot);} + lenos = strlen(publicID); + if (lenos > 0) + { + if (publicID[lenos - 1] != '/'){strcat(publicID, "/\0");} + } + strcat(publicID, "origin/\0"); + if (evid != NULL) + { + strcat(publicID, evid); + strcat(publicID, "/\0"); + } + if (method != NULL){strcat(publicID, method);} + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "origin\0"); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "publicID\0", + BAD_CAST publicID); + // + if (origin.lhaveEllipse) + { + LOG_ERRMSG("%s", "Error ellipse not yet done"); + } + // + if (origin.lhaveOriUnc) + { + LOG_ERRMSG("%s", "Error origin uncertainty not yet done"); + } + // + rc += xmlTextWriterEndElement(writer); // + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error writing focalMechanism!"); + return -1; + } + return 0; +} diff --git a/src/xml/quakeML/principalAxes.c b/src/xml/quakeML/principalAxes.c new file mode 100644 index 00000000..2f2019c4 --- /dev/null +++ b/src/xml/quakeML/principalAxes.c @@ -0,0 +1,136 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" +/*! + * @brief Writes the tension, pressure, and null principal axes. + * + * @param[in] taxis tension principal axis defined by its + * azimuth angle (dgrees), plunge angle (degrees), + * and length (Nm) respectively [3] + * @param[in] paxis pressure principal axis defined by its + * azimuth angle (dgrees), plunge angle (degrees), + * and length (Nm) respectively [3] + * @param[in] naxis null (intermediate) principal axis defined by its + * azimuth angle (dgrees), plunge angle (degrees), + * and length (Nm) respectively [3] + * + * @param[in,out] xml_writer handle of XML writer to which the principal + * axes will be written + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int xml_quakeML_writePrincipalAxes(const double taxis[3], + const double paxis[3], + const double naxis[3], + void *xml_writer) +{ + xmlTextWriterPtr writer; + int rc; + //------------------------------------------------------------------------// + rc = 0; + writer = (xmlTextWriterPtr ) xml_writer; + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "principalAxess\0"); + //-----------------------------tension axis-------------------------------// + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "tAxis\0"); + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "azimuth\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", taxis[0]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "plunge\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", taxis[1]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "length\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", taxis[2]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + //-----------------------------pressure axis------------------------------// + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "pAxis\0"); + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "azimuth\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", paxis[0]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "plunge\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", paxis[1]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "length\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", paxis[2]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + //------------------------------null axis---------------------------------// + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "nAxis\0"); + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "azimuth\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", naxis[0]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "plunge\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%f", naxis[1]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "length\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", naxis[2]); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing principal axes"); + return -1; + } + return 0; +} +//============================================================================// +/*! + * @brief Reads the nodal planes + * + * @bug This is not yet programmed + * + */ +/* +int xml_quakeML_readPrincipalAxes(const void *xml_reader, + const double PA_NAN, + double taxis[3], + double paxis[3], + double naxis[3]) +{ + const char *fcnm = "xml_quakeML_readPrincipalAxes\0"; + LOG_ERRMSG("%s", "Error this isn't programmed yet"); + return -1; +} +*/ diff --git a/src/xml/quakeML/tensor.c b/src/xml/quakeML/tensor.c new file mode 100644 index 00000000..460d79db --- /dev/null +++ b/src/xml/quakeML/tensor.c @@ -0,0 +1,97 @@ +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +/*! + * @brief Writes the moment tensor terms in Up, South, East coordinates + * as described in Aki and Richards - Quantitative Seismology + * 2nd Ed. pg 113. + * + * @param[in] Mrr Mrr component of moment tensor (USE) coordinates. + * Units are Newton-meters. + * @param[in] Mtt Mtt component of moment tensor (USE) coordinates. + * Units are Newton-meters. + * @param[in] Mpp Mpp component of moment tensor (USE) coordinates. + * Units are Newton-meters. + * @param[in] Mrt Mrt component of moment tensor (USE) coordinates. + * Units are Newton-meters. + * @param[in] Mrp Mrp component of moment tensor (USE) coordinates. + * Units are Newton-meters. + * @param[in] Mtp Mtp component of moment tensor (USE) coordinates. + * Units are Newton-meters. + * + * @param[in,out] xml_writer handle to XML writer to which to write + * the (moment) tensor + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + * @date May 2016 + * + */ +int xml_quakeML_writeTensor(const double Mrr, const double Mtt, + const double Mpp, const double Mrt, + const double Mrp, const double Mtp, + void *xml_writer) +{ + xmlTextWriterPtr writer; + int rc; + //------------------------------------------------------------------------// + // + // Cast the writer + rc = 0; + writer = (xmlTextWriterPtr ) xml_writer; + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "tensor\0"); + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "Mrr\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", Mrr); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "Mtt\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", Mtt); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "Mpp\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", Mpp); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "Mrt\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", Mrt); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "Mrp\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", Mrp); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "Mtp\0"); + rc += xmlTextWriterWriteFormatElement(writer, BAD_CAST "value\0", + "%e", Mtp); + rc += xmlTextWriterEndElement(writer); // + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing tensor!"); + return -1; + } + return 0; +} diff --git a/src/xml/quakeML/time.c b/src/xml/quakeML/time.c new file mode 100644 index 00000000..a9eacc87 --- /dev/null +++ b/src/xml/quakeML/time.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +int xml_quakeML_writeTime(const double time, + const enum alert_units_enum time_units, + const bool lhaveTime, + const double timeUncer, + const enum alert_units_enum timeUncer_units, + const bool lhaveTimeUncer, + const double confidence, + const bool lhaveConfidence, + void *xml_writer) +{ + xmlTextWriterPtr writer; + char units[128]; + int rc; + //------------------------------------------------------------------------// + // + // nothing to do + if (!lhaveTime && !lhaveTimeUncer && !lhaveConfidence){return 0;} + // get writer + rc = 0; + writer = (xmlTextWriterPtr) xml_writer; + // Begin + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing time"); + return -1; + } + return 0; +} diff --git a/src/xml/quakeML/units.c b/src/xml/quakeML/units.c new file mode 100644 index 00000000..dddc8212 --- /dev/null +++ b/src/xml/quakeML/units.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include "gfast_xml.h" +#include "gfast_core.h" + +/*! + * @brief Converts the enumerated units a string. + * + * @param[in] enum_units Enumerated units defined in alert_units_enum. + * + * @param[out] char_units Corresponding string representation of the + * enum_units. + * + * @author Ben Baker, ISTI + * + */ +void __xml_units__enum2string(enum alert_units_enum enum_units, + char char_units[128]) +{ + const char *fcnm = "__alert_units__units2string\0"; + memset(char_units, 0, 128*sizeof(char)); + if (enum_units == DEGREES) + { + strcpy(char_units, "deg\0"); + } + else if (enum_units == KILOMETERS) + { + strcpy(char_units, "km\0"); + } + else if (enum_units == METERS) + { + strcpy(char_units, "meters\0"); + } + else if (enum_units == SECONDS) + { + strcpy(char_units, "sec\0"); + } + else if (enum_units == UTC) + { + strcpy(char_units, "UTC\0"); + } + else if (enum_units == MOMENT_MAGNITUDE) + { + strcpy(char_units, "Mw\0"); + } + else if (enum_units == DYNE_CENTIMETERS) + { + strcpy(char_units, "dyne_cm\0"); + } + else if (enum_units == NEWTON_METERS) + { + strcpy(char_units, "newton_meters\0"); + } + else + { + if (enum_units != UNKNOWN_UNITS) + { + LOG_WARNMSG("%s: Warning unknown unit %d\n", fcnm, enum_units); + } + } + return; +} +//============================================================================// +/*! + * @brief Converts string units to enumerated units + * + * @param[in] char_units string represenation of units to convert + * to enumerated units + * + * @result enumerated unit representation fo char_units + * + * @author Ben Baker, ISTI + * + */ +enum alert_units_enum + __xml_units__string2enum(const char *char_units) +{ + const char *fcnm = "__alert_units__string2enum\0"; + enum alert_units_enum enum_units = UNKNOWN_UNITS; + // Not defined + if (char_units == NULL){return enum_units;} + if (strlen(char_units) == 0){return enum_units;} + // Degrees + if (strcasecmp(char_units, "deg\0") == 0 || + strcasecmp(char_units, "degrees\0") == 0) + { + enum_units = DEGREES; + } + // Kilometers + else if (strcasecmp(char_units, "km\0") == 0 || + strcasecmp(char_units, "kilometers\0") == 0) + { + enum_units = KILOMETERS; + } + // Meters + else if (strcasecmp(char_units, "meters\0") == 0) + { + enum_units = METERS; + } + // Moment-magnitude + //else if (strcasecmp(char_units, "Mw\0") == 0) + // MTH: Temp hack to prevent complaints for PDL mag units != 'Mw': + else if (strcasecmp(char_units, "Mw\0") == 0 || + strcasecmp(char_units, "Mww\0") == 0 || + strcasecmp(char_units, "Mwr\0") == 0 || + strcasecmp(char_units, "Ml\0") == 0 || + strcasecmp(char_units, "Mb\0") == 0 || + strcasecmp(char_units, "Ms\0") == 0 || + strcasecmp(char_units, "Md\0") == 0 ) + { + enum_units = MOMENT_MAGNITUDE; + } + // Dyne centimeters + else if (strcasecmp(char_units, "dyne_cm\0") == 0 || + strcasecmp(char_units, "dyne_centimeters\0") == 0) + { + enum_units = DYNE_CENTIMETERS; + } + // Newton meters + else if (strcasecmp(char_units, "newton_meters\0") == 0 || + strcasecmp(char_units, "Nm\0") == 0) + { + enum_units = NEWTON_METERS; + } + // Time - Seconds + else if (strcasecmp(char_units, "sec\0") == 0 || + strcasecmp(char_units, "seconds\0") == 0){ + enum_units = SECONDS; + } + // Time - UTC + else if (strcasecmp(char_units, "UTC\0") == 0){ + enum_units = UTC; + } + // No idea + else + { + LOG_WARNMSG("%s: Unknown units: %s\n", fcnm, char_units); + } + return enum_units; +} diff --git a/src/xml/shakeAlert/Makefile b/src/xml/shakeAlert/Makefile new file mode 100644 index 00000000..74e6cd74 --- /dev/null +++ b/src/xml/shakeAlert/Makefile @@ -0,0 +1,63 @@ +# Makefile for GFAST/src/xml/shakeAlert +# +EEWDIR = ../../../.. +include $(EEWDIR)/Make.include.$(shell uname) + +#ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +#endif +#ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +#endif +#ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +#endif + +OBJS = coreInfo.o segment.o slip.o vertex.o vertices.o geometry.o + +DEBUG = -g +CFLAGS += -O0 -D_REENTRANT -Dstatic_config + +INCL = -I ../../../include $(XML2_INCL) $(ISCL_INCL) + +SYSLIBS = -lpthread -lnsl -lrt -lz + +all: $(OBJS) + +%.o: %.c + $(CC) -c $< $(CFLAGS) $(DEBUG) $(INCL) + +ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f;) + +rm-ids: *.c + $(foreach f, $^, $(BUILD_UTILS)/updateId $f -r;) + +# depend +-include $(DEPENDFILES) + +depend: + touch $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) + $(MAKEDEPEND) -f $(DEPENDFILES) -a -Y -- $(CCFLAGS) $(INCL) *.cc + +cleandepend: + rm -rf $(DEPENDFILES) + +clean: + -rm -f *.o $(BIN) + +veryclean: clean rm-ids cleandepend + +install: $(BIN) | $(INSTALL_GFAST_BIN_DIR) + cp $(BIN) $(INSTALL_GFAST_BIN_DIR)/ + +# coverage +cleancoverage: clean + -rm -rf *.gcno *.gcda *.gcov *.info + +buildcoverage: prepcoverage all + +prepcoverage: + $(eval CCFLAGS=${CCFLAGS} -fprofile-arcs -ftest-coverage) + $(eval CFLAGS=${CFLAGS} -fprofile-arcs -ftest-coverage) diff --git a/src/xml/shakeAlert/coreInfo.c b/src/xml/shakeAlert/coreInfo.c new file mode 100644 index 00000000..2a7e7994 --- /dev/null +++ b/src/xml/shakeAlert/coreInfo.c @@ -0,0 +1,512 @@ +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wpadded" +#endif +#include +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" +#include "iscl/iscl/iscl_defs.h" +#include "iscl/iscl/iscl_enum.h" +#include "iscl/time/time.h" + +/*! + * @brief Reads from the input shakeAlert XML message into the core structure + * + * @param[in] xml_reader Pointer to core_info xmlNodePtr. + * @param[in] SA_NAN If an item is not found then this will be its default + * value. + * + * @param[out] core On successful exit contains the event ID, magnitude, + * magnitude uncertainty, latitude, latitude uncertainty, + * longitude, longitude uncertainty, depth, depth + * uncertainty, origin time, origin time uncertainty, + * with accompanying units as well as likelihood. + * + * @result 0 indicates success. + * + * @author Ben Baker, ISTI + * + */ +int xml_shakeAlert_readCoreInfo(void *xml_reader, + const double SA_NAN, + struct coreInfo_struct *core) +{ + xmlNodePtr core_xml, core_xml_info; + xmlAttrPtr attr; + xmlChar *value = NULL; + enum unpack_types_enum + { + UNPACK_INT = 0, + UNPACK_DOUBLE = 1, + UNPACK_TIME = 2 + }; + const int nitems = 12; + const xmlChar *citems[12] = { BAD_CAST "mag\0", BAD_CAST "mag_uncer\0", + BAD_CAST "lat\0", BAD_CAST "lat_uncer\0", + BAD_CAST "lon\0", BAD_CAST "lon_uncer\0", + BAD_CAST "depth\0", BAD_CAST "depth_uncer\0", + BAD_CAST "orig_time\0", + BAD_CAST "orig_time_uncer\0", + BAD_CAST "likelihood\0", + BAD_CAST "num_stations\0"}; + double values[12]; + int units[12], ivalues[12]; + const int types[12] = {UNPACK_DOUBLE, UNPACK_DOUBLE, + UNPACK_DOUBLE, UNPACK_DOUBLE, + UNPACK_DOUBLE, UNPACK_DOUBLE, + UNPACK_DOUBLE, UNPACK_DOUBLE, + UNPACK_TIME, UNPACK_DOUBLE, + UNPACK_INT}; + int dom, hour, ierr, item, item0, minute, month, nzmsec, nzmusec, + nzsec, year; + bool lfound, lunpack; + size_t lenos; + const double tol = 1.e-14; + //------------------------------------------------------------------------// + // + // Initialize result + ierr = 0; + lfound = false; + memset(core, 0, sizeof(struct coreInfo_struct)); + for (item=0; itemname, BAD_CAST "core_info\0") != 0)) + { + LOG_ERRMSG("Error xml_reader does not start at core_info %s!", + core_xml->name); + return -1; + } + // Get the eventID + attr = xmlHasProp(core_xml, BAD_CAST "id\0"); + if (attr) + { + value = xmlNodeListGetString(core_xml->doc, attr->children, 1); + if (value == NULL) + { + LOG_ERRMSG("%s", "Error getting event ID"); + return -1; + } + lenos = MIN(128, (size_t) xmlStrlen(value)); //strlen((const char *) value)); + strncpy(core->id, (const char *) value, lenos); + xmlFree(value); + } + else + { + LOG_WARNMSG("%s", "Warning couldn't lift the event ID"); + } + // Now parse the core info + item0 =-1; + core_xml_info = core_xml->xmlChildrenNode; + while (core_xml_info != NULL) + { + // Require we are working on an element node + if (core_xml_info->type != XML_ELEMENT_NODE) + { + goto NEXT_CORE_XML_INFO; + } + lfound = true; + lunpack = false; + // Try taking the next item in citems + if (item0 < nitems) + { + if (xmlStrcmp(core_xml_info->name, citems[item0+1]) == 0) + { + lunpack = true; + item0 = item0 + 1; + } + } + // Otherwise do a linear search of citems + if (!lunpack) + { + for (item=0; itemname, citems[item]) == 0) + { + lunpack = true; + item0 = item + 1; + break; + } + } + } + // I didn't find this value in citems - weird - continue + if (!lunpack) + { + LOG_WARNMSG("Warning couldn't find item %s", core_xml_info->name); + goto NEXT_CORE_XML_INFO; + } + // Check on item index to avoid a segfault + if (item0 < 0 || item0 > nitems - 1) + { + LOG_ERRMSG("Invalid index %s %d", core_xml_info->name, item0); + ierr = 1; + lfound = false; + goto ERROR; + } + // Are there units associated with a double to unpack? + attr = xmlHasProp(core_xml_info, BAD_CAST "units\0"); + if (attr && types[item0] != UNPACK_TIME) + { + value = xmlNodeListGetString(core_xml_info->doc, + attr->children, 1); + units[item0] = __xml_units__string2enum((char *)value); + free(value); + } + // Is there a value to unpack? + value = xmlNodeGetContent(core_xml_info); + if (value != NULL) + { + if (types[item0] == UNPACK_INT) + { + ivalues[item0] = (int) (xmlXPathCastStringToNumber(value) + 0.5); + } + else if (types[item0] == UNPACK_DOUBLE) + { + values[item0] = xmlXPathCastStringToNumber(value); + } + else if (types[item0] == UNPACK_TIME) + { + sscanf((char *)value, "%4d-%2d-%2dT%2d:%2d:%2d.%3dZ", + &year, &month, &dom, &hour, + &minute, &nzsec, &nzmsec); + nzmusec = nzmsec*1000; + values[item0] = time_calendar2epoch2(year, month, dom, hour, + minute, nzsec, nzmusec); + units[item0] = SECONDS; + } + else + { + LOG_WARNMSG("Unknown type %d\n", types[item0]); + } + free(value); + } +NEXT_CORE_XML_INFO:; + core_xml_info = core_xml_info->next; + } // End loop on core_xml_info + if (!lfound) + { + LOG_ERRMSG("%s", "Error I couldn't find any elements in core_info"); + ierr = 1; + } +ERROR:; + if (ierr != 0) + { + for (item=0; itemmag = values[0]; + core->magUncer = values[1]; + core->lat = values[2]; + core->latUncer = values[3]; + core->lon = values[4]; + core->lonUncer = values[5]; + core->depth = values[6]; + core->depthUncer = values[7]; + core->origTime = values[8]; + core->origTimeUncer = values[9]; + core->likelihood = values[10]; + core->numStations = ivalues[11]; + if (fabs(core->mag - SA_NAN) > tol){core->lhaveMag = true;} + if (fabs(core->magUncer - SA_NAN) > tol){core->lhaveMagUncer = true;} + if (fabs(core->lat - SA_NAN) > tol){core->lhaveLat = true;} + if (fabs(core->latUncer - SA_NAN) > tol){core->lhaveLatUncer = true;} + if (fabs(core->lon - SA_NAN) > tol){core->lhaveLon = true;} + if (fabs(core->lonUncer - SA_NAN) > tol){core->lhaveLonUncer = true;} + if (fabs(core->depth - SA_NAN) > tol){core->lhaveDepth = true;} + if (fabs(core->depthUncer - SA_NAN) > tol){core->lhaveDepthUncer = true;} + if (fabs(core->origTime - SA_NAN) > tol){core->lhaveOrigTime = true;} + if (fabs(core->origTimeUncer - SA_NAN) > tol) + { + core->lhaveOrigTimeUncer = true; + } + if (fabs(core->likelihood - SA_NAN) > tol){core->lhaveLikelihood = true;} + // Copy the units + core->magUnits = (enum alert_units_enum) units[0]; + core->magUncerUnits = (enum alert_units_enum) units[1]; + core->latUnits = (enum alert_units_enum) units[2]; + core->latUncerUnits = (enum alert_units_enum) units[3]; + core->lonUnits = (enum alert_units_enum) units[4]; + core->lonUncerUnits = (enum alert_units_enum) units[5]; + core->depthUnits = (enum alert_units_enum) units[6]; + core->depthUncerUnits = (enum alert_units_enum) units[7]; + core->origTimeUnits = (enum alert_units_enum) units[8]; + core->origTimeUncerUnits = (enum alert_units_enum) units[9]; + if (core->magUnits != UNKNOWN_UNITS) + { + core->lhaveMagUnits = true; + } + if (core->magUncerUnits != UNKNOWN_UNITS) + { + core->lhaveMagUncerUnits = true; + } + if (core->latUnits != UNKNOWN_UNITS) + { + core->lhaveLatUnits = true; + } + if (core->latUncerUnits != UNKNOWN_UNITS) + { + core->lhaveLatUncerUnits = true; + } + if (core->lonUnits != UNKNOWN_UNITS) + { + core->lhaveLonUnits = true; + } + if (core->lonUncerUnits != UNKNOWN_UNITS) + { + core->lhaveLonUncerUnits = true; + } + if (core->depthUnits != UNKNOWN_UNITS) + { + core->lhaveDepthUnits = true; + } + if (core->depthUncerUnits != UNKNOWN_UNITS) + { + core->lhaveDepthUncerUnits = true; + } + if (core->origTimeUnits != UNKNOWN_UNITS) + { + core->lhaveOrigTimeUnits = true; + } + if (core->origTimeUncerUnits != UNKNOWN_UNITS) + { + core->lhaveOrigTimeUncerUnits = true; + } + return ierr; +} +//============================================================================// +/*! + * @brief Writes the shakeAlert core info to the xmlTextWriter xml_writer. + * + * @param[in] core Contains the core information which is the + * event ID, magnitude, magnitude uncertainty, + * latitude, latitude uncertainty, longitude, + * longitude uncertainty, depth, depth uncertainty, + * origin time, origin time uncertainty, all with + * accompanying units and the likelihood. + * + * @param[in,out] xml_writer Pointer to xmlTextWriterPtr which is updated + * with the shakeAlert core_info. + * + * @result 0 indicates success. + * + * @author Ben Baker, ISTI + * + */ +int xml_shakeAlert_writeCoreInfo(struct coreInfo_struct core, + void *xml_writer) +{ + xmlTextWriterPtr writer; + char units[128], var[128], cevtime[128]; + int rc; + //------------------------------------------------------------------------// + rc = 0; + writer = (xmlTextWriterPtr) xml_writer; + + rc += xmlTextWriterStartElement(writer, BAD_CAST "core_info\0"); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "id\0", + BAD_CAST core.id); + // magnitude: float + if (core.lhaveMag) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "mag\0"); + if (core.lhaveMagUncer) + { + __xml_units__enum2string(core.magUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.mag); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // magnitude uncertainty: float + if (core.lhaveMagUncer) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "mag_uncer\0"); + if (core.lhaveMagUncerUnits) + { + __xml_units__enum2string(core.magUncerUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.magUncer); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // latitude: float + if (core.lhaveLat) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "lat\0"); + if (core.lhaveLatUnits) + { + __xml_units__enum2string(core.latUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.lat); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // latitude uncertainty: float + if (core.lhaveLatUncer) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "lat_uncer\0"); + if (core.lhaveLatUncerUnits) + { + __xml_units__enum2string(core.latUncerUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.latUncer); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // longitude: float + if (core.lhaveLon) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "lon\0"); + if (core.lhaveLonUnits) + { + __xml_units__enum2string(core.lonUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.lon); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // longitude uncertainty: float + if (core.lhaveLonUncer) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "lon_uncer\0"); + if (core.lhaveLonUncerUnits) + { + __xml_units__enum2string(core.lonUncerUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.lonUncer); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // depth: float + if (core.lhaveDepth) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "depth\0"); + if (core.lhaveDepthUnits) + { + __xml_units__enum2string(core.depthUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.depth); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // depth uncertainty: float + if (core.lhaveDepthUncer) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "depth_uncer\0"); + if (core.lhaveDepthUncerUnits) + { + __xml_units__enum2string(core.depthUncerUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.depthUncer); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // origin time: YYYY-MM-DD:HH:MM:SS.SSSZ" + if (core.lhaveOrigTime) + { + rc = xml_epoch2string(core.origTime, cevtime); + rc += xmlTextWriterStartElement(writer, BAD_CAST "orig_time\0"); + if (core.lhaveOrigTimeUnits) + { + __xml_units__enum2string(core.origTimeUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + rc += xmlTextWriterWriteString(writer, BAD_CAST cevtime); + rc += xmlTextWriterEndElement(writer); + } + // o.t. uncertainty: float + if (core.lhaveOrigTimeUncer) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "orig_time_uncer\0"); + if (core.lhaveOrigTimeUncerUnits) + { + __xml_units__enum2string(core.origTimeUncerUnits, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + } + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.origTimeUncer); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // likelihood + if (core.lhaveLikelihood) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "likelihood\0"); + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", core.likelihood); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // number of stations + if (core.numStations > 0) + { + rc += xmlTextWriterStartElement(writer, BAD_CAST "num_stations\0") ; + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%d", core.numStations); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + } + // + rc = xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing core info"); + } + return rc; +} diff --git a/src/xml/shakeAlert/geometry.c b/src/xml/shakeAlert/geometry.c new file mode 100644 index 00000000..5c92dce9 --- /dev/null +++ b/src/xml/shakeAlert/geometry.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +//============================================================================// +/*! + * @brief Writes the slip on a fault patch in the finite fault. + * + * @param[in] strike Strike direction. + * @param[in] strike_units Units for strike (e.g. DEGREES). + * @param[in] dip Dip direction. + * @param[in] dip_units Units for dip (e.g. DEGREES). + * + * @param[in,out] xml_writer Pointer to xmlTExtWriterPtr to which the slip + * is to be written. + * + * @author Carl Ulberg (UW) + * + * @date November 2021 + * + */ +int xml_shakeAlert_writeGeometry(const double strike, + const enum alert_units_enum strike_units, + const double dip, + const enum alert_units_enum dip_units, + void *xml_writer) +{ + xmlTextWriterPtr writer; + char units[128], var[128]; + int rc; + //------------------------------------------------------------------------// + rc = 0; + writer = (xmlTextWriterPtr ) xml_writer; + // + rc += xmlTextWriterStartElement(writer, BAD_CAST "geometry\0"); + // strike: float + rc += xmlTextWriterStartElement(writer, BAD_CAST "strike\0"); + __xml_units__enum2string(strike_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", strike); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + // dip: float + rc += xmlTextWriterStartElement(writer, BAD_CAST "dip\0"); + __xml_units__enum2string(dip_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", dip); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing geometry"); + return -1; + } + return 0; +} \ No newline at end of file diff --git a/src/xml/shakeAlert/segment.c b/src/xml/shakeAlert/segment.c new file mode 100644 index 00000000..5121dec5 --- /dev/null +++ b/src/xml/shakeAlert/segment.c @@ -0,0 +1,144 @@ +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#pragma clang diagnostic ignored "-Wpadded" +#endif +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +/*! + * @brief Writes a segment (fault patch) of the finite fault. A segment + * is comprised of vertices and slip. + * + * + * @param[in] shape Segment shape. This can be: + * LINE (2) which has two points. + * TRIANGLE (3) which has three points. + * RECTANGLE (4) which has four points. + * @param[in] lats the latitudes at each vertex. the length should + * correspond to the number of points indicated by + * shape. + * @param[in] lat_units units for the input latitudes (e.g. DEGREES) + * @param[in] lons the longitudes at each vertex. the length should + * correspond to the number of points indicated by + * shape. + * @param[in] lon_units units for the input longitudes (e.g. DEGREES) + * @param[in] depths the depths at each vertex. the length should + * correspond to the number of points indicated by + * shape. + * @param[in] depth_units units for the input depths (e.g. KILOMETERS) + * @param[in] strike strike direction + * @param[in] strike_units units for strike (e.g. DEGREES) + * @param[in] dip dip direction + * @param[in] dip_units units for dip (e.g. DEGREES) + * @param[in] ss slip in strike + * @param[in] ss_units units for slip in strike direction on segment + * (e.g. METERS) + * @param[in] ds slip in dip direction + * @param[in] ds_units units for slip in dip direction on segment + * (e.g. METERS) + * @param[in] ss_uncer uncertainty on slip in strike direction for this + * segment with units given by ss_unc_units. if + * negative this value is ignored. + * @param[in] ss_uncer_units units for uncertainty for slip in strike + * direction (e.g. METERS) + * @param[in] ds_uncer uncertainty on slip in strike direction for this + * segment with units given by ds_unc_units. if + * negative this value is ignored. + * @param[in] ds_uncer_units units for ucnertainty for slip in + * dip direction (e.g. METERS) + * + * @param[in,out] xml_writer xmlTextWriterPtr to which to write segment + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + */ +int xml_shakeAlert_writeSegment(const enum xml_segmentShape_enum shape, + const double *lats, + const enum alert_units_enum lat_units, + const double *lons, + const enum alert_units_enum lon_units, + const double *depths, + const enum alert_units_enum depth_units, + const double strike, + const enum alert_units_enum strike_units, + const double dip, + const enum alert_units_enum dip_units, + const double ss, + const enum alert_units_enum ss_units, + const double ds, + const enum alert_units_enum ds_units, + const double ss_uncer, + const enum alert_units_enum ss_uncer_units, + const double ds_uncer, + const enum alert_units_enum ds_uncer_units, + void *xml_writer) +{ + xmlTextWriterPtr writer; + int rc; + //------------------------------------------------------------------------// + rc = 0; + writer = (xmlTextWriterPtr) xml_writer; + if (shape != LINE && shape != TRIANGLE && shape != RECTANGLE) + { + LOG_ERRMSG("Invalid shape %d\n", shape); + return -1; + } + // Begin + rc += xmlTextWriterStartElement(writer, BAD_CAST "segment\0"); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error starting element"); + return -1; + } + // Write the vertices + rc = xml_shakeAlert_writeVertices(shape, + lats, lat_units, + lons, lon_units, + depths, depth_units, + (void *)writer); + if (rc < 0) + { + LOG_ERRMSG("Error writing vertices %d",rc); + return -1; + } + // Write the slip + rc = xml_shakeAlert_writeSlip(ss, ss_units, + ds, ds_units, + ss_uncer, ss_uncer_units, + ds_uncer, ds_uncer_units, + (void *)writer); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing slip"); + return -1; + } + // Write the fault geometry + rc = xml_shakeAlert_writeGeometry(strike, strike_units, + dip, dip_units, + (void *)writer); + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing fault geometry"); + return -1; + } + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing segment"); + return -1; + } + return 0; +} + diff --git a/src/xml/shakeAlert/slip.c b/src/xml/shakeAlert/slip.c new file mode 100644 index 00000000..1bf952d3 --- /dev/null +++ b/src/xml/shakeAlert/slip.c @@ -0,0 +1,261 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" +/*! + * @brief Unpacks the vertex's latitude, longitude, and depth. + * + * @param[in] xml_reader Corresponds to the children of the xmlNodePtr + * segment node pointer. + * @param[in] VTX_NAN Default value for element if it cannot be read. + * + * @param[out] ss Slip along strike (m). + * @param[out] ss_uncer Uncertainty in the slip along strike (m). + * @param[out] ds Slip down dip (m). + * @param[out] ds_uncer Uncertainty in slip down dip (m). + * + * @result 0 indicates success. + * + * @author Ben Baker (ISTI) + * + * @date May 2016 + * + * @bug There are no unit conversions thus the shakeAlert XML is expected to + * have units meters for all variables + * + */ +int xml_shakeAlert_readSlip(void *xml_reader, const double VTX_NAN, + double *ss, double *ss_uncer, + double *ds, double *ds_uncer) +{ + xmlNodePtr slip_xml; + xmlChar *value; + enum unpack_types_enum + { + UNPACK_DOUBLE = 1 + }; + const int nitems = 4; + const xmlChar *citems[4] = { BAD_CAST "ss\0", + BAD_CAST "ss_uncer\0", + BAD_CAST "ds\0", + BAD_CAST "ds_uncer\0" }; + double values[4]; + const int types[4] = {UNPACK_DOUBLE, + UNPACK_DOUBLE, + UNPACK_DOUBLE, + UNPACK_DOUBLE}; + int ierr, item, item0, nfound; + bool lunpack; + //------------------------------------------------------------------------// + // + // Initialize + ierr = 0; + nfound = 0; + for (item=0; itemname, (const xmlChar *) "slip\0"))) + { + LOG_ERRMSG("%s", "Error reader must start at "); + ierr = 1; + goto ERROR; + } + // Try to get the ss, ss_uncer, ds, ds_uncer + item0 =-1; + while (slip_xml != NULL){ + // Require we are working on an element node + if (slip_xml->type != XML_ELEMENT_NODE){goto NEXT_SLIP_XML;} + lunpack = false; + // Try taking the next item in the citems + if (item0 < nitems){ + if (!xmlStrcmp(slip_xml->name, citems[item0+1])) + { + lunpack = true; + item0 = item0 + 1; + } + } + // Otherwise do a linear search of citems + if (!lunpack) + { + for (item=0; itemname, citems[item])) + { + lunpack = true; + item0 = item + 1; + break; + } + } + } + // I didn't find this value in citems - weird - continue + if (!lunpack) + { + LOG_WARNMSG("Warning couldn't find item %s\n", slip_xml->name); + goto NEXT_SLIP_XML; + } + // Check on item index to avoid a segfault + if (item0 < 0 || item0 > nitems - 1) + { + LOG_ERRMSG("Invalid index %s %d\n", slip_xml->name, item0); + ierr = 1; + goto ERROR; + } + // FIXME - unpack units and convert + + // Is there a value to unpack + value = xmlNodeGetContent(slip_xml); + if (value != NULL) + { + if (types[item0] == UNPACK_DOUBLE) + { + values[item0] = xmlXPathCastStringToNumber(value); + } + else + { + LOG_ERRMSG("Invalid type %d!", types[item0]); + goto ERROR; + } + nfound = nfound + 1; + free(value); + } +NEXT_SLIP_XML:; + slip_xml = slip_xml->next; + } // Loop on slip +ERROR:; + // Get what we can + if (ierr == 0) + { + *ss = values[0]; + *ss_uncer = values[1]; + *ds = values[2]; + *ds_uncer = values[3]; + if (nfound < 4) + { + for (item=0; item + rc += xmlTextWriterStartElement(writer, BAD_CAST "slip\0"); + // slip along strike: float + rc += xmlTextWriterStartElement(writer, BAD_CAST "ss\0"); + __xml_units__enum2string(ss_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", ss); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + // uncertainty in slip along strike float + rc += xmlTextWriterStartElement(writer, BAD_CAST "ss_uncer\0"); + __xml_units__enum2string(ss_uncer_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", ss_uncer); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + // slip down dip: float + rc += xmlTextWriterStartElement(writer, BAD_CAST "ds\0"); + __xml_units__enum2string(ds_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", ds); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + // uncertainty in dip down dip float + rc += xmlTextWriterStartElement(writer, BAD_CAST "ds_uncer\0"); + __xml_units__enum2string(ds_uncer_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, 128*sizeof(char)); + sprintf(var, "%f", ds_uncer); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing slip"); + return -1; + } + return 0; +} diff --git a/src/xml/shakeAlert/vertex.c b/src/xml/shakeAlert/vertex.c new file mode 100644 index 00000000..32d58e3b --- /dev/null +++ b/src/xml/shakeAlert/vertex.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" +/*! + * @brief Unpacks the vertex's latitude, longitude, and depth + * + * @param[in] xml_reader corresponds to the children of the xmlNodePtr + * vertex node pointer + * @param[in] VTX_NAN default value for node + * + * @param[out] lat latitude of vertex (degrees) + * @param[out] lon longitude of vertex (degrees) + * @param[out] depth depth of vertex (km) + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + * @date May 2016 + * + * @bug There are no unit conversions thus the shakeAlert XML is expected to + * have units degrees for lat and lon, and km for depth + * + */ +int xml_shakeAlert_readVertex(void *xml_reader, const double VTX_NAN, + double *lat, double *lon, double *depth) +{ + xmlNodePtr vertex_xml; + xmlChar *value; + enum unpack_types_enum + { + UNPACK_DOUBLE = 1 + }; + const int nitems = 3; + const xmlChar *citems[3] = { BAD_CAST "lat\0", + BAD_CAST "lon\0", + BAD_CAST "depth\0" }; + double values[3]; + const int types[3] = {UNPACK_DOUBLE, + UNPACK_DOUBLE, + UNPACK_DOUBLE}; + int ierr, item, item0, nfound; + bool lunpack; + //------------------------------------------------------------------------// + // + // Initialize + ierr = 0; + nfound = 0; + for (item=0; itemparent->name, BAD_CAST "vertex\0") != 0) + { + LOG_ERRMSG("%s", "Error reader must start at "); + ierr = 1; + goto ERROR; + } + // Try to get the lat, lon, depth + item0 =-1; + while (vertex_xml != NULL) + { + // Require we are working on an element node + if (vertex_xml->type != XML_ELEMENT_NODE){goto NEXT_VERTEX_XML;} + lunpack = false; + // Try taking the next item in the citems + if (item0 < nitems) + { + if (!xmlStrcmp(vertex_xml->name, citems[item0+1])) + { + lunpack = true; + item0 = item0 + 1; + } + } + // Otherwise do a linear search of citems + if (!lunpack) + { + for (item=0; itemname, citems[item])) + { + lunpack = true; + item0 = item + 1; + break; + } + } + } + // I didn't find this value in citems - weird - continue + if (!lunpack) + { + LOG_WARNMSG("Warning couldn't find item %s", vertex_xml->name); + goto NEXT_VERTEX_XML; + } + // Check on item index to avoid a segfault + if (item0 < 0 || item0 > nitems - 1) + { + LOG_ERRMSG("Invalid index %s %d", vertex_xml->name, item0); + ierr = 1; + goto ERROR; + } + // FIXME - unpack units and convert + + // Is there a value to unpack + value = xmlNodeGetContent(vertex_xml); + if (value != NULL) + { + if (types[item0] == UNPACK_DOUBLE) + { + values[item0] = xmlXPathCastStringToNumber(value); + } + else + { + LOG_ERRMSG("Invalid type %d!", types[item0]); + goto ERROR; + } + nfound = nfound + 1; + free(value); + } +NEXT_VERTEX_XML:; + vertex_xml = vertex_xml->next; + } // Loop on vertex +ERROR:; + // Get what we can + if (ierr == 0) + { + *lat = values[0]; + *lon = values[1]; + *depth = values[2]; + if (nfound < 3) + { + for (item=0; item + rc += xmlTextWriterStartElement(writer, BAD_CAST "vertex\0"); + // Latitude: float + rc += xmlTextWriterStartElement(writer, BAD_CAST "lat\0"); + __xml_units__enum2string(lat_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, sizeof(var)); + sprintf(var, "%f", lat); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + // Longitude: float + rc += xmlTextWriterStartElement(writer, BAD_CAST "lon\0"); + __xml_units__enum2string(lon_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, sizeof(var)); + sprintf(var, "%f", lon); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + // Depth: float + rc += xmlTextWriterStartElement(writer, BAD_CAST "depth\0"); + __xml_units__enum2string(depth_units, units); + rc += xmlTextWriterWriteAttribute(writer, BAD_CAST "units\0", + BAD_CAST units); + memset(var, 0, sizeof(var)); + sprintf(var, "%f", depth); + rc += xmlTextWriterWriteString(writer, BAD_CAST var); + rc += xmlTextWriterEndElement(writer); + // + rc += xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("%s", "Error writing vertex!"); + return -1; + } + return 0; +} diff --git a/src/xml/shakeAlert/vertices.c b/src/xml/shakeAlert/vertices.c new file mode 100644 index 00000000..2472f518 --- /dev/null +++ b/src/xml/shakeAlert/vertices.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#include +#include +#include +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include "gfast_xml.h" +#include "gfast_core.h" + +/*! + * @brief Reads the vertices in a segment + * + * @param[in] xml_reader pointer to xmlNodePtr reader beginning at + * vertices + * @param[in] shape segment shape + * LINE (2) - segment is a line + * TRIANGLE (3) - segment is a triangle + * RECTANGLE (4) - segment is a rectangle + * @param[in] VTX_NAN default value should a vertex value not be found + * + * @param[out] lat latitude (degrees) at each vertex [shape] + * @param[out] lon longitude (degrees) at each vertex [shape] + * @param[out] depth depth (km) at each vertex [shape] + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + * @date May 2016 + * + */ +int xml_shakeAlert_readVertices(void *xml_reader, + const enum xml_segmentShape_enum shape, + const double VTX_NAN, + double *__restrict__ lat, + double *__restrict__ lon, + double *__restrict__ depth) +{ + xmlNodePtr vertices_xml, vertex_xml; + int ierr, nv, nvref; + //------------------------------------------------------------------------// + // + // Check the input + ierr = 0; + nvref = shape; + if (nvref < 2 || nvref > 4) + { + LOG_ERRMSG("Invalid shape %d\n", shape); + return -1; + } + if (lat == NULL || lon == NULL || depth == NULL) + { + if (lat == NULL){LOG_ERRMSG("%s", "Error lat pointer is NULL");} + if (lon == NULL){LOG_ERRMSG("%s", "Error lon pointer is NULL");} + if (depth == NULL) + { + LOG_ERRMSG("%s", "Error depth pointer is NULL"); + } + return -1; + } + // Initialize result + for (nv=0; nvname, BAD_CAST "vertices\0") != 0) + { + LOG_ERRMSG("%s", "Error reader must start at "); + return -1; + } + // Get the group length + nv = 0; + ierr = 0; + while(vertices_xml != NULL) + { + // Only want to unpack vertex's + if (xmlStrcmp(vertices_xml->name, BAD_CAST "vertex\0") != 0) + { + goto NEXT_VERTICES_XML; + } + // Update the pointer and read the next vertex + nv = nv + 1; + vertex_xml = vertices_xml->xmlChildrenNode; + ierr = ierr + xml_shakeAlert_readVertex((void *)vertex_xml, VTX_NAN, + &lat[nv], &lon[nv], &depth[nv]); + if (ierr != 0) + { + LOG_ERRMSG("Error unpacking vertex %d\n", nv + 1); + ierr = ierr + 1; + } +NEXT_VERTICES_XML:; + vertices_xml = vertices_xml->next; + } // Loop on vertices + // Note the failures + if (nv != nvref) + { + if (shape == LINE) + { + LOG_ERRMSG("%s", "Failed to get all vertices on line"); + } + if (shape == TRIANGLE) + { + LOG_ERRMSG("%s", "Failed to get all vertices on triangle"); + } + if (shape == RECTANGLE) + { + LOG_ERRMSG("%s", "Error failed to get all vertices on rectangle"); + } + ierr = ierr + 1; + } + if (ierr != 0) + { + LOG_ERRMSG("%s", "Errors detect in unpacking vertices"); + } + return ierr; +} +//============================================================================// +/*! + * @brief Writes the vertices for a segment + * + * @param[in] shape Segment shape. This can be: + * LINE (2) which has two points. + * TRIANGLE (3) which has three points. + * RECTANGLE (4) which has four points. + * @param[in] lats the latitudes at each vertex. the length should + * correspond to the number of points indicated by + * shape. + * @param[in] lat_units units for the input latitudes (e.g. DEGREES) + * @param[in] lons the longitudes at each vertex. the length should + * correspond to the number of points indicated by + * shape. + * @param[in] lon_units units for the input longitudes (e.g. DEGREES) + * @param[in] depths the depths at each vertex. the length should + * correspond to the number of points indicated by + * shape. + * @param[in] depth_units units for the input depths (e.g. KILOMETERS) + * + * @param[in,out] xml_writer xmlTextWriterPtr to which to add vertices + * + * @result 0 indicates success + * + * @author Ben Baker (ISTI) + * + * @date April 2016 + * + */ +int xml_shakeAlert_writeVertices(const enum xml_segmentShape_enum shape, + const double *lats, + const enum alert_units_enum lat_units, + const double *lons, + const enum alert_units_enum lon_units, + const double *depths, + const enum alert_units_enum depth_units, + void *xml_writer) +{ + xmlTextWriterPtr writer; + int i, npts, rc; + //------------------------------------------------------------------------// + // + // Classify segment shape to get the number of points + rc = 0; + writer = (xmlTextWriterPtr )xml_writer; + npts = shape; + if (shape < 2 || shape > 4) + { + LOG_ERRMSG("Invalid shape %d", shape); + return -1; + } + // Begin + rc = xmlTextWriterStartElement(writer, BAD_CAST "vertices\0"); + // Write each vertex + for (i=0; i + rc = xmlTextWriterEndElement(writer); // + if (rc < 0) + { + LOG_ERRMSG("Error closing vertices %d", rc); + return -1; + } + return 0; +} diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt new file mode 100644 index 00000000..100d5482 --- /dev/null +++ b/unit_tests/CMakeLists.txt @@ -0,0 +1,9 @@ +add_sources( +cmt.c +coord.c +ff.c +pgd.c +readCoreInfo.c +tests.c +) +set (SRCS_UT ${SRCS} PARENT_SCOPE) diff --git a/unit_tests/cmt.c b/unit_tests/cmt.c new file mode 100644 index 00000000..2e3395f7 --- /dev/null +++ b/unit_tests/cmt.c @@ -0,0 +1,480 @@ +#include +#include +#include +#include +#include +#include "gfast.h" +#include "iscl/memory/memory.h" + +int cmt_greens_test(void); +int cmt_inversion_test(void); + +static bool lequal(double a, double b, double tol) +{ + if (a == 0.0 && b == 0.0){return true;} + if (fabs(a - b)/fabs(a + b) > tol){return false;} + return true; +} + +int cmt_greens_test(void) +{ + const int l1 = 4; + const double x1[4] = {26739.10093066, -22080.60946829, + 172341.17727517, 89347.93966518}; + const double y1[4] = {65206.90127427, -104816.33293538, + 15936.72789605, 37791.23706562}; + const double z1[4] = {-1039.536171, -1180.767, + -2184.68922, -1118.946446}; + const double Gref[3*4*5]= {4.14238313e-22, -1.61043451e-23, -1.64545230e-22, + 2.58162686e-22, -5.52745034e-24, + 3.06830559e-22, -5.52745034e-24, -6.74743229e-23, + 3.83452299e-23, -4.89152924e-24, + -5.52745034e-24, 1.64867566e-22, -1.71290667e-27, + -2.80320397e-24, 6.76065018e-23, + -1.07114045e-22, -5.72795465e-24, 7.53643367e-23, + -1.41160425e-22, -1.02773811e-24, + -9.46107508e-23, -1.02773811e-24, 1.58762517e-23, + -1.38548157e-23, -1.06580004e-24, + -1.02773811e-24, -7.54467746e-23, -3.09557167e-28, + -1.16553865e-24, -1.58936181e-23, + 3.08791337e-23, -3.91440464e-25, -2.71594759e-24, + -2.64749287e-24, -2.04886701e-25, + 1.88799182e-23, -2.04886701e-25, -2.93704961e-23, + -5.80147604e-23, -2.58815699e-24, + -2.04886701e-25, 2.71984347e-24, -1.78022499e-28, + 5.49179132e-25, 2.94126265e-23, + 1.65271763e-22, -2.06977634e-24, -3.65770788e-23, + -1.99279630e-23, -2.33197132e-24, + 2.22799729e-22, -2.33197132e-24, -8.64773658e-23, + -1.33626579e-22, -6.59679291e-24, + -2.33197132e-24, 3.66208854e-23, -4.32350695e-28, + 1.13175414e-24, 8.65809354e-23}; + + double G[(3*4)*5]; + int i, ierr, indx, j; + ierr = GFAST_core_cmt_setForwardModel(l1, true, y1, x1, z1, G); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error setting forward model!"); + return EXIT_FAILURE; + } + indx = 0; + for (i=0; i<3*l1; i++) + { + for (j=0; j<5; j++) + { + //if (fabs( (G[indx] - Gref[indx])/Gref[indx] ) > 1.e-8) + if (!lequal(G[indx], Gref[indx], 1.e-8)) + { + LOG_ERRMSG("Failed to set deviatoric G %e %e %d", + G[indx], Gref[indx], indx); + return EXIT_FAILURE; + } + indx = indx + 1; + } + } + LOG_INFOMSG("%s", "Success!"); + return EXIT_SUCCESS; +} + +static int read_results(const char *filenm, + struct GFAST_cmt_props_struct *cmt_props, + struct GFAST_offsetData_struct *cmt_data, + struct GFAST_cmtResults_struct *cmt, + double *SA_lat, double *SA_lon, double *SA_dep) +{ + FILE *infl; + char cline[128]; + double mxx, myy, mzz, mxy, mxz, myz; + int i, idep, ierr, ldevi; + ierr = 1; + infl = fopen(filenm, "r"); + // line 1 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%d %d %d %d %d %d %d %lf %lf\n", + &cmt_data->nsites, &cmt_props->ngridSearch_deps, + &cmt_props->ngridSearch_lats, &cmt_props->ngridSearch_lons, + &cmt_props->utm_zone, &cmt_props->min_sites, + &ldevi, &cmt_props->window_vel, + &cmt_props->window_avg); + cmt_props->ldeviatoric = true; + if (ldevi != 1){cmt_props->ldeviatoric = false;} + // line 2 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf\n", SA_lat, SA_lon, SA_dep); + cmt_data->ubuff = memory_calloc64f(cmt_data->nsites); + cmt_data->ebuff = memory_calloc64f(cmt_data->nsites); + cmt_data->nbuff = memory_calloc64f(cmt_data->nsites); + cmt_data->wtu = memory_calloc64f(cmt_data->nsites); + cmt_data->wte = memory_calloc64f(cmt_data->nsites); + cmt_data->wtn = memory_calloc64f(cmt_data->nsites); + cmt_data->sta_lat = memory_calloc64f(cmt_data->nsites); + cmt_data->sta_lon = memory_calloc64f(cmt_data->nsites); + cmt_data->sta_alt = memory_calloc64f(cmt_data->nsites); + cmt_data->lactive = ISCL_memory_calloc__bool(cmt_data->nsites); + cmt_data->lmask = ISCL_memory_calloc__bool(cmt_data->nsites); + // cmt data + for (i=0; insites; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf\n", + &cmt_data->sta_lat[i], &cmt_data->sta_lon[i], + &cmt_data->sta_alt[i], + &cmt_data->nbuff[i], &cmt_data->ebuff[i], &cmt_data->ubuff[i]); + cmt_data->wtu[i] = 1.0; + cmt_data->wte[i] = 1.0; + cmt_data->wtn[i] = 1.0; + cmt_data->lactive[i] = true; + } + // Results + depths in grid search + cmt->nsites = cmt_data->nsites; + cmt->ndeps = cmt_props->ngridSearch_deps; + cmt->nlats = cmt_props->ngridSearch_lats; + cmt->nlons = cmt_props->ngridSearch_lons; + cmt->l2 = memory_calloc64f(cmt->ndeps); + cmt->pct_dc = memory_calloc64f(cmt->ndeps); + cmt->objfn = memory_calloc64f(cmt->ndeps); + cmt->mts = memory_calloc64f(cmt->ndeps*6); + cmt->str1 = memory_calloc64f(cmt->ndeps); + cmt->str2 = memory_calloc64f(cmt->ndeps); + cmt->dip1 = memory_calloc64f(cmt->ndeps); + cmt->dip2 = memory_calloc64f(cmt->ndeps); + cmt->rak1 = memory_calloc64f(cmt->ndeps); + cmt->rak2 = memory_calloc64f(cmt->ndeps); + cmt->Mw = memory_calloc64f(cmt->ndeps); + cmt->srcDepths = memory_calloc64f(cmt->ndeps); + cmt->EN = memory_calloc64f(cmt->ndeps*cmt_data->nsites); + cmt->NN = memory_calloc64f(cmt->ndeps*cmt_data->nsites); + cmt->UN = memory_calloc64f(cmt->ndeps*cmt_data->nsites); + cmt->Einp = memory_calloc64f(cmt_data->nsites); + cmt->Ninp = memory_calloc64f(cmt_data->nsites); + cmt->Uinp = memory_calloc64f(cmt_data->nsites); + for (idep=0; idepndeps; idep++) + { + // depth + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf\n", &cmt->srcDepths[idep]); + // moment tensor + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf\n", + &mxx, &myy, &mzz, &mxy, &mxz, &myz); + cmt->mts[6*idep+0] = mxx; + cmt->mts[6*idep+1] = myy; + cmt->mts[6*idep+2] = mzz; + cmt->mts[6*idep+3] = mxy; + cmt->mts[6*idep+4] = mxz; + cmt->mts[6*idep+5] = myz; + // rest of information + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf %lf %lf\n", + &cmt->str1[idep], &cmt->dip1[idep], &cmt->rak1[idep], + &cmt->str2[idep], &cmt->dip2[idep], &cmt->rak2[idep], + &cmt->Mw[idep], &cmt->objfn[idep]); + if (cmt->rak1[idep] > 180.0){cmt->rak1[idep] = cmt->rak1[idep] - 360.0;} + if (cmt->rak2[idep] > 180.0){cmt->rak2[idep] = cmt->rak2[idep] - 360.0;} + } + fclose(infl); + ierr = 0; +ERROR:; + return ierr; +} +//============================================================================// +int cmt_inversion_test(void) +{ + const char *filenm = "files/final_cmt.maule.txt\0"; + struct GFAST_cmt_props_struct cmt_props; + struct GFAST_offsetData_struct cmt_data; + struct GFAST_cmtResults_struct cmt_ref, cmt; + double SA_lat, SA_lon, SA_dep; + int i, ierr, j; + memset(&cmt_props, 0, sizeof(cmt_props)); + memset(&cmt_data, 0, sizeof(cmt_data)); + memset(&cmt_ref, 0, sizeof(cmt_ref)); + memset(&cmt, 0, sizeof(cmt)); + ierr = read_results(filenm, + &cmt_props, + &cmt_data, + &cmt_ref, + &SA_lat, &SA_lon, &SA_dep); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading input file"); + return EXIT_FAILURE; + } + // Set space + cmt.nsites = cmt_ref.nsites; + cmt.ndeps = cmt_ref.ndeps; + cmt.nlats = cmt_ref.nlats; + cmt.nlons = cmt_ref.nlons; + cmt.l2 = memory_calloc64f(cmt.ndeps); + cmt.pct_dc = memory_calloc64f(cmt.ndeps); + cmt.objfn = memory_calloc64f(cmt.ndeps); + cmt.mts = memory_calloc64f(cmt.ndeps*6); + cmt.str1 = memory_calloc64f(cmt.ndeps); + cmt.str2 = memory_calloc64f(cmt.ndeps); + cmt.dip1 = memory_calloc64f(cmt.ndeps); + cmt.dip2 = memory_calloc64f(cmt.ndeps); + cmt.rak1 = memory_calloc64f(cmt.ndeps); + cmt.rak2 = memory_calloc64f(cmt.ndeps); + cmt.Mw = memory_calloc64f(cmt.ndeps); + cmt.srcDepths = memory_calloc64f(cmt.ndeps); + cmt.EN = memory_calloc64f(cmt.ndeps*cmt_data.nsites); + cmt.NN = memory_calloc64f(cmt.ndeps*cmt_data.nsites); + cmt.UN = memory_calloc64f(cmt.ndeps*cmt_data.nsites); + cmt.Einp = memory_calloc64f(cmt_data.nsites); + cmt.Ninp = memory_calloc64f(cmt_data.nsites); + cmt.Uinp = memory_calloc64f(cmt_data.nsites); + cmt.lsiteUsed = memory_calloc8l(cmt_data.nsites); + for (i=0; i 360.0){azi = azi - 360.0;} + if (azi < 180.0){backazi[i] = azi + 180.0;} + if (azi > 180.0){backazi[i] = azi - 180.0;} + if (azi == 180.0){backazi[i] = 0.0;} + // Relative source receiver location in (x,y,z) coordinates + xrs[i] = x1 - x2; + yrs[i] = y1 - y2; + zrs[i] = SA_dep*1000.0; + azims[i] = 90.0 - azi + 180.0; + } // Loop on stations + // Compute the corresponding Green's functions + G = (double *)calloc(ldg*n6, sizeof(double)); + ierr = GFAST_CMT__setForwardModel(l1, false, + xrs, yrs, zrs, azims, + G); + if (ierr != 0){ + printf("%s: Failed to compute greens functions\n", __func__); + return -1; + } + indx = 0; + for (i=0; i 1.e-7){ + printf("%s: Failed to compute G!\n", __func__); + printf("%e %e\n",G[indx],Gref[indx]); + return -1; + } + indx = indx + 1; + } + } + + free(G); + free(xrs); + free(yrs); + free(zrs); + free(backazi); + free(azims); + printf("%s: Success!\n", __func__); + return 0; +} +*/ diff --git a/unit_tests/coord.c b/unit_tests/coord.c new file mode 100644 index 00000000..49b144f0 --- /dev/null +++ b/unit_tests/coord.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include "gfast.h" + +int coord_test_ll2utm(void); + +int coord_test_ll2utm(void) +{ + double lat, lat0, lon, lon0,utmEast0, utmEast1, utmEastReference, + utmNorthReference, utmNorth0, utmNorth1; + int utm_unknown_zone, utm_zone, utm_zone_ref; + bool lnorthp; + // Seattle + lat = 47.6062; + lon =-122.3321; + utmEastReference = 550200.2133598323; //550200.21; + utmNorthReference = 5272748.591307523; //5272748.59; + utm_zone_ref = 10; + utm_zone = 10; + utm_unknown_zone =-1; + GFAST_core_coordtools_ll2utm(lat, lon, &utmNorth0, &utmEast0, + &lnorthp, &utm_unknown_zone); + GFAST_core_coordtools_ll2utm(lat, lon + 360.0, &utmNorth1, &utmEast1, + &lnorthp, &utm_zone); + if (!lnorthp) + { + LOG_ERRMSG("%s", "Wrong hemisphere"); + return EXIT_FAILURE; + } + if (utm_unknown_zone != utm_zone_ref || utm_zone != utm_zone_ref) + { + LOG_ERRMSG("%s", "Failed to compute utm_zone"); + return EXIT_FAILURE; + } + if (fabs(utmEast0 - utmEastReference) > 0.001 || + fabs(utmEast1 - utmEastReference) > 0.001) + { + LOG_ERRMSG("%s", "Failed to get easting"); + return EXIT_FAILURE; + } + if (fabs(utmNorth0 - utmNorthReference) > 0.001 || + fabs(utmNorth1 - utmNorthReference) > 0.001) + { + LOG_ERRMSG("%s", "Failed to get northing"); + return EXIT_FAILURE; + } + // Recover + GFAST_core_coordtools_utm2ll(utm_zone, lnorthp, utmNorth0, utmEast0, + &lat0, &lon0); + if (fabs(lat0 - lat) > 1.e-5) + { + LOG_ERRMSG("%s", "Failed to recover lat"); + return EXIT_FAILURE; + } + if ((fabs(lon0 - lon) > 1.e-5) && (fabs(lon0 - 360.0 - lon) > 1.e-5)) + { + LOG_ERRMSG("Failed to recover lon %f %f", lon, lon0); + return EXIT_FAILURE; + } + // Santiago + lat =-33.4489; + lon =-70.6693; + utmEastReference = 344846.7203081217; //344846.72 + utmNorthReference = 6297700.155849966; //6297700.16 + utm_zone_ref = 19; + utm_zone = 19; + utm_unknown_zone =-1; + GFAST_core_coordtools_ll2utm(lat, lon + 360.0, &utmNorth0, &utmEast0, + &lnorthp, &utm_unknown_zone); + GFAST_core_coordtools_ll2utm(lat, lon, &utmNorth1, &utmEast1, + &lnorthp, &utm_zone); + if (lnorthp) + { + LOG_ERRMSG("%s", "Wrong hemisphere 2"); + return EXIT_FAILURE; + } + if (utm_unknown_zone != utm_zone_ref || utm_zone != utm_zone_ref) + { + LOG_ERRMSG("%s", "Failed to compute utm_zone 2"); + return EXIT_FAILURE; + } + if (fabs(utmEast0 - utmEastReference) > 0.001 || + fabs(utmEast1 - utmEastReference) > 0.001) + { + LOG_ERRMSG("Failed to get easting 2 %f %f", utmEast0, utmEast1); + return EXIT_FAILURE; + } + if (fabs(utmNorth0 - utmNorthReference) > 0.001 || + fabs(utmNorth1 - utmNorthReference) > 0.001) + { + LOG_ERRMSG("%s", "Failed to get northing 2"); + return EXIT_FAILURE; + } + // Recover + GFAST_core_coordtools_utm2ll(utm_zone, lnorthp, utmNorth0, utmEast0, + &lat0, &lon0); + if (fabs(lat0 - lat) > 1.e-5) + { + LOG_ERRMSG("%s", "Failed to recover lat 2"); + return EXIT_FAILURE; + } + if ((fabs(lon0 - lon) > 1.e-5) && (fabs(lon0 - 360.0 - lon) > 1.e-5)) + { + LOG_ERRMSG("Failed to recover lon 2 %f %f", lon, lon0); + return EXIT_FAILURE; + } + LOG_INFOMSG("%s", "Success!"); + return EXIT_SUCCESS; +} + +/* + int nstat = 9; + double xutm_ref[9] = {343323.63430894, 372234.82479856, 423564.1189781, + 203806.59303668, 136995.95792472, 723723.33606821, + 379490.42778671, 409390.05963976, 391311.1466216}; + double yutm_ref[9] = {5411348.46298294, 4743799.38939605, 5037463.63108665, + 5532670.66847299, 5622424.34340908, 4642449.79043267, + 5350682.38926825, 4525582.50275946, 4484576.434264}; + double stla[9] = { 48.83532872, 42.83609887, 45.48651503, + 49.87305293, 50.64035267, 41.90232489, + 48.29785467, 40.87630594, 40.50478709}; + double stlo[9] = {-125.13510527,-124.56334629,-123.97812400, + -127.12266484,-128.13499899,-120.30283244, + -124.62490719,-124.07537043,-124.28278289}; + double xutm, yutm; + int zone = 10, zone_out; + bool lnorth; + int i, ierr; + double lon0_deg =-123.0; + double tol = 1.e-3; // milimeters +*/ +/* + zone_out =-1; + for (i=0; i tol || + fabs(yutm - yutm_ref[i]) > tol){ + printf("%s: Failed to convert coordinate\n", fcnm); + return -1; + } + // For kicks check the original (note the tolerance is finer but + // that's because I computed the `reference' solution with GFAST + GFAST_coordtools__ll2utm(stla[i], stlo[i], + &yutm, &xutm, + &lnorth, &zone_out); + if (fabs(xutm - xutm_ref[i]) > 1.e-5 || + fabs(yutm - yutm_ref[i]) > 1.e-5 || + !lnorth){ + printf("%s: Failed to convert original coordinate\n", fcnm); + return -1; + } + } + LOG_INFOMSG("%s", "Success!"); + return EXIT_SUCCESS; +} +*/ diff --git a/unit_tests/ff.c b/unit_tests/ff.c new file mode 100644 index 00000000..06b76238 --- /dev/null +++ b/unit_tests/ff.c @@ -0,0 +1,683 @@ +#include +#include +#include +#include +#include +#include "gfast.h" +#include "iscl/memory/memory.h" + +int ff_meshPlane_test(void); +int ff_greens_test(void); +int ff_regularizer_test(void); +double *__read_grns(const char *fname, int *nrows, int *ncols, int *ierr); +struct sparseMatrix_coo_struct __read_treg(const char *fname, int *ierr); +int ff_inversion_test(void); +double *__read_xyz(const char *fname, int *l1, int *l2, int *ierr); +int __read_faultPlane(const char *fname, + int *utm_zone, + double *SA_lat, double *SA_lon, double *SA_dep, + double *flen_pct, double *fwid_pct, + double *Mw, double *strike, double *dip, + struct GFAST_faultPlane_struct *ff); + +struct sparseMatrix_coo_struct +{ + double *A; /*!< Values of sparse matrix [nnz] */ + int *irn; /*!< Row numbers of non-zeros [nnz] */ + int *jcn; /*!< Column number of non-zeros [nnz] */ + int nnz; /*!< Number of non-zeros in COO matrix */ +}; + +static bool lequal(double a, double b, double tol) +{ + if (a == 0.0 && b == 0.0){return true;} + if (fabs(a - b)/fabs(a + b) > tol){return false;} + return true; +} + +int __read_faultPlane(const char *fname, + int *utm_zone, + double *SA_lat, double *SA_lon, double *SA_dep, + double *flen_pct, double *fwid_pct, + double *Mw, double *strike, double *dip, + struct GFAST_faultPlane_struct *ff) +{ + FILE *infl; + char cline[128]; + int i, ierr, l2; + ierr = 1; + infl = fopen(fname, "r"); + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf %lf %lf %d %d %d\n", + SA_lat, SA_lon, SA_dep, + flen_pct, fwid_pct, + Mw, strike, dip, + &ff->nstr, &ff->ndip, utm_zone); + l2 = ff->ndip*ff->nstr; + ff->fault_xutm = ISCL_memory_calloc__double(l2); + ff->fault_yutm = ISCL_memory_calloc__double(l2); + ff->fault_alt = ISCL_memory_calloc__double(l2); + ff->strike = ISCL_memory_calloc__double(l2); + ff->dip = ISCL_memory_calloc__double(l2); + ff->length = ISCL_memory_calloc__double(l2); + ff->width = ISCL_memory_calloc__double(l2); + for (i=0; ifault_xutm[i], &ff->fault_yutm[i], &ff->fault_alt[i], + &ff->strike[i], &ff->dip[i], &ff->length[i], &ff->width[i]); + } +ERROR:; + fclose(infl); + ierr = 0; + return ierr; +} + +static int read_results(const char *fname, + struct GFAST_ff_props_struct *ff_props, + struct GFAST_offsetData_struct *ff_data, + struct GFAST_ffResults_struct *ff) + //double *SA_lat, double *SA_lon, double *SA_dep) +{ + FILE *infl; + char cline[128]; + int i, ierr, l2; + ierr = 1; + infl = fopen(fname, "r"); + // line 1 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%d %d %d %d %d %lf %lf %lf %lf\n", + &ff_props->nstr, &ff_props->ndip, &ff_props->utm_zone, + &ff_props->nfp, &ff_props->min_sites, + &ff_props->window_vel, &ff_props->window_avg, + &ff_props->flen_pct, &ff_props->fwid_pct); + l2 = ff_props->nstr*ff_props->ndip; + // line 2 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf\n", &ff->SA_lat, &ff->SA_lon, + &ff->SA_dep, &ff->SA_mag); + // line 3 + ff->nfp = ff_props->nfp; + ff->fp = (struct GFAST_faultPlane_struct *) + calloc((size_t) ff->nfp, sizeof(struct GFAST_faultPlane_struct)); + ff->vr = ISCL_memory_calloc__double(ff->nfp); + ff->Mw = ISCL_memory_calloc__double(ff->nfp); + ff->str = ISCL_memory_calloc__double(ff->nfp); + ff->dip = ISCL_memory_calloc__double(ff->nfp); + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf\n", + &ff->str[0], &ff->str[1], &ff->dip[0], &ff->dip[1]); + // line 4 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%d\n", &ff_data->nsites); + ff_data->ubuff = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->ebuff = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->nbuff = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->wtu = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->wte = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->wtn = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->sta_lat = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->sta_lon = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->sta_alt = ISCL_memory_calloc__double(ff_data->nsites); + ff_data->lactive = ISCL_memory_calloc__bool(ff_data->nsites); + ff_data->lmask = ISCL_memory_calloc__bool(ff_data->nsites); + // ff data + for (i=0; insites; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf %lf %lf\n", + &ff_data->sta_lat[i], &ff_data->sta_lon[i], + &ff_data->sta_alt[i], + &ff_data->nbuff[i], &ff_data->ebuff[i], &ff_data->ubuff[i]); + ff_data->wtu[i] = 1.0; + ff_data->wte[i] = 1.0; + ff_data->wtn[i] = 1.0; + ff_data->lactive[i] = true; + } + // allocate space for fault + for (i=0; infp; i++) + { + ff->fp[i].maxobs = ff_data->nsites; + ff->fp[i].nstr = ff_props->nstr; + ff->fp[i].ndip = ff_props->ndip; + ff->fp[i].sslip = ISCL_memory_calloc__double(l2); + ff->fp[i].dslip = ISCL_memory_calloc__double(l2); + } + // ff results vr + mag + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf\n", + &ff->vr[0], &ff->vr[1], &ff->Mw[0], &ff->Mw[1]); + // ff results slip models + for (i=0; ifp[0].dslip[i], &ff->fp[0].sslip[i], + &ff->fp[1].dslip[i], &ff->fp[1].sslip[i]); + } + fclose(infl); + ierr = 0; +ERROR:; + return ierr; +} + +struct sparseMatrix_coo_struct __read_treg(const char *fname, int *ierr) +{ + FILE *infl; + char cline[128]; + struct sparseMatrix_coo_struct coo; + int i; + *ierr = 1; + memset(&coo, 0, sizeof(struct sparseMatrix_coo_struct)); + infl = fopen(fname, "r"); + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){return coo;} + sscanf(cline, "%d\n", &coo.nnz); + coo.A = (double *)calloc((size_t) coo.nnz, sizeof(double)); + coo.irn = (int *)calloc((size_t) coo.nnz, sizeof(double)); + coo.jcn = (int *)calloc((size_t) coo.nnz, sizeof(double)); + for (i=0; i 0.0) + { + for (inz=0; inz 1.e-6) + if (!lequal(Gmat[i], grns1[i], tol)) + { + LOG_ERRMSG("Error with grns1 %e %e %e", + Gmat[i], grns1[i], + fabs( (Gmat[i] - grns1[i])/grns1[i] )); + return EXIT_FAILURE; + } + } + // dip = 0.0 + for (i=0; i 1.e-6) + if (!lequal(Gmat[i], grns2[i], tol)) + { + LOG_ERRMSG("Error with grns2 %e %e", + Gmat[i], grns2[i]); + return EXIT_FAILURE; + } + } + free(Gmat); + free(grns1); + free(grns2); + free(dip); + free(strike); + free(width); + free(length); + free(xrs); + free(yrs); + free(zrs); + LOG_INFOMSG("%s", "Success!"); + return EXIT_SUCCESS; +} +//============================================================================// +int ff_meshPlane_test(void) +{ + const char *fname[2] = {"files/final_fp1.maule.txt\0", + "files/final_fp2.maule.txt\0"}; + struct GFAST_faultPlane_struct ff, ff_ref; + double SA_lat, SA_lon, SA_dep, Mw, flen_pct, fwid_pct, strike, dip; + int i, ierr, ifp, l2, utm_zone; + int verbose = 0; + const int nfp = 2; + for (ifp=0; ifp + + + 3.4000 + 0.5000 + 38.8000 + 0.5000 + -122.8200 + 0.5000 + 8.0000 + 5.0000 + 2011-08-11T23:21:07.753Z + 20.0000 + 0.8000 + + + + + STA1.NET.CHAN.LOC + 1234.5600 + 33.1200 + -123.4500 + + + + STA2.NET.CHAN.LOC + 2345.6700 + 32.8500 + -124.0200 + + + + + + STA1.NET.CHAN.LOC + 2334.4500 + 33.1200 + -123.4500 + + + + STA2.NET.CHAN.LOC + 1893.2000 + 32.8500 + -124.0200 + + + + + diff --git a/unit_tests/mt.c b/unit_tests/mt.c new file mode 100644 index 00000000..c35415be --- /dev/null +++ b/unit_tests/mt.c @@ -0,0 +1,509 @@ +#include +#include +#include +#include +#include "gfast.h" +#ifdef GFAST_USE_INTEL +#include +#else +#include +#endif +#include "cmopad.h" + +struct mt_t +{ + double mt[6]; + double tax[3]; + double bax[3]; + double pax[3]; + double sdr1[3]; //strike dip rake; fault plane 2 + double sdr2[3]; //strike dip rake; fault plane 1 + double mag; + double exp; +}; + +int decompose(int, struct mt_t); +int compareEV(double tol, double e, double *xe, double *xref); +int compareSDR(double tol, double *sdr1, double *sdr2, + double *sdr1ref, double *sdr2ref); +int cmopad_test(int verb); + +int cmopad_test(int verb) +{ + /*! + * Moment tensor decomposition verification: + * http://www.globalcmt.org/cgi-bin/globalcmt-cgi-bin/CMT4/form?itype=ymd&yr=2014&mo=1&day=1&otype=ymd&oyr=2014&omo=1&oday=5&jyr=2014&jday=1&ojyr=1976&ojday=1&nday=1&lmw=0&umw=10&lms=0&ums=10&lmb=0&umb=10&llat=-90&ulat=90&llon=-180&ulon=180&lhd=0&uhd=1000<s=-9999&uts=9999&lpe1=0&upe1=90&lpe2=0&upe2=90&list=5 + */ + // Event 1 + struct mt_t mt; + int n6 = 6, incx = 1, ierr; + //double mt[5]; + double xscal; + //-----------------------------------1------------------------------------// + if (verb > 0){printf("Testing source 1...\n");} + mt.exp = 23.0 - 7.0; + mt.mag = 5.1; + mt.mt[0] =-4.360; + mt.mt[1] = 3.200; + mt.mt[2] = 1.170; + mt.mt[3] =-0.794; + mt.mt[4] = 1.650; + mt.mt[5] = 2.060; + mt.sdr1[0] = 77.0; + mt.sdr1[1] = 47.0; + mt.sdr1[2] =-62.0; + mt.sdr2[0] = 219.0; + mt.sdr2[1] = 50.0; + mt.sdr2[2] =-117.0; + mt.tax[0] = 4.49; + mt.tax[1] = 1.0; + mt.tax[2] = 328.0; + mt.bax[0] = 0.56; + mt.bax[1] = 20.0; + mt.bax[2] = 237.0; + mt.pax[0] =-5.04; + mt.pax[1] = 70.0; + mt.pax[2] = 61.0; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("Error decomposing 1\n"); + return EXIT_FAILURE; + } + if (ierr != 0) + { + printf("mopad failed test 1\n"); + return EXIT_FAILURE; + } + //--------------------------------------2----------------------------------// + if (verb > 0){printf("Testing source 1...\n");} + mt.exp = 23.0 - 7.0; + mt.mag = 5.0; + mt.mt[0] =-4.480; + mt.mt[1] = 1.440; + mt.mt[2] = 3.040; + mt.mt[3] = 0.603; + mt.mt[4] = 0.722; + mt.mt[5] =-1.870; + mt.sdr1[0] =316.0; + mt.sdr1[1] = 44.0; + mt.sdr1[2] =-105.0; + mt.sdr2[0] = 157.0; + mt.sdr2[1] = 48.0; + mt.sdr2[2] =-76.0; + mt.tax[0] = 4.28; + mt.tax[1] = 2.0; + mt.tax[2] = 237.0; + mt.bax[0] = 0.37; + mt.bax[1] = 10.0; + mt.bax[2] = 327.0; + mt.pax[0] =-4.66; + mt.pax[1] = 79.0; + mt.pax[2] =137.0; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("mopad failed test 2\n"); + return EXIT_FAILURE; + } + //------------------------------------3-----------------------------------// + if (verb > 0){printf("Testing source 3...\n");} + mt.exp = 23.0 - 7.0; + mt.mag = 4.9; + mt.mt[0] =-2.460; + mt.mt[1] = 0.207; + mt.mt[2] = 2.250; + mt.mt[3] = 0.793; + mt.mt[4] = 0.267; + mt.mt[5] =-0.363; + mt.sdr1[0] =335.0; + mt.sdr1[1] = 46.0; + mt.sdr1[2] =-113.0; + mt.sdr2[0] = 186.0; + mt.sdr2[1] = 49.0; + mt.sdr2[2] =-68.0; + mt.tax[0] = 2.32; + mt.tax[1] = 2.0; + mt.tax[2] = 261.0; + mt.bax[0] = 0.38; + mt.bax[1] = 16.0; + mt.bax[2] = 351.0; + mt.pax[0] =-2.70; + mt.pax[1] = 74.0; + mt.pax[2] =165.0; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("mopad failed test 3\n"); + return EXIT_FAILURE; + } + //-----------------------------------4------------------------------------// + if (verb > 0){printf("Testing source 4...\n");} + mt.exp = 23.0 - 7.0; + mt.mag = 4.9; + mt.mt[0] =-2.270; + mt.mt[1] = 0.058; + mt.mt[2] = 2.210; + mt.mt[3] = 0.079; + mt.mt[4] =-0.737; + mt.mt[5] = 0.246; + mt.sdr1[0] =190.0; + mt.sdr1[1] = 36.0; + mt.sdr1[2] =-84.0; + mt.sdr2[0] = 3.0; + mt.sdr2[1] = 54.0; + mt.sdr2[2] =-94.0; + mt.tax[0] = 2.35; + mt.tax[1] = 9.0; + mt.tax[2] = 96.0; + mt.bax[0] = 0.04; + mt.bax[1] = 4.0; + mt.bax[2] = 5.0; + mt.pax[0] =-2.39; + mt.pax[1] = 80.0; + mt.pax[2] =253.0; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("mopad failed test 4\n"); + return EXIT_FAILURE; + } + //-----------------------------------5------------------------------------// + if (verb > 0){printf("Testing source 5...\n");} + mt.exp = 26.0 - 7.0; + mt.mag = 6.5; + mt.mt[0] = 0.745; + mt.mt[1] =-0.036; + mt.mt[2] =-0.709; + mt.mt[3] =-0.242; + mt.mt[4] =-0.048; + mt.mt[5] = 0.208; + mt.sdr1[0] =181.0; + mt.sdr1[1] = 47.0; + mt.sdr1[2] =114.0; + mt.sdr2[0] = 328.0; + mt.sdr2[1] = 48.0; + mt.sdr2[2] = 67.0; + mt.tax[0] = 0.82; + mt.tax[1] = 73.0; + mt.tax[2] = 166.0; + mt.bax[0] =-0.05; + mt.bax[1] = 17.0; + mt.bax[2] = 344.0; + mt.pax[0] =-0.77; + mt.pax[1] = 1.0; + mt.pax[2] = 74.0; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("mopad failed test 5\n"); + return EXIT_FAILURE; + } + //-----------------------------------6------------------------------------// + if (verb > 0){printf("Testing source 6...\n");} + mt.exp = 24.0 - 7.0; + mt.mag = 5.3; + mt.mt[0] = 0.700; + mt.mt[1] =-0.883; + mt.mt[2] = 0.183; + mt.mt[3] = 0.260; + mt.mt[4] = 0.289; + mt.mt[5] = 0.712; + mt.sdr1[0] =329.0; + mt.sdr1[1] = 54.0; + mt.sdr1[2] =141.0; + mt.sdr2[0] = 85.0; + mt.sdr2[1] = 59.0; + mt.sdr2[2] = 43.0; + mt.tax[0] = 1.01; + mt.tax[1] = 51.0; + mt.tax[2] = 300.0; + mt.bax[0] = 0.24; + mt.bax[1] = 39.0; + mt.bax[2] = 113.0; + mt.pax[0] =-1.25; + mt.pax[1] = 3.0; + mt.pax[2] = 206.; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("mopad failed test 6\n"); + return EXIT_FAILURE; + } + //-----------------------------------7------------------------------------// + if (verb > 0){printf("Testing source 7...\n");} + mt.exp = 23.0 - 7.0; + mt.mag = 5.0; + mt.mt[0] = 3.150; + mt.mt[1] =-2.470; + mt.mt[2] =-0.676; + mt.mt[3] = 1.650; + mt.mt[4] = 1.880; + mt.mt[5] =-1.470; + mt.sdr1[0] =252.0; + mt.sdr1[1] = 28.0; + mt.sdr1[2] =111.0; + mt.sdr2[0] = 49.0; + mt.sdr2[1] = 64.0; + mt.sdr2[2] = 79.0; + mt.tax[0] = 4.08; + mt.tax[1] = 69.0; + mt.tax[2] = 297.0; + mt.bax[0] = 0.01; + mt.bax[1] = 10.0; + mt.bax[2] = 54.0; + mt.pax[0] =-4.08; + mt.pax[1] = 18.0; + mt.pax[2] = 147.0; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("mopad failed test 7\n"); + return EXIT_FAILURE; + } + //-----------------------------------8------------------------------------// + if (verb > 0){printf("Testing source 8...\n");} + mt.exp = 23.0 - 7.0; + mt.mag = 4.8; + mt.mt[0] =-1.870; + mt.mt[1] = 0.488; + mt.mt[2] = 1.380; + mt.mt[3] =-0.057; + mt.mt[4] = 0.600; + mt.mt[5] = 0.664; + mt.sdr1[0] = 36.0; + mt.sdr1[1] = 38.0; + mt.sdr1[2] =-76.0; + mt.sdr2[0] = 199.0; + mt.sdr2[1] = 53.0; + mt.sdr2[2] =-101.0; + mt.tax[0] = 1.80; + mt.tax[1] = 8.0; + mt.tax[2] = 296.0; + mt.bax[0] = 0.18; + mt.bax[1] = 9.0; + mt.bax[2] = 205.0; + mt.pax[0] =-1.99; + mt.pax[1] = 78.0; + mt.pax[2] = 69.0; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("mopad failed test 8\n"); + return EXIT_FAILURE; + } + //-----------------------------------9------------------------------------// + if (verb > 0){printf("Testing source 9...\n");} + mt.exp = 23.0 - 7.0; + mt.mag = 5.0; + mt.mt[0] =-3.540; + mt.mt[1] = 1.040; + mt.mt[2] = 2.510; + mt.mt[3] =-0.474; + mt.mt[4] = 1.640; + mt.mt[5] = 1.530; + mt.sdr1[0] = 47.0; + mt.sdr1[1] = 38.0; + mt.sdr1[2] =-63.0; + mt.sdr2[0] = 195.0; + mt.sdr2[1] = 56.0; + mt.sdr2[2] =-109.0; + mt.tax[0] = 3.66; + mt.tax[1] = 10.0; + mt.tax[2] = 299.0; + mt.bax[0] = 0.45; + mt.bax[1] = 16.0; + mt.bax[2] =206.0; + mt.pax[0] =-4.10; + mt.pax[1] = 71.0; + mt.pax[2] = 58.0; + xscal = pow(10.0,mt.exp); + cblas_dscal(n6, xscal, mt.mt, incx); + ierr = decompose(0,mt); + if (ierr != 0) + { + printf("mopad failed test 9\n"); + return EXIT_FAILURE; + } + printf("cmopad_test: Success!\n"); + return EXIT_SUCCESS; +} + +//============================================================================// + +int compareEV(double tol, double e, double *xe, double *xref) +{ + if (fabs(xe[2]/pow(10.0,e) - xref[0]) > tol) + { + printf("Error on eigenvalue %f %f\n",xe[2]/pow(10.0,e),xref[0]); + return -1; + } + else if (fabs(round(xe[1]) - xref[1]) > tol) + { + printf("Error on plunge %f %f\n",xe[1], xref[1]); + return -1; + } + else if (fabs(round(xe[0]) - xref[2]) > tol) + { + printf("Error on the azimuth %f %f\n",xe[2],xref[0]); + return -1; + } + return 0; +} + +//============================================================================// + +int compareSDR(double tol, double *sdr1, double *sdr2, + double *sdr1ref, double *sdr2ref) +{ + int i, lfail, lpass, lrev; + + // Fault plane 1 may be fault plane 2, so leave the option to reverse + lpass = 0; //Hope for the worst + for (lrev=0; lrev < 2; lrev++) + { + lfail = 0; + for (i=0; i<3; i++) + { + if (lrev == 0) + { + if (fabs(sdr1[i] - sdr1ref[i]) > tol) + { + lfail = 1; + break; + } + if (fabs(sdr2[i] - sdr2ref[i]) > tol) + { + lfail = 1; + break; + } + } + else + { + if (fabs(sdr2[i] - sdr1ref[i]) > tol) + { + lfail = 1; + break; + } + if (fabs(sdr1[i] - sdr2ref[i]) > tol) + { + lfail = 1; + break; + } + } // End check on reversal + } + if (lfail == 1) + { + lpass = 1; + break; + } + } // Loop on reverse + return lpass; +} +//============================================================================// + +int decompose(int iverb, struct mt_t mt) +{ + struct cmopad_struct src; + const char *fcnm = "decompose\0"; + enum cmopad_basis_enum cin, cloc; + double M[3][3], pax[3], bax[3], tax[3]; + int ierr; + M[0][0] = mt.mt[0]; //Mrr + M[1][1] = mt.mt[1]; //Mtt + M[2][2] = mt.mt[2]; //Mpp + M[0][1] = M[1][0] = mt.mt[3]; //Mrt + M[0][2] = M[2][0] = mt.mt[4]; //Mrp + M[1][2] = M[2][1] = mt.mt[5]; //Mtp + // Mopad works in North, East, Down frame but inversion is Up, South, East + cin = USE; + cloc = NED; + cmopad_basis_transformMatrixM33(M, cin, cloc); //USE -> NED + // Compute the isotropic, CLVD, DC decomposition + ierr = cmopad_standardDecomposition(M, &src); + if (ierr != 0) + { + printf("%s: Error in decomposition!\n", fcnm); + return -1; + } + // Compute the princple axes with corresponding strikes, dips, and rakes + ierr = cmopad_MT2PrincipalAxisSystem(iverb, &src); + if (ierr != 0) + { + printf("%s: Error computing principal axis\n",fcnm); + return -1; + } + // Compute the pressure, null, and, tension principal axes as len,az,plunge + cin = NED; //MoPaD is in north, east, down + ierr = cmopad_Eigenvector2PrincipalAxis(cin, src.eig_pnt[0], + src.p_axis, pax); + if (ierr != 0) + { + printf("%s: Error converting pax\n",fcnm); + return -1; + } + ierr = cmopad_Eigenvector2PrincipalAxis(cin, src.eig_pnt[1], + src.null_axis, bax); + if (ierr != 0){ + printf("%s: Error converting bax\n",fcnm); + return -1; + } + ierr = cmopad_Eigenvector2PrincipalAxis(cin, src.eig_pnt[2], + src.t_axis, tax); + if (ierr != 0) + { + printf("%s: Error converting tax\n",fcnm); + return -1; + } + // Check the strike/dip/rake + if (compareSDR(1.0, src.fp1, src.fp2, mt.sdr1, mt.sdr2) != 1) + { + printf("%s: Error computing strike/dip/rake\n",fcnm); + return -1; + } + //printf("%f\n",src.seismic_moment/(pow(10.0,mt.exp))); + if (fabs(src.moment_magnitude - mt.mag) > 0.1) + { + printf("%s: Error on magnitude\n", fcnm); + return -1; + } + if (compareEV(0.01, mt.exp, tax, mt.tax) != 0) + { + printf("%s: Error in tax\n",fcnm); + return -1; + } + if (compareEV(0.01, mt.exp, bax, mt.bax) != 0) + { + printf("%s: Error in bax\n",fcnm); + return -1; + } + if (compareEV(0.01, mt.exp, pax, mt.pax) != 0) + { + printf("%s: Error in pax\n", fcnm); + return -1; + } +/* + printf("%f %f %f\n",tax[2]/(pow(10.0,mt.exp)),tax[1],tax[0]); + printf("%f %f %f\n",bax[2]/(pow(10.0,mt.exp)),bax[1],bax[0]); + printf("%f %f %f\n",pax[2]/(pow(10.0,mt.exp)),pax[1],pax[0]); + printf("%f %f %f\n",src.fp1[0],src.fp1[1],src.fp1[2]); + printf("%f %f %f\n",src.fp2[0],src.fp2[1],src.fp2[2]); +*/ + return 0; +} diff --git a/unit_tests/numpy.c b/unit_tests/numpy.c new file mode 100644 index 00000000..fda48f99 --- /dev/null +++ b/unit_tests/numpy.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include "gfast.h" + +int numpy_lstsq_test() +{ + const char *fcnm = "numpy_lstsq_test\0"; + double *gmat, *gmatRow, *b, *x, *svals, *R, + RRef[9], sref[3], x1ref[3], diag[3], rcond; + int m = 10; + int n = 3; + int nrhs = 1; + int i, ierr, j, rank_out; + //------------------------------------------------------------------------// + // + // Set the projectile least squares problem Parameter Estimation and + // Inverse Problems - Aster et al. + gmat = (double *)calloc(m*n, sizeof(double)); + gmatRow = (double *)calloc(m*n, sizeof(double)); + b = (double *)calloc(m, sizeof(double)); + x = (double *)calloc(n, sizeof(double)); + for (i=0; i 1.e-12){ + printf("%s: Failed to solve least squares problem\n", fcnm); + return EXIT_FAILURE; + } + } + // Solve the least-squares problem with QR + ierr = numpy_lstsq__qr(LAPACK_COL_MAJOR, + m, n, nrhs, gmat, b, x, NULL); + if (ierr != 0){ + printf("%s: Failed test 1.1\n", fcnm); + return EXIT_FAILURE; + } + for (i=0; i 1.e-12){ + printf("%s: Failed to solve QR least squares problem\n", fcnm); + return EXIT_FAILURE; + } + } + // Get the R matrix + R = (double *)calloc(n*n, sizeof(double)); + ierr = numpy_lstsq__qr(LAPACK_COL_MAJOR, + m, n, nrhs, gmat, b, x, R); + if (ierr != 0){ + printf("%s: Failed test 1.1\n", fcnm); + return EXIT_FAILURE; + } + for (i=0; i 1.e-12){ + printf("%s: Failed to solve QR least squares problem 1.1\n", fcnm); + return EXIT_FAILURE; + } + for (j=0; j 1.e-12){ + printf("%s: R retrieval test 1.1 %f ", fcnm, R[j*n+i]); + return EXIT_FAILURE; + } + } + } + // Invert the R matrix + ierr = LAPACKE_dtrtri(LAPACK_COL_MAJOR, 'U', 'N', n, R, n); + for (i=0; i 1.e-12){ + printf("%s: Failed to compute diagonal 1.1 %f %f\n", + fcnm, diag[i], cblas_ddot(n, &R[n*i], 1, &R[n*i], 1)); + return EXIT_FAILURE; + } + } + // Do it again with row major format + ierr = numpy_lstsq__qr(LAPACK_ROW_MAJOR, + m, n, nrhs, gmatRow, b, x, R); + if (ierr != 0){ + printf("%s: Failed test 1.1\n", fcnm); + return EXIT_FAILURE; + } + for (i=0; i 1.e-12){ + printf("%s: Failed to solve QR least squares problem 1.2\n", fcnm); + return EXIT_FAILURE; + } + for (j=0; j 1.e-12){ + printf("%s: R retrieval test 1.2 %f ", fcnm, R[i*n+j]); + return EXIT_FAILURE; + } + } + } + // Invert the R matrix + ierr = LAPACKE_dtrtri(LAPACK_ROW_MAJOR, 'U', 'N', n, R, n); + for (i=0; i 1.e-12){ + printf("%s: Failed to compute diagonal\n", fcnm); + return EXIT_FAILURE; + } + } + // Solve the least squares problem and get the matrix rank + ierr = numpy_lstsq(LAPACK_COL_MAJOR, + m, n, nrhs, gmat, b, + NULL, x, &rank_out, svals); + if (rank_out != 3 || ierr != 0){ + printf("%s: Failed test 2\n", fcnm); + return EXIT_FAILURE; + } + for (i=0; i 1.e-12){ + printf("%s: Failed to solve least squares problem 2\n", fcnm); + return EXIT_FAILURE; + } + } + // Solve the least squares and get the rank and singular values + svals = (double *)calloc(fmin(m, n), sizeof(double)); + rcond =-1.0; + ierr = numpy_lstsq(LAPACK_COL_MAJOR, + m, n, nrhs, gmat, b, + &rcond, x, &rank_out, svals); + if (rank_out != 3 || ierr != 0){ + printf("%s: Failed test 3\n", fcnm); + return EXIT_FAILURE; + } + for (i=0; i 1.e-12 || + fabs(sref[i] - svals[i]) > 1.e-12){ + printf("%s: Failed to solve least squares problem 3\n", fcnm); + return EXIT_FAILURE; + } + } + // Free space + if (R != NULL){free(R);} + if (b != NULL){free(b);} + if (gmat != NULL){free(gmat);} + if (x != NULL){free(x);} + if (svals != NULL){free(svals);} + if (gmatRow != NULL){free(gmatRow);} + printf("%s: Success!\n", fcnm); + return EXIT_SUCCESS; +} diff --git a/unit_tests/pgd.c b/unit_tests/pgd.c new file mode 100644 index 00000000..49161500 --- /dev/null +++ b/unit_tests/pgd.c @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include +#include "gfast.h" +#include "iscl/memory/memory.h" + +int pgd_inversion_test(void); +int pgd_inversion_test2(void); + +static bool lequal(double a, double b, double tol) +{ + if (a == 0.0 && b == 0.0){return true;} + if (fabs(a - b)/fabs(a + b) > tol){return false;} + return true; +} + +int pgd_inversion_test(void) +{ + int verbose = 4; + double dist_tol = 6.0; + double disp_def = 0.01; + double IQR, M, VR; + double SA_lat = 47.19; + double SA_lon =-122.66; + double SA_dep = 57.0; + // stations: bamf, cabl, chzz, eliz, holb, neah, p058, p159 + int l1 = 9; + double wts[9]; + double stla[9] = { 48.83532872, 42.83609887, 45.48651503, + 49.87305293, 50.64035267, 41.90232489, + 48.29785467, 40.87630594, 40.50478709}; + double stlo[9] = {-125.13510527,-124.56334629,-123.97812400, + -127.12266484,-128.13499899,-120.30283244, + -124.62490719,-124.07537043,-124.28278289}; + double staAlt[9] = {0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0}; + double utmRecvNorthing[9], utmRecvEasting[9], Uest[9*1]; + double d[9] = {4, 7.1, 8, 3, 1, 9, 6, 5.5, 6.5}; + double srdist[9]; + double SA_xutm, SA_yutm, utmSrcEasting, utmSrcNorthing, xutm, yutm; + int zone = 10; + const int ndeps = 1; + bool lnorth; + int i, ierr; + ierr = 0; + // Compute source location + GFAST_core_coordtools_ll2utm(SA_lat, SA_lon, + &SA_yutm, &SA_xutm, + &lnorth, &zone); + utmSrcNorthing = SA_yutm; + utmSrcEasting = SA_xutm; + // Compute station locations + for (i=0; i 1.e-4) + { + LOG_ERRMSG("Failed to compute M %f", M); + return -1; + } +/* + if (fabs(VR - 6.1681204583368228) > 1.e-6){ + printf("%s: Failed to compute VR\n", __func__); + return -1; + } +*/ + LOG_INFOMSG("%s", "Success!"); + return EXIT_SUCCESS; +} + +static int read_results(const char *filenm, + struct GFAST_pgd_props_struct *pgd_props, + struct GFAST_peakDisplacementData_struct *pgd_data, + struct GFAST_pgdResults_struct *pgd, + double *SA_lat, double *SA_lon, double *SA_dep) +{ + FILE *infl; + char cline[128]; + int i, ierr; + //------------------------------------------------------------------------// + ierr = 1; + infl = fopen(filenm, "r"); + // line 1 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%d %d %d %d %lf %lf %lf\n", + &pgd_data->nsites, &pgd_props->ngridSearch_deps, + &pgd_props->utm_zone, &pgd_props->min_sites, + &pgd_props->dist_tol, &pgd_props->disp_def, + &pgd_props->window_vel); + // line 2 + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf\n", SA_lat, SA_lon, SA_dep); + // pgd data + pgd_data->pd = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->wt = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->sta_lat = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->sta_lon = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->sta_alt = ISCL_memory_calloc__double(pgd_data->nsites); + pgd_data->lmask = ISCL_memory_calloc__bool(pgd_data->nsites); + pgd_data->lactive = ISCL_memory_calloc__bool(pgd_data->nsites); + for (i=0; insites; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf %lf\n", + &pgd_data->sta_lat[i], &pgd_data->sta_lon[i], + &pgd_data->sta_alt[i], &pgd_data->pd[i]); + pgd_data->wt[i] = 1.0; + pgd_data->lactive[i] = true; + } + // Results + depths in grid search + pgd->nsites = pgd_data->nsites; + pgd->ndeps = pgd_props->ngridSearch_deps; + pgd->nlats = 1; + pgd->nlons = 1; + pgd->mpgd = ISCL_memory_calloc__double(pgd->ndeps); + pgd->mpgd_vr = ISCL_memory_calloc__double(pgd->ndeps); + pgd->dep_vr_pgd = ISCL_memory_calloc__double(pgd->ndeps); + pgd->iqr = ISCL_memory_calloc__double(pgd->ndeps); + pgd->UP = ISCL_memory_calloc__double(pgd->ndeps*pgd->nsites); + pgd->UPinp = ISCL_memory_calloc__double(pgd->nsites); + pgd->srcDepths = ISCL_memory_calloc__double(pgd->ndeps); + pgd->srdist = ISCL_memory_calloc__double(pgd->ndeps*pgd->nsites); + pgd->lsiteUsed = ISCL_memory_calloc__bool(pgd->nsites); + // (a) depths + for (i=0; indeps; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf\n", &pgd->srcDepths[i]); + } + // (b) results + for (i=0; indeps; i++) + { + memset(cline, 0, sizeof(cline)); + if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} + sscanf(cline, "%lf %lf %lf\n", + &pgd->mpgd[i], &pgd->mpgd_vr[i], &pgd->iqr[i]); + } + fclose(infl); + ierr = 0; +ERROR:; + return ierr; +} +//============================================================================// +/*! + * @brief Benchmark against the final result in Brendan's python scripts + */ +int pgd_inversion_test2(void) +{ + const char *filenm = "files/final_pgd.maule.txt\0"; + struct GFAST_pgd_props_struct pgd_props; + struct GFAST_peakDisplacementData_struct pgd_data; + struct GFAST_pgdResults_struct pgd_ref, pgd; + double SA_lat, SA_lon, SA_dep, age_of_event; + const double tol = 1.e-4; + int i, ierr; + memset(&pgd_props, 0, sizeof(pgd_props)); + memset(&pgd_data, 0, sizeof(pgd_data)); + memset(&pgd_ref, 0, sizeof(pgd_ref)); + memset(&pgd, 0, sizeof(pgd)); + age_of_event = 0; + ierr = read_results(filenm, + &pgd_props, + &pgd_data, + &pgd_ref, + &SA_lat, &SA_lon, &SA_dep); + if (ierr != 0) + { + LOG_ERRMSG("%s", "Error reading input file"); + return EXIT_FAILURE; + } + // Set space + pgd.nsites = pgd_ref.nsites; + pgd.ndeps = pgd_ref.ndeps; + pgd.nlats = 1; + pgd.nlons = 1; + pgd.mpgd = ISCL_memory_calloc__double(pgd.ndeps); + pgd.mpgd_vr = ISCL_memory_calloc__double(pgd.ndeps); + pgd.dep_vr_pgd = ISCL_memory_calloc__double(pgd.ndeps); + pgd.iqr = ISCL_memory_calloc__double(pgd.ndeps); + pgd.UP = ISCL_memory_calloc__double(pgd.ndeps*pgd.nsites); + pgd.UPinp = ISCL_memory_calloc__double(pgd.nsites); + pgd.srcDepths = ISCL_memory_calloc__double(pgd.ndeps); + pgd.srdist = ISCL_memory_calloc__double(pgd.ndeps*pgd.nsites); + pgd.lsiteUsed = ISCL_memory_calloc__bool(pgd.nsites); + for (i=0; i +#include +#include +#include +#include "gfast.h" + +int readCoreInfo_test(void); +/* +int GFAST_alert__parse__shakeAlertXML(const char *message, double SA_NAN, + struct GFAST_shakeAlert_struct *SA) +{ + struct coreInfo_struct core; + int ierr, length; + // Initialize + memset(SA, 0, sizeof(struct GFAST_shakeAlert_struct)); + memset(&core, 0, sizeof(struct coreInfo_struct)); + length = strlen(message); + if (length == 0){ + printf("%s: Error the message is empty\n", __func__); + return -1; + } + // Extract the pertinent shakeAlert information for GFAST + ierr = GFAST_xml_read__SACoreInfo(message, SA_NAN, &core); + if (ierr != 0){ + printf("%s: Error parsing core shakeAlert information\n", __func__); + }else{ + strcpy(SA->eventid, core.id); + SA->time = core.orig_time; + SA->lat = core.lat; + SA->lon = core.lon; + SA->dep = core.depth; + SA->mag = core.mag; + } + return 0; +} +*/ + +int readCoreInfo_test(void) +{ + FILE *xmlfl; + struct GFAST_shakeAlert_struct SA; + char *message = NULL; + long fsize; + int ierr; + // Read the message into memory + xmlfl = fopen("message.xml", "rb"); + fseek(xmlfl, 0, SEEK_END); + fsize = ftell(xmlfl); + rewind(xmlfl); + message = (char *)calloc((size_t) (fsize + 1), sizeof(char)); // +1 to null terminate + if (fread(message, (size_t) fsize, 1, xmlfl) == 0){ + printf("%s: Nothing read\n", __func__); + return EXIT_FAILURE; + } + fclose(xmlfl); + // Parse it + //ierr = GFAST_alert__parse__shakeAlertXML(message, SA_NAN, &SA); + ierr = eewUtils_parseCoreXML(message, SA_NAN, &SA); + free(message); + if (ierr != 0){ + printf("%s: Error getting shakeAlert info\n", __func__); + return EXIT_FAILURE; + } + // Check it + if (strcasecmp(SA.eventid, "4557299\0") != 0){ + printf("%s: Couldn't parse ID\n", __func__); + return EXIT_FAILURE; + } + if (fabs(SA.time - 1313104867.753000) > 1.e-4){ + printf("%s: Couldn't parse time\n", __func__); + return EXIT_FAILURE; + } + if (fabs(SA.mag - 3.4) > 1.e-4){ + printf("%s: Couldn't parse magnitude\n", __func__); + return EXIT_FAILURE; + } + if (fabs(SA.lat - 38.8) > 1.e-4){ + printf("%s: Couldn't parse latitude\n", __func__); + return EXIT_FAILURE; + } + + if (!(fabs(SA.lon - -122.82) < 1.e-4 || fabs(SA.lon - (-122.82 + 360.0)) < 1.e-4)) + { + printf("%s: Couldn't parse longitude %f %f\n", __func__, SA.lon, -122.82); + return EXIT_FAILURE; + } + if (fabs(SA.dep - 8.0) > 1.e-4){ + printf("%s: Couldn't parse depth\n", __func__); + return EXIT_FAILURE; + } + //printf("%f %f %f %f %f\n", SA.time, SA.mag, SA.lat, SA.lon, SA.dep); + printf("%s: Success!\n", __func__); + return EXIT_SUCCESS; +} + diff --git a/unit_tests/tests.c b/unit_tests/tests.c new file mode 100644 index 00000000..0ac4b95d --- /dev/null +++ b/unit_tests/tests.c @@ -0,0 +1,121 @@ +#include +#include + +int coord_test_ll2utm(void); +int pgd_inversion_test(void); +int pgd_inversion_test2(void); +int cmopad_test(int verb); +int readCoreInfo_test(void); +int cmt_greens_test(void); +int cmt_inversion_test(void); +int ff_greens_test(void); +int ff_meshPlane_test(void); +int ff_regularizer_test(void); +int ff_inversion_test(void); + +int main() +{ + int ierr; + + //------------------------------------------------------------------------// + // test the vital core utilities. if any of these fail then the program // + // will fail // + //------------------------------------------------------------------------// + printf("%s: Beginning core tests...\n", __func__); + ierr = readCoreInfo_test(); + if (ierr != 0) + { + printf("%s: Failed the coreInfo test\n", __func__); + return EXIT_FAILURE; + } + +/* + if (ierr != 0) + { + printf("%s: Failed the least-squares test!\n", __func__); + return EXIT_FAILURE; + } +*/ + + ierr = coord_test_ll2utm(); + if (ierr != 0) + { + printf("%s: Failed the latlon 2 utm test!\n", __func__); + return EXIT_FAILURE; + } + +/* + ierr = cmopad_test(0); + if (ierr != 0) + { + printf("%s: Failed MT decomposition!\n", __func__); + return EXIT_FAILURE; + } +*/ + + //------------------------------------------------------------------------// + // test the forward modeling and regularization matrices. if any of // + // these fail the inversions will fail. // + //------------------------------------------------------------------------// + printf("\n%s: Beginning matrix generation tests...\n", __func__); + ierr = cmt_greens_test(); + if (ierr != 0) + { + printf("%s: Failed to compute Greens functions!\n", __func__); + return EXIT_FAILURE; + } + + ierr = ff_greens_test(); + if (ierr != 0) + { + printf("%s: Failed the ff greens test\n", __func__); + return EXIT_FAILURE; + } + + ierr = ff_meshPlane_test(); + if (ierr != 0) + { + printf("%s: FAiled to meshPlane test\n", __func__); + return EXIT_FAILURE; + } + + ierr = ff_regularizer_test(); + if (ierr != 0) + { + printf("%s: Failed the ff regularizer test\n", __func__); + return EXIT_FAILURE; + } + + //------------------------------------------------------------------------// + // verify the inversions. // + //------------------------------------------------------------------------// + printf("\n%s: Beginning inversions tests...\n", __func__); + ierr = pgd_inversion_test(); + if (ierr != 0) + { + printf("%s: Failed PGD inversion test!\n", __func__); + return EXIT_FAILURE; + } + ierr = pgd_inversion_test2(); + if (ierr != 0) + { + printf("%s: Failed PGD inversion test2\n", __func__); + return EXIT_FAILURE; + } + + ierr = cmt_inversion_test(); + if (ierr != 0) + { + printf("%s: Failed CMT inversion test\n", __func__); + return EXIT_FAILURE; + } + + ierr = ff_inversion_test(); + if (ierr != 0) + { + printf("%s: Failed FF Inversion test\n", __func__); + return EXIT_FAILURE; + } + printf("%s: All tests passed\n", __func__); + return EXIT_SUCCESS; +} From ecd4bf549357431236f47fd0463be2842985bfda Mon Sep 17 00:00:00 2001 From: Claude Felizardo Date: Tue, 3 Jan 2023 21:50:47 +0000 Subject: [PATCH 03/18] Updated property generator script to create GTESTs, updated Makefiles to make use of the auto-generated files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..97e33f5e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# local files to be ignored by git + +src/gfast_eew From 663246b095d82040d3b6e802f9f021d1e2f7f718 Mon Sep 17 00:00:00 2001 From: Andrew Good Date: Wed, 4 Jan 2023 00:09:09 +0000 Subject: [PATCH 04/18] Merge AUTO_UT updates --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..97e33f5e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# local files to be ignored by git + +src/gfast_eew From 74e7c14a0143a1d032dd34feaad68c688535ceb2 Mon Sep 17 00:00:00 2001 From: Carl Ulberg Date: Wed, 18 Jan 2023 19:08:25 +0000 Subject: [PATCH 05/18] GFAST v1.2.2 - add q channel and logging/timing updates --- include/dmlibWrapper.h | 19 +++- include/gfast_config.h | 2 +- include/gfast_core.h | 14 +-- include/gfast_struct.h | 7 +- include/gfast_traceBuffer.h | 2 +- run/bin/gfast_eew_env.sh | 12 +++ run/bin/run_gfast.sh | 9 +- run/params/pgd_threshold_PW.txt | 96 ++++++++++++++--- src/core/data/initialize.c | 1 + src/core/data/readMetaDataFile.c | 30 ++++-- src/core/data/readSiteMaskFile.c | 19 +++- src/core/waveformProcessor/Makefile | 2 +- src/core/waveformProcessor/parseQChannel.c | 68 ++++++++++++ src/core/waveformProcessor/peakDisplacement.c | 39 +++++-- .../peakDisplacementHelper.c | 30 ++---- src/dmlib/dmlibWrapper.cpp | 89 ++++++++++++--- src/eewUtils/driveGFAST.c | 1 + src/gfast_eew.c | 52 ++++++++- src/tests/CoreWaveformProcessorUT.cc | 102 ++++++++++-------- src/traceBuffer/ewrr/classifyRetval.c | 43 +++++--- src/traceBuffer/ewrr/settb2DataFromGFAST.c | 6 +- src/traceBuffer/h5/copyTraceBufferToGFAST.c | 24 ++++- src/traceBuffer/h5/setData.c | 34 +++--- src/traceBuffer/h5/setTraceBufferFromGFAST.c | 8 +- 24 files changed, 523 insertions(+), 186 deletions(-) create mode 100644 run/bin/gfast_eew_env.sh create mode 100644 src/core/waveformProcessor/parseQChannel.c diff --git a/include/dmlibWrapper.h b/include/dmlibWrapper.h index 35eb82f8..e4e1d06b 100644 --- a/include/dmlibWrapper.h +++ b/include/dmlibWrapper.h @@ -65,6 +65,17 @@ extern "C" { @return 1 if success, 0 if not initialized and -1 for error */ int stopEventSender(); + + /*! + @brief instantiates and starts new DMMessageEncoder for event xmls. + @return 1 if success, 0 if already connected and -1 for error + */ + int startEventEncoder(); + /*! + @brief stops active DMMessageEncoder for events. + @return 1 if success, 0 if not initialized and -1 for error + */ + int stopEventEncoder(); /*! @brief sends static event message @@ -101,6 +112,11 @@ extern "C" { @return 1 if success, 0 if not initialized and -1 for error */ int sendHeartbeat(); + /*! + @brief Returns the dmlib version string + @return Version string + */ + char *getDmLibVersion(); /*! @brief create xml message from coreEvent_info and GFAST_peakDisplacementData_struct @@ -116,7 +132,8 @@ extern "C" { @param[out] ierr 0 for success, -1 for error @return returns a ShakeAlert xml message */ - char *dmlibWrapper_createPGDXML(const enum opmode_type mode, + char *dmlibWrapper_createPGDXML(const double currentTime, + const enum opmode_type mode, const char *alg_vers, const char *instance, const char *message_type, diff --git a/include/gfast_config.h b/include/gfast_config.h index e8e0eac7..4b17c8a9 100644 --- a/include/gfast_config.h +++ b/include/gfast_config.h @@ -1,6 +1,6 @@ #ifndef _gfast_config__h_ #define _gfast_config__h_ 1 -#define GFAST_VERSION "gfast-1.2.1-2022-11-28" +#define GFAST_VERSION "gfast-1.2.2-2022-12-28" #define GFAST_MAXMSG_LEN 4096 #define MAX_OUTPUT_INTERVALS 16 #define MAX_THROTTLING_THRESHOLDS 100 diff --git a/include/gfast_core.h b/include/gfast_core.h index 0c24c841..dcdbbf3c 100644 --- a/include/gfast_core.h +++ b/include/gfast_core.h @@ -535,6 +535,12 @@ int core_scaling_readRawSigmaThresholdLookupFile(const char *rawSigmaThresholdLo //----------------------------------------------------------------------------// // Waveform processor // //----------------------------------------------------------------------------// +/* Parse the packed quality channel, return chi^2 value */ +double core_waveformProcessor_parseQChannelChi2CWU( + const double q_value); +/* Parse the packed quality channel, return mapped chi^2 value*/ +int core_waveformProcessor_parseQChannelChi2CWUmap( + const double q_value); /* Compute the offset in north, east, and up */ int core_waveformProcessor_offset(const int utm_zone, const double svel_window, @@ -564,16 +570,12 @@ double core_waveformProcessor_peakDisplacementHelper( const double *__restrict__ ubuff, const double *__restrict__ nbuff, const double *__restrict__ ebuff, - const double *__restrict__ usigmabuff, - const double *__restrict__ nsigmabuff, - const double *__restrict__ esigmabuff, const int nMaxLeader, const double tmin, const double tmax, double *obsTime, - double *uMaxUncertainty, - double *nMaxUncertainty, - double *eMaxUncertainty); + int *iRef, + int *iPeak); #define GFAST_core_cmt_decomposeMomentTensor(...) \ core_cmt_decomposeMomentTensor(__VA_ARGS__) diff --git a/include/gfast_struct.h b/include/gfast_struct.h index fbee04fd..51b8b201 100644 --- a/include/gfast_struct.h +++ b/include/gfast_struct.h @@ -420,7 +420,7 @@ struct GFAST_waveform3CData_struct { char netw[64]; /*!< Network name */ char stnm[64]; /*!< Station name */ - char chan[6][64]; /*!< Channel codes (Z, N, E, 3, 2, 1) */ + char chan[7][64]; /*!< Channel codes (Z, N, E, 3, 2, 1, Q) */ char loc[64]; /*!< Location code */ double *ubuff; /*!< Up precise-point position buffer (meters). If any sample is not known it should be a NAN. [maxpts] */ @@ -434,6 +434,8 @@ struct GFAST_waveform3CData_struct sample is not known it should be a NAN. [maxpts] */ double *esigmabuff; /*!< East precise-point position buffer (meters). If any sample is not known it should be a NAN. */ + double *qbuff; /*!< Quality channel value. Multiple pieces of information are + encoded here. */ double *tbuff; /*!< Epochal time buffer (s) [maxpts] */ //double epoch; /*!< Epoch time (seconds) corresponding to first sample // of u, n, and e traces */ @@ -441,7 +443,8 @@ struct GFAST_waveform3CData_struct double sta_lat; /*!< Site latitude [-90,90] (degrees) */ double sta_lon; /*!< Site longitude [0,360] (degrees) */ double sta_alt; /*!< Site altitude (m) */ - double gain[6]; /*!< Instrument gain on all three channels */ + double gain[7]; /*!< Instrument gain on all 3 channels + 3 channel sigmas + + quality channel */ int maxpts; /*!< Max number of poitns in buffer. This is computed from the site sampling period and the GFAST_parm_struct's bufflen */ diff --git a/include/gfast_traceBuffer.h b/include/gfast_traceBuffer.h index d3c19674..867d9919 100644 --- a/include/gfast_traceBuffer.h +++ b/include/gfast_traceBuffer.h @@ -130,7 +130,7 @@ struct h5trace_struct double dt; /*!< Sampling period (seconds) */ double gain; /*!< Instrument gain */ int idest; /*!< Maps this trace back to the appropriate - six-component data stream */ + seven-component data stream */ int maxpts; /*!< Max number of points in data buffers */ int npts1; /*!< Number of points in buffer 1 - TODO - delete */ int npts2; /*!< Number of points in buffer 2 - TODO - delete */ diff --git a/run/bin/gfast_eew_env.sh b/run/bin/gfast_eew_env.sh new file mode 100644 index 00000000..070ecc43 --- /dev/null +++ b/run/bin/gfast_eew_env.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +echo -e 'Version: $Id: gfast_env.sh 000 2023-01-11 18:00:00Z ulbergc $\n' + +# With "LEAPSECONDS=", times will be handled consistently internally +# pending addressing iscl <-> dmlib issues. +export LEAPSECONDS= +# export LEAPSECONDS=/app/share/etc/leapseconds +#env | grep LEAPSECONDS + +source /app/eewdata/run/bin/ew_linux.bash +#env | sort | grep EW diff --git a/run/bin/run_gfast.sh b/run/bin/run_gfast.sh index 4d19fc51..34492e50 100755 --- a/run/bin/run_gfast.sh +++ b/run/bin/run_gfast.sh @@ -4,7 +4,7 @@ # starting and stopping gfast in ShakeAlert context # -echo -e 'Version: 0.0 dev: run_gfast.sh\n' +echo -e 'Version: $Id: run_gfast.sh 001 2023-01-11 18:00:00Z ulbergc $\n' RETVAL=0 ulimit -c unlimited @@ -22,10 +22,6 @@ APP_LOGDIR="${APP_RUNDIR}/logs" APP_CMD="${APP_BINDIR}/${APP} ${APP_CFGDIR}/gfast.props" APP_LOG="/app/share/bin/conlog -l ${APP_LOGDIR}/${APP}" -#earthworm environment -export EW_PARAMS=/app/eewdata/run/params -export EW_INSTALLATION=INST_UW - # Location of PID file(s) PIDDIR="${APP_RUNDIR}/pids" @@ -33,6 +29,9 @@ PIDDIR="${APP_RUNDIR}/pids" NUMBER_OF_CHECKS=10 PAUSE=1 +# Setup environment before running program. This includes Earthworm settings +source ${APP_RUNDIR}/bin/${APP}_env.sh + # Kill running process(es) kill_proc() { RC=2 diff --git a/run/params/pgd_threshold_PW.txt b/run/params/pgd_threshold_PW.txt index 4b80f0fe..f399b912 100644 --- a/run/params/pgd_threshold_PW.txt +++ b/run/params/pgd_threshold_PW.txt @@ -1,15 +1,81 @@ -20 18 3 -25 27 3 -30 37 3 -35 47 3 -40 56 3 -45 66 3 -50 75 3 -55 85 3 -60 94 3 -65 104 3 -70 114 3 -75 123 3 -80 133 3 -85 142 3 -90 152 3 \ No newline at end of file +10 18 3 +11 19 3 +12 20 3 +13 20 3 +14 21 3 +15 22 3 +16 23 3 +17 24 3 +18 24 3 +19 25 3 +20 26 3 +21 27 3 +22 27 3 +23 28 3 +24 29 3 +25 29 3 +26 30 3 +27 31 3 +28 31 3 +29 32 3 +30 33 3 +31 33 3 +32 34 3 +33 35 3 +34 35 3 +35 36 3 +36 36 3 +37 37 3 +38 38 3 +39 38 3 +40 39 3 +41 39 3 +42 40 3 +43 40 3 +44 41 3 +45 41 3 +46 42 3 +47 42 3 +48 43 3 +49 43 3 +50 44 3 +51 44 3 +52 45 3 +53 45 3 +54 46 3 +55 46 3 +56 46 3 +57 47 3 +58 47 3 +59 48 3 +60 48 3 +61 48 3 +62 49 3 +63 49 3 +64 49 3 +65 50 3 +66 50 3 +67 50 3 +68 51 3 +69 51 3 +70 51 3 +71 51 3 +72 52 3 +73 52 3 +74 52 3 +75 52 3 +76 53 3 +77 53 3 +78 53 3 +79 53 3 +80 53 3 +81 54 3 +82 54 3 +83 54 3 +84 54 3 +85 54 3 +86 54 3 +87 55 3 +88 55 3 +89 55 3 +90 55 3 \ No newline at end of file diff --git a/src/core/data/initialize.c b/src/core/data/initialize.c index 2b81fc24..146f328a 100644 --- a/src/core/data/initialize.c +++ b/src/core/data/initialize.c @@ -57,6 +57,7 @@ int core_data_initialize(struct GFAST_props_struct props, gps_data->data[k].usigmabuff = memory_calloc64f(mpts); gps_data->data[k].nsigmabuff = memory_calloc64f(mpts); gps_data->data[k].esigmabuff = memory_calloc64f(mpts); + gps_data->data[k].qbuff = memory_calloc64f(mpts); gps_data->data[k].tbuff = memory_calloc64f(mpts); } return 0; diff --git a/src/core/data/readMetaDataFile.c b/src/core/data/readMetaDataFile.c index ae1948cf..a7013ec3 100644 --- a/src/core/data/readMetaDataFile.c +++ b/src/core/data/readMetaDataFile.c @@ -38,8 +38,8 @@ int core_data_readMetaDataFile(const char *metaDataFile, site[256], chan[64], chan1[64], loc[64], loc1[64], netw[64], netw1[64], stat[64], stat1[64], sensorType[64], units[64]; - double gain0[6], dt, elev, gain, lat, lon; - int *lines, i, ierr, j, k, lfound, nlines, nlines_total, ns; + double gain0[7], dt, elev, gain, lat, lon; + int *lines, i, ierr, j, k, lfound, nlines, nlines_total, ns, debug; // Initialize ierr = 0; infl = NULL; @@ -49,6 +49,7 @@ int core_data_readMetaDataFile(const char *metaDataFile, nlines = 0; nlines_total = 0; ns = 0; + debug = 0; // Require the site file exists if (!os_path_isfile(metaDataFile)) { @@ -115,7 +116,6 @@ int core_data_readMetaDataFile(const char *metaDataFile, ns = 0; for (i=0; istream_length] = i; @@ -301,6 +314,8 @@ NEXT_LINE:; // Try another site to match strcat( gps_data->data[k].chan[4], "2\0"); strncpy(gps_data->data[k].chan[5], chan, 2); strcat( gps_data->data[k].chan[5], "1\0"); + strncpy(gps_data->data[k].chan[6], chan, 2); + strcat( gps_data->data[k].chan[6], "Q\0"); strcpy(gps_data->data[k].loc, loc); gps_data->data[k].sta_lat = lat; gps_data->data[k].sta_lon = lon; @@ -312,6 +327,7 @@ NEXT_LINE:; // Try another site to match gps_data->data[k].gain[3] = gain; gps_data->data[k].gain[4] = gain; gps_data->data[k].gain[5] = gain; + gps_data->data[k].gain[6] = 1; // Quality channel has no gain if (gain == 0.0 || dt <= 0.0 || isnan(dt)) { if (gain == 0.0) diff --git a/src/core/data/readSiteMaskFile.c b/src/core/data/readSiteMaskFile.c index 037d093e..5ce6a422 100644 --- a/src/core/data/readSiteMaskFile.c +++ b/src/core/data/readSiteMaskFile.c @@ -18,7 +18,7 @@ static int splitLine(const char *cline, * @param[in,out] gps_data on input contains the sites and SNCL's. * on output, if the SNCL is located in the * site mask file, the site is masked from the - * inverserions. + * inversions. * * @result 0 indicates success * @@ -55,7 +55,7 @@ int core_data_readSiteMaskFile(const char *siteMaskFile, LOG_ERRMSG("%s", "Premature end of file"); return -1; } - if (i == 0){continue;} + // if (i == 0){continue;} if (strlen(cline) == 0) { LOG_ERRMSG("%s", "Error line is blank!"); @@ -65,6 +65,14 @@ int core_data_readSiteMaskFile(const char *siteMaskFile, { cline[strlen(cline)-1] = '\0'; } + // Skip comment lines: + if (cline[0] == '#') + { + if (verbose > 0) { + LOG_DEBUGMSG("Skip comment line: %s", cline); + } + continue; + } ierr = splitLine(cline, netw, stnm, loc, chan, &iusePGD, &iuseCMT, &iuseFF); @@ -87,12 +95,13 @@ int core_data_readSiteMaskFile(const char *siteMaskFile, strcasecmp(gps_data->data[k].chan[2], chan) == 0 || strcasecmp(gps_data->data[k].chan[3], chan) == 0 || strcasecmp(gps_data->data[k].chan[4], chan) == 0 || - strcasecmp(gps_data->data[k].chan[5], chan) == 0) + strcasecmp(gps_data->data[k].chan[5], chan) == 0 || + strcasecmp(gps_data->data[k].chan[6], chan) == 0) { if (verbose > 0) { - LOG_INFOMSG("Masking %s.%s.%s.%s", - netw, stnm, chan, loc); + LOG_INFOMSG("Masking %s.%s.%s", + netw, stnm, loc); } if (iusePGD == 0) { diff --git a/src/core/waveformProcessor/Makefile b/src/core/waveformProcessor/Makefile index 9a76850c..86f4bde9 100644 --- a/src/core/waveformProcessor/Makefile +++ b/src/core/waveformProcessor/Makefile @@ -14,7 +14,7 @@ CFLAGS+=$(GFAST_USE_AMQ) CFLAGS+=$(GFAST_USE_DMLIB) #endif -OBJS = offset.o peakDisplacement.o peakDisplacementHelper.o +OBJS = offset.o peakDisplacement.o peakDisplacementHelper.o parseQChannel.o DEBUG = -g CCFLAGS += -O0 -D_REENTRANT -Dstatic_config diff --git a/src/core/waveformProcessor/parseQChannel.c b/src/core/waveformProcessor/parseQChannel.c new file mode 100644 index 00000000..94e90a1d --- /dev/null +++ b/src/core/waveformProcessor/parseQChannel.c @@ -0,0 +1,68 @@ +#include +#include "gfast_core.h" + + +/*! + * @brief Unpack the quality channel. It should be a 6 digit integer, with the + * first 2 digits being n_satellites, middle 2 digits being pdop, and + * the last 2 digits being chi^2 as calculated by CWU (formerly fixtype) + * + * @param[in] q_value Q channel value + * + * @result the computed chi^2 value for the station + * + * @author Brendan Crowell (PNSN) and Carl Ulberg (PNSN) + * + * @date Dec 2022 + * + */ +double core_waveformProcessor_parseQChannelChi2CWU( + const double q_value) +{ + double chi2; + int chimap; + + // Extract the last 2 digits + chimap = core_waveformProcessor_parseQChannelChi2CWUmap(q_value); + + // Apply conversion to real numbers + // Reverse operation provided by Craig Scrivner of CWU + // int( ( log10(chi2) + 4 ) * 25 ) + // Should map 0.0001 -> 0, 0.001 -> 25, 0.01 -> 50, 0.99 -> 99 + chi2 = pow(10, (double)(chimap) / 25 - 4); + + return chi2; +} + + +/*! + * @brief Unpack the quality channel. It should be a 6 digit integer, with the + * first 2 digits being n_satellites, middle 2 digits being pdop, and + * the last 2 digits being chi^2 as calculated by CWU (formerly fixtype) + * + * @param[in] q_value Q channel value. It is a double to stay consistent + * with other data buffers. But treated as integer here. + * + * @result the mapped chi^2 value for the channel (between 00-99) + * + * @author Brendan Crowell (PNSN) and Carl Ulberg (PNSN) + * + * @date Dec 2022 + * + */ +int core_waveformProcessor_parseQChannelChi2CWUmap( + const double q_value) +{ + int chimap; + + // Extract the last 2 digits + if (q_value < 0) { + LOG_WARNMSG("parseQChannelChi2CWU - q_value is negative (%lf), changing to positive!", + q_value); + chimap = (int)(q_value * -1) % 100; + } else { + chimap = (int)(q_value) % 100; + } + + return chimap; +} \ No newline at end of file diff --git a/src/core/waveformProcessor/peakDisplacement.c b/src/core/waveformProcessor/peakDisplacement.c index 4fdfc54e..718bd7b4 100644 --- a/src/core/waveformProcessor/peakDisplacement.c +++ b/src/core/waveformProcessor/peakDisplacement.c @@ -47,8 +47,8 @@ int core_waveformProcessor_peakDisplacement( { double currentTime, distance, effectiveHypoDist, epoch, peakDisp, x1, x2, y1, y2, tmin, tmax, obsTime, - uMaxUncertainty, nMaxUncertainty, eMaxUncertainty; - int k, nsites, zone_loc; + uMaxUncertainty, nMaxUncertainty, eMaxUncertainty, qMax, qRef, qPeak; + int k, nsites, zone_loc, iRef, iPeak; //unused int i; bool lnorthp; bool lnorthp_event; @@ -85,9 +85,12 @@ int core_waveformProcessor_peakDisplacement( *ierr = 0; nsites = 0; obsTime = 0.0; + iRef = 0; + iPeak = 0; uMaxUncertainty = 0.0; eMaxUncertainty = 0.0; nMaxUncertainty = 0.0; + qMax = 0.0; if (gps_data.stream_length != pgd_data->nsites) { LOG_ERRMSG("Inconsistent structure sizes %d %d", @@ -117,9 +120,12 @@ int core_waveformProcessor_peakDisplacement( for (k=0; ksta_lat[k] = gps_data.data[k].sta_lat; pgd_data->sta_lon[k] = gps_data.data[k].sta_lon; @@ -196,16 +202,12 @@ int core_waveformProcessor_peakDisplacement( gps_data.data[k].ubuff, gps_data.data[k].nbuff, gps_data.data[k].ebuff, - gps_data.data[k].usigmabuff, - gps_data.data[k].nsigmabuff, - gps_data.data[k].esigmabuff, nMaxLeader, tmin, tmax, &obsTime, - &uMaxUncertainty, - &nMaxUncertainty, - &eMaxUncertainty); + &iRef, + &iPeak); /* The Crowell et al. [2016] coefficients are @@ -241,14 +243,31 @@ M 9 at 100km: -6.687 + 150 - 21.4*2 = 100 cm(?) } else { - LOG_MSG("%s.%s.%s.%s peakDisp=%f dist=%.2f, peakSigmas=(%.4f,%.4f,%.4f)", + // If there is a real observation, get the associated max uncertainties and q values + if (!isnan(gps_data.data[k].usigmabuff[iRef]) && !isnan(gps_data.data[k].usigmabuff[iPeak])) { + uMaxUncertainty = fmax(gps_data.data[k].usigmabuff[iRef], gps_data.data[k].usigmabuff[iPeak]); + } + if (!isnan(gps_data.data[k].nsigmabuff[iRef]) && !isnan(gps_data.data[k].nsigmabuff[iPeak])) { + nMaxUncertainty = fmax(gps_data.data[k].nsigmabuff[iRef], gps_data.data[k].nsigmabuff[iPeak]); + } + if (!isnan(gps_data.data[k].esigmabuff[iRef]) && !isnan(gps_data.data[k].esigmabuff[iPeak])) { + eMaxUncertainty = fmax(gps_data.data[k].esigmabuff[iRef], gps_data.data[k].esigmabuff[iPeak]); + } + if (!isnan(gps_data.data[k].qbuff[iRef]) && !isnan(gps_data.data[k].qbuff[iPeak])) { + qRef = core_waveformProcessor_parseQChannelChi2CWU(gps_data.data[k].qbuff[iRef]); + qPeak = core_waveformProcessor_parseQChannelChi2CWU(gps_data.data[k].qbuff[iPeak]); + qMax = fmax(qRef, qPeak); + } + + LOG_MSG("%s.%s.%s.%s peakDisp=%f dist=%.2f, peakSigmas=(%.4f,%.4f,%.4f), peakQ=%.4f", gps_data.data[k].stnm, gps_data.data[k].chan[0], gps_data.data[k].netw, gps_data.data[k].loc, peakDisp, distance, uMaxUncertainty, nMaxUncertainty, - eMaxUncertainty); + eMaxUncertainty, + qMax); } // Is the observation above the defined minimum? diff --git a/src/core/waveformProcessor/peakDisplacementHelper.c b/src/core/waveformProcessor/peakDisplacementHelper.c index d8b88134..0633c77a 100644 --- a/src/core/waveformProcessor/peakDisplacementHelper.c +++ b/src/core/waveformProcessor/peakDisplacementHelper.c @@ -56,16 +56,12 @@ double core_waveformProcessor_peakDisplacementHelper( const double *__restrict__ ubuff, const double *__restrict__ nbuff, const double *__restrict__ ebuff, - const double *__restrict__ usigmabuff, - const double *__restrict__ nsigmabuff, - const double *__restrict__ esigmabuff, const int nMaxLeader, const double tmin, const double tmax, double *obsTime, - double *uMaxUncertainty, - double *nMaxUncertainty, - double *eMaxUncertainty + int *iRef, + int *iPeak ) { double diffT, peakDisplacement_i, peakDisplacement, e0, n0, u0; @@ -76,9 +72,8 @@ double core_waveformProcessor_peakDisplacementHelper( // // Set the initial position *obsTime = 0.0; - *uMaxUncertainty = 0.0; - *nMaxUncertainty = 0.0; - *eMaxUncertainty = 0.0; + *iRef = 0; + *iPeak = 0; u0 = 0.0; n0 = 0.0; e0 = 0.0; @@ -123,11 +118,6 @@ double core_waveformProcessor_peakDisplacementHelper( return (double) NAN; } - // Get initial uncertainty for each component - if (!isnan(usigmabuff[indx0])) *uMaxUncertainty = usigmabuff[indx0]; - if (!isnan(nsigmabuff[indx0])) *nMaxUncertainty = nsigmabuff[indx0]; - if (!isnan(esigmabuff[indx0])) *eMaxUncertainty = esigmabuff[indx0]; - // Compute the maximum peak ground displacement peakDisplacement = PD_MAX_NAN; if (debug) { @@ -154,16 +144,6 @@ double core_waveformProcessor_peakDisplacementHelper( peakDisplacement = fmax(peakDisplacement_i, peakDisplacement); } // Loop on data points - if (debug) { - LOG_DEBUGMSG("Uncertainties at indx0:%d (%f,%f,%f), at ipeak:%d (%f,%f,%f", - indx0, *uMaxUncertainty, *nMaxUncertainty, *eMaxUncertainty, - ipeak, usigmabuff[ipeak], nsigmabuff[ipeak], esigmabuff[ipeak]); - } - - if (!isnan(usigmabuff[ipeak])) *uMaxUncertainty = fmax(usigmabuff[ipeak], *uMaxUncertainty); - if (!isnan(nsigmabuff[ipeak])) *nMaxUncertainty = fmax(nsigmabuff[ipeak], *nMaxUncertainty); - if (!isnan(esigmabuff[ipeak])) *eMaxUncertainty = fmax(esigmabuff[ipeak], *eMaxUncertainty); - if (fabs(peakDisplacement - PD_MAX_NAN)/fabs(PD_MAX_NAN) < 1.e-10) { LOG_MSG("%s", "Returning NAN because peakDisp is ~ PD_MAX_NAN"); @@ -171,6 +151,8 @@ double core_waveformProcessor_peakDisplacementHelper( } if (!isnan(peakDisplacement)){ *obsTime = epoch + dt * ipeak; + *iRef = indx0; + *iPeak = ipeak; // LOG_MSG("Got peak [%f] at ipeak:%d ubuff[i]=%f (u0=%f) nbuff[i]=%f (n0=%f) ebuff[i]=%f (e0=%f) ", // peakDisplacement, ipeak, ubuff[ipeak], u0, nbuff[ipeak], n0, ebuff[ipeak], e0); } diff --git a/src/dmlib/dmlibWrapper.cpp b/src/dmlib/dmlibWrapper.cpp index 6cd3c91f..09c39bc7 100644 --- a/src/dmlib/dmlibWrapper.cpp +++ b/src/dmlib/dmlibWrapper.cpp @@ -12,6 +12,7 @@ #include "HBProducer.h" #include "DMMessageReceiver.h" #include "DMMessageSender.h" +#include "DMMessageEncoder.h" #include "dmlibWrapper.h" #include "gfast_activeMQ.h" #include "gfast_struct.h" @@ -27,6 +28,7 @@ namespace { static HBProducer *hbproducer=NULL; static DMMessageReceiver *eventreceiver=NULL; static DMMessageSender *eventsender=NULL; + static DMMessageEncoder *eventencoder=NULL; static CoreEventInfo *eventmessage=NULL; static std::string hbSender=""; static std::string hbTopic=""; @@ -197,12 +199,12 @@ char *eventReceiverGetMessage(const int ms_wait, int *ierr) { } int stopEventReceiver() { - if (eventreceiver==NULL) { - LOG_DEBUGMSG("%s: Event receiver not running",__func__); + if (eventreceiver == NULL) { + LOG_DEBUGMSG("%s: Event receiver not running", __func__); return 0; } else { delete eventreceiver; - eventreceiver=NULL; + eventreceiver = NULL; } return 1; } @@ -241,16 +243,47 @@ int startEventSender(const char eventtopic[]) { } int stopEventSender() { - if (eventsender==NULL) { - LOG_DEBUGMSG("%s: Event sender not running",__func__); + if (eventsender == NULL) { + LOG_DEBUGMSG("%s: Event sender not running", __func__); return 0; } else { delete eventsender; - eventsender=NULL; + eventsender = NULL; } - if (eventmessage!=NULL) { + if (eventmessage != NULL) { delete eventmessage; - eventmessage=NULL; + eventmessage = NULL; + } + return 1; +} + +int startEventEncoder() { + if (conVerbose > 2) + { + LOG_DEBUGMSG("%s: Starting dmlib DMMessageEncoder", __func__); + } + if (eventencoder != NULL) { + LOG_DEBUGMSG("%s: Event encoder already initalized", __func__); + return 0; + } + try { + eventencoder = new DMMessageEncoder(); + } + catch (exception &e) + { + LOG_ERRMSG("%s: Encountered Exception creating DMMessageEncoder\n%s",__func__,e.what()); + return -1; + } + return 1; +} + +int stopEventEncoder() { + if (eventencoder == NULL) { + LOG_DEBUGMSG("%s: Event encoder not running",__func__); + return 0; + } else { + delete eventencoder; + eventencoder = NULL; } return 1; } @@ -363,7 +396,19 @@ int sendHeartbeat(){ return 1; } -char *dmlibWrapper_createPGDXML(const enum opmode_type mode, +char *getDmLibVersion() { + char *version=NULL; + std::string version_string; + version_string = DMLib::getVersion(); + + version = (char *)calloc(version_string.length() + 1, sizeof(char)); + strcpy(version, version_string.c_str()); + + return version; +} + +char *dmlibWrapper_createPGDXML(const double currentTime, + const enum opmode_type mode, const char *alg_vers, const char *instance, const char *message_type, @@ -425,12 +470,12 @@ char *dmlibWrapper_createPGDXML(const enum opmode_type mode, // required to create FiniteFaultMessage enum FaultSegment::FaultSegmentShape shape = FaultSegment::UNKNOWN_SEGMENT; - // Get time stamp for when message is sent + // Get time stamp for when message is sent. Corresponds to currentTime from + // the outer driveGFAST loop to be consistent with the last time we have + // data for. int rc; char cnow[128]; - double now; - now = time_timeStamp(); - rc = xml_epoch2string(now, cnow); + rc = xml_epoch2string(currentTime, cnow); if (rc != 0) { LOG_DEBUGMSG("%s", "Error getting time string!"); } @@ -442,6 +487,19 @@ char *dmlibWrapper_createPGDXML(const enum opmode_type mode, latUncerUnits, lonUnits, lonUncerUnits, depthUnits, depthUncerUnits, origTimeUnits, origTimeUncerUnits); + // Replace time based on datestr. Accounts for potential leapseconds issues when switching + // between ISCL and ShakeAlert/qlib2 time handling. + // ShakeAlert wants 2011-05-06T18:12:37.038Z" format which is provided by xml_epoch2string + char origTimeChar[128]; + rc = xml_epoch2string(core->origTime, origTimeChar); + if (rc != 0) { + LOG_DEBUGMSG("%s", "Error getting time string!"); + } + std::string origTimeStr(origTimeChar); + algMessage.setOriginTime(origTimeStr); + LOG_DEBUGMSG("old origTime: %lf, origTimeChar: %s, origTimeStr: %s, new origTime: %lf", + core->origTime, origTimeChar, origTimeStr.c_str(), algMessage.getOriginTime()); + // LOG_MSG("%s", "createEventXML - created algMessage"); // Now add pgd observations to algMessage @@ -547,7 +605,10 @@ char *dmlibWrapper_createPGDXML(const enum opmode_type mode, std::string msg_tmp; try { - msg_tmp = eventsender->getEncodedMessage(&algMessage); + // Using separate Encoder instead of the Sender's Encoder allows for easier testing and separation + // of tasks. + msg_tmp = eventencoder->encodeMessage(&algMessage); + // msg_tmp = eventsender->getEncodedMessage(&algMessage); } catch (exception &e) { LOG_ERRMSG("%s: DMMessageSender error while encoding: %s",__func__,e.what()); diff --git a/src/eewUtils/driveGFAST.c b/src/eewUtils/driveGFAST.c index a034351b..477e2a9f 100644 --- a/src/eewUtils/driveGFAST.c +++ b/src/eewUtils/driveGFAST.c @@ -421,6 +421,7 @@ int eewUtils_driveGFAST(const double currentTime, // Encode xml with dmlib LOG_MSG("%s", "driveGFAST: CWU_TEST dmlib encoding"); pgdXML = dmlibWrapper_createPGDXML( + currentTime, props.opmode, GFAST_VERSION, program_instance, diff --git a/src/gfast_eew.c b/src/gfast_eew.c index 749ba8c4..7dec709b 100644 --- a/src/gfast_eew.c +++ b/src/gfast_eew.c @@ -24,6 +24,37 @@ */ char *check_dir_for_messages(const char *dirname, int *ierr); +/*! + * @brief Print program and library information + * @param[in] use_dmlib Is dmlib being used? + * @param[in] fcnm What is the name of the main function? + */ + +void printProgramInfo(bool use_dmlib, const char *fcnm) { + const int bufflen = 1024; + char *message=NULL; + int ind; + unsigned H5majnum, H5minnum, H5relnum; + + ind = 0; + message = (char *)malloc(bufflen * sizeof(char)); + + ind += snprintf(message + ind, bufflen - ind, "%s Version: %s (Build %s %s by %s)\n", + fcnm, GFAST_VERSION, __DATE__, __TIME__, BUILDER); + + if (use_dmlib) { + char *dmlib_version = getDmLibVersion(); + ind += snprintf(message + ind, bufflen - ind, "%s\n", dmlib_version); + free(dmlib_version); + } + H5get_libversion(&H5majnum, &H5minnum, &H5relnum); + ind += snprintf(message + ind, bufflen - ind, "HDF5 library version: %u.%u.%u\n", + H5majnum, H5minnum, H5relnum); + ind += snprintf(message + ind, bufflen - ind, "ISCL library version: %s\n", ISCL_VERSION); + + LOG_MSG("%s", message); + free(message); +} /*! * @brief GFAST earthquake early warning driver routine @@ -81,8 +112,8 @@ int main(int argc, char **argv) // logging stuff init_plog(); - LOG_MSG("%s Version: %s (Build %s %s by %s)", - fcnm, GFAST_VERSION, __DATE__, __TIME__, BUILDER); + printProgramInfo(USE_DMLIB, fcnm); + // Initialize. Only works if propfile is specified if (argc > 1) { strncpy(propfilename, argv[1], PATH_MAX - 1); @@ -237,6 +268,16 @@ int main(int argc, char **argv) goto ERROR; } } + /*start message encoder*/ + if (props.verbose > 0) { + LOG_MSG("%s: Initializing event xml encoder...", fcnm); + } + ierr = startEventEncoder(); + if (ierr < 0) { + LOG_ERRMSG("%s: Error initializing event encoder object", fcnm); + goto ERROR; + } + /*start message sender*/ if (props.verbose > 0) { LOG_MSG("%s: Initializing event sender on %s...", @@ -340,10 +381,10 @@ int main(int argc, char **argv) LOG_MSG("== [GFAST t0:%f] Beginning main loop", t0); if (tstatus1 - tstatus0 > 3600.0) { - LOG_DEBUGMSG("%s: GFAST has been running for %d hours, start time %f", + LOG_MSG("%s: GFAST has been running for %d hours, start time %f", fcnm, (int) ((tstatus1 - tstatus)/3600.0), tstatus); - LOG_DEBUGMSG("%s: Version %s (Build %s %s by %s)\n", - fcnm, GFAST_VERSION, __DATE__, __TIME__, BUILDER); + printProgramInfo(USE_DMLIB, fcnm); + tstatus0 = tstatus1; } @@ -549,6 +590,7 @@ int main(int argc, char **argv) stopEventReceiver(); stopHBProducer(); stopEventSender(); + stopEventEncoder(); //stopDestinationConnection(); } activeMQ_stop(); diff --git a/src/tests/CoreWaveformProcessorUT.cc b/src/tests/CoreWaveformProcessorUT.cc index 4b8b6f0b..eec6ae82 100644 --- a/src/tests/CoreWaveformProcessorUT.cc +++ b/src/tests/CoreWaveformProcessorUT.cc @@ -18,15 +18,14 @@ * the initial reference time and the peak displacement time. */ void testPDHelper_helper(int npts, double *ubuff, double *nbuff, double *ebuff, - double *usigmabuff, double *nsigmabuff, double *esigmabuff, - double expPeakDisp, double expObsTime, - double expUMaxSigma, double expNMaxSigma, double expEMaxSigma) + double expPeakDisp, int expIRef, int expIPeak) { // Input values double dt, ev_time, epoch, tmin, tmax; int nMaxLeader; // Return values - double peakDisp, obsTime, uMaxUncertainty, nMaxUncertainty, eMaxUncertainty; + double peakDisp, obsTime, expObsTime; + int iRef, iPeak; // Initialize inputs dt = 1.0; @@ -36,11 +35,13 @@ void testPDHelper_helper(int npts, double *ubuff, double *nbuff, double *ebuff, tmax = 10; // distance / min_svel_window (default 0.01 km/s) nMaxLeader = 2; + // The observation time is based on the input epoch time + expObsTime = epoch + expIPeak * dt; + // Initialize outputs to verify they change? obsTime = -1; - uMaxUncertainty = -1; - nMaxUncertainty = -1; - eMaxUncertainty = -1; + iRef = -1; + iPeak = -1; peakDisp = core_waveformProcessor_peakDisplacementHelper( npts, @@ -50,24 +51,18 @@ void testPDHelper_helper(int npts, double *ubuff, double *nbuff, double *ebuff, ubuff, nbuff, ebuff, - usigmabuff, - nsigmabuff, - esigmabuff, nMaxLeader, tmin, tmax, &obsTime, - &uMaxUncertainty, - &nMaxUncertainty, - &eMaxUncertainty + &iRef, + &iPeak ); EXPECT_DOUBLE_EQ(expPeakDisp, peakDisp); EXPECT_DOUBLE_EQ(expObsTime, obsTime); - EXPECT_DOUBLE_EQ(expUMaxSigma, uMaxUncertainty); - EXPECT_DOUBLE_EQ(expNMaxSigma, nMaxUncertainty); - EXPECT_DOUBLE_EQ(expEMaxSigma, eMaxUncertainty); - + EXPECT_EQ(expIRef, iRef); + EXPECT_EQ(expIPeak, iPeak); } TEST(CoreWaveformProcessor, testPeakDisplacementHelperBasic) { @@ -75,16 +70,12 @@ TEST(CoreWaveformProcessor, testPeakDisplacementHelperBasic) { double ubuff[NPTS] = {1, 2, 3, 4}; double nbuff[NPTS] = {1, 2, 3, 4}; double ebuff[NPTS] = {1, 2, 3, 4}; - double usigmabuff[NPTS] = {1, 2, 3, 4}; - double nsigmabuff[NPTS] = {1, 2, 3, 4}; - double esigmabuff[NPTS] = {1, 2, 3, 4}; int npts = NPTS; double expPeakDisp = pow(pow(4 - 1, 2) + pow(4 - 1, 2) + pow(4 - 1, 2), 0.5); testPDHelper_helper(npts, ubuff, nbuff, ebuff, - usigmabuff, nsigmabuff, esigmabuff, - expPeakDisp, 5, 4, 4, 4); + expPeakDisp, 0, 3); } TEST(CoreWaveformProcessor, testPeakDisplacementHelperEarlyNans) { @@ -92,48 +83,67 @@ TEST(CoreWaveformProcessor, testPeakDisplacementHelperEarlyNans) { double ubuff[NPTS] = {NAN, 2, 3, 4}; double nbuff[NPTS] = {NAN, 2, 3, 4}; double ebuff[NPTS] = {NAN, 2, 3, 4}; - double usigmabuff[NPTS] = {10, 2, 3, 4}; - double nsigmabuff[NPTS] = {1, 21, 3, 4}; - double esigmabuff[NPTS] = {1, 2, 3, 3}; int npts = NPTS; double expPeakDisp = pow(pow(4 - 2, 2) + pow(4 - 2, 2) + pow(4 - 2, 2), 0.5); testPDHelper_helper(npts, ubuff, nbuff, ebuff, - usigmabuff, nsigmabuff, esigmabuff, - expPeakDisp, 5, 4, 21, 3); + expPeakDisp, 1, 3); } -TEST(CoreWaveformProcessor, testPeakDisplacementHelperNanSigmas) { +TEST(CoreWaveformProcessor, testPeakDisplacementHelperMiddlePeak) { const int NPTS = 4; - double ubuff[NPTS] = {1, 2, 3, 4}; + double ubuff[NPTS] = {1, 2, 5, 4}; double nbuff[NPTS] = {1, 2, 3, 4}; - double ebuff[NPTS] = {1, 2, 3, 4}; - double usigmabuff[NPTS] = {NAN}; - double nsigmabuff[NPTS] = {NAN}; - double esigmabuff[NPTS] = {NAN}; + double ebuff[NPTS] = {1, 2, 5, 4}; int npts = NPTS; - double expPeakDisp = pow(pow(4 - 1, 2) + pow(4 - 1, 2) + pow(4 - 1, 2), 0.5); + double expPeakDisp = pow(pow(5 - 1, 2) + pow(3 - 1, 2) + pow(5 - 1, 2), 0.5); testPDHelper_helper(npts, ubuff, nbuff, ebuff, - usigmabuff, nsigmabuff, esigmabuff, - expPeakDisp, 5, 0, 0, 0); + expPeakDisp, 0, 2); } -TEST(CoreWaveformProcessor, testPeakDisplacementHelperMiddlePeak) { +TEST(CoreWaveformProcessor, testPeakDisplacementHelperEarlyNansMiddlePeak) { const int NPTS = 4; - double ubuff[NPTS] = {1, 2, 5, 4}; - double nbuff[NPTS] = {1, 2, 3, 4}; - double ebuff[NPTS] = {1, 2, 5, 4}; - double usigmabuff[NPTS] = {1, 2, 3, 4}; - double nsigmabuff[NPTS] = {1, 2, 3, 4}; - double esigmabuff[NPTS] = {1, 2, 3, 4}; + double ubuff[NPTS] = {NAN, 2, 5, 4}; + double nbuff[NPTS] = {NAN, 2, 3, 4}; + double ebuff[NPTS] = {NAN, 2, 5, 4}; int npts = NPTS; - double expPeakDisp = pow(pow(5 - 1, 2) + pow(3 - 1, 2) + pow(5 - 1, 2), 0.5); + double expPeakDisp = pow(pow(5 - 2, 2) + pow(3 - 2, 2) + pow(5 - 2, 2), 0.5); testPDHelper_helper(npts, ubuff, nbuff, ebuff, - usigmabuff, nsigmabuff, esigmabuff, - expPeakDisp, 4, 3, 3, 3); + expPeakDisp, 1, 2); +} + +TEST(CoreWaveformProcessor, testParseQChannel) { + double value; + + // Temp code to print all values + // int chimap; + // double chi2; + // for (int i = 0; i < 100; i++) { + // value = 12300 + i; + // chi2 = core_waveformProcessor_parseQChannelChi2CWU(value); + // chimap = core_waveformProcessor_parseQChannelChi2CWUmap(value); + // std::cout << value << ": " << chimap << ", " << chi2 << std::endl; + // } + + // Test a few values + value = 12300; + EXPECT_EQ(0, core_waveformProcessor_parseQChannelChi2CWUmap(value)); + EXPECT_DOUBLE_EQ(0.0001, core_waveformProcessor_parseQChannelChi2CWU(value)); + + value = 612325; + EXPECT_EQ(25, core_waveformProcessor_parseQChannelChi2CWUmap(value)); + EXPECT_DOUBLE_EQ(0.001, core_waveformProcessor_parseQChannelChi2CWU(value)); + + value = 765450; + EXPECT_EQ(50, core_waveformProcessor_parseQChannelChi2CWUmap(value)); + EXPECT_DOUBLE_EQ(0.01, core_waveformProcessor_parseQChannelChi2CWU(value)); + + value = 234575; + EXPECT_EQ(75, core_waveformProcessor_parseQChannelChi2CWUmap(value)); + EXPECT_DOUBLE_EQ(0.1, core_waveformProcessor_parseQChannelChi2CWU(value)); } diff --git a/src/traceBuffer/ewrr/classifyRetval.c b/src/traceBuffer/ewrr/classifyRetval.c index 97a730d7..83990bfd 100644 --- a/src/traceBuffer/ewrr/classifyRetval.c +++ b/src/traceBuffer/ewrr/classifyRetval.c @@ -2,8 +2,10 @@ #include #include #include +#include "transport.h" #include "gfast_traceBuffer.h" #include "gfast_core.h" + /*! * @brief Classifies return value from an earthworm get transport activity. * @@ -24,54 +26,65 @@ int traceBuffer_ewrr_classifyGetRetval(const int retval) { char msg[128]; // Got a requested message (modid, type, class) - if (retval == GET_OK){return 1;} + if (retval == GET_OK) {return 1;} // No logos of requested messages in in memory - if (retval == GET_NONE){return 0;} + if (retval == GET_NONE) {return 0;} memset(msg, 0, 128*sizeof(char)); // Got a message but missed some if (retval == GET_MISS) { - sprintf(msg, "%s: Some messages were missed", __func__); - // LOG_MSG("%s", msg); + sprintf( + msg, + "%s: GET_MISS: Some messages were missed", + __func__); LOG_WARNMSG("%s", msg); return -1; } // Got a message but ntrack_get was exceeded if (retval == GET_NOTRACK) { - sprintf(msg, "%s: Message exceeded NTRACK_GET", __func__); - // LOG_MSG("%s", msg); + sprintf( + msg, + "%s: GET_NOTRACK: Message exceeded NTRACK_GET", + __func__); LOG_WARNMSG("%s", msg); return -1; } // Message requested exceeded my buffer if (retval == GET_TOOBIG) { - sprintf(msg, - "%s: Next message of requested logo(s) is too big", __func__); - // LOG_MSG("%s", msg); + sprintf( + msg, + "%s: GET_TOOBIG: Next message of requested logo(s) is too big", + __func__); LOG_WARNMSG("%s", msg); return -2; } // Didn't check ring fast enough and missed a message if (retval == GET_MISS_LAPPED) { - sprintf(msg, "%s: Some messages were overwritten", __func__); - // LOG_MSG("%s", msg); + sprintf( + msg, + "%s: GET_MISS_LAPPED: Some messages were overwritten", + __func__); LOG_WARNMSG("%s", msg); return -1; } // Message contains a gap if (retval == GET_MISS_SEQGAP) { - sprintf(msg, "%s: A gap in messages was detected", __func__); - // LOG_MSG("%s", msg); + sprintf( + msg, + "%s: GET_MISS_SEQGAP: A gap in messages was detected", + __func__); LOG_WARNMSG("%s", msg); return -1; } // I don't know - sprintf(msg, "%s: Could not classify return value", __func__); - LOG_MSG("%s", msg); + sprintf( + msg, + "%s: Could not classify return value", + __func__); LOG_WARNMSG("%s", msg); return -2; } diff --git a/src/traceBuffer/ewrr/settb2DataFromGFAST.c b/src/traceBuffer/ewrr/settb2DataFromGFAST.c index 1f0b94a2..7de3de1b 100644 --- a/src/traceBuffer/ewrr/settb2DataFromGFAST.c +++ b/src/traceBuffer/ewrr/settb2DataFromGFAST.c @@ -34,7 +34,7 @@ int traceBuffer_ewrr_settb2DataFromGFAST(struct GFAST_data_struct *gpsData, } // Init tb2Data_struct - tb2Data->ntraces = 6 * gpsData->stream_length; + tb2Data->ntraces = 7 * gpsData->stream_length; tb2Data->traces = (struct tb2Trace_struct *) calloc( (size_t) tb2Data->ntraces, sizeof(struct tb2Trace_struct) ); tb2Data->hashmap = (struct tb2_hashmap_struct *) @@ -47,8 +47,8 @@ int traceBuffer_ewrr_settb2DataFromGFAST(struct GFAST_data_struct *gpsData, // Copy channel names it = 0; for (k = 0; k < gpsData->stream_length; k++) { - // Loop over each channel: Z, N, E, 3, 2, 1 - for (i = 0; i < 6; i++) { + // Loop over each channel: Z, N, E, 3, 2, 1, Q + for (i = 0; i < 7; i++) { strcpy(tb2Data->traces[it].netw, gpsData->data[k].netw); strcpy(tb2Data->traces[it].stnm, gpsData->data[k].stnm); strcpy(tb2Data->traces[it].chan, gpsData->data[k].chan[i]); diff --git a/src/traceBuffer/h5/copyTraceBufferToGFAST.c b/src/traceBuffer/h5/copyTraceBufferToGFAST.c index f6a05423..014a44a1 100644 --- a/src/traceBuffer/h5/copyTraceBufferToGFAST.c +++ b/src/traceBuffer/h5/copyTraceBufferToGFAST.c @@ -37,13 +37,13 @@ int traceBuffer_h5_copyTraceBufferToGFAST( double dt, gain; int i, ierr, ierr1, j, k, l; bool *ltInit; - const int ncomp = 6; + const int ncomp = 7; int debug = 0; ierr = 0; if (traceBuffer->ntraces < 1){return ierr;} // Nothing to do if (fmod(traceBuffer->ntraces, ncomp) != 0) { - LOG_WARNMSG("%s", "Expecting multiple of 6 traces"); + LOG_WARNMSG("%s", "Expecting multiple of 7 traces"); } ltInit = memory_calloc8l((int) (fmax(traceBuffer->ntraces/ncomp, 1))); // Copy the data back @@ -216,6 +216,21 @@ int traceBuffer_h5_copyTraceBufferToGFAST( cblas_dscal(gps_data->data[k].npts, gain, gps_data->data[k].esigmabuff, 1); } + else if (j == 6) + { + gps_data->data[k].npts = traceBuffer->traces[i].ncopy; + ierr1 = copyTrace(gps_data->data[k].npts, + traceBuffer->traces[i].data, + gps_data->data[k].maxpts, + gps_data->data[k].qbuff); + memory_free64f(&traceBuffer->traces[i].data); + if (ierr1 != 0) + { + LOG_ERRMSG("%s", "Error copying qbuff"); + ierr = ierr + 1; + } + // No gain for quality channel + } } if (debug) { @@ -223,7 +238,7 @@ int traceBuffer_h5_copyTraceBufferToGFAST( LOG_DEBUGMSG("copyTB2GFAST data values, ncomp: %d", ncomp); for (k = 0; k < gps_data->stream_length; k++) { npts = gps_data->data[k].npts; - LOG_DEBUGMSG("%s.%s.%sNE321.%s: [%f %f %f %f %f %f]", + LOG_DEBUGMSG("%s.%s.%sNE321Q.%s: [%f %f %f %f %f %f %f]", gps_data->data[k].netw, gps_data->data[k].stnm, gps_data->data[k].chan[0], @@ -233,7 +248,8 @@ int traceBuffer_h5_copyTraceBufferToGFAST( gps_data->data[k].ebuff[npts - 1], gps_data->data[k].usigmabuff[npts - 1], gps_data->data[k].nsigmabuff[npts - 1], - gps_data->data[k].esigmabuff[npts - 1] + gps_data->data[k].esigmabuff[npts - 1], + gps_data->data[k].qbuff[npts - 1] ); } } diff --git a/src/traceBuffer/h5/setData.c b/src/traceBuffer/h5/setData.c index 2b4c499b..ffc3dcc5 100644 --- a/src/traceBuffer/h5/setData.c +++ b/src/traceBuffer/h5/setData.c @@ -222,8 +222,8 @@ NEXT_TRACE:; { LOG_ERRMSG("npts to update is invalid %d %d %d", c1, c2, tb2Data.traces[i].npts); - LOG_DEBUGMSG("setData: i=%d tb2Data %s.%s npts:%d nchunks:%d chunkPtr[0]=%d chunkPtr[nchunks]=%d (c2-c1) != npts!", - i, tb2Data.traces[i].stnm, tb2Data.traces[i].chan, tb2Data.traces[i].npts, tb2Data.traces[i].nchunks, c1, c2); + LOG_DEBUGMSG("setData: i=%d tb2Data %s.%s npts:%d nchunks:%d chunkPtr[0]=%d chunkPtr[nchunks]=%d (c2-c1) != npts!", + i, tb2Data.traces[i].stnm, tb2Data.traces[i].chan, tb2Data.traces[i].npts, tb2Data.traces[i].nchunks, c1, c2); return -1; } for (chunk=0; chunkntraces = traceBuffer->ntraces + 6; // Z, N, E, 3, 2, 1 + traceBuffer->ntraces = traceBuffer->ntraces + 7; // Z, N, E, 3, 2, 1, Q } if (traceBuffer->ntraces < 1) { @@ -101,8 +101,8 @@ NEXT_STATION:; { continue; } - // Loop for number of channels (z, n, e, 3, 2, 1) - for (j = 0; j < 6; j++) + // Loop for number of channels (z, n, e, 3, 2, 1, q) + for (j = 0; j < 7; j++) { memset(traceBuffer->traces[i].netw, 0, sizeof(traceBuffer->traces[i].netw)); @@ -117,7 +117,7 @@ NEXT_STATION:; strcpy(traceBuffer->traces[i].chan, gps_data.data[k].chan[j]); strcpy(traceBuffer->traces[i].loc, gps_data.data[k].loc); traceBuffer->traces[i].dtGroupNumber = ndtGroups[k]; - traceBuffer->traces[i].idest = k * 6 + j; + traceBuffer->traces[i].idest = k * 7 + j; if (debug) { LOG_DEBUGMSG("setH5: Check traceBuffer->traces[%d].chan = %s", From c351465de4ff8e890ea6e17a52c52e1547dd51e6 Mon Sep 17 00:00:00 2001 From: ulbergc Date: Mon, 6 Feb 2023 14:28:27 -0800 Subject: [PATCH 06/18] Update gfast params in gfast.props and sa.conf --- run/params/gfast.props.SA | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run/params/gfast.props.SA b/run/params/gfast.props.SA index a9fcc8ca..3f3015fd 100644 --- a/run/params/gfast.props.SA +++ b/run/params/gfast.props.SA @@ -39,7 +39,7 @@ waitTime=1.0 # zone. Otherwise, if utm_zone is set to -12345 or not specified the UTM # zone will be estimated from the event hpyocenter provided in the ElarmS # message -utm_zone = 10 +utm_zone = -12345 # Mechanism for initializing sampling period # 1 -> Sets GPS sampling period to default (dt_default) # 2 -> Obtains the sampling period from the dtfile From 841281570efd6b86b6576a22b00f4eb40894d0e4 Mon Sep 17 00:00:00 2001 From: claude Date: Tue, 7 Feb 2023 14:08:04 -0800 Subject: [PATCH 07/18] Initial changes for building on RedHat 8.7 --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 58271b19..22d78b5b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -34,7 +34,7 @@ LIBS = $(EW_LIB) $(ISCL_LIB) $(INIPARSER_LIB) $(XML2_LIB) $(HDF5_LIB) $(COMP $(ACTIVEMQ_LIB) $(DM_LIB) $(APR_LIB) $(LAPACKE_LIB) $(CBLAS_LIB) $(FFTW_LIB) $(SSL_LIB) \ $(XERCES_LIB) $(QLIB2_LIB) $(CRYPTO_LIB) $(EWLIB)/libew_mt.a -SYSLIBS = -ldl -lm -lnsl -lrt -pthread -lz -lsz -lstdc++ +SYSLIBS = -ldl -lm -lrt -pthread -lz -lsz -lstdc++ %.o: %.c $(cc) -c $< -o $@ $(UFLAGS) $(CFLAGS) $(DEBUG) $(INCL) From 34427a96d75e560902dc91944e136f58e9755bfe Mon Sep 17 00:00:00 2001 From: Carl Ulberg Date: Thu, 23 Mar 2023 17:20:25 +0000 Subject: [PATCH 08/18] Update doxygen algorithm version strings --- src/doxygen.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doxygen.conf b/src/doxygen.conf index 40cc57b5..15f03d17 100644 --- a/src/doxygen.conf +++ b/src/doxygen.conf @@ -14,7 +14,7 @@ LAYOUT_FILE = ../../doxygen.layout PROJECT_NAME = "GFAST" # version number -PROJECT_NUMBER = "GFAST: gfast-1.2.1-2022-11-28" +PROJECT_NUMBER = "GFAST: gfast-1.2.2-2022-12-28" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From a85bfaed30272f5b38f6f1e81f4187fe02bcbf91 Mon Sep 17 00:00:00 2001 From: Carl Ulberg Date: Thu, 13 Apr 2023 00:44:00 +0000 Subject: [PATCH 09/18] add GFAST 1.2.3 --- Make.include.gfast | 92 ++++++ include/gfast_config.h | 4 +- include/gfast_core.h | 93 +++++- include/gfast_struct.h | 1 + run/params/gfast.props.SA | 3 + src/Makefile | 14 +- src/activeMQ/Makefile | 14 +- src/core/Makefile | 14 +- src/core/cmt/Makefile | 14 +- src/core/coordtools/Makefile | 14 +- src/core/data/Makefile | 14 +- src/core/events/Makefile | 14 +- src/core/ff/Makefile | 14 +- src/core/log/Makefile | 19 +- src/core/properties/Makefile | 14 +- src/core/properties/initialize.c | 28 +- src/core/properties/print.c | 6 + src/core/scaling/Makefile | 14 +- src/core/scaling/pgd_readIni.c | 4 +- src/core/waveformProcessor/Makefile | 14 +- src/core/waveformProcessor/parseQChannel.c | 32 ++ src/core/waveformProcessor/peakDisplacement.c | 44 ++- src/dmlib/Makefile | 14 +- src/eewUtils/Makefile | 14 +- src/eewUtils/driveGFAST.c | 34 ++- src/gfast_eew.c | 106 ++++--- src/hdf5/Makefile | 14 +- src/tests/CoreWaveformProcessorUT.cc | 277 +++++++++++++++++- src/tests/Makefile | 14 +- src/traceBuffer/Makefile | 14 +- src/traceBuffer/ewrr/Makefile | 14 +- .../ewrr/unpackTraceBuf2Messages.c | 2 +- src/traceBuffer/h5/Makefile | 14 +- src/xml/Makefile | 14 +- src/xml/quakeML/Makefile | 14 +- src/xml/shakeAlert/Makefile | 14 +- 36 files changed, 725 insertions(+), 314 deletions(-) create mode 100644 Make.include.gfast diff --git a/Make.include.gfast b/Make.include.gfast new file mode 100644 index 00000000..2206b965 --- /dev/null +++ b/Make.include.gfast @@ -0,0 +1,92 @@ +# Makefile variables specific to GFAST + +# Make.include.Linux should define things like CFLAGS, CCFLAGS, BITS +include $(EEWDIR)/Make.include.$(shell uname) + +# Next set of vars are for GFAST +GFAST_USE_EW=-DGFAST_USE_EW +GFAST_USE_AMQ=-DGFAST_USE_AMQ +GFAST_USE_DMLIB=-DGFAST_USE_DMLIB + +ifdef GFAST_USE_EW +CFLAGS+=$(GFAST_USE_EW) +endif +ifdef GFAST_USE_AMQ +CFLAGS+=$(GFAST_USE_AMQ) +endif +ifdef GFAST_USE_DMLIB +CFLAGS+=$(GFAST_USE_DMLIB) +endif +ifdef ENABLE_PLOG +CFLAGS+=$(ENABLE_PLOG) +endif + +ifeq ($(COMPEARTH),) + COMPEARTH=/usr/local/mtbeach +endif +ifeq ($(COMPEARTH_INCL),) + COMPEARTH_INCL=-I$(COMPEARTH)/include +endif +ifeq ($(COMPEARTH_LIB),) + COMPEARTH_LIB=$(COMPEARTH)/lib/libcompearth_static.a +endif + +ifeq ($(ISCL),) + ISCL=/usr/local/iscl +endif +ifeq ($(ISCL_INCL),) + ISCL_INCL=-I$(ISCL)/include +endif +ifeq ($(ISCL_LIB),) + ISCL_LIB=$(ISCL)/lib/libiscl_static.a +endif + +ifeq ($(INIPARSER),) + INIPARSER=/usr/local/iniparser-4.1 +endif +ifeq ($(INIPARSER_INCL),) + INIPARSER_INCL=-I$(INIPARSER)/include +endif +ifeq ($(INIPARSER_LIB),) + INIPARSER_LIB=$(INIPARSER)/lib/libiniparser.a +endif + +ifeq ($(LAPACKE),) + LAPACKE=/usr +endif +ifeq ($(LAPACKE_INCL),) + LAPACKE_INCL=-I$(LAPACKE)/include/lapacke +endif +ifeq ($(LAPACKE_LIB),) + LAPACKE_LIB=$(LAPACKE)/lib$(BITS)/liblapack.so.3 $(LAPACKE)/lib$(BITS)/liblapacke.so.3 +endif + +ifeq ($(XML2),) + XML2=/usr +endif +ifeq ($(XML2_INCL),) + XML2_INCL=-I$(XML2)/include/libxml2 +endif +ifeq ($(XML2_LIB),) + XML2_LIB=-L$(XML2)/lib$(BITS) -lxml2 +endif + +ifeq ($(CBLAS),) + CBLAS=/usr +endif +ifeq ($(CBLAS_INCL),) + CBLAS_INCL=-I$(CBLAS)/include/openblas +endif +ifeq ($(CBLAS_LIB),) + CBLAS_LIB=-L$(CBLAS)/lib$(BITS)/atlas -ltatlas +endif + +ifeq ($(HDF5),) + HDF5=/usr +endif +ifeq ($(HDF5_INCL),) + HDF5_INCL=-I$(HDF5)/include +endif +ifeq ($(HDF5_LIB),) + HDF5_LIB=-lhdf5 +endif \ No newline at end of file diff --git a/include/gfast_config.h b/include/gfast_config.h index 4b17c8a9..08123f31 100644 --- a/include/gfast_config.h +++ b/include/gfast_config.h @@ -1,7 +1,7 @@ #ifndef _gfast_config__h_ #define _gfast_config__h_ 1 -#define GFAST_VERSION "gfast-1.2.2-2022-12-28" -#define GFAST_MAXMSG_LEN 4096 +#define GFAST_VERSION "gfast-1.2.3-2023-04-10" +#define GFAST_MAXMSG_LEN 8192 #define MAX_OUTPUT_INTERVALS 16 #define MAX_THROTTLING_THRESHOLDS 100 #define MAX_SIGMA_LOOKUP_VALUES 100 diff --git a/include/gfast_core.h b/include/gfast_core.h index dcdbbf3c..2812e822 100644 --- a/include/gfast_core.h +++ b/include/gfast_core.h @@ -304,6 +304,7 @@ int core_ff_weightObservations(const int mrows, // Logging // //----------------------------------------------------------------------------// +#ifdef ENABLE_PLOG void init_plog(); void core_log_plog_V(const char *msg); void core_log_plog_D(const char *msg); @@ -312,6 +313,7 @@ void core_log_plog_W(const char *msg); void core_log_plog_E(const char *msg); void core_log_plog_F(const char *msg); void core_log_plog_N(const char *msg); +#endif #ifndef ERRMSG #define ERRMSG(msg, fmt, ...) \ @@ -325,6 +327,7 @@ void core_log_plog_N(const char *msg); }; #endif +#ifdef ENABLE_PLOG #ifndef LOG_ERRMSG #define LOG_ERRMSG(fmt, ...) \ { \ @@ -334,7 +337,23 @@ void core_log_plog_N(const char *msg); core_log_plog_E(errmsg); \ }; #endif +#else +#ifndef LOG_ERRMSG +#define LOG_ERRMSG(fmt, ...) \ +{ \ + char errmsg[GFAST_MAXMSG_LEN]; \ + memset(errmsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + sprintf(errmsg, "[ERROR]: (%s:%s:line=%d) ", __FILE__, __func__, __LINE__ );\ + do \ + { \ + snprintf(&errmsg[strlen(errmsg)], GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + } while(0); \ + core_log_logErrorMessage(errmsg); \ +}; +#endif +#endif +#ifdef ENABLE_PLOG #ifndef LOG_WARNMSG #define LOG_WARNMSG(fmt, ...) \ { \ @@ -344,7 +363,23 @@ void core_log_plog_N(const char *msg); core_log_plog_W(warnmsg); \ }; #endif +#else +#ifndef LOG_WARNMSG +#define LOG_WARNMSG(fmt, ...) \ +{ \ + char warnmsg[GFAST_MAXMSG_LEN]; \ + memset(warnmsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + sprintf(warnmsg, "[WARNING]: (%s:%s:line=%d) ", __FILE__, __func__, __LINE__ ); \ + do \ + { \ + snprintf(&warnmsg[strlen(warnmsg)], GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + } while(0); \ + core_log_logWarningMessage(warnmsg); \ +}; +#endif +#endif +#ifdef ENABLE_PLOG #ifndef LOG_INFOMSG #define LOG_INFOMSG(fmt, ...) \ { \ @@ -354,7 +389,23 @@ void core_log_plog_N(const char *msg); core_log_plog_I(infoMsg); \ }; #endif +#else +#ifndef LOG_INFOMSG +#define LOG_INFOMSG(fmt, ...) \ +{ \ + char infoMsg[GFAST_MAXMSG_LEN]; \ + memset(infoMsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + sprintf(infoMsg, "[INFO] %s: ", __func__); \ + do \ + { \ + snprintf(&infoMsg[strlen(infoMsg)], GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + } while(0); \ + core_log_logInfoMessage(infoMsg); \ +}; +#endif +#endif +#ifdef ENABLE_PLOG #ifndef LOG_DEBUGMSG #define LOG_DEBUGMSG(fmt, ...) \ { \ @@ -364,7 +415,23 @@ void core_log_plog_N(const char *msg); core_log_plog_D(debugMsg); \ }; #endif +#else +#ifndef LOG_DEBUGMSG +#define LOG_DEBUGMSG(fmt, ...) \ +{ \ + char debugMsg[GFAST_MAXMSG_LEN]; \ + memset(debugMsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + sprintf(debugMsg, "[DEBUG] %s: ", __func__); \ + do \ + { \ + snprintf(&debugMsg[strlen(debugMsg)], GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + } while(0); \ + core_log_logDebugMessage(debugMsg); \ +}; +#endif +#endif +#ifdef ENABLE_PLOG #ifndef LOG_MSG #define LOG_MSG(fmt, ...) \ { \ @@ -374,6 +441,27 @@ void core_log_plog_N(const char *msg); core_log_plog_I(debugMsg); \ }; #endif +#else +#ifndef LOG_MSG +#define LOG_MSG(fmt, ...) \ +{ \ + char debugMsg[GFAST_MAXMSG_LEN]; \ + memset(debugMsg, 0, GFAST_MAXMSG_LEN*sizeof(char)); \ + struct tm *gtime; \ + time_t now; \ + time(&now); \ + gtime = gmtime(&now); \ + sprintf(debugMsg, "%4d-%02d-%02d %2d:%02d:%02d [MTH] %s: ", \ + gtime->tm_year+1900, gtime->tm_mon + 1, gtime->tm_mday, \ + gtime->tm_hour % 24, gtime->tm_min, gtime->tm_sec, __func__); \ + do \ + { \ + snprintf(&debugMsg[strlen(debugMsg)], GFAST_MAXMSG_LEN, fmt, __VA_ARGS__); \ + } while(0); \ + core_log_logMessage(debugMsg); \ +}; +#endif +#endif int core_log_closeLogs(void); int core_log_closeErrorLog(void); @@ -538,9 +626,12 @@ int core_scaling_readRawSigmaThresholdLookupFile(const char *rawSigmaThresholdLo /* Parse the packed quality channel, return chi^2 value */ double core_waveformProcessor_parseQChannelChi2CWU( const double q_value); -/* Parse the packed quality channel, return mapped chi^2 value*/ +/* Parse the packed quality channel, return mapped chi^2 value */ int core_waveformProcessor_parseQChannelChi2CWUmap( const double q_value); +/* Parse the packed quality channel, return goodness (0 or 1) */ +int core_waveformProcessor_parseQChannelGoodness( + const double q_value); /* Compute the offset in north, east, and up */ int core_waveformProcessor_offset(const int utm_zone, const double svel_window, diff --git a/include/gfast_struct.h b/include/gfast_struct.h index 51b8b201..d54aa0d8 100644 --- a/include/gfast_struct.h +++ b/include/gfast_struct.h @@ -56,6 +56,7 @@ struct GFAST_pgd_props_struct double u_raw_sigma_threshold; /*!< Maximum raw sigma (up) to allow in pd calculations (cm) */ double n_raw_sigma_threshold; /*!< Maximum raw sigma (east) to allow in pd calculations (cm) */ double e_raw_sigma_threshold; /*!< Maximum raw sigma (north) to allow in pd calculations (cm) */ + int q_value_threshold; /*!< Don't use pd observations for a station if q value is below threshold */ double pgd_sigma_throttle; /*!< Maximum pgd magnitude uncertainty to allow in sending xml */ double SA_mag_threshold; /*!< Magnitude threshold above which to send xml messages */ double minimum_pgd_cm; /*!< Minimum value to include a pgd value in inversion (cm) */ diff --git a/run/params/gfast.props.SA b/run/params/gfast.props.SA index 3f3015fd..1ca059c5 100644 --- a/run/params/gfast.props.SA +++ b/run/params/gfast.props.SA @@ -110,6 +110,9 @@ pgdThresholdLookupFile = /app/gfast/run/params/pgd_threshold_PW.txt # Positional uncertainty thresholds for including peak displacement observations # If not specified, allow any or NAN uncertainties rawSigmaThresholdLookupFile = /app/gfast/run/params/raw_sigma_threshold_PW.txt +# Q channel threshold (as of 3/22/23, using the last digit, which is the +# encoded goodness value). If goodness is below this threshold (<), ignore the observation +q_value_threshold = 1 # If defined, don't send xml if pgd_sigma is greater than this value pgd_sigma_throttle = 0.5 # Message throttling logic diff --git a/src/Makefile b/src/Makefile index 22d78b5b..6db9944b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,6 +1,8 @@ # Makefile for GFAST EEWDIR = ../.. -include $(EEWDIR)/Make.include.$(shell uname) +GFAST_DIR = .. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast EW_INCL = -I$(EWDIR)/include EWLIB = $(EWDIR)/lib @@ -8,16 +10,6 @@ EWLIB = $(EWDIR)/lib DM_DIR = $(EEWDIR)/libs/dmlib DM_LIB = $(DM_DIR)/libdm.a -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif - # Used to add more information on program startup output UFLAGS = -DBUILDER=\"$(BUILDER)\" diff --git a/src/activeMQ/Makefile b/src/activeMQ/Makefile index 8e2275a7..7e37f578 100644 --- a/src/activeMQ/Makefile +++ b/src/activeMQ/Makefile @@ -1,17 +1,9 @@ # Makefile for GFAST/src/activeMQ # EEWDIR = ../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = activeMQ.c.o activeMQ.cpp.o readIni.c.o # ShakeAlertConsumer.cpp.o consumer.cpp.o diff --git a/src/core/Makefile b/src/core/Makefile index e82119e3..635db668 100644 --- a/src/core/Makefile +++ b/src/core/Makefile @@ -1,17 +1,9 @@ # Makefile for GFAST/src/core EEWDIR = ../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast SDIRS = cmt data events ff log properties scaling waveformProcessor coordtools LIB = gfast_core.a diff --git a/src/core/cmt/Makefile b/src/core/cmt/Makefile index bb85691b..8b23e75a 100644 --- a/src/core/cmt/Makefile +++ b/src/core/cmt/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = decomposeMomentTensor.o gridSearch.o setDiagonalWeightMatrix.o \ weightForwardModel.o depthGridSearch.o initialize.o setForwardModel.o \ diff --git a/src/core/coordtools/Makefile b/src/core/coordtools/Makefile index 27fa19be..3ef9892f 100644 --- a/src/core/coordtools/Makefile +++ b/src/core/coordtools/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = ll2utm.o utm2ll.o diff --git a/src/core/data/Makefile b/src/core/data/Makefile index b8d20941..926076ab 100644 --- a/src/core/data/Makefile +++ b/src/core/data/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = finalize.o initialize.o readMetaDataFile.o readSiteMaskFile.o diff --git a/src/core/events/Makefile b/src/core/events/Makefile index 1543074d..2d44b812 100644 --- a/src/core/events/Makefile +++ b/src/core/events/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = freeEvents.o newEvent.o removeCancelledEvent.o removeExpiredEvents.o\ getMinOriginTime.o printEvent.o removeExpiredEvent.o updateEvent.o syncXMLStatusWithEvents.o diff --git a/src/core/ff/Makefile b/src/core/ff/Makefile index aa38da74..5a9dd836 100644 --- a/src/core/ff/Makefile +++ b/src/core/ff/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast DEBUG = -g diff --git a/src/core/log/Makefile b/src/core/log/Makefile index e8977978..bb655488 100644 --- a/src/core/log/Makefile +++ b/src/core/log/Makefile @@ -2,20 +2,15 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast +ifdef ENABLE_PLOG OBJS = log.cpp.o -# log.c.o +else +OBJS = log.c.o +endif DEBUG = -g CCFLAGS += -O0 -D_REENTRANT -Dstatic_config diff --git a/src/core/properties/Makefile b/src/core/properties/Makefile index cd6982cc..45a73448 100644 --- a/src/core/properties/Makefile +++ b/src/core/properties/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = finalize.o initialize.o print.o diff --git a/src/core/properties/initialize.c b/src/core/properties/initialize.c index db95e9bd..021269f1 100644 --- a/src/core/properties/initialize.c +++ b/src/core/properties/initialize.c @@ -51,7 +51,11 @@ int core_properties_initialize(const char *propfilename, // Require the properties file exists if (!os_path_isfile(propfilename)) { +#ifdef ENABLE_PLOG LOG_ERRMSG("properties file (%s) does not exist\n", propfilename); +#else + printf("properties file (%s) does not exist\n", propfilename); +#endif return -1; } @@ -62,22 +66,28 @@ int core_properties_initialize(const char *propfilename, // Load the ini file ini = iniparser_load(propfilename); if (ini == NULL) { +#ifdef ENABLE_PLOG LOG_ERRMSG("Iniparser could not read: %s\n", propfilename); +#else + printf("Iniparser could not read: %s\n", propfilename); +#endif return -1; } strcpy(props->propfilename, propfilename); //-------------------------GFAST General Parameters-----------------------// +#ifndef ENABLE_PLOG // set open output log file. - // s = iniparser_getstring(ini, "general:logFileName\0", - // "gfast.log\0"); - // LOG_DEBUGMSG("Opening %s for log output\n",s); - // core_log_openLog(s); - // if (!os_path_isfile(s)) - // { - // LOG_ERRMSG("Cannot open log output file %s\n", s); - // return -1; - // } + s = iniparser_getstring(ini, "general:logFileName\0", + "gfast.log\0"); + printf("Opening %s for log output\n",s); + core_log_openLog(s); + if (!os_path_isfile(s)) + { + printf("Cannot open log output file %s\n", s); + return -1; + } +#endif //metadata file s = iniparser_getstring(ini, "general:metaDataFile\0", diff --git a/src/core/properties/print.c b/src/core/properties/print.c index e72648e7..510e2d14 100644 --- a/src/core/properties/print.c +++ b/src/core/properties/print.c @@ -231,6 +231,12 @@ void core_properties_print(struct GFAST_props_struct props) } else { LOG_DEBUGMSG("%s Will allow any E raw sigma values in pd calculations", lspace); } + if (props.pgd_props.q_value_threshold >= 0) { + LOG_DEBUGMSG("%s Will ignore pd values if Q value < %d", + lspace, props.pgd_props.q_value_threshold); + } else { + LOG_DEBUGMSG("%s Will allow any Q values in pd calculations", lspace); + } LOG_DEBUGMSG("%s Will throttle messages below SA mag %f", lspace, props.pgd_props.SA_mag_threshold); LOG_DEBUGMSG("%s Will throttle messages above pgd mag sigma %f", diff --git a/src/core/scaling/Makefile b/src/core/scaling/Makefile index 304ad864..8ba9d7de 100644 --- a/src/core/scaling/Makefile +++ b/src/core/scaling/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = pgd_depthGridSearch.o pgd_gridSearch.o pgd_readIni.o \ pgd_setForwardModel.o pgd_weightForwardModel.o pgd_finalize.o \ diff --git a/src/core/scaling/pgd_readIni.c b/src/core/scaling/pgd_readIni.c index 71372e16..a9185d3c 100644 --- a/src/core/scaling/pgd_readIni.c +++ b/src/core/scaling/pgd_readIni.c @@ -166,11 +166,13 @@ int core_scaling_pgd_readIni(const char *propfilename, ierr = core_scaling_readSigmaLookupFile(sigmaLookupFile, pgd_props); + // only use PGD observations if Q value >= this threshold + setVarName(group, "q_value_threshold\0", var); + pgd_props->q_value_threshold = iniparser_getint(ini, var, -1); // only send XML for pgd magnitude sigma below this threshold setVarName(group, "pgd_sigma_throttle\0", var); pgd_props->pgd_sigma_throttle = iniparser_getdouble(ini, var, 10); - // props->pgd_sigma_throttle = iniparser_getdouble(ini, "general:pgd_sigma_throttle\0", 10); if (pgd_props->pgd_sigma_throttle <= 0) { LOG_ERRMSG("Error pgd_sigma_throttle must be positive: %f", diff --git a/src/core/waveformProcessor/Makefile b/src/core/waveformProcessor/Makefile index 86f4bde9..3bcbe564 100644 --- a/src/core/waveformProcessor/Makefile +++ b/src/core/waveformProcessor/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = offset.o peakDisplacement.o peakDisplacementHelper.o parseQChannel.o diff --git a/src/core/waveformProcessor/parseQChannel.c b/src/core/waveformProcessor/parseQChannel.c index 94e90a1d..083ac4d3 100644 --- a/src/core/waveformProcessor/parseQChannel.c +++ b/src/core/waveformProcessor/parseQChannel.c @@ -65,4 +65,36 @@ int core_waveformProcessor_parseQChannelChi2CWUmap( } return chimap; +} + + +/*! + * @brief Unpack the quality channel. The most recent definition as of 3/22/23 was: + * Q = 100000*int(10*PDOP) + 1000*nsat + 10*fixtyp + goodness + * + * @param[in] q_value Q channel value. It is a double to stay consistent + * with other data buffers. But treated as integer here. + * + * @result the goodness value (0 or 1) - a combination of chi^2, nsats, clocks, etc. + * + * @author Brendan Crowell (PNSN) and Carl Ulberg (PNSN) + * + * @date Mar 2023 + * + */ +int core_waveformProcessor_parseQChannelGoodness( + const double q_value) +{ + int goodness; + + // Extract the last 1 digit, should only be 0 or 1, so modulo 2 should work + if (q_value < 0) { + LOG_WARNMSG("parseQChannelChi2CWU - q_value is negative (%lf), changing to positive!", + q_value); + goodness = (int)(q_value * -1) % 2; + } else { + goodness = (int)(q_value) % 2; + } + + return goodness; } \ No newline at end of file diff --git a/src/core/waveformProcessor/peakDisplacement.c b/src/core/waveformProcessor/peakDisplacement.c index 718bd7b4..f8443d27 100644 --- a/src/core/waveformProcessor/peakDisplacement.c +++ b/src/core/waveformProcessor/peakDisplacement.c @@ -47,7 +47,8 @@ int core_waveformProcessor_peakDisplacement( { double currentTime, distance, effectiveHypoDist, epoch, peakDisp, x1, x2, y1, y2, tmin, tmax, obsTime, - uMaxUncertainty, nMaxUncertainty, eMaxUncertainty, qMax, qRef, qPeak; + uMaxUncertainty, nMaxUncertainty, eMaxUncertainty; + int qMin, qRef, qPeak; int k, nsites, zone_loc, iRef, iPeak; //unused int i; bool lnorthp; @@ -78,6 +79,20 @@ int core_waveformProcessor_peakDisplacement( const double u_raw_sigma_threshold = pgd_props->u_raw_sigma_threshold; const double n_raw_sigma_threshold = pgd_props->n_raw_sigma_threshold; const double e_raw_sigma_threshold = pgd_props->e_raw_sigma_threshold; + // Threshold value for Q channel. If the observed Q value for the reference + // or peak displacement is <= this threshold, ignore the pd observation. + // If q_value_threshold is < 0, allow any Q value + const int q_value_threshold = pgd_props->q_value_threshold; + + LOG_MSG("Calculating PD, svel=(%.1f/%.1f), pgd_bounds=(%.1f/%.1f), sigma_thresh=(%.1f/%.1f/%.1f), q_thresh=%d", + svel_window, + min_svel_window, + min_pgd_cm, + max_pgd_cm, + u_raw_sigma_threshold, + n_raw_sigma_threshold, + e_raw_sigma_threshold, + q_value_threshold); //------------------------------------------------------------------------// // @@ -90,7 +105,7 @@ int core_waveformProcessor_peakDisplacement( uMaxUncertainty = 0.0; eMaxUncertainty = 0.0; nMaxUncertainty = 0.0; - qMax = 0.0; + qMin = 0; if (gps_data.stream_length != pgd_data->nsites) { LOG_ERRMSG("Inconsistent structure sizes %d %d", @@ -125,7 +140,7 @@ int core_waveformProcessor_peakDisplacement( uMaxUncertainty = 0.0; eMaxUncertainty = 0.0; nMaxUncertainty = 0.0; - qMax = 0.0; + qMin = 0; // Make sure I have the latest/greatest site location pgd_data->sta_lat[k] = gps_data.data[k].sta_lat; pgd_data->sta_lon[k] = gps_data.data[k].sta_lon; @@ -187,7 +202,6 @@ int core_waveformProcessor_peakDisplacement( gps_data.data[k].netw, gps_data.data[k].loc); */ - //if (distance < effectiveHypoDist) if (distance < effectiveHypoDist) { // Compute the peak displacement max(norm(u + n + e, 2)) @@ -254,12 +268,12 @@ M 9 at 100km: -6.687 + 150 - 21.4*2 = 100 cm(?) eMaxUncertainty = fmax(gps_data.data[k].esigmabuff[iRef], gps_data.data[k].esigmabuff[iPeak]); } if (!isnan(gps_data.data[k].qbuff[iRef]) && !isnan(gps_data.data[k].qbuff[iPeak])) { - qRef = core_waveformProcessor_parseQChannelChi2CWU(gps_data.data[k].qbuff[iRef]); - qPeak = core_waveformProcessor_parseQChannelChi2CWU(gps_data.data[k].qbuff[iPeak]); - qMax = fmax(qRef, qPeak); + qRef = core_waveformProcessor_parseQChannelGoodness(gps_data.data[k].qbuff[iRef]); + qPeak = core_waveformProcessor_parseQChannelGoodness(gps_data.data[k].qbuff[iPeak]); + qMin = fmin(qRef, qPeak); } - LOG_MSG("%s.%s.%s.%s peakDisp=%f dist=%.2f, peakSigmas=(%.4f,%.4f,%.4f), peakQ=%.4f", + LOG_MSG("%s.%s.%s.%s peakDisp=%f dist=%.2f, peakSigmas=(%.4f,%.4f,%.4f), minQ=%d", gps_data.data[k].stnm, gps_data.data[k].chan[0], gps_data.data[k].netw, gps_data.data[k].loc, peakDisp, @@ -267,7 +281,7 @@ M 9 at 100km: -6.687 + 150 - 21.4*2 = 100 cm(?) uMaxUncertainty, nMaxUncertainty, eMaxUncertainty, - qMax); + qMin); } // Is the observation above the defined minimum? @@ -313,6 +327,18 @@ M 9 at 100km: -6.687 + 150 - 21.4*2 = 100 cm(?) ); } + // Is the observation under the Q value threshold? + if ((q_value_threshold >= 0) && (qMin < q_value_threshold)) { + l_use_observation = false; + LOG_DEBUGMSG("CCC PeakDisp, %s.%s.%s.%s ignoring observation, qRef/qPeak: (%d/%d), threshold: %d", + gps_data.data[k].stnm, gps_data.data[k].chan[0], + gps_data.data[k].netw, gps_data.data[k].loc, + qRef, + qPeak, + q_value_threshold + ); + } + // If it isn't a NaN and within the sanity bounds then retain it for processing if (l_use_observation) { pgd_data->pd_time[k] = obsTime; // epoch diff --git a/src/dmlib/Makefile b/src/dmlib/Makefile index 9b38c1f5..477f6cf9 100644 --- a/src/dmlib/Makefile +++ b/src/dmlib/Makefile @@ -2,20 +2,12 @@ # EEWDIR = ../../.. -include $(EEWDIR)/Make.include.$(shell uname) +GFAST_DIR = ../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast DMLIB_INCL = -I$(EEWDIR)/libs/dmlib -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif - OBJS = dmlibWrapper.cpp.o LIB = DEBUG = -g diff --git a/src/eewUtils/Makefile b/src/eewUtils/Makefile index c6b62048..908fc929 100644 --- a/src/eewUtils/Makefile +++ b/src/eewUtils/Makefile @@ -3,20 +3,12 @@ # EEWDIR = ../../.. -include $(EEWDIR)/Make.include.$(shell uname) +GFAST_DIR = ../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast EW_INCL = -I$(EWDIR)/include -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif - OBJS = driveCMT.o driveFF.o drivePGD.o makeXML.o\ parseCoreXML.o setLogFileNames.o driveGFAST.o diff --git a/src/eewUtils/driveGFAST.c b/src/eewUtils/driveGFAST.c index 477e2a9f..ffcbf3a4 100644 --- a/src/eewUtils/driveGFAST.c +++ b/src/eewUtils/driveGFAST.c @@ -117,8 +117,10 @@ int eewUtils_driveGFAST(const double currentTime, struct GFAST_activeEvents_xml_status *xml_status) { struct GFAST_shakeAlert_struct SA; - // char errorLogFileName[PATH_MAX], infoLogFileName[PATH_MAX], - // debugLogFileName[PATH_MAX], warnLogFileName[PATH_MAX]; +#ifndef ENABLE_PLOG + char errorLogFileName[PATH_MAX], infoLogFileName[PATH_MAX], + debugLogFileName[PATH_MAX], warnLogFileName[PATH_MAX]; +#endif char *cmtQML, *ffXML, *pgdXML; double t1, t2, age_of_event, t_time, t_time0, t_loop, t_event; int mins; @@ -159,8 +161,10 @@ int eewUtils_driveGFAST(const double currentTime, t1 = SA.time; // Origin time t2 = currentTime; age_of_event = (t2 - t1); - LOG_MSG("%s: Starting event time:%lf evid:%s [age_of_event=%f]", + LOG_MSG("%s: Starting event, current time:%lf evid:%s [age_of_event=%f]", fcnm, t2, SA.eventid, age_of_event); + LOG_MSG("%s: Event info OT:%lf lat:%lf lon:%lf mag:%lf", + fcnm, SA.time, SA.lat, SA.lon, SA.mag); // Skip event if the times doen't make sense if (t1 > t2) { @@ -188,13 +192,15 @@ int eewUtils_driveGFAST(const double currentTime, // Set the log file names. Comment out in advance of providing compile // option to use these (for NOAA) or plog (for ShakeAlert) - CWU - // eewUtils_setLogFileNames(SA.eventid,props.SAoutputDir, - // errorLogFileName, infoLogFileName, - // debugLogFileName, warnLogFileName); - // core_log_openErrorLog(errorLogFileName); - // core_log_openInfoLog(infoLogFileName); - // core_log_openWarningLog(warnLogFileName); - // core_log_openDebugLog(debugLogFileName); +#ifndef ENABLE_PLOG + eewUtils_setLogFileNames(SA.eventid,props.SAoutputDir, + errorLogFileName, infoLogFileName, + debugLogFileName, warnLogFileName); + core_log_openErrorLog(errorLogFileName); + core_log_openInfoLog(infoLogFileName); + core_log_openWarningLog(warnLogFileName); + core_log_openDebugLog(debugLogFileName); +#endif /////////////////////////////////////////////////////////////////////////// // Retrieve data from h5 buffer @@ -665,8 +671,10 @@ int eewUtils_driveGFAST(const double currentTime, } } } // End check on updating archive or finalizing event +#ifndef ENABLE_PLOG // Close the logs - // core_log_closeLogs(); + core_log_closeLogs(); +#endif } // Loop on the events LOG_MSG("MTH: end loop on events ierr=%d [Timing: %.3fs]\n", ierr, time_timeStamp() - t_loop); @@ -863,7 +871,7 @@ bool send_xml_filter(const struct GFAST_props_struct *props, // skip site if it wasn't used if (!pgd->lsiteUsed[i]) { continue; } // pd is in meters, so convert to cm before comparing to threshold - if (pgd_data->pd[i] * 100. > props->pgd_props.throttle_pgd_threshold[i_throttle]) { + if (pgd_data->pd[i] * 100. >= props->pgd_props.throttle_pgd_threshold[i_throttle]) { num_pgd_exceeded++; } } @@ -896,7 +904,7 @@ bool send_xml_filter(const struct GFAST_props_struct *props, LOG_DEBUGMSG("%s: PGD mag sigma: %f, threshold mag sigma: %f, PGD mag: %f", __func__, core->magUncer, props->pgd_props.pgd_sigma_throttle, core->mag); } - if (core->magUncer < props->pgd_props.pgd_sigma_throttle) { + if (core->magUncer <= props->pgd_props.pgd_sigma_throttle) { mag_sigma_met = true; LOG_MSG("%s: PGD mag sigma met! PGD mag sigma: %f, threshold mag sigma: %f, PGD mag: %f", __func__, core->magUncer, props->pgd_props.pgd_sigma_throttle, core->mag); diff --git a/src/gfast_eew.c b/src/gfast_eew.c index 7dec709b..75540fa1 100644 --- a/src/gfast_eew.c +++ b/src/gfast_eew.c @@ -30,7 +30,7 @@ char *check_dir_for_messages(const char *dirname, int *ierr); * @param[in] fcnm What is the name of the main function? */ -void printProgramInfo(bool use_dmlib, const char *fcnm) { +void printProgramInfo(const char *fcnm) { const int bufflen = 1024; char *message=NULL; int ind; @@ -42,17 +42,22 @@ void printProgramInfo(bool use_dmlib, const char *fcnm) { ind += snprintf(message + ind, bufflen - ind, "%s Version: %s (Build %s %s by %s)\n", fcnm, GFAST_VERSION, __DATE__, __TIME__, BUILDER); - if (use_dmlib) { - char *dmlib_version = getDmLibVersion(); - ind += snprintf(message + ind, bufflen - ind, "%s\n", dmlib_version); - free(dmlib_version); - } +#ifdef GFAST_USE_DMLIB + char *dmlib_version = getDmLibVersion(); + ind += snprintf(message + ind, bufflen - ind, "%s\n", dmlib_version); + free(dmlib_version); +#endif H5get_libversion(&H5majnum, &H5minnum, &H5relnum); ind += snprintf(message + ind, bufflen - ind, "HDF5 library version: %u.%u.%u\n", H5majnum, H5minnum, H5relnum); ind += snprintf(message + ind, bufflen - ind, "ISCL library version: %s\n", ISCL_VERSION); +#ifdef ENABLE_PLOG LOG_MSG("%s", message); +#else + // Need to use printf until GFAST_core_properties_initialize is called + printf("%s\n", message); +#endif free(message); } @@ -93,10 +98,12 @@ int main(int argc, char **argv) int ierr, im, msWait, nTracebufs2Read; bool lacquire, lnewEvent, in_loop; const int rdwt = 2; // H5 file is read only (1) or read/write (2) - // char errorLogFileName[PATH_MAX]; - // char infoLogFileName[PATH_MAX]; - // char debugLogFileName[PATH_MAX]; - // char warnLogFileName[PATH_MAX]; +#ifndef ENABLE_PLOG + char errorLogFileName[PATH_MAX]; + char infoLogFileName[PATH_MAX]; + char debugLogFileName[PATH_MAX]; + char warnLogFileName[PATH_MAX]; +#endif bool check_message_dir = false; bool USE_AMQ = false; bool USE_DMLIB = false; @@ -109,16 +116,22 @@ int main(int argc, char **argv) #endif #endif +#ifdef ENABLE_PLOG // logging stuff init_plog(); +#endif - printProgramInfo(USE_DMLIB, fcnm); + printProgramInfo(fcnm); // Initialize. Only works if propfile is specified if (argc > 1) { strncpy(propfilename, argv[1], PATH_MAX - 1); } else { +#ifdef ENABLE_PLOG LOG_MSG("%s", "Usage: gfast_eew propfilename"); +#else + printf("%s\n", "Usage: gfast_eew propfilename"); +#endif return EXIT_SUCCESS; } @@ -164,7 +177,11 @@ int main(int argc, char **argv) memset(&tb2Data, 0, sizeof(struct tb2Data_struct)); // Read the program properties +#ifdef ENABLE_PLOG LOG_MSG("%s: Reading configuration from %s", fcnm, propfilename); +#else + printf("%s: Reading configuration from %s\n", fcnm, propfilename); +#endif ierr = GFAST_core_properties_initialize(propfilename, opmode, &props); if (ierr != 0) { LOG_ERRMSG("%s: Error reading GFAST initialization file: %s\n", fcnm, propfilename); @@ -200,26 +217,26 @@ int main(int argc, char **argv) if (USE_AMQ) { activeMQ_start(); // start library - /* - Start connection, to be used by DMMessageSender. - This should be written using just dmlib - CWU - */ - ierr = startDestinationConnection( - props.activeMQ_props.user, - props.activeMQ_props.password, - props.activeMQ_props.destinationURL, - props.activeMQ_props.msReconnect, - props.activeMQ_props.maxAttempts, - props.verbose); - if (ierr == 0) { - LOG_ERRMSG("%s: Attempted to re-initialize activeMQ connection object", fcnm); - } - if (ierr < 0) { - LOG_ERRMSG("%s: Error initializing activeMQ connection object", fcnm); - goto ERROR; - } /* dmlib startup */ if (USE_DMLIB) { + /* + Start connection, to be used by DMMessageSender. + This should be written using just dmlib - CWU + */ + ierr = startDestinationConnection( + props.activeMQ_props.user, + props.activeMQ_props.password, + props.activeMQ_props.destinationURL, + props.activeMQ_props.msReconnect, + props.activeMQ_props.maxAttempts, + props.verbose); + if (ierr == 0) { + LOG_ERRMSG("%s: Attempted to re-initialize activeMQ connection object", fcnm); + } + if (ierr < 0) { + LOG_ERRMSG("%s: Error initializing activeMQ connection object", fcnm); + goto ERROR; + } /*start message receiver*/ if (props.verbose > 0) { LOG_MSG("%s: Initializing event receiver on %s...", @@ -358,7 +375,7 @@ int main(int argc, char **argv) amqMessage = NULL; // Don't start loop until prop.waitTime has elapsed (default 1 second) t1 = time_timeStamp(); - double tloop = t1-t0; + double tloop = t1 - t0; // Print time for the previous iteration. Only print once until // props.waitTime has been reached and iteration actually starts again. @@ -368,9 +385,12 @@ int main(int argc, char **argv) } if (tloop < props.waitTime) { + usleep((props.waitTime - tloop) * 1000 * 1000); + // Put in a continue here since t1 is reset at the top of the loop + // Want to make sure it is representing the actual start continue; } - else if ((props.waitTime>0.0)&&((tloop) >= 2*props.waitTime)) { + else if ((props.waitTime > 0.0) && (tloop >= 2 * props.waitTime)) { LOG_MSG("== [GFAST t :%f] Main loop [Timing: %.4fs] >= 2x%f s waitTimes. not keeping up", time_timeStamp(), tloop, props.waitTime); } @@ -383,7 +403,7 @@ int main(int argc, char **argv) if (tstatus1 - tstatus0 > 3600.0) { LOG_MSG("%s: GFAST has been running for %d hours, start time %f", fcnm, (int) ((tstatus1 - tstatus)/3600.0), tstatus); - printProgramInfo(USE_DMLIB, fcnm); + printProgramInfo(fcnm); tstatus0 = tstatus1; } @@ -503,6 +523,24 @@ int main(int argc, char **argv) LOG_INFOMSG("%s: New event %s added", fcnm, SA.eventid); if (props.verbose > 2){GFAST_core_events_printEvents(SA);} } +#ifndef ENABLE_PLOG + // Set the log file names + eewUtils_setLogFileNames(SA.eventid,props.SAoutputDir, + errorLogFileName, infoLogFileName, + debugLogFileName, warnLogFileName); + if (os_path_isfile(errorLogFileName)) { + remove(errorLogFileName); + } + if (os_path_isfile(infoLogFileName)) { + remove(infoLogFileName); + } + if (os_path_isfile(debugLogFileName)) { + remove(debugLogFileName); + } + if (os_path_isfile(warnLogFileName)) { + remove(warnLogFileName); + } +#endif // Initialize the HDF5 file ierr = GFAST_hdf5_initialize(props.h5ArchiveDir, SA.eventid, @@ -607,8 +645,10 @@ int main(int argc, char **argv) GFAST_core_data_finalize(&gps_data); GFAST_core_properties_finalize(&props); traceBuffer_h5_finalize(&h5traceBuffer); +#ifndef ENABLE_PLOG // Close the big logfile - // core_log_closeLog(); + core_log_closeLog(); +#endif if (ierr != 0) { printf("%s: Terminating with error\n", fcnm); return EXIT_FAILURE; diff --git a/src/hdf5/Makefile b/src/hdf5/Makefile index bcdeda72..f0ebe8e2 100644 --- a/src/hdf5/Makefile +++ b/src/hdf5/Makefile @@ -2,17 +2,9 @@ # EEWDIR = ../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = copy.o getMaxGroupNumber.o initialize.o setFileName.o \ createType.o h5_cinter.o memory.o update.o diff --git a/src/tests/CoreWaveformProcessorUT.cc b/src/tests/CoreWaveformProcessorUT.cc index eec6ae82..9a15070b 100644 --- a/src/tests/CoreWaveformProcessorUT.cc +++ b/src/tests/CoreWaveformProcessorUT.cc @@ -11,6 +11,8 @@ #include "iscl/memory/memory.h" #include "gfast.h" +#include "gfast_ut_utils.h" + /* * Test the peakDisplacementHelper function. With input data and uncertainty @@ -121,29 +123,300 @@ TEST(CoreWaveformProcessor, testParseQChannel) { double value; // Temp code to print all values - // int chimap; + // int chimap, goodness; // double chi2; // for (int i = 0; i < 100; i++) { // value = 12300 + i; // chi2 = core_waveformProcessor_parseQChannelChi2CWU(value); // chimap = core_waveformProcessor_parseQChannelChi2CWUmap(value); - // std::cout << value << ": " << chimap << ", " << chi2 << std::endl; + // goodness = core_waveformProcessor_parseQChannelGoodness(value); + // std::cout << value << ": " << chimap << ", " << chi2 << ", " << goodness << std::endl; // } // Test a few values value = 12300; EXPECT_EQ(0, core_waveformProcessor_parseQChannelChi2CWUmap(value)); EXPECT_DOUBLE_EQ(0.0001, core_waveformProcessor_parseQChannelChi2CWU(value)); + EXPECT_EQ(0, core_waveformProcessor_parseQChannelGoodness(value)); value = 612325; EXPECT_EQ(25, core_waveformProcessor_parseQChannelChi2CWUmap(value)); EXPECT_DOUBLE_EQ(0.001, core_waveformProcessor_parseQChannelChi2CWU(value)); + EXPECT_EQ(1, core_waveformProcessor_parseQChannelGoodness(value)); value = 765450; EXPECT_EQ(50, core_waveformProcessor_parseQChannelChi2CWUmap(value)); EXPECT_DOUBLE_EQ(0.01, core_waveformProcessor_parseQChannelChi2CWU(value)); + EXPECT_EQ(0, core_waveformProcessor_parseQChannelGoodness(value)); value = 234575; EXPECT_EQ(75, core_waveformProcessor_parseQChannelChi2CWUmap(value)); EXPECT_DOUBLE_EQ(0.1, core_waveformProcessor_parseQChannelChi2CWU(value)); + EXPECT_EQ(1, core_waveformProcessor_parseQChannelGoodness(value)); +} + +void fill_gps_data(struct GFAST_data_struct *gps_data, + const int k, + const char *netw, + const char *stat, + const char *chan, + const char *loc, + const double lat, + const double lon, + const double elev, + const double dt, + const double gain, + const int mpts) { + strcpy(gps_data->data[k].netw, netw); + strcpy(gps_data->data[k].stnm, stat); + strncpy(gps_data->data[k].chan[0], chan, 2); + strcat( gps_data->data[k].chan[0], "Z\0"); + strncpy(gps_data->data[k].chan[1], chan, 2); + strcat( gps_data->data[k].chan[1], "N\0"); + strncpy(gps_data->data[k].chan[2], chan, 2); + strcat( gps_data->data[k].chan[2], "E\0"); + strncpy(gps_data->data[k].chan[3], chan, 2); + strcat( gps_data->data[k].chan[3], "3\0"); + strncpy(gps_data->data[k].chan[4], chan, 2); + strcat( gps_data->data[k].chan[4], "2\0"); + strncpy(gps_data->data[k].chan[5], chan, 2); + strcat( gps_data->data[k].chan[5], "1\0"); + strncpy(gps_data->data[k].chan[6], chan, 2); + strcat( gps_data->data[k].chan[6], "Q\0"); + strcpy(gps_data->data[k].loc, loc); + gps_data->data[k].sta_lat = lat; + gps_data->data[k].sta_lon = lon; + gps_data->data[k].sta_alt = elev; + gps_data->data[k].dt = dt; + gps_data->data[k].gain[0] = gain; + gps_data->data[k].gain[1] = gain; + gps_data->data[k].gain[2] = gain; + gps_data->data[k].gain[3] = gain; + gps_data->data[k].gain[4] = gain; + gps_data->data[k].gain[5] = gain; + gps_data->data[k].gain[6] = 1; // Quality channel has no gain + + gps_data->data[k].maxpts = mpts; + gps_data->data[k].ubuff = memory_calloc64f(mpts); + gps_data->data[k].nbuff = memory_calloc64f(mpts); + gps_data->data[k].ebuff = memory_calloc64f(mpts); + gps_data->data[k].usigmabuff = memory_calloc64f(mpts); + gps_data->data[k].nsigmabuff = memory_calloc64f(mpts); + gps_data->data[k].esigmabuff = memory_calloc64f(mpts); + gps_data->data[k].qbuff = memory_calloc64f(mpts); + gps_data->data[k].tbuff = memory_calloc64f(mpts); +} + +/* + * Fixture for testing peakDisplacement() function + * Has two "normal" stations that can be put out of spec in various ways + * in order to not return peak displacement measurements + */ +class CoreWaveformProcessorFixture : public::testing::Test { + protected: + struct GFAST_pgd_props_struct pgd_props; + struct GFAST_data_struct gps_data; + struct GFAST_peakDisplacementData_struct pgd_data; + struct GFAST_pgdResults_struct pgd; + + double lat, lon, dep, time; + int ierr, nsites_pgd, k, j; + + void SetUp() { + const int NPTS = 10; + + // Initialize necessary pgd properties + memset(&pgd_props, 0, sizeof(struct GFAST_pgd_props_struct)); + pgd_props.utm_zone = -12345; + pgd_props.window_vel = 3; + pgd_props.min_window_vel = 0.01; + pgd_props.minimum_pgd_cm = 0.0; + pgd_props.maximum_pgd_cm = 3500; + pgd_props.u_raw_sigma_threshold = 35; + pgd_props.n_raw_sigma_threshold = 17; + pgd_props.e_raw_sigma_threshold = 14; + pgd_props.q_value_threshold = 1; + pgd_props.ngridSearch_deps = 10; + pgd_props.ngridSearch_lats = 1; + pgd_props.ngridSearch_lons = 1; + pgd_props.min_sites = 2; + + // Initialize origin + lat = 46; + lon = -122; + dep = 8; + time = 0; + + // Initialize gps_data + memset(&gps_data, 0, sizeof(struct GFAST_data_struct)); + + gps_data.stream_length = 2; + gps_data.data = (struct GFAST_waveform3CData_struct *) + calloc((size_t) gps_data.stream_length, + sizeof(struct GFAST_waveform3CData_struct)); + fill_gps_data(&gps_data, 0, "UW\0", "TEST1\0", "LYZ\0", "00\0", 46.02, -122.02, 1, 1, 1, NPTS); + fill_gps_data(&gps_data, 1, "UW\0", "TEST2\0", "LYZ\0", "00\0", 46.03, -122.03, 1, 1, 1, NPTS); + + // Initialize pgd_data, pgd + memset(&pgd_data, 0, sizeof( struct GFAST_peakDisplacementData_struct)); + memset(&pgd, 0, sizeof(struct GFAST_pgdResults_struct)); + + ierr = core_scaling_pgd_initialize(pgd_props, gps_data, &pgd, &pgd_data); + + // Now actually put some data in gps_data + double tdata[NPTS] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + double udata[NPTS] = {0, 3, 5, 6, 4, 3, -1, 0, 3, 4}; + double ndata[NPTS] = {0, 2, 3, 4, 5, 3, 2, 0, -1, -4}; + double edata[NPTS] = {0, -3, -5, -4, -4, -3, -1, 0, 2, 3}; + double usigmadata[NPTS] = {.1, .1, .1, .1, .1, .1, .1, .1, .1, .1}; + double nsigmadata[NPTS] = {.1, .1, .1, .1, .1, .1, .1, .1, .1, .1}; + double esigmadata[NPTS] = {.1, .1, .1, .1, .1, .1, .1, .1, .1, .1}; + double qdata[NPTS] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + for (k = 0; k < gps_data.stream_length; k++) { + for (j = 0; j < NPTS; j++) { + gps_data.data[k].ubuff[j] = udata[j]; + gps_data.data[k].nbuff[j] = ndata[j]; + gps_data.data[k].ebuff[j] = edata[j]; + gps_data.data[k].usigmabuff[j] = usigmadata[j]; + gps_data.data[k].nsigmabuff[j] = nsigmadata[j]; + gps_data.data[k].esigmabuff[j] = esigmadata[j]; + gps_data.data[k].qbuff[j] = qdata[j]; + gps_data.data[k].tbuff[j] = tdata[j]; + } + gps_data.data[k].npts = NPTS; + } + } + + void TearDown() {} +}; + +TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementNormal) { + nsites_pgd = GFAST_core_waveformProcessor_peakDisplacement( + &pgd_props, + lat, + lon, + dep, + time, + gps_data, + &pgd_data, + &ierr); + + EXPECT_EQ(2, nsites_pgd); + EXPECT_EQ(1, pgd_data.lactive[0]); + EXPECT_EQ(1, pgd_data.lactive[1]); + + EXPECT_TRUE(lequal(8.24621, pgd_data.pd[0], .00001)) << "Error pgd is wrong"; +} + +TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementTooDistant) { + // If a station is not within the s-wave mask, it should be ignored + gps_data.data[0].sta_lat = 40; + nsites_pgd = GFAST_core_waveformProcessor_peakDisplacement( + &pgd_props, + lat, + lon, + dep, + time, + gps_data, + &pgd_data, + &ierr); + + EXPECT_EQ(1, nsites_pgd); + EXPECT_EQ(0, pgd_data.lactive[0]); + EXPECT_EQ(1, pgd_data.lactive[1]); +} + +TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementMasked) { + // If a site is masked (via siteMaskFile) it should be ignored + pgd_data.lmask[1] = true; + nsites_pgd = GFAST_core_waveformProcessor_peakDisplacement( + &pgd_props, + lat, + lon, + dep, + time, + gps_data, + &pgd_data, + &ierr); + + EXPECT_EQ(1, nsites_pgd); + EXPECT_EQ(1, pgd_data.lactive[0]); + EXPECT_EQ(0, pgd_data.lactive[1]); +} + +TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementMinPGD) { + // A displacement that is 0.0 (flat-lined) should be ignored + for (j = 0; j < 10; j++) { + gps_data.data[0].ubuff[j] = 0; + gps_data.data[0].nbuff[j] = 0; + gps_data.data[0].ebuff[j] = 0; + } + nsites_pgd = GFAST_core_waveformProcessor_peakDisplacement( + &pgd_props, + lat, + lon, + dep, + time, + gps_data, + &pgd_data, + &ierr); + + EXPECT_EQ(1, nsites_pgd); + EXPECT_EQ(0, pgd_data.lactive[0]); + EXPECT_EQ(1, pgd_data.lactive[1]); +} + +TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementMaxPGD) { + // A displacement that is too large should be ignored + gps_data.data[1].ebuff[3] = 1000; + nsites_pgd = GFAST_core_waveformProcessor_peakDisplacement( + &pgd_props, + lat, + lon, + dep, + time, + gps_data, + &pgd_data, + &ierr); + + EXPECT_EQ(1, nsites_pgd); + EXPECT_EQ(1, pgd_data.lactive[0]); + EXPECT_EQ(0, pgd_data.lactive[1]); +} + +TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementSigma) { + // An uncertainty that is too large means the pgd should be ignored + gps_data.data[0].esigmabuff[0] = 10; + nsites_pgd = GFAST_core_waveformProcessor_peakDisplacement( + &pgd_props, + lat, + lon, + dep, + time, + gps_data, + &pgd_data, + &ierr); + + EXPECT_EQ(1, nsites_pgd); + EXPECT_EQ(0, pgd_data.lactive[0]); + EXPECT_EQ(1, pgd_data.lactive[1]); +} + +TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementQThreshold) { + // A q value that doesn't meet the criteria means the pgd should be ignored + gps_data.data[1].qbuff[0] = 0; + nsites_pgd = GFAST_core_waveformProcessor_peakDisplacement( + &pgd_props, + lat, + lon, + dep, + time, + gps_data, + &pgd_data, + &ierr); + + EXPECT_EQ(1, nsites_pgd); + EXPECT_EQ(1, pgd_data.lactive[0]); + EXPECT_EQ(0, pgd_data.lactive[1]); } diff --git a/src/tests/Makefile b/src/tests/Makefile index ce6b7d21..3ee219e9 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -2,7 +2,9 @@ # Modeled after libs/utils/tests/Makefile, may need additional changes EEWDIR = ../../.. -include $(EEWDIR)/Make.include.$(shell uname) +GFAST_DIR = ../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast EW_INCL = -I$(EWDIR)/include EWLIB = $(EWDIR)/lib @@ -10,16 +12,6 @@ EWLIB = $(EWDIR)/lib DM_DIR = $(EEWDIR)/libs/dmlib DM_LIB = $(DM_DIR)/libdm.a -#ifdef GFAST_USE_EW -CCFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CCFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CCFLAGS+=$(GFAST_USE_DMLIB) -#endif - OBJS = ../activeMQ/gfast_amq.a ../eewUtils/gfast_utils.a ../xml/gfast_xml.a ../core/gfast_core.a \ ../traceBuffer/traceBuffer.a ../hdf5/hdf5.a ../activeMQ/gfast_amq.a diff --git a/src/traceBuffer/Makefile b/src/traceBuffer/Makefile index 4186ee36..24ba036f 100644 --- a/src/traceBuffer/Makefile +++ b/src/traceBuffer/Makefile @@ -1,20 +1,12 @@ # Makefile for GFAST/src/traceBuffer EEWDIR = ../../.. -include $(EEWDIR)/Make.include.$(shell uname) +GFAST_DIR = ../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast EW_INCL = -I$(EWDIR)/include -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif - DEBUG = -g INCL = -I ../../include $(HDF5_INCL) $(EW_INCL) $(CBLAS_INCL) $(ISCL_INCL) diff --git a/src/traceBuffer/ewrr/Makefile b/src/traceBuffer/ewrr/Makefile index 81c93151..0c850dfe 100644 --- a/src/traceBuffer/ewrr/Makefile +++ b/src/traceBuffer/ewrr/Makefile @@ -2,20 +2,12 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast EW_INCL = -I$(EWDIR)/include -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif - OBJS = classifyRetval.o flushRing.o freetb2Trace.o initialize.o \ unpackTraceBuf2Messages.o finalize.o freetb2Data.o getMessagesFromRing.o \ settb2DataFromGFAST.o tb2_hash.o diff --git a/src/traceBuffer/ewrr/unpackTraceBuf2Messages.c b/src/traceBuffer/ewrr/unpackTraceBuf2Messages.c index 990a1729..40e523f6 100644 --- a/src/traceBuffer/ewrr/unpackTraceBuf2Messages.c +++ b/src/traceBuffer/ewrr/unpackTraceBuf2Messages.c @@ -94,7 +94,7 @@ int traceBuffer_ewrr_unpackTraceBuf2Messages( //char **msg_logos = (char **)malloc(sizeof(char *) * nRead); //char msg_logos[nRead][15]; - char buf[15]; + char buf[256]; char *logo, *nscl; int debug = 0; diff --git a/src/traceBuffer/h5/Makefile b/src/traceBuffer/h5/Makefile index 204631ed..718d0a68 100644 --- a/src/traceBuffer/h5/Makefile +++ b/src/traceBuffer/h5/Makefile @@ -2,20 +2,12 @@ # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast EW_INCL = -I$(EWDIR)/include -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif - OBJS = copyTraceBufferToGFAST.o getDoubleArray.o readData.o \ setScalars.o finalize.o getScalars.o setData.o setTraceBufferFromGFAST.o \ getData.o initialize.o setFileName.o diff --git a/src/xml/Makefile b/src/xml/Makefile index 5ccb9113..8a7460ba 100644 --- a/src/xml/Makefile +++ b/src/xml/Makefile @@ -1,17 +1,9 @@ # Makefile for GFAST/xml EEWDIR = ../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast SDIRS = quakeML shakeAlert LIB = gfast_xml.a diff --git a/src/xml/quakeML/Makefile b/src/xml/quakeML/Makefile index cae4d574..23fe5b45 100644 --- a/src/xml/quakeML/Makefile +++ b/src/xml/quakeML/Makefile @@ -1,17 +1,9 @@ # Makefile for GFAST/src/xml/quakeML # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = depth.o focalMechanism.o longitude.o momentTensor.o origin.o \ tensor.o units.o epoch2string.o latitude.o magnitude.o nodalPlanes.o \ diff --git a/src/xml/shakeAlert/Makefile b/src/xml/shakeAlert/Makefile index 74e6cd74..6e47741a 100644 --- a/src/xml/shakeAlert/Makefile +++ b/src/xml/shakeAlert/Makefile @@ -1,17 +1,9 @@ # Makefile for GFAST/src/xml/shakeAlert # EEWDIR = ../../../.. -include $(EEWDIR)/Make.include.$(shell uname) - -#ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -#endif -#ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -#endif -#ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -#endif +GFAST_DIR = ../../.. +# Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) +include $(GFAST_DIR)/Make.include.gfast OBJS = coreInfo.o segment.o slip.o vertex.o vertices.o geometry.o From e61638a81fcdd06008e5b67195dc061625250ddb Mon Sep 17 00:00:00 2001 From: Carl Ulberg Date: Wed, 10 May 2023 22:44:08 +0000 Subject: [PATCH 10/18] Gfast updates for sa3.1.0 --- include/gfast_config.h | 2 +- run/bin/gfast_eew_env.sh | 2 +- src/core/waveformProcessor/peakDisplacement.c | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/gfast_config.h b/include/gfast_config.h index 08123f31..4011c688 100644 --- a/include/gfast_config.h +++ b/include/gfast_config.h @@ -1,6 +1,6 @@ #ifndef _gfast_config__h_ #define _gfast_config__h_ 1 -#define GFAST_VERSION "gfast-1.2.3-2023-04-10" +#define GFAST_VERSION "gfast-1.2.3-2023-05-09" #define GFAST_MAXMSG_LEN 8192 #define MAX_OUTPUT_INTERVALS 16 #define MAX_THROTTLING_THRESHOLDS 100 diff --git a/run/bin/gfast_eew_env.sh b/run/bin/gfast_eew_env.sh index 070ecc43..0f52b24f 100644 --- a/run/bin/gfast_eew_env.sh +++ b/run/bin/gfast_eew_env.sh @@ -4,7 +4,7 @@ echo -e 'Version: $Id: gfast_env.sh 000 2023-01-11 18:00:00Z ulbergc $\n' # With "LEAPSECONDS=", times will be handled consistently internally # pending addressing iscl <-> dmlib issues. -export LEAPSECONDS= +export LEAPSECONDS=no-correction-for-gfast # export LEAPSECONDS=/app/share/etc/leapseconds #env | grep LEAPSECONDS diff --git a/src/core/waveformProcessor/peakDisplacement.c b/src/core/waveformProcessor/peakDisplacement.c index f8443d27..0774a946 100644 --- a/src/core/waveformProcessor/peakDisplacement.c +++ b/src/core/waveformProcessor/peakDisplacement.c @@ -106,6 +106,8 @@ int core_waveformProcessor_peakDisplacement( eMaxUncertainty = 0.0; nMaxUncertainty = 0.0; qMin = 0; + qRef = 0; + qPeak = 0; if (gps_data.stream_length != pgd_data->nsites) { LOG_ERRMSG("Inconsistent structure sizes %d %d", @@ -141,6 +143,8 @@ int core_waveformProcessor_peakDisplacement( eMaxUncertainty = 0.0; nMaxUncertainty = 0.0; qMin = 0; + qRef = 0; + qPeak = 0; // Make sure I have the latest/greatest site location pgd_data->sta_lat[k] = gps_data.data[k].sta_lat; pgd_data->sta_lon[k] = gps_data.data[k].sta_lon; From 488c38678c666ab757a80dcd1394d0a12ca46d17 Mon Sep 17 00:00:00 2001 From: ulbergc Date: Fri, 12 May 2023 08:27:28 -0700 Subject: [PATCH 11/18] Change q value threshold (turned off for now) --- run/params/gfast.props.SA | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run/params/gfast.props.SA b/run/params/gfast.props.SA index 1ca059c5..029ce168 100644 --- a/run/params/gfast.props.SA +++ b/run/params/gfast.props.SA @@ -112,7 +112,7 @@ pgdThresholdLookupFile = /app/gfast/run/params/pgd_threshold_PW.txt rawSigmaThresholdLookupFile = /app/gfast/run/params/raw_sigma_threshold_PW.txt # Q channel threshold (as of 3/22/23, using the last digit, which is the # encoded goodness value). If goodness is below this threshold (<), ignore the observation -q_value_threshold = 1 +q_value_threshold = -1 # If defined, don't send xml if pgd_sigma is greater than this value pgd_sigma_throttle = 0.5 # Message throttling logic From c81fcbfcf8baa12c560a0052c6c77d847d7e6e14 Mon Sep 17 00:00:00 2001 From: Carl Ulberg Date: Fri, 13 Oct 2023 17:08:32 +0000 Subject: [PATCH 12/18] Update GFAST to v1.2.4 --- .gitignore | 1 + ChangeLog | 83 +++ include/gfast_activeMQ.h | 8 +- include/gfast_config.h | 2 +- include/gfast_core.h | 43 +- include/gfast_eewUtils.h | 25 + include/gfast_struct.h | 36 +- run/params/gfast.props.SA | 18 + src/core/events/Makefile | 8 +- src/core/events/newEvent.c | 5 +- src/core/properties/print.c | 36 ++ src/core/scaling/pgd_readIni.c | 15 +- .../peakDisplacementHelper.c | 13 +- src/dmlib/dmlibWrapper.cpp | 14 +- src/eewUtils/Makefile | 5 +- src/eewUtils/driveGFAST.c | 279 +++------- src/eewUtils/fillCoreEventInfo.c | 77 +++ src/eewUtils/sendXMLFilter.c | 220 ++++++++ src/tests/CoreDataUT.cc | 37 ++ src/tests/CoreEventsUT.cc | 96 +++- src/tests/CoreWaveformProcessorUT.cc | 136 +++-- src/tests/DmLibWrapperUT.cc | 112 ++++ src/tests/EewUtilsUT.cc | 520 +++++++++++++++--- src/tests/Hdf5UT.cc | 105 ++++ src/tests/Makefile | 37 +- src/tests/data/eewUtils_quakeML_example.cmt | 119 ++++ src/tests/data/eewUtils_xml_example.ff | 2 + src/tests/data/eewUtils_xml_example.pgd | 2 + src/tests/data/gfast.props | 23 +- src/tests/data/site_mask_file.dat | 4 + src/tests/gfast_ut_utils.h | 73 ++- src/xml/quakeML/epoch2string.c | 2 +- 32 files changed, 1729 insertions(+), 427 deletions(-) create mode 100644 ChangeLog create mode 100644 src/eewUtils/fillCoreEventInfo.c create mode 100644 src/eewUtils/sendXMLFilter.c create mode 100644 src/tests/DmLibWrapperUT.cc create mode 100644 src/tests/Hdf5UT.cc create mode 100644 src/tests/data/eewUtils_quakeML_example.cmt create mode 100644 src/tests/data/eewUtils_xml_example.ff create mode 100644 src/tests/data/eewUtils_xml_example.pgd create mode 100644 src/tests/data/site_mask_file.dat diff --git a/.gitignore b/.gitignore index 97e33f5e..953781a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ # local files to be ignored by git src/gfast_eew +src/tests/data/tmp diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..7de780cb --- /dev/null +++ b/ChangeLog @@ -0,0 +1,83 @@ +version 1.2.4 2023-08-03 Carl Ulberg + * Summary: + - Add internal/external message versions in driveGFAST. The internal versions start at v-1, + then decrement by 1 on every single iteration. The external version numbers start at v0, + and increment by 1 on pgd xml messages that are actually sent to the Solution Aggregator. + Every message is still saved in the run/out directory - if the message was sent to the SA, + it will have the positive, external version number. If it was not sent, it will have the + negative, internal version number. + - Change how pgd xml timestamp is defined. Previously it represented the time at the start + of the current iteration. Now it represents the time closest to when the message is + actually sent (really from when the message is generated, but then it is sent in the next + step). + - Add publish change thresholds. Among the other send filter logic, the change thresholds + ensure that GFAST won't send identical (or nearly identical) messages to the SA. + - Refactor some code out of driveGFAST (easier to unit test), fillCoreEventInfo and + sendXMLFilter + - New unit tests +version 1.2.3 2023-04-10 Carl Ulberg + * Summary: + - Fully use Q channel with "goodness/use" flag. If configuration is set, GFAST will ignore + data points and PGD observations with a use flag of 0, as determined by the CWU/Fastlane + processing. + - Use "sleep" instead of "while true" loop for each 1s iteration. Saves processor time, + although may lead to slight creep in iteration start time. +version 1.2.2 2022-12-28 Carl Ulberg + * Summary: + - Bring Q channel through processing. Not entirely set up, but the Q channel is mostly + available when calculating PGD, along with the 6 other channels: ENZ/ENZ uncertainty. +version 1.2.1 2022-11-28 Carl Ulberg + * Summary: + - Add hashmap to tb2 processing to speed up get/unpack messages. + - Add raw observation uncertainty thresholds in PGD processing. This is intended to handle + clock correction steps in the data. +version 1.2.0 2022-10-04 Carl Ulberg + * Summary: + - Add GFAST to ShakeAlert repo + - Use DMMessageReceiver for reading AMQ messages. + - Add GFAST to ShakeAlert unit test coverage report. + - Add config options for turning on/off pgd/cmt/ff processing. + - Reduce hdf5 archive size +### Versions before this were in the PNSN github repo at https://github.com/pnsn/GFAST ### +version 1.1.10 2022-07-27 Carl Ulberg + * Summary: + - logging updates, etc before adding to ShakeAlert repo +version 1.1.9 2022-06-29 Carl Ulberg + * Summary: + - pgd_mag_sigma throttling and updated instance header +version 1.1.8 2022-05-27 Carl Ulberg + * Summary: + - add 'assoc' attribute to pgd xml +version 1.1.7 2022-04-28 Carl Ulberg + * Summary: + - min/max pgd thresholds +version 1.1.6 2022-04-01 Carl Ulberg + * Summary: + - update cmt quakeml +version 1.1.5 2022-03-01 Carl Ulberg + * Summary: + - add time/mag based magnitude uncertainty +version 1.1.4b 2022-02-18 Carl Ulberg + * Summary: + - throttle based on time-varying pgd_obs +version 1.1.4 2022-01-14 Carl Ulberg + * Summary: + - throttle based on pgd_obs +version 1.1.3b 2021-12-22 Carl Ulberg + * Summary: + - use nan uncert +version 1.1.3 2021-12-02 Carl Ulberg + * Summary: + - Throttle xml based on SA mag +version 1.1.2 2021-11-17 Carl Ulberg + * Summary: + - Add strike, dip to ff xml message (using old xml writer) +version 1.1.1 2021-11-09 Carl Ulberg + * Summary: + - bug fix from 1.1.0 to only add pgd observations that were used in pgd inversion +version 1.1.0 2021 Carl Ulberg + * Summary: + - Use dmlib to encode pgd xml, with pgd observations +version 1.0.0 2021 Carl Ulberg + * Summary: + - Initial merge of SAdev and 2020 branches from GFAST PNSN github repo \ No newline at end of file diff --git a/include/gfast_activeMQ.h b/include/gfast_activeMQ.h index 953f58f3..b12a7072 100644 --- a/include/gfast_activeMQ.h +++ b/include/gfast_activeMQ.h @@ -50,10 +50,6 @@ void activeMQ_producer_finalize(void *producerIn); /* Send a text message */ int activeMQ_producer_sendMessage(void *producerIn, const char *message); -/* Convenience function to set the tcp URI request */ -char *activeMQ_setTcpURIRequest(const char *url, - const int msReconnect, - const int maxAttempts); /* Initialize the ActiveMQ producer */ void *activeMQ_producer_initialize(const char AMQuser[], const char AMQpassword[], @@ -63,6 +59,10 @@ void *activeMQ_producer_initialize(const char AMQuser[], const bool clientAck, const int verbose, int *ierr); +/* Convenience function to set the tcp URI request */ +char *activeMQ_setTcpURIRequest(const char *url, + const int msReconnect, + const int maxAttempts); #ifndef __cplusplus diff --git a/include/gfast_config.h b/include/gfast_config.h index 4011c688..1a006a61 100644 --- a/include/gfast_config.h +++ b/include/gfast_config.h @@ -1,6 +1,6 @@ #ifndef _gfast_config__h_ #define _gfast_config__h_ 1 -#define GFAST_VERSION "gfast-1.2.3-2023-05-09" +#define GFAST_VERSION "gfast-1.2.4-2023-10-12" #define GFAST_MAXMSG_LEN 8192 #define MAX_OUTPUT_INTERVALS 16 #define MAX_THROTTLING_THRESHOLDS 100 diff --git a/include/gfast_core.h b/include/gfast_core.h index 2812e822..f16a7792 100644 --- a/include/gfast_core.h +++ b/include/gfast_core.h @@ -153,10 +153,10 @@ int core_data_readSiteMaskFile(const char *siteMaskFile, //----------------------------------------------------------------------------// /* Frees memory on an event structure */ void core_events_freeEvents(struct GFAST_activeEvents_struct *events); -/* Convenience function to find min origin time in event list */ -double core_events_getMinOriginTime(struct GFAST_props_struct props, - struct GFAST_activeEvents_struct events, - bool *lnoEvents); +// /* Convenience function to find min origin time in event list */ +// double core_events_getMinOriginTime(struct GFAST_props_struct props, +// struct GFAST_activeEvents_struct events, +// bool *lnoEvents); /* Adds a new event to the event list */ bool core_events_newEvent(struct GFAST_shakeAlert_struct SA, struct GFAST_activeEvents_struct *events, @@ -166,12 +166,12 @@ bool core_events_syncXMLStatusWithEvents(struct GFAST_activeEvents_struct *event /* Print the events in the event list */ void core_events_printEvents(struct GFAST_shakeAlert_struct SA); -/* Remove a cancelled event from the events list */ -bool core_events_removeCancelledEvent(const char *evid, - const double currentTime, - const int verbose, - struct GFAST_shakeAlert_struct SA, - struct GFAST_activeEvents_struct *events); +// /* Remove a cancelled event from the events list */ +// bool core_events_removeCancelledEvent(const char *evid, +// const double currentTime, +// const int verbose, +// struct GFAST_shakeAlert_struct SA, +// struct GFAST_activeEvents_struct *events); /* Look through the events list and remove expired events */ int core_events_removeExpiredEvents(const double maxTime, const double currenTime, @@ -183,10 +183,10 @@ bool core_events_removeExpiredEvent(const double maxtime, const int verbose, struct GFAST_shakeAlert_struct SA, struct GFAST_activeEvents_struct *events); -/* Potentially add the shakeAlert event to the event list */ -bool core_events_updateEvent(struct GFAST_shakeAlert_struct SA, - struct GFAST_activeEvents_struct *events, - int *ierr); +// /* Potentially add the shakeAlert event to the event list */ +// bool core_events_updateEvent(struct GFAST_shakeAlert_struct SA, +// struct GFAST_activeEvents_struct *events, +// int *ierr); //----------------------------------------------------------------------------// @@ -708,24 +708,23 @@ double core_waveformProcessor_peakDisplacementHelper( core_data_readMetaDataFile(__VA_ARGS__) #define GFAST_core_data_readSiteMaskFile(...) \ core_data_readSiteMaskFile(__VA_ARGS__) - + #define GFAST_core_events_freeEvents(...) \ core_events_freeEvents(__VA_ARGS__) -#define GFAST_core_events_getMinOriginTime(...) \ - core_events_getMinOriginTime(__VA_ARGS__) #define GFAST_core_events_newEvent(...) \ core_events_newEvent(__VA_ARGS__) #define GFAST_core_events_syncXMLStatusWithEvents(...) \ core_events_syncXMLStatusWithEvents(__VA_ARGS__) - #define GFAST_core_events_printEvents(...) \ core_events_printEvents(__VA_ARGS__) -#define GFAST_core_events_removeCancelledEvent(...) \ - core_events_removeCancelledEvent(__VA_ARGS__) #define GFAST_core_events_removeExpiredEvent(...) \ core_events_removeExpiredEvent(__VA_ARGS__) -#define GFAST_core_events_updateEvent(...) \ - core_events_updateEvent(__VA_ARGS__) +// #define GFAST_core_events_getMinOriginTime(...) +// core_events_getMinOriginTime(__VA_ARGS__) +// #define GFAST_core_events_removeCancelledEvent(...) +// core_events_removeCancelledEvent(__VA_ARGS__) +// #define GFAST_core_events_updateEvent(...) +// core_events_updateEvent(__VA_ARGS__) #define GFAST_core_ff_faultPlaneGridSearch(...) \ core_ff_faultPlaneGridSearch(__VA_ARGS__) diff --git a/include/gfast_eewUtils.h b/include/gfast_eewUtils.h index 7eced1c4..6303f7c4 100644 --- a/include/gfast_eewUtils.h +++ b/include/gfast_eewUtils.h @@ -96,6 +96,31 @@ void eewUtils_setLogFileNames(const char *eventid, char infoLogFileName[PATH_MAX], char debugLogFileName[PATH_MAX], char warnLogFileName[PATH_MAX]); +/* Fill a coreInfo struct with the given values */ +int eewUtils_fillCoreEventInfo( + const char *evid, + const int version, + const double SA_lat, + const double SA_lon, + const double SA_depth, + const double SA_mag, + const double SA_time, + const int num_stations, + struct coreInfo_struct *core); +/* Helper function for eewUtils_sendXMLFilter, check change thresholds */ +bool eewUtils_changeThresholdsExceeded( + const struct GFAST_props_struct *props, + const struct coreInfo_struct *core, + const struct coreInfo_struct *last_sent_core); +/* Determine if PGD message should be sent */ +bool eewUtils_sendXMLFilter( + const struct GFAST_props_struct *props, + const struct GFAST_shakeAlert_struct *SA, + const struct GFAST_pgdResults_struct *pgd, + const struct GFAST_peakDisplacementData_struct *pgd_data, + const struct coreInfo_struct *core, + const struct coreInfo_struct *last_sent_core, + const double age_of_event); #define GFAST_eewUtils_driveCMT(...) \ eewUtils_driveCMT(__VA_ARGS__) diff --git a/include/gfast_struct.h b/include/gfast_struct.h index d54aa0d8..d0792f26 100644 --- a/include/gfast_struct.h +++ b/include/gfast_struct.h @@ -62,6 +62,12 @@ struct GFAST_pgd_props_struct double minimum_pgd_cm; /*!< Minimum value to include a pgd value in inversion (cm) */ double maximum_pgd_cm; /*!< Maximum value to include a pgd value in inversion (cm) */ int max_assoc_stations; /*!< Maximum stations to add the 'assoc' tag to in xml */ + double change_threshold_mag; /*!< Minimum magnitude change threshold */ + double change_threshold_mag_uncer; /*!< Minimum magnitude uncertainty change threshold */ + double change_threshold_lat; /*!< Minimum latitude change threshold */ + double change_threshold_lon; /*!< Minimum longitude change threshold */ + double change_threshold_orig_time; /*!< Minimum origin time change threshold */ + int change_threshold_num_stations; /*!< Minimum number of stations change threshold */ }; struct GFAST_cmt_props_struct @@ -494,20 +500,6 @@ struct GFAST_activeEvents_struct char pad1[4]; }; -struct GFAST_xml_output_status -{ - char eventid[128]; /*!< Event ID. */ - int version; /*!< GFAST iteration version for this event ID. */ - bool interval_complete[3][MAX_OUTPUT_INTERVALS]; /*!< intervals_complete[] for pgd + cmt + ff = 3 */ -}; - -struct GFAST_activeEvents_xml_status -{ - struct GFAST_xml_output_status *SA_status; - int nev; - //char pad1[4]; /* MTH: seems to be for byte alignment but **check this** */ -}; - struct coreInfo_struct { char id[128]; /*!< Event ID */ @@ -583,6 +575,22 @@ struct coreInfo_struct int numStations; /*!< Number of stations used in event. */ }; +struct GFAST_xml_output_status +{ + char eventid[128]; /*!< Event ID. */ + int internal_version; /*!< GFAST internal version for this event ID. Always < 0 */ + int external_version; /*!< GFAST external version for this event ID. Always >= 0 */ + struct coreInfo_struct last_sent_core; /*!< Core info of the last sent message */ + bool interval_complete[3][MAX_OUTPUT_INTERVALS]; /*!< intervals_complete[] for pgd + cmt + ff = 3 */ +}; + +struct GFAST_activeEvents_xml_status +{ + struct GFAST_xml_output_status *SA_status; + int nev; + //char pad1[4]; /* MTH: seems to be for byte alignment but **check this** */ +}; + struct GFAST_xmlMessages_struct { char **evids; /*!< Event IDs. */ diff --git a/run/params/gfast.props.SA b/run/params/gfast.props.SA index 029ce168..7cce0557 100644 --- a/run/params/gfast.props.SA +++ b/run/params/gfast.props.SA @@ -104,27 +104,45 @@ pgd_min_sites = 4 # Lookup table for non-density corrected value to generate magnitude # uncertainty based on time and magnitude sigmaLookupFile = /app/gfast/run/params/M99.txt + # Lookup table for time-dependant PGD thresholds # columns: time (s) | threshold (cm) | n stations pgdThresholdLookupFile = /app/gfast/run/params/pgd_threshold_PW.txt + # Positional uncertainty thresholds for including peak displacement observations # If not specified, allow any or NAN uncertainties rawSigmaThresholdLookupFile = /app/gfast/run/params/raw_sigma_threshold_PW.txt + # Q channel threshold (as of 3/22/23, using the last digit, which is the # encoded goodness value). If goodness is below this threshold (<), ignore the observation q_value_threshold = -1 + # If defined, don't send xml if pgd_sigma is greater than this value pgd_sigma_throttle = 0.5 + # Message throttling logic SA_mag_threshold = 6.0 + # Minimum and maximum thresholds for using pgd values in inversion (cm). Any # values equal or outside these bounds will be ignored in the inversion. minimum_pgd_cm = 0.0 maximum_pgd_cm = 3500.0 + # Number of observations to be given the 'assoc=true' attribute, which is used # by the ShakeAlert Solution Aggregator in associating algorithm messages. max_assoc_stations = 6 +# Change thresholds to decide when to send a message, assuming other throttles +# pass. If any of these are met or exceeded, a new message would be sent. If +# none are exceeded, message would not be sent. +# If not present, threshold will be ignored +change_threshold_mag = 0.05 +change_threshold_mag_uncer = 0.05 +change_threshold_lat = 0.05 +change_threshold_lon = 0.05 +change_threshold_orig_time = 1 +change_threshold_num_stations = 1 + ################################################################################ # CMT/Finite Fault Properties # ################################################################################ diff --git a/src/core/events/Makefile b/src/core/events/Makefile index 2d44b812..7e618a2a 100644 --- a/src/core/events/Makefile +++ b/src/core/events/Makefile @@ -6,8 +6,12 @@ GFAST_DIR = ../../.. # Make.include.gfast will include $(EEWDIR)/Make.include.$(shell uname) include $(GFAST_DIR)/Make.include.gfast -OBJS = freeEvents.o newEvent.o removeCancelledEvent.o removeExpiredEvents.o\ - getMinOriginTime.o printEvent.o removeExpiredEvent.o updateEvent.o syncXMLStatusWithEvents.o +OBJS = freeEvents.o newEvent.o removeExpiredEvents.o\ + printEvent.o removeExpiredEvent.o syncXMLStatusWithEvents.o + +# Remove some files from compile for now since they are not used - CWU 8/18/23 +# OBJS = freeEvents.o newEvent.o removeCancelledEvent.o removeExpiredEvents.o\ +# getMinOriginTime.o printEvent.o removeExpiredEvent.o updateEvent.o syncXMLStatusWithEvents.o DEBUG = -g CCFLAGS += -O0 -D_REENTRANT -Dstatic_config diff --git a/src/core/events/newEvent.c b/src/core/events/newEvent.c index dd12e4b0..30c2c6d0 100644 --- a/src/core/events/newEvent.c +++ b/src/core/events/newEvent.c @@ -97,7 +97,10 @@ bool core_events_newEvent(struct GFAST_shakeAlert_struct SA, // MTH: Same thing for xml output status structs // Create a status output_status from incoming SA eventid strcpy(output_status.eventid, SA.eventid); - output_status.version=-1; /*will increment to 0 on first xml update*/ + output_status.internal_version = 0; /*will decrement to -1 on first xml update*/ + output_status.external_version = -1; /*will increment to 0 on first xml update*/ + memset(&output_status.last_sent_core, 0, sizeof(struct coreInfo_struct)); + // Append this output_status to the incoming xml_status list of records Xtemp.nev = nev0 + 1; Xtemp.SA_status = (struct GFAST_xml_output_status *) calloc((size_t) Xtemp.nev, sizeof(struct GFAST_xml_output_status)); diff --git a/src/core/properties/print.c b/src/core/properties/print.c index 510e2d14..caab9dd3 100644 --- a/src/core/properties/print.c +++ b/src/core/properties/print.c @@ -248,6 +248,42 @@ void core_properties_print(struct GFAST_props_struct props) lspace, props.pgd_props.maximum_pgd_cm); LOG_DEBUGMSG("%s GFAST Maximum stations to include assoc tag: %d", lspace, props.pgd_props.max_assoc_stations); + + // Change thresholds to prevent sending the same (or very similar) solution + bool change_thresholds_not_set = true; + if (props.pgd_props.change_threshold_mag >= 0) { + change_thresholds_not_set = false; + LOG_DEBUGMSG("%s Change threshold, magnitude: %f", + lspace, props.pgd_props.change_threshold_mag); + } + if (props.pgd_props.change_threshold_mag_uncer >= 0) { + change_thresholds_not_set = false; + LOG_DEBUGMSG("%s Change threshold, magnitude uncertainty: %f", + lspace, props.pgd_props.change_threshold_mag_uncer); + } + if (props.pgd_props.change_threshold_lat >= 0) { + change_thresholds_not_set = false; + LOG_DEBUGMSG("%s Change threshold, latitude: %f", + lspace, props.pgd_props.change_threshold_lat); + } + if (props.pgd_props.change_threshold_lon >= 0) { + change_thresholds_not_set = false; + LOG_DEBUGMSG("%s Change threshold, longitude: %f", + lspace, props.pgd_props.change_threshold_lon); + } + if (props.pgd_props.change_threshold_orig_time >= 0) { + change_thresholds_not_set = false; + LOG_DEBUGMSG("%s Change threshold, origin time: %f (s)", + lspace, props.pgd_props.change_threshold_orig_time); + } + if (props.pgd_props.change_threshold_num_stations >= 0) { + change_thresholds_not_set = false; + LOG_DEBUGMSG("%s Change threshold, number of stations: %d", + lspace, props.pgd_props.change_threshold_num_stations); + } + if (change_thresholds_not_set) { + LOG_DEBUGMSG("%s Change thresholds not set!", lspace); + } } else { diff --git a/src/core/scaling/pgd_readIni.c b/src/core/scaling/pgd_readIni.c index a9185d3c..e459c78f 100644 --- a/src/core/scaling/pgd_readIni.c +++ b/src/core/scaling/pgd_readIni.c @@ -183,7 +183,6 @@ int core_scaling_pgd_readIni(const char *propfilename, // only send XML for SA magnitude above this threshold setVarName(group, "SA_mag_threshold\0", var); pgd_props->SA_mag_threshold = iniparser_getdouble(ini, var, -10.0); - // props->SA_mag_threshold = iniparser_getdouble(ini, "general:SA_mag_threshold\0", -10.0); setVarName(group, "minimum_pgd_cm\0", var); pgd_props->minimum_pgd_cm = iniparser_getdouble(ini, var, -1.0); @@ -203,6 +202,20 @@ int core_scaling_pgd_readIni(const char *propfilename, goto ERROR; } + // Change thresholds to prevent sending the same (or very similar) message + setVarName(group, "change_threshold_mag\0", var); + pgd_props->change_threshold_mag = iniparser_getdouble(ini, var, -1.0); + setVarName(group, "change_threshold_mag_uncer\0", var); + pgd_props->change_threshold_mag_uncer = iniparser_getdouble(ini, var, -1.0); + setVarName(group, "change_threshold_lat\0", var); + pgd_props->change_threshold_lat = iniparser_getdouble(ini, var, -1.0); + setVarName(group, "change_threshold_lon\0", var); + pgd_props->change_threshold_lon = iniparser_getdouble(ini, var, -1.0); + setVarName(group, "change_threshold_orig_time\0", var); + pgd_props->change_threshold_orig_time = iniparser_getdouble(ini, var, -1.0); + setVarName(group, "change_threshold_num_stations\0", var); + pgd_props->change_threshold_num_stations = iniparser_getint(ini, var, -1); + ERROR:; iniparser_freedict(ini); return ierr; diff --git a/src/core/waveformProcessor/peakDisplacementHelper.c b/src/core/waveformProcessor/peakDisplacementHelper.c index 0633c77a..6b675686 100644 --- a/src/core/waveformProcessor/peakDisplacementHelper.c +++ b/src/core/waveformProcessor/peakDisplacementHelper.c @@ -14,7 +14,7 @@ /*! * @brief Waveform processor to estimate the peak displacement observed * on a 3 channel GPS stream where the peak displacement at any - * sample is Euclidean norm of it's displacement. + * sample is Euclidean norm of its displacement. * * @param[in] npts number of points in time series * @param[in] dt sampling period (s) of GPS buffers @@ -23,21 +23,14 @@ * @param[in] ubuff vertical position [npts] * @param[in] nbuff north position [npts] * @param[in] ebuff east position [npts] - * @param[in] usigmabuff vertical position uncertainty [npts] - * @param[in] nsigmabuff north position uncertainty [npts] - * @param[in] esigmabuff east position uncertainty [npts] * @param[in] nMaxLeader latest time index to start measurement in * case of nan's * @param[in] tmin distance / svel_window (s) * @param[in] tmax distance / min_svel_window (s) * * @param[out] obsTime epochal time of peak displacment (s) - * @param[out] uMaxUncertainty peak vertical uncertainty at the reference - * or peak displacement times (m) - * @param[out] nMaxUncertainty peak north uncertainty at the reference - * or peak displacement times (m) - * @param[out] eMaxUncertainty peak east uncertainty at the reference - * or peak displacement times (m) + * @param[out] iRef index of reference value + * @param[out] iPeak index of peak value * * * @result the peak displacement observed on a trace. this has the same diff --git a/src/dmlib/dmlibWrapper.cpp b/src/dmlib/dmlibWrapper.cpp index 09c39bc7..c6911885 100644 --- a/src/dmlib/dmlibWrapper.cpp +++ b/src/dmlib/dmlibWrapper.cpp @@ -470,9 +470,8 @@ char *dmlibWrapper_createPGDXML(const double currentTime, // required to create FiniteFaultMessage enum FaultSegment::FaultSegmentShape shape = FaultSegment::UNKNOWN_SEGMENT; - // Get time stamp for when message is sent. Corresponds to currentTime from - // the outer driveGFAST loop to be consistent with the last time we have - // data for. + // Get time stamp for when the message is sent, based on the timestamp sent from the outer + // driveGFAST loop. Could be based on the actual current time, or the last time we have data for. int rc; char cnow[128]; rc = xml_epoch2string(currentTime, cnow); @@ -500,8 +499,6 @@ char *dmlibWrapper_createPGDXML(const double currentTime, LOG_DEBUGMSG("old origTime: %lf, origTimeChar: %s, origTimeStr: %s, new origTime: %lf", core->origTime, origTimeChar, origTimeStr.c_str(), algMessage.getOriginTime()); - // LOG_MSG("%s", "createEventXML - created algMessage"); - // Now add pgd observations to algMessage int i, j; int scnl_n = 8; @@ -544,7 +541,6 @@ char *dmlibWrapper_createPGDXML(const double currentTime, // skip site if it wasn't used if (!pgd->lsiteUsed[i]) { continue; } - // LOG_MSG("createEventXML - i = %d, setting chars", i); // see core/data/readMetaDataFile for similar SNCL parsing memset(obs_sta, 0, scnl_n*sizeof(char)); memset(obs_net, 0, scnl_n*sizeof(char)); @@ -554,7 +550,6 @@ char *dmlibWrapper_createPGDXML(const double currentTime, work = (char *)calloc(strlen(pgd_data->stnm[i])+1, sizeof(char)); strcpy(work, pgd_data->stnm[i]); - // LOG_MSG("%s", "createEventXML - starting NSCL tokenizing"); token = strtok(work, "."); int i_tok = 0; while (token) @@ -566,10 +561,8 @@ char *dmlibWrapper_createPGDXML(const double currentTime, i_tok++; token = strtok(NULL, "."); } - // LOG_MSG("%s", "createEventXML - done NSCL tokenizing, freeing work"); delete work; work = NULL; - // LOG_MSG("%s", "createEventXML - freed work, adding gmobs"); assoc_flag = (n_assoc >= max_assoc_stations) ? false : true; // Make sure longitude follows ShakeAlert convention @@ -594,9 +587,6 @@ char *dmlibWrapper_createPGDXML(const double currentTime, assoc_flag); n_assoc++; - - // LOG_DEBUGMSG("createEventXML - added obs=%f, sta=%s, i=%d, j=%d, dist=%f, assoc=%d, n_assoc=%d", - // pgd_data->pd[i] * 100., pgd_data->stnm[i], i, j, vals[j].dist, assoc_flag, n_assoc); } LOG_MSG("%s", "createEventXML - finished adding gmobs, encoding message"); diff --git a/src/eewUtils/Makefile b/src/eewUtils/Makefile index 908fc929..7dd84df8 100644 --- a/src/eewUtils/Makefile +++ b/src/eewUtils/Makefile @@ -9,8 +9,9 @@ include $(GFAST_DIR)/Make.include.gfast EW_INCL = -I$(EWDIR)/include -OBJS = driveCMT.o driveFF.o drivePGD.o makeXML.o\ -parseCoreXML.o setLogFileNames.o driveGFAST.o +OBJS = driveCMT.o driveFF.o drivePGD.o makeXML.o \ +parseCoreXML.o setLogFileNames.o driveGFAST.o fillCoreEventInfo.o \ +sendXMLFilter.o LIB = gfast_utils.a DEBUG = -g diff --git a/src/eewUtils/driveGFAST.c b/src/eewUtils/driveGFAST.c index ffcbf3a4..c1287d5d 100644 --- a/src/eewUtils/driveGFAST.c +++ b/src/eewUtils/driveGFAST.c @@ -24,7 +24,6 @@ * @param[in] interval_in_mins is interval in minutes? * @return status code. */ - int eewUtils_writeXML(const char *dirname, const char *eventid, const char *msg_type, const char *message, int interval, bool interval_in_mins); bool check_mins_against_intervals(struct GFAST_props_struct props, @@ -35,36 +34,6 @@ bool check_mins_against_intervals(struct GFAST_props_struct props, bool * interval_complete, double age); -/*! - * @brief Fills a given coreInfo_struct with the appropriate information - * @param[in] evid Event ID - * @param[in] version Event version number - * @param[in] SA_lat Event latitude - * @param[in] SA_lon Event longitude - * @param[in] SA_depth Event depth - * @param[in] SA_mag Event magnitude - * @param[in] SA_time Event origin time (UTC) - * @param[in] num_stations Number of stations contributing - * @param[out] core struct to fill with information - * @return status code. - */ -int fill_core_event_info(const char *evid, - const int version, - const double SA_lat, - const double SA_lon, - const double SA_depth, - const double SA_mag, - const double SA_time, - const int num_stations, - struct coreInfo_struct *core); - -bool send_xml_filter(const struct GFAST_props_struct *props, - const struct GFAST_shakeAlert_struct *SA, - const struct GFAST_pgdResults_struct *pgd, - const struct GFAST_peakDisplacementData_struct *pgd_data, - const struct coreInfo_struct *core, - const double age_of_event); - /*! * @brief Expert earthquake early warning GFAST driver. * @@ -158,13 +127,17 @@ int eewUtils_driveGFAST(const double currentTime, t_event = time_timeStamp(); // Get the streams for this event memcpy(&SA, &events->SA[iev], sizeof(struct GFAST_shakeAlert_struct)); + + // internal_version always decrements by 1 + xml_status->SA_status[iev].internal_version -= 1; + t1 = SA.time; // Origin time t2 = currentTime; age_of_event = (t2 - t1); - LOG_MSG("%s: Starting event, current time:%lf evid:%s [age_of_event=%f]", - fcnm, t2, SA.eventid, age_of_event); - LOG_MSG("%s: Event info OT:%lf lat:%lf lon:%lf mag:%lf", - fcnm, SA.time, SA.lat, SA.lon, SA.mag); + LOG_MSG("%s: Starting event, current time:%lf evid:%s internal version: %d [age_of_event=%lf]", + fcnm, t2, SA.eventid, xml_status->SA_status[iev].internal_version, age_of_event); + LOG_MSG("%s: SA event info OT:%lf lat:%lf lon:%lf mag:%lf SA version:%d", + fcnm, SA.time, SA.lat, SA.lon, SA.mag, SA.version); // Skip event if the times doen't make sense if (t1 > t2) { @@ -190,9 +163,8 @@ int eewUtils_driveGFAST(const double currentTime, continue; } - // Set the log file names. Comment out in advance of providing compile - // option to use these (for NOAA) or plog (for ShakeAlert) - CWU #ifndef ENABLE_PLOG + // Set the log file names. eewUtils_setLogFileNames(SA.eventid,props.SAoutputDir, errorLogFileName, infoLogFileName, debugLogFileName, warnLogFileName); @@ -398,24 +370,29 @@ int eewUtils_driveGFAST(const double currentTime, // Make xml messages /////////////////////////////////////////////////////////////////////////// t_time0 = time_timeStamp(); + LOG_MSG("driveGFAST: make XML msgs: lpgdSuccess=%d lcmtSuccess=%d lffSuccess=%d", lpgdSuccess, lcmtSuccess, lffSuccess); - xml_status->SA_status[iev].version += 1; - char *message_type = (xml_status->SA_status[iev].version==0)?"new\0":"update\0"; + char sversion[6]; - snprintf(sversion,6,"%d",xml_status->SA_status[iev].version); + char message_type[16]; + snprintf(sversion, 6, "%d", xml_status->SA_status[iev].internal_version); + sprintf(message_type, "%s", "update\0"); // Fill coreInfo_struct to pass to makeXML for pgd and ff struct coreInfo_struct core; memset(&core, 0, sizeof(struct coreInfo_struct)); - ierr = fill_core_event_info(SA.eventid, xml_status->SA_status[iev].version, SA.lat, - SA.lon, SA.dep, SA.mag, SA.time, 0, &core); + ierr = eewUtils_fillCoreEventInfo(SA.eventid, xml_status->SA_status[iev].internal_version, + SA.lat, SA.lon, SA.dep, SA.mag, SA.time, 0, &core); - // Make the PGD xml + // Handle the PGD xml if (props.pgd_props.do_pgd && lpgdSuccess) { if (props.verbose > 2) { LOG_DEBUGMSG("%s", "Generating pgd XML"); } + + bool send_pgd = false; + // Change depth, mag to match optimal pgd (by variance reduction) pgdOpt = array_argmax64f(pgd->ndeps, pgd->dep_vr_pgd, &ierr); core.depth = pgd->srcDepths[pgdOpt]; @@ -423,11 +400,42 @@ int eewUtils_driveGFAST(const double currentTime, core.magUncer = pgd->mpgd_sigma[pgdOpt]; core.numStations = nsites_pgd; +#ifdef GFAST_USE_AMQ + // Determine if message should be sent via ActiveMQ + if (!eewUtils_sendXMLFilter( + &props, + &SA, + pgd, + pgd_data, + &core, + &(xml_status->SA_status[iev].last_sent_core), + age_of_event)) + { + // Update version, message type if message should be sent + send_pgd = true; + xml_status->SA_status[iev].external_version += 1; + core.version = xml_status->SA_status[iev].external_version; + snprintf(sversion, 6, "%d", xml_status->SA_status[iev].external_version); + if (xml_status->SA_status[iev].external_version == 0) { + sprintf(message_type, "%s", "new\0"); + } + LOG_MSG("driveGFAST: PGD message will be sent! Internal version: %d, external version: %d", + xml_status->SA_status[iev].internal_version, + xml_status->SA_status[iev].external_version) + } +#endif /* GFAST_USE_AMQ */ + + // Make PGD xml #ifdef GFAST_USE_DMLIB - // Encode xml with dmlib + // Encode xml with dmlib LOG_MSG("%s", "driveGFAST: CWU_TEST dmlib encoding"); + // Use time closest to when xml is actually sent to be consistent with ShakeAlert + // algorithms. + // Alternative is to use the "currentTime" variable to correspond to the start of the + // processing loop in gfast_eew. + double timestamp = time_timeStamp(); pgdXML = dmlibWrapper_createPGDXML( - currentTime, + timestamp, props.opmode, GFAST_VERSION, program_instance, @@ -463,16 +471,19 @@ int eewUtils_driveGFAST(const double currentTime, SA.eventid, iev, xml_status->SA_status[iev].eventid); } -#if defined GFAST_USE_AMQ && defined GFAST_USE_DMLIB - // Send message via ActiveMQ if appropriate - if (!send_xml_filter(&props, &SA, pgd, pgd_data, &core, age_of_event)) { +#ifdef GFAST_USE_AMQ + if (send_pgd) { if (pgdXML != NULL) { sendEventXML(pgdXML); + memcpy( + &(xml_status->SA_status[iev].last_sent_core), + &core, + sizeof(core)); } - LOG_MSG("== Sending xml, [GFAST t0:%f] evid:%s pgdXML=[%s]\n", - currentTime, SA.eventid, pgdXML); + LOG_MSG("== Sending xml, [GFAST t0:%f] evid:%s version:%d pgdXML=[%s]\n", + currentTime, SA.eventid, core.version, pgdXML); } -#endif /* GFAST_USE_AMQ && GFAST_USE_DMLIB */ +#endif /* GFAST_USE_AMQ */ if (props.output_interval_mins[0] == 0) { // Output at every iteration int index = core.version; @@ -485,10 +496,15 @@ int eewUtils_driveGFAST(const double currentTime, check_mins_against_intervals(props, mins, SA.eventid, "pgd", pgdXML, xml_status->SA_status[iev].interval_complete[0], age_of_event); } + + // reset version, message type to reflect internal state for cmt, ff + core.version = xml_status->SA_status[iev].internal_version; + snprintf(sversion, 6, "%d", xml_status->SA_status[iev].internal_version); + sprintf(message_type, "%s", "update\0"); LOG_MSG("Leaving PGD writeXML ierr=%d", ierr); } //if props.pgd_props.do_pgd && lpgdSuccess - // Make the CMT quakeML + // Handle the CMT quakeML if (props.cmt_props.do_cmt && lcmtSuccess) { if (props.verbose > 2) { LOG_DEBUGMSG("%s", "Generating CMT QuakeML"); @@ -524,7 +540,7 @@ int eewUtils_driveGFAST(const double currentTime, xml_status->SA_status[iev].interval_complete[1], age_of_event); } } // if props.cmt_props.do_cmt && lcmtSuccess - // Make the finite fault XML + // Handle the finite fault XML if (props.ff_props.do_ff && lffSuccess) { if (props.verbose > 2) { LOG_DEBUGMSG("Generating FF XML; preferred plane=%d", @@ -763,160 +779,3 @@ bool check_mins_against_intervals(struct GFAST_props_struct props, return false; } - -int fill_core_event_info(const char *evid, - const int version, - const double SA_lat, - const double SA_lon, - const double SA_depth, - const double SA_mag, - const double SA_time, - const int num_stations, - struct coreInfo_struct *core) -{ - strcpy(core->id, evid); - core->version = version; - core->mag = SA_mag; - core->lhaveMag = true; - core->magUnits = MOMENT_MAGNITUDE; - core->lhaveMagUnits = true; - core->magUncer = 0.5; - core->lhaveMagUncer = true; - core->magUncerUnits = MOMENT_MAGNITUDE; - core->lhaveMagUncerUnits = true; - core->lat = SA_lat; - core->lhaveLat = true; - core->latUnits = DEGREES; - core->lhaveLatUnits = true; - core->latUncer = (double) NAN; - core->lhaveLatUncer = true; - core->latUncerUnits = DEGREES; - core->lhaveLatUncerUnits = true; - // GFAST would call lon -120 as 240 by default. Change this to be - // consistent with ShakeAlert seismic algorithms - core->lon = (SA_lon > 180) ? SA_lon - 360: SA_lon; - core->lhaveLon = true; - core->lonUnits = DEGREES; - core->lhaveLonUnits = true; - core->lonUncer = (double) NAN; - core->lhaveLonUncer = true; - core->lonUncerUnits = DEGREES; - core->lhaveLonUncerUnits = true; - core->depth = SA_depth; - core->lhaveDepth = true; - core->depthUnits = KILOMETERS; - core->lhaveDepthUnits = true; - core->depthUncer = (double) NAN; - core->lhaveDepthUncer = true; - core->depthUncerUnits = KILOMETERS; - core->lhaveDepthUncerUnits = true; - core->origTime = SA_time; - core->lhaveOrigTime = true; - core->origTimeUnits = UTC; - core->lhaveOrigTimeUnits = true; - core->origTimeUncer = (double) NAN; - core->lhaveOrigTimeUncer = true; - core->origTimeUncerUnits = SECONDS; - core->lhaveOrigTimeUncerUnits = true; - core->likelihood = 0.8; - core->lhaveLikelihood = true; - core->numStations = num_stations; - return 0; -} - -/* - * Return true if this message should not be sent (false if it should be sent) - */ -bool send_xml_filter(const struct GFAST_props_struct *props, - const struct GFAST_shakeAlert_struct *SA, - const struct GFAST_pgdResults_struct *pgd, - const struct GFAST_peakDisplacementData_struct *pgd_data, - const struct coreInfo_struct *core, - const double age_of_event) -{ - - // Conditions can be met or exceeded. - // Exceeded is used if a value being more than a threshold means no throttling - // Met is used if a value being less than a threshold means no throttling - bool pgd_exceeded = false; - bool mag_exceeded = false; - bool mag_sigma_met = false; - // Determine if pgd threshold is exceeded n times - int num_pgd_exceeded = 0, i, i_throttle; - - // Find the correct throttle criteria based on the time after origin - i_throttle = -1; - for (i = 0; i < props->pgd_props.n_throttle; i++) { - if (props->pgd_props.throttle_time_threshold[i] > age_of_event) break; - i_throttle++; - } - i_throttle = (i_throttle < 0) ? 0: i_throttle; - if (props->verbose > 2) { - LOG_DEBUGMSG("%s: For age_of_event %.2f, using i_throttle=%d, thresholds for time=%.1f, pgd=%.1f, nsta=%d", - __func__, - age_of_event, - i_throttle, - props->pgd_props.throttle_time_threshold[i_throttle], - props->pgd_props.throttle_pgd_threshold[i_throttle], - props->pgd_props.throttle_num_stations[i_throttle]) - } - - // Assumes pgd->nsites = pgd_data->nsites and indices correspond - if (pgd->nsites != pgd_data->nsites) { - LOG_ERRMSG("%s: nsites don't match for pgd, pgd_data! %d, %d\n", - __func__, pgd->nsites, pgd_data->nsites); - return false; - } - for (i = 0; i < pgd->nsites; i++) { - // skip site if it wasn't used - if (!pgd->lsiteUsed[i]) { continue; } - // pd is in meters, so convert to cm before comparing to threshold - if (pgd_data->pd[i] * 100. >= props->pgd_props.throttle_pgd_threshold[i_throttle]) { - num_pgd_exceeded++; - } - } - - if (props->verbose > 2) { - LOG_DEBUGMSG("%s: PGD threshold of %.1f cm exceeded at %d stations (threshold num: %d)", - __func__, props->pgd_props.throttle_pgd_threshold[i_throttle], num_pgd_exceeded, - props->pgd_props.throttle_num_stations[i_throttle]); - } - if (num_pgd_exceeded >= props->pgd_props.throttle_num_stations[i_throttle]) { - LOG_MSG("%s: PGD threshold of %.1f cm exceeded at %d stations (threshold num: %d)", - __func__, props->pgd_props.throttle_pgd_threshold[i_throttle], num_pgd_exceeded, - props->pgd_props.throttle_num_stations[i_throttle]); - pgd_exceeded = true; - } - - // Determine if SA mag threshold is exceeded - if (props->verbose > 2) { - LOG_DEBUGMSG("%s: SA mag: %f, threshold mag: %f", - __func__, SA->mag, props->pgd_props.SA_mag_threshold); - } - if (SA->mag >= props->pgd_props.SA_mag_threshold) { - mag_exceeded = true; - LOG_MSG("%s: SA magnitude exceeded! SA mag: %f, threshold mag: %f", - __func__, SA->mag, props->pgd_props.SA_mag_threshold); - } - - // Determine if pgd magnitude sigma threshold is met - if (props->verbose > 2) { - LOG_DEBUGMSG("%s: PGD mag sigma: %f, threshold mag sigma: %f, PGD mag: %f", - __func__, core->magUncer, props->pgd_props.pgd_sigma_throttle, core->mag); - } - if (core->magUncer <= props->pgd_props.pgd_sigma_throttle) { - mag_sigma_met = true; - LOG_MSG("%s: PGD mag sigma met! PGD mag sigma: %f, threshold mag sigma: %f, PGD mag: %f", - __func__, core->magUncer, props->pgd_props.pgd_sigma_throttle, core->mag); - } - - if (pgd_exceeded && mag_exceeded && mag_sigma_met) { - LOG_MSG("%s: Message not throttled (%s v%d)! pgd_exceeded: %d, mag_exceeded: %d, mag_sigma_met: %d", - __func__, core->id, core->version, pgd_exceeded, mag_exceeded, mag_sigma_met); - return false; - } - - LOG_MSG("%s: Message throttled (%s v%d)! pgd_exceeded: %d, mag_exceeded: %d, mag_sigma_met: %d", - __func__, core->id, core->version, pgd_exceeded, mag_exceeded, mag_sigma_met); - return true; -} diff --git a/src/eewUtils/fillCoreEventInfo.c b/src/eewUtils/fillCoreEventInfo.c new file mode 100644 index 00000000..a9918a4d --- /dev/null +++ b/src/eewUtils/fillCoreEventInfo.c @@ -0,0 +1,77 @@ +#include +#include +#include "gfast_struct.h" + +/*! + * @brief Fills a given coreInfo_struct with the appropriate information + * @param[in] evid Event ID + * @param[in] version Event version number + * @param[in] SA_lat Event latitude + * @param[in] SA_lon Event longitude + * @param[in] SA_depth Event depth + * @param[in] SA_mag Event magnitude + * @param[in] SA_time Event origin time (UTC) + * @param[in] num_stations Number of stations contributing + * @param[out] core struct to fill with information + * @return status code. + */ +int eewUtils_fillCoreEventInfo( + const char *evid, + const int version, + const double SA_lat, + const double SA_lon, + const double SA_depth, + const double SA_mag, + const double SA_time, + const int num_stations, + struct coreInfo_struct *core) +{ + strcpy(core->id, evid); + core->version = version; + core->mag = SA_mag; + core->lhaveMag = true; + core->magUnits = MOMENT_MAGNITUDE; + core->lhaveMagUnits = true; + core->magUncer = 0.5; + core->lhaveMagUncer = true; + core->magUncerUnits = MOMENT_MAGNITUDE; + core->lhaveMagUncerUnits = true; + core->lat = SA_lat; + core->lhaveLat = true; + core->latUnits = DEGREES; + core->lhaveLatUnits = true; + core->latUncer = (double) NAN; + core->lhaveLatUncer = true; + core->latUncerUnits = DEGREES; + core->lhaveLatUncerUnits = true; + // GFAST would call lon -120 as 240 by default. Change this to be + // consistent with ShakeAlert seismic algorithms + core->lon = (SA_lon > 180) ? SA_lon - 360: SA_lon; + core->lhaveLon = true; + core->lonUnits = DEGREES; + core->lhaveLonUnits = true; + core->lonUncer = (double) NAN; + core->lhaveLonUncer = true; + core->lonUncerUnits = DEGREES; + core->lhaveLonUncerUnits = true; + core->depth = SA_depth; + core->lhaveDepth = true; + core->depthUnits = KILOMETERS; + core->lhaveDepthUnits = true; + core->depthUncer = (double) NAN; + core->lhaveDepthUncer = true; + core->depthUncerUnits = KILOMETERS; + core->lhaveDepthUncerUnits = true; + core->origTime = SA_time; + core->lhaveOrigTime = true; + core->origTimeUnits = UTC; + core->lhaveOrigTimeUnits = true; + core->origTimeUncer = (double) NAN; + core->lhaveOrigTimeUncer = true; + core->origTimeUncerUnits = SECONDS; + core->lhaveOrigTimeUncerUnits = true; + core->likelihood = 0.8; + core->lhaveLikelihood = true; + core->numStations = num_stations; + return 0; +} \ No newline at end of file diff --git a/src/eewUtils/sendXMLFilter.c b/src/eewUtils/sendXMLFilter.c new file mode 100644 index 00000000..769cd9c1 --- /dev/null +++ b/src/eewUtils/sendXMLFilter.c @@ -0,0 +1,220 @@ +#include +#include +#include "gfast_struct.h" +#include "gfast_core.h" + + +/* + * Return true if the change thresholds are met or exceeded. + * For each change threshold, the threshold value must be >= 0 to be evaluated + * In other words, if the threshold is negative, it won't be used + * If any single threshold is met or exceeded, return true + */ +bool eewUtils_changeThresholdsExceeded( + const struct GFAST_props_struct *props, + const struct coreInfo_struct *core, + const struct coreInfo_struct *last_sent_core) +{ + // If all of the thresholds are unset, just ignore the whole check and return true. + if ((props->pgd_props.change_threshold_mag < 0) && + (props->pgd_props.change_threshold_mag_uncer < 0) && + (props->pgd_props.change_threshold_lat < 0) && + (props->pgd_props.change_threshold_lon < 0) && + (props->pgd_props.change_threshold_orig_time < 0) && + (props->pgd_props.change_threshold_num_stations < 0)) + { + LOG_DEBUGMSG("%s: All change thresholds unset, not checking!", __func__); + return true; + } + + // Check magnitude + if ((props->pgd_props.change_threshold_mag >= 0) && + (fabs(core->mag - last_sent_core->mag) >= props->pgd_props.change_threshold_mag)) + { + LOG_DEBUGMSG("%s: Returning true for mag: %f >= %f", + __func__, + fabs(core->mag - last_sent_core->mag), + props->pgd_props.change_threshold_mag); + return true; + } + // Check magnitude uncertainty + if ((props->pgd_props.change_threshold_mag_uncer >= 0) && + (fabs(core->magUncer - last_sent_core->magUncer) >= props->pgd_props.change_threshold_mag_uncer)) + { + LOG_DEBUGMSG("%s: Returning true for mag uncer: %f >= %f", + __func__, + fabs(core->magUncer - last_sent_core->magUncer), + props->pgd_props.change_threshold_mag_uncer); + return true; + } + // Check latitude + if ((props->pgd_props.change_threshold_lat >= 0) && + (fabs(core->lat - last_sent_core->lat) >= props->pgd_props.change_threshold_lat)) + { + LOG_DEBUGMSG("%s: Returning true for lat: %f >= %f", + __func__, + fabs(core->lat - last_sent_core->lat), + props->pgd_props.change_threshold_lat); + return true; + } + // Check longitude + if ((props->pgd_props.change_threshold_lon >= 0) && + (fabs(core->lon - last_sent_core->lon) >= props->pgd_props.change_threshold_lon)) + { + LOG_DEBUGMSG("%s: Returning true for lon: %f >= %f", + __func__, + fabs(core->lon - last_sent_core->lon), + props->pgd_props.change_threshold_lon); + return true; + } + // Check origin time + if ((props->pgd_props.change_threshold_orig_time >= 0) && + (fabs(core->origTime - last_sent_core->origTime) >= props->pgd_props.change_threshold_orig_time)) + { + LOG_DEBUGMSG("%s: Returning true for ot: %f >= %f", + __func__, + fabs(core->origTime - last_sent_core->origTime), + props->pgd_props.change_threshold_orig_time); + return true; + } + // Check number of stations + if ((props->pgd_props.change_threshold_num_stations >= 0) && + (abs(core->numStations - last_sent_core->numStations) >= props->pgd_props.change_threshold_num_stations)) + { + LOG_DEBUGMSG("%s: Returning true for num stations: %d >= %d", + __func__, + abs(core->numStations - last_sent_core->numStations), + props->pgd_props.change_threshold_num_stations); + return true; + } + + // If none of the thresholds are exceeded, return false + LOG_DEBUGMSG("%s: Returning false, no thresholds met", __func__); + return false; +} + +/* + * Return true if this message should not be sent (false if it should be sent) + */ +bool eewUtils_sendXMLFilter( + const struct GFAST_props_struct *props, + const struct GFAST_shakeAlert_struct *SA, + const struct GFAST_pgdResults_struct *pgd, + const struct GFAST_peakDisplacementData_struct *pgd_data, + const struct coreInfo_struct *core, + const struct coreInfo_struct *last_sent_core, + const double age_of_event) +{ + + // Conditions can be met or exceeded. + // Exceeded is used if a value being more than a threshold means no throttling + // Met is used if a value being less than a threshold means no throttling + bool pgd_exceeded = false; + bool mag_exceeded = false; + bool mag_sigma_met = false; + bool change_thresholds_exceeded = false; + + // Determine if pgd threshold is exceeded n times + int num_pgd_exceeded = 0, i, i_throttle; + + // Find the correct throttle criteria based on the time after origin + i_throttle = -1; + for (i = 0; i < props->pgd_props.n_throttle; i++) { + if (props->pgd_props.throttle_time_threshold[i] > age_of_event) break; + i_throttle++; + } + i_throttle = (i_throttle < 0) ? 0: i_throttle; + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: For age_of_event %.2f, using i_throttle=%d, thresholds for time=%.1f, pgd=%.1f, nsta=%d", + __func__, + age_of_event, + i_throttle, + props->pgd_props.throttle_time_threshold[i_throttle], + props->pgd_props.throttle_pgd_threshold[i_throttle], + props->pgd_props.throttle_num_stations[i_throttle]) + } + + // Assumes pgd->nsites = pgd_data->nsites and indices correspond + if (pgd->nsites != pgd_data->nsites) { + LOG_ERRMSG("%s: nsites don't match for pgd, pgd_data! %d, %d\n", + __func__, pgd->nsites, pgd_data->nsites); + return false; + } + for (i = 0; i < pgd->nsites; i++) { + // skip site if it wasn't used + if (!pgd->lsiteUsed[i]) { continue; } + // pd is in meters, so convert to cm before comparing to threshold + if (pgd_data->pd[i] * 100. >= props->pgd_props.throttle_pgd_threshold[i_throttle]) { + num_pgd_exceeded++; + } + } + + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: PGD threshold of %.1f cm exceeded at %d stations (threshold num: %d)", + __func__, props->pgd_props.throttle_pgd_threshold[i_throttle], num_pgd_exceeded, + props->pgd_props.throttle_num_stations[i_throttle]); + } + if (num_pgd_exceeded >= props->pgd_props.throttle_num_stations[i_throttle]) { + LOG_MSG("%s: PGD threshold of %.1f cm exceeded at %d stations (threshold num: %d)", + __func__, props->pgd_props.throttle_pgd_threshold[i_throttle], num_pgd_exceeded, + props->pgd_props.throttle_num_stations[i_throttle]); + pgd_exceeded = true; + } + + // Determine if SA mag threshold is exceeded + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: SA mag: %f, threshold mag: %f", + __func__, SA->mag, props->pgd_props.SA_mag_threshold); + } + if (SA->mag >= props->pgd_props.SA_mag_threshold) { + mag_exceeded = true; + LOG_MSG("%s: SA magnitude exceeded! SA mag: %f, threshold mag: %f", + __func__, SA->mag, props->pgd_props.SA_mag_threshold); + } + + // Determine if pgd magnitude sigma threshold is met + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: PGD mag sigma: %f, threshold mag sigma: %f, PGD mag: %f", + __func__, core->magUncer, props->pgd_props.pgd_sigma_throttle, core->mag); + } + if (core->magUncer <= props->pgd_props.pgd_sigma_throttle) { + mag_sigma_met = true; + LOG_MSG("%s: PGD mag sigma met! PGD mag sigma: %f, threshold mag sigma: %f, PGD mag: %f", + __func__, core->magUncer, props->pgd_props.pgd_sigma_throttle, core->mag); + } + + // Check change thresholds exceeded from the last sent message (first one automatically counts) + if (props->verbose > 2) { + LOG_DEBUGMSG("%s: PGD change thresholds -> dmag:%f, dmagU:%f, dlat:%f, dlon:%f, dot:%f, dnsta:%d", + __func__, + core->mag - last_sent_core->mag, + core->magUncer - last_sent_core->magUncer, + core->lat - last_sent_core->lat, + core->lon - last_sent_core->lon, + core->origTime - last_sent_core->origTime, + core->numStations - last_sent_core->numStations + ); + } + if (eewUtils_changeThresholdsExceeded(props, core, last_sent_core)) { + change_thresholds_exceeded = true; + LOG_MSG("%s: PGD change thresholds exceeded! dmag:%f, dmagU:%f, dlat:%f, dlon:%f, dot:%f, dnsta:%d", + __func__, + core->mag - last_sent_core->mag, + core->magUncer - last_sent_core->magUncer, + core->lat - last_sent_core->lat, + core->lon - last_sent_core->lon, + core->origTime - last_sent_core->origTime, + core->numStations - last_sent_core->numStations + ); + } + + if (pgd_exceeded && mag_exceeded && mag_sigma_met && change_thresholds_exceeded) { + LOG_MSG("%s: Message not throttled (%s v%d)! pgd_exceeded: %d, mag_exceeded: %d, mag_sigma_met: %d, change_thresholds_exceeded: %d", + __func__, core->id, core->version, pgd_exceeded, mag_exceeded, mag_sigma_met, change_thresholds_exceeded); + return false; + } + + LOG_MSG("%s: Message throttled (%s v%d)! pgd_exceeded: %d, mag_exceeded: %d, mag_sigma_met: %d, change_thresholds_exceeded: %d", + __func__, core->id, core->version, pgd_exceeded, mag_exceeded, mag_sigma_met, change_thresholds_exceeded); + return true; +} \ No newline at end of file diff --git a/src/tests/CoreDataUT.cc b/src/tests/CoreDataUT.cc index 55e0d8d0..d5cc3673 100644 --- a/src/tests/CoreDataUT.cc +++ b/src/tests/CoreDataUT.cc @@ -76,6 +76,43 @@ TEST(CoreData, testReadMetaDataFileWithMetaDataNetworks) { free(metaDataNetworks); } +TEST(CoreData, testReadSiteMaskFile) { + const char *metaDataFile; + const char *siteMaskFile; + char **metaDataNetworks; + int ierr; + struct GFAST_data_struct gps_data; + + // initialize + metaDataFile = "data/merged_chanfile_coord.dat\0"; + siteMaskFile = "data/site_mask_file.dat\0"; + memset(&gps_data, 0, sizeof(struct GFAST_data_struct)); + metaDataNetworks = NULL; + + ierr = core_data_readMetaDataFile(metaDataFile, + metaDataNetworks, + 0, + &gps_data); + EXPECT_EQ(0, ierr) << "Error reading sites file"; + EXPECT_EQ(492, gps_data.stream_length); + + ierr = core_data_readSiteMaskFile(siteMaskFile, 1, &gps_data); + + // Verify the masks are correct + int npgd = 0, ncmt = 0, nff = 0; + for (int i = 0; i < gps_data.stream_length; i++) { + npgd += !gps_data.data[i].lskip_pgd; + ncmt += !gps_data.data[i].lskip_cmt; + nff += !gps_data.data[i].lskip_ff; + } + EXPECT_EQ(489, npgd); + EXPECT_EQ(490, ncmt); + EXPECT_EQ(491, nff); + + // finalize + GFAST_core_data_finalize(&gps_data); +} + TEST(CoreData, testInitialize) { char propfilename[1024]; int ierr, i; diff --git a/src/tests/CoreEventsUT.cc b/src/tests/CoreEventsUT.cc index 3b7a5ed4..e7c4427b 100644 --- a/src/tests/CoreEventsUT.cc +++ b/src/tests/CoreEventsUT.cc @@ -10,8 +10,8 @@ #include "gfast.h" -// test freeEvents, getMinOriginTime, newEvent, printEvent, removeCancelledEvent, -// removeExpiredEvent, removeExpiredEvents, syncXMLStatusWithEvents, updateEvent +// test freeEvents, newEvent, printEvent, +// removeExpiredEvent, removeExpiredEvents, syncXMLStatusWithEvents void get_SA(GFAST_shakeAlert_struct *SA) { // Initialize new event strcpy(SA->eventid, "12345\0"); @@ -149,3 +149,95 @@ TEST_F(CoreEventsFixture, testNewEventUpdatePreviousEvents) { EXPECT_STREQ(SA2.eventid, xml_status.SA_status[0].eventid); } + +TEST_F(CoreEventsFixture, testPrintEvent) { + EXPECT_NO_THROW(GFAST_core_events_printEvents(SA);); +} + +TEST_F(CoreEventsFixture, testRemoveExpiredEventsNone) { + int ret; + ret = core_events_removeExpiredEvents(100, SA.time, 1, &events); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, events.nev); + EXPECT_EQ(0, xml_status.nev); +} + +TEST_F(CoreEventsFixture, testRemoveExpiredEventsOneSync) { + lnewEvent = GFAST_core_events_newEvent(SA, &events, &xml_status); + EXPECT_EQ(1, events.nev); + EXPECT_EQ(1, xml_status.nev); + int ret; + ret = core_events_removeExpiredEvents(100, SA.time + 200, 1, &events); + EXPECT_EQ(1, ret); + EXPECT_EQ(0, events.nev); + EXPECT_EQ(1, xml_status.nev); + + ret = core_events_syncXMLStatusWithEvents(&events, &xml_status); + EXPECT_EQ(0, xml_status.nev); +} + +TEST_F(CoreEventsFixture, testRemoveExpiredEventsMultipleSync) { + // Make the second event + struct GFAST_shakeAlert_struct SA2; + memset(&SA2, 0, sizeof(struct GFAST_shakeAlert_struct)); + get_SA(&SA2); + strcpy(SA2.eventid, "9876\0"); + SA2.version = 0; + SA2.mag = 3.9; + SA2.time += 300; + + // Add both events, verify + lnewEvent = GFAST_core_events_newEvent(SA, &events, &xml_status); + EXPECT_TRUE(lnewEvent); + + lnewEvent = GFAST_core_events_newEvent(SA2, &events, &xml_status); + EXPECT_TRUE(lnewEvent); + + EXPECT_EQ(2, events.nev); + EXPECT_EQ(2, xml_status.nev); + + // Now remove one + int ret; + ret = core_events_removeExpiredEvents(100, SA.time + 200, 1, &events); + EXPECT_EQ(1, ret); + EXPECT_EQ(1, events.nev); + EXPECT_EQ(2, xml_status.nev); + + ret = core_events_syncXMLStatusWithEvents(&events, &xml_status); + EXPECT_EQ(1, xml_status.nev); +} + +TEST_F(CoreEventsFixture, testRemoveExpiredEventExists) { + lnewEvent = GFAST_core_events_newEvent(SA, &events, &xml_status); + EXPECT_EQ(1, events.nev); + EXPECT_EQ(1, xml_status.nev); + + struct GFAST_shakeAlert_struct SArem; + memset(&SArem, 0, sizeof(struct GFAST_shakeAlert_struct)); + memcpy(&SArem, &SA, sizeof(struct GFAST_shakeAlert_struct)); + + int ret; + ret = core_events_removeExpiredEvent(100, SA.time + 200, 1, SArem, &events); + EXPECT_EQ(1, ret); + EXPECT_EQ(0, events.nev); + EXPECT_EQ(1, xml_status.nev); +} + +TEST_F(CoreEventsFixture, testRemoveExpiredEventNoExists) { + lnewEvent = GFAST_core_events_newEvent(SA, &events, &xml_status); + EXPECT_EQ(1, events.nev); + EXPECT_EQ(1, xml_status.nev); + + struct GFAST_shakeAlert_struct SA2; + memset(&SA2, 0, sizeof(struct GFAST_shakeAlert_struct)); + get_SA(&SA2); + strcpy(SA2.eventid, "9876\0"); + SA2.version = 0; + SA2.mag = 3.9; + + int ret; + ret = core_events_removeExpiredEvent(100, SA.time + 200, 1, SA2, &events); + EXPECT_EQ(0, ret); + EXPECT_EQ(1, events.nev); + EXPECT_EQ(1, xml_status.nev); +} diff --git a/src/tests/CoreWaveformProcessorUT.cc b/src/tests/CoreWaveformProcessorUT.cc index 9a15070b..40a71d04 100644 --- a/src/tests/CoreWaveformProcessorUT.cc +++ b/src/tests/CoreWaveformProcessorUT.cc @@ -119,6 +119,19 @@ TEST(CoreWaveformProcessor, testPeakDisplacementHelperEarlyNansMiddlePeak) { expPeakDisp, 1, 2); } +TEST(CoreWaveformProcessor, testPeakDisplacementHelperMiddleNans) { + const int NPTS = 4; + double ubuff[NPTS] = {1, 2, NAN, 4}; + double nbuff[NPTS] = {1, 2, NAN, 4}; + double ebuff[NPTS] = {1, 2, NAN, 4}; + int npts = NPTS; + + double expPeakDisp = pow(pow(4 - 1, 2) + pow(4 - 1, 2) + pow(4 - 1, 2), 0.5); + + testPDHelper_helper(npts, ubuff, nbuff, ebuff, + expPeakDisp, 0, 3); +} + TEST(CoreWaveformProcessor, testParseQChannel) { double value; @@ -155,58 +168,6 @@ TEST(CoreWaveformProcessor, testParseQChannel) { EXPECT_EQ(1, core_waveformProcessor_parseQChannelGoodness(value)); } -void fill_gps_data(struct GFAST_data_struct *gps_data, - const int k, - const char *netw, - const char *stat, - const char *chan, - const char *loc, - const double lat, - const double lon, - const double elev, - const double dt, - const double gain, - const int mpts) { - strcpy(gps_data->data[k].netw, netw); - strcpy(gps_data->data[k].stnm, stat); - strncpy(gps_data->data[k].chan[0], chan, 2); - strcat( gps_data->data[k].chan[0], "Z\0"); - strncpy(gps_data->data[k].chan[1], chan, 2); - strcat( gps_data->data[k].chan[1], "N\0"); - strncpy(gps_data->data[k].chan[2], chan, 2); - strcat( gps_data->data[k].chan[2], "E\0"); - strncpy(gps_data->data[k].chan[3], chan, 2); - strcat( gps_data->data[k].chan[3], "3\0"); - strncpy(gps_data->data[k].chan[4], chan, 2); - strcat( gps_data->data[k].chan[4], "2\0"); - strncpy(gps_data->data[k].chan[5], chan, 2); - strcat( gps_data->data[k].chan[5], "1\0"); - strncpy(gps_data->data[k].chan[6], chan, 2); - strcat( gps_data->data[k].chan[6], "Q\0"); - strcpy(gps_data->data[k].loc, loc); - gps_data->data[k].sta_lat = lat; - gps_data->data[k].sta_lon = lon; - gps_data->data[k].sta_alt = elev; - gps_data->data[k].dt = dt; - gps_data->data[k].gain[0] = gain; - gps_data->data[k].gain[1] = gain; - gps_data->data[k].gain[2] = gain; - gps_data->data[k].gain[3] = gain; - gps_data->data[k].gain[4] = gain; - gps_data->data[k].gain[5] = gain; - gps_data->data[k].gain[6] = 1; // Quality channel has no gain - - gps_data->data[k].maxpts = mpts; - gps_data->data[k].ubuff = memory_calloc64f(mpts); - gps_data->data[k].nbuff = memory_calloc64f(mpts); - gps_data->data[k].ebuff = memory_calloc64f(mpts); - gps_data->data[k].usigmabuff = memory_calloc64f(mpts); - gps_data->data[k].nsigmabuff = memory_calloc64f(mpts); - gps_data->data[k].esigmabuff = memory_calloc64f(mpts); - gps_data->data[k].qbuff = memory_calloc64f(mpts); - gps_data->data[k].tbuff = memory_calloc64f(mpts); -} - /* * Fixture for testing peakDisplacement() function * Has two "normal" stations that can be put out of spec in various ways @@ -218,6 +179,7 @@ class CoreWaveformProcessorFixture : public::testing::Test { struct GFAST_data_struct gps_data; struct GFAST_peakDisplacementData_struct pgd_data; struct GFAST_pgdResults_struct pgd; + struct GFAST_offsetData_struct offset_data; double lat, lon, dep, time; int ierr, nsites_pgd, k, j; @@ -263,6 +225,10 @@ class CoreWaveformProcessorFixture : public::testing::Test { ierr = core_scaling_pgd_initialize(pgd_props, gps_data, &pgd, &pgd_data); + // Also initialize offset data (for cmt, ff) + memset(&offset_data, 0, sizeof(struct GFAST_offsetData_struct)); + initialize_offset_data(&gps_data, &offset_data); + // Now actually put some data in gps_data double tdata[NPTS] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; double udata[NPTS] = {0, 3, 5, 6, 4, 3, -1, 0, 3, 4}; @@ -289,6 +255,44 @@ class CoreWaveformProcessorFixture : public::testing::Test { } void TearDown() {} + + void initialize_offset_data(struct GFAST_data_struct *gps_data, + struct GFAST_offsetData_struct *offset_data) + { + offset_data->stnm = (char **)calloc((size_t) gps_data->stream_length, + sizeof(char *)); + offset_data->ubuff = memory_calloc64f(gps_data->stream_length); + offset_data->nbuff = memory_calloc64f(gps_data->stream_length); + offset_data->ebuff = memory_calloc64f(gps_data->stream_length); + offset_data->wtu = memory_calloc64f(gps_data->stream_length); + offset_data->wtn = memory_calloc64f(gps_data->stream_length); + offset_data->wte = memory_calloc64f(gps_data->stream_length); + offset_data->sta_lat = memory_calloc64f(gps_data->stream_length); + offset_data->sta_lon = memory_calloc64f(gps_data->stream_length); + offset_data->sta_alt = memory_calloc64f(gps_data->stream_length); + offset_data->lmask = memory_calloc8l(gps_data->stream_length); + offset_data->lactive = memory_calloc8l(gps_data->stream_length); + offset_data->nsites = gps_data->stream_length; + + for (int i=0; insites; i++) + { + offset_data->sta_lat[i] = gps_data->data[i].sta_lat; + offset_data->sta_lon[i] = gps_data->data[i].sta_lon; + offset_data->sta_alt[i] = gps_data->data[i].sta_alt; + offset_data->stnm[i] = (char *)calloc(64, sizeof(char)); + strcpy(offset_data->stnm[i], gps_data->data[i].netw); + strcat(offset_data->stnm[i], ".\0"); + strcat(offset_data->stnm[i], gps_data->data[i].stnm); + strcat(offset_data->stnm[i], ".\0"); + strncpy(offset_data->stnm[i], gps_data->data[i].chan[0], 2); + strcat(offset_data->stnm[i], "?.\0"); + if (strlen(gps_data->data[i].loc) > 0) + { + strcat(offset_data->stnm[i], gps_data->data[i].loc); + } + offset_data->lmask[i] = false; + } + } }; TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementNormal) { @@ -420,3 +424,31 @@ TEST_F(CoreWaveformProcessorFixture, testPeakDisplacementQThreshold) { EXPECT_EQ(1, pgd_data.lactive[0]); EXPECT_EQ(0, pgd_data.lactive[1]); } + +TEST_F(CoreWaveformProcessorFixture, testOffset) { + int nsites, ierr; + // An svel_window of 3.5 will put the swave_times at 2.41 and 2.56 + double svel_window = 3.5; + + nsites = core_waveformProcessor_offset( + -12345, + svel_window, + lat, + lon, + dep, + time, + gps_data, + &offset_data, + &ierr); + + EXPECT_EQ(0, ierr); + EXPECT_EQ(2, nsites); + + double toler = 1e-5; + EXPECT_NEAR(3, offset_data.ubuff[0], toler); + EXPECT_NEAR(1.5, offset_data.nbuff[0], toler); + EXPECT_NEAR(-1.5, offset_data.ebuff[0], toler); + EXPECT_NEAR(2.71429, offset_data.ubuff[1], toler); + EXPECT_NEAR(1.28571, offset_data.nbuff[1], toler); + EXPECT_NEAR(-1, offset_data.ebuff[1], toler); +} \ No newline at end of file diff --git a/src/tests/DmLibWrapperUT.cc b/src/tests/DmLibWrapperUT.cc new file mode 100644 index 00000000..e045fe1d --- /dev/null +++ b/src/tests/DmLibWrapperUT.cc @@ -0,0 +1,112 @@ +/** + * @file DmLibWrapperUT.cc + * @author Carl Ulberg, University of Washington (ulbergc@uw.edu) + * @brief This tests files in the dmlib/ directory. + */ + +#include "gtest/gtest.h" +#include "ut_log_init.h" +#include "ut_main.h" +#include "ut_xml_utils.h" + +#include "gfast.h" +#include "gfast_eewUtils.h" +#include "dmlibWrapper.h" + +#include "gfast_ut_utils.h" + +#include "iscl/memory/memory.h" +#include "iscl/array/array.h" +#include "iscl/iscl/iscl_enum.h" + + +TEST(DmLibWrapper, testCreatePGDXml) { + char *pgdXML; + const char *filenm = "data/final_pgd.maule.txt\0"; + const char *program_instance = "gfast@eew-uw-dev1\0"; + const char *message_type = "update\0"; + struct GFAST_pgd_props_struct pgd_props; + struct GFAST_peakDisplacementData_struct pgd_data; + struct GFAST_pgdResults_struct pgd_ref, pgd; + double SA_lat, SA_lon, SA_dep, age_of_event; + int i, ierr, max_assoc_stations, pgdOpt; + double currentTime = 0; + enum isclError_enum ierr_iscl; + + pgdXML = NULL; + memset(&pgd_props, 0, sizeof(pgd_props)); + memset(&pgd_data, 0, sizeof(pgd_data)); + memset(&pgd_ref, 0, sizeof(pgd_ref)); + memset(&pgd, 0, sizeof(pgd)); + age_of_event = 0; + max_assoc_stations = 1; + ierr = read_pgd_results(filenm, + &pgd_props, + &pgd_data, + &pgd_ref, + &SA_lat, &SA_lon, &SA_dep); + + EXPECT_EQ(0, ierr) << "Error reading input file"; + + // Set space + pgd.nsites = pgd_ref.nsites; + pgd.ndeps = pgd_ref.ndeps; + pgd.nlats = 1; + pgd.nlons = 1; + pgd.mpgd = ISCL_memory_calloc__double(pgd.ndeps); + pgd.mpgd_sigma = ISCL_memory_calloc__double(pgd.ndeps); + pgd.mpgd_vr = ISCL_memory_calloc__double(pgd.ndeps); + pgd.dep_vr_pgd = ISCL_memory_calloc__double(pgd.ndeps); + pgd.iqr = ISCL_memory_calloc__double(pgd.ndeps); + pgd.UP = ISCL_memory_calloc__double(pgd.ndeps*pgd.nsites); + pgd.UPinp = ISCL_memory_calloc__double(pgd.nsites); + pgd.srcDepths = ISCL_memory_calloc__double(pgd.ndeps); + pgd.srdist = ISCL_memory_calloc__double(pgd.ndeps*pgd.nsites); + pgd.lsiteUsed = ISCL_memory_calloc__bool(pgd.nsites); + for (i=0; i + + +class Hdf5Fixture : public::testing::Test { + protected: + + const char *dir_tmp = "data/tmp\0"; + const char *evid = "1234\0"; + // Careful with expected_path!! It will be deleted on TearDown + const char *expected_path = "data/tmp/1234_archive.h5\0"; + const char *propfilename = "data/gfast.props\0"; + int ierr; + hid_t file; + + void SetUp() { + ierr = hdf5_initialize(dir_tmp, evid, propfilename); + + EXPECT_EQ(0, ierr); + htri_t is_file; + is_file = H5Fis_hdf5(expected_path); + EXPECT_EQ(1, is_file); + } + + void TearDown() { + if (H5Fis_hdf5(expected_path)) { + file = H5Fopen(expected_path, H5F_ACC_RDWR, H5P_DEFAULT); + H5Fflush(file, H5F_SCOPE_GLOBAL); + H5Fclose(file); + remove(expected_path); + } + } + +}; + +TEST_F(Hdf5Fixture, testSetFileName) { + char fname[PATH_MAX]; + + ierr = hdf5_setFileName(dir_tmp, evid, fname); + + EXPECT_EQ(0, ierr); + EXPECT_STREQ(expected_path, fname); +} + +TEST_F(Hdf5Fixture, testSetFileNameNullEvid) { + char fname[PATH_MAX]; + evid = NULL; + + ierr = hdf5_setFileName(dir_tmp, evid, fname); + + EXPECT_EQ(-1, ierr); +} + +TEST_F(Hdf5Fixture, testSetFileNameEmptyEvid) { + char fname[PATH_MAX]; + evid = ""; + + ierr = hdf5_setFileName(dir_tmp, evid, fname); + + EXPECT_EQ(-1, ierr); +} + +TEST_F(Hdf5Fixture, testSetFileNameNullAdir) { + char fname[PATH_MAX]; + dir_tmp = NULL; + + ierr = hdf5_setFileName(dir_tmp, evid, fname); + + EXPECT_EQ(0, ierr); + EXPECT_STREQ("./1234_archive.h5", fname); +} + +TEST_F(Hdf5Fixture, testSetFileNameEmptyAdir) { + char fname[PATH_MAX]; + dir_tmp = ""; + + ierr = hdf5_setFileName(dir_tmp, evid, fname); + + EXPECT_EQ(0, ierr); + EXPECT_STREQ("./1234_archive.h5", fname); +} + +TEST_F(Hdf5Fixture, testCinterItemExists) { + file = H5Fopen(expected_path, H5F_ACC_RDONLY, H5P_DEFAULT); + ASSERT_EQ(1, h5_item_exists(file, "/DataStructures")); + EXPECT_EQ(1, h5_item_exists(file, "/DataStructures/peakDisplacementDataStructure")); + ASSERT_EQ(1, h5_item_exists(file, "/InitializationFile")); + EXPECT_EQ(1, h5_item_exists(file, "/InitializationFile/IniFile")); + EXPECT_EQ(1, h5_item_exists(file, "/GFAST_History")); + EXPECT_EQ(1, h5_item_exists(file, "/Summary")); + EXPECT_EQ(0, h5_item_exists(file, "/Fake")); + H5Fclose(file); +} diff --git a/src/tests/Makefile b/src/tests/Makefile index 3ee219e9..98bf1ca7 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -12,20 +12,23 @@ EWLIB = $(EWDIR)/lib DM_DIR = $(EEWDIR)/libs/dmlib DM_LIB = $(DM_DIR)/libdm.a -OBJS = ../activeMQ/gfast_amq.a ../eewUtils/gfast_utils.a ../xml/gfast_xml.a ../core/gfast_core.a \ - ../traceBuffer/traceBuffer.a ../hdf5/hdf5.a ../activeMQ/gfast_amq.a +OBJS = ../dmlib/dmlibWrapper.cpp.o ../activeMQ/gfast_amq.a ../eewUtils/gfast_utils.a \ + ../xml/gfast_xml.a ../core/gfast_core.a ../traceBuffer/traceBuffer.a ../hdf5/hdf5.a \ + ../activeMQ/gfast_amq.a DATA = UNITTESTS = \ - CoreWaveformProcessorUT \ - CoreActiveMqUT \ - EewUtilsUT \ - CoreScalingUT \ - CoreCoordtoolsUT \ - CoreDataUT \ - CoreEventsUT \ - TraceBufferEwrrUT + CoreActiveMqUT \ + CoreCoordtoolsUT \ + CoreDataUT \ + CoreEventsUT \ + CoreScalingUT \ + CoreWaveformProcessorUT \ + DmLibWrapperUT \ + EewUtilsUT \ + Hdf5UT \ + TraceBufferEwrrUT INCL = -I$(THIRD_PARTY) \ $(AQMS_INCL) $(OTL_INCL) $(APR_INCL) $(ACTIVEMQ_INCL) $(QLIB2_INCL) \ @@ -38,13 +41,11 @@ INCL = -I$(THIRD_PARTY) \ -I$(EEWDIR)/libs/datapkt \ -I$(EEWDIR)/gfast/include -LIBS += $(AQMS_LIB) $(DM_LIB) $(ACTIVEMQ_LIB) \ - $(QLIB2_LIB) $(XERCES_LIB) $(GTEST_LIB) $(GMOCK_LIB) \ - $(EW_LIB) $(ISCL_LIB) $(INIPARSER_LIB) $(XML2_LIB) $(HDF5_LIB) $(COMPEARTH_LIB) \ - $(APR_LIB) $(LAPACKE_LIB) $(CBLAS_LIB) $(FFTW_LIB) $(SSL_LIB) \ - $(CRYPTO_LIB) $(EWLIB)/libew_mt.a \ - -L$(THIRD_PARTY)/libtntime -ltntime \ - -L$(THIRD_PARTY)/libtnstd -ltnstd +LIBS = $(EW_LIB) $(ISCL_LIB) $(INIPARSER_LIB) $(XML2_LIB) $(HDF5_LIB) $(COMPEARTH_LIB) \ + $(ACTIVEMQ_LIB) $(DM_LIB) $(APR_LIB) $(LAPACKE_LIB) $(CBLAS_LIB) $(FFTW_LIB) $(SSL_LIB) \ + $(XERCES_LIB) $(QLIB2_LIB) $(CRYPTO_LIB) $(EWLIB)/libew_mt.a $(GTEST_LIB) $(GMOCK_LIB) + +SYSLIBS = -ldl -lm -lrt -pthread -lz -lsz -lstdc++ # comment this next line out to TURN OFF debugging print statments DEBUG =-g @@ -76,7 +77,7 @@ test: $(UNITTESTS) -$(foreach test, $^, echo -e "\n**** $(test) ****\n"; ./$(test);) %UT: %UT.o - $(CC) $< $(OBJS) $(LIBS) -o $@ + $(CC) $< $(UFLAGS) $(CCFLAGS) $(OBJS) $(LIBS) $(SYSLIBS) -o $@ # test report cleantestreport: diff --git a/src/tests/data/eewUtils_quakeML_example.cmt b/src/tests/data/eewUtils_quakeML_example.cmt new file mode 100644 index 00000000..16dad56e --- /dev/null +++ b/src/tests/data/eewUtils_quakeML_example.cmt @@ -0,0 +1,119 @@ + + + + + + + + 9.922327e+00 + + + + 3.000000e+00 + + + 1.000000e+00 + + + 2.000000e+00 + + + 5.000000e+00 + + + -6.000000e+00 + + + -4.000000e+00 + + + + 0.091126 + + + 0.707308 + + + + + + 90.000000 + + + 7.460045 + + + -144.735610 + + + + + 324.964874 + + + 85.701068 + + + -83.897425 + + + + + + + 49.299988 + + + 40.399763 + + + 1.017597e+01 + + + + + 241.537565 + + + 48.949095 + + + -5.668683e+00 + + + + + 144.505696 + + + 6.085340 + + + -4.507288e+00 + + + + + + + -5.425927e+00 + + Mw_gps + + + + + 46.000000 + + + -122.000000 + + + 8.000000 + + + + + diff --git a/src/tests/data/eewUtils_xml_example.ff b/src/tests/data/eewUtils_xml_example.ff new file mode 100644 index 00000000..80de6402 --- /dev/null +++ b/src/tests/data/eewUtils_xml_example.ff @@ -0,0 +1,2 @@ + +8.7531610.500000-35.909000nan-72.733000nan35.000000nan1970-01-01T00:00:00.000Znan0.800000501-38.091856285.13434519.488937-37.598740285.35754119.488937-37.719242285.78487725.693362-38.213361285.56399425.693362-0.0004700.8084060.0003250.80840616.2063408.794004-37.598740285.35754119.488937-37.104947285.57742919.488937-37.224473286.00249125.693362-37.719242285.78487725.693362-1.49836323.2643161.69135123.89850116.2063408.794004-37.104947285.57742919.488937-36.610500285.79411319.488937-36.729075286.21694125.693362-37.224473286.00249125.693362-2.79490823.8625793.88004722.66786416.2063408.794004-36.610500285.79411319.488937-36.115419286.00769519.488937-36.233069286.42832725.693362-36.729075286.21694125.693362-3.49189324.1993635.30090120.60648316.2063408.794004-36.115419286.00769519.488937-35.619727286.21827319.488937-35.736475286.63674825.693362-36.233069286.42832725.693362-3.39320624.3572196.44557223.50557116.2063408.794004-35.619727286.21827319.488937-35.123443286.42594219.488937-35.239314286.84229825.693362-35.736475286.63674825.693362-2.96157623.6246318.84914921.78123016.2063408.794004-35.123443286.42594219.488937-34.626587286.63079419.488937-34.741605287.04506925.693362-35.239314286.84229825.693362-2.30902823.8226919.91075319.09695716.2063408.794004-34.626587286.63079419.488937-34.129178286.83291819.488937-34.243367287.24515125.693362-34.741605287.04506925.693362-1.30373323.0551287.13783523.06638716.2063408.794004-34.129178286.83291819.488937-33.631236287.03240319.488937-33.744618287.44263025.693362-34.243367287.24515125.693362-0.49071120.8933383.84405720.97300716.2063408.794004-33.631236287.03240319.488937-33.132778287.22933319.488937-33.245377287.63759125.693362-33.744618287.44263025.6933620.0002720.8083630.0020460.80822616.2063408.794004-38.213361285.56399425.693362-37.719242285.78487725.693362-37.838282286.21375831.897787-38.333384285.99523931.897787-0.0005430.8082980.0002110.80830316.2063408.794004-37.719242285.78487725.693362-37.224473286.00249125.693362-37.342557286.42904931.897787-37.838282286.21375831.897787-2.07789725.3603552.49285928.05429516.2063408.794004-37.224473286.00249125.693362-36.729075286.21694125.693362-36.846228286.64121731.897787-37.342557286.42904931.897787-3.94980421.9858375.84181323.81722616.2063408.794004-36.729075286.21694125.693362-36.233069286.42832725.693362-36.349316286.85036231.897787-36.846228286.64121731.897787-5.20271323.2114777.79186718.26401216.2063408.794004-36.233069286.42832725.693362-35.736475286.63674825.693362-35.851841287.05658031.897787-36.349316286.85036231.897787-4.47632824.6312088.72546625.25795516.2063408.794004-35.736475286.63674825.693362-35.239314286.84229825.693362-35.353823287.25996831.897787-35.851841287.05658031.897787-3.65311121.39681411.76334421.82075316.2063408.794004-35.239314286.84229825.693362-34.741605287.04506925.693362-34.855281287.46061631.897787-35.353823287.25996831.897787-4.19538022.80240713.74492616.72109016.2063408.794004-34.741605287.04506925.693362-34.243367287.24515125.693362-34.356234287.65861431.897787-34.855281287.46061631.897787-2.64267223.0509779.79572625.23431716.2063408.794004-34.243367287.24515125.693362-33.744618287.44263025.693362-33.856698287.85404831.897787-34.356234287.65861431.897787-0.66503819.5165385.22089522.48429816.2063408.794004-33.744618287.44263025.693362-33.245377287.63759125.693362-33.356693288.04700131.897787-33.856698287.85404831.8977870.0000880.8082260.0030730.80706016.2063408.794004-38.333384285.99523931.897787-37.838282286.21375831.897787-37.955840286.64416638.102213-38.451903286.42806238.102213-0.0002830.808293-0.0000060.80830316.2063408.794004-37.838282286.21375831.897787-37.342557286.42904931.897787-37.459178286.85708638.102213-37.955840286.64416638.102213-1.49880923.3020352.18864727.51705516.2063408.794004-37.342557286.42904931.897787-36.846228286.64121731.897787-36.961939287.06692338.102213-37.459178286.85708638.102213-2.81394814.0033505.35355124.29526216.2063408.794004-36.846228286.64121731.897787-36.349316286.85036231.897787-36.464141287.27378038.102213-36.961939287.06692338.102213-4.53835516.8123307.09157019.88782916.2063408.794004-36.349316286.85036231.897787-35.851841287.05658031.897787-35.965806287.47775238.102213-36.464141287.27378038.102213-2.45685220.2482666.38555623.94707716.2063408.794004-35.851841287.05658031.897787-35.353823287.25996831.897787-35.466951287.67893438.102213-35.965806287.47775238.102213-0.74988313.2587167.45758818.15491116.2063408.794004-35.353823287.25996831.897787-34.855281287.46061631.897787-34.967596287.87741738.102213-35.466951287.67893438.102213-5.43032016.3631939.94584617.24664316.2063408.794004-34.855281287.46061631.897787-34.356234287.65861431.897787-34.467759288.07329038.102213-34.967596287.87741738.102213-3.63657519.3033117.40308223.57533016.2063408.794004-34.356234287.65861431.897787-33.856698287.85404831.897787-33.967458288.26663838.102213-34.467759288.07329038.1022130.02520313.6439094.01266123.15282216.2063408.794004-33.856698287.85404831.897787-33.356693288.04700131.897787-33.466709288.45754638.102213-33.967458288.26663838.1022130.0013570.808060-0.0004960.80656316.2063408.794004-38.451903286.42806238.102213-37.955840286.64416638.102213-38.071893287.07608144.306638-38.568897286.86244144.3066380.0000450.808291-0.0001610.80829516.2063408.794004-37.955840286.64416638.102213-37.459178286.85708638.102213-37.574317287.28657944.306638-38.071893287.07608144.306638-0.49340620.1389281.18203221.85892816.2063408.794004-37.459178286.85708638.102213-36.961939287.06692338.102213-37.076188287.49404044.306638-37.574317287.28657944.306638-0.83308717.4331233.25304919.42794516.2063408.794004-36.961939287.06692338.102213-36.464141287.27378038.102213-36.577525287.69856244.306638-37.076188287.49404044.306638-1.82422418.5749804.41879216.10049116.2063408.794004-36.464141287.27378038.102213-35.965806287.47775238.102213-36.078350287.90024344.306638-36.577525287.69856244.3066380.54735318.2868672.50644619.96443816.2063408.794004-35.965806287.47775238.102213-35.466951287.67893438.102213-35.578679288.09917744.306638-36.078350287.90024344.3066382.68012314.7983901.46955913.55755116.2063408.794004-35.466951287.67893438.102213-34.967596287.87741738.102213-35.078532288.29545344.306638-35.578679288.09917744.306638-4.36011715.5256993.61704710.92210916.2063408.794004-34.967596287.87741738.102213-34.467759288.07329038.102213-34.577926288.48916044.306638-35.078532288.29545344.306638-2.94914716.8009223.13486519.14083416.2063408.794004-34.467759288.07329038.102213-33.967458288.26663838.102213-34.076878288.68038444.306638-34.577926288.48916044.3066380.73496312.9112442.12617619.74075616.2063408.794004-33.967458288.26663838.102213-33.466709288.45754638.102213-33.575406288.86920744.306638-34.076878288.68038444.3066380.0032130.8077730.0109880.80435716.2063408.794004-38.568897286.86244144.306638-38.071893287.07608144.306638-38.186422287.50948150.511063-38.684345287.29835650.5110630.0001250.808321-0.0003880.80832316.2063408.794004-38.071893287.07608144.306638-37.574317287.28657944.306638-37.687952287.71751050.511063-38.186422287.50948150.5110630.0000730.8086080.0003470.80863116.2063408.794004-37.574317287.28657944.306638-37.076188287.49404044.306638-37.188954287.92254650.511063-37.687952287.71751050.5110630.0005500.8085280.0022200.80854116.2063408.794004-37.076188287.49404044.306638-36.577525287.69856244.306638-36.689448288.12468950.511063-37.188954287.92254650.511063-0.0004920.8085520.0036590.80842716.2063408.794004-36.577525287.69856244.306638-36.078350287.90024344.306638-36.189454288.32403450.511063-36.689448288.12468950.5110630.0050140.8083610.0010920.80850116.2063408.794004-36.078350287.90024344.306638-35.578679288.09917744.306638-35.688988288.52067650.511063-36.189454288.32403450.5110630.0176860.8071120.0042710.80793916.2063408.794004-35.578679288.09917744.306638-35.078532288.29545344.306638-35.188069288.71470350.511063-35.688988288.52067650.511063-0.0146150.8074110.0067330.80783516.2063408.794004-35.078532288.29545344.306638-34.577926288.48916044.306638-34.686715288.90620550.511063-35.188069288.71470350.511063-0.0058960.8082690.0011520.80843416.2063408.794004-34.577926288.48916044.306638-34.076878288.68038444.306638-34.184942289.09526550.511063-34.686715288.90620550.5110630.0021670.8082570.0025250.80842916.2063408.794004-34.076878288.68038444.306638-33.575406288.86920744.306638-33.682768289.28196650.511063-34.184942289.09526550.5110630.0009820.8080740.0055430.80757116.2063408.794004 diff --git a/src/tests/data/eewUtils_xml_example.pgd b/src/tests/data/eewUtils_xml_example.pgd new file mode 100644 index 00000000..e3a0b881 --- /dev/null +++ b/src/tests/data/eewUtils_xml_example.pgd @@ -0,0 +1,2 @@ + +6.5000000.40000046.000000nan-122.000000nan8.000000nan1970-01-01T00:00:00.000Znan0.800000 diff --git a/src/tests/data/gfast.props b/src/tests/data/gfast.props index e73ffdcd..ee27a995 100644 --- a/src/tests/data/gfast.props +++ b/src/tests/data/gfast.props @@ -10,7 +10,7 @@ metaDataFile=data/merged_chanfile_coord.dat #SA_events_dir=xxxxx SA_output_dir=data #output_interval_mins=1,2,3,4,5,10 -#siteMaskFile=xxxxx +siteMaskFile=data/site_mask_file.dat # File with station names and sampling periods #dtfile=GFAST_streams_dt.txt # ElarmS message file @@ -97,18 +97,37 @@ pgd_window_vel = 3.0 pgd_min_sites = 4 # Message throttling logic and related +# Lookup table for non-density corrected value to generate magnitude +# uncertainty based on time and magnitude sigmaLookupFile = data/M99.txt +# Lookup table for time-dependant PGD thresholds +# columns: time (s) | threshold (cm) | n stations +pgdThresholdLookupFile = data/pgd_threshold_PW.txt +# Positional uncertainty thresholds for including peak displacement observations +# If not specified, allow any or NAN uncertainties +rawSigmaThresholdLookupFile = data/raw_sigma_threshold_PW.txt # If defined, don't send xml if pgd_sigma is greater than this value pgd_sigma_throttle = 0.5 # Message throttling logic -SA_mag_threshold = -5.0 +SA_mag_threshold = 6.0 # Minimum and maximum thresholds for using pgd values in inversion, in cm minimum_pgd_cm = 0.0 maximum_pgd_cm = 3500.0 max_assoc_stations = 6 +# Change thresholds to decide when to send a message, assuming other throttles +# pass. If any of these are met or exceeded, a new message would be sent. If +# none are exceeded, message would not be sent. +# If not present, threshold will be ignored +change_threshold_mag = 0.05 +change_threshold_mag_uncer = 0.05 +change_threshold_lat = 0.05 +change_threshold_lon = 0.05 +change_threshold_orig_time = 1 +change_threshold_num_stations = 1 + ################################################################################ # CMT/Finite Fault Properties # ################################################################################ diff --git a/src/tests/data/site_mask_file.dat b/src/tests/data/site_mask_file.dat new file mode 100644 index 00000000..9f061254 --- /dev/null +++ b/src/tests/data/site_mask_file.dat @@ -0,0 +1,4 @@ +# net sta loc cha usePGD useCMT useFF +CI 7ODM 20 LYE 0 0 1 +CI ALPP 20 LYE 0 1 1 +CI BCWR 20 LYE 0 0 0 \ No newline at end of file diff --git a/src/tests/gfast_ut_utils.h b/src/tests/gfast_ut_utils.h index 5b24cf34..1c1979db 100644 --- a/src/tests/gfast_ut_utils.h +++ b/src/tests/gfast_ut_utils.h @@ -56,13 +56,16 @@ int read_pgd_results(const char *filenm, if (fgets(cline, sizeof(cline), infl) == NULL){goto ERROR;} sscanf(cline, "%lf %lf %lf\n", SA_lat, SA_lon, SA_dep); // pgd data - pgd_data->pd = ISCL_memory_calloc__double(pgd_data->nsites); - pgd_data->wt = ISCL_memory_calloc__double(pgd_data->nsites); - pgd_data->sta_lat = ISCL_memory_calloc__double(pgd_data->nsites); - pgd_data->sta_lon = ISCL_memory_calloc__double(pgd_data->nsites); - pgd_data->sta_alt = ISCL_memory_calloc__double(pgd_data->nsites); - pgd_data->lmask = ISCL_memory_calloc__bool(pgd_data->nsites); - pgd_data->lactive = ISCL_memory_calloc__bool(pgd_data->nsites); + pgd_data->stnm = (char **)calloc((size_t) pgd_data->nsites, + sizeof(char *)); + pgd_data->pd = memory_calloc64f(pgd_data->nsites); + pgd_data->wt = memory_calloc64f(pgd_data->nsites); + pgd_data->sta_lat = memory_calloc64f(pgd_data->nsites); + pgd_data->sta_lon = memory_calloc64f(pgd_data->nsites); + pgd_data->sta_alt = memory_calloc64f(pgd_data->nsites); + pgd_data->pd_time = memory_calloc64f(pgd_data->nsites); + pgd_data->lmask = memory_calloc8l(pgd_data->nsites); + pgd_data->lactive = memory_calloc8l(pgd_data->nsites); for (i=0; insites; i++) { memset(cline, 0, sizeof(cline)); @@ -70,8 +73,12 @@ int read_pgd_results(const char *filenm, sscanf(cline, "%lf %lf %lf %lf\n", &pgd_data->sta_lat[i], &pgd_data->sta_lon[i], &pgd_data->sta_alt[i], &pgd_data->pd[i]); + pgd_data->pd_time[i] = 0.0; pgd_data->wt[i] = 1.0; pgd_data->lactive[i] = true; + + pgd_data->stnm[i] = (char *)calloc(64, sizeof(char)); + sprintf(pgd_data->stnm[i],"XX%02d", i); } // Results + depths in grid search pgd->nsites = pgd_data->nsites; @@ -311,3 +318,55 @@ int read_ff_results(const char *fname, ERROR:; return ierr; } + +void fill_gps_data(struct GFAST_data_struct *gps_data, + const int k, + const char *netw, + const char *stat, + const char *chan, + const char *loc, + const double lat, + const double lon, + const double elev, + const double dt, + const double gain, + const int mpts) { + strcpy(gps_data->data[k].netw, netw); + strcpy(gps_data->data[k].stnm, stat); + strncpy(gps_data->data[k].chan[0], chan, 2); + strcat( gps_data->data[k].chan[0], "Z\0"); + strncpy(gps_data->data[k].chan[1], chan, 2); + strcat( gps_data->data[k].chan[1], "N\0"); + strncpy(gps_data->data[k].chan[2], chan, 2); + strcat( gps_data->data[k].chan[2], "E\0"); + strncpy(gps_data->data[k].chan[3], chan, 2); + strcat( gps_data->data[k].chan[3], "3\0"); + strncpy(gps_data->data[k].chan[4], chan, 2); + strcat( gps_data->data[k].chan[4], "2\0"); + strncpy(gps_data->data[k].chan[5], chan, 2); + strcat( gps_data->data[k].chan[5], "1\0"); + strncpy(gps_data->data[k].chan[6], chan, 2); + strcat( gps_data->data[k].chan[6], "Q\0"); + strcpy(gps_data->data[k].loc, loc); + gps_data->data[k].sta_lat = lat; + gps_data->data[k].sta_lon = lon; + gps_data->data[k].sta_alt = elev; + gps_data->data[k].dt = dt; + gps_data->data[k].gain[0] = gain; + gps_data->data[k].gain[1] = gain; + gps_data->data[k].gain[2] = gain; + gps_data->data[k].gain[3] = gain; + gps_data->data[k].gain[4] = gain; + gps_data->data[k].gain[5] = gain; + gps_data->data[k].gain[6] = 1; // Quality channel has no gain + + gps_data->data[k].maxpts = mpts; + gps_data->data[k].ubuff = memory_calloc64f(mpts); + gps_data->data[k].nbuff = memory_calloc64f(mpts); + gps_data->data[k].ebuff = memory_calloc64f(mpts); + gps_data->data[k].usigmabuff = memory_calloc64f(mpts); + gps_data->data[k].nsigmabuff = memory_calloc64f(mpts); + gps_data->data[k].esigmabuff = memory_calloc64f(mpts); + gps_data->data[k].qbuff = memory_calloc64f(mpts); + gps_data->data[k].tbuff = memory_calloc64f(mpts); +} diff --git a/src/xml/quakeML/epoch2string.c b/src/xml/quakeML/epoch2string.c index bcd3fcf0..9c4d82bf 100644 --- a/src/xml/quakeML/epoch2string.c +++ b/src/xml/quakeML/epoch2string.c @@ -33,7 +33,7 @@ int xml_epoch2string(double epoch, char cepoch[128]) } sec = (double) nzsec + (double) nzmusec*1.e-6; sprintf(cepoch, - "%04d-%02d-%02dT%02d:%02d:%04.3fZ", + "%04d-%02d-%02dT%02d:%02d:%06.3fZ", nzyear, month, mday, nzhour, nzmin, sec); return 0; } From 4c0af5ce594fc2fbe439a5b9152402538fdb840d Mon Sep 17 00:00:00 2001 From: claude Date: Tue, 24 Oct 2023 01:18:52 +0000 Subject: [PATCH 13/18] consolidate definition of gen_recursive_targets macro --- Makefile | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 3f0a2a45..60c7cbe1 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ # Toplevel Makefile for GFAST +EEWDIR = .. +include $(EEWDIR)/Makefile.rules + SUBDIRS=src .PHONY: all show-targets $(SUBDIRS) @@ -9,17 +12,7 @@ TARGET_LIST=show-targets all: $(SUBDIRS) -# define macro to generate rules for target, list of sub targets and rule for each. -define gen_recursive_targets -.PHONY: $(1) $(2:%=$(1)-%) -$(1): $(2:%=$(1)-%) -$(2:%=$(1)-%): - $(MAKE) -C $$(@:$$$(1)-%=%) $1 - @echo -e "" -TARGET_LIST+= $(1) $(2:%=$(1)-%) -endef - -# use macro to define recursive targets +# use macro defined in Makefile.rules to define recursive targets $(eval $(call gen_recursive_targets, all, $(SUBDIRS))) $(eval $(call gen_recursive_targets, ids, $(SUBDIRS))) $(eval $(call gen_recursive_targets, rm-ids, $(SUBDIRS))) From 930eacd1a99f76edf8bad594dc7128c2d1f5d2f3 Mon Sep 17 00:00:00 2001 From: Andrew Good Date: Thu, 2 Nov 2023 18:04:17 -0700 Subject: [PATCH 14/18] 20231102: Bugfix to finder/src/Makefile and gfast/src/Makefile to make cleancoverage/veryclean directives delete appropriate UT and .info files. --- src/Makefile | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Makefile b/src/Makefile index 6db9944b..d16c3d41 100644 --- a/src/Makefile +++ b/src/Makefile @@ -72,6 +72,12 @@ install: make -C $$dir install ; \ done +TESTDIR = ./tests +ut: + make -C $(TESTDIR) ut +test: + make -C $(TESTDIR) test + clean: -rm -f *.o $(EXE) for dir in $(SUBDIRS) ; do \ @@ -83,18 +89,13 @@ veryclean: cleandocs for dir in $(SUBDIRS) ; do \ make -C $$dir veryclean ; \ done + make -C $(TESTDIR) veryclean depend: for dir in $(SUBDIRS) ; do \ make -C $$dir depend ; \ done -TESTDIR = ./tests -ut: - make -C $(TESTDIR) ut -test: - make -C $(TESTDIR) test - # coverage INFODIR = $(EEWDIR)/coverage/info COVDIR = $(EEWDIR)/coverage/html @@ -108,7 +109,7 @@ coverage: cleancoverage covdirs buildcoverage runcoverage cleancoverage: -rm -rf *.gcno *.gcda *.gcov *.info $(COVDIR) - make -C tests cleancoverage + make -C $(TESTDIR) cleancoverage for dir in $(SUBDIRS) ; do \ make -C $$dir cleancoverage ; \ done From 59d007acc6c130502e4b7b6692b9522dd199e0f8 Mon Sep 17 00:00:00 2001 From: ulbergc Date: Wed, 20 Dec 2023 22:00:13 +0000 Subject: [PATCH 15/18] Separate unit tests from Make system since they require ShakeAlert environment --- src/Makefile | 8 ++++---- src/tests/Makefile | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Makefile b/src/Makefile index ad975ea2..be444372 100644 --- a/src/Makefile +++ b/src/Makefile @@ -71,22 +71,22 @@ install: TESTDIR = ./tests ut: - make -C $(TESTDIR) ut + # make -C $(TESTDIR) ut test: - make -C $(TESTDIR) test + # make -C $(TESTDIR) test clean: -rm -f *.o $(EXE) for dir in $(SUBDIRS) ; do \ make -C $$dir clean ; \ done - make -C $(TESTDIR) clean + # make -C $(TESTDIR) clean veryclean: cleandocs for dir in $(SUBDIRS) ; do \ make -C $$dir veryclean ; \ done - make -C $(TESTDIR) veryclean + # make -C $(TESTDIR) veryclean depend: for dir in $(SUBDIRS) ; do \ diff --git a/src/tests/Makefile b/src/tests/Makefile index ccebed89..e123eaa2 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,5 +1,6 @@ # Makefile for gfast unit tests -# Modeled after libs/utils/tests/Makefile, may need additional changes +# Currently setup to run within a ShakeAlert directory. Will need work +# to run in a standalone GFAST installation EEWDIR = ../../.. include $(EEWDIR)/Make.include.$(shell uname) From 24be129f27c64862cc994029b3d50151c0d1e431 Mon Sep 17 00:00:00 2001 From: ulbergc Date: Wed, 20 Dec 2023 22:21:45 +0000 Subject: [PATCH 16/18] fix libxml2 make paths --- src/Make.include.Linux | 4 ++-- src/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Make.include.Linux b/src/Make.include.Linux index 49c2e98b..3e247c0a 100644 --- a/src/Make.include.Linux +++ b/src/Make.include.Linux @@ -38,8 +38,8 @@ LAPACKE_INCL=-I /usr/include/lapacke LAPACKE_LIB= $(LIB_DIR)/liblapack.so.3 $(LIB_DIR)/liblapacke.so.3 #LAPACKE_LIB= $(LIB_DIR)/liblapack_atlas.a #LAPACKE_LIB=-llapack -llapacke -XML_INCL=-I /usr/include/libxml2 -XML_LIB=-lxml2 +XML2_INCL=-I /usr/include/libxml2 +XML2_LIB=-lxml2 FFTW_INCL= FFTW_LIB= SSL_LIB=/usr/lib64/libssl.so.10 diff --git a/src/Makefile b/src/Makefile index be444372..ceb6c25d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,7 @@ traceBuffer/traceBuffer.a hdf5/hdf5.a activeMQ/gfast_amq.a ifdef GFAST_USE_DMLIB OBJS += dmlib/dmlibWrapper.cpp.o endif -LIBS = $(EW_LIB) $(ISCL_LIB) $(INIPARSER_LIB) $(XML_LIB) $(HDF5_LIB) $(COMPEARTH_LIB) \ +LIBS = $(EW_LIB) $(ISCL_LIB) $(INIPARSER_LIB) $(XML2_LIB) $(HDF5_LIB) $(COMPEARTH_LIB) \ $(ACTIVEMQ_LIB) $(DM_LIB) $(APR_LIB) $(LAPACKE_LIB) $(CBLAS_LIB) $(FFTW_LIB) $(SSL_LIB) \ $(XERCES_LIB) $(QLIB2_LIB) $(CRYPTO_LIB) SYSLIBS = -ldl -lm -lnsl -lrt -pthread -lz -lsz -lstdc++ From 94480a22f1030347a62c5068a64111f671620912 Mon Sep 17 00:00:00 2001 From: ulbergc Date: Wed, 20 Dec 2023 22:42:15 +0000 Subject: [PATCH 17/18] Update gfast version number and modify cmake settings --- CMakeLists.txt | 4 ++-- CMakeModules/FindXML2.cmake | 2 +- README.md | 8 +++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b3831e3..a8dbe8a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ ENABLE_LANGUAGE(CXX) ENABLE_TESTING() SET(GFAST_VERSION_MAJOR 1) SET(GFAST_VERSION_MINOR 2) -SET(GFAST_VERSION_PATCH 3) +SET(GFAST_VERSION_PATCH 4) SET(GFAST_VERSION ${GFAST_VERSION_MAJOR}.${GFAST_VERSION_MINOR}.${GFAST_VERSION_PATCH}) IF ("${GFAST_INSTANCE}" STREQUAL "") SET(GFAST_INSTANCE "DEFAULT") @@ -114,7 +114,7 @@ SET(SRCS_CORE #ADD_SUBDIRECTORY(src/eewUtils) SET(SRCS_EEW src/eewUtils/driveCMT.c src/eewUtils/driveFF.c src/eewUtils/driveGFAST.c src/eewUtils/drivePGD.c src/eewUtils/makeXML.c src/eewUtils/parseCoreXML.c - src/eewUtils/setLogFileNames.c) + src/eewUtils/setLogFileNames.c src/eewUtils/fillCoreEventInfo.c) #ADD_SUBDIRECTORY(src/traceBuffer) SET(SRCS_H5TB src/traceBuffer/h5/copyTraceBufferToGFAST.c src/traceBuffer/h5/finalize.c src/traceBuffer/h5/getData.c src/traceBuffer/h5/getDoubleArray.c diff --git a/CMakeModules/FindXML2.cmake b/CMakeModules/FindXML2.cmake index 4923848b..690aba65 100644 --- a/CMakeModules/FindXML2.cmake +++ b/CMakeModules/FindXML2.cmake @@ -19,7 +19,7 @@ find_library(LIBXML2_LIBRARY NAMES xml2 libxml2 include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE # if all listed variables are TRUE -find_package_handle_standard_args(LibXml2 DEFAULT_MSG +find_package_handle_standard_args(XML2 DEFAULT_MSG LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARY ) diff --git a/README.md b/README.md index fd2309c5..2eb857fb 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ This is the source code for Geodetic First Approximation of Size and Timing (GFA ## Recent updates +2023/12/20 CWU: Sync most recent changes from ShakeAlert GFAST version to the PNSN repo (GFAST v1.2.4) 2023/03/20 CWU: Sync most recent changes from ShakeAlert GFAST version to the PNSN repo (GFAST v1.2.3-beta) ~2021/10 CWU: merge 2020 and SAdev branches into one branch to use going forward, called "development" 2020/05/27 MTH: Working on new branch (=2020) with cleaned up dependencies and build instructions. @@ -14,7 +15,7 @@ This is the source code for Geodetic First Approximation of Size and Timing (GFA 2. include contains the GFAST C include files. 3. legacy is the original Python source code. 4. src contains the source code. - + src/activeMQ contains C++ readers/writers and C interfaes for using ActiveMQ. + + src/activeMQ contains C++ readers/writers and C interfaces for using ActiveMQ. + src/core contains the core GFAST computations. + src/dmlib contains functionality making use of some ShakeAlert libraries, primarily related to ActiveMQ connections and xml encoding/decoding. Access to the ShakeAlert code repository would be necessary to build using these codes. + src/eewUtils contains application specific functions for performing the earthquake early warning tasks. @@ -22,6 +23,7 @@ This is the source code for Geodetic First Approximation of Size and Timing (GFA + src/traceBuffer contains routines for reading an Earthworm ring and converting to a GFAST specific buffer. + src/uw contains functions specific to the University of Washington and Amazon project. + src/xml contains functions for certainly writing and potentially reading QuakeML and ShakeAlert specific XML. + + src/tests contains googletest unit tests, primarily tuned to work within a ShakeAlert environment/repo 5. unit\_tests contains some simple regression tests for the core modules. # Building GFAST @@ -186,7 +188,7 @@ But here's how to do it in stand-alone >make // will build lib/libiscl_shared.so and lib/libiscl_static.a -7. [compearth/mtbeach](https://github.com/carltape/mtbeach.git) for the moment tensor decompositions. Note, this was in Ben Baker's [compearth repository](https://github.com/bakerb845/compearth), but was merged back into Carl Tape's repository, and the moment tensor part was renames mtbeach. Also, you'll need to descend into c_src. +7. [compearth/mtbeach](https://github.com/carltape/mtbeach.git) for the moment tensor decompositions. Note, this was in Ben Baker's [compearth repository](https://github.com/bakerb845/compearth), but was merged back into Carl Tape's repository, and the moment tensor part was renamed mtbeach. Also, you'll need to descend into c_src. Clone and build >git clone https://github.com/carltape/mtbeach.git @@ -243,7 +245,7 @@ But here's how to do it in stand-alone 9a. [ActiveMQ](http://activemq.apache.org/) The C++ portion. These will require other things that you likely already have like libssl, libcrypto, and the Apache runtime library. - Note: [MTH] I haven't found the APR to be necessary + Note: [MTH] I haven't found the APR to be necessary Note: For building GFAST, the instructions here for downloading and installing activemq-cpp are sufficient. However, as soon as gfast_eew starts, it will try to connect From cee62dc7e02177c18dad2f6530b46d455cc05480 Mon Sep 17 00:00:00 2001 From: ulbergc Date: Wed, 20 Dec 2023 22:51:29 +0000 Subject: [PATCH 18/18] More cleanup from ShakeAlert sync --- CMakeLists.txt | 3 +- Make.include.gfast | 92 ---------------------------------------------- 2 files changed, 2 insertions(+), 93 deletions(-) delete mode 100644 Make.include.gfast diff --git a/CMakeLists.txt b/CMakeLists.txt index a8dbe8a2..bdc4c7ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,8 @@ SET(SRCS_CORE #ADD_SUBDIRECTORY(src/eewUtils) SET(SRCS_EEW src/eewUtils/driveCMT.c src/eewUtils/driveFF.c src/eewUtils/driveGFAST.c src/eewUtils/drivePGD.c src/eewUtils/makeXML.c src/eewUtils/parseCoreXML.c - src/eewUtils/setLogFileNames.c src/eewUtils/fillCoreEventInfo.c) + src/eewUtils/setLogFileNames.c src/eewUtils/fillCoreEventInfo.c + src/eewUtils/sendXMLFilter.c) #ADD_SUBDIRECTORY(src/traceBuffer) SET(SRCS_H5TB src/traceBuffer/h5/copyTraceBufferToGFAST.c src/traceBuffer/h5/finalize.c src/traceBuffer/h5/getData.c src/traceBuffer/h5/getDoubleArray.c diff --git a/Make.include.gfast b/Make.include.gfast deleted file mode 100644 index 2206b965..00000000 --- a/Make.include.gfast +++ /dev/null @@ -1,92 +0,0 @@ -# Makefile variables specific to GFAST - -# Make.include.Linux should define things like CFLAGS, CCFLAGS, BITS -include $(EEWDIR)/Make.include.$(shell uname) - -# Next set of vars are for GFAST -GFAST_USE_EW=-DGFAST_USE_EW -GFAST_USE_AMQ=-DGFAST_USE_AMQ -GFAST_USE_DMLIB=-DGFAST_USE_DMLIB - -ifdef GFAST_USE_EW -CFLAGS+=$(GFAST_USE_EW) -endif -ifdef GFAST_USE_AMQ -CFLAGS+=$(GFAST_USE_AMQ) -endif -ifdef GFAST_USE_DMLIB -CFLAGS+=$(GFAST_USE_DMLIB) -endif -ifdef ENABLE_PLOG -CFLAGS+=$(ENABLE_PLOG) -endif - -ifeq ($(COMPEARTH),) - COMPEARTH=/usr/local/mtbeach -endif -ifeq ($(COMPEARTH_INCL),) - COMPEARTH_INCL=-I$(COMPEARTH)/include -endif -ifeq ($(COMPEARTH_LIB),) - COMPEARTH_LIB=$(COMPEARTH)/lib/libcompearth_static.a -endif - -ifeq ($(ISCL),) - ISCL=/usr/local/iscl -endif -ifeq ($(ISCL_INCL),) - ISCL_INCL=-I$(ISCL)/include -endif -ifeq ($(ISCL_LIB),) - ISCL_LIB=$(ISCL)/lib/libiscl_static.a -endif - -ifeq ($(INIPARSER),) - INIPARSER=/usr/local/iniparser-4.1 -endif -ifeq ($(INIPARSER_INCL),) - INIPARSER_INCL=-I$(INIPARSER)/include -endif -ifeq ($(INIPARSER_LIB),) - INIPARSER_LIB=$(INIPARSER)/lib/libiniparser.a -endif - -ifeq ($(LAPACKE),) - LAPACKE=/usr -endif -ifeq ($(LAPACKE_INCL),) - LAPACKE_INCL=-I$(LAPACKE)/include/lapacke -endif -ifeq ($(LAPACKE_LIB),) - LAPACKE_LIB=$(LAPACKE)/lib$(BITS)/liblapack.so.3 $(LAPACKE)/lib$(BITS)/liblapacke.so.3 -endif - -ifeq ($(XML2),) - XML2=/usr -endif -ifeq ($(XML2_INCL),) - XML2_INCL=-I$(XML2)/include/libxml2 -endif -ifeq ($(XML2_LIB),) - XML2_LIB=-L$(XML2)/lib$(BITS) -lxml2 -endif - -ifeq ($(CBLAS),) - CBLAS=/usr -endif -ifeq ($(CBLAS_INCL),) - CBLAS_INCL=-I$(CBLAS)/include/openblas -endif -ifeq ($(CBLAS_LIB),) - CBLAS_LIB=-L$(CBLAS)/lib$(BITS)/atlas -ltatlas -endif - -ifeq ($(HDF5),) - HDF5=/usr -endif -ifeq ($(HDF5_INCL),) - HDF5_INCL=-I$(HDF5)/include -endif -ifeq ($(HDF5_LIB),) - HDF5_LIB=-lhdf5 -endif \ No newline at end of file