version  0.0.1
Defines the C++ API for MsPASS
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Protected Attributes | List of all members
mspass::seismic::CoreSeismogram Class Reference

Vector (three-component) seismogram data object. More...

#include <CoreSeismogram.h>

Inheritance diagram for mspass::seismic::CoreSeismogram:
mspass::seismic::BasicTimeSeries mspass::utility::Metadata mspass::utility::BasicMetadata mspass::seismic::Seismogram mspass::seismic::SeismogramWGaps

Public Member Functions

 CoreSeismogram ()
 
 CoreSeismogram (const size_t nsamples)
 
 CoreSeismogram (const std::vector< mspass::seismic::CoreTimeSeries > &ts, const unsigned int component_to_clone=0)
 
 CoreSeismogram (const mspass::utility::Metadata &md, const bool load_data=true)
 Construct from Metadata definition that includes data path.
 
 CoreSeismogram (const CoreSeismogram &)
 
void set_dt (const double sample_interval)
 Set the sample interval.
 
void set_npts (const size_t npts)
 Set the number of samples attribute for data.
 
void sync_npts ()
 Sync the number of samples attribute with actual data size.
 
void set_t0 (const double t0in)
 Set the data start time.
 
CoreSeismogramoperator= (const CoreSeismogram &)
 
CoreSeismogramoperator+= (const CoreSeismogram &d)
 Summation operator.
 
const CoreSeismogram operator+ (const CoreSeismogram &other) const
 
CoreSeismogramoperator*= (const double)
 
CoreSeismogramoperator-= (const CoreSeismogram &d)
 Subtraction operator.
 
const CoreSeismogram operator- (const CoreSeismogram &other) const
 
std::vector< doubleoperator[] (const int sample) const
 
std::vector< doubleoperator[] (const double time) const
 Overloaded version of operator[] for time.
 
virtual ~CoreSeismogram ()
 
void rotate_to_standard ()
 
void rotate (mspass::utility::SphericalCoordinate &sc)
 
void rotate (const double nu[3])
 
void rotate (const double phi)
 Rotate horizontals by a simple angle in degrees.
 
void transform (const double a[3][3])
 
void free_surface_transformation (const mspass::seismic::SlownessVector u, const double vp0, const double vs0)
 
mspass::utility::dmatrix get_transformation_matrix () const
 
bool set_transformation_matrix (const mspass::utility::dmatrix &A)
 Define the transformaton matrix.
 
bool set_transformation_matrix (const double a[3][3])
 Define the transformaton matrix with a C style 3x3 matrix.
 
bool set_transformation_matrix (pybind11::object a)
 Define the transformaton matrix with a python object.
 
bool cardinal () const
 
bool orthogonal () const
 
double endtime () const noexcept
 
- Public Member Functions inherited from mspass::seismic::BasicTimeSeries
 BasicTimeSeries ()
 
 BasicTimeSeries (const BasicTimeSeries &)
 
virtual ~BasicTimeSeries ()
 Virtual destructor.
 
double time (const int i) const
 
int sample_number (double t) const
 
double endtime () const noexcept
 
bool shifted () const
 
double get_t0shift () const
 
double time_reference () const
 
void force_t0_shift (const double t)
 Force a t0 shift value on data.
 
virtual void ator (const double tshift)
 
virtual void rtoa ()
 
virtual void shift (const double dt)
 
bool live () const
 
bool dead () const
 
void kill ()
 
void set_live ()
 
double dt () const
 
bool time_is_UTC () const
 
bool time_is_relative () const
 
TimeReferenceType timetype () const
 
double samprate () const
 
size_t npts () const
 
double t0 () const
 
std::vector< double > time_axis () const
 
void set_tref (const TimeReferenceType newtref)
 Force the time standard.
 
BasicTimeSeriesoperator= (const BasicTimeSeries &parent)
 

Public Attributes

mspass::utility::dmatrix u
 

Protected Attributes

bool components_are_orthogonal
 
bool components_are_cardinal
 
double tmatrix [3][3]
 
- Protected Attributes inherited from mspass::seismic::BasicTimeSeries
bool mlive
 
double mdt
 
double mt0
 
size_t nsamp
 
TimeReferenceType tref
 
bool t0shift_is_valid
 
double t0shift
 

Detailed Description

Vector (three-component) seismogram data object.

A three-component seismogram is a common concept in seismology. The concept used here is that a three-component seismogram is a time series with a 3-vector as the data at each time step. As a result the data are stored internally as a matrix with row defining the component number (C indexing 0,1,2) and the column defining the time variable. The object inherits common concepts of a time series through the BasicTimeSeries object. Auxiliary parameters are defined for the object through inheritance of a Metadata object.

Author
Gary L. Pavlis

Constructor & Destructor Documentation

◆ CoreSeismogram() [1/5]

mspass::seismic::CoreSeismogram::CoreSeismogram ( )

Default constructor.

Sets ns to zero and builds an empty data matrix. The live variable in BasicTimeSeries is also set false.

27 /* mlive and tref are set in BasicTimeSeries so we don't use putters for
28 them here. These three initialize Metadata properly for these attributes*/
29 this->set_dt(1.0);
30 this->set_t0(0.0);
31 this->set_npts(0);
34 for (int i = 0; i < 3; ++i)
35 for (int j = 0; j < 3; ++j)
36 if (i == j)
37 tmatrix[i][i] = 1.0;
38 else
39 tmatrix[i][j] = 0.0;
40}
BasicTimeSeries()
Definition BasicTimeSeries.cc:45
double tmatrix[3][3]
Definition CoreSeismogram.h:529
void set_dt(const double sample_interval)
Set the sample interval.
Definition CoreSeismogram.cc:1006
void set_t0(const double t0in)
Set the data start time.
Definition CoreSeismogram.cc:1022
bool components_are_orthogonal
Definition CoreSeismogram.h:512
void set_npts(const size_t npts)
Set the number of samples attribute for data.
Definition CoreSeismogram.cc:1039
bool components_are_cardinal
Definition CoreSeismogram.h:521
Metadata()
Definition Metadata.h:75
T get(const std::string key) const
Definition Metadata.h:445

References components_are_cardinal, components_are_orthogonal, mspass::utility::Metadata::get(), set_dt(), set_npts(), set_t0(), and tmatrix.

◆ CoreSeismogram() [2/5]

mspass::seismic::CoreSeismogram::CoreSeismogram ( const size_t  nsamples)

Simplest parameterized constructor.

Initializes data and sets aside memory for matrix of size 3xnsamples. The data matrix is not initialized and the object is marked as not live.

Parameters
nsamplesnumber of samples expected for holding data.
43 /* IMPORTANT: this constructor assumes BasicTimeSeries initializes the
44 equivalent of:
45 set_dt(1.0)
46 set_t0(0.0)
47 set_tref(TimeReferenceType::Relative)
48 this->kill() - i.e. marked dead
49 */
50 this->set_npts(
51 nsamples); // Assume this is an allocator of the 3xnsamples matrix
54 for (int i = 0; i < 3; ++i)
55 for (int j = 0; j < 3; ++j)
56 if (i == j)
57 tmatrix[i][i] = 1.0;
58 else
59 tmatrix[i][j] = 0.0;
60}

References components_are_cardinal, components_are_orthogonal, mspass::utility::Metadata::get(), set_npts(), and tmatrix.

◆ CoreSeismogram() [3/5]

mspass::seismic::CoreSeismogram::CoreSeismogram ( const std::vector< mspass::seismic::CoreTimeSeries > &  ts,
const unsigned int  component_to_clone = 0 
)

Construct a three component seismogram from three TimeSeries objects.

A three component seismogram is commonly assembled from individual single channel components. This constructor does the process taking reasonable care to deal with (potentially) irregular start and end times of the individual components. If the start and end times are all the same it uses a simple copy operation. Otherwise it runs a more complicated (read much slower) algorithm that handles the ragged start and stop times by adding a marked gap.

