version  0.0.1
Defines the C++ API for MsPASS
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. More...
 
 CoreSeismogram (const CoreSeismogram &)
 
void set_dt (const double sample_interval)
 Set the sample interval. More...
 
void set_npts (const size_t npts)
 Set the number of samples attribute for data. More...
 
void sync_npts ()
 Sync the number of samples attribute with actual data size. More...
 
void set_t0 (const double t0in)
 Set the data start time. More...
 
CoreSeismogramoperator= (const CoreSeismogram &)
 
CoreSeismogramoperator+= (const CoreSeismogram &d)
 Summation operator. More...
 
const CoreSeismogram operator+ (const CoreSeismogram &other) const
 
CoreSeismogramoperator*= (const double)
 
CoreSeismogramoperator-= (const CoreSeismogram &d)
 Subtraction operator. More...
 
const CoreSeismogram operator- (const CoreSeismogram &other) const
 
std::vector< double > operator[] (const int sample) const
 
std::vector< double > operator[] (const double time) const
 Overloaded version of operator[] for time. More...
 
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. More...
 
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. More...
 
bool set_transformation_matrix (const double a[3][3])
 Define the transformaton matrix with a C style 3x3 matrix. More...
 
bool set_transformation_matrix (pybind11::object a)
 Define the transformaton matrix with a python object. More...
 
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. More...
 
double time (const int i) const
 
int sample_number (double t) const
 
double endtime () const noexcept
 
bool shifted () const
 
double time_reference () const
 
void force_t0_shift (const double t)
 Force a t0 shift value on data. More...
 
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
 
void set_tref (const TimeReferenceType newtref)
 Force the time standard. More...
 
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.

29 {
30  /* mlive and tref are set in BasicTimeSeries so we don't use putters for
31  them here. These three initialize Metadata properly for these attributes*/
32  this->set_dt(1.0);
33  this->set_t0(0.0);
34  this->set_npts(0);
37  for(int i=0; i<3; ++i)
38  for(int j=0; j<3; ++j)
39  if(i==j)
40  tmatrix[i][i]=1.0;
41  else
42  tmatrix[i][j]=0.0;
43 }
BasicTimeSeries()
Definition: BasicTimeSeries.cc:42
double tmatrix[3][3]
Definition: CoreSeismogram.h:519
void set_dt(const double sample_interval)
Set the sample interval.
Definition: CoreSeismogram.cc:1028
void set_t0(const double t0in)
Set the data start time.
Definition: CoreSeismogram.cc:1047
bool components_are_orthogonal
Definition: CoreSeismogram.h:489
void set_npts(const size_t npts)
Set the number of samples attribute for data.
Definition: CoreSeismogram.cc:1067
bool components_are_cardinal
Definition: CoreSeismogram.h:511
Metadata()
Definition: Metadata.h:80

References components_are_cardinal, components_are_orthogonal, 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.
46 {
47  /* IMPORTANT: this constructor assumes BasicTimeSeries initializes the
48  equivalent of:
49  set_dt(1.0)
50  set_t0(0.0)
51  set_tref(TimeReferenceType::Relative)
52  this->kill() - i.e. marked dead
53  */
54  this->set_npts(nsamples); // Assume this is an allocator of the 3xnsamples matrix
57  for(int i=0; i<3; ++i)
58  for(int j=0; j<3; ++j)
59  if(i==j)
60  tmatrix[i][i]=1.0;
61  else
62  tmatrix[i][j]=0.0;
63 }

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

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

References components_are_cardinal, components_are_orthogonal, and tmatrix.

◆ ~CoreSeismogram()

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

Standard destructor.

301 {};

Member Function Documentation

◆ cardinal()

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

Returns true of components are cardinal.

