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 }
1501 } catch (NoSuchMatPropException e) {
1502
1503 throw new SlownessModelException("Caught NoSuchMatPropException: "+
1504 e.getMessage());
1505 }
1506
1507
1508
1509
1510 if (! isPWave) {
1511 if (! allowInnerCoreS &&
1512 sLayer.getBotDepth() > vMod.getIocbDepth()) {
1513 break;
1514 } else if (topVelocity == 0.0) {
1515 continue;
1516 }
1517 }
1518
1519 if ((sLayer.getTopP() - p)*(p - sLayer.getBotP()) > 0) {
1520 madeAChange = true;
1521 topLayer = (SlownessLayer)sLayer.clone();
1522 topLayer.setBotP(p);
1523 if (sLayer.getBotDepth() != sLayer.getTopDepth()) {
1524
1525
1526 slope = (botVelocity - topVelocity ) /
1527 (sLayer.getBotDepth()-sLayer.getTopDepth());
1528 topLayer.setBotDepth(interpolate(p,
1529 topVelocity,
1530 sLayer.getTopDepth(),
1531 slope));
1532
1533 }
1534 botLayer = (SlownessLayer)sLayer.clone();
1535 botLayer.setTopP(p);
1536 botLayer.setTopDepth(topLayer.getBotDepth());
1537 layers.removeElementAt(i);
1538 layers.insertElementAt(botLayer, i);
1539 layers.insertElementAt(topLayer, i);
1540 otherIndex = otherLayers.indexOf(sLayer);
1541 if (otherIndex != -1) {
1542 otherLayers.removeElementAt(otherIndex);
1543 otherLayers.insertElementAt(botLayer, otherIndex);
1544 otherLayers.insertElementAt(topLayer, otherIndex);
1545 }
1546
1547 }
1548 }
1549 }
1550
1551 /*** Resets the slowness layers that correspond to critical points.
1552 */
1553 protected void fixCriticalPoints() throws NoSuchLayerException {
1554 CriticalDepth cd;
1555 SlownessLayer sLayer;
1556 for (int i=0; i< criticalDepthVector.size() ; i++) {
1557 cd = (CriticalDepth)criticalDepthVector.elementAt(i);
1558
1559 cd.PLayerNum = layerNumberBelow(cd.depth, PWAVE);
1560 sLayer = getSlownessLayer(cd.PLayerNum, PWAVE);
1561 if (cd.PLayerNum == PLayers.size()-1 && sLayer.getBotDepth() == cd.depth) {
1562 cd.PLayerNum++;
1563 }
1564
1565 cd.SLayerNum = layerNumberBelow(cd.depth, SWAVE);
1566 sLayer = getSlownessLayer(cd.SLayerNum, SWAVE);
1567 if (cd.SLayerNum == SLayers.size()-1 && sLayer.getBotDepth() == cd.depth) {
1568 cd.SLayerNum++;
1569 }
1570 }
1571 }
1572
1573 /*** Finds the index of the slowness layer that contains the given depth
1574 * Note that if the depth is a layer boundary, it returns the shallower
1575 * of the two or possibly more (since total reflections are zero
1576 * thickness layers) layers.
1577 *
1578 * @return the layer number.
1579 * @exception NoSuchLayerException occurs if no layer in the slowness
1580 * model contains the given depth.
1581 */
1582 public int layerNumberAbove(double depth, boolean isPWave)
1583 throws NoSuchLayerException {
1584 SlownessLayer tempLayer;
1585 Vector layers;
1586
1587 if (isPWave) {
1588 layers = PLayers;
1589 } else {
1590 layers = SLayers;
1591 }
1592
1593
1594 tempLayer = (SlownessLayer)layers.elementAt(0);
1595 if (tempLayer.getTopDepth() == depth) {
1596 return 0;
1597 }
1598 if (depth < tempLayer.getTopDepth() ||
1599 ((SlownessLayer)layers.elementAt(layers.size()-1)).getBotDepth() < depth) {
1600 throw new NoSuchLayerException(depth);
1601 }
1602
1603 int tooSmallNum = 0;
1604 int tooLargeNum = layers.size()-1;
1605 int currentNum = 0;
1606 boolean found = false;
1607 while ( ! found) {
1608 currentNum = Math.round((tooSmallNum + tooLargeNum) / 2.0f);
1609 tempLayer = getSlownessLayer(currentNum, isPWave);
1610
1611 if (tempLayer.getTopDepth() >= depth) {
1612 tooLargeNum = currentNum-1;
1613 } else if (tempLayer.getBotDepth() < depth) {
1614 tooSmallNum = currentNum+1;
1615 } else {
1616 found = true;
1617 }
1618 }
1619 return currentNum;
1620 }
1621
1622 /*** Finds the index of the slowness layer that contains the given depth
1623 * Note that if the depth is a layer boundary, it returns the deeper
1624 * of the two or possibly more (since total reflections are zero
1625 * thickness layers) layers.
1626 *
1627 * @return the layer number.
1628 * @exception NoSuchLayerException occurs if no layer in the slowness
1629 * model contains the given depth.
1630 */
1631 public int layerNumberBelow(double depth, boolean isPWave)
1632 throws NoSuchLayerException {
1633 SlownessLayer tempLayer;
1634 Vector layers;
1635
1636 if (isPWave) {
1637 layers = PLayers;
1638 } else {
1639 layers = SLayers;
1640 }
1641
1642
1643 tempLayer = (SlownessLayer)layers.elementAt(0);
1644 if (tempLayer.getTopDepth() == depth) {
1645 return 0;
1646 }
1647
1648 tempLayer = (SlownessLayer)layers.elementAt(layers.size()-1);
1649 if (tempLayer.getBotDepth() == depth) {
1650 return layers.size()-1;
1651 }
1652
1653 if (depth < ((SlownessLayer)layers.elementAt(0)).getTopDepth() ||
1654 ((SlownessLayer)layers.elementAt(layers.size()-1)).getBotDepth() < depth) {
1655 throw new NoSuchLayerException(depth);
1656 }
1657
1658 int tooSmallNum = 0;
1659 int tooLargeNum = layers.size()-1;
1660 int currentNum = 0;
1661 boolean found = false;
1662 while ( ! found) {
1663 currentNum = Math.round((tooSmallNum + tooLargeNum) / 2.0f);
1664 tempLayer = getSlownessLayer(currentNum, isPWave);
1665
1666 if (tempLayer.getTopDepth() > depth) {
1667 tooLargeNum = currentNum-1;
1668 } else if (tempLayer.getBotDepth() <= depth) {
1669 tooSmallNum = currentNum+1;
1670 } else {
1671 found = true;
1672 }
1673 }
1674 return currentNum;
1675 }
1676
1677
1678 /*** Performs consistency check on the slowness model.
1679 * @return true if successful, throws SlownessModelException otherwise.
1680 * @exception SlownessModelException if any check fails
1681 */
1682 public boolean validate()
1683 throws SlownessModelException
1684 {
1685 boolean isOK = true;
1686 double prevDepth;
1687 DepthRange highSZoneDepth, fluidZone;
1688 SlownessLayer sLayer;
1689
1690
1691 if (radiusOfEarth <= 0.0) {
1692 throw new SlownessModelException(
1693 "Radius of earth is not positive. radiusOfEarth = "+radiusOfEarth);
1694 }
1695
1696
1697 if (maxDepthInterval <= 0.0) {
1698 throw new SlownessModelException(
1699 "maxDepthInterval is not positive. maxDepthInterval = "+
1700 maxDepthInterval);
1701 }
1702
1703
1704 Vector highSlownessLayerDepths = highSlownessLayerDepthsP;
1705 boolean isPWave = PWAVE;
1706 for (int j=0;j<2; j++, isPWave = SWAVE) {
1707 if (isPWave) {
1708 highSlownessLayerDepths = highSlownessLayerDepthsP;
1709 } else {
1710 highSlownessLayerDepths = highSlownessLayerDepthsS;
1711 }
1712
1713 prevDepth= -1*Double.MAX_VALUE;
1714 for (int i=0;i<highSlownessLayerDepths.size();i++) {
1715 highSZoneDepth = (DepthRange)highSlownessLayerDepths.elementAt(i);
1716 if (highSZoneDepth.topDepth >= highSZoneDepth.botDepth) {
1717 throw new SlownessModelException(
1718 "High slowness zone has zero or negative thickness. Num "+
1719 i+" isPWave="+isPWave+
1720 " top depth "+highSZoneDepth.topDepth+
1721 " bottom depth "+highSZoneDepth.botDepth);
1722 }
1723 if (highSZoneDepth.topDepth <= prevDepth) {
1724 throw new SlownessModelException
1725 ("High slowness zone overlaps previous zone. Num "+
1726 i+" isPWave="+isPWave+
1727 " top depth "+highSZoneDepth.topDepth+
1728 " bottom depth "+highSZoneDepth.botDepth);
1729 }
1730 prevDepth = highSZoneDepth.botDepth;
1731 }
1732 }
1733
1734
1735 prevDepth= -1*Double.MAX_VALUE;
1736 for (int i=0;i<fluidLayerDepths.size();i++) {
1737 fluidZone = (DepthRange)fluidLayerDepths.elementAt(i);
1738 if (fluidZone.topDepth >= fluidZone.botDepth) {
1739 throw new SlownessModelException(
1740 "Fluid zone has zero or negative thickness. Num "+
1741 i+" top depth "+fluidZone.topDepth+
1742 " bottom depth "+fluidZone.botDepth);
1743 }
1744 if (fluidZone.topDepth <= prevDepth) {
1745 throw new SlownessModelException
1746 ("Fluid zone overlaps previous zone. Num "+
1747 i+" top depth "+fluidZone.topDepth+
1748 " bottom depth "+fluidZone.botDepth);
1749 }
1750 prevDepth = fluidZone.botDepth;
1751 }
1752
1753
1754 isPWave = PWAVE;
1755 double prevBotP;
1756 for (int j=0;j<2; j++, isPWave = SWAVE) {
1757
1758 prevDepth= 0.0;
1759 if (getNumLayers(isPWave) > 0) {
1760 prevBotP = getSlownessLayer(0, isPWave).getTopP();
1761 } else {
1762 prevBotP = -1;
1763 }
1764 for (int i=0;i<getNumLayers(isPWave);i++) {
1765 sLayer = getSlownessLayer(i, isPWave);
1766 isOK &= sLayer.validate();
1767
1768 if (sLayer.getTopDepth() > prevDepth) {
1769 throw new SlownessModelException(
1770 "Gap of "+(sLayer.getTopDepth()-prevDepth)+
1771 " between slowness layers. Num "+
1772 i+" isPWave="+isPWave+
1773 " top depth "+sLayer.getTopDepth()+
1774 " bottom depth "+sLayer.getBotDepth());
1775 }
1776 if (sLayer.getTopDepth() < prevDepth) {
1777 throw new SlownessModelException(
1778 "Slowness layer overlaps previous layer by "+
1779 (prevDepth-sLayer.getTopDepth())+". Num "+
1780 i+" isPWave="+isPWave+
1781 " top depth "+sLayer.getTopDepth()+
1782 " bottom depth "+sLayer.getBotDepth());
1783 }
1784 if (sLayer.getTopP() != prevBotP) {
1785 throw new SlownessModelException(
1786 "Slowness layer gap/overlaps previous layer in slowness "+
1787 ". Num "+ i+" isPWave="+isPWave+
1788 " prevBotP= "+prevBotP+
1789 " sLayer= "+sLayer);
1790 }
1791 if (Double.isNaN(sLayer.getTopDepth())) {
1792 throw new SlownessModelException(
1793 "Top depth is NaN, layerNum="+i+
1794 " waveType="+(isPWave?'P':'S'));
1795 }
1796 if (Double.isNaN(sLayer.getBotDepth())) {
1797 throw new SlownessModelException(
1798 "Top depth is NaN, layerNum="+i+
1799 " waveType="+(isPWave?'P':'S'));
1800 }
1801 prevBotP = sLayer.getBotP();
1802 prevDepth = sLayer.getBotDepth();
1803 }
1804 }
1805
1806
1807 return isOK;
1808 }
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948 public Object clone() {
1949 SlownessModel newObject;
1950 try {
1951 newObject = (SlownessModel)super.clone();
1952
1953 newObject.criticalDepthVector = new Vector(criticalDepthVector.size());
1954 for (int i=0;i<criticalDepthVector.size();i++) {
1955 newObject.criticalDepthVector.addElement(
1956 ((CriticalDepth)criticalDepthVector.elementAt(i)).clone());
1957 }
1958
1959 newObject.highSlownessLayerDepthsP =
1960 new Vector(highSlownessLayerDepthsP.size());
1961 for (int i=0;i<highSlownessLayerDepthsP.size();i++) {
1962 newObject.highSlownessLayerDepthsP.addElement(
1963 ((DepthRange)highSlownessLayerDepthsP.elementAt(i)).clone());
1964 }
1965
1966 newObject.highSlownessLayerDepthsS =
1967 new Vector(highSlownessLayerDepthsS.size());
1968 for (int i=0;i<highSlownessLayerDepthsS.size();i++) {
1969 newObject.highSlownessLayerDepthsS.addElement(
1970 ((DepthRange)highSlownessLayerDepthsS.elementAt(i)).clone());
1971 }
1972
1973 newObject.fluidLayerDepths = new Vector(fluidLayerDepths.size());
1974 for (int i=0;i<fluidLayerDepths.size();i++) {
1975 newObject.fluidLayerDepths.addElement(
1976 ((DepthRange)fluidLayerDepths.elementAt(i)).clone());
1977 }
1978
1979 newObject.PLayers = new Vector(getNumLayers(PWAVE));
1980 for (int i=0;i<getNumLayers(PWAVE);i++) {
1981 newObject.PLayers.addElement( getSlownessLayerClone(i, PWAVE));
1982 }
1983
1984 newObject.SLayers = new Vector(getNumLayers(SWAVE));
1985 for (int i=0;i<getNumLayers(SWAVE);i++) {
1986 newObject.SLayers.addElement( getSlownessLayerClone(i, SWAVE));
1987 }
1988 return newObject;
1989
1990 } catch (CloneNotSupportedException e) {
1991
1992 System.err.println("Caught CloneNotSupportedException: "+
1993 e.getMessage());
1994 throw new InternalError(e.toString());
1995 }
1996
1997 }
1998
1999 public String toString() {
2000 int topCriticalLayerNum;
2001 int botCriticalLayerNum;
2002 String desc = "";
2003
2004 desc = "radiusOfEarth="+radiusOfEarth+
2005 "\n maxDeltaP="+maxDeltaP+
2006 "\n minDeltaP="+minDeltaP+
2007 "\n maxDepthInterval="+maxDepthInterval+
2008 "\n maxRangeInterval="+maxRangeInterval+
2009 "\n allowInnerCoreS="+allowInnerCoreS+
2010 "\n slownessTolerance="+slownessTolerance+
2011 "\n getNumLayers('P')="+getNumLayers(PWAVE)+
2012 "\n getNumLayers('S')="+getNumLayers(SWAVE)+
2013 "\n fluidLayerDepths.size()="+fluidLayerDepths.size()+
2014 "\n highSlownessLayerDepthsP.size()="+
2015 highSlownessLayerDepthsP.size()+
2016 "\n highSlownessLayerDepthsS.size()="+
2017 highSlownessLayerDepthsS.size()+
2018 "\n criticalDepthVector.size()="+criticalDepthVector.size()+
2019 "\n";
2020
2021 if (criticalDepthVector.size()!=0) {
2022 desc += ("**** Critical Depth Layers ************************\n");
2023 botCriticalLayerNum =
2024 ((CriticalDepth)criticalDepthVector.elementAt(0)).velLayerNum-1;
2025 for (int criticalNum=1;criticalNum<criticalDepthVector.size();
2026 criticalNum++) {
2027 topCriticalLayerNum = botCriticalLayerNum+1;
2028 botCriticalLayerNum =
2029 ((CriticalDepth)criticalDepthVector.elementAt(criticalNum)).velLayerNum-1;
2030 desc += " "+topCriticalLayerNum+","+botCriticalLayerNum;
2031 }
2032 }
2033 desc += "\n";
2034
2035 if (fluidLayerDepths.size()!=0) {
2036 desc+="\n**** Fluid Layer Depths ************************\n";
2037 for (int i=0;i<fluidLayerDepths.size();i++) {
2038 desc+=((DepthRange)fluidLayerDepths.elementAt(i)).topDepth+","+
2039 ((DepthRange)fluidLayerDepths.elementAt(i)).botDepth+" ";
2040 }
2041 }
2042 desc += "\n";
2043
2044 if (highSlownessLayerDepthsP.size()!=0) {
2045 desc+="\n**** P High Slowness Layer Depths ****************\n";
2046 for (int i=0;i<highSlownessLayerDepthsP.size();i++) {
2047 desc+=((DepthRange)highSlownessLayerDepthsP.elementAt(i)).topDepth+","+
2048 ((DepthRange)highSlownessLayerDepthsP.elementAt(i)).botDepth+" ";
2049 }
2050 }
2051 desc += "\n";
2052
2053 if (highSlownessLayerDepthsS.size()!=0) {
2054 desc+="\n**** S High Slowness Layer Depths ****************\n";
2055 for (int i=0;i<highSlownessLayerDepthsS.size();i++) {
2056 desc+=((DepthRange)highSlownessLayerDepthsS.elementAt(i)).topDepth+","+
2057 ((DepthRange)highSlownessLayerDepthsS.elementAt(i)).botDepth+" ";
2058 }
2059 }
2060 desc += "\n";
2061
2062 return desc;
2063 }
2064 }
2065