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.FileNotFoundException;
20 import java.io.IOException;
21 import java.io.OptionalDataException;
22 import java.io.Serializable;
23 import java.io.StreamCorruptedException;
24 import java.util.Vector;
25
26 /***
27 * Stores and transforms seismic phase names to and from their corresponding
28 * sequence of branches.
29 *
30 * @version 1.1.3 Wed Jul 18 15:00:35 GMT 2001
31 * @author H. Philip Crotwell
32 */
33 public class SeismicPhase implements Serializable, Cloneable {
34
35 /*** Enables debugging output. */
36 public transient boolean DEBUG = false;
37
38 /*** Enables verbose output. */
39 public transient boolean verbose = false;
40
41 /*** TauModel to generate phase for. */
42 protected TauModel tMod;
43
44 /***
45 * Used by addToBranch when the path turns within a segment. We assume that
46 * no ray will turn downward so turning implies turning from downward to
47 * upward, ie U.
48 */
49 protected static final int TURN = 0;
50
51 /***
52 * Used by addToBranch when the path reflects off the top of the end of a
53 * segment, ie ^.
54 */
55 protected static final int REFLECTTOP = 1;
56
57 /***
58 * Used by addToBranch when the path reflects off the bottom of the end of a
59 * segment, ie v.
60 */
61 protected static final int REFLECTBOT = 2;
62
63 /***
64 * Used by addToBranch when the path transmits up through the end of a
65 * segment.
66 */
67 protected static final int TRANSUP = 3;
68
69 /***
70 * Used by addToBranch when the path transmits down through the end of a
71 * segment.
72 */
73 protected static final int TRANSDOWN = 4;
74
75 /***
76 * The maximum degrees that a Pn or Sn can refract along the moho. Note this
77 * is not the total distance, only the segment along the moho. The default
78 * is 20 degrees.
79 */
80 protected double maxRefraction = 20;
81
82 /***
83 * The maximum degrees that a Pdiff or Sdiff can diffract along the CMB.
84 * Note this is not the total distance, only the segment along the CMB. The
85 * default is 60 degrees.
86 */
87 protected double maxDiffraction = 60;
88
89 /***
90 * The source depth within the TauModel that was used to generate this
91 * phase.
92 */
93 protected double sourceDepth;
94
95 /***
96 * Array of distances corresponding to the ray parameters stored in
97 * rayParams.
98 */
99 protected double[] dist = new double[0];
100
101 /***
102 * Array of times corresponding to the ray parameters stored in rayParams.
103 */
104 protected double[] time = new double[0];
105
106 /*** Array of possible ray parameters for this phase. */
107 protected double[] rayParams = new double[0];
108
109 /*** Minimum ray parameter that exists for this phase. */
110 protected double minRayParam;
111
112 /*** Maximum ray parameter that exists for this phase. */
113 protected double maxRayParam;
114
115 /***
116 * Index within TauModel.rayParams that corresponds to maxRayParam. Note
117 * that maxRayParamIndex < minRayParamIndex as ray parameter decreases with
118 * increasing index.
119 */
120 protected int maxRayParamIndex = -1;
121
122 /***
123 * Index within TauModel.rayParams that corresponds to minRayParam. Note
124 * that maxRayParamIndex < minRayParamIndex as ray parameter decreases with
125 * increasing index.
126 */
127 protected int minRayParamIndex = -1;
128
129 /*** The minimum distance that this phase can be theoretically observed. */
130 protected double minDistance = 0.0;
131
132 /*** The maximum distance that this phase can be theoretically observed. */
133 protected double maxDistance = Double.MAX_VALUE;
134
135 /***
136 * Vector holding all arrivals for this phase at the given distance. They
137 * are stored as Arrival objects.
138 *
139 * @see Arrival
140 * @see calcTime(double)
141 * @see calcPierce(TauModel)
142 * @see calcPath(TauModel)
143 */
144 protected Vector arrivals = new Vector();
145
146 /***
147 * Array of branch numbers for the given phase. Note that this depends upon
148 * both the earth model and the source depth.
149 */
150 protected Vector branchSeq = new Vector();
151
152 /*** The phase name, ie PKiKP. */
153 protected String name;
154
155 /***
156 * name with depths corrected to be actuall discontinuities in the model.
157 */
158 protected String puristName;
159
160 /*** Vector containing Strings for each leg. */
161 protected Vector legs = new Vector();
162
163 /***
164 * temporary branch number so we know where to start add to the branch
165 * sequence. Used in addToBranch() and parseName().
166 */
167 protected transient int currBranch;
168
169 /***
170 * temporary end action so we know what we did at the end of the last
171 * section of the branch sequence. Used in addToBranch() and parseName().
172 */
173 protected transient int endAction;
174
175 /***
176 * records the end action for the current leg. Will be one of
177 * SeismicPhase.TURN, SeismicPhase.TRANSDOWN, SeismicPhase.TRANSUP,
178 * SeismicPhase.REFLECTBOT, or SeismicPhase.REFLECTTOP. This allows a check
179 * to make sure the path is correct. Used in addToBranch() and parseName().
180 */
181 protected Vector legAction = new Vector();
182
183 /***
184 * true if the current leg of the phase is down going. This allows a check
185 * to make sure the path is correct. Used in addToBranch() and parseName().
186 */
187 protected Vector downGoing = new Vector();
188
189 /***
190 * Vector of wave types corresponding to each leg of the phase.
191 *
192 * @see legs
193 */
194 protected Vector waveType = new Vector();
195
196 public static final boolean PWAVE = true;
197
198 public static final boolean SWAVE = false;
199
200
201
202 /***
203 * @param phaseName
204 * String containing a name of the phase.
205 * @param tMod
206 * Tau model to be used to construct the phase.
207 */
208 public SeismicPhase(String name, TauModel tMod) {
209 this.name = name;
210 this.sourceDepth = tMod.sourceDepth;
211 this.tMod = tMod;
212 }
213
214
215 public boolean hasArrivals() {
216 if(arrivals.size() > 0) {
217 return true;
218 } else {
219 return false;
220 }
221 }
222
223 /*** Returns arrival time array. */
224 public Arrival[] getArrivals() {
225 Arrival[] returnArrivals = new Arrival[arrivals.size()];
226 for(int i = 0; i < arrivals.size(); i++) {
227 returnArrivals[i] = (Arrival)((Arrival)arrivals.elementAt(i));
228 }
229 return returnArrivals;
230 }
231
232 public void setTauModel(TauModel tMod) throws TauModelException {
233 this.tMod = tMod;
234 init();
235 }
236
237 public TauModel getTauModel() {
238 return tMod;
239 }
240
241 public void setDEBUG(boolean DEBUG) {
242 this.DEBUG = DEBUG;
243 }
244
245 public double getMinDistance() {
246 return minDistance;
247 }
248
249 public double getMaxDistance() {
250 return maxDistance;
251 }
252
253 public double getMaxRayParam() {
254 return maxRayParam;
255 }
256
257 public double getMinRayParam() {
258 return minRayParam;
259 }
260
261 public int getMaxRayParamIndex() {
262 return maxRayParamIndex;
263 }
264
265 public int getMinRayParamIndex() {
266 return minRayParamIndex;
267 }
268
269 public double getMaxDiffraction() {
270 return maxDiffraction;
271 }
272
273 public void setMaxDiffraction(double maxDiffraction) {
274 this.maxDiffraction = maxDiffraction;
275 }
276
277 public String getName() {
278 return name;
279 }
280
281 public String getPuristName() {
282 return name;
283 }
284
285 public String[] getLegs() {
286 String[] legsArray = new String[legs.size()];
287 for(int i = 0; i < legs.size(); i++) {
288 legsArray[i] = (String)legs.elementAt(i);
289 }
290 return legsArray;
291 }
292
293 public double[] getRayParams() {
294 return (double[])rayParams.clone();
295 }
296
297 public double[] getDist() {
298 return (double[])dist.clone();
299 }
300
301 public double[] getTime() {
302 return (double[])time.clone();
303 }
304
305 public double[] getTau() {
306 double[] tau = new double[dist.length];
307 for(int i = 0; i < dist.length; i++) {
308 tau[i] = time[i] - rayParams[i] * dist[i];
309 }
310 return tau;
311 }
312
313
314 public void init() throws TauModelException {
315 legPuller();
316 createPuristName(tMod);
317 parseName(tMod);
318 sumBranches(tMod);
319 }
320
321 /*** calculates arrival times for this phase. */
322 public void calcTime(double deg) {
323 double tempDeg = deg;
324 if(tempDeg < 0.0) {
325 tempDeg *= -1.0;
326 }
327 while(tempDeg > 360.0) {
328 tempDeg -= 360.0;
329 }
330 if(tempDeg > 180.0) {
331 tempDeg = 360.0 - tempDeg;
332 }
333
334 double radDist = tempDeg * Math.PI / 180.0;
335 arrivals.removeAllElements();
336
337
338
339
340
341
342
343
344 int n = 0;
345 Arrival newArrival;
346 double searchDist;
347 while(n * 2.0 * Math.PI + radDist <= maxDistance) {
348
349
350
351
352 searchDist = n * 2.0 * Math.PI + radDist;
353 for(int rayNum = 0; rayNum < (dist.length - 1); rayNum++) {
354 if(searchDist == dist[rayNum + 1]
355 && rayNum + 1 != dist.length - 1) {
356
357 continue;
358 } else if((dist[rayNum] - searchDist)
359 * (searchDist - dist[rayNum + 1]) >= 0.0) {
360
361 if((rayParams[rayNum] == rayParams[rayNum + 1])
362 && rayParams.length > 2) {
363
364
365
366
367 continue;
368 }
369 if(DEBUG) {
370 System.err.println("SeismicPhase " + name
371 + ", found arrival:\n" + "dist "
372 + (float)(180 / Math.PI * dist[rayNum]) + " "
373 + (float)(180 / Math.PI * searchDist) + " "
374 + (float)(180 / Math.PI * dist[rayNum + 1]));
375 }
376 double arrivalTime = (searchDist - dist[rayNum])
377 / (dist[rayNum + 1] - dist[rayNum])
378 * (time[rayNum + 1] - time[rayNum]) + time[rayNum];
379 double arrivalRayParam = (searchDist - dist[rayNum + 1])
380 * (rayParams[rayNum] - rayParams[rayNum + 1])
381 / (dist[rayNum] - dist[rayNum + 1])
382 + rayParams[rayNum + 1];
383 newArrival = new Arrival(this,
384 arrivalTime,
385 searchDist,
386 arrivalRayParam,
387 rayNum,
388 name,
389 puristName,
390 sourceDepth);
391 arrivals.addElement(newArrival);
392 }
393 }
394
395
396
397
398 searchDist = (n + 1) * 2.0 * Math.PI - radDist;
399 if(tempDeg != 180) {
400 for(int rayNum = 0; rayNum < (dist.length - 1); rayNum++) {
401 if(searchDist == dist[rayNum + 1]
402 && rayNum + 1 != dist.length - 1) {
403
404 continue;
405 } else if((dist[rayNum] - searchDist)
406 * (searchDist - dist[rayNum + 1]) >= 0.0) {
407 if((rayParams[rayNum] == rayParams[rayNum + 1])
408 && rayParams.length > 2) {
409
410
411
412
413 continue;
414 }
415 if(DEBUG) {
416 System.err.println("SeismicPhase " + name
417 + ", found arrival:\n" + "dist "
418 + (float)(180 / Math.PI * dist[rayNum])
419 + " " + (float)(180 / Math.PI * searchDist)
420 + " "
421 + (float)(180 / Math.PI * dist[rayNum + 1]));
422 }
423 double arrivalTime = (searchDist - dist[rayNum])
424 / (dist[rayNum + 1] - dist[rayNum])
425 * (time[rayNum + 1] - time[rayNum])
426 + time[rayNum];
427 double arrivalRayParam = (searchDist - dist[rayNum])
428 * (rayParams[rayNum + 1] - rayParams[rayNum])
429 / (dist[rayNum + 1] - dist[rayNum])
430 + rayParams[rayNum];
431 newArrival = new Arrival(this,
432 arrivalTime,
433 searchDist,
434 arrivalRayParam,
435 rayNum,
436 name,
437 puristName,
438 sourceDepth);
439 arrivals.addElement(newArrival);
440 }
441 }
442 }
443 n++;
444 }
445 }
446
447 /***
448 * changes maxRayParam and minRayParam whenever there is a phase conversion.
449 * For instance, SKP needs to change the maxRayParam because there are SKS
450 * ray parameters that cannot propagate from the cmb into the mantle as a p
451 * wave.
452 */
453 protected void phaseConversion(TauModel tMod,
454 int fromBranch,
455 int endAction,
456 boolean isPtoS) throws TauModelException {
457 if(endAction == TURN) {
458
459 throw new TauModelException("Illegal endAction: endAction="
460 + endAction
461 + "\nphase conversion are not allowed at turn points.");
462 } else if(endAction == REFLECTTOP) {
463 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(fromBranch,
464 isPtoS)
465 .getMaxRayParam());
466 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(fromBranch,
467 !isPtoS)
468 .getMaxRayParam());
469 } else if(endAction == REFLECTBOT) {
470 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(fromBranch,
471 isPtoS)
472 .getMinTurnRayParam());
473 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(fromBranch,
474 !isPtoS)
475 .getMinTurnRayParam());
476 } else if(endAction == TRANSUP) {
477 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(fromBranch,
478 isPtoS)
479 .getMaxRayParam());
480 maxRayParam = Math.min(maxRayParam,
481 tMod.getTauBranch(fromBranch - 1, !isPtoS)
482 .getMinTurnRayParam());
483 } else if(endAction == TRANSDOWN) {
484 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(fromBranch,
485 isPtoS)
486 .getMinRayParam());
487 maxRayParam = Math.min(maxRayParam,
488 tMod.getTauBranch(fromBranch + 1, !isPtoS)
489 .getMaxRayParam());
490 } else {
491 throw new TauModelException("Illegal endAction: endAction="
492 + endAction);
493 }
494 }
495
496
497
498
499
500
501
502 protected void addToBranch(TauModel tMod,
503 int startBranch,
504 int endBranch,
505 boolean isPWave,
506 int endAction) throws TauModelException {
507 int endOffset;
508 boolean isDownGoing;
509 this.endAction = endAction;
510 if(DEBUG) {
511 System.out.print("start=" + startBranch + " end=" + endBranch
512 + " endOffset=");
513 if(endAction == TURN) {
514 System.out.println("TURN");
515 } else if(endAction == REFLECTTOP) {
516 System.out.println("REFLECTTOP");
517 } else if(endAction == REFLECTBOT) {
518 System.out.println("REFLECTBOT");
519 } else if(endAction == TRANSUP) {
520 System.out.println("TRANSUP");
521 } else if(endAction == TRANSDOWN) {
522 System.out.println("TRANSDOWN");
523 } else {
524 System.out.println(endAction);
525 }
526 }
527 if(endAction == TURN) {
528 endOffset = 0;
529 isDownGoing = true;
530 minRayParam = Math.max(minRayParam, tMod.getTauBranch(endBranch,
531 isPWave)
532 .getMinTurnRayParam());
533 } else if(endAction == REFLECTTOP) {
534 endOffset = 0;
535 isDownGoing = false;
536 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(endBranch,
537 isPWave)
538 .getMaxRayParam());
539 } else if(endAction == REFLECTBOT) {
540 endOffset = 0;
541 isDownGoing = true;
542 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(endBranch,
543 isPWave)
544 .getMinTurnRayParam());
545 } else if(endAction == TRANSUP) {
546 endOffset = -1;
547 isDownGoing = false;
548 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(endBranch,
549 isPWave)
550 .getMaxRayParam());
551 } else if(endAction == TRANSDOWN) {
552 endOffset = 1;
553 isDownGoing = true;
554 maxRayParam = Math.min(maxRayParam, tMod.getTauBranch(endBranch,
555 isPWave)
556 .getMinRayParam());
557 } else {
558 throw new TauModelException("Illegal endAction: endAction="
559 + endAction);
560 }
561 if(isDownGoing) {
562
563 for(int i = startBranch; i <= endBranch; i++) {
564 branchSeq.addElement(new Integer(i));
565 downGoing.addElement(new Boolean(isDownGoing));
566 waveType.addElement(new Boolean(isPWave));
567 legAction.addElement(new Integer(endAction));
568 }
569 if(DEBUG) {
570 for(int i = startBranch; i <= endBranch; i++) {
571 System.out.println("i=" + i + " isDownGoing=" + isDownGoing
572 + " isPWave=" + isPWave + " startBranch="
573 + startBranch + " endBranch=" + endBranch + " "
574 + endAction);
575 }
576 }
577 } else {
578
579 for(int i = startBranch; i >= endBranch; i--) {
580 branchSeq.addElement(new Integer(i));
581 downGoing.addElement(new Boolean(isDownGoing));
582 waveType.addElement(new Boolean(isPWave));
583 legAction.addElement(new Integer(endAction));
584 }
585 if(DEBUG) {
586 for(int i = startBranch; i >= endBranch; i--) {
587 System.out.println("i=" + i + " isDownGoing=" + isDownGoing
588 + " isPWave=" + isPWave + " startBranch="
589 + startBranch + " endBranch=" + endBranch + " "
590 + endAction);
591 }
592 }
593 }
594 currBranch = endBranch + endOffset;
595 }
596
597 /***
598 * Finds the closest discontinuity to the given depth that can have
599 * refletions and phase transformations.
600 *
601 * @returns the branch number with the closest top depth.
602 */
603 public int closestBranchToDepth(TauModel tMod, String depthString) {
604 if(depthString.equals("m")) {
605 return tMod.getMohoBranch();
606 } else if(depthString.equals("c")) {
607 return tMod.getCmbBranch();
608 } else if(depthString.equals("i")) { return tMod.getIocbBranch(); }
609
610 int disconBranch = -1;
611 double disconMax = Double.MAX_VALUE;
612 double disconDepth = (Double.valueOf(depthString)).doubleValue();
613 TauBranch tBranch;
614 for(int i = 0; i < tMod.getNumBranches(); i++) {
615 tBranch = tMod.getTauBranch(i, PWAVE);
616 if(Math.abs(disconDepth - tBranch.getTopDepth()) < disconMax
617 && !tMod.isNoDisconDepth(tBranch.getTopDepth())) {
618 disconBranch = i;
619 disconMax = Math.abs(disconDepth - tBranch.getTopDepth());
620 }
621 }
622 return disconBranch;
623 }
624
625 /***
626 * Constructs a branch sequence from the given phase name and tau model.
627 */
628 protected void parseName(TauModel tMod) throws TauModelException {
629 String prevLeg;
630 String currLeg = (String)legs.elementAt(0);
631 String nextLeg = currLeg;
632 branchSeq.removeAllElements();
633 boolean isDownGoing;
634 boolean isPWave = PWAVE;
635 boolean isPWavePrev = isPWave;
636
637
638
639
640 if(legs.size() == 2 && currLeg.endsWith("kmps")) { return; }
641
642 if(name.indexOf('J') != -1 && !tMod.sMod.isAllowInnerCoreS()) { throw new TauModelException("'J' phases were not created for this model: "
643 + name); }
644
645 if(currLeg.equals("p") || currLeg.startsWith("P")
646 || currLeg.equals("K") || currLeg.equals("I")) {
647 isPWave = PWAVE;
648 isPWavePrev = isPWave;
649 } else if(currLeg.equals("s") || currLeg.startsWith("S")
650 || currLeg.equals("J")) {
651 isPWave = SWAVE;
652 isPWavePrev = isPWave;
653 }
654
655
656
657
658
659
660 if(currLeg.startsWith("P") || currLeg.startsWith("S")) {
661
662 currBranch = tMod.getSourceBranch();
663 isDownGoing = true;
664 endAction = REFLECTBOT;
665
666 } else if(currLeg.equals("p") || currLeg.equals("s")) {
667
668 isDownGoing = false;
669 endAction = REFLECTTOP;
670
671 if(tMod.getSourceBranch() != 0) {
672 currBranch = tMod.getSourceBranch() - 1;
673 } else {
674
675
676
677
678 maxRayParam = -1;
679 minRayParam = -1;
680 return;
681 }
682 } else {
683 throw new TauModelException("First phase not recognized: "
684 + currLeg
685 + " must be one of P, Pg, Pn, Pdiff, p or the S equivalents");
686 }
687
688
689
690
691 if(tMod.getSourceBranch() != 0) {
692 maxRayParam = Math.max(tMod.getTauBranch(tMod.getSourceBranch() - 1,
693 isPWave)
694 .getMinTurnRayParam(),
695 tMod.getTauBranch(tMod.getSourceBranch(),
696 isPWave).getMaxRayParam());
697 } else {
698 maxRayParam = tMod.getTauBranch(tMod.getSourceBranch(), isPWave)
699 .getMaxRayParam();
700 }
701 minRayParam = 0.0;
702 int disconBranch = 0;
703 double legDepth, nextLegDepth = 0.0;
704 boolean isLegDepth, isNextLegDepth = false;
705 endAction = TRANSDOWN;
706
707
708
709
710 currLeg = "START";
711 for(int legNum = 0; legNum < legs.size() - 1; legNum++) {
712 prevLeg = currLeg;
713 currLeg = nextLeg;
714 nextLeg = (String)legs.elementAt(legNum + 1);
715 if(DEBUG) {
716 System.out.println(legNum + " " + prevLeg + " " + currLeg
717 + " " + nextLeg);
718 }
719 legDepth = nextLegDepth;
720 isLegDepth = isNextLegDepth;
721
722 try {
723 nextLegDepth = (new Double(nextLeg)).doubleValue();
724 isNextLegDepth = true;
725 } catch(NumberFormatException e) {
726 nextLegDepth = -1;
727 isNextLegDepth = false;
728 }
729
730 isPWavePrev = isPWave;
731 if(currLeg.equals("p") || currLeg.startsWith("P")
732 || currLeg.equals("I")) {
733 isPWave = PWAVE;
734 } else if(currLeg.equals("s") || currLeg.startsWith("S")
735 || currLeg.equals("J")) {
736 isPWave = SWAVE;
737 } else if(currLeg.equals("K")) {
738
739
740
741
742
743
744
745
746
747 }
748
749 if(branchSeq.size() > 0 && isPWavePrev != isPWave) {
750 phaseConversion(tMod,
751 ((Integer)branchSeq.elementAt(branchSeq.size() - 1)).intValue(),
752 endAction,
753 isPWavePrev);
754 }
755
756 if(currLeg.equals("p") || currLeg.equals("s")) {
757 if(nextLeg.startsWith("v")) {
758 throw new TauModelException("p and s must always be up going "
759 + " and cannot come immediately before a top-side reflection."
760 + " currLeg=" + currLeg + " nextLeg=" + nextLeg);
761 } else if(nextLeg.startsWith("^")) {
762 disconBranch = closestBranchToDepth(tMod,
763 nextLeg.substring(1));
764 if(currBranch >= disconBranch) {
765 addToBranch(tMod,
766 currBranch,
767 disconBranch,
768 isPWave,
769 REFLECTTOP);
770 } else {
771 throw new TauModelException("Phase not recognized: "
772 + currLeg + " followed by " + nextLeg
773 + " when currBranch=" + currBranch
774 + " > disconBranch=" + disconBranch);
775 }
776 } else if(nextLeg.equals("m")
777 && currBranch >= tMod.getMohoBranch()) {
778 addToBranch(tMod,
779 currBranch,
780 tMod.getMohoBranch(),
781 isPWave,
782 TRANSUP);
783 } else if(nextLeg.startsWith("P") || nextLeg.startsWith("S")
784 || nextLeg.equals("END")) {
785 addToBranch(tMod, currBranch, 0, isPWave, REFLECTTOP);
786 } else if(isNextLegDepth) {
787 disconBranch = closestBranchToDepth(tMod, nextLeg);
788 addToBranch(tMod,
789 currBranch,
790 disconBranch,
791 isPWave,
792 TRANSUP);
793 } else {
794 throw new TauModelException("Phase not recognized: "
795 + currLeg + " followed by " + nextLeg);
796 }
797
798 } else if(currLeg.equals("P") || currLeg.equals("S")) {
799 if(nextLeg.equals("P") || nextLeg.equals("S")
800 || nextLeg.equals("Pn") || nextLeg.equals("Sn")
801 || nextLeg.equals("END")) {
802 if(endAction == TRANSDOWN || endAction == REFLECTTOP) {
803
804 addToBranch(tMod,
805 currBranch,
806 tMod.getCmbBranch() - 1,
807 isPWave,
808 TURN);
809 }
810 addToBranch(tMod, currBranch, 0, isPWave, REFLECTTOP);
811 } else if(nextLeg.startsWith("v")) {
812 disconBranch = closestBranchToDepth(tMod,
813 nextLeg.substring(1));
814 if(currBranch <= disconBranch - 1) {
815 addToBranch(tMod,
816 currBranch,
817 disconBranch - 1,
818 isPWave,
819 REFLECTBOT);
820 } else {
821 throw new TauModelException("Phase not recognized: "
822 + currLeg + " followed by " + nextLeg
823 + " when currBranch=" + currBranch
824 + " < disconBranch=" + disconBranch);
825 }
826 } else if(nextLeg.startsWith("^")) {
827 disconBranch = closestBranchToDepth(tMod,
828 nextLeg.substring(1));
829 if(prevLeg.equals("K")) {
830 addToBranch(tMod,
831 currBranch,
832 disconBranch,
833 isPWave,
834 REFLECTTOP);
835 } else if(prevLeg.startsWith("^") || prevLeg.equals("P")
836 || prevLeg.equals("S") || prevLeg.equals("p")
837 || prevLeg.equals("s") || prevLeg.equals("START")) {
838 addToBranch(tMod,
839 currBranch,
840 tMod.getCmbBranch() - 1,
841 isPWave,
842 TURN);
843 addToBranch(tMod,
844 currBranch,
845 disconBranch,
846 isPWave,
847 REFLECTTOP);
848 } else if((prevLeg.startsWith("v") && disconBranch < closestBranchToDepth(tMod,
849 prevLeg.substring(1)))
850 || (prevLeg.equals("m") && disconBranch < tMod.getMohoBranch())
851 || (prevLeg.equals("c") && disconBranch < tMod.getCmbBranch())) {
852 addToBranch(tMod,
853 currBranch,
854 disconBranch,
855 isPWave,
856 REFLECTTOP);
857 } else {
858 throw new TauModelException("Phase not recognized: "
859 + currLeg + " followed by " + nextLeg
860 + " when currBranch=" + currBranch
861 + " > disconBranch=" + disconBranch);
862 }
863 } else if(nextLeg.equals("c")) {
864 addToBranch(tMod,
865 currBranch,
866 tMod.getCmbBranch() - 1,
867 isPWave,
868 REFLECTBOT);
869 } else if(nextLeg.equals("K")) {
870 addToBranch(tMod,
871 currBranch,
872 tMod.getCmbBranch() - 1,
873 isPWave,
874 TRANSDOWN);
875 } else if(nextLeg.equals("m")
876 || (isNextLegDepth && nextLegDepth < tMod.getCmbDepth())) {
877
878
879 disconBranch = closestBranchToDepth(tMod, nextLeg);
880 if(DEBUG) {
881 System.out.println("DisconBranch=" + disconBranch
882 + " for " + nextLeg);
883 System.out.println(tMod.getTauBranch(disconBranch,
884 isPWave)
885 .getTopDepth());
886 }
887 if(endAction == TURN || endAction == REFLECTBOT
888 || endAction == TRANSUP) {
889
890 if(disconBranch > currBranch) {
891
892
893 throw new TauModelException("Phase not recognized: "
894 + currLeg
895 + " followed by "
896 + nextLeg
897 + " when currBranch="
898 + currBranch
899 + " > disconBranch=" + disconBranch);
900 }
901 addToBranch(tMod,
902 currBranch,
903 disconBranch,
904 isPWave,
905 TRANSUP);
906 } else {
907
908
909
910
911
912 String nextNextLeg = (String)legs.elementAt(legNum + 2);
913 if(nextNextLeg.equals("p") || nextNextLeg.equals("s")) {
914
915 addToBranch(tMod,
916 currBranch,
917 tMod.getCmbBranch() - 1,
918 isPWave,
919 TURN);
920 addToBranch(tMod,
921 currBranch,
922 disconBranch,
923 isPWave,
924 TRANSUP);
925 } else if(nextNextLeg.equals("P")
926 || nextNextLeg.equals("S")) {
927 if(disconBranch > currBranch) {
928
929 addToBranch(tMod,
930 currBranch,
931 disconBranch - 1,
932 isPWave,
933 TRANSDOWN);
934 } else {
935
936
937
938 maxRayParam = -1;
939 if(DEBUG) {
940 System.out.println("Cannot phase convert on the "
941 + "downgoing side if the discontinuity is above "
942 + "the phase leg starting point, "
943 + currLeg
944 + " "
945 + nextLeg
946 + " "
947 + nextNextLeg
948 + ", so this phase, "
949 + getName()
950 + " is illegal for this sourceDepth.");
951 }
952 return;
953 }
954 } else {
955 throw new TauModelException("Phase not recognized: "
956 + currLeg
957 + " followed by "
958 + nextLeg
959 + " followed by " + nextNextLeg);
960 }
961 }
962 } else {
963 throw new TauModelException("Phase not recognized: "
964 + currLeg + " followed by " + nextLeg);
965 }
966 } else if(currLeg.startsWith("P") || currLeg.startsWith("S")) {
967 if(currLeg.equals("Pdiff") || currLeg.equals("Sdiff")) {
968
969
970
971
972
973 if(maxRayParam >= tMod.getTauBranch(tMod.getCmbBranch() - 1,
974 isPWave)
975 .getMinTurnRayParam()
976 && minRayParam <= tMod.getTauBranch(tMod.getCmbBranch() - 1,
977 isPWave)
978 .getMinTurnRayParam()) {
979 addToBranch(tMod,
980 currBranch,
981 tMod.getCmbBranch() - 1,
982 isPWave,
983 TURN);
984 maxRayParam = minRayParam;
985 if(nextLeg.equals("END")) {
986 addToBranch(tMod,
987 currBranch,
988 0,
989 isPWave,
990 REFLECTTOP);
991 }
992 } else {
993
994 maxRayParam = -1;
995 if(DEBUG) {
996 System.out.println("Cannot have the head wave "
997 + currLeg + " within phase " + name
998 + " for this sourceDepth and/or path.");
999 }
1000 return;
1001 }
1002 } else if(currLeg.equals("Pg") || currLeg.equals("Sg")
1003 || currLeg.equals("Pn") || currLeg.equals("Sn")) {
1004 if(currBranch >= tMod.getMohoBranch()) {
1005
1006
1007
1008
1009
1010
1011 maxRayParam = -1;
1012 if(DEBUG) {
1013 System.out.println("(currBranch >= tMod.getMohoBranch() "
1014 + currBranch
1015 + " "
1016 + tMod.getMohoBranch()
1017 + " so there cannot be a "
1018 + currLeg
1019 + " phase for this sourceDepth and/or path.");
1020 }
1021 return;
1022 }
1023 if(currLeg.equals("Pg") || currLeg.equals("Sg")) {
1024 addToBranch(tMod,
1025 currBranch,
1026 tMod.getMohoBranch() - 1,
1027 isPWave,
1028 TURN);
1029 addToBranch(tMod, currBranch, 0, isPWave, REFLECTTOP);
1030 } else if(currLeg.equals("Pn") || currLeg.equals("Sn")) {
1031
1032
1033
1034
1035
1036
1037 if(maxRayParam >= tMod.getTauBranch(tMod.getMohoBranch(),
1038 isPWave)
1039 .getMaxRayParam()
1040 && minRayParam <= tMod.getTauBranch(tMod.getMohoBranch(),
1041 isPWave)
1042 .getMaxRayParam()) {
1043 addToBranch(tMod,
1044 currBranch,
1045 tMod.getMohoBranch(),
1046 isPWave,
1047 TURN);
1048 addToBranch(tMod,
1049 currBranch,
1050 tMod.getMohoBranch(),
1051 isPWave,
1052 TRANSUP);
1053 minRayParam = maxRayParam;
1054 if(nextLeg.equals("END") || nextLeg.startsWith("P")
1055 || nextLeg.startsWith("S")) {
1056 addToBranch(tMod,
1057 currBranch,
1058 0,
1059 isPWave,
1060 REFLECTTOP);
1061 }
1062 } else {
1063
1064
1065 maxRayParam = -1;
1066 if(DEBUG) {
1067 System.out.println("Cannot have the head wave "
1068 + currLeg + " within phase " + name
1069 + " for this sourceDepth and/or path.");
1070 }
1071 return;
1072 }
1073 }
1074 } else {
1075 throw new TauModelException("Phase not recognized: "
1076 + currLeg + " followed by " + nextLeg);
1077 }
1078 } else if(currLeg.equals("K")) {
1079
1080 if(nextLeg.equals("P") || nextLeg.equals("S")) {
1081 if(prevLeg.equals("P") || prevLeg.equals("S")
1082 || prevLeg.equals("K")) {
1083 addToBranch(tMod,
1084 currBranch,
1085 tMod.getIocbBranch() - 1,
1086 isPWave,
1087 TURN);
1088 }
1089 addToBranch(tMod,
1090 currBranch,
1091 tMod.getCmbBranch(),
1092 isPWave,
1093 TRANSUP);
1094 } else if(nextLeg.equals("K")) {
1095 if(prevLeg.equals("P") || prevLeg.equals("S")
1096 || prevLeg.equals("K")) {
1097 addToBranch(tMod,
1098 currBranch,
1099 tMod.getIocbBranch() - 1,
1100 isPWave,
1101 TURN);
1102 }
1103 addToBranch(tMod,
1104 currBranch,
1105 tMod.getCmbBranch(),
1106 isPWave,
1107 REFLECTTOP);
1108 } else if(nextLeg.equals("I") || nextLeg.equals("J")) {
1109 addToBranch(tMod,
1110 currBranch,
1111 tMod.getIocbBranch() - 1,
1112 isPWave,
1113 TRANSDOWN);
1114 } else if(nextLeg.equals("i")) {
1115 addToBranch(tMod,
1116 currBranch,
1117 tMod.getIocbBranch() - 1,
1118 isPWave,
1119 REFLECTBOT);
1120 } else {
1121 throw new TauModelException("Phase not recognized: "
1122 + currLeg + " followed by " + nextLeg);
1123 }
1124 } else if(currLeg.equals("I") || currLeg.equals("J")) {
1125
1126 addToBranch(tMod,
1127 currBranch,
1128 tMod.getNumBranches() - 1,
1129 isPWave,
1130 TURN);
1131 if(nextLeg.equals("I") || nextLeg.equals("J")) {
1132 addToBranch(tMod,
1133 currBranch,
1134 tMod.getIocbBranch(),
1135 isPWave,
1136 REFLECTTOP);
1137 } else if(nextLeg.equals("K")) {
1138 addToBranch(tMod,
1139 currBranch,
1140 tMod.getIocbBranch(),
1141 isPWave,
1142 TRANSUP);
1143 }
1144 } else if(currLeg.equals("m")) {} else if(currLeg.equals("c")) {} else if(currLeg.equals("i")) {} else if(currLeg.startsWith("^")) {} else if(currLeg.startsWith("v")) {} else if(isLegDepth) {} else {
1145 throw new TauModelException("Phase not recognized: " + currLeg
1146 + " followed by " + nextLeg);
1147 }
1148 }
1149 }
1150
1151 /***
1152 * Tokenizes a phase name into legs, ie PcS becomes 'P'+'c'+'S' while p^410P
1153 * would become 'p'+'^410'+'P'. Once a phase name has been broken into
1154 * tokens we can begin to construct the sequence of branches to which it
1155 * corresponds. Only minor error checking is done at this point, for
1156 * instance PIP generates an exception but ^410 doesn't. It also appends
1157 * "END" as the last leg.
1158 *
1159 * @throws TauModelException
1160 * if the phase name cannot be tokenized.
1161 */
1162 protected void legPuller() throws TauModelException {
1163 int offset = 0;
1164 legs.removeAllElements();
1165
1166 if(name.endsWith("kmps")) {
1167 try {
1168 double vel = Double.valueOf(name.substring(0, name.length() - 4))
1169 .doubleValue();
1170 legs.addElement(name);
1171 } catch(NumberFormatException e) {
1172 throw new TauModelException("Invalid phase name:\n" + name);
1173 }
1174 } else while(offset < name.length()) {
1175 if(name.charAt(offset) == 'K' || name.charAt(offset) == 'I'
1176 || name.charAt(offset) == 'J' || name.charAt(offset) == 'p'
1177 || name.charAt(offset) == 's' || name.charAt(offset) == 'm'
1178 || name.charAt(offset) == 'c' || name.charAt(offset) == 'i') {
1179
1180 legs.addElement(name.substring(offset, offset + 1));
1181 offset = offset + 1;
1182 } else if(name.charAt(offset) == 'P' || name.charAt(offset) == 'S') {
1183
1184
1185
1186
1187 if(offset + 1 == name.length()
1188 || name.charAt(offset + 1) == 'P'
1189 || name.charAt(offset + 1) == 'S'
1190 || name.charAt(offset + 1) == 'K'
1191 || name.charAt(offset + 1) == 'p'
1192 || name.charAt(offset + 1) == 's'
1193 || name.charAt(offset + 1) == 'm'
1194 || name.charAt(offset + 1) == 'c'
1195 || name.charAt(offset + 1) == '^'
1196 || name.charAt(offset + 1) == 'v'
1197 || Character.isDigit(name.charAt(offset + 1))) {
1198 legs.addElement(name.substring(offset, offset + 1));
1199 offset++;
1200 } else if(name.charAt(offset + 1) == 'g'
1201 || name.charAt(offset + 1) == 'b'
1202 || name.charAt(offset + 1) == 'n') {
1203
1204 legs.addElement(name.substring(offset, offset + 2));
1205 offset = offset + 2;
1206 } else if(name.length() >= offset + 5
1207 && (name.substring(offset, offset + 5).equals("Sdiff") || name.substring(offset,
1208 offset + 5)
1209 .equals("Pdiff"))) {
1210 legs.addElement(name.substring(offset, offset + 5));
1211 offset = offset + 5;
1212 } else {
1213 throw new TauModelException("Invalid phase name:\n"
1214 + name.substring(offset) + " in " + name);
1215 }
1216 } else if(name.charAt(offset) == '^' || name.charAt(offset) == 'v') {
1217
1218
1219
1220
1221 if(name.charAt(offset + 1) == 'm'
1222 || name.charAt(offset + 1) == 'c'
1223 || name.charAt(offset + 1) == 'i') {
1224 legs.addElement(name.substring(offset, offset + 2));
1225 offset = offset + 2;
1226 } else if(Character.isDigit(name.charAt(offset + 1))) {
1227 int numDigits = 1;
1228 while(offset + numDigits + 1 < name.length()
1229 && Character.isDigit(name.charAt(offset + numDigits
1230 + 1))) {
1231 numDigits++;
1232 }
1233 legs.addElement(name.substring(offset, offset + numDigits
1234 + 1));
1235 offset = offset + numDigits + 1;
1236 } else {
1237 throw new TauModelException("Invalid phase name:\n"
1238 + name.substring(offset) + " in " + name);
1239 }
1240 } else if(Character.isDigit(name.charAt(offset))
1241 || name.charAt(offset) == '.') {
1242 String numString = name.substring(offset, offset + 1);
1243 offset++;
1244 while(Character.isDigit(name.charAt(offset))
1245 || name.charAt(offset) == '.') {
1246 numString += name.substring(offset, offset + 1);
1247 offset++;
1248 }
1249 try {
1250 Double d = new Double(numString);
1251 legs.addElement(numString);
1252 } catch(NumberFormatException e) {
1253 throw new TauModelException("Invalid phase name: "
1254 + numString + "\n" + e.getMessage() + " in " + name);
1255 }
1256 } else {
1257 throw new TauModelException("Invalid phase name:\n"
1258 + name.substring(offset) + " in " + name);
1259 }
1260 }
1261 legs.addElement(new String("END"));
1262 if(!phaseValidate()) { throw new TauModelException("Phase failed validation: "
1263 + name); }
1264 }
1265
1266 protected void createPuristName(TauModel tMod) {
1267 String currLeg = (String)legs.elementAt(0);
1268
1269
1270
1271
1272 if(legs.size() == 2 && currLeg.endsWith("kmps")) {
1273 puristName = name;
1274 return;
1275 }
1276 puristName = "";
1277 double legDepth;
1278 int intLegDepth;
1279 int disconBranch;
1280
1281 for(int legNum = 0; legNum < legs.size() - 1; legNum++) {
1282 currLeg = (String)legs.elementAt(legNum);
1283
1284
1285 if(currLeg.startsWith("v") || currLeg.startsWith("^")) {
1286 disconBranch = closestBranchToDepth(tMod, currLeg.substring(1));
1287 legDepth = tMod.getTauBranch(disconBranch, true).getTopDepth();
1288 puristName += currLeg.substring(0, 1);
1289 if(legDepth == Math.rint(legDepth)) {
1290 intLegDepth = (int)legDepth;
1291 puristName += intLegDepth;
1292 } else {
1293 puristName += legDepth;
1294 }
1295 } else {
1296 try {
1297 legDepth = (new Double(currLeg)).doubleValue();
1298
1299
1300 disconBranch = closestBranchToDepth(tMod, currLeg);
1301 legDepth = tMod.getTauBranch(disconBranch, true)
1302 .getTopDepth();
1303 if(legDepth == Math.rint(legDepth)) {
1304 intLegDepth = (int)legDepth;
1305 puristName += intLegDepth;
1306 } else {
1307 puristName += legDepth;
1308 }
1309 } catch(NumberFormatException e) {
1310 puristName += currLeg;
1311 }
1312 }
1313 }
1314 }
1315
1316 /***
1317 * Sums the appropriate branches for this phase.
1318 *
1319 * @throws TauModelException
1320 * if the topDepth of the high slowness zone is not contained
1321 * within the TauModel. This should never happen and would
1322 * indicate an invalid TauModel.
1323 */
1324 protected void sumBranches(TauModel tMod) throws TauModelException {
1325 if(maxRayParam < 0.0 || minRayParam > maxRayParam) {
1326
1327 rayParams = new double[0];
1328 minRayParam = -1;
1329 maxRayParam = -1;
1330 dist = new double[0];
1331 time = new double[0];
1332 maxDistance