479 {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.

487  {
488  return(mt0+mdt*static_cast<double>(u.columns()-1));
489  };
size_t columns() const
Definition: dmatrix.cc:232

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

References components_are_cardinal, components_are_orthogonal, mspass::seismic::BasicTimeSeries::dead(), mspass::seismic::SlownessVector::mag(), mspass::utility::SphericalCoordinate::phi, mspass::utility::SphericalCoordinate::radius, rotate(), mspass::utility::dmatrix::size(), mspass::utility::SphericalCoordinate::theta, transform(), u, mspass::seismic::SlownessVector::ux, and mspass::seismic::SlownessVector::uy.

◆ 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.
432  {
433  mspass::utility::dmatrix result(3,3);
434  for(int i=0;i<3;++i)
435  for(int j=0;j<3;++j) result(i,j)=tmatrix[i][j];
436  return result;
437  };
Lightweight, simple matrix object.
Definition: dmatrix.h:102

References tmatrix.

◆ operator*=()

CoreSeismogram & mspass::seismic::CoreSeismogram::operator*= ( const double  scale)

Multiply data by a scalar.

916 {
917  /* do nothing to empty data or data marked dead*/
918  if((this->npts()==0) || (this->dead())) return(*this);
919  /* We can use this dscal blas function because dmatrix puts all the data
920  in a continguous block. Beware if there is am implementation change for
921  the matrix data*/
922  double *ptr=this->u.get_address(0,0);
923  dscal(3*this->npts(),scale,ptr,1);
924  return(*this);
925 }
size_t npts() const
Definition: BasicTimeSeries.h:183

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

◆ operator+()

const CoreSeismogram mspass::seismic::CoreSeismogram::operator+ ( const CoreSeismogram other) const

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.

1017 {
1018  CoreSeismogram result(*this);
1019  result += other;
1020  return result;
1021 }
CoreSeismogram()
Definition: CoreSeismogram.cc:28

◆ operator+=()

CoreSeismogram & mspass::seismic::CoreSeismogram::operator+= ( const CoreSeismogram d)

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.
927 {
928  int i,iend,jend;
929  size_t j,i0,j0;
930  // Silently do nothing if d or lhs is marked dead
931  if( d.dead() || (this->dead()) ) return(*this);
932  // Silently do nothing if d does not overlap with data to contain sum
933  if( (d.endtime()<mt0)
934  || (d.mt0>(this->endtime())) ) return(*this);
935  if(d.tref!=(this->tref))
936  throw MsPASSError("CoreSeismogram += operator cannot handle data with inconsistent time base\n",
937  ErrorSeverity::Invalid);
938  /* this defines the range of left and right hand sides to be summed */
939  i=d.sample_number(this->mt0);
940  if(i<0)
941  {
942  j0=this->sample_number(d.t0());
943  i0=0;
944  }
945  else
946  {
947  j0=0;
948  i0=i;
949  }
950  iend=d.sample_number(this->endtime());
951  jend=this->sample_number(d.endtime());
952  if(iend>=(d.npts()))
953  {
954  iend=d.npts()-1;
955  }
956  if(jend>=this->npts())
957  {
958  jend=this->npts()-1;
959  }
960  for(i=i0,j=j0; i<=iend && j<=jend; ++i,++j)
961  {
962  this->u(0,j)+=d.u(0,i);
963  this->u(1,j)+=d.u(1,i);
964  this->u(2,j)+=d.u(2,i);
965  }
966  return(*this);
967 }
int sample_number(double t) const
Definition: BasicTimeSeries.h:74
double endtime() const noexcept
Definition: CoreSeismogram.h:486

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

◆ operator-()

const CoreSeismogram mspass::seismic::CoreSeismogram::operator- ( const CoreSeismogram other) const

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).

1023 {
1024  CoreSeismogram result(*this);
1025  result -= other;
1026  return result;
1027 }

◆ operator-=()