If start or end times are not constant the algorithm shortens the output to the latest start time and earliest end time respectively.

Note this constructor requires variables hang and vang, which are orientation angles defined in the CSS3.0 schema (NOT spherical coordinates by the way), by set for each component. This is used to construct the transformation matrix for the object that allows, for example, removing raw data orientation errors using rotate_to_standard. The constructor will throw an exception if any component does not have these attributes set in their Metadata area.

Exceptions
SeisppErrorexception can be throw for a variety of serious problems.
Parameters
tsvector of 3 TimeSeries objects to be used to assemble this Seismogram. Input vector order could be arbitrary because a transformation matrix is computed, but for efficiency standard order (E,N,Z) is advised.
component_to_clonethe auxiliary parameters (Metadata and BasicTimeSeries common parameters) from one of the components is cloned to assure common required parameters are copied to this object. This argument controls which of the three components passed through ts is used. Default is 0.

◆ CoreSeismogram() [4/5]

mspass::seismic::CoreSeismogram::CoreSeismogram ( const mspass::utility::Metadata md,
const bool  load_data = true 
)

Construct from Metadata definition that includes data path.

A Metadata object is sufficiently general that it can contain enough information to contruct an object from attributes contained in it. This constuctor uses that approach, with the actual loading of data being an option (on by default). In mspass this is constructor is used to load data with Metadata constructed from MongoDB and then using the path created from two parameters (dir and dfile used as in css3.0 wfdisc) to read data. The API is general but the implementation in mspass is very rigid. It blindly assumes the data being read are binary doubles in the right byte order and ordered in the native order for dmatrix (Fortran order). i.e. the constuctor does a raw fread of ns*3 doubles into the internal array used in the dmatrix implementation.

A second element of the Metadata that is special for MsPASS is the handling of the transformation matrix by this constructor. In MsPASS the transformation matrix is stored as a python object in MongoDB. This constructor aims to fetch that entity with the key 'tmatrix'. To be more robust and simpler to use with data not loaded from mongodb we default tmatrix to assume the data are in standard coordinates. That is, if the key tmatrix is not defined in Metadata passed as arg0, the constructor assumes it should set the transformation matrix to an identity. Use set_transformation_matrix if that assumption is wrong for your data.

Parameters
mdis the Metadata used for the construction.
load_dataif true (default) a file name is constructed from dir+"/"+dfile, the file is openned, fseek is called to foff, data are read with fread, and the file is closed. If false a dmatrix for u is still created of size 3xns, but the matrix is only initialized to all zeros.
Exceptions
Willthrow a MsPASSError if required metadata are missing.
93 : Metadata(md) {
94 string dfile, dir;
95 long foff;
96 FILE *fp;
97 double *inbuffer;
98
100 mlive = false;
101 try {
102 /* Names used are from mspass defintions as of Jan 2020.
103 We don't need to call the set methods for these attributes as they
104 would add the overhead of setting delta, startime, and npts to the
105 same value passed. */
106 this->mdt = this->get_double(SEISMICMD_dt);
107 this->mt0 = this->get_double(SEISMICMD_t0);
109 if (this->get_string(SEISMICMD_time_standard) == "UTC")
111 else {
113 /* For now we can't post an error because this is CoreSeismogram
114 so elog is not defined. For now let this error be silent as it
115 is harmless */
116 /*
117 this->elog.log_error("CoreSeismogram Metadata constructor",
118 SEISMICMD_time_standard+" attribute is not defined - set to Relative",
119 ErrorSeverity::Complaint);
120 */
121 }
122 }
123 if (this->time_is_relative()) {
124 /* It is not an error if a t0 shift is not defined and we are
125 in relative time. That is the norm for active source data. */
126 if (this->is_defined(SEISMICMD_t0_shift)) {
127 double t0shift = this->get_double(SEISMICMD_t0_shift);
128 this->force_t0_shift(t0shift);
129 }
130 }
131 /* This section is done specially to handle interaction with MongoDB.
132 We store tmatrix there as a python object so we use a get_any to fetch
133 it. Oct 22, 2021 added a bug fix to handle tmatrix not defined.
134 We will take a null (undefined) tmatrix stored in the database to
135 imply the data are cardinal and orthogonal (i.e. stardard geographic
136 coordinates in e,n,z order.)*/
137 if (this->is_defined("tmatrix")) {
139 boost::any_cast<py::object>(this->get_any("tmatrix")));
140 components_are_cardinal = this->tmatrix_is_cardinal();
143 else
144 components_are_orthogonal = false; // May be wrong but cost is tiny
145 } else {
146 /* this might not be needed but best be explicit*/
147 for (auto i = 0; i < 3; ++i)
148 for (auto j = 0; j < 3; ++j)
149 this->tmatrix[i][j] = 0.0;
150 for (auto i = 0; i < 3; ++i)
151 this->tmatrix[i][i] = 1.0;
154 }
155 /* We have to handle nsamp specially in the case when load_data
156 is false. To be consistent with TimeSeries we use a feature that
157 if the Metadata container does not define npts we default it.
158 In this case that means the default constructor for u and set
159 nsamp to 0 (via set_npts). */
160 if (md.is_defined(SEISMICMD_npts)) {
161 long int ns = md.get_long(SEISMICMD_npts);
162 this->set_npts(ns); /* note this is assumed to initialize u*/
163 } else {
164 this->set_npts(0);
165 }
166 /* Note previous code had an else clause to to with the
167 following conditional. It used to zero the u matrix.
168 The call to set_npts above will always do that so that would
169 have been redundant and was removed June 2022*/
170 if (load_data) {
171 dir = this->get_string(SEISMICMD_dir);
172 dfile = this->get_string(SEISMICMD_dfile);
173 foff = this->get_long(SEISMICMD_foff);
174 string fname = dir + "/" + dfile;
175 if ((fp = fopen(fname.c_str(), "r")) == NULL)
176 throw(MsPASSError(string("Open failure for file ") + fname,
177 ErrorSeverity::Invalid));
178 if (foff > 0)
179 fseek(fp, foff, SEEK_SET);
180 /* The older seispp code allowed byte swapping here. For
181 efficiency we don't support that here and assume can do a
182 raw fread from the file and get valid data. If support for
183 other types is needed this will need to be extended. Here
184 we just point fread at the internal u array. */
185 inbuffer = this->u.get_address(0, 0);
186 unsigned int nt = 3 * this->nsamp;
187 if (fread((void *)(inbuffer), sizeof(double), nt, fp) != nt) {
188 fclose(fp);
189 throw(MsPASSError(
190 string("CoreSeismogram constructor: fread error on file ") + fname,
191 ErrorSeverity::Invalid));
192 }
193 fclose(fp);
194 mlive = true;
195 }
196 } catch (MsPASSError &mpe) {
197 throw(mpe);
198 } catch (boost::bad_any_cast &be) {
199 throw(MsPASSError(
200 string("CoreSeismogram constructor: tmatrix type is not recognized"),
201 ErrorSeverity::Invalid));
202 } catch (...) {
203 throw;
204 };
205}
size_t nsamp
Definition BasicTimeSeries.h:255
bool mlive
Definition BasicTimeSeries.h:243
void force_t0_shift(const double t)
Force a t0 shift value on data.
Definition BasicTimeSeries.h:109
void set_tref(const TimeReferenceType newtref)
Force the time standard.
Definition BasicTimeSeries.h:233
double mdt
Definition BasicTimeSeries.h:247
double mt0
Definition BasicTimeSeries.h:251
bool set_transformation_matrix(const mspass::utility::dmatrix &A)
Define the transformaton matrix.
Definition CoreSeismogram.cc:775
mspass::utility::dmatrix u
Definition CoreSeismogram.h:52
bool is_defined(const std::string key) const noexcept
Definition Metadata.cc:63
long get_long(const std::string key) const
Definition Metadata.h:176
boost::any get_any(const std::string key) const
Definition Metadata.h:277
std::string get_string(const std::string key) const override
Definition Metadata.h:202
double get_double(const std::string key) const override
Definition Metadata.h:131
const std::string SEISMICMD_t0_shift("starttime_shift")
const std::string SEISMICMD_dfile("dfile")
const std::string SEISMICMD_foff("foff")
const std::string SEISMICMD_t0("starttime")
const std::string SEISMICMD_dt("delta")
const std::string SEISMICMD_time_standard("time_standard")
const std::string SEISMICMD_dir("dir")
const std::string SEISMICMD_npts("npts")

