1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package edu.sc.seis.TauP;
29
30 import java.io.Serializable;
31 import java.util.Vector;
32
33 /***
34 * This class provides storage and methods for generating slowness-depth
35 * pairs.
36 *
37 * @version 1.1.3 Wed Jul 18 15:00:35 GMT 2001
38
39
40
41 * @author H. Philip Crotwell
42 *
43 */
44 public abstract class SlownessModel implements Serializable, Cloneable {
45
46 /*** True to enable debugging output. */
47 transient public boolean DEBUG = false;
48
49 /*** True to enable verbose output. */
50 transient public boolean verbose = false;
51
52 /*** Radius of the Earth in km, usually input from the velocity model. */
53 protected double radiusOfEarth = 6371.0;
54
55 /*** Velocity Model used to get slowness model. Usually set in
56 * createSlowness(). */
57 protected VelocityModel vMod;
58
59 /*** Stores the layer number for layers in the velocity model with
60 * a critical point at their top. These form the
61 * "branches" of slowness sampling.
62 * @see edu.sc.seis.TauP.CriticalDepth */
63 protected Vector criticalDepthVector = new Vector();
64
65 /*** Stores depth ranges that contains a high
66 * slowness zone for P. Stored as DepthRange objects, containing
67 * the top depth and bottom depth.
68 * @see DepthRange */
69 protected Vector highSlownessLayerDepthsP = new Vector();
70
71 /*** Stores depth ranges that contains a high
72 * slowness zone for S. Stored as DepthRange objects, containing
73 * the top depth and bottom depth.
74 * @see DepthRange */
75 protected Vector highSlownessLayerDepthsS = new Vector();
76
77 /*** Stores depth ranges that are fluid, ie S velocity is zero.
78 * Stored as DepthRange objects, containing
79 * the top depth and bottom depth.
80 * @see DepthRange */
81 protected Vector fluidLayerDepths = new Vector();
82
83 /*** Initial length of the slowness vectors. */
84 protected static int vectorLength = 256;
85
86 /*** Stores the final slowness-depth layers for P waves. Stored as
87 * SlownessLayer objects.
88 * @see edu.sc.seis.TauP.SlownessLayer */
89 protected Vector PLayers = new Vector(vectorLength);
90
91 /*** Stores the final slowness-depth layers for S waves. Stored as
92 * SlownessLayer objects. Note that SLayers and PLayers share the
93 * same SlownessLayer object within fluid layers, so changes made
94 * to one will affect the other.
95 * @see edu.sc.seis.TauP.SlownessLayer */
96 protected Vector SLayers = new Vector(vectorLength);
97
98 /*** Minimum difference between successive slowness samples. The
99 * default is 0.1 (km-sec/km or sec/rad for spherical, sec/km
100 * for flat models). This keeps the sampling from becoming too
101 * fine. For example, a strong negative S velocity gradient just
102 * above the CMB will cause the totally reflected ScS too have
103 * an extremely large range of distances, over a very small range
104 * of ray parameters. The distance check would otherwise
105 * force a very fine sampling of this region. However since in this
106 * case time and distance are likely to be very close to being
107 * linearly related, this sort of sampling is overkill. So we
108 * ignore the distance check if the ray parameter becomes smaller
109 * than minDeltaP. */
110 protected double minDeltaP = 0.1;
111
112 /*** Maximum difference between successive slowness samples. The
113 * default is 11.0 (km-sec/km or sec/rad for spherical, sec/km
114 * for flat models). See Buland and Chapman p1292 */
115 protected double maxDeltaP = 11.0;
116
117 /*** Maximum difference between successive depth samples,
118 * default is 115 km. See Buland and Chapman p1292*/
119 protected double maxDepthInterval = 115.0;
120
121 /*** Maximum difference between successive ranges, in radians. The
122 * default is 200 km / radiusOfEarth. See Buland and Chapman p1292.
123 * @see radiusOfEarth */
124 protected double maxRangeInterval = 200.0/radiusOfEarth;
125
126 protected double maxInterpError = .5;
127
128 /*** Should we allow J phases, S waves in the inner core? If true, then
129 * the slowness sampling for S will use the S velocity structure for
130 * the inner core. If false, then we will use the P velocity structure
131 * for both the inner and outer core for S waves as well as P waves.
132 * Disallowing inner core S phases reduces the number of slowness
133 * samples significantly due to the large geometrical spreading
134 * of S waves in the inner core. The default is false.
135 * @see minInnerCoreDepth */
136 protected boolean allowInnerCoreS = true;
137
138 /*** Tolerance for slownesses. If two slownesses are closer that this
139 * value, then we consider them to be identical. Basically this just
140 * provides some protection against numerical "chatter". */
141 protected double slownessTolerance = 1e-16;
142
143 /*** Just useful for calling methods that need to know whether to use P or
144 * S waves. */
145 public static final boolean PWAVE = true;
146
147 /*** Just useful for calling methods that need to know whether to use P or
148 * S waves. */
149 public static final boolean SWAVE = false;
150
151
152
153
154
155 public void setRadiusOfEarth(double radiusOfEarth) {
156 this.radiusOfEarth = radiusOfEarth;
157 }
158
159 public void setMinDeltaP(double minDeltaP) {
160 this.minDeltaP = minDeltaP;
161 }
162
163 public void setMaxDeltaP(double maxDeltaP) {
164 this.maxDeltaP = maxDeltaP;
165 }
166
167 public void setMaxDepthInterval(double maxDepthInterval) {
168 this.maxDepthInterval = maxDepthInterval;
169 }
170
171 /*** sets the maximum range interval for surface focus turning
172 * waves between slowness samples, input in degrees.
173 * */
174 public void setMaxRangeInterval(double maxRangeInterval) {
175 this.maxRangeInterval = maxRangeInterval * Math.PI / 180.0 ;
176 }
177
178 /*** sets the maximum value of the estimated error due to linear
179 * interpolation. Care should be taken not to set this too small
180 * as a very large number of samples may be required. Note also
181 * that this is only an estimate of the error, and thus the bound
182 * is by no means assured. */
183 public void setMaxInterpError(double maxInterpError) {
184 this.maxInterpError = maxInterpError;
185 }
186
187 public void setAllowInnerCoreS(boolean allowInnerCoreS) {
188 this.allowInnerCoreS = allowInnerCoreS;
189 }
190
191 public void setSlownessTolerance(double slownessTolerance) {
192 this.slownessTolerance = slownessTolerance;
193 }
194
195
196
197 public final double getRadiusOfEarth() {
198 return radiusOfEarth;
199 }
200
201 public final double getMinDeltaP() {
202 return minDeltaP;
203 }
204
205 public final double getMaxDeltaP() {
206 return maxDeltaP;
207 }
208
209 public final double getMaxDepthInterval() {
210 return maxDepthInterval;
211 }
212
213 /*** @returns the maximum range interval for surface focus turning
214 * waves between slowness samples output in degrees. */
215 public final double getMaxRangeInterval() {
216 return 180.0 * maxRangeInterval /Math.PI;
217 }
218
219 /*** gets the maximum value of the estimated error due to linear
220 * interpolation. Care should be taken not to set this too small
221 * as a very large number of samples may be required. Note also
222 * that this is only an estimate of the error, and thus the bound
223 * is by no means assured. */
224 public final double getMaxInterpError() {
225 return maxInterpError;
226 }
227
228 public final boolean isAllowInnerCoreS() {
229 return allowInnerCoreS;
230 }
231
232 public final double getSlownessTolerance() {
233 return slownessTolerance;
234 }
235
236 public final int getNumCriticalDepths() {
237 return criticalDepthVector.size();
238 }
239
240 public final CriticalDepth getCriticalDepth(int i) {
241 return (CriticalDepth)criticalDepthVector.elementAt(i);
242 }
243
244 public final int getNumLayers(boolean isPWave) {
245 if (isPWave) {
246 return PLayers.size();
247 } else {
248 return SLayers.size();
249 }
250 }
251
252 /*** @returns the minimum ray parameter that turns, but is not reflected,
253 * at or above the given depth. Normally this is the slowness sample
254 * at the given depth, but if the depth is within a high slowness zone,
255 * then it may be smaller.
256 */
257 public double getMinTurnRayParam(double depth, boolean isPWave)
258 throws NoSuchLayerException, SlownessModelException {
259 double minPSoFar = Double.MAX_VALUE;
260 SlownessLayer sLayer;
261 Vector layers;
262
263 if (isPWave) {
264 layers = PLayers;
265 } else {
266 layers = SLayers;
267 }
268
269 if (depthInHighSlowness(depth, Double.MAX_VALUE, isPWave)) {
270 for (int i=0;i<layers.size();i++) {
271 sLayer = getSlownessLayer(i, isPWave);
272 if (sLayer.getBotDepth() == depth) {
273 minPSoFar = Math.min(minPSoFar, sLayer.getBotP());
274 return minPSoFar;
275 } else if (sLayer.getBotDepth() > depth) {
276 minPSoFar = Math.min(minPSoFar,
277 sLayer.evaluateAt_bullen(depth,getRadiusOfEarth()));
278 return minPSoFar;
279 } else {
280 minPSoFar = Math.min(minPSoFar, sLayer.getBotP());
281 }
282 }
283 } else {
284 sLayer = getSlownessLayer(layerNumberAbove(depth, isPWave), isPWave);
285 if (depth == sLayer.getBotDepth()) {
286 minPSoFar = sLayer.getBotP();
287 } else {
288 minPSoFar = sLayer.evaluateAt_bullen(depth,getRadiusOfEarth());
289 }
290 }
291 return minPSoFar;
292 }
293
294 /*** @returns the minimum ray parameter that turns or is reflected
295 * at or above the given depth. Normally this is the slowness sample
296 * at the given depth, but if the depth is within a high slowness zone,
297 * then it may be smaller. Also, at first order discontinuities, there
298 * may be many slowness samples at the same depth.
299 */
300 public double getMinRayParam(double depth, boolean isPWave)
301 throws NoSuchLayerException, SlownessModelException {
302 double minPSoFar = getMinTurnRayParam(depth, isPWave);
303 int i=layerNumberAbove(depth, isPWave);
304 int j=layerNumberBelow(depth, isPWave);
305 SlownessLayer sLayerAbove = getSlownessLayer(i, isPWave);
306 SlownessLayer sLayerBelow = getSlownessLayer(j, isPWave);
307
308 if (sLayerAbove.getBotDepth() == depth) {
309 minPSoFar = Math.min(Math.min(minPSoFar, sLayerAbove.getBotP()), sLayerBelow.getTopP());
310 }
311 return minPSoFar;
312 }
313
314 /*** @returns the DepthRange objects for all high slowness zones
315 * within the slowness model. */
316 public DepthRange[] getHighSlowness(boolean isPWave) {
317 Vector highSlownessLayerDepths;
318 if (isPWave) {
319 highSlownessLayerDepths = highSlownessLayerDepthsP;
320 } else {
321 highSlownessLayerDepths = highSlownessLayerDepthsS;
322 }
323
324 DepthRange[] hsz = new DepthRange[highSlownessLayerDepths.size()];
325 for (int i=0; i< highSlownessLayerDepths.size();i++) {
326 hsz[i] = (DepthRange)(
327 ((DepthRange)highSlownessLayerDepths.elementAt(i)).clone());
328 }
329 return hsz;
330 }
331
332 /*** @returns a clone of the requested waveType slowness layer. Note that
333 * as this is a clone, no changes made to the layer will be
334 * incorporated into the slowness model. */
335 public SlownessLayer getSlownessLayerClone(int layerNum, boolean isPWave) {
336 if (isPWave) {
337 return (SlownessLayer)((SlownessLayer)PLayers.elementAt(layerNum)).clone();
338 } else {
339 return (SlownessLayer)((SlownessLayer)SLayers.elementAt(layerNum)).clone();
340 }
341 }
342
343 /*** Returns the SlownessLayer of the requested waveType. This is NOT a
344 * clone and any changes will possibly corrupt the SlownessModel.
345 */
346 protected SlownessLayer getSlownessLayer(int layerNum, boolean isPWave) {
347 if (isPWave) {
348 return (SlownessLayer)PLayers.elementAt(layerNum);
349 } else {
350 return (SlownessLayer)SLayers.elementAt(layerNum);
351 }
352 }
353
354
355
356 public abstract double toSlowness(double velocity, double depth) throws SlownessModelException;
357
358 public abstract double toVelocity(double slowness, double depth) throws SlownessModelException;
359
360 public abstract TimeDist layerTimeDist(double rayParam, int layerNum,
361 boolean isPWave) throws SlownessModelException;
362
363 public abstract SlownessLayer toSlownessLayer(VelocityLayer vLayer, boolean isPWave) throws SlownessModelException;
364
365 public abstract double interpolate(double p, double topVelocity,
366 double topDepth, double slope) throws SlownessModelException;
367
368
369
370 /*** generate approximate distance, in radians, for a ray from a surface
371 * source that turns at the bottom of the given slowness layer.
372 *
373 * @exception NoSuchLayerException occurs if no layer in the
374 * velocity model contains the given depth.
375 * @exception SlownessModelException occurs if getNumLayers() == 0 as
376 * we cannot compute a distance without a
377 * layer.
378 */
379 public TimeDist approxDistance(int slownessTurnLayer, double p, boolean isPWave)
380 throws NoSuchLayerException,
381 SlownessModelException
382 {
383
384
385
386
387
388 if (slownessTurnLayer>=getNumLayers(isPWave)) {
389 throw new SlownessModelException(
390 "Can't calculate a distance when "+
391 "slownessTurnLayer >= getNumLayers("+isPWave+")\n"+
392 " slownessTurnLayer="+slownessTurnLayer+
393 " getNumLayers()="+getNumLayers(isPWave));
394 }
395 if (p < 0.0) {
396 throw new SlownessModelException(
397 "approxDistance: Ray parameter is negative!!!"+p+
398 " slownessTurnLayer="+slownessTurnLayer);
399 }
400
401
402
403
404
405
406 TimeDist td = new TimeDist(p);
407 TimeDist layerTD;
408
409 for (int layerNum=0;layerNum<=slownessTurnLayer;layerNum++) {
410 td.add( layerTimeDist(p, layerNum, isPWave));
411 }
412
413
414
415 td.dist *= 2.0;
416 td.time *= 2.0;
417 return td;
418 }
419
420 /*** Determines if the given depth and corresponding slowness
421 * is contained within a high
422 * slowness zone. Whether the high slowness zone includes its upper
423 * boundary and its lower boundaries depends upon the ray parameter.
424 * The slowness at the depth is needed because if depth happens to
425 * correspond to a discontinuity that marks the bottom of the
426 * high slowness zone but the ray is actually a total reflection
427 * then it is not part of the high slowness zone.
428 * Calls depthInHighSlowness(double, double, DepthRange).
429 * @see depthInHighSlowness. */
430 public boolean depthInHighSlowness(double depth, double rayParam, boolean isPWave) {
431 DepthRange highSZoneDepth = new DepthRange();
432 return depthInHighSlowness(depth, rayParam, highSZoneDepth, isPWave);
433 }
434
435 /*** Determines if the given depth and corresponding slowness
436 * is contained within a high
437 * slowness zone. Whether the high slowness zone includes its upper
438 * boundary and its lower boundaries depends upon the ray parameter.
439 * The slowness at the depth is needed because if depth happens to
440 * correspond to a discontinuity that marks the bottom of the
441 * high slowness zone but the ray is actually a total reflection
442 * then it is not part of the high slowness zone.
443 * The ray parameter that delimits the zone, ie it can turn at the
444 * top and the bottom, is in the zone at the top, but out of the
445 * zone at the bottom.
446 * */
447 public boolean depthInHighSlowness(double depth, double rayParam,
448 DepthRange highSZoneDepth, boolean isPWave) {
449 DepthRange tempRange;
450 Vector highSlownessLayerDepths;
451 if (isPWave) {
452 highSlownessLayerDepths = highSlownessLayerDepthsP;
453 } else {
454 highSlownessLayerDepths = highSlownessLayerDepthsS;
455 }
456
457 for (int i=0;i<highSlownessLayerDepths.size();i++) {
458 tempRange = (DepthRange)highSlownessLayerDepths.elementAt(i);
459 if (tempRange.topDepth <= depth && depth <= tempRange.botDepth) {
460 highSZoneDepth.topDepth = tempRange.topDepth;
461 highSZoneDepth.botDepth = tempRange.botDepth;
462 highSZoneDepth.rayParam = tempRange.rayParam;
463 if (rayParam > tempRange.rayParam || (
464 rayParam == tempRange.rayParam &&
465 depth == tempRange.topDepth)) {
466 return true;
467 }
468 }
469 }
470 return false;
471 }
472
473 /*** Determines if the given depth is contained within a fluid
474 * zone. The fluid zone includes its upper
475 * boundary but not its lower boundary. Calls
476 * depthInFluid(double, DepthRange).
477 * @see depthInFluid(double, DepthRange). */
478 public boolean depthInFluid(double depth) {
479 DepthRange fluidZoneDepth = new DepthRange();
480 return depthInFluid(depth, fluidZoneDepth);
481 }
482
483 /*** Determines if the given depth is contained within a
484 * fluid zone. The fluid zone includes its upper
485 * boundary but not its lower boundary. The top and bottom
486 * of the fluid zone are returned in DepthRange.
487 */
488 public boolean depthInFluid(double depth, DepthRange fluidZoneDepth) {
489 DepthRange tempRange;
490
491 for (int i=0;i<fluidLayerDepths.size();i++) {
492 tempRange = (DepthRange)fluidLayerDepths.elementAt(i);
493 if (tempRange.topDepth <= depth && depth < tempRange.botDepth) {
494 fluidZoneDepth.topDepth = tempRange.topDepth;
495 fluidZoneDepth.botDepth = tempRange.botDepth;
496 return true;
497 }
498 }
499 return false;
500 }
501
502
503
504
505
506
507
508
509
510
511 public SplitLayerInfo splitLayer(double depth, boolean isPWave)
512 throws SlownessModelException, NoSuchLayerException {
513 Vector layers, otherLayers;
514 if (isPWave) {
515 layers = PLayers;
516 otherLayers = SLayers;
517 } else {
518 layers = SLayers;
519 otherLayers = PLayers;
520 }
521 boolean otherWaveType = ! isPWave;
522 boolean changeMade = false;
523
524 int layerNum = layerNumberAbove(depth, isPWave);
525 SlownessLayer sLayer = getSlownessLayer(layerNum, isPWave);
526
527 if (sLayer.getTopDepth()==depth || sLayer.getBotDepth()==depth) {
528
529
530 return new SplitLayerInfo(false, false, 0.0);
531 } else if (Math.abs(sLayer.getTopDepth() - depth) < 0.000001) {
532
533 sLayer.setTopDepth(depth);
534 sLayer = getSlownessLayer(layerNum-1, isPWave);
535 sLayer.setBotDepth(depth);
536 return new SplitLayerInfo(false, true, sLayer.getBotP());
537 } else if (Math.abs(depth - sLayer.getBotDepth()) < 0.000001) {
538
539 sLayer.setBotDepth(depth);
540 sLayer = getSlownessLayer(layerNum+1, isPWave);
541 sLayer.setTopDepth(depth);
542 return new SplitLayerInfo(false, true, sLayer.getTopP());
543 } else {
544 double p = sLayer.evaluateAt_bullen(depth, radiusOfEarth);
545 int index = -1;
546 int otherIndex = -1;
547 SlownessLayer topLayer, botLayer;
548
549 topLayer = (SlownessLayer)sLayer.clone();
550 topLayer.setBotP(p);
551 topLayer.setBotDepth(depth);
552
553 botLayer = (SlownessLayer)sLayer.clone();
554 botLayer.setTopP(p);
555 botLayer.setTopDepth(topLayer.getBotDepth());
556 layers.removeElementAt(layerNum);
557 layers.insertElementAt(botLayer, layerNum);
558 layers.insertElementAt(topLayer, layerNum);
559
560 for (int i=0; i<getNumCriticalDepths(); i++) {
561 CriticalDepth cd = getCriticalDepth(i);
562 if (cd.getLayerNum(isPWave) > layerNum) {
563 cd.setLayerNum(cd.getLayerNum(isPWave)+1, isPWave);
564 }
565 }
566
567
568
569 otherIndex = otherLayers.indexOf(sLayer);
570 if (otherIndex != -1) {
571 otherLayers.removeElementAt(otherIndex);
572 otherLayers.insertElementAt(botLayer, otherIndex);
573 otherLayers.insertElementAt(topLayer, otherIndex);
574 }
575 for (int otherLayerNum=0; otherLayerNum< otherLayers.size() ; otherLayerNum++) {
576 sLayer = (SlownessLayer)otherLayers.elementAt(otherLayerNum);
577 if ((sLayer.getTopP() - p)*(p-sLayer.getBotP()) > 0.0) {
578
579
580 topLayer = (SlownessLayer)sLayer.clone();
581 topLayer.setBotP(p);
582 topLayer.setBotDepth(sLayer.bullenDepthFor(p, radiusOfEarth));
583
584 botLayer = (SlownessLayer)sLayer.clone();
585 botLayer.setTopP(p);
586 botLayer.setTopDepth(topLayer.getBotDepth());
587
588 otherLayers.removeElementAt(otherLayerNum);
589 otherLayers.insertElementAt(botLayer, otherLayerNum);
590 otherLayers.insertElementAt(topLayer, otherLayerNum);
591
592 for (int critNum=0; critNum<getNumCriticalDepths(); critNum++) {
593 CriticalDepth cd = getCriticalDepth(critNum);
594 if (cd.getLayerNum(otherWaveType) > otherLayerNum) {
595 cd.setLayerNum(cd.getLayerNum(otherWaveType)+1, otherWaveType);
596 }
597 }
598 }
599 }
600 return new SplitLayerInfo(true, false, p);
601 }
602 }
603
604 /***
605 * Finds all critical points within a velocity model. Critical points
606 * are first order discontinuities in velocity/slowness, local extrema
607 * in slowness. A high
608 * slowness zone is a low velocity zone, but it is possible to have
609 * a slight low velocity zone within a spherical earth that is
610 * not a high slowness zone and thus does not exhibit
611 * any of the pathological behavior of a low velocity zone.
612 *
613 * @exception NoSuchMatPropException occurs if wavetype is not
614 * recognized.
615 * @exception SlownessModelException occurs if validate() returns
616 * false, this indicates a bug in the code.
617 */
618 protected void findCriticalPoints()
619 throws SlownessModelException {
620
621 double topP, botP;
622 double topDepth, botDepth = getRadiusOfEarth();
623 double topVelocity, botVelocity;
624
625 double minPSoFar = Double.MAX_VALUE;
626 double minSSoFar = Double.MAX_VALUE;
627 DepthRange highSlownessZoneP = new DepthRange();
628 DepthRange highSlownessZoneS = new DepthRange();
629 boolean inHighSlownessZoneP = false;
630 boolean inHighSlownessZoneS = false;
631
632 DepthRange fluidZone = new DepthRange();
633 boolean inFluidZone = false;
634
635 boolean belowOuterCore = false;
636
637
638 VelocityLayer prevVLayer, currVLayer;
639
640 SlownessLayer prevSLayer, currSLayer, prevPLayer, currPLayer;
641
642
643 highSlownessLayerDepthsP.removeAllElements();
644 highSlownessLayerDepthsS.removeAllElements();
645 criticalDepthVector.removeAllElements();
646 fluidLayerDepths.removeAllElements();
647
648
649
650 currVLayer = vMod.getVelocityLayer(0);
651 currVLayer = new VelocityLayer(0,
652 currVLayer.getTopDepth(), currVLayer.getTopDepth(),
653 currVLayer.getTopPVelocity(), currVLayer.getTopPVelocity(),
654 currVLayer.getTopSVelocity(), currVLayer.getTopSVelocity(),
655 currVLayer.getTopDensity(), currVLayer.getTopDensity(),
656 currVLayer.getTopQp(), currVLayer.getTopQp(),
657 currVLayer.getTopQs(),currVLayer.getTopQs());
658
659 currSLayer = toSlownessLayer(currVLayer, SWAVE);
660 currPLayer = toSlownessLayer(currVLayer, PWAVE);
661
662
663
664 criticalDepthVector.addElement(new CriticalDepth(0.0, 0, 0, 0));
665
666
667 if (!inFluidZone && currVLayer.getTopSVelocity()==0.0 ) {
668 inFluidZone = true;
669 fluidZone = new DepthRange();
670 fluidZone.topDepth = currVLayer.getTopDepth();
671 currSLayer = currPLayer;
672 }
673 if (minSSoFar > currSLayer.getTopP()) {
674 minSSoFar = currSLayer.getTopP();
675 }
676 if (minPSoFar > currPLayer.getTopP()) {
677 minPSoFar = currPLayer.getTopP();
678 }
679
680 for (int layerNum=0;layerNum<vMod.getNumLayers();layerNum++) {
681
682 prevVLayer = currVLayer;
683 prevSLayer = currSLayer;
684 prevPLayer = currPLayer;
685 currVLayer = vMod.getVelocityLayerClone(layerNum);
686 currSLayer = toSlownessLayer(currVLayer, SWAVE);
687 currPLayer = toSlownessLayer(currVLayer, PWAVE);
688
689
690
691 if (!inFluidZone && currVLayer.getTopSVelocity()==0.0 ) {
692 inFluidZone = true;
693 fluidZone = new DepthRange();
694 fluidZone.topDepth = currVLayer.getTopDepth();
695 }
696
697
698
699 if (inFluidZone && currVLayer.getTopSVelocity()!=0.0) {
700 if (prevVLayer.getBotDepth() > vMod.getIocbDepth() ) {
701 belowOuterCore = true;
702 }
703 inFluidZone = false;
704 fluidZone.botDepth = prevVLayer.getBotDepth();
705 fluidLayerDepths.addElement(fluidZone);
706 }
707
708
709
710
711 if (inFluidZone || ( belowOuterCore && ! allowInnerCoreS )) {
712 currSLayer = currPLayer;
713 }
714
715 if (prevSLayer.getBotP() != currSLayer.getTopP() || prevPLayer.getBotP() != currPLayer.getTopP()) {
716
717 criticalDepthVector.addElement(new CriticalDepth(currSLayer.getTopDepth(), layerNum, -1, -1));
718
719 if (DEBUG) {
720 System.out.println("first order discontinuity, depth="+
721 currSLayer.getTopDepth());
722 System.out.println(prevSLayer+"\n"+currSLayer);
723 System.out.println(prevPLayer+"\n"+currPLayer);
724 }
725
726 if (inHighSlownessZoneS && (currSLayer.getTopP() < minSSoFar)) {
727
728 if (DEBUG) {
729 System.out.println("top of current layer is the bottom"+
730 " of a high slowness zone.");
731 }
732 highSlownessZoneS.botDepth = currSLayer.getTopDepth();
733 highSlownessLayerDepthsS.addElement(highSlownessZoneS);
734 inHighSlownessZoneS = false;
735 }
736 if (inHighSlownessZoneP && (currPLayer.getTopP() < minPSoFar)) {
737
738 if (DEBUG) {
739 System.out.println("top of current layer is the bottom"+
740 " of a high slowness zone.");
741 }
742 highSlownessZoneP.botDepth = currSLayer.getTopDepth();
743 highSlownessLayerDepthsP.addElement(highSlownessZoneP);
744 inHighSlownessZoneP = false;
745 }
746
747
748
749
750 if (minPSoFar > currPLayer.getTopP()) {
751 minPSoFar = currPLayer.getTopP();
752 }
753 if (minSSoFar > currSLayer.getTopP()) {
754 minSSoFar = currSLayer.getTopP();
755 }
756
757 if (!inHighSlownessZoneS && (
758 prevSLayer.getBotP() < currSLayer.getTopP() ||
759 currSLayer.getTopP() < currSLayer.getBotP())) {
760
761 if (DEBUG) {
762 System.out.println("Found S high slowness at first order "+
763 "discontinuity, layer = "+layerNum);
764 }
765 inHighSlownessZoneS = true;
766 highSlownessZoneS = new DepthRange();
767 highSlownessZoneS.topDepth = currSLayer.getTopDepth();
768 highSlownessZoneS.rayParam = minSSoFar;
769 }
770 if (!inHighSlownessZoneP && (
771 prevPLayer.getBotP() < currPLayer.getTopP() ||
772 currPLayer.getTopP() < currPLayer.getBotP())) {
773
774 if (DEBUG) {
775 System.out.println("Found P high slowness at first order "+
776 "discontinuity, layer = "+layerNum);
777 }
778 inHighSlownessZoneP = true;
779 highSlownessZoneP = new DepthRange();
780 highSlownessZoneP.topDepth = currPLayer.getTopDepth();
781 highSlownessZoneP.rayParam = minPSoFar;
782 }
783
784 } else {
785 if ((prevSLayer.getTopP()-prevSLayer.getBotP())*
786 (prevSLayer.getBotP()-currSLayer.getBotP()) < 0.0 ||
787 (prevPLayer.getTopP()-prevPLayer.getBotP())*
788 (prevPLayer.getBotP()-currPLayer.getBotP()) < 0.0) {
789
790 criticalDepthVector.addElement(new CriticalDepth(currSLayer.getTopDepth(),layerNum,-1,-1));
791
792 if (DEBUG) {
793 System.out.println("local slowness extrema, depth="+
794 currSLayer.getTopDepth());
795 }
796
797 if (!inHighSlownessZoneP && (currPLayer.getTopP() < currPLayer.getBotP())) {
798
799 if (DEBUG) {
800 System.out.println("start of a P high slowness zone,"+
801 " local slowness extrema, minPSoFar="+minPSoFar);
802 }
803 inHighSlownessZoneP = true;
804 highSlownessZoneP = new DepthRange();
805 highSlownessZoneP.topDepth = currPLayer.getTopDepth();
806 highSlownessZoneP.rayParam = minPSoFar;
807 }
808 if (!inHighSlownessZoneS && (currSLayer.getTopP() < currSLayer.getBotP())) {
809
810 if (DEBUG) {
811 System.out.println("start of a S high slowness zone,"+
812 " local slowness extrema, minSSoFar="+minSSoFar);
813 }
814 inHighSlownessZoneS = true;
815 highSlownessZoneS = new DepthRange();
816 highSlownessZoneS.topDepth = currSLayer.getTopDepth();
817 highSlownessZoneS.rayParam = minSSoFar;
818 }
819 }
820 }
821
822 if (inHighSlownessZoneP && (currPLayer.getBotP() < minPSoFar)) {
823
824 if (DEBUG) {
825 System.out.println("layer contains the bottom of a P "+
826 "high slowness zone. minPSoFar="+minPSoFar+" "+currPLayer);
827 }
828 highSlownessZoneP.botDepth = findDepth(minPSoFar,
829 layerNum, layerNum, PWAVE);
830 highSlownessLayerDepthsP.addElement(highSlownessZoneP);
831 inHighSlownessZoneP = false;
832 }
833 if (inHighSlownessZoneS && (currSLayer.getBotP() < minSSoFar)) {
834
835 if (DEBUG) {
836 System.out.println("layer contains the bottom of a S "+
837 "high slowness zone. minSSoFar="+minSSoFar+" "+currSLayer);
838 }
839 highSlownessZoneS.botDepth = findDepth(minSSoFar,
840 layerNum, layerNum, SWAVE);
841 highSlownessLayerDepthsS.addElement(highSlownessZoneS);
842 inHighSlownessZoneS = false;
843 }
844
845 if (minPSoFar > currPLayer.getBotP()) {
846 minPSoFar = currPLayer.getBotP();
847 }
848 if (minPSoFar > currPLayer.getTopP()) {
849 minPSoFar = currPLayer.getTopP();
850 }
851 if (minSSoFar > currSLayer.getBotP()) {
852 minSSoFar = currSLayer.getBotP();
853 }
854 if (minSSoFar > currSLayer.getTopP()) {
855 minSSoFar = currSLayer.getTopP();
856 }
857
858 if (DEBUG && inHighSlownessZoneS) {
859 System.out.println("In S high slowness zone, layerNum = "+layerNum+
860 " minSSoFar="+minSSoFar);
861 }
862 if (DEBUG && inHighSlownessZoneP) {
863 System.out.println("In P high slowness zone, layerNum = "+layerNum+
864 " minPSoFar="+minPSoFar);
865 }
866 }
867
868
869
870 criticalDepthVector.addElement(new CriticalDepth(getRadiusOfEarth(),vMod.getNumLayers(),-1,-1));
871
872
873
874 if (inHighSlownessZoneS) {
875 highSlownessZoneS.botDepth = currVLayer.getBotDepth();
876 highSlownessLayerDepthsS.addElement(highSlownessZoneS);
877 }
878 if (inHighSlownessZoneP) {
879 highSlownessZoneP.botDepth = currVLayer.getBotDepth();
880 highSlownessLayerDepthsP.addElement(highSlownessZoneP);
881 }
882
883
884
885
886
887 if (inFluidZone ) {
888 fluidZone.botDepth = currVLayer.getBotDepth();
889 fluidLayerDepths.addElement(fluidZone);
890 }
891
892 if (DEBUG && criticalDepthVector.size()!=0) {
893 int botCriticalLayerNum, topCriticalLayerNum;
894 String desc =
895 "**** Critical Velocity Layers ************************\n";
896 botCriticalLayerNum =
897 ((CriticalDepth)criticalDepthVector.elementAt(0)).velLayerNum-1;
898 for (int criticalNum=1; criticalNum<criticalDepthVector.size(); criticalNum++) {
899 topCriticalLayerNum = botCriticalLayerNum+1;
900 botCriticalLayerNum =
901 ((CriticalDepth)criticalDepthVector.elementAt(criticalNum)).velLayerNum-1;
902 desc += " "+topCriticalLayerNum+","+botCriticalLayerNum;
903 }
904 System.out.println(desc);
905 }
906
907 if (DEBUG && highSlownessLayerDepthsP.size()!=0) {
908 for (int layerNum=0;layerNum<highSlownessLayerDepthsP.size();layerNum++) {
909 System.out.println((DepthRange)highSlownessLayerDepthsP.elementAt(layerNum));
910 }
911 }
912 if (DEBUG && highSlownessLayerDepthsS.size()!=0) {
913 for (int layerNum=0;layerNum<highSlownessLayerDepthsS.size();layerNum++) {
914 System.out.println((DepthRange)highSlownessLayerDepthsS.elementAt(layerNum));
915 }
916 }
917
918 if (!validate()) {
919 throw new SlownessModelException("Validation Failed!");
920 }
921 }
922
923 /*** Finds a depth corresponding to a slowness over the whole
924 * VelocityModel. Calls findDepth(double, int, int, char).
925 */
926 public double findDepth(double rayParam, boolean isPWave)
927 throws SlownessModelException {
928 return findDepth(rayParam, 0, vMod.getNumLayers()-1, isPWave);
929 }
930
931 /*** Finds a depth corresponding to a slowness between two given
932 * depths in the Velocity Model. Calls findDepth(double, int, int, char).
933 */
934 public double findDepth(double rayParam, double topDepth, double botDepth,
935 boolean isPWave) throws SlownessModelException {
936 try {
937 int topLayerNum = vMod.layerNumberBelow(topDepth);
938 if (vMod.getVelocityLayer(topLayerNum).getBotDepth() == topDepth) {
939 topLayerNum++;
940 }
941 int botLayerNum = vMod.layerNumberAbove(botDepth);
942 return findDepth(rayParam, topLayerNum, botLayerNum, isPWave);
943 } catch (NoSuchLayerException e) {
944 throw new SlownessModelException(e.getMessage());
945 }
946 }
947
948 /*** Finds a depth corresponding to a slowness between two given
949 * velocity layers, including the top and the bottom.
950 * We also check to see if the slowness is less than the bottom
951 * slowness of these layers but greater than the top slowness
952 * of the next deeper layer. This corresponds to a total reflection.
953 * In this case a check needs to be made to see if this is an S wave
954 * reflecting off of a fluid layer, use P velocity below in this case.
955 * We assume that slowness is monotonic within these layers and
956 * therefore there is only one depth with the given slowness.
957 * This means we return the first depth that we find.
958 *
959 * @exception SlownessModelException occurs if
960 * topCriticalLayer > botCriticalLayer because there are no layers
961 * to search, or if there is an increase in slowness, ie a negative
962 * velocity gradient, that just balances the decrease in slowness due
963 * to the spherical earth, or if the ray parameter p is not contained
964 * within the specified layer range.
965 */
966 public double findDepth(double p,
967 int topCriticalLayer, int botCriticalLayer, boolean isPWave)
968 throws SlownessModelException {
969
970 VelocityLayer velLayer = new VelocityLayer();
971 double topP=Double.MAX_VALUE, botP=Double.MAX_VALUE;
972 double topVelocity, botVelocity;
973 double depth;
974 double denominator;
975 double slope;
976
977 char waveType;
978 if (isPWave) {
979 waveType = 'P';
980 } else {
981 waveType = 'S';
982 }
983
984 try {
985 if (topCriticalLayer > botCriticalLayer) {
986 throw new SlownessModelException("findDepth: no layers to search!: "+
987 "topCriticalLayer = "+topCriticalLayer+
988 "botCriticalLayer = "+botCriticalLayer);
989 }
990
991 for (int layerNum=topCriticalLayer;layerNum<=botCriticalLayer;layerNum++){
992 velLayer = (VelocityLayer)vMod.getVelocityLayer(layerNum);
993 topVelocity = velLayer.evaluateAtTop(waveType);
994 botVelocity = velLayer.evaluateAtBottom(waveType);
995
996 topP = toSlowness(topVelocity, velLayer.getTopDepth());
997 botP = toSlowness(botVelocity, velLayer.getBotDepth());
998
999
1000
1001 if (Math.abs(topP - p) < slownessTolerance) {
1002 return velLayer.getTopDepth();
1003 }
1004 if (Math.abs(p - botP) < slownessTolerance) {
1005 return velLayer.getBotDepth();
1006 }
1007
1008 if ((topP - p)*(p - botP) >= 0.0) {
1009
1010
1011
1012
1013
1014 slope = (botVelocity-topVelocity)/
1015 (velLayer.getBotDepth()-velLayer.getTopDepth());
1016 depth = interpolate(p, topVelocity, velLayer.getTopDepth(), slope);
1017 return depth;
1018
1019 } else if (layerNum==topCriticalLayer &&
1020 Math.abs(p-topP)<slownessTolerance) {
1021
1022
1023 return velLayer.getTopDepth();
1024 }
1025
1026
1027
1028
1029
1030 if (layerNum < vMod.getNumLayers()-1) {
1031 velLayer = (VelocityLayer)vMod.getVelocityLayerClone(
1032 layerNum+1);
1033 topVelocity = velLayer.evaluateAtTop(waveType);
1034
1035 if (! isPWave &&
1036 depthInFluid(velLayer.getTopDepth())){
1037
1038
1039
1040 topVelocity = velLayer.evaluateAtTop('P');
1041 }
1042 topP = toSlowness(topVelocity, velLayer.getTopDepth());
1043 if (botP >= p && p >= topP) {
1044 return velLayer.getTopDepth();
1045 }
1046 }
1047 }
1048
1049 if (Math.abs(p-botP)<slownessTolerance) {
1050
1051
1052 System.out.println(" p is just outside the bottommost layer."+
1053 " This probably shouldn't be allowed to happen!\n");
1054 return velLayer.getBotDepth();
1055 }
1056 } catch (NoSuchMatPropException e) {
1057
1058 e.printStackTrace();
1059 }
1060
1061 throw new SlownessModelException("slowness p="+p+
1062 " is not contained within the specified layers."+
1063 "\np="+p+" topCriticalLayer="+topCriticalLayer+
1064 " botCriticalLayer="+ botCriticalLayer+" isPWave="+ isPWave+
1065 " topP="+topP+" botP="+botP);
1066 }
1067
1068 /***
1069 * This method takes a velocity model and creates a vector containing
1070 * slowness-depth layers that, hopefully, adequately sample both
1071 * slowness and depth so that the travel time as a function of
1072 * distance can be reconstructed from the theta function.
1073 * It catches NoSuchLayerException which might be generated in the
1074 * velocity model. This shouldn't happen though.
1075 * @see VelocityModel
1076 * @exception SlownessModelException occurs if the validation on the
1077 * velocity model fails, or if the velocity model
1078 * has no layers.
1079 * @exception NoSuchMatPropException occurs if wavetype is not
1080 * recognized.
1081 */
1082 public void createSample(VelocityModel velModel)
1083 throws SlownessModelException, NoSuchMatPropException, NoSuchLayerException
1084 {
1085
1086 VelocityLayer velLayer;
1087 double maxVelSoFar = 0.0;
1088 double previousBotVel;
1089 int botCriticalLayerNum, topCriticalLayerNum;
1090 DepthRange highSZoneDepth = new DepthRange();
1091
1092
1093
1094 if (velModel.validate()== false) {
1095 throw new SlownessModelException("Error in velocity model!");
1096 }
1097 if (velModel.getNumLayers()==0) {
1098 throw new SlownessModelException("velModel.getNumLayers()==0");
1099 }
1100
1101 if (DEBUG) {System.out.println("start createSample");}
1102 vMod = velModel;
1103 setRadiusOfEarth(velModel.getRadiusOfEarth());
1104
1105
1106 if (DEBUG) {System.out.println("findCriticalPoints");}
1107 findCriticalPoints();
1108 if (DEBUG) {System.out.println("coarseSample");}
1109 coarseSample();
1110
1111 boolean isOK = false;
1112 if (DEBUG) {
1113 isOK = validate();
1114 System.out.println("rayParamCheck");}
1115 rayParamIncCheck();
1116
1117 if (DEBUG) {
1118 isOK &= validate();
1119 System.out.println("depthIncCheck");}
1120 depthIncCheck();
1121
1122 if (DEBUG) {
1123 isOK &= validate();
1124 System.out.println("distanceCheck");}
1125 distanceCheck();
1126
1127 if (DEBUG) {
1128 isOK &= validate();
1129 System.out.println("fixCriticalPoints");}
1130 fixCriticalPoints();
1131
1132 if (DEBUG) {
1133 System.out.println("done createSample");
1134 }
1135 }
1136
1137 /*** Creates a coarse slowness sampling of the velocity model (vMod). The
1138 * resultant slowness layers will satisfy the maximum depth increments
1139 * as well as sampling each point specified within the VelocityModel.
1140 * The P and S sampling will also be compatible.
1141 */
1142 protected void coarseSample()
1143 throws SlownessModelException, NoSuchLayerException {
1144 VelocityLayer prevVLayer;
1145 VelocityLayer origVLayer;
1146 VelocityLayer currVLayer = new VelocityLayer();
1147 SlownessLayer currPLayer, currSLayer;
1148
1149 PLayers.removeAllElements();
1150 SLayers.removeAllElements();
1151
1152
1153 origVLayer = vMod.getVelocityLayer(0);
1154 origVLayer = new VelocityLayer(0,
1155 origVLayer.getTopDepth(), origVLayer.getTopDepth(),
1156 origVLayer.getTopPVelocity(), origVLayer.getTopPVelocity(),
1157 origVLayer.getTopSVelocity(), origVLayer.getTopSVelocity(),
1158 origVLayer.getTopDensity(), origVLayer.getTopDensity(),
1159 origVLayer.getTopQp(), origVLayer.getTopQp(),
1160 origVLayer.getTopQs(),origVLayer.getTopQs());
1161
1162 try {
1163 for (int layerNum=0; layerNum < vMod.getNumLayers(); layerNum++) {
1164 prevVLayer = origVLayer;
1165 origVLayer = vMod.getVelocityLayer(layerNum);
1166
1167
1168
1169
1170 if (prevVLayer.getBotPVelocity() != origVLayer.getTopPVelocity() ||
1171 (prevVLayer.getBotSVelocity() != origVLayer.getTopSVelocity() &&
1172 (allowInnerCoreS ||
1173 origVLayer.getTopDepth() < vMod.getIocbDepth()))) {
1174 currVLayer.setTopDepth(prevVLayer.getBotDepth());
1175 currVLayer.setBotDepth(prevVLayer.getBotDepth());
1176 currVLayer.setTopPVelocity(prevVLayer.evaluateAtBottom('P'));
1177 currVLayer.setBotPVelocity(origVLayer.evaluateAtTop('P'));
1178
1179
1180
1181
1182
1183 if (prevVLayer.getBotSVelocity() == 0.0) {
1184 currVLayer.setTopSVelocity(prevVLayer.evaluateAtBottom('P'));
1185 } else {
1186 currVLayer.setTopSVelocity(prevVLayer.evaluateAtBottom('S'));
1187 }
1188 if (origVLayer.getTopSVelocity() == 0.0) {
1189 currVLayer.setBotSVelocity(origVLayer.evaluateAtTop('P'));
1190 } else {
1191 currVLayer.setBotSVelocity(origVLayer.evaluateAtTop('S'));
1192 }
1193
1194
1195
1196
1197 currPLayer = toSlownessLayer(currVLayer, PWAVE);
1198 PLayers.addElement(currPLayer);
1199 if ((prevVLayer.getBotSVelocity() == 0.0 &&
1200 origVLayer.getTopSVelocity() == 0.0) ||
1201 (! allowInnerCoreS &&
1202 currVLayer.getTopDepth() >= vMod.getIocbDepth())) {
1203 currSLayer = currPLayer;
1204 } else {
1205 currSLayer = toSlownessLayer(currVLayer, SWAVE);
1206 }
1207 SLayers.addElement(currSLayer);
1208 }
1209
1210 currPLayer = toSlownessLayer(origVLayer, PWAVE);
1211 PLayers.addElement(currPLayer);
1212
1213 if (depthInFluid(origVLayer.getTopDepth()) ||
1214 (! allowInnerCoreS && origVLayer.getTopDepth() >= vMod.getIocbDepth())) {
1215 currSLayer = currPLayer;
1216 } else {
1217 currSLayer = toSlownessLayer(origVLayer, SWAVE);
1218 }
1219 SLayers.addElement(currSLayer);
1220 }
1221
1222
1223
1224
1225 int highZoneNum, SLayerNum;
1226 SlownessLayer highSLayer;
1227 DepthRange highZone;
1228 for (highZoneNum = 0; highZoneNum < highSlownessLayerDepthsS.size(); highZoneNum++) {
1229 highZone = (DepthRange)highSlownessLayerDepthsS.elementAt(highZoneNum);
1230 SLayerNum = layerNumberAbove(highZone.botDepth, SWAVE);
1231 highSLayer = getSlownessLayer(SLayerNum, SWAVE);
1232 while (highSLayer.getTopDepth() == highSLayer.getBotDepth() &&
1233 (highSLayer.getTopP() - highZone.rayParam)*(highZone.rayParam - highSLayer.getBotP()) < 0) {
1234 SLayerNum++;
1235 highSLayer = getSlownessLayer(SLayerNum, SWAVE);
1236 }
1237 if (highZone.rayParam != highSLayer.getBotP()) {
1238 addSlowness(highZone.rayParam, SWAVE);
1239 }
1240 }
1241 for (highZoneNum = 0; highZoneNum < highSlownessLayerDepthsP.size(); highZoneNum++) {
1242 highZone = (DepthRange)highSlownessLayerDepthsP.elementAt(highZoneNum);
1243 SLayerNum = layerNumberAbove(highZone.botDepth, PWAVE);
1244 highSLayer = getSlownessLayer(SLayerNum, PWAVE);
1245 while (highSLayer.getTopDepth() == highSLayer.getBotDepth() &&
1246 (highSLayer.getTopP() - highZone.rayParam)*(highZone.rayParam - highSLayer.getBotP()) < 0) {
1247 SLayerNum++;
1248 highSLayer = getSlownessLayer(SLayerNum, PWAVE);
1249 }
1250 if (highZone.rayParam != highSLayer.getBotP()) {
1251 addSlowness(highZone.rayParam, PWAVE);
1252 }
1253 }
1254
1255 double botP = -1;
1256 double topP = -1;
1257 for (int j=0; j<PLayers.size(); j++) {
1258 topP = ((SlownessLayer)PLayers.elementAt(j)).getTopP();
1259 if (topP != botP) {
1260 addSlowness(topP, SWAVE);
1261 }
1262 botP = ((SlownessLayer)PLayers.elementAt(j)).getBotP();
1263 addSlowness(botP, SWAVE);
1264 }
1265 botP = -1;
1266 for (int j=0; j<SLayers.size(); j++) {
1267 topP = ((SlownessLayer)SLayers.elementAt(j)).getTopP();
1268 if (topP != botP) {
1269 addSlowness(topP, PWAVE);
1270 }
1271 botP = ((SlownessLayer)SLayers.elementAt(j)).getBotP();
1272 addSlowness(botP, PWAVE);
1273 }
1274 } catch (NoSuchMatPropException e) {
1275
1276 e.printStackTrace();
1277 }
1278 }
1279
1280 /*** Checks to make sure that no slowness layer spans more than maxDeltaP.
1281 */
1282 protected void rayParamIncCheck()
1283 throws SlownessModelException, NoSuchLayerException
1284 {
1285 SlownessLayer sLayer;
1286 double numNewP;
1287 double deltaP;
1288
1289 for (int j=0; j<SLayers.size(); j++) {
1290 sLayer = (SlownessLayer)SLayers.elementAt(j);
1291 if (Math.abs(sLayer.getTopP() - sLayer.getBotP()) > maxDeltaP) {
1292 numNewP = Math.ceil(Math.abs(sLayer.getTopP() - sLayer.getBotP())
1293 / maxDeltaP);
1294 deltaP = (sLayer.getTopP() - sLayer.getBotP()) / numNewP;
1295
1296 for (int rayNum=1; rayNum < numNewP; rayNum++) {
1297 addSlowness(sLayer.getTopP()+rayNum*deltaP, PWAVE);
1298 addSlowness(sLayer.getTopP()+rayNum*deltaP, SWAVE);
1299 }
1300 }
1301 }
1302 for (int j=0; j<PLayers.size(); j++) {
1303 sLayer = (SlownessLayer)PLayers.elementAt(j);
1304 if (Math.abs(sLayer.getTopP() - sLayer.getBotP()) > maxDeltaP) {
1305 numNewP = Math.ceil(Math.abs(sLayer.getTopP() - sLayer.getBotP())
1306 / maxDeltaP);
1307 deltaP = (sLayer.getTopP() - sLayer.getBotP()) / numNewP;
1308
1309 for (int rayNum=1; rayNum < numNewP; rayNum++) {
1310 addSlowness(sLayer.getTopP()+rayNum*deltaP, PWAVE);
1311 addSlowness(sLayer.getTopP()+rayNum*deltaP, SWAVE);
1312 }
1313 }
1314 }
1315 }
1316
1317 /*** Checks to make sure no slowness layer spans more than
1318 * maxDepthInterval. */
1319 protected void depthIncCheck()
1320 throws SlownessModelException, NoSuchLayerException
1321 {
1322 SlownessLayer sLayer;
1323 int numNewDepths;
1324 double deltaDepth;
1325 double velocity;
1326 double p;
1327
1328 try {
1329 for (int j=0; j<SLayers.size(); j++) {
1330 sLayer = (SlownessLayer)SLayers.elementAt(j);
1331 if ((sLayer.getBotDepth() - sLayer.getTopDepth()) > maxDepthInterval) {
1332 numNewDepths = (int)Math.ceil((sLayer.getBotDepth() - sLayer.getTopDepth()) / maxDepthInterval);
1333 deltaDepth = (sLayer.getBotDepth() - sLayer.getTopDepth()) / numNewDepths;
1334 for (int depthNum=1; depthNum < numNewDepths; depthNum++) {
1335 velocity = vMod.evaluateAbove(sLayer.getTopDepth() + depthNum*deltaDepth, 'S');
1336 if (velocity == 0.0 || (! allowInnerCoreS &&
1337 sLayer.getTopDepth()+ depthNum*deltaDepth >= vMod.getIocbDepth()) ) {
1338 velocity = vMod.evaluateAbove(sLayer.getTopDepth() + depthNum*deltaDepth, 'P');
1339 }
1340 p = toSlowness(velocity, sLayer.getTopDepth() + depthNum*deltaDepth);
1341 addSlowness(p, PWAVE);
1342 addSlowness(p, SWAVE);
1343 }
1344 }
1345 }
1346 for (int j=0; j<PLayers.size(); j++) {
1347 sLayer = (SlownessLayer)PLayers.elementAt(j);
1348 if ((sLayer.getBotDepth() - sLayer.getTopDepth()) > maxDepthInterval) {
1349 numNewDepths = (int)Math.ceil((sLayer.getBotDepth() - sLayer.getTopDepth()) / maxDepthInterval);
1350 deltaDepth = (sLayer.getBotDepth() - sLayer.getTopDepth()) / numNewDepths;
1351 for (int depthNum=1; depthNum < numNewDepths; depthNum++) {
1352 p = toSlowness(vMod.evaluateAbove(sLayer.getTopDepth() + depthNum*deltaDepth, 'P'),
1353 sLayer.getTopDepth() + depthNum*deltaDepth);
1354 addSlowness(p, PWAVE);
1355 addSlowness(p, SWAVE);
1356 }
1357 }
1358 }
1359 } catch (NoSuchMatPropException e) {
1360
1361 e.printStackTrace();
1362 }
1363 }
1364
1365 /*** Checks to make sure no slowness layer spans more than maxRangeInterval
1366 * and that the (estimated) error due to linear interpolation is less than
1367 * maxInterpError. */
1368 protected void distanceCheck() throws SlownessModelException, NoSuchMatPropException, NoSuchLayerException {
1369 SlownessLayer sLayer, prevSLayer;
1370 int j;
1371 TimeDist prevTD;
1372 TimeDist currTD;
1373 TimeDist prevPrevTD;
1374 boolean isCurrOK;
1375 boolean isPrevOK;
1376 boolean currWaveType, otherWaveType;
1377
1378
1379 for (int waveN=0; waveN < 2; waveN++) {
1380 currWaveType = waveN==0 ? SWAVE : PWAVE;
1381 otherWaveType = ! currWaveType;
1382 prevPrevTD = null;
1383 prevTD = null;
1384 currTD = null;
1385 isCurrOK = false;
1386 isPrevOK = false;
1387 j=0;
1388 sLayer = getSlownessLayer(0, currWaveType);
1389 while ( j < getNumLayers(currWaveType)) {
1390 prevSLayer = sLayer;
1391 sLayer = getSlownessLayer(j, currWaveType);
1392 if ( ! depthInHighSlowness(sLayer.getBotDepth(), sLayer.getBotP(), currWaveType) &&
1393 ! depthInHighSlowness(sLayer.getTopDepth(), sLayer.getTopP(), currWaveType)) {
1394
1395
1396 if (isCurrOK ) {
1397 if (isPrevOK) {
1398 prevPrevTD = prevTD;
1399 } else {
1400 prevPrevTD = null;
1401 }
1402 prevTD = currTD;
1403 isPrevOK = true;
1404 } else {
1405 prevTD = approxDistance(j-1, sLayer.getTopP(), currWaveType);
1406 isPrevOK = true;
1407 }
1408 currTD = approxDistance(j, sLayer.getBotP(), currWaveType);
1409 isCurrOK = true;
1410
1411
1412 if ( Math.abs(prevTD.dist - currTD.dist) > maxRangeInterval &&
1413 Math.abs(sLayer.getTopP() - sLayer.getBotP()) > 2*minDeltaP) {
1414 addSlowness((sLayer.getTopP()+sLayer.getBotP())/2.0, PWAVE);
1415 addSlowness((sLayer.getTopP()+sLayer.getBotP())/2.0, SWAVE);
1416 currTD = prevTD;
1417 prevTD = prevPrevTD;
1418 } else {
1419
1420
1421
1422
1423
1424 if (prevPrevTD != null && Math.abs(
1425 prevTD.time - ((currTD.time-prevPrevTD.time)*
1426 (prevTD.dist-prevPrevTD.dist)/
1427 (currTD.dist - prevPrevTD.dist) + prevPrevTD.time)) > maxInterpError) {
1428
1429 addSlowness((prevSLayer.getTopP()+prevSLayer.getBotP())/2.0, PWAVE);
1430 addSlowness((prevSLayer.getTopP()+prevSLayer.getBotP())/2.0, SWAVE);
1431 addSlowness((sLayer.getTopP()+sLayer.getBotP())/2.0, PWAVE);
1432 addSlowness((sLayer.getTopP()+sLayer.getBotP())/2.0, SWAVE);
1433 currTD = prevPrevTD;
1434 isPrevOK = false;
1435 j--;
1436 sLayer = getSlownessLayer( ((j-1>=0) ? j-1 : 0),currWaveType);
1437
1438 } else {
1439 j++;
1440 if (DEBUG && (j % 100 == 0)) { System.out.print(" "+j); }
1441 }
1442 }
1443 } else {
1444 prevPrevTD = null;
1445 prevTD = null;
1446 currTD = null;
1447 isCurrOK = false;
1448 isPrevOK = false;
1449 j++;
1450 if (DEBUG && (j % 100 == 0)) { System.out.print(" "+j); }
1451 }
1452
1453 }
1454 if (DEBUG) {
1455 System.out.println("\nNumber of "+(currWaveType ? 'P' : 'S')+" slowness layers: "+j);
1456 }
1457 }
1458 }
1459
1460 /*** Adds the given ray parameter, p, to the slowness sampling for the
1461 * given waveType. It splits slowness layers as needed and keeps
1462 * P and S sampling consistant within fluid layers. Note, this makes
1463 * use of the velocity model, so all interpolation is linear in
1464 * velocity, not in slowness!
1465 * @returns true if a change was made, false otherwise.
1466 */
1467 protected void addSlowness(double p, boolean isPWave)
1468 throws SlownessModelException, NoSuchLayerException
1469 {
1470 boolean madeAChange = false;
1471 Vector layers, otherLayers;
1472 SlownessLayer sLayer, topLayer, botLayer;
1473 double slope;
1474 double topVelocity, botVelocity;
1475 int otherIndex;
1476
1477 if (isPWave) {
1478 layers = PLayers;
1479 otherLayers = SLayers;
1480 } else {
1481 layers = SLayers;
1482 otherLayers = PLayers;
1483 }
1484
1485 for (int i=0; i< layers.size(); i++) {
1486 sLayer = (SlownessLayer)layers.elementAt(i);
1487 try {
1488 if (sLayer.getTopDepth() != sLayer.getBotDepth()) {
1489 topVelocity = vMod.evaluateBelow(sLayer.getTopDepth(),
1490 (isPWave ? 'P' : 'S'));
1491 botVelocity = vMod.evaluateAbove(sLayer.getBotDepth(),
1492 (isPWave ? 'P' : 'S'));
1493 } else {
1494
1495
1496 topVelocity = vMod.evaluateAbove(sLayer.getBotDepth(),
1497 (isPWave ? 'P' : 'S'));
1498 botVelocity = vMod.evaluateBelow(sLayer.getTopDepth(),
1499 (isPWave ? 'P' : 'S'));
1500