CoreSeismogram & mspass::seismic::CoreSeismogram::operator-= ( const CoreSeismogram d)

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.
973 {
974  int i,iend,jend;
975  size_t j,i0,j0;
976  // Sun's compiler complains about const objects without this.
977  CoreSeismogram& d=const_cast<CoreSeismogram&>(data);
978  // Silently do nothing if d is marked dead
979  if(!d.mlive) return(*this);
980  // Silently do nothing if d does not overlap with data to contain sum
981  if( (d.endtime()<mt0)
982  || (d.mt0>(this->endtime())) ) return(*this);
983  if(d.tref!=(this->tref))
984  throw MsPASSError("CoreSeismogram += operator cannot handle data with inconsistent time base\n",
985  ErrorSeverity::Invalid);
986  /* this defines the range of left and right hand sides to be summed */
987  i=d.sample_number(this->mt0);
988  if(i<0)
989  {
990  j0=this->sample_number(d.t0());
991  i0=0;
992  }
993  else
994  {
995  j0=0;
996  i0=i;
997  }
998  iend=d.sample_number(this->endtime());
999  jend=this->sample_number(d.endtime());
1000  if(iend>=(d.npts()))
1001  {
1002  iend=d.npts()-1;
1003  }
1004  if(jend>=this->npts())
1005  {
1006  jend=this->npts()-1;
1007  }
1008  for(i=i0,j=j0; i<=iend && j<=jend; ++i,++j)
1009  {
1010  this->u(0,j)-=d.u(0,i);
1011  this->u(1,j)-=d.u(1,i);
1012  this->u(2,j)-=d.u(2,i);
1013  }
1014  return(*this);
1015 }

References endtime(), 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=()

CoreSeismogram & mspass::seismic::CoreSeismogram::operator= ( const CoreSeismogram seisin)

Standard assignment operator.

897 {
898  if(this!=&seisin)
899  {
900  this->BasicTimeSeries::operator=(seisin);
901  this->Metadata::operator=(seisin);
902  components_are_orthogonal=seisin.components_are_orthogonal;
903  components_are_cardinal=seisin.components_are_cardinal;
904  for(int i=0; i<3; ++i)
905  {
906  for(int j=0; j<3; ++j)
907  {
908  tmatrix[i][j]=seisin.tmatrix[i][j];
909  }
910  }
911  u=seisin.u;
912  }
913  return(*this);
914 }
BasicTimeSeries & operator=(const BasicTimeSeries &parent)
Definition: BasicTimeSeries.cc:62
Metadata & operator=(const Metadata &mdold)
Definition: Metadata.cc:108

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

◆ operator[]() [1/2]

vector< double > mspass::seismic::CoreSeismogram::operator[] ( const double  time) const

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.
1134 {
1135  try {
1136  vector<double> result;
1137  int i=this->sample_number(t);
1138  /* could test for a negative i and i too large but we assume
1139  the dmatrix container will throw an exception if it resolves that way*/
1140  for(int k=0;k<3;++k)
1141  result.push_back(this->u(k,i));
1142  return result;
1143  }catch(...){throw;};
1144 }

References mspass::seismic::BasicTimeSeries::sample_number().

◆ operator[]() [2/2]

vector< double > mspass::seismic::CoreSeismogram::operator[] ( const int  sample) const

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.
1124 {
1125  try {
1126  vector<double> result;
1127  result.reserve(3);
1128  for(int k=0;k<3;++k)
1129  result.push_back(this->u(k,i));
1130  return result;
1131  }catch(...){throw;};
1132 }

◆ orthogonal()

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

Return true if the components are orthogonal.