References components_are_cardinal, components_are_orthogonal, mspass::seismic::BasicTimeSeries::force_t0_shift(), mspass::utility::Metadata::get(), mspass::utility::Metadata::get_any(), mspass::utility::Metadata::get_double(), mspass::utility::Metadata::get_long(), mspass::utility::Metadata::get_string(), mspass::utility::Metadata::is_defined(), mspass::seismic::BasicTimeSeries::mdt, mspass::seismic::BasicTimeSeries::mlive, mspass::seismic::BasicTimeSeries::mt0, mspass::seismic::BasicTimeSeries::nsamp, mspass::seismic::Relative, mspass::seismic::SEISMICMD_dfile(), mspass::seismic::SEISMICMD_dir(), mspass::seismic::SEISMICMD_dt(), mspass::seismic::SEISMICMD_foff(), mspass::seismic::SEISMICMD_npts(), mspass::seismic::SEISMICMD_t0(), mspass::seismic::SEISMICMD_t0_shift(), mspass::seismic::SEISMICMD_time_standard(), set_npts(), set_transformation_matrix(), mspass::seismic::BasicTimeSeries::set_tref(), tmatrix, u, and mspass::seismic::UTC.

◆ CoreSeismogram() [5/5]

mspass::seismic::CoreSeismogram::CoreSeismogram ( const CoreSeismogram t3c)

Standard copy constructor.

63 : BasicTimeSeries(dynamic_cast<const BasicTimeSeries &>(t3c)),
64 Metadata(dynamic_cast<const Metadata &>(t3c)), u(t3c.u) {
65 int i, j;
66 components_are_orthogonal = t3c.components_are_orthogonal;
67 components_are_cardinal = t3c.components_are_cardinal;
68 for (i = 0; i < 3; ++i)
69 for (j = 0; j < 3; ++j)
70 tmatrix[i][j] = t3c.tmatrix[i][j];
71}

References components_are_cardinal, components_are_orthogonal, mspass::utility::Metadata::get(), and tmatrix.

◆ ~CoreSeismogram()

virtual mspass::seismic::CoreSeismogram::~CoreSeismogram ( )
inlinevirtual

Standard destructor.

303{};

Member Function Documentation

◆ cardinal()

bool mspass::seismic::CoreSeismogram::cardinal ( ) const
inline

Returns true of components are cardinal.

490{ return components_are_cardinal; };

References components_are_cardinal.

◆ endtime()

double mspass::seismic::CoreSeismogram::endtime ( ) const
inlinenoexcept

Returns the end time (time associated with last data sample) of this data object.

497 {
498 return (mt0 + mdt * static_cast<double>(u.columns() - 1));
499 };
size_t columns() const
Definition dmatrix.cc:216

References mspass::utility::dmatrix::columns(), mspass::seismic::BasicTimeSeries::mdt, mspass::seismic::BasicTimeSeries::mt0, and u.

◆ free_surface_transformation()

void mspass::seismic::CoreSeismogram::free_surface_transformation ( const mspass::seismic::SlownessVector  u,
const double  vp0,
const double  vs0 
)

Computes and applies the Kennett [1991] free surface transformation matrix.

Kennett [1991] gives the form for a free surface transformation operator that reduces to a nonorthogonal transformation matrix when the wavefield is not evanescent. On output x1 will be transverse, x2 will be SV (radial), and x3 will be longitudinal.

Parameters
uslowness vector off the incident wavefield
vp0Surface P wave velocity
vs0Surface S wave velocity.
707 {
708 if ((u.size()[1] <= 0) || dead())
709 return; // do nothing in these situations
710 double a02, b02, pslow, p2;
711 double qa, qb, vpz, vpr, vsr, vsz;
712 pslow = uvec.mag();
713 // silently do nothing if magnitude of the slowness vector is 0
714 // (vertical incidence)
715 if (pslow < DBL_EPSILON)
716 return;
717 // Can't handle evanescent waves with this operator
718 double vapparent = 1.0 / pslow;
719 if (vapparent < a0 || vapparent < b0) {
720 stringstream ss;
721 ss << "CoreSeismogram::free_surface_transformation method: illegal input"
722 << endl
723 << "Apparent velocity defined by input slowness vector=" << vapparent
724 << endl
725 << "Smaller than specified surface P velocity=" << a0
726 << " or S velocity=" << b0 << endl
727 << "That implies evanescent waves that violate the assumption of this "
728 "operator"
729 << endl;
730 throw MsPASSError(ss.str(), ErrorSeverity::Invalid);
731 }
732
733 // First the horizonal rotation
734 SphericalCoordinate scor;
735 // rotation angle is - azimuth to put x2 (north in standard coord)
736 // in radial direction
737 scor.phi = atan2(uvec.uy, uvec.ux);
738 scor.theta = 0.0;
739 scor.radius = 1.0;
740 // after this transformation x1=transverse horizontal
741 // x2=radial horizonal, and x3 is still vertical
742 this->rotate(scor);
743
744 a02 = a0 * a0;
745 b02 = b0 * b0;
746 p2 = pslow * pslow;
747 qa = sqrt((1.0 / a02) - p2);
748 qb = sqrt((1.0 / b02) - p2);
749 vpz = -(1.0 - 2.0 * b02 * p2) / (2.0 * a0 * qa);
750 vpr = pslow * b02 / a0;
751 vsr = (1.0 - 2.0 * b02 * p2) / (2.0 * b0 * qb);
752 vsz = pslow * b0;
753 /* Now construct the transformation matrix
754 This is different from Bostock's original code
755 in sign and order. Also note this transformation
756 is not scaled to have a unit matrix norm so amplitudes
757 after the transformation are distorted. rotate_to_standard,
758 however, should still restore original data within roundoff
759 error if called on the result. */
760 double fstran[3][3];
761 fstran[0][0] = 0.5;
762 fstran[0][1] = 0.0;
763 fstran[0][2] = 0.0;
764 fstran[1][0] = 0.0;
765 fstran[1][1] = vsr;
766 fstran[1][2] = vpr;
767 fstran[2][0] = 0.0;
768 fstran[2][1] = -vsz;
769 fstran[2][2] = -vpz;
770 this->transform(fstran);
771
774}
bool dead() const
Definition BasicTimeSeries.h:145
void rotate(mspass::utility::SphericalCoordinate &sc)
Definition CoreSeismogram.cc:524
void transform(const double a[3][3])
Definition CoreSeismogram.cc:653
std::vector< size_t > size() const
Return a vector with 2 elements giving the size.
Definition dmatrix.cc:207

References components_are_cardinal, components_are_orthogonal, mspass::seismic::BasicTimeSeries::dead(), mspass::utility::Metadata::get(), mspass::utility::SphericalCoordinate::phi, rotate(), mspass::utility::dmatrix::size(), transform(), and u.

◆ get_transformation_matrix()

mspass::utility::dmatrix mspass::seismic::CoreSeismogram::get_transformation_matrix ( ) const
inline

Return current transformation matrix.

The transformation matrix is maintained internally in this object. Transformations like rotations and the transform method can change make this matrix not an identity matrix. It should always be an identity matrix when the coordinates are cardinal (i.e. ENZ).

