def test_operators(): d = _CoreTimeSeries(10) d1 = make_constant_data_ts(d, nsamp=10) dsave = _CoreTimeSeries(d1) d = _CoreTimeSeries(6) d2 = make_constant_data_ts(d, t0=-0.2, nsamp=6, val=2.0) dsave = _CoreTimeSeries(d1) d1 += d2 assert np.allclose(d1.data, [3, 3, 3, 3, 1, 1, 1, 1, 1, 1]) d1 = _CoreTimeSeries(dsave) d = d1 + d2 assert np.allclose(d.data, [3, 3, 3, 3, 1, 1, 1, 1, 1, 1]) d1 = _CoreTimeSeries(dsave) d1 *= 2.5 assert np.allclose(d1.data, [2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5]) d3 = TimeSeries(10) d4 = TimeSeries(6) d3 = make_constant_data_ts(d3, nsamp=10) d4 = make_constant_data_ts(d4, t0=-0.2, nsamp=6, val=2.0) dsave = _CoreTimeSeries(d3) d3 = TimeSeries(dsave) d3 += d4 assert np.allclose(d3.data, [3, 3, 3, 3, 1, 1, 1, 1, 1, 1]) d3 = TimeSeries(dsave) d = d3 + d4 assert np.allclose(d.data, [3, 3, 3, 3, 1, 1, 1, 1, 1, 1]) d1 = _CoreTimeSeries(dsave) d3 = TimeSeries(dsave) d3 *= 2.5 assert np.allclose(d3.data, [2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5]) x = np.linspace(-0.7, 1.2, 20) for t in x: d3 = TimeSeries(dsave) d4.t0 = t d3 += d4 # These are selected asserts of the incremental test above # visually d4 moves through d3 as the t0 value advance. Assert # tests end member: skewed left, inside, and skewed right d3 = TimeSeries(dsave) d4.t0 = -0.7 # no overlap test d3 += d4 assert np.allclose(d3.data, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) d3 = TimeSeries(dsave) d4.t0 = -0.3 # overlap left d3 += d4 assert np.allclose(d3.data, [3, 3, 3, 1, 1, 1, 1, 1, 1, 1]) d3 = TimeSeries(dsave) d4.t0 = 0.3 # d4 inside d3 test d3 += d4 assert np.allclose(d3.data, [1, 1, 1, 3, 3, 3, 3, 3, 3, 1]) d3 = TimeSeries(dsave) d4.t0 = 0.7 # partial overlap right d3 += d4 assert np.allclose(d3.data, [1, 1, 1, 1, 1, 1, 1, 3, 3, 3]) d3 = TimeSeries(dsave) d4.t0 = 1.0 # no overlap test right d3 += d4 assert np.allclose(d3.data, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) # Repeat the same test for Seismogram objects # This section is edited cut-paste of above # Intentionally do not test _CoreSeismogram directly because # currently if it works for Seismogram it will for _CoreSeismogram d = _CoreSeismogram(10) d1 = make_constant_data_seis(d, nsamp=10) dsave = _CoreSeismogram(d1) d = _CoreSeismogram(6) d2 = make_constant_data_seis(d, t0=-0.2, nsamp=6, val=2.0) dsave = _CoreSeismogram(d1) d1 += d2 assert np.allclose( d1.data, np.array([ [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ]), ) d1 = _CoreSeismogram(dsave) d = d1 + d2 assert np.allclose( d.data, np.array([ [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ]), ) d1 = _CoreSeismogram(dsave) d1 *= 2.5 assert np.allclose( d1.data, np.array([ [2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5], [2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5], [2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5], ]), ) d3 = Seismogram(10) d4 = Seismogram(6) d3 = make_constant_data_seis(d3, nsamp=10) d4 = make_constant_data_seis(d4, t0=-0.2, nsamp=6, val=2.0) dsave = Seismogram(d3) d3 += d4 assert np.allclose( d3.data, np.array([ [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ]), ) d3 = Seismogram(dsave) d = d3 + d4 assert np.allclose( d.data, np.array([ [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [3.0, 3.0, 3.0, 3.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ]), ) d3 = Seismogram(dsave) d3 *= 2.5 assert np.allclose( d1.data, np.array([ [2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5], [2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5], [2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5], ]), ) x = np.linspace(-0.7, 1.2, 20) for t in x: d3 = Seismogram(dsave) d4.t0 = t d3 += d4 # These are selected asserts of the incremental test above # visually d4 moves through d3 as the t0 value advance. Assert # tests end member: skewed left, inside, and skewed right d3 = Seismogram(dsave) d4.t0 = -0.7 # no overlap test d3 += d4 assert np.allclose( d3.data, np.array([ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], ]), ) d3 = Seismogram(dsave) d4.t0 = -0.3 # overlap left d3 += d4 assert np.allclose( d3.data, np.array([ [3, 3, 3, 1, 1, 1, 1, 1, 1, 1], [3, 3, 3, 1, 1, 1, 1, 1, 1, 1], [3, 3, 3, 1, 1, 1, 1, 1, 1, 1], ]), ) d3 = Seismogram(dsave) d4.t0 = 0.3 # d4 inside d3 test d3 += d4 assert np.allclose( d3.data, np.array([ [1, 1, 1, 3, 3, 3, 3, 3, 3, 1], [1, 1, 1, 3, 3, 3, 3, 3, 3, 1], [1, 1, 1, 3, 3, 3, 3, 3, 3, 1], ]), ) d3 = Seismogram(dsave) d4.t0 = 0.7 # partial overlap right d3 += d4 assert np.allclose( d3.data, np.array([ [1, 1, 1, 1, 1, 1, 1, 3, 3, 3], [1, 1, 1, 1, 1, 1, 1, 3, 3, 3], [1, 1, 1, 1, 1, 1, 1, 3, 3, 3], ]), ) d3 = Seismogram(dsave) d4.t0 = 1.0 # no overlap test right d3 += d4 assert np.allclose( d3.data, np.array([ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], ]), ) # Repeat exactly for - test but different numeric results # just omit *= tests d = _CoreTimeSeries(10) d1 = make_constant_data_ts(d, nsamp=10) dsave = _CoreTimeSeries(d1) d = _CoreTimeSeries(6) d2 = make_constant_data_ts(d, t0=-0.2, nsamp=6, val=2.0) dsave = _CoreTimeSeries(d1) d1 -= d2 assert np.allclose(d1.data, [-1, -1, -1, -1, 1, 1, 1, 1, 1, 1]) d1 = _CoreTimeSeries(dsave) d = d1 - d2 assert np.allclose(d.data, [-1, -1, -1, -1, 1, 1, 1, 1, 1, 1]) d3 = TimeSeries(10) d4 = TimeSeries(6) d3 = make_constant_data_ts(d3, nsamp=10) d4 = make_constant_data_ts(d4, t0=-0.2, nsamp=6, val=2.0) dsave = _CoreTimeSeries(d3) d3 = TimeSeries(dsave) d3 -= d4 assert np.allclose(d3.data, [-1, -1, -1, -1, 1, 1, 1, 1, 1, 1]) d3 = TimeSeries(dsave) d = d3 - d4 assert np.allclose(d.data, [-1, -1, -1, -1, 1, 1, 1, 1, 1, 1]) x = np.linspace(-0.7, 1.2, 20) for t in x: d3 = TimeSeries(dsave) d4.t0 = t d3 -= d4 # These are selected asserts of the incremental test above # visually d4 moves through d3 as the t0 value advance. Assert # tests end member: skewed left, inside, and skewed right d3 = TimeSeries(dsave) d4.t0 = -0.7 # no overlap test d3 -= d4 assert np.allclose(d3.data, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) d3 = TimeSeries(dsave) d4.t0 = -0.3 # overlap left d3 -= d4 assert np.allclose(d3.data, [-1, -1, -1, 1, 1, 1, 1, 1, 1, 1]) d3 = TimeSeries(dsave) d4.t0 = 0.3 # d4 inside d3 test d3 -= d4 assert np.allclose(d3.data, [1, 1, 1, -1, -1, -1, -1, -1, -1, 1]) d3 = TimeSeries(dsave) d4.t0 = 0.7 # partial overlap right d3 -= d4 assert np.allclose(d3.data, [1, 1, 1, 1, 1, 1, 1, -1, -1, -1]) d3 = TimeSeries(dsave) d4.t0 = 1.0 # no overlap test right d3 -= d4 assert np.allclose(d3.data, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) # Repeat the same test for Seismogram objects # This section is edited cut-paste of above # Intentionally do not test _CoreSeismogram directly because # currently if it works for Seismogram it will for _CoreSeismogram d = _CoreSeismogram(10) d1 = make_constant_data_seis(d, nsamp=10) dsave = _CoreSeismogram(d1) d = _CoreSeismogram(6) d2 = make_constant_data_seis(d, t0=-0.2, nsamp=6, val=2.0) dsave = _CoreSeismogram(d1) d1 -= d2 assert np.allclose( d1.data, np.array([ [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ]), ) d1 = _CoreSeismogram(dsave) d = d1 - d2 assert np.allclose( d.data, np.array([ [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ]), ) d3 = Seismogram(10) d4 = Seismogram(6) d3 = make_constant_data_seis(d3, nsamp=10) d4 = make_constant_data_seis(d4, t0=-0.2, nsamp=6, val=2.0) dsave = Seismogram(d3) d3 -= d4 assert np.allclose( d3.data, np.array([ [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ]), ) d3 = Seismogram(dsave) d = d3 - d4 assert np.allclose( d.data, np.array([ [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], ]), ) x = np.linspace(-0.7, 1.2, 20) for t in x: d3 = Seismogram(dsave) d4.t0 = t d3 -= d4 # These are selected asserts of the incremental test above # visually d4 moves through d3 as the t0 value advance. Assert # tests end member: skewed left, inside, and skewed right d3 = Seismogram(dsave) d4.t0 = -0.7 # no overlap test d3 -= d4 assert np.allclose( d3.data, np.array([ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], ]), ) d3 = Seismogram(dsave) d4.t0 = -0.3 # overlap left d3 -= d4 assert np.allclose( d3.data, np.array([ [-1, -1, -1, 1, 1, 1, 1, 1, 1, 1], [-1, -1, -1, 1, 1, 1, 1, 1, 1, 1], [-1, -1, -1, 1, 1, 1, 1, 1, 1, 1], ]), ) d3 = Seismogram(dsave) d4.t0 = 0.3 # d4 inside d3 test d3 -= d4 assert np.allclose( d3.data, np.array([ [1, 1, 1, -1, -1, -1, -1, -1, -1, 1], [1, 1, 1, -1, -1, -1, -1, -1, -1, 1], [1, 1, 1, -1, -1, -1, -1, -1, -1, 1], ]), ) d3 = Seismogram(dsave) d4.t0 = 0.7 # partial overlap right d3 -= d4 assert np.allclose( d3.data, np.array([ [1, 1, 1, 1, 1, 1, 1, -1, -1, -1], [1, 1, 1, 1, 1, 1, 1, -1, -1, -1], [1, 1, 1, 1, 1, 1, 1, -1, -1, -1], ]), ) d3 = Seismogram(dsave) d4.t0 = 1.0 # no overlap test right d3 -= d4 assert np.allclose( d3.data, np.array([ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], ]), )
def test_CoreSeismogram(): md = Metadata() md["delta"] = 0.01 md["starttime"] = 0.0 md["npts"] = 100 # test metadata constructor md["tmatrix"] = np.random.rand(3, 3) cseis = _CoreSeismogram(md, False) assert (cseis.tmatrix == md["tmatrix"]).all() md["tmatrix"] = dmatrix(np.random.rand(3, 3)) cseis = _CoreSeismogram(md, False) assert (cseis.tmatrix == md["tmatrix"]).all() md["tmatrix"] = np.random.rand(9) cseis = _CoreSeismogram(md, False) assert (cseis.tmatrix == md["tmatrix"].reshape(3, 3)).all() md["tmatrix"] = np.random.rand(1, 9) cseis = _CoreSeismogram(md, False) assert (cseis.tmatrix == md["tmatrix"].reshape(3, 3)).all() md["tmatrix"] = np.random.rand(9, 1) cseis = _CoreSeismogram(md, False) assert (cseis.tmatrix == md["tmatrix"].reshape(3, 3)).all() md["tmatrix"] = np.random.rand(3, 3).tolist() cseis = _CoreSeismogram(md, False) assert np.isclose(cseis.tmatrix, np.array(md["tmatrix"]).reshape(3, 3)).all() md["tmatrix"] = np.random.rand(9).tolist() cseis = _CoreSeismogram(md, False) assert np.isclose(cseis.tmatrix, np.array(md["tmatrix"]).reshape(3, 3)).all() # test whether the setter of tmatrix updates metadata correctly tm = np.random.rand(1, 9) cseis.tmatrix = tm assert (cseis.tmatrix == tm.reshape(3, 3)).all() assert np.isclose(cseis.tmatrix, np.array(cseis["tmatrix"]).reshape(3, 3)).all() tm = np.random.rand(9).tolist() cseis.tmatrix = tm assert np.isclose(cseis.tmatrix, np.array(tm).reshape(3, 3)).all() assert np.isclose(cseis.tmatrix, np.array(cseis["tmatrix"]).reshape(3, 3)).all() # test exceptions md["tmatrix"] = np.random.rand(4, 2) with pytest.raises(MsPASSError, match="should be a 3x3 matrix"): _CoreSeismogram(md, False) md["tmatrix"] = dmatrix(np.random.rand(2, 4)) with pytest.raises(MsPASSError, match="should be a 3x3 matrix"): _CoreSeismogram(md, False) md["tmatrix"] = 42 with pytest.raises(MsPASSError, match="not recognized"): _CoreSeismogram(md, False) md.erase("tmatrix") # tmatrix not defined is taken to default to tmatrix being an identity # matrix. We test that condition here cseis = _CoreSeismogram(md, False) assert np.isclose(cseis.tmatrix, np.eye(3)).all() md["tmatrix"] = {4: 2} with pytest.raises(MsPASSError, match="type is not recognized"): _CoreSeismogram(md, False) md["tmatrix"] = np.random.rand(9).tolist() md["tmatrix"][3] = "str" with pytest.raises(MsPASSError, match="should be float"): _CoreSeismogram(md, False) md["tmatrix"] = np.random.rand(3, 4).tolist() with pytest.raises(MsPASSError, match="should be a 3x3 list of list"): _CoreSeismogram(md, False) md["tmatrix"] = [1, 2, 3] with pytest.raises(MsPASSError, match="should be a 3x3 list of list"): _CoreSeismogram(md, False) md["tmatrix"] = np.random.rand(2, 2).tolist() with pytest.raises( MsPASSError, match="should be a list of 9 floats or a 3x3 list of list"): _CoreSeismogram(md, False) md["tmatrix"] = np.random.rand(3, 3).tolist() md["tmatrix"][1][1] = "str" with pytest.raises(MsPASSError, match="should be float"): _CoreSeismogram(md, False)
def Stream2Seismogram(st, master=0, cardinal=False, azimuth="azimuth", dip="dip"): """ Convert obspy Stream to a Seismogram. Convert an obspy Stream object with 3 components to a mspass::Seismogram (three-component data) object. This implementation actually converts each component first to a TimeSeries and then calls a C++ function to assemble the complete Seismogram. This has some inefficiencies, but the assumption is this function is called early on in a processing chain to build a raw data set. :param st: input obspy Stream object. The object MUST have exactly 3 components or the function will throw a AssertionError exception. The program is less dogmatic about start times and number of samples as these are handled by the C++ function this python script calls. Be warned, however, that the C++ function can throw a MsPASSrror exception that should be handled separately. :param master: a Seismogram is an assembly of three channels composed created from three TimeSeries/Trace objects. Each component may have different metadata (e.g. orientation data) and common metadata (e.g. station coordinates). To assemble a Seismogram a decision has to be made on which component has the definitive common metadata. We use a simple algorithm and clone the data from one component defined by this index. Must be 0,1, or 2 or the function wil throw a RuntimeError. Default is 0. :param cardinal: boolean used to define one of two algorithms used to assemble the bundle. When true the three input components are assumed to be in cardinal directions (x1=positive east, x2=positive north, and x3=positive up) AND in a fixed order of E,N,Z. Otherwise the Metadata fetched with the azimuth and dip keys are used for orientation. :param azimuth: defines the Metadata key used to fetch the azimuth angle used to define the orientation of each component Trace object. Default is 'azimuth' used by obspy. Note azimuth=hang in css3.0. Cannot be aliased - must be present in obspy Stats unless cardinal is true :param dip: defines the Metadata key used to fetch the vertical angle orientation of each data component. Vertical angle (vang in css3.0) is exactly the same as theta in spherical coordinates. Default is obspy 'dip' key. Cannot be aliased - must be defined in obspy Stats unless cardinal is true :raise: Can throw either an AssertionError or MsPASSrror(currently defaulted to pybind11's default RuntimeError. Error message can be obtained by calling the what method of RuntimeError). """ # First make sure we have exactly 3 components assert len(st) == 3, "Stream length must be EXACTLY 3 for 3-components" assert 0 <= master < 3, "master argument must be 0, 1, or 2" # if all traces are dead in a stream, it should be converted to a dead seismogram try: size = len(st) for i in range(len(st)): if st[i].dead_mspass: size -= 1 if size == 0: res = Seismogram() res.live = False return res except AttributeError: pass # Complicated logic here, but the point is to make sure the azimuth # attribute is set. The cardinal part is to override the test if # we can assume he components are ENZ if not cardinal: if (azimuth not in st[0].stats or azimuth not in st[1].stats or azimuth not in st[2].stats): raise RuntimeError("Stream2Seismogram: Required attribute " + azimuth + " must be in mdother list") if not cardinal: if dip not in st[0].stats or dip not in st[1].stats or dip not in st[ 2].stats: raise RuntimeError("Stream2Seismogram: Required attribute " + dip + " must be in mdother list") # Outer exception handler to handle range of possible errors in # converting each component. Note we pass an empty list for mdother # and aliases except the master bundle = [] for i in range(3): bundle.append(Trace2TimeSeries(st[i])) # The constructor we use below has frozen names hang for azimuth and # vang for what obspy calls dip. Copy to those names - should work # even if the hang and vang are the names although with some inefficiency # assume that would not be normal so avoid unnecessary code if cardinal: bundle[0].put(Keywords.channel_hang, 90.0) bundle[1].put(Keywords.channel_hang, 0.0) bundle[2].put(Keywords.channel_hang, 0.0) bundle[0].put(Keywords.channel_vang, 90.0) bundle[1].put(Keywords.channel_vang, 90.0) bundle[2].put(Keywords.channel_vang, 0.0) else: for i in range(3): hang = bundle[i].get_double(azimuth) bundle[i].put(Keywords.channel_hang, hang) vang = bundle[i].get_double(dip) bundle[i].put(Keywords.channel_vang, vang) # Assume now bundle contains all the pieces we need. This constructor # for _CoreSeismogram should then do the job # This may throw an exception, but we require the caller to handle it # All errors returned by this constructor currenlty leave the data INVALID # so handler should discard anything with an error dout = _CoreSeismogram(bundle, master) res = Seismogram(dout, "INVALID") res.live = True return res
def test_CoreSeismogram(): md = Metadata() md['delta'] = 0.01 md['starttime'] = 0.0 md['npts'] = 100 # test metadata constructor md['tmatrix'] = np.random.rand(3, 3) cseis = _CoreSeismogram(md, False) assert (cseis.transformation_matrix == md['tmatrix']).all() md['tmatrix'] = dmatrix(np.random.rand(3, 3)) cseis = _CoreSeismogram(md, False) assert (cseis.transformation_matrix == md['tmatrix']).all() md['tmatrix'] = np.random.rand(9) cseis = _CoreSeismogram(md, False) assert (cseis.transformation_matrix == md['tmatrix'].reshape(3, 3)).all() md['tmatrix'] = np.random.rand(1, 9) cseis = _CoreSeismogram(md, False) assert (cseis.transformation_matrix == md['tmatrix'].reshape(3, 3)).all() md['tmatrix'] = np.random.rand(9, 1) cseis = _CoreSeismogram(md, False) assert (cseis.transformation_matrix == md['tmatrix'].reshape(3, 3)).all() md['tmatrix'] = np.random.rand(3, 3).tolist() cseis = _CoreSeismogram(md, False) assert np.isclose(cseis.transformation_matrix, np.array(md['tmatrix']).reshape(3, 3)).all() md['tmatrix'] = np.random.rand(9).tolist() cseis = _CoreSeismogram(md, False) assert np.isclose(cseis.transformation_matrix, np.array(md['tmatrix']).reshape(3, 3)).all() # test whether the setter of transformation_matrix updates metadata correctly tm = np.random.rand(1, 9) cseis.transformation_matrix = tm assert (cseis.transformation_matrix == tm.reshape(3, 3)).all() assert np.isclose(cseis.transformation_matrix, np.array(cseis['tmatrix']).reshape(3, 3)).all() tm = np.random.rand(9).tolist() cseis.transformation_matrix = tm assert np.isclose(cseis.transformation_matrix, np.array(tm).reshape(3, 3)).all() assert np.isclose(cseis.transformation_matrix, np.array(cseis['tmatrix']).reshape(3, 3)).all() # test exceptions md['tmatrix'] = np.random.rand(4, 2) with pytest.raises(MsPASSError, match="should be a 3x3 matrix"): _CoreSeismogram(md, False) md['tmatrix'] = dmatrix(np.random.rand(2, 4)) with pytest.raises(MsPASSError, match="should be a 3x3 matrix"): _CoreSeismogram(md, False) md['tmatrix'] = 42 with pytest.raises(MsPASSError, match="not recognized"): _CoreSeismogram(md, False) md.erase('tmatrix') with pytest.raises(MsPASSError, match="Error trying to extract"): _CoreSeismogram(md, False) md['tmatrix'] = {4: 2} with pytest.raises(MsPASSError, match="type is not recognized"): _CoreSeismogram(md, False) md['tmatrix'] = np.random.rand(9).tolist() md['tmatrix'][3] = 'str' with pytest.raises(MsPASSError, match="should be float"): _CoreSeismogram(md, False) md['tmatrix'] = np.random.rand(3, 4).tolist() with pytest.raises(MsPASSError, match="should be a 3x3 list of list"): _CoreSeismogram(md, False) md['tmatrix'] = [1, 2, 3] with pytest.raises(MsPASSError, match="should be a 3x3 list of list"): _CoreSeismogram(md, False) md['tmatrix'] = np.random.rand(2, 2).tolist() with pytest.raises( MsPASSError, match="should be a list of 9 floats or a 3x3 list of list"): _CoreSeismogram(md, False) md['tmatrix'] = np.random.rand(3, 3).tolist() md['tmatrix'][1][1] = 'str' with pytest.raises(MsPASSError, match="should be float"): _CoreSeismogram(md, False)
def test_scale(): dts=_CoreTimeSeries(9) dir=setbasics(dts,9) d3c=_CoreSeismogram(5) setbasics(d3c,5) dts.data[0]=3.0 dts.data[1]=2.0 dts.data[2]=-4.0 dts.data[3]=1.0 dts.data[4]=-100.0 dts.data[5]=-1.0 dts.data[6]=5.0 dts.data[7]=1.0 dts.data[8]=-6.0 # MAD o=f above should be 2 # perf of 0.8 should be 4 # rms should be just over 10=10.010993957 print('Starting tests for time series data of amplitude functions') ampmad=MADAmplitude(dts) print('MAD amplitude estimate=',ampmad) assert(ampmad==3.0) amprms=RMSAmplitude(dts) print('RMS amplitude estimate=',amprms) assert(round(amprms,2)==100.46) amppeak=PeakAmplitude(dts) ampperf80=PerfAmplitude(dts,0.8) print('Peak amplitude=',amppeak) print('80% clip level amplitude=',ampperf80) assert(amppeak==100.0) assert(ampperf80==6.0) print('Starting comparable tests for 3c data') d3c.data[0,0]=3.0 d3c.data[0,1]=2.0 d3c.data[1,2]=-4.0 d3c.data[2,3]=1.0 d3c.data[0,4]=np.sqrt(2)*(100.0) d3c.data[1,4]=-np.sqrt(2)*(100.0) ampmad=MADAmplitude(d3c) print('MAD amplitude estimate=',ampmad) amprms=RMSAmplitude(d3c) print('RMS amplitude estimate=',amprms) amppeak=PeakAmplitude(d3c) ampperf60=PerfAmplitude(d3c,0.6) print('Peak amplitude=',amppeak) print('60% clip level amplitude=',ampperf60) assert(amppeak==200.0) assert(ampperf60==4.0) assert(ampmad==3.0) amptest=round(amprms,2) assert(amptest==89.48) print('Trying scaling functions for TimeSeries') # we need a deep copy here since scaling changes the data d2=TimeSeries(dts) amp=_scale(d2,ScalingMethod.Peak,1.0) print('Computed peak amplitude=',amp) print(d2.data) d2=TimeSeries(dts) amp=_scale(d2,ScalingMethod.Peak,10.0) print('Computed peak amplitude with peak set to 10=',amp) print(d2.data) assert(amp==100.0) assert(d2.data[4]==-10.0) print('verifying scale has modified and set calib correctly') calib=d2.get_double('calib') assert(calib==10.0) d2=TimeSeries(dts) d2.put('calib',6.0) print('test 2 with MAD metric and initial calib of 6') amp=_scale(d2,ScalingMethod.MAD,1.0) calib=d2.get_double('calib') print('New calib value set=',calib) assert(calib==18.0) print('Testing 3C scale functions') d=Seismogram(d3c) amp=_scale(d,ScalingMethod.Peak,1.0) print('Peak amplitude returned by scale funtion=',amp) calib=d.get_double('calib') print('Calib value retrieved (assumed inital 1.0)=',calib) print('Testing python scale function wrapper - first on a TimeSeries with defaults') d2=TimeSeries(dts) amp=scale(d2) print('peak amplitude returned =',amp[0]) assert(amp[0]==100.0) d=Seismogram(d3c) amp=scale(d) print('peak amplitude returned test Seismogram=',amp[0]) assert(amp[0]==200.0) print('starting tests of scale on ensembles') print('first test TimeSeriesEnemble with 5 scaled copies of same vector used earlier in this test') ens=TimeSeriesEnsemble() scls=[2.0,4.0,1.0,10.0,5.0] # note 4 s the median of this vector npts=dts.npts for i in range(5): d=TimeSeries(dts) for k in range(npts): d.data[k]*=scls[i] d.put('calib',1.0) ens.member.append(d) # work on a copy because scaling alters data in place enscpy=TimeSeriesEnsemble(ens) amps=scale(enscpy) print('returned amplitudes for members scaled individually') for i in range(5): print(amps[i]) assert(amps[i]==100.0*scls[i]) enscpy=TimeSeriesEnsemble(ens) amp=scale(enscpy,scale_by_section=True) print('average amplitude=',amp[0]) #assert(amp[0]==4.0) avgamp=amp[0] for i in range(5): calib=enscpy.member[i].get_double("calib") print('member number ',i,' calib is ',calib) assert(round(calib)==400.0) #print(enscpy.member[i].data) # similar test for SeismogramEnsemble npts=d3c.npts ens=SeismogramEnsemble() for i in range(5): d=Seismogram(d3c) for k in range(3): for j in range(npts): d.data[k,j]*=scls[i] d.put('calib',1.0) ens.member.append(d) print('Running comparable tests on SeismogramEnsemble') enscpy=SeismogramEnsemble(ens) amps=scale(enscpy) print('returned amplitudes for members scaled individually') for i in range(5): print(amps[i]) assert(round(amps[i])==round(200.0*scls[i])) print('Trying section scaling of same data') enscpy=SeismogramEnsemble(ens) amp=scale(enscpy,scale_by_section=True) print('average amplitude=',amp[0]) assert(round(amp[0])==800.0) avgamp=amp[0] for i in range(5): calib=enscpy.member[i].get_double("calib") print('member number ',i,' calib is ',calib) assert(round(calib)==800.0)