481 {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.
616 {
617  if( (u.size()[1]<=0) || this->dead()) return; // do nothing in these situations
618  SphericalCoordinate xsc=UnitVectorToSpherical(nu);
619  this->rotate(xsc);
620 }

References 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).
630 {
631  if( (u.size()[1]<=0) || dead()) return; // do nothing in these situations
632  int i,j,k;
633  double a,b;
634  a=cos(phi);
635  b=sin(phi);
636  double tmnew[3][3];
637  tmnew[0][0] = a;
638  tmnew[1][0] = -b;
639  tmnew[2][0] = 0.0;
640  tmnew[0][1] = b;
641  tmnew[1][1] = a;
642  tmnew[2][1] = 0.0;
643  tmnew[0][2] = 0.0;
644  tmnew[1][2] = 0.0;
645  tmnew[2][2] = 1.0;
646 
647  /* Now multiply the data by this transformation matrix.
648  Note trick in this i only goes to 2 because 3 component
649  is an identity.*/
650  double *work[2];
651  for(i=0; i<2; ++i)work[i] = new double[nsamp];
652  for(i=0; i<2; ++i)
653  {
654  dcopy(nsamp,u.get_address(0,0),3,work[i],1);
655  dscal(nsamp,tmnew[i][0],work[i],1);
656  daxpy(nsamp,tmnew[i][1],u.get_address(1,0),3,work[i],1);
657  }
658  for(i=0; i<2; ++i) dcopy(nsamp,work[i],1,u.get_address(i,0),3);
659  double tm_tmp[3][3];
660  double prod;
661  for(i=0; i<3; ++i)
662  for(j=0; j<3; ++j)
663  {
664  for(prod=0.0,k=0; k<3; ++k)
665  prod+=tmnew[i][k]*tmatrix[k][j];
666  tm_tmp[i][j]=prod;
667  }
668  for(i=0; i<3; ++i)
669  for(j=0; j<3; ++j)tmatrix[i][j]=tm_tmp[i][j];
671  for(i=0; i<2; ++i) delete [] work[i];
672 }

References components_are_cardinal, mspass::seismic::BasicTimeSeries::dead(), 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.
545 {
546  if( (u.size()[1]<=0) || dead()) return; // do nothing in these situations
547 
548  //Earlier version had a reset of the nsamp variable here - we need to trust
549  //that is correct here for efficiency. We the new API it would be hard
550  //to have that happen. without a serious blunder
551  int i;
552  double theta, phi; /* corrected angles after dealing with signs */
553  double a,b,c,d;
554 
555  //
556  //Undo any previous transformations
557  //
558  this->rotate_to_standard();
559  if(xsc.theta == M_PI)
560  {
561  //This will be left handed
562  tmatrix[2][2] = -1.0;
563  dscal(nsamp,-1.0,u.get_address(2,0),3);
564  return;
565  }
566 
567  if(xsc.theta < 0.0)
568  {
569  theta = -(xsc.theta);
570  phi = xsc.phi + M_PI;
571  if(phi > M_PI) phi -= (2.0*M_PI);
572  }
573  else if(xsc.theta > M_PI)
574  {
575  theta = xsc.theta - M_PI;
576  phi = xsc.phi + M_PI;
577  if(phi > M_PI) phi -= (2.0*M_PI);
578  }
579  else
580  {
581  theta = xsc.theta;
582  phi = xsc.phi;
583  }
584  /* Am using a formula here for azimuth with is pi/2 - phi*/
585  double azimuth=M_PI_2-phi;
586  a = cos(azimuth);
587  b = sin(azimuth);
588  c = cos(theta);
589  d = sin(theta);
590 
591  tmatrix[0][0] = a;
592  tmatrix[1][0] = b*c;
593  tmatrix[2][0] = b*d;
594  tmatrix[0][1] = -b;
595  tmatrix[1][1] = a*c;
596  tmatrix[2][1] = a*d;
597  tmatrix[0][2] = 0.0;
598  tmatrix[1][2] = -d;
599  tmatrix[2][2] = c;
600 
601  /* Now multiply the data by this transformation matrix. */
602  double *work[3];
603  for(i=0; i<3; ++i)work[i] = new double[nsamp];
604  for(i=0; i<3; ++i)
605  {
606  dcopy(nsamp,u.get_address(0,0),3,work[i],1);
607  dscal(nsamp,tmatrix[i][0],work[i],1);
608  daxpy(nsamp,tmatrix[i][1],u.get_address(1,0),3,work[i],1);
609  daxpy(nsamp,tmatrix[i][2],u.get_address(2,0),3,work[i],1);
610  }
611  for(i=0; i<3; ++i) dcopy(nsamp,work[i],1,u.get_address(i,0),3);
613  for(i=0; i<3; ++i) delete [] work[i];
614 }
void rotate_to_standard()
Definition: CoreSeismogram.cc:400

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