Returns
3x3 transformation matrix.
440 {
441 mspass::utility::dmatrix result(3, 3);
442 for (int i = 0; i < 3; ++i)
443 for (int j = 0; j < 3; ++j)
444 result(i, j) = tmatrix[i][j];
445 return result;
446 };
Lightweight, simple matrix object.
Definition dmatrix.h:104

References tmatrix.

◆ operator*=()

Multiply data by a scalar.

903 {
904 /* do nothing to empty data or data marked dead*/
905 if ((this->npts() == 0) || (this->dead()))
906 return (*this);
907 /* We can use this dscal blas function because dmatrix puts all the data
908 in a continguous block. Beware if there is am implementation change for
909 the matrix data*/
910 double *ptr = this->u.get_address(0, 0);
911 dscal(3 * this->npts(), scale, ptr, 1);
912 return (*this);
913}
size_t npts() const
Definition BasicTimeSeries.h:171

References mspass::seismic::BasicTimeSeries::dead(), mspass::seismic::BasicTimeSeries::npts(), and u.

◆ operator+()

Addition operator.

This operator is implemented in a standard way utilizing operator+=. For data with irregular start and end times that has an important consequence; the operator is not communative. i.e given x an y z=x+y will not yield the same result as z=y+x.

995 {
996 CoreSeismogram result(*this);
997 result += other;
998 return result;
999}
CoreSeismogram()
Definition CoreSeismogram.cc:26

References mspass::utility::Metadata::get().

◆ operator+=()

Summation operator.

Summing data from signals of irregular length requires handling potential mismatches in size and overlap. This behaves the way a += operator should logically behave in that situation. That is, because the lhs is where the sum is being accumulated, the size is always controlled by the left hand side of the operator. Any portions of the right hand side that are outside the t0 to endtime() of the left hand side are silently discarded. If the start time of the right hand side is greater than t0 or the endtime is less than endtime of the lhs there will be discontinuties in the sum there the ends of the rhs are inside the range of the lhs.

Parameters
dis other signal to add to this.
Exceptions
MsPASSErrorcan be thrown if lhs and rhs do not have matching time standards.
914 {
915 int i, iend, jend;
916 size_t j, i0, j0;
917 // Silently do nothing if d or lhs is marked dead
918 if (d.dead() || (this->dead()))
919 return (*this);
920 // Silently do nothing if d does not overlap with data to contain sum
921 if ((d.endtime() < mt0) || (d.mt0 > (this->endtime())))
922 return (*this);
923 if (d.tref != (this->tref))
924 throw MsPASSError("CoreSeismogram += operator cannot handle data with "
925 "inconsistent time base\n",
926 ErrorSeverity::Invalid);
927 /* this defines the range of left and right hand sides to be summed */
928 i = d.sample_number(this->mt0);
929 if (i < 0) {
930 j0 = this->sample_number(d.t0());
931 i0 = 0;
932 } else {
933 j0 = 0;
934 i0 = i;
935 }
936 iend = d.sample_number(this->endtime());
937 jend = this->sample_number(d.endtime());
938 if (iend >= (d.npts())) {
939 iend = d.npts() - 1;
940 }
941 if (jend >= this->npts()) {
942 jend = this->npts() - 1;
943 }
944 for (i = i0, j = j0; i <= iend && j <= jend; ++i, ++j) {
945 this->u(0, j) += d.u(0, i);
946 this->u(1, j) += d.u(1, i);
947 this->u(2, j) += d.u(2, i);
948 }
949 return (*this);
950}
int sample_number(double t) const
Definition BasicTimeSeries.h:72
double endtime() const noexcept
Definition CoreSeismogram.h:497

References mspass::seismic::BasicTimeSeries::dead(), endtime(), mspass::utility::Metadata::get(), mspass::seismic::BasicTimeSeries::mt0, mspass::seismic::BasicTimeSeries::npts(), mspass::seismic::BasicTimeSeries::sample_number(), mspass::seismic::BasicTimeSeries::t0(), mspass::seismic::BasicTimeSeries::tref, and u.

◆ operator-()

Subtraction operator.

This operator is implemented in a standard way utilizing operator-=. For data with irregular start and end times that has an important consequence; the operator is not communative. i.e given x an y z=x-y will not yield the same result as z=-(y-x).

1001 {
1002 CoreSeismogram result(*this);
1003 result -= other;
1004 return result;
1005}

References mspass::utility::Metadata::get().

◆ operator-=()

Subtraction operator.

Differencing data from signals of irregular length requires handling potential mismatches in size and overlap. This behaves the way a -= operator should logically behave in that situation. That is, because the lhs is where the sum is being accumulated, the size is always controlled by the left hand side of the operator. Any portions of the right hand side that are outside the t0 to endtime() of the left hand side are silently discarded. If the start time of the right hand side is greater than t0 or the endtime is less than endtime of the lhs there will be discontinuties in the sum there the ends of the rhs are inside the range of the lhs.

Parameters
dis other signal to subract from this.
Exceptions
MsPASSErrorcan be thrown if lhs and rhs do not have matching time standards.
955 {
956 int i, iend, jend;
957 size_t j, i0, j0;
958 // Sun's compiler complains about const objects without this.
959 CoreSeismogram &d = const_cast<CoreSeismogram &>(data);
960 // Silently do nothing if d is marked dead
961 if (!d.mlive)
962 return (*this);
963 // Silently do nothing if d does not overlap with data to contain sum
964 if ((d.endtime() < mt0) || (d.mt0 > (this->endtime())))
965 return (*this);
966 if (d.tref != (this->tref))
967 throw MsPASSError("CoreSeismogram += operator cannot handle data with "
968 "inconsistent time base\n",
969 ErrorSeverity::Invalid);
970 /* this defines the range of left and right hand sides to be summed */
971 i = d.sample_number(this->mt0);
972 if (i < 0) {
973 j0 = this->sample_number(d.t0());
974 i0 = 0;
975 } else {
976 j0 = 0;
977 i0 = i;
978 }
979 iend = d.sample_number(this->endtime());
980 jend = this->sample_number(d.endtime());
981 if (iend >= (d.npts())) {
982 iend = d.npts() - 1;
983 }
984 if (jend >= this->npts()) {
985 jend = this->npts() - 1;
986 }
987 for (i = i0, j = j0; i <= iend && j <= jend; ++i, ++j) {
988 this->u(0, j) -= d.u(0, i);
989 this->u(1, j) -= d.u(1, i);
990 this->u(2, j) -= d.u(2, i);
991 }
992 return (*this);
993}

References endtime(), mspass::utility::Metadata::get(), mspass::seismic::BasicTimeSeries::mlive, mspass::seismic::BasicTimeSeries::mt0, mspass::seismic::BasicTimeSeries::npts(), mspass::seismic::BasicTimeSeries::sample_number(), mspass::seismic::BasicTimeSeries::t0(), mspass::seismic::BasicTimeSeries::tref, and u.

◆ operator=()

Standard assignment operator.

888 {
889 if (this != &seisin) {
892 components_are_orthogonal = seisin.components_are_orthogonal;
893 components_are_cardinal = seisin.components_are_cardinal;
894 for (int i = 0; i < 3; ++i) {
895 for (int j = 0; j < 3; ++j) {
896 tmatrix[i][j] = seisin.tmatrix[i][j];
897 }
898 }
899 u = seisin.u;
900 }
901 return (*this);
902}
BasicTimeSeries & operator=(const BasicTimeSeries &parent)
Definition BasicTimeSeries.cc:63
Metadata & operator=(const Metadata &mdold)
Definition Metadata.cc:90

References components_are_cardinal, components_are_orthogonal, mspass::utility::Metadata::get(), mspass::seismic::BasicTimeSeries::operator=(), mspass::utility::Metadata::operator=(), tmatrix, and u.

◆ operator[]() [1/2]

Overloaded version of operator[] for time.

Sometimes it is useful to ask for data at a specified time without worrying about the time conversion. This simplifies that process. It is still subject to an exception if the the time requested is outside the data range.

Parameters
timeis the time of the requested sample
Returns
3 vector of data samples at requested time
Exceptions
MsPASSErrorwill be thrown if the time is outside the data range.
1097 {
1098 try {
1099 vector<double> result;
1100 int i = this->sample_number(t);
1101 /* could test for a negative i and i too large but we assume
1102 the dmatrix container will throw an exception if it resolves that way*/
1103 for (int k = 0; k < 3; ++k)
1104 result.push_back(this->u(k, i));
1105 return result;
1106 } catch (...) {
1107 throw;
1108 };
1109}

References mspass::utility::Metadata::get(), and mspass::seismic::BasicTimeSeries::sample_number().

◆ operator[]() [2/2]

Extract a sample from data vector.

A sample in this context means a three-vector at a requested sample index. Range checking is implicit because of the internal use of the dmatrix to store the samples of data. This operator is an alternative to extracting samples through indexing of the internal dmatrix u that holds the data.

Parameters
sampleis the sample number requested (must be in range or an exception will be thrown)
Exceptions
MsPASSErrorif the requested sample is outside the range of the data. Note this includes an implicit "outside" defined when the contents are marked dead. Note the code does this by catching an error thrown by dmatrix in this situation, printing the error message from the dmatrix object, and then throwing a new SeisppError with a shorter message.
Returns
std::vector containing a 3 vector of the samples at requested sample number
Parameters
sampleis the integer sample number of data desired.
1086 {
1087 try {
1088 vector<double> result;
1089 result.reserve(3);
1090 for (int k = 0; k < 3; ++k)
1091 result.push_back(this->u(k, i));
1092 return result;
1093 } catch (...) {
1094 throw;
1095 };
1096}

References mspass::utility::Metadata::get().

◆ orthogonal()

bool mspass::seismic::CoreSeismogram::orthogonal ( ) const
inline

Return true if the components are orthogonal.

492{ return components_are_orthogonal; };

References components_are_orthogonal.

◆ rotate() [1/3]

void mspass::seismic::CoreSeismogram::rotate ( const double  nu[3])

Rotate data using a P wave type coordinate definition.

In seismology the longitudinal motion direction of a P wave defines a direction in space. This method rotates the data into a coordinate system defined by a direction passed through the argument. The data are rotated such that x1 becomes the transverse component, x2 becomes radial, and x3 becomes longitudinal. In the special case for a vector pointing in the x3 direction the data are not altered.

This method effectively turns nu into a SphericalCoordinate object and calles the related rotate method that has a SphericalCoordinate object as an argument. The potential confusion of orientation is not as extreme here. After the transformation x3prime will point in the direction of nu, x2 will be in the x3-x3prime plane (rotation by theta) and orthogonal to x3prime, and x1 will be horizontal and perpendicular to x2prime and x3prime.

A VERY IMPORTANT thing to recognize about this tranformation is it will always yield a result relative to cardinal coordinates. i.e. if the data had been previously rotated or were not originally in ENZ form they will be first transformed to ENZ before actually performing this transformation. Use the transform or horizontal rotation method to

Parameters
nudefines direction of x3 direction (longitudinal) as a unit vector with three components.
593 {
594 if ((u.size()[1] <= 0) || this->dead())
595 return; // do nothing in these situations
596 SphericalCoordinate xsc = UnitVectorToSpherical(nu);
597 this->rotate(xsc);
598}

References mspass::utility::Metadata::get(), rotate(), mspass::utility::dmatrix::size(), and u.

◆ rotate() [2/3]

void mspass::seismic::CoreSeismogram::rotate ( const double  phi)

Rotate horizontals by a simple angle in degrees.

A common transformation in 3C processing is a rotation of the
horizontal components by an angle.  This leaves the vertical
(assumed here x3) unaltered.   This routine rotates the horizontals
by angle phi using with positive phi counterclockwise as in
polar coordinates and the azimuth angle of spherical coordinates.

Note this transformation is cummulative.  i.e. this transformation
is cumulative.  The internal transformation matrix will be updated.
This is a useful feature for things like incremental horizontal
rotation in rotational angle grid searches.

\param phi rotation angle around x3 axis in counterclockwise
  direction (in radians).
607 {
608 if ((u.size()[1] <= 0) || dead())
609 return; // do nothing in these situations
610 int i, j, k;
611 double a, b;
612 a = cos(phi);
613 b = sin(phi);
614 double tmnew[3][3];
615 tmnew[0][0] = a;
616 tmnew[1][0] = -b;
617 tmnew[2][0] = 0.0;
618 tmnew[0][1] = b;
619 tmnew[1][1] = a;
620 tmnew[2][1] = 0.0;
621 tmnew[0][2] = 0.0;
622 tmnew[1][2] = 0.0;
623 tmnew[2][2] = 1.0;
624
625 /* Now multiply the data by this transformation matrix.
626 Note trick in this i only goes to 2 because 3 component
627 is an identity.*/
628 double *work[2];
629 for (i = 0; i < 2; ++i)
630 work[i] = new double[nsamp];
631 for (i = 0; i < 2; ++i) {
632 dcopy(nsamp, u.get_address(0, 0), 3, work[i], 1);
633 dscal(nsamp, tmnew[i][0], work[i], 1);
634 daxpy(nsamp, tmnew[i][1], u.get_address(1, 0), 3, work[i], 1);
635 }
636 for (i = 0; i < 2; ++i)
637 dcopy(nsamp, work[i], 1, u.get_address(i, 0), 3);
638 double tm_tmp[3][3];
639 double prod;
640 for (i = 0; i < 3; ++i)
641 for (j = 0; j < 3; ++j) {
642 for (prod = 0.0, k = 0; k < 3; ++k)
643 prod += tmnew[i][k] * tmatrix[k][j];
644 tm_tmp[i][j] = prod;
645 }
646 for (i = 0; i < 3; ++i)
647 for (j = 0; j < 3; ++j)
648 tmatrix[i][j] = tm_tmp[i][j];
650 for (i = 0; i < 2; ++i)
651 delete[] work[i];
652}

References components_are_cardinal, mspass::seismic::BasicTimeSeries::dead(), mspass::utility::Metadata::get(), mspass::seismic::BasicTimeSeries::nsamp, mspass::utility::dmatrix::size(), tmatrix, and u.

◆ rotate() [3/3]

void mspass::seismic::CoreSeismogram::rotate ( mspass::utility::SphericalCoordinate sc)

Rotate data using a P wave type coordinate definition.

In seismology the longitudinal motion direction of a P wave defines a direction in space. This method rotates the data into a coordinate system defined by a direction passed through the argument. The data are rotated such that x1 becomes the transverse component, x2 becomes radial, and x3 becomes longitudinal. In the special case for a vector pointing in the x3 direction the data are not altered. The transformation matrix is effectively the matrix product of two coordinate rotations: (1) rotation around x3 by angle phi and (2) rotation around x1 by theta.

The sense of this transformation is confusing because of a difference in convention between spherical coordinates and standard earth coordinates. In particular, orientation on the earth uses a convention with x2 being the x2 axis and bearings are relative to that with a standard azimuth measured clockwise from north. Spherical coordinate angle phi (used here) is measured counterclockwise relative to the x1 axis, which is east in standard earth coordinates. This transformation is computed using a phi angle. To use this then to compute a transformation to standard ray coordinates with x2 pointing in the direction of wavefront advance, phi should be set to pi/2-azimuth which gives the phi angle needed to rotate x2 to radial. This is extremely confusing because in spherical coordinates it would be more intuitive to rotate x1 to radial, but this is NOT the convention used here. In general to use this feature the best way to avoid this confusion is to use the PMHalfSpaceModel procedure to compute a SphericalCoordinate object consistent with given propagation direction defined by a slowness vector. Alternatively, use the free_surface_transformation method defined below.

A VERY IMPORTANT thing to recognize about this tranformation is it will always yield a result relative to cardinal coordinates. i.e. if the data had been previously rotated or were not originally in ENZ form they will be first transformed to ENZ before actually performing this transformation. Use the transform or horizontal rotation method to create cummulative transformations.

Parameters
scdefines final x3 direction (longitudinal) in a spherical coordinate structure.
524 {
525 if ((u.size()[1] <= 0) || dead())
526 return; // do nothing in these situations
527
528 // Earlier version had a reset of the nsamp variable here - we need to trust
529 // that is correct here for efficiency. We the new API it would be hard
530 // to have that happen. without a serious blunder
531 int i;
532 double theta, phi; /* corrected angles after dealing with signs */
533 double a, b, c, d;
534
535 //
536 // Undo any previous transformations
537 //
538 this->rotate_to_standard();
539 if (xsc.theta == M_PI) {
540 // This will be left handed
541 tmatrix[2][2] = -1.0;
542 dscal(nsamp, -1.0, u.get_address(2, 0), 3);
543 return;
544 }
545
546 if (xsc.theta < 0.0) {
547 theta = -(xsc.theta);
548 phi = xsc.phi + M_PI;
549 if (phi > M_PI)
550 phi -= (2.0 * M_PI);
551 } else if (xsc.theta > M_PI) {
552 theta = xsc.theta - M_PI;
553 phi = xsc.phi + M_PI;
554 if (phi > M_PI)
555 phi -= (2.0 * M_PI);
556 } else {
557 theta = xsc.theta;
558 phi = xsc.phi;
559 }
560 /* Am using a formula here for azimuth with is pi/2 - phi*/
561 double azimuth = M_PI_2 - phi;
562 a = cos(azimuth);
563 b = sin(azimuth);
564 c = cos(theta);
565 d = sin(theta);
566
567 tmatrix[0][0] = a;
568 tmatrix[1][0] = b * c;
569 tmatrix[2][0] = b * d;
570 tmatrix[0][1] = -b;
571 tmatrix[1][1] = a * c;
572 tmatrix[2][1] = a * d;
573 tmatrix[0][2] = 0.0;
574 tmatrix[1][2] = -d;
575 tmatrix[2][2] = c;
576
577 /* Now multiply the data by this transformation matrix. */
578 double *work[3];
579 for (i = 0; i < 3; ++i)
580 work[i] = new double[nsamp];
581 for (i = 0; i < 3; ++i) {
582 dcopy(nsamp, u.get_address(0, 0), 3, work[i], 1);
583 dscal(nsamp, tmatrix[i][0], work[i], 1);
584 daxpy(nsamp, tmatrix[i][1], u.get_address(1, 0), 3, work[i], 1);
585 daxpy(nsamp, tmatrix[i][2], u.get_address(2, 0), 3, work[i], 1);
586 }
587 for (i = 0; i < 3; ++i)
588 dcopy(nsamp, work[i], 1, u.get_address(i, 0), 3);
590 for (i = 0; i < 3; ++i)
591 delete[] work[i];
592}
void rotate_to_standard()
Definition CoreSeismogram.cc:380

References components_are_cardinal, mspass::seismic::BasicTimeSeries::dead(), mspass::utility::Metadata::get(), mspass::seismic::BasicTimeSeries::nsamp, rotate_to_standard(), mspass::utility::dmatrix::size(), mspass::utility::SphericalCoordinate::theta, tmatrix, and u.

◆ rotate_to_standard()

void mspass::seismic::CoreSeismogram::rotate_to_standard ( )

Apply inverse transformation matrix to return data to cardinal direction components.

It is frequently necessary to make certain a set of three component data are oriented to the standard reference frame (EW, NS, Vertical). This function does this. For efficiency it checks the components_are_cardinal variable and does nothing if it is set true. Otherwise, it applies the inverse transformation and then sets this variable true. Note even if the current transformation matrix is not orthogonal it will be put back into cardinal coordinates.

Exceptions
SeisppErrorthrown if the an inversion of the transformation matrix is required and that matrix is singular. This can happen if the transformation matrix is incorrectly defined or the actual data are coplanar.
380 {
381 if ((u.size()[1] <= 0) || this->dead())
382 return; // do nothing in these situations
383 double *work[3];
384 int i, j;
386 return;
387 /* We assume nsamp is the number of samples = number of columns in u - we
388 don't check here for efficiency */
389 for (j = 0; j < 3; ++j)
390 work[j] = new double[nsamp];
392 //
393 // Use a daxpy algorithm. tmatrix stores the
394 // forward transformation used to get current
395 // Use the transpose to get back
396 //
397 for (i = 0; i < 3; ++i) {
398 // x has a stride of 3 because we store in fortran order in x
399 dcopy(nsamp, u.get_address(0, 0), 3, work[i], 1);
400 dscal(nsamp, tmatrix[0][i], work[i], 1);
401 daxpy(nsamp, tmatrix[1][i], u.get_address(1, 0), 3, work[i], 1);
402 daxpy(nsamp, tmatrix[2][i], u.get_address(2, 0), 3, work[i], 1);
403 }
404 for (i = 0; i < 3; ++i)
405 dcopy(nsamp, work[i], 1, u.get_address(i, 0), 3);
406 } else {
407 //
408 // Enter here only when the transformation matrix is
409 // not orthogonal. We have to construct a fortran
410 // order matrix a to use LINPACK routine in sunperf/perf
411 // This could be done with the matrix template library
412 // but the overhead ain't worth it
413 //
414 double a[9];
415 int ipivot[3];
416 int info;
417 a[0] = tmatrix[0][0];
418 a[1] = tmatrix[1][0];
419 a[2] = tmatrix[2][0];
420 a[3] = tmatrix[0][1];
421 a[4] = tmatrix[1][1];
422 a[5] = tmatrix[2][1];
423 a[6] = tmatrix[0][2];
424 a[7] = tmatrix[1][2];
425 a[8] = tmatrix[2][2];
426 // LAPACK routine with FORTRAN interface using pass by reference and
427 // pointers
428 int three(3);
429 dgetrf(three, three, a, three, ipivot, info);
430 if (info != 0) {
431 for (i = 0; i < 3; ++i)
432 delete[] work[i];
433 throw(MsPASSError(string("rotate_to_standard: LU factorization of "
434 "transformation matrix failed"),
435 ErrorSeverity::Invalid));
436 }
437 // inversion routine after factorization from lapack FORT$RAN interface
438 double awork[10]; // Larger than required but safety value small cost
439 int ldwork(10);
440 dgetri(three, a, three, ipivot, awork, ldwork, info);
441 // This is the openblas version
442 // info=LAPACKE_dgetri(LAPACK_COL_MAJOR,3,a,3,ipivot);
443 if (info != 0) {
444 for (i = 0; i < 3; ++i)
445 delete[] work[i];
446 throw(MsPASSError(string("rotate_to_standard: LU factorization "
447 "inversion of transformation matrix failed"),
448 ErrorSeverity::Invalid));
449 }
450
451 tmatrix[0][0] = a[0];
452 tmatrix[1][0] = a[1];
453 tmatrix[2][0] = a[2];
454 tmatrix[0][1] = a[3];
455 tmatrix[1][1] = a[4];
456 tmatrix[2][1] = a[5];
457 tmatrix[0][2] = a[6];
458 tmatrix[1][2] = a[7];
459 tmatrix[2][2] = a[8];
460 /* The inverse is now in tmatrix so we reverse the
461 rows and columms from above loop */
462
463 for (i = 0; i < 3; ++i) {
464 dcopy(nsamp, u.get_address(0, 0), 3, work[i], 1);
465 dscal(nsamp, tmatrix[i][0], work[i], 1);
466 daxpy(nsamp, tmatrix[i][1], u.get_address(1, 0), 3, work[i], 1);
467 daxpy(nsamp, tmatrix[i][2], u.get_address(2, 0), 3, work[i], 1);
468 }
469 for (i = 0; i < 3; ++i)
470 dcopy(nsamp, work[i], 1, u.get_address(i, 0), 3);
472 }
473 //
474 // Have to set the transformation matrix to an identity now
475 //
476 for (i = 0; i < 3; ++i)
477 for (j = 0; j < 3; ++j)
478 if (i == j)
479 tmatrix[i][i] = 1.0;
480 else
481 tmatrix[i][j] = 0.0;
482
484 for (i = 0; i < 3; ++i)
485 delete[] work[i];
486}

References components_are_cardinal, components_are_orthogonal, mspass::utility::Metadata::get(), mspass::seismic::BasicTimeSeries::nsamp, mspass::utility::dmatrix::size(), tmatrix, and u.

◆ set_dt()

void mspass::seismic::CoreSeismogram::set_dt ( const double  sample_interval)
virtual

Set the sample interval.

This method is complicated by the need to sync the changed value with Metadata. That is further complicated by the need to support aliases for the keys used to defined dt in Metadata. That is handled by first setting the internal dt value and then going through a fixed list of valid alias keys for dt. Any that exist are changed. If none were previously defined the unique name (see documentation) is added to Metadata.

Parameters
sample_intervalis the new data sample interval to be used.

Reimplemented from mspass::seismic::BasicTimeSeries.

1006 {
1007 this->BasicTimeSeries::set_dt(sample_interval);
1008 /* This is the unique name defined in the mspass schema - we always set it. */
1009 this->put(SEISMICMD_dt, sample_interval);
1010 /* these are hard coded aliases for sample_interval */
1011 std::set<string> aliases;
1012 std::set<string>::iterator aptr;
1013 /* Note these aren't set in keywords - aliases are flexible and this
1014 can allow another way to make these attribute names more flexible. */
1015 aliases.insert("dt");
1016 for (aptr = aliases.begin(); aptr != aliases.end(); ++aptr) {
1017 if (this->is_defined(*aptr)) {
1018 this->put(*aptr, sample_interval);
1019 }
1020 }
1021}
virtual void set_dt(const double sample_interval)
Set the sample interval.
Definition BasicTimeSeries.h:197

References mspass::utility::Metadata::get(), mspass::utility::Metadata::is_defined(), mspass::seismic::SEISMICMD_dt(), and mspass::seismic::BasicTimeSeries::set_dt().

◆ set_npts()

void mspass::seismic::CoreSeismogram::set_npts ( const size_t  npts)
virtual

Set the number of samples attribute for data.

This method is complicated by the need to sync the changed value with Metadata. That is further complicated by the need to support aliases for the keys used to defined npts in Metadata. That is handled by first setting the internal npts value (actually ns) and then going through a fixed list of valid alias keys for npts. Any that exist are changed. If none were previously defined the unique name (see documentation) is added to Metadata.

This attribute has an additional complication compared to other setter that are overrides from BasicTimeSeries. That is, the number of points define the data buffer size to hold the sample data. To guarantee the buffer size and the internal remain consistent this method clears any existing content of the dmatrix u and initializes the 3xnpts matrix to 0s. Note this means if one is using this to assemble a data object in pieces you MUST call this method before loading any data or it will be cleared and you will mysteriously find the data are all zeros.

Parameters
nptsis the new number of points to set.

Reimplemented from mspass::seismic::BasicTimeSeries.

1039 {
1041 /* This is the unique name - we always set it. The weird
1042 cast is necessary to avoid type mismatch with unsigned.
1043 We use the name defined in keywords.h which we can always assume
1044 matches the schema for the unique name*/
1045 this->put(SEISMICMD_npts, (long int)npts);
1046 /* these are hard coded aliases for sample_interval */
1047 std::set<string> aliases;
1048 std::set<string>::iterator aptr;
1049 aliases.insert("nsamp");
1050 aliases.insert("wfdisc.nsamp");
1051 for (aptr = aliases.begin(); aptr != aliases.end(); ++aptr) {
1052 if (this->is_defined(*aptr)) {
1053 this->put(*aptr, (long int)npts);
1054 }
1055 }
1056 /* this method has the further complication that npts sets the size of the
1057 data matrix. Here we resize the matrix and initialize it to 0s.*/
1058 if (npts == 0) {
1059 this->u = dmatrix();
1060 } else {
1061 this->u = dmatrix(3, npts);
1062 this->u.zero();
1063 }
1064}
virtual void set_npts(const size_t npts)
Set the number of samples attribute for data.
Definition BasicTimeSeries.h:209
void zero()
Definition dmatrix.cc:203

References mspass::utility::Metadata::get(), mspass::utility::Metadata::is_defined(), mspass::seismic::BasicTimeSeries::npts(), mspass::seismic::SEISMICMD_npts(), mspass::seismic::BasicTimeSeries::set_npts(), u, and mspass::utility::dmatrix::zero().

◆ set_t0()

void mspass::seismic::CoreSeismogram::set_t0 ( const double  t0in)
virtual

Set the data start time.

This method is complicated by the need to sync the changed value with Metadata. That is further complicated by the need to support aliases for the keys used to defined npts in Metadata. That is handled by first setting the internal t0 value and then going through a fixed list of valid alias keys for it. Any that exist are changed. If none were previously defined the unique name (see documentation) is added to Metadata.

This is a dangerous method to use on real data as it can mess up the time if not handled correctly. It should be used only when that sharp knife is needed such as in assembling data outside of constructors in a test program.

Parameters
t0inis the new data sample interval to be used.

Reimplemented from mspass::seismic::BasicTimeSeries.

1022 {
1024 /* This is the unique name - we always set it. Pulled from keywords.h
1025 which should match the schema. aliases are hard coded not defined as
1026 keywords */
1027 this->put(SEISMICMD_t0, t0in);
1028 /* these are hard coded aliases for sample_interval */
1029 std::set<string> aliases;
1030 std::set<string>::iterator aptr;
1031 aliases.insert("t0");
1032 aliases.insert("time");
1033 for (aptr = aliases.begin(); aptr != aliases.end(); ++aptr) {
1034 if (this->is_defined(*aptr)) {
1035 this->put(*aptr, t0in);
1036 }
1037 }
1038}
virtual void set_t0(const double t0in)
Set the data start time.
Definition BasicTimeSeries.h:221

References mspass::utility::Metadata::get(), mspass::utility::Metadata::is_defined(), mspass::seismic::SEISMICMD_t0(), and mspass::seismic::BasicTimeSeries::set_t0().

◆ set_transformation_matrix() [1/3]

bool mspass::seismic::CoreSeismogram::set_transformation_matrix ( const double  a[3][3])

Define the transformaton matrix with a C style 3x3 matrix.

Parameters
ais a C style 3x3 matrix.
Returns
true if the given transformation matrix is an identity meaning components_are_cardinal gets set true. false if the test for an identity matrix fails.
Exceptions
Willthrow a MsPASSError if the input matrix is not 3x3.
796 {
797 for (int i = 0; i < 3; ++i)
798 for (int j = 0; j < 3; ++j)
799 tmatrix[i][j] = a[i][j];
800 py::list tmatrix_l;
801 for (int i = 0; i < 3; ++i)
802 for (int j = 0; j < 3; ++j)
803 tmatrix_l.append(a[i][j]);
804 this->put_object(SEISMICMD_tmatrix, tmatrix_l);
805 bool cardinal;
806 cardinal = this->tmatrix_is_cardinal();
807 if (cardinal) {
810 } else {
812 /* Not necessarily true, but small overhead cost*/
814 }
816}
bool cardinal() const
Definition CoreSeismogram.h:490
const std::string SEISMICMD_tmatrix("tmatrix")

References cardinal(), components_are_cardinal, components_are_orthogonal, mspass::utility::Metadata::get(), mspass::seismic::SEISMICMD_tmatrix(), and tmatrix.

◆ set_transformation_matrix() [2/3]

bool mspass::seismic::CoreSeismogram::set_transformation_matrix ( const mspass::utility::dmatrix A)

Define the transformaton matrix.

Occasionally we need to set the transformation matrix manually. The type example is input with a format where the component directions are embedded. We use a dmatrix as it is more easily wrapped for python than the raw C 2D array which really doesn't translate well between the languages.

Parameters
Ais the 3X3 matrix copied to the internal transformation matrix array.
Returns
true if the given transformation matrix is an identity meaning components_are_cardinal gets set true. false if the test for an identity matrix fails.
Exceptions
Willthrow a MsPASSError if the input matrix is not 3x3.
775 {
776 for (int i = 0; i < 3; ++i)
777 for (int j = 0; j < 3; ++j)
778 tmatrix[i][j] = A(i, j);
779 py::list tmatrix_l;
780 for (int i = 0; i < 3; ++i)
781 for (int j = 0; j < 3; ++j)
782 tmatrix_l.append(A(i, j));
783 this->put_object(SEISMICMD_tmatrix, tmatrix_l);
784 bool cardinal;
785 cardinal = this->tmatrix_is_cardinal();
786 if (cardinal) {
789 } else {
791 /* Not necessarily true, but small overhead cost*/
793 }
795}

References cardinal(), components_are_cardinal, components_are_orthogonal, mspass::utility::Metadata::get(), mspass::seismic::SEISMICMD_tmatrix(), and tmatrix.

◆ set_transformation_matrix() [3/3]

bool mspass::seismic::CoreSeismogram::set_transformation_matrix ( pybind11::object  a)

Define the transformaton matrix with a python object.

Parameters
ais a python object of 9 elements with types of dmatrix, numpy array, or list.
Returns
true if the given transformation matrix is an identity meaning components_are_cardinal gets set true. false if the test for an identity matrix fails.
Exceptions
Willthrow a MsPASSError if the input type or dimension is not recognized.

◆ sync_npts()

void mspass::seismic::CoreSeismogram::sync_npts ( )

Sync the number of samples attribute with actual data size.

This method syncs the npts attribute with the actual size of the dmatrix u. It also syncs aliases in the same way as the set_npts method.

1065 {
1066 if (nsamp != this->u.columns()) {
1067 this->BasicTimeSeries::set_npts(this->u.columns());
1068 /* This is the unique name - we always set it. The weird
1069 cast is necessary to avoid type mismatch with unsigned.
1070 As above converted to keywords.h const string to make
1071 this easier to maintain*/
1072 this->put(SEISMICMD_npts, (long int)nsamp);
1073 /* these are hard coded aliases for sample_interval */
1074 std::set<string> aliases;
1075 std::set<string>::iterator aptr;
1076 aliases.insert("nsamp");
1077 aliases.insert("wfdisc.nsamp");
1078 for (aptr = aliases.begin(); aptr != aliases.end(); ++aptr) {
1079 if (this->is_defined(*aptr)) {
1080 this->put(*aptr, (long int)nsamp);
1081 }
1082 }
1083 }
1084}

References mspass::utility::dmatrix::columns(), mspass::utility::Metadata::get(), mspass::utility::Metadata::is_defined(), mspass::seismic::BasicTimeSeries::nsamp, mspass::seismic::SEISMICMD_npts(), mspass::seismic::BasicTimeSeries::set_npts(), and u.

◆ transform()

void mspass::seismic::CoreSeismogram::transform ( const double  a[3][3])

Applies an arbitrary transformation matrix to the data. i.e. after calling this method the data will have been multiplied by the matrix a and the transformation matrix will be updated. The later allows cascaded transformations to data.

Parameters
ais a C style 3x3 matrix.
653 {
654 if ((u.size()[1] <= 0) || dead())
655 return; // do nothing in these situations
656 /* Older version had this - we need to trust ns is already u.columns(). */
657 // size_t ns = u.size()[1];
658 size_t i, j, k;
659 double *work[3];
660 for (i = 0; i < 3; ++i)
661 work[i] = new double[nsamp];
662 for (i = 0; i < 3; ++i) {
663 dcopy(nsamp, u.get_address(0, 0), 3, work[i], 1);
664 dscal(nsamp, a[i][0], work[i], 1);
665 daxpy(nsamp, a[i][1], u.get_address(1, 0), 3, work[i], 1);
666 daxpy(nsamp, a[i][2], u.get_address(2, 0), 3, work[i], 1);
667 }
668 for (i = 0; i < 3; ++i)
669 dcopy(nsamp, work[i], 1, u.get_address(i, 0), 3);
670 for (i = 0; i < 3; ++i)
671 delete[] work[i];
672 /* Hand code this rather than use dmatrix or other library.
673 Probably dumb, but this is just a 3x3 system. This
674 is simply a multiply of a*tmatrix with result replacing
675 the internal tmatrix */
676 double tmnew[3][3];
677 double prod;
678 for (i = 0; i < 3; ++i)
679 for (j = 0; j < 3; ++j) {
680 for (prod = 0.0, k = 0; k < 3; ++k)
681 prod += a[i][k] * tmatrix[k][j];
682 tmnew[i][j] = prod;
683 }
684 for (i = 0; i < 3; ++i)
685 for (j = 0; j < 3; ++j)
686 tmatrix[i][j] = tmnew[i][j];
687 components_are_cardinal = this->tmatrix_is_cardinal();
688 /* Assume this method does not yield cartesian coordinate directions.*/
691}

References components_are_cardinal, components_are_orthogonal, mspass::seismic::BasicTimeSeries::dead(), mspass::utility::Metadata::get(), mspass::seismic::BasicTimeSeries::nsamp, mspass::utility::dmatrix::size(), tmatrix, and u.

Member Data Documentation

◆ components_are_cardinal

bool mspass::seismic::CoreSeismogram::components_are_cardinal
protected

Defines of the contents of the object are in Earth cardinal coordinates.

Cardinal means the cardinal directions at a point on the earth. That is, x1 is positive east, x2 is positive north, and x3 is positive up. Like the components_are_orthogonal variable the purpose of this variable is to simplify common tests for properties of a given data series.

◆ components_are_orthogonal

bool mspass::seismic::CoreSeismogram::components_are_orthogonal
protected

Defines if the contents of this object are components of an orthogonal basis.

Most raw 3c seismic data use orthogonal components, but this is not universal. Furthermore, some transformations (e.g. the free surface transformation operator) define transformations to basis sets that are not orthogonal. Because detecting orthogonality from a transformation is a nontrivial thing (rounding error is the complication) this is made a part of the object to simplify a number of algorithms.

◆ tmatrix

double mspass::seismic::CoreSeismogram::tmatrix[3][3]
protected

Transformation matrix.

This is a 3x3 transformation that defines how the data in this object is produced from cardinal coordinates. That is, if u is the contents of this object the data in cardinal directions can be produced by tmatrix^-1 * u.

◆ u

mspass::utility::dmatrix mspass::seismic::CoreSeismogram::u

Holds the actual data.

Matrix is 3xns. Thus the rows are the component number and columns define time position. Note there is a redundancy in these definitions that must be watched if you manipulate the contents of this matrix. That is, BasicTimeSeries defines ns, but the u matrix has it's own internal size definitions. Currently no tests are done to validate this consistency. All constructors handle this, but again because u is public be very careful in altering u.


The documentation for this class was generated from the following files: