1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package edu.sc.seis.TauP;
18
19 import java.io.BufferedInputStream;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.InvalidClassException;
27 import java.io.ObjectInputStream;
28 import java.io.ObjectOutputStream;
29 import java.io.OptionalDataException;
30 import java.io.OutputStream;
31 import java.io.Serializable;
32 import java.io.StreamCorruptedException;
33 import java.io.StreamTokenizer;
34
35 /***
36 * provides storage all of the TauBranch's comprising a model.
37 *
38 * @version 1.1.3 Wed Jul 18 15:00:35 GMT 2001
39 * @author H. Philip Crotwell
40 */
41 public class TauModel implements Serializable, Cloneable {
42
43 /*** True to enable debugging output. */
44 transient public boolean DEBUG = false;
45
46 /*** True if this is a spherical slowness model. False if flat. */
47 public boolean spherical = true;
48
49 /*** Depth for which tau model was constructed. */
50 protected double sourceDepth = 0.0;
51
52 /*** Branch with the source at its top. */
53 protected int sourceBranch = 0;
54
55 /***
56 * Depths that should not have reflections or phase conversions. For
57 * instance, if the source is not at a branch boundary then noDisconDepths
58 * contains source depth and reflections and phase conversions are not
59 * allowed at this branch boundary. If the source happens to fall on a real
60 * discontinuity then then it is not included.
61 */
62 protected double[] noDisconDepths = new double[0];
63
64 /*** Depth of the moho. */
65 protected double mohoDepth;
66
67 /*** Branch with the moho at its top. */
68 protected int mohoBranch;
69
70 /*** Depth of the cmb. */
71 protected double cmbDepth;
72
73 /*** Branch with the cmb at its top. */
74 protected int cmbBranch;
75
76 /*** Depth of the iocb. */
77 protected double iocbDepth;
78
79 /*** Branch with the iocb at its top. */
80 protected int iocbBranch;
81
82 /*** Radius of the Earth in km, usually input from the velocity model. */
83 protected double radiusOfEarth = 6371.0;
84
85 /***
86 * The slowness model that was used to generate the tau model. This in
87 * needed in order to modify the tau branches from a surface focus event to
88 * an event at depth. This is normally be set when the tau model is
89 * generated to be a clone of the slowness model.
90 */
91 public SlownessModel sMod;
92
93 /***
94 * ray parameters used to construct the tau branches. This may only be a
95 * subset of the slownesses/ray parameters saved in the slowness model due
96 * to high slowness zones (low velocity zones).
97 */
98 protected double[] rayParams;
99
100 /***
101 * 2D Array containing a TauBranch object corresponding to each "branch" of
102 * the tau model, 0 is P and 1 is S. Branches correspond to depth regions
103 * between discontinuities or reversals in slowness gradient for a wave
104 * type. Each branch contains time, distance, and tau increments for each
105 * ray parameter in rayParams for the layer. Rays that turn above the branch
106 * layer are assigned 0.0 time, distance, and tau increments.
107 */
108 public TauBranch[][] tauBranches = new TauBranch[2][];
109
110
111
112 /*** @returns the name of the earth model used to construct the tau model. */
113 public String getModelName() {
114 return sMod.vMod.getModelName();
115 }
116
117 public SlownessModel getSlownessModel() {
118 return sMod;
119 }
120
121 public VelocityModel getVelocityModel() {
122 return sMod.vMod;
123 }
124
125 /*** @returns depth for which tau model was constructed. */
126 public double getSourceDepth() {
127 return sourceDepth;
128 }
129
130 /*** @returns branch number with the source at its top. */
131 public int getSourceBranch() {
132 return sourceBranch;
133 }
134
135 /***
136 * Branches, such as the branch with the source at its top, that are not
137 * allowed to have reflections and phase conversions at their tops.
138 */
139 public double[] getNoDisconDepths() {
140 return noDisconDepths;
141 }
142
143 /***
144 * Does the given branch number have a noDisconDepth at its top? We test
145 * against PWave Tau branches (ie true) since S is the same.
146 */
147 public boolean isNoDisconBranch(int branchNum) {
148 for(int i = 0; i < noDisconDepths.length; i++) {
149 if(noDisconDepths[i] == getTauBranch(branchNum, true).getTopDepth()) { return true; }
150 }
151 return false;
152 }
153
154 /***
155 * Is the given depth a "noDisconDepth"?
156 */
157 public boolean isNoDisconDepth(double noDisconDepth) {
158 for(int i = 0; i < noDisconDepths.length; i++) {
159 if(noDisconDepths[i] == noDisconDepth) { return true; }
160 }
161 return false;
162 }
163
164 public synchronized void setNoDisconDepths(double[] noDisconDepths) {
165 this.noDisconDepths = noDisconDepths;
166 }
167
168 public synchronized void appendNoDisconDepth(double noDisconDepth) {
169 double[] temp = new double[noDisconDepths.length + 1];
170 System.arraycopy(noDisconDepths, 0, temp, 0, noDisconDepths.length);
171 noDisconDepths = temp;
172 noDisconDepths[noDisconDepths.length - 1] = noDisconDepth;
173 }
174
175 /*** @returns depth of the moho. */
176 public double getMohoDepth() {
177 return mohoDepth;
178 }
179
180 /*** @returns branch number with the moho at its top. */
181 public int getMohoBranch() {
182 return mohoBranch;
183 }
184
185 /*** @returns depth of the cmb. */
186 public double getCmbDepth() {
187 return cmbDepth;
188 }
189
190 /*** @returns branch number with the cmb at its top. */
191 public int getCmbBranch() {
192 return cmbBranch;
193 }
194
195 /*** @returns depth of the iocb. */
196 public double getIocbDepth() {
197 return iocbDepth;
198 }
199
200 /*** @returns branch number with the iocb at its top. */
201 public int getIocbBranch() {
202 return iocbBranch;
203 }
204
205 /***
206 * @returns the radius of the Earth in km, usually input from the velocity
207 * model.
208 */
209 public double getRadiusOfEarth() {
210 return radiusOfEarth;
211 }
212
213 /***
214 * @returns an array, cloned, of the ray parameters used to construct the
215 * tau branches. This may only be a subset of the slownesses/ray
216 * parameters saved in the slowness model due to high slowness
217 * zones (low velocity zones).
218 */
219 public double[] getRayParams() {
220 return (double[])rayParams.clone();
221 }
222
223 public double getOneRayParam(int i) {
224 return rayParams[i];
225 }
226
227 public int getNumBranches() {
228 return tauBranches[0].length;
229 }
230
231 public TauBranch getTauBranch(int branchNum, boolean isPWave) {
232 if(isPWave) {
233 return tauBranches[0][branchNum];
234 } else {
235 return tauBranches[1][branchNum];
236 }
237 }
238
239 /***
240 * returns an array of the depths that are boundaries between branches
241 */
242 public double[] getBranchDepths() {
243 double[] branchDepths = new double[getNumBranches()];
244
245 branchDepths[0] = getTauBranch(0, true).getTopDepth();
246 for(int i = 1; i < branchDepths.length; i++) {
247 branchDepths[i] = getTauBranch(i - 1, true).getBotDepth();
248 }
249 return branchDepths;
250 }
251
252 /***
253 * returns the turning depth for a ray of given ray parameter. Note this is
254 * for a surface source, and so converted phases my give incorrect results,
255 * e.g. SKS for certain ray parameters turns within the upper part of the
256 * outer core that is a low velocity zone for P so no P wave of that ray
257 * parameter could reach the core. For layer specific turning points, see
258 * the other SlownessModel.findDepth.
259 */
260 public double findDepth(double rayParam, boolean isPWave)
261 throws TauModelException {
262 try {
263 return sMod.findDepth(rayParam, isPWave);
264 } catch(SlownessModelException e) {
265 throw new TauModelException("findDepth: caught SlownessModelException:"
266 + e.getMessage());
267 }
268 }
269
270
271 /***
272 * Calculates tau for each branch within a slowness model.
273 *
274 * @exception SlownessModelException
275 * occurs if getNumLayers() < 1 as we cannot compute a
276 * distance without a layer.
277 */
278 public void calcTauIncFrom(SlownessModel sMod)
279 throws SlownessModelException, NoSuchLayerException,
280 TauModelException, NoSuchMatPropException {
281 SlownessLayer topSLayer, botSLayer, currSLayer;
282 TimeDist timedist = new TimeDist();
283 int topCritLayerNum, botCritLayerNum;
284
285
286
287
288 if(DEBUG) {
289 System.out.println("Size of slowness model:"
290 + " sMod.getNumLayers('P') = " + sMod.getNumLayers(true)
291 + ", sMod.getNumLayers('S') = " + sMod.getNumLayers(false));
292 }
293 if(sMod.getNumLayers(true) == 0 || sMod.getNumLayers(false) == 0) { throw new SlownessModelException("Can't calculate tauInc when getNumLayers() = 0. "
294 + "I need more slowness samples."); }
295 if(!sMod.validate()) { throw new SlownessModelException("Validation failed: "
296 + "Something is wrong with the slowness model."); }
297 this.sMod = (SlownessModel)sMod.clone();
298 radiusOfEarth = sMod.getRadiusOfEarth();
299 sourceDepth = 0.0;
300 sourceBranch = 0;
301
302
303
304
305
306
307 int numBranches = sMod.getNumCriticalDepths() - 1;
308 tauBranches[0] = new TauBranch[numBranches];
309 tauBranches[1] = new TauBranch[numBranches];
310
311
312
313
314
315 int rayNum = 0;
316 double minPSoFar = sMod.getSlownessLayerClone(0, false).getTopP();
317 double[] tempRayParams = new double[2 * sMod.getNumLayers(false)
318 + sMod.getNumCriticalDepths()];
319
320 tempRayParams[rayNum] = minPSoFar;
321 rayNum++;
322 for(int layerNum = 0; layerNum < sMod.getNumLayers(false); layerNum++) {
323 currSLayer = sMod.getSlownessLayer(layerNum, false);
324
325
326
327
328
329 if(currSLayer.getTopP() < minPSoFar) {
330 tempRayParams[rayNum] = currSLayer.getTopP();
331 rayNum++;
332 minPSoFar = currSLayer.getTopP();
333 }
334
335
336
337
338
339 if(currSLayer.getBotP() < minPSoFar) {
340 tempRayParams[rayNum] = currSLayer.getBotP();
341 rayNum++;
342 minPSoFar = currSLayer.getBotP();
343 }
344 }
345
346 rayParams = new double[rayNum];
347 System.arraycopy(tempRayParams, 0, rayParams, 0, rayNum);
348 tempRayParams = null;
349 if(DEBUG) {
350 System.out.println("Number of slowness samples for tau =" + rayNum);
351 }
352 CriticalDepth topCritDepth, botCritDepth;
353 int waveNum;
354 boolean isPWave;
355 for(waveNum = 0, isPWave = true; waveNum < 2; waveNum++, isPWave = false) {
356
357 minPSoFar = sMod.getSlownessLayerClone(0, isPWave).getTopP();
358
359 for(int critNum = 0; critNum < sMod.getNumCriticalDepths() - 1; critNum++) {
360 topCritDepth = sMod.getCriticalDepth(critNum);
361 topCritLayerNum = topCritDepth.getLayerNum(isPWave);
362 botCritDepth = sMod.getCriticalDepth(critNum + 1);
363 botCritLayerNum = botCritDepth.getLayerNum(isPWave) - 1;
364 if(DEBUG) {
365 System.out.println("Calculating " + (isPWave ? "P" : "S")
366 + " tau branch for branch " + critNum
367 + " topCritLayerNum=" + topCritLayerNum
368 + " botCritLayerNum=" + botCritLayerNum
369 + "\nminPSoFar=" + minPSoFar);
370 }
371 tauBranches[waveNum][critNum] = new TauBranch(topCritDepth.depth,
372 botCritDepth.depth,
373 isPWave);
374 tauBranches[waveNum][critNum].DEBUG = DEBUG;
375 tauBranches[waveNum][critNum].createBranch(sMod,
376 minPSoFar,
377 rayParams);
378
379
380
381
382
383
384 topSLayer = sMod.getSlownessLayer(topCritLayerNum, isPWave);
385 botSLayer = sMod.getSlownessLayer(botCritLayerNum, isPWave);
386 minPSoFar = Math.min(minPSoFar, Math.min(topSLayer.getTopP(),
387 botSLayer.getBotP()));
388 botSLayer = sMod.getSlownessLayer(sMod.layerNumberAbove(botCritDepth.depth,
389 isPWave),
390 isPWave);
391 minPSoFar = Math.min(minPSoFar, botSLayer.getBotP());
392 }
393 }
394
395
396
397
398
399 double bestMoho = Double.MAX_VALUE;
400 double bestCmb = Double.MAX_VALUE;
401 double bestIocb = Double.MAX_VALUE;
402 for(int branchNum = 0; branchNum < tauBranches[0].length; branchNum++) {
403 TauBranch tBranch = (TauBranch)tauBranches[0][branchNum];
404 if(Math.abs(tBranch.getTopDepth() - sMod.vMod.getMohoDepth()) <= bestMoho) {
405 mohoBranch = branchNum;
406 bestMoho = Math.abs(tBranch.getTopDepth()
407 - sMod.vMod.getMohoDepth());
408 }
409 if(Math.abs(tBranch.getTopDepth() - sMod.vMod.getCmbDepth()) < bestCmb) {
410 cmbBranch = branchNum;
411 bestCmb = Math.abs(tBranch.getTopDepth()
412 - sMod.vMod.getCmbDepth());
413 }
414 if(Math.abs(tBranch.getTopDepth() - sMod.vMod.getIocbDepth()) < bestIocb) {
415 iocbBranch = branchNum;
416 bestIocb = Math.abs(tBranch.getTopDepth()
417 - sMod.vMod.getIocbDepth());
418 }
419 }
420
421
422
423 mohoDepth = tauBranches[0][mohoBranch].getTopDepth();
424 cmbDepth = tauBranches[0][cmbBranch].getTopDepth();
425 iocbDepth = tauBranches[0][iocbBranch].getTopDepth();
426 if(!validate()) { throw new TauModelException("calcTauIncFrom: Validation failed!"); }
427 }
428
429 /***
430 * Finds the branch that either has the depth as its top boundary, or
431 * strictly contains the depth. Also, we allow the bottommost branch to
432 * contain its bottom depth, so that the center if the earth is contained
433 * within the bottom branch.
434 */
435 public int findBranch(double depth) throws TauModelException {
436 for(int i = 0; i < tauBranches[0].length; i++) {
437 if(tauBranches[0][i].getTopDepth() <= depth
438 && tauBranches[0][i].getBotDepth() > depth) { return i; }
439 }
440
441 if(tauBranches[0][tauBranches[0].length - 1].getBotDepth() == depth) {
442 return tauBranches[0].length - 1;
443 } else {
444 throw new TauModelException("No TauBranch contains depth=" + depth);
445 }
446 }
447
448 /***
449 * Computes a new tau model for a source at depth using the previously
450 * computed branches for a surface source. No change is needed to the
451 * branches above and below the branch containing the depth, except for the
452 * addition of a slowness sample. The branch containing the source depth is
453 * split into 2 branches, and up going branch and a downgoing branch.
454 * Additionally, the slowness at the source depth must be sampled exactly as
455 * it is an extremal point for each of these branches. See Buland and
456 * Chapman p 1290.
457 */
458 public TauModel depthCorrect(double depth) throws TauModelException {
459 if(sourceDepth != 0.0) { throw new TauModelException("depthCorrect: Can't depth correct "
460 + "a tau model that is not for a surface source."); }
461 if(depth > getCmbDepth()) { throw new TauModelException("depthCorrect: Can't depth correct "
462 + "for a depth in the core."); }
463 TauModel tMod = splitBranch(depth);
464 tMod.sourceDepth = depth;
465 tMod.sourceBranch = tMod.findBranch(depth);
466 validate();
467 return tMod;
468 }
469
470 /***
471 * returns a new TauModel with the branches containing depth split at depth.
472 * Used for putting a source at depth since a source can only be located on
473 * a branch boundary.
474 */
475 public TauModel splitBranch(double depth) throws TauModelException {
476 TauModel tMod;
477 int topCritLayerNum, botCritLayerNum;
478 SlownessLayer topSLayer, botSLayer;
479 try {
480 tMod = (TauModel)clone();
481
482
483
484
485 for(int branchNum = 0; branchNum < tMod.tauBranches[0].length; branchNum++) {
486 if(tMod.tauBranches[0][branchNum].getTopDepth() == depth
487 || tMod.tauBranches[0][branchNum].getBotDepth() == depth) { return tMod; }
488 }
489
490
491
492 int indexP = -1;
493 double PWaveRayParam = -1.0;
494 int indexS = -1;
495 double SWaveRayParam = -1.0;
496 int waveNum;
497 boolean isPWave;
498 SplitLayerInfo splitInfo;
499
500
501
502
503
504 for(waveNum = 1, isPWave = false; waveNum >= 0; waveNum--, isPWave = true) {
505 splitInfo = tMod.sMod.splitLayer(depth, isPWave);
506 if(splitInfo.movedSample) {} else if(splitInfo.neededSplit) {
507
508
509
510
511 int layerNum = tMod.sMod.layerNumberAbove(depth, isPWave);
512 SlownessLayer sLayer = tMod.sMod.getSlownessLayer(layerNum,
513 isPWave);
514 double newRayParam = splitInfo.getRayParam();
515 int index = -1;
516
517
518
519 for(int i = 0; i < tMod.rayParams.length - 1; i++) {
520 if(tMod.rayParams[i] < newRayParam
521 && tMod.rayParams[i + 1] > newRayParam) {
522 index = i;
523 double[] oldRayParams = tMod.rayParams;
524 tMod.rayParams = new double[oldRayParams.length + 1];
525 System.arraycopy(oldRayParams,
526 0,
527 tMod.rayParams,
528 0,
529 index);
530 tMod.rayParams[index] = newRayParam;
531 System.arraycopy(oldRayParams,
532 index,
533 tMod.rayParams,
534 index + 1,
535 oldRayParams.length - index);
536 if(isPWave) {
537 indexP = index;
538 PWaveRayParam = newRayParam;
539 } else {
540 indexS = index;
541 SWaveRayParam = newRayParam;
542 }
543 break;
544 }
545 }
546 }
547 }
548
549
550
551
552
553 int branchToSplit = tMod.findBranch(depth);
554 int topCritLayerNumP, botCritLayerNumP;
555 int topCritLayerNumS, botCritLayerNumS;
556 int splitLayerNumP, splitLayerNumS;
557 TauBranch[][] newtauBranches = new TauBranch[2][tMod.getNumBranches() + 1];
558 for(int i = 0; i < branchToSplit; i++) {
559 newtauBranches[0][i] = (TauBranch)tMod.tauBranches[0][i].clone();
560 newtauBranches[1][i] = (TauBranch)tMod.tauBranches[1][i].clone();
561 topCritLayerNumP = tMod.sMod.layerNumberBelow(newtauBranches[0][i].getTopDepth(),
562 true);
563 botCritLayerNumP = tMod.sMod.layerNumberAbove(newtauBranches[0][i].getBotDepth(),
564 true);
565 topCritLayerNumS = tMod.sMod.layerNumberBelow(newtauBranches[1][i].getTopDepth(),
566 false);
567 botCritLayerNumS = tMod.sMod.layerNumberAbove(newtauBranches[1][i].getBotDepth(),
568 false);
569 if(indexS != -1) {
570
571
572 newtauBranches[0][i].insert(SWaveRayParam,
573 tMod.sMod,
574 indexS);
575 newtauBranches[1][i].insert(SWaveRayParam,
576 tMod.sMod,
577 indexS);
578 }
579 if(indexP != -1) {
580
581
582 newtauBranches[0][i].insert(PWaveRayParam,
583 tMod.sMod,
584 indexP);
585 newtauBranches[1][i].insert(PWaveRayParam,
586 tMod.sMod,
587 indexP);
588 }
589 }
590 tMod.appendNoDisconDepth(depth);
591 topCritLayerNumS = tMod.sMod.layerNumberBelow(tMod.tauBranches[1][branchToSplit].getTopDepth(),
592 false);
593 splitLayerNumS = tMod.sMod.layerNumberAbove(depth, false);
594 newtauBranches[1][branchToSplit] = new TauBranch(tMod.tauBranches[1][branchToSplit].getTopDepth(),
595 depth,
596 false);
597 newtauBranches[1][branchToSplit].createBranch(tMod.sMod,
598 tMod.tauBranches[1][branchToSplit].getMaxRayParam(),
599 tMod.rayParams);
600 newtauBranches[1][branchToSplit + 1] = tMod.tauBranches[1][branchToSplit].difference(newtauBranches[1][branchToSplit],
601 indexP,
602 indexS,
603 tMod.sMod,
604 newtauBranches[1][branchToSplit].getMinRayParam(),
605 tMod.rayParams);
606 topCritLayerNumP = tMod.sMod.layerNumberBelow(tMod.tauBranches[0][branchToSplit].getTopDepth(),
607 true);
608 splitLayerNumP = tMod.sMod.layerNumberAbove(depth, true);
609 newtauBranches[0][branchToSplit] = new TauBranch(tMod.tauBranches[0][branchToSplit].getTopDepth(),
610 depth,
611 true);
612 newtauBranches[0][branchToSplit].createBranch(tMod.sMod,
613 tMod.tauBranches[0][branchToSplit].getMaxRayParam(),
614 tMod.rayParams);
615 newtauBranches[0][branchToSplit + 1] = tMod.tauBranches[0][branchToSplit].difference(newtauBranches[0][branchToSplit],
616 indexP,
617 indexS,
618 tMod.sMod,
619 newtauBranches[0][branchToSplit].getMinRayParam(),
620 tMod.rayParams);
621 for(int i = branchToSplit + 1; i < tMod.tauBranches[0].length; i++) {
622 newtauBranches[1][i + 1] = tMod.tauBranches[1][i];
623 newtauBranches[0][i + 1] = tMod.tauBranches[0][i];
624 if(indexS != -1) {
625
626
627 newtauBranches[0][i + 1].insert(SWaveRayParam,
628 tMod.sMod,
629 indexS);
630 newtauBranches[1][i + 1].insert(SWaveRayParam,
631 tMod.sMod,
632 indexS);
633 }
634 if(indexP != -1) {
635
636
637 newtauBranches[0][i + 1].insert(PWaveRayParam,
638 tMod.sMod,
639 indexP);
640 newtauBranches[1][i + 1].insert(PWaveRayParam,
641 tMod.sMod,
642 indexP);
643 }
644 }
645 tMod.tauBranches = newtauBranches;
646
647
648
649
650 if(tMod.sourceDepth > depth) tMod.sourceBranch++;
651 if(tMod.mohoDepth > depth) tMod.mohoBranch++;
652 if(tMod.cmbDepth > depth) tMod.cmbBranch++;
653 if(tMod.iocbDepth > depth) tMod.iocbBranch++;
654 if(!tMod.validate()) { throw new TauModelException("splitBranch("
655 + depth + "): Validation failed!"); }
656 } catch(NoSuchLayerException e) {
657 throw new TauModelException("TauModel.depthCorrect - "
658 + "NoSuchLayerException", e);
659 } catch(SlownessModelException e) {
660 e.printStackTrace();
661 throw new TauModelException("TauModel.depthCorrect - "
662 + "SlownessModelException", e);
663 } finally {}
664 return tMod;
665 }
666
667 public void writeModel(String filename) throws IOException {
668 FileOutputStream fOut = new FileOutputStream(filename);
669 ObjectOutputStream out = new ObjectOutputStream(fOut);
670 try {
671 out.writeObject(this);
672 } finally {
673 out.close();
674 fOut.close();
675 }
676 }
677
678 public void writeModelToStream(OutputStream outStream) throws IOException {
679 ObjectOutputStream out = new ObjectOutputStream(outStream);
680 out.writeObject(this);
681 }
682
683 public static TauModel readModel(String filename)
684 throws FileNotFoundException, IOException,
685 StreamCorruptedException, ClassNotFoundException,
686 OptionalDataException {
687 TauModel tMod;
688 BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename));
689 try {
690 tMod = readModelFromStream(in);
691 } finally {
692 in.close();
693 }
694 return tMod;
695 }
696
697 public static TauModel readModelFromStream(InputStream inStream)
698 throws InvalidClassException, IOException,
699 StreamCorruptedException, ClassNotFoundException,
700 OptionalDataException {
701 ObjectInputStream in = new ObjectInputStream(inStream);
702 TauModel tMod = (TauModel)in.readObject();
703 return tMod;
704 }
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746 public boolean validate() {
747 for(int i = 0; i < rayParams.length - 1; i++) {
748 if(rayParams[i + 1] >= rayParams[i]) {
749 System.err.println("RayParams are not monotonically decreasing. "
750 + "rayParams["
751 + i
752 + "]="
753 + rayParams[i]
754 + " rayParams[" + (i + 1) + "]=" + rayParams[(i + 1)]);
755 return false;
756 }
757 }
758 if(tauBranches[0].length != tauBranches[1].length) {
759 System.err.println("TauBranches for P and S are not equal. "
760 + tauBranches[0].length + " " + tauBranches[1].length);
761 return false;
762 }
763 if(tauBranches[0][0].getTopDepth() != 0 || tauBranches[1][0].getTopDepth() != 0) {
764 System.err.println("branch 0 topDepth != 0");
765 return false;
766 }
767
768 if(tauBranches[1][0].getMaxRayParam() != rayParams[0]) {
769 System.err.println("branch 0 maxRayParam != rayParams[0]");
770 return false;
771 }
772 for(int i = 1; i < getNumBranches(); i++) {
773 if(tauBranches[0][i].getTopDepth() != tauBranches[1][i].getTopDepth()) {
774 System.err.println("branch " + i + " P topDepth != S topDepth");
775 return false;
776 }
777 if(tauBranches[0][i].getBotDepth() != tauBranches[1][i].getBotDepth()) {
778 System.err.println("branch " + i + " P botDepth != S botDepth");
779 return false;
780 }
781 if(tauBranches[0][i].getTopDepth() != tauBranches[0][i - 1].getBotDepth()) {
782 System.err.println("branch " + i + " topDepth != botDepth of "
783 + (i - 1));
784 return false;
785 }
786 if(tauBranches[0][i].getMaxRayParam() != tauBranches[0][i - 1].getMinRayParam()) {
787 System.err.println("branch " + i
788 + " P maxRayParam != minRayParam of " + (i - 1)
789 + "\nmaxRayParam=" + tauBranches[0][i].getMaxRayParam()
790 + "\nminRayParam=" + tauBranches[0][i - 1].getMinRayParam());
791 return false;
792 }
793 if(tauBranches[1][i].getMaxRayParam() != tauBranches[1][i - 1].getMinRayParam()) {
794 System.err.println("branch " + i
795 + " S maxRayParam != minRayParam of " + (i - 1)
796 + "\nmaxRayParam=" + tauBranches[1][i].getMaxRayParam()
797 + "\nminRayParam=" + tauBranches[1][i - 1].getMinRayParam()
798 + "\ndepth = " + tauBranches[1][i].getTopDepth());
799 return false;
800 }
801 }
802 if(tauBranches[0][getNumBranches() - 1].getMinRayParam() != 0) {
803 System.err.println("branch tauBranches[0].length-1 minRayParam != 0");
804 return false;
805 }
806 if(tauBranches[1][getNumBranches() - 1].getMinRayParam() != 0) {
807 System.err.println("branch tauBranches[1].length-1 minRayParam != 0");
808 return false;
809 }
810 return true;
811 }
812
813 public void print() {
814 double deg, time;
815 if(DEBUG) System.out.println("Starting print() in TauModel");
816 System.out.println("Delta tau for each slowness sample and layer.");
817 for(int j = 0; j < rayParams.length; j++) {
818 deg = 0;
819 time = 0;
820 for(int i = 0; i < getNumBranches(); i++) {
821 deg += tauBranches[0][i].getDist(j) * 180 / Math.PI;
822 time += tauBranches[0][i].time[j];
823 System.out.println(" i " + i + " j " + j + " rayParam "
824 + rayParams[j] + " tau " + tauBranches[0][i].tau[j]
825 + " time " + tauBranches[0][i].time[j] + " dist "
826 + tauBranches[0][i].getDist(j) + " degrees "
827 + (tauBranches[0][i].getDist(j) * 180 / Math.PI));
828 }
829 System.out.println();
830 System.out.println("deg= " + deg + " time=" + time);
831 }
832 }
833
834 /***
835 * Returns a clone of the tau model so that changes to the clone do not
836 * affect the original.
837 */
838 public Object clone() {
839 TauModel newObject;
840 try {
841 newObject = (TauModel)super.clone();
842 newObject.rayParams = (double[])rayParams.clone();
843 newObject.sMod = (SlownessModel)sMod.clone();
844 newObject.tauBranches = new TauBranch[2][getNumBranches()];
845 for(int i = 0; i < getNumBranches(); i++) {
846 newObject.tauBranches[0][i] = (TauBranch)tauBranches[0][i].clone();
847 newObject.tauBranches[1][i] = (TauBranch)tauBranches[1][i].clone();
848 }
849 return newObject;
850 } catch(CloneNotSupportedException e) {
851
852 System.err.println("Caught CloneNotSupportedException: "
853 + e.getMessage());
854 throw new InternalError(e.toString());
855 }
856 }
857
858 public String toString() {
859 if(DEBUG) System.out.println("Starting toString() in TauModel");
860 String desc = "Delta tau for each slowness sample and layer.\n";
861 for(int j = 0; j < rayParams.length; j++) {
862 for(int i = 0; i < tauBranches[0].length; i++) {
863 desc += " i " + i + " j " + j + " rayParam " + rayParams[j]
864 + " tau " + tauBranches[0][i].tau[j] + " time "
865 + tauBranches[0][i].time[j] + " dist "
866 + tauBranches[0][i].getDist(j) + " degrees "
867 + (tauBranches[0][i].getDist(j) * 180 / Math.PI) + "\n";
868 }
869 desc += "\n";
870 }
871 return desc;
872 }
873
874 public static void main(String[] args) {
875 VelocityModel vMod = new VelocityModel();
876 SphericalSModel sMod = new SphericalSModel();
877 TauModel tMod = new TauModel();
878 int branch, rayNum;
879 String modelFilename;
880 if(args.length == 1) {
881 modelFilename = args[0];
882 } else {
883 modelFilename = "iasp91.tvel";
884 }
885 boolean DEBUG = false;
886 try {
887 vMod.setFileType("tvel");
888 vMod.readVelocityFile(modelFilename);
889 System.out.println("Done reading.");
890 sMod.createSample(vMod);
891 tMod.calcTauIncFrom(sMod);
892 StreamTokenizer tokenIn = new StreamTokenizer(new InputStreamReader(System.in));
893 tokenIn.parseNumbers();
894 System.out.println("Enter branch rayNum");
895 tokenIn.nextToken();
896 while(tokenIn.ttype == StreamTokenizer.TT_NUMBER) {
897 branch = (int)tokenIn.nval;
898 tokenIn.nextToken();
899 rayNum = (int)tokenIn.nval;
900 System.out.println("ray parameter=" + tMod.rayParams[rayNum]
901 + " distance="
902 + tMod.tauBranches[0][branch].getDist(rayNum) + " time="
903 + tMod.tauBranches[0][branch].time[rayNum] + " tau="
904 + tMod.tauBranches[0][branch].tau[rayNum]);
905 System.out.println("Enter branch rayNum");
906 tokenIn.nextToken();
907 }
908 } catch(IOException e) {
909 System.out.println("Tried to read!\n Caught IOException "
910 + e.getMessage());
911 } catch(VelocityModelException e) {
912 System.out.println("Tried to read!\n Caught VelocityModelException "
913 + e.getMessage());
914 } catch(SlownessModelException e) {
915 System.out.println("Caught SlownessModelException "
916 + e.getMessage());
917 e.printStackTrace();
918 } catch(TauModelException e) {
919 System.out.println("Caught TauModelException " + e.getMessage());
920 e.printStackTrace();
921 } finally {
922 System.out.println("Done!\n");
923 }
924 }
925 }