References components_are_cardinal, components_are_orthogonal, 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.

1029 {
1030  this->BasicTimeSeries::set_dt(sample_interval);
1031  /* This is the unique name defined in the mspass schema - we always set it. */
1032  this->put(SEISMICMD_dt,sample_interval);
1033  /* these are hard coded aliases for sample_interval */
1034  std::set<string> aliases;
1035  std::set<string>::iterator aptr;
1036  /* Note these aren't set in keywords - aliases are flexible and this
1037  can allow another way to make these attribute names more flexible. */
1038  aliases.insert("dt");
1039  for(aptr=aliases.begin();aptr!=aliases.end();++aptr)
1040  {
1041  if(this->is_defined(*aptr))
1042  {
1043  this->put(*aptr,sample_interval);
1044  }
1045  }
1046 }
virtual void set_dt(const double sample_interval)
Set the sample interval.
Definition: BasicTimeSeries.h:198

References 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.

1068 {
1070  /* This is the unique name - we always set it. The weird
1071  cast is necessary to avoid type mismatch with unsigned.
1072  We use the name defined in keywords.h which we can always assume
1073  matches the schema for the unique name*/
1074  this->put(SEISMICMD_npts,(long int)npts);
1075  /* these are hard coded aliases for sample_interval */
1076  std::set<string> aliases;
1077  std::set<string>::iterator aptr;
1078  aliases.insert("nsamp");
1079  aliases.insert("wfdisc.nsamp");
1080  for(aptr=aliases.begin();aptr!=aliases.end();++aptr)
1081  {
1082  if(this->is_defined(*aptr))
1083  {
1084  this->put(*aptr,(long int)npts);
1085  }
1086  }
1087  /* this method has the further complication that npts sets the size of the
1088  data matrix. Here we resize the matrix and initialize it to 0s.*/
1089  if(npts==0)
1090  {
1091  this->u = dmatrix();
1092  }
1093  else
1094  {
1095  this->u=dmatrix(3,npts);
1096  this->u.zero();
1097  }
1098 }
virtual void set_npts(const size_t npts)
Set the number of samples attribute for data.
Definition: BasicTimeSeries.h:213
void zero()
Definition: dmatrix.cc:215

References 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.

1048 {
1049  this->BasicTimeSeries::set_t0(t0in);
1050  /* This is the unique name - we always set it. Pulled from keywords.h
1051  which should match the schema. aliases are hard coded not defined as
1052  keywords */
1053  this->put(SEISMICMD_t0,t0in);
1054  /* these are hard coded aliases for sample_interval */
1055  std::set<string> aliases;
1056  std::set<string>::iterator aptr;
1057  aliases.insert("t0");
1058  aliases.insert("time");
1059  for(aptr=aliases.begin();aptr!=aliases.end();++aptr)
1060  {
1061  if(this->is_defined(*aptr))
1062  {
1063  this->put(*aptr,t0in);
1064  }
1065  }
1066 }
virtual void set_t0(const double t0in)
Set the data start time.
Definition: BasicTimeSeries.h:228

References 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.
811 {
812  for(int i=0;i<3;++i)
813  for(int j=0;j<3;++j) tmatrix[i][j]=a[i][j];
814  py::list tmatrix_l;
815  for(int i=0;i<3;++i)
816  for(int j=0;j<3;++j) tmatrix_l.append(a[i][j]);
817  this->put_object(SEISMICMD_tmatrix, tmatrix_l);
818  bool cardinal;
819  cardinal=this->tmatrix_is_cardinal();
820  if(cardinal)
821  {
824  }
825  else
826  {
828  /* Not necessarily true, but small overhead cost*/
830  }
832 }
bool cardinal() const
Definition: CoreSeismogram.h:479
const std::string SEISMICMD_tmatrix("tmatrix")

References cardinal(), components_are_cardinal, components_are_orthogonal, 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.
788 {
789  for(int i=0;i<3;++i)
790  for(int j=0;j<3;++j) tmatrix[i][j]=A(i,j);
791  py::list tmatrix_l;
792  for(int i=0;i<3;++i)
793  for(int j=0;j<3;++j) tmatrix_l.append(A(i, j));
794  this->put_object(SEISMICMD_tmatrix, tmatrix_l);
795  bool cardinal;
796  cardinal=this->tmatrix_is_cardinal();
797  if(cardinal)
798  {
801  }
802  else
803  {
805  /* Not necessarily true, but small overhead cost*/
807  }
809 }

References cardinal(), components_are_cardinal, components_are_orthogonal, 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.

1100 {
1101  if(nsamp != this->u.columns()) {
1102  this->BasicTimeSeries::set_npts(this->u.columns());
1103  /* This is the unique name - we always set it. The weird
1104  cast is necessary to avoid type mismatch with unsigned.
1105  As above converted to keywords.h const string to make
1106  this easier to maintain*/
1107  this->put(SEISMICMD_npts,(long int)nsamp);
1108  /* these are hard coded aliases for sample_interval */
1109  std::set<string> aliases;
1110  std::set<string>::iterator aptr;
1111  aliases.insert("nsamp");
1112  aliases.insert("wfdisc.nsamp");
1113  for(aptr=aliases.begin();aptr!=aliases.end();++aptr)
1114  {
1115  if(this->is_defined(*aptr))
1116  {
1117  this->put(*aptr,(long int)nsamp);
1118  }
1119  }
1120  }
1121 }

References mspass::utility::dmatrix::columns(), 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.
674 {
675  if( (u.size()[1]<=0) || dead()) return; // do nothing in these situations
676  /* Older version had this - we need to trust ns is already u.columns(). */
677  //size_t ns = u.size()[1];
678  size_t i,j,k;
679  double *work[3];
680  for(i=0; i<3; ++i) work[i] = new double[nsamp];
681  for(i=0; i<3; ++i)
682  {
683  dcopy(nsamp,u.get_address(0,0),3,work[i],1);
684  dscal(nsamp,a[i][0],work[i],1);
685  daxpy(nsamp,a[i][1],u.get_address(1,0),3,work[i],1);
686  daxpy(nsamp,a[i][2],u.get_address(2,0),3,work[i],1);
687  }
688  for(i=0; i<3; ++i) dcopy(nsamp,work[i],1,u.get_address(i,0),3);
689  for(i=0; i<3; ++i) delete [] work[i];
690  /* Hand code this rather than use dmatrix or other library.
691  Probably dumb, but this is just a 3x3 system. This
692  is simply a multiply of a*tmatrix with result replacing
693  the internal tmatrix */
694  double tmnew[3][3];
695  double prod;
696  for(i=0; i<3; ++i)
697  for(j=0; j<3; ++j)
698  {
699  for(prod=0.0,k=0; k<3; ++k)
700  prod+=a[i][k]*tmatrix[k][j];
701  tmnew[i][j]=prod;
702  }
703  for(i=0; i<3; ++i)
704  for(j=0; j<3; ++j)tmatrix[i][j]=tmnew[i][j];
705  components_are_cardinal = this->tmatrix_is_cardinal();
706  /* Assume this method does not yield cartesian coordinate directions.*/
708 }

References components_are_cardinal, components_are_orthogonal, mspass::seismic::BasicTimeSeries::dead(), 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: