GPLIB++
SeismicModel.cpp
Go to the documentation of this file.
1 #include "SeismicModel.h"
2 #include <algorithm>
3 #include <fstream>
4 #include <iostream>
5 #include <numeric>
6 #include <cassert>
7 
8 using namespace std;
9 
10 namespace gplib
11  {
12 
13  SeismicModel::SeismicModel(const int nlayers) :
14  SourceDepth(0.0), dt(0.0), npts(0)
15  {
16  Init(nlayers);
17  }
18 
20  {
21  }
22 
24  {
25  //when we use the copy constructor the vectors
26  //of the new object are empty so we can use a back_inserter
27  copy(source.PVelocity.begin(), source.PVelocity.end(), back_inserter(
28  this->PVelocity));
29  copy(source.SVelocity.begin(), source.SVelocity.end(), back_inserter(
30  this->SVelocity));
31  copy(source.Density.begin(), source.Density.end(), back_inserter(
32  this->Density));
33  copy(source.Thickness.begin(), source.Thickness.end(), back_inserter(
34  this->Thickness));
35  copy(source.Qp.begin(), source.Qp.end(), back_inserter(this->Qp));
36  copy(source.Qs.begin(), source.Qs.end(), back_inserter(this->Qs));
37  SourceDepth = source.SourceDepth;
38  dt = source.dt;
39  npts = source.npts;
40  }
41 
43  {
44  if (this == &source)
45  return *this;
46  const int nelements = source.PVelocity.size();
47  //for the regular copy operator we have to delete old data
48  //so we allocate new space and copy the elements
49  PVelocity.assign(nelements, 0);
50  SVelocity.assign(nelements, 0);
51  Density.assign(nelements, 0);
52  Thickness.assign(nelements, 0);
53  Qp.assign(nelements, 0);
54  Qs.assign(nelements, 0);
55 
56  copy(source.PVelocity.begin(), source.PVelocity.end(),
57  PVelocity.begin());
58  copy(source.SVelocity.begin(), source.SVelocity.end(),
59  SVelocity.begin());
60  copy(source.Density.begin(), source.Density.end(), Density.begin());
61  copy(source.Thickness.begin(), source.Thickness.end(),
62  Thickness.begin());
63  copy(source.Qp.begin(), source.Qp.end(), Qp.begin());
64  copy(source.Qs.begin(), source.Qs.end(), Qs.begin());
65  SourceDepth = source.SourceDepth;
66  dt = source.dt;
67  npts = source.npts;
68  return *this;
69  }
70 
71  void SeismicModel::Init(const int nlayers)
72  {
73  //with this function we can easily allocate
74  //elements for the different vectors
75  PVelocity.assign(nlayers, 0);
76  SVelocity.assign(nlayers, 0);
77  Density.assign(nlayers, 0);
78  Thickness.assign(nlayers, 0);
79  Qp.assign(nlayers, 0);
80  Qs.assign(nlayers, 0);
81  }
82  //! Returns true if elem1 and elem2 agree within tolarance
83  bool SeismicModel::FuzzComp(const double elem1, const double elem2,
84  const double tolerance)
85  {
86  return (std::abs(elem1 - elem2) < tolerance);
87  }
88 
89  int SeismicModel::FindLayer(const double depth)
90  {
91  //make sure the depth is positive
92  assert(depth > 0.0);
93  double currentbottom = 0;
94  size_t i = 0;
95  //we have to check that the bottom of the current layer
96  //is deeper then what we are looking for
97  //and that we don't look past the last index
98  while (depth > currentbottom && i < Thickness.size())
99  {
100  currentbottom += Thickness.at(i);
101  ++i;
102  }
103  //if we reach the end it means we are in the lower most
104  //halfspace and return the index of the last layer
105  return min(i, Thickness.size() - 1);
106  }
107 
108  double SeismicModel::MatchSlowness(const double slowness,
109  const tArrivalType mode)
110  {
111  double x = 0;
112  double currdepth = 0;
113  trealdata *velocity;
114  const int sourcelayer = FindLayer(SourceDepth) - 1;
115 
116  if (mode == DirectS)
117  velocity = &SVelocity;
118  else
119  velocity = &PVelocity;
120  for (int i = 0; i < sourcelayer; ++i)
121  {
122  x += Thickness.at(i) * tan(asin(slowness * velocity->at(i)));
123  currdepth += Thickness.at(i);
124  }
125  x += (SourceDepth - currdepth) * tan(asin(slowness * velocity->at(
126  sourcelayer)));
127  return x;
128  }
129 
131  const double sdepth, const double rdepth, const double p)
132  {
133  int sourceindex = FindLayer(sdepth);
134  int recindex = FindLayer(rdepth);
135  const double hdistance = MatchSlowness(p, mode);
136  double currdepth = accumulate(Thickness.begin(), Thickness.begin()
137  + recindex, 0.0);
138  trealdata *velocity;
139  if (mode == DirectS)
140  velocity = &SVelocity;
141  else
142  velocity = &PVelocity;
143  double t = p * hdistance;
144  double eta = sqrt(1 / pow(velocity->at(recindex), 2) - p * p);
145  t += (currdepth - rdepth) * eta;
146  for (int i = recindex; i < sourceindex; ++i)
147  {
148  currdepth += Thickness.at(i);
149  eta = sqrt(1 / pow(velocity->at(i), 2) - p * p);
150  t += eta * Thickness.at(i);
151  }
152  eta = sqrt(1 / pow(velocity->at(sourceindex), 2) - p * p);
153  t += (sdepth - currdepth) * eta;
154  return t;
155  }
156 
158  const double recdist)
159  {
160  const double tolerance = 0.001;
161  double angle = PI / 4.;
162  double distance = 0;
163  trealdata *velocity;
164  double p = 0;
165  double currdepth = 0;
166  int preclevel = 3;
167 
168  if (mode == DirectS)
169  velocity = &SVelocity;
170  else
171  velocity = &PVelocity;
172  while (!FuzzComp(recdist, distance, tolerance))
173  {
174  currdepth = 0;
175  p = sin(angle) / velocity->at(0);
176  distance = MatchSlowness(p, mode);
177  if (distance > recdist)
178  angle -= PI * pow(0.5, preclevel);
179  else
180  angle += PI * pow(0.5, preclevel);
181  preclevel++;
182  }
183  return CalcTravelTime(mode, SourceDepth, 0.0, p);
184  }
185 
186  void SeismicModel::PlotVelWithErrors(const std::string &filename)
187  {
188  bool haveErrors = false;
189  if (!SVelErrors.empty() && !ThickErrors.empty())
190  haveErrors = true;
191  ofstream outfile(filename.c_str());
192  double cumthick = 0;
193  const unsigned int size = Thickness.size();
194  for (unsigned int i = 0; i < size; ++i)
195  {
196  outfile << cumthick << " " << SVelocity.at(i);
197  if (haveErrors)
198  outfile << " " << ThickErrors.at(i) << " " << SVelErrors.at(i);
199  outfile << endl;
200  cumthick += Thickness.at(i);
201  outfile << cumthick << " " << SVelocity.at(i);
202  if (haveErrors)
203  outfile << " " << ThickErrors.at(i) << " " << SVelErrors.at(i);
204  outfile << endl;
205  }
206  }
207 
208  void SeismicModel::WritePlot(const std::string &filename)
209  {
210  ofstream outfile((filename + ".plot").c_str());
211  double cumthick = 0;
212  const unsigned int size = Thickness.size();
213  for (unsigned int i = 0; i < size; ++i)
214  {
215  outfile << cumthick << " " << SVelocity.at(i) << " "
216  << PVelocity.at(i) << " " << Density.at(i) << endl;
217  cumthick += Thickness.at(i);
218  outfile << cumthick << " " << SVelocity.at(i) << " "
219  << PVelocity.at(i) << " " << Density.at(i) << endl;
220  }
221  outfile << cumthick * 2.0 << " " << SVelocity.at(size - 1) << " "
222  << PVelocity.at(size - 1) << " " << Density.at(size - 1) << endl;
223  }
224  }
double CalcArrival(const tArrivalType mode, const double recdist)
void WritePlot(const std::string &filename)
Write out an ascii file for plotting with xmgrace etc.
int FindLayer(const double depth)
Returns the index of the layer that correponds to depth in km.
tArrivalType
Do we want to calculate the arrival of a direct S-Wave or a P-wave.
Definition: SeismicModel.h:21
The class SeismicModel is the base class for some of the model format for seismic codes...
Definition: SeismicModel.h:17
SeismicModel & operator=(const SeismicModel &source)
void Init(const int nlayers)
Init provides a convenient way to allocate memory in all structures for a given number of layers...
SeismicModel(const int nlayers=0)
void PlotVelWithErrors(const std::string &filename)
Write out an ascii file with error bars for plotting with xmgrace etc.
double CalcTravelTime(const tArrivalType mode, const double sdepth, const double rdepth, const double p)
const int size
Definition: perftest.cpp:14
double MatchSlowness(const double slowness, const tArrivalType mode)
Given a slowness in s/km and a wave type calculate the distance that matches this slowness...