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.BufferedOutputStream;
20 import java.io.BufferedWriter;
21 import java.io.DataOutputStream;
22 import java.io.FileNotFoundException;
23 import java.io.FileOutputStream;
24 import java.io.FileReader;
25 import java.io.IOException;
26 import java.io.InputStreamReader;
27 import java.io.InvalidClassException;
28 import java.io.OptionalDataException;
29 import java.io.OutputStreamWriter;
30 import java.io.StreamCorruptedException;
31 import java.io.StreamTokenizer;
32 import java.io.Writer;
33 import java.util.ArrayList;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Properties;
37 import java.util.Vector;
38 import org.apache.log4j.BasicConfigurator;
39
40 /***
41 * Calculate travel times for different branches using linear interpolation
42 * between known slowness samples.
43 *
44 * @version 1.1.3 Wed Jul 18 15:00:35 GMT 2001
45 * @author H. Philip Crotwell
46 */
47 public class TauP_Time {
48
49 /*** Turns on debugging output. */
50 public boolean DEBUG = false;
51
52 /*** Turns on verbose output. */
53 public boolean verbose = false;
54
55 protected String modelName = "iasp91";
56
57 /***
58 * Tau model calculated previously.
59 *
60 * @see TauModel
61 */
62 protected TauModel tMod;
63
64 /***
65 * TauModel derived from tMod by correcting it for a non-surface source.
66 */
67 protected transient TauModel tModDepth;
68
69 /***
70 * vector to hold the SeismicPhases for the phases named in phaseNames.
71 */
72 protected Vector phases = new Vector(10);
73
74 /*** names of phases to be used, ie PKIKP. */
75 protected Vector phaseNames = new Vector(10);
76
77 protected double depth = 0.0;
78
79 protected double degrees = Double.MAX_VALUE;
80
81 protected double azimuth = Double.MAX_VALUE;
82
83 protected double backAzimuth = Double.MAX_VALUE;
84
85 protected double stationLat = Double.MAX_VALUE;
86
87 protected double stationLon = Double.MAX_VALUE;
88
89 protected double eventLat = Double.MAX_VALUE;
90
91 protected double eventLon = Double.MAX_VALUE;
92
93 protected Vector arrivals = new Vector(10);
94
95 protected boolean GUI = false;
96
97 protected boolean onlyPrintRayP = false;
98
99 protected boolean onlyPrintTime = false;
100
101 protected String outFile = "";
102
103 protected DataOutputStream dos;
104
105 protected Properties toolProps;
106
107 protected Outputs outForms;
108
109
110 public TauP_Time() {
111 try {
112 toolProps = PropertyLoader.load();
113 } catch(Exception e) {
114 Alert.warning("Unable to load properties, using defaults.",
115 e.getMessage());
116 toolProps = new Properties();
117 }
118 outForms = new Outputs(toolProps);
119 }
120
121 public TauP_Time(TauModel tMod) throws TauModelException {
122 this();
123 this.tMod = tMod;
124 this.tModDepth = tMod;
125 modelName = tMod.sMod.vMod.getModelName();
126 }
127
128 /***
129 * creates a TauP_Time object with the tau model specified by modelName
130 * already loaded.
131 *
132 * @throws TauModelException
133 * if the file can't be found or is corrupted in some way.
134 */
135 public TauP_Time(String modelName) throws TauModelException {
136 this();
137 try {
138 loadTauModel(modelName);
139 } catch(FileNotFoundException e) {
140 throw new TauModelException("FileNotFoundException:"
141 + e.getMessage(), e);
142 } catch(InvalidClassException e) {
143 throw new TauModelException("InvalidClassException:"
144 + e.getMessage(), e);
145 } catch(StreamCorruptedException e) {
146 throw new TauModelException("StreamCorruptedException:"
147 + e.getMessage(), e);
148 } catch(OptionalDataException e) {
149 throw new TauModelException("OptionalDataException:"
150 + e.getMessage(), e);
151 } catch(IOException e) {
152 throw new TauModelException("IOException:" + e.getMessage(), e);
153 }
154 }
155
156
157 public String[] getPhaseNames() {
158 String[] phases = new String[phaseNames.size()];
159 for(int i = 0; i < phaseNames.size(); i++) {
160 phases[i] = ((PhaseName)phaseNames.elementAt(i)).getName();
161 }
162 return phases;
163 }
164
165 public String getPhaseNameString() {
166
167 if(getNumPhases() == 0) return "";
168 String phases = ((PhaseName)phaseNames.elementAt(0)).getName();
169 for(int i = 1; i < getNumPhases(); i++) {
170 phases += "," + ((PhaseName)phaseNames.elementAt(i)).getName();
171 }
172 return phases;
173 }
174
175 public void setPhaseNames(String[] phaseNames) {
176 this.phaseNames.removeAllElements();
177 for(int i = 0; i < phaseNames.length; i++) {
178 appendPhaseName(phaseNames[i]);
179 }
180 }
181
182 public void setPhaseNames(PhaseName[] phaseNames) {
183 this.phaseNames.removeAllElements();
184 for(int i = 0; i < phaseNames.length; i++) {
185 this.phaseNames.addElement(phaseNames[i]);
186 }
187 }
188
189 public static List getPhaseNames(String phaseName) {
190 List names = new ArrayList();
191 if(phaseName.equalsIgnoreCase("ttp")
192 || phaseName.equalsIgnoreCase("tts")
193 || phaseName.equalsIgnoreCase("ttbasic")
194 || phaseName.equalsIgnoreCase("tts+")
195 || phaseName.equalsIgnoreCase("ttp+")
196 || phaseName.equalsIgnoreCase("ttall")) {
197 if(phaseName.equalsIgnoreCase("ttp")
198 || phaseName.equalsIgnoreCase("ttp+")
199 || phaseName.equalsIgnoreCase("ttbasic")
200 || phaseName.equalsIgnoreCase("ttall")) {
201 names.add("p");
202 names.add("P");
203 names.add("Pn");
204 names.add("Pdiff");
205 names.add("PKP");
206 names.add("PKiKP");
207 names.add("PKIKP");
208 }
209 if(phaseName.equalsIgnoreCase("tts")
210 || phaseName.equalsIgnoreCase("tts+")
211 || phaseName.equalsIgnoreCase("ttbasic")
212 || phaseName.equalsIgnoreCase("ttall")) {
213 names.add("s");
214 names.add("S");
215 names.add("Sn");
216 names.add("Sdiff");
217 names.add("SKS");
218 names.add("SKIKS");
219 }
220 if(phaseName.equalsIgnoreCase("ttp+")
221 || phaseName.equalsIgnoreCase("ttbasic")
222 || phaseName.equalsIgnoreCase("ttall")) {
223 names.add("PcP");
224 names.add("pP");
225 names.add("pPdiff");
226 names.add("pPKP");
227 names.add("pPKIKP");
228 names.add("pPKiKP");
229 names.add("sP");
230 names.add("sPdiff");
231 names.add("sPKP");
232 names.add("sPKIKP");
233 names.add("sPKiKP");
234 }
235 if(phaseName.equalsIgnoreCase("tts+")
236 || phaseName.equalsIgnoreCase("ttbasic")
237 || phaseName.equalsIgnoreCase("ttall")) {
238 names.add("sS");
239 names.add("sSdiff");
240 names.add("sSKS");
241 names.add("sSKIKS");
242 names.add("ScS");
243 names.add("pS");
244 names.add("pSdiff");
245 names.add("pSKS");
246 names.add("pSKIKS");
247 }
248 if(phaseName.equalsIgnoreCase("ttbasic")
249 || phaseName.equalsIgnoreCase("ttall")) {
250 names.add("ScP");
251 names.add("SKP");
252 names.add("SKIKP");
253 names.add("PKKP");
254 names.add("PKIKKIKP");
255 names.add("SKKP");
256 names.add("SKIKKIKP");
257 names.add("PP");
258 names.add("PKPPKP");
259 names.add("PKIKPPKIKP");
260 }
261 if(phaseName.equalsIgnoreCase("ttall")) {
262 names.add("SKiKP");
263 names.add("PP");
264 names.add("ScS");
265 names.add("PcS");
266 names.add("PKS");
267 names.add("PKIKS");
268 names.add("PKKS");
269 names.add("PKIKKIKS");
270 names.add("SKKS");
271 names.add("SKIKKIKS");
272 names.add("SKSSKS");
273 names.add("SKIKSSKIKS");
274 names.add("SS");
275 names.add("SP");
276 names.add("PS");
277 }
278 } else {
279 names.add(phaseName);
280 }
281 return names;
282 }
283
284 public synchronized void appendPhaseName(String phaseName) {
285 List names = getPhaseNames(phaseName);
286 Iterator it = names.iterator();
287 while(it.hasNext()) {
288 appendPhaseName(new PhaseName((String)it.next()));
289 }
290 }
291
292 public synchronized void appendPhaseName(PhaseName phaseName) {
293 boolean unique = true;
294 if(phaseName.name == null || phaseName.name.length() == 0) {
295
296 return;
297 }
298 for(int i = 0; i < phaseNames.size(); i++) {
299 if(((PhaseName)phaseNames.elementAt(i)).equals(phaseName)) {
300 unique = false;
301 return;
302 }
303 }
304 if(unique) {
305 this.phaseNames.addElement(phaseName);
306 }
307 }
308
309 public int getNumPhases() {
310 return phaseNames.size();
311 }
312
313 public void clearPhaseNames() {
314 phases.removeAllElements();
315 phaseNames.removeAllElements();
316 }
317
318 public double getSourceDepth() {
319 return Double.valueOf(toolProps.getProperty("taup.source.depth", "0.0"))
320 .doubleValue();
321 }
322
323 public void setSourceDepth(double depth) {
324 this.depth = depth;
325 toolProps.put("taup.source.depth", Double.toString(depth));
326 }
327
328 public String getTauModelName() {
329 return modelName;
330 }
331
332 public TauModel getTauModel() {
333 return tMod;
334 }
335
336 public void setTauModel(TauModel tMod) {
337 this.tMod = tMod;
338 this.tModDepth = tMod;
339 modelName = tMod.sMod.vMod.getModelName();
340 toolProps.put("taup.model.name", modelName);
341 }
342
343 public void loadTauModel(String modelName) throws FileNotFoundException,
344 InvalidClassException, IOException, StreamCorruptedException,
345 OptionalDataException, TauModelException {
346 this.modelName = modelName;
347 readTauModel();
348 this.modelName = tMod.sMod.vMod.getModelName();
349 }
350
351 public double[] getDisconDepths() {
352 return tMod.sMod.vMod.getDisconDepths();
353 }
354
355 public void clearArrivals() {
356 arrivals.removeAllElements();
357 }
358
359 public int getNumArrivals() {
360 return arrivals.size();
361 }
362
363 public Arrival getArrival(int i) {
364 return (Arrival)((Arrival)arrivals.elementAt(i)).clone();
365 }
366
367 public Arrival[] getArrivals() {
368 Arrival[] returnArrivals = new Arrival[arrivals.size()];
369 for(int i = 0; i < arrivals.size(); i++) {
370 returnArrivals[i] = (Arrival)((Arrival)arrivals.elementAt(i)).clone();
371 }
372 return returnArrivals;
373 }
374
375
376 /***
377 * Reads the velocity model, slowness model, and tau model from a file saved
378 * using Java's Serializable interface. Performs a depth correction if the
379 * current depth is not 0.0
380 */
381 protected void readTauModel() throws FileNotFoundException,
382 InvalidClassException, IOException, StreamCorruptedException,
383 OptionalDataException, TauModelException {
384 try {
385 TauModel tModLoad = TauModelLoader.load(modelName,
386 toolProps.getProperty("taup.model.path"));
387 if(tModLoad != null) {
388 tMod = tModLoad;
389 tModDepth = tMod;
390 this.modelName = tMod.sMod.vMod.getModelName();
391 }
392 } catch(ClassNotFoundException e) {
393 Alert.error("Caught ClassNotFoundException",
394 e.getMessage()
395 + "\nThere must be something wrong with your installation of TauP.");
396 throw new RuntimeException("Caught ClassNotFoundException"
397 + e.getMessage()
398 + "\nThere must be something wrong with your installation of TauP.",
399 e);
400 } catch(InvalidClassException e) {
401 Alert.error("Model file "
402 + modelName
403 + " is not compatible with the current version.",
404 "Recreate using taup_create.");
405 throw new RuntimeException("Model file " + modelName
406 + " is not compatible with the current version."
407 + "Recreate using taup_create.", e);
408 }
409 }
410
411 /***
412 * Reads in list of phase names from a text file. So long as each phase name
413 * is separated by some whitespace, " " or newline or tab, it should read
414 * them fine. Also, comments are allowed, either # or // are comments to the
415 * end of the line while c style slash-star make a block a comment.
416 */
417 protected void readPhaseFile(String filename) throws IOException {
418 FileReader fileIn = new FileReader(filename);
419 StreamTokenizer tokenIn = new StreamTokenizer(fileIn);
420 tokenIn.commentChar('#');
421 tokenIn.slashStarComments(true);
422 tokenIn.slashSlashComments(true);
423 tokenIn.wordChars('^', '^');
424 tokenIn.wordChars('0', '9');
425 tokenIn.wordChars('.', '.');
426 tokenIn.wordChars('[', '[');
427 tokenIn.wordChars(']', ']');
428 while(tokenIn.nextToken() != StreamTokenizer.TT_EOF) {
429 if(tokenIn.sval != null) {
430 parsePhaseList(tokenIn.sval);
431 } else {
432 if(DEBUG) {
433 Alert.info("Token.sval was null! nval=" + tokenIn.nval);
434 }
435 }
436 }
437 }
438
439 /***
440 * parses a comma separated list of phase names and adds them to the
441 * phaseNames vector. Each phase can have an optional argument after a dash.
442 * This would be used for specifying which sac header to put the time in, or
443 * for other unforeseen uses. This may be called multiple times to append
444 * more phases. For example: P-0,PcP-1,ScP-4,Sn,SS,S^410S would, assuming no
445 * previous phases have been added, put P in T0, PcP in T1, ScP in T5, Sn in
446 * T2, SS in T3, and S^410S in T5.
447 */
448 public void parsePhaseList(String phaseList) {
449 int offset = 0;
450 int phaseSepIndex;
451 String phaseEntry;
452 phaseList = phaseList.replace(' ', ',');
453
454
455 phaseSepIndex = phaseList.indexOf(",,", offset);
456 while(phaseSepIndex != -1) {
457 phaseList = phaseList.substring(0, phaseSepIndex)
458 + phaseList.substring(phaseSepIndex + 1);
459 phaseSepIndex = phaseList.indexOf(",,", offset);
460 }
461
462 if(phaseList.charAt(0) == ',') {
463 if(phaseList.length() > 1) {
464 phaseList = phaseList.substring(1);
465 } else {
466
467 return;
468 }
469 }
470
471 if(phaseList.charAt(phaseList.length() - 1) == ',') {
472
473
474 phaseList = phaseList.substring(0, phaseList.length() - 1);
475 }
476 while(offset < phaseList.length()) {
477 phaseSepIndex = phaseList.indexOf(',', offset);
478 if(phaseSepIndex != -1) {
479 phaseEntry = phaseList.substring(offset, phaseSepIndex);
480 offset = phaseSepIndex + 1;
481 } else {
482 phaseEntry = phaseList.substring(offset);
483 offset = phaseList.length();
484 }
485 phaseSepIndex = phaseEntry.indexOf('-');
486 if(phaseSepIndex == -1) {
487
488 appendPhaseName(phaseEntry);
489 } else {
490 if(phaseSepIndex == phaseEntry.length() - 2
491 && Character.isDigit(phaseEntry.charAt(phaseEntry.length() - 1))) {
492
493
494
495
496 appendPhaseName(new PhaseName(phaseEntry.substring(0,
497 phaseSepIndex),
498 Integer.valueOf(phaseEntry.substring(phaseSepIndex + 1,
499 phaseEntry.length()))
500 .intValue()));
501 } else {
502 Alert.warning("Problem with phase=" + phaseEntry,
503 "Skipping this phase.");
504 }
505 }
506 }
507 }
508
509 /***
510 * Parses a comma separated list of distances and returns them in an array.
511 */
512 public double[] parseDegreeList(String degList) {
513 int offset = 0;
514 int commaIndex;
515 String degEntry;
516 int numDegrees = 0;
517 double[] degreesFound = new double[degList.length()];
518 while(offset < degList.length()) {
519 commaIndex = degList.indexOf(',', offset);
520 if(commaIndex != -1) {
521 degEntry = degList.substring(offset, commaIndex);
522 degreesFound[numDegrees] = Double.valueOf(degEntry)
523 .doubleValue();
524 offset = commaIndex + 1;
525 numDegrees++;
526 } else {
527 degEntry = degList.substring(offset);
528 degreesFound[numDegrees] = Double.valueOf(degEntry)
529 .doubleValue();
530 offset = degList.length();
531 numDegrees++;
532 }
533 }
534 double[] temp = new double[numDegrees];
535 System.arraycopy(degreesFound, 0, temp, 0, numDegrees);
536 degreesFound = temp;
537 return degreesFound;
538 }
539
540
541
542
543
544 protected String[] parseCmdLineArgs(String[] args) throws IOException {
545 int i = 0;
546 String[] noComprendoArgs = new String[args.length];
547 int numNoComprendoArgs = 0;
548 boolean cmdLineArgPhase = false;
549 boolean cmdLineArgPhaseFile = false;
550 while(i < args.length) {
551 if(args[i].equalsIgnoreCase("-help")) {
552 printUsage();
553 noComprendoArgs[numNoComprendoArgs++] = args[i];
554 } else if(args[i].equalsIgnoreCase("-version")) {
555 Alert.info(Version.getVersion());
556 noComprendoArgs[numNoComprendoArgs++] = args[i];
557 } else if(args[i].equalsIgnoreCase("-verbose")) {
558 verbose = true;
559 } else if(args[i].equalsIgnoreCase("-debug")) {
560 verbose = true;
561 DEBUG = true;
562 } else if(args[i].equalsIgnoreCase("-gui")) {
563 GUI = true;
564 } else if(args[i].equalsIgnoreCase("-rayp")) {
565 onlyPrintRayP = true;
566 onlyPrintTime = false;
567 } else if(args[i].equalsIgnoreCase("-time")) {
568 onlyPrintTime = true;
569 onlyPrintRayP = false;
570 } else if(i < args.length - 1) {
571 if(args[i].equalsIgnoreCase("-mod")
572 || args[i].equalsIgnoreCase("-model")) {
573 toolProps.put("taup.model.name", args[i + 1]);
574 i++;
575 } else if(args[i].equalsIgnoreCase("-h")) {
576 toolProps.put("taup.source.depth", args[i + 1]);
577 i++;
578 } else if(args[i].equalsIgnoreCase("-deg")) {
579 degrees = Double.valueOf(args[i + 1]).doubleValue();
580 i++;
581 } else if(args[i].equalsIgnoreCase("-km")) {
582 degrees = Double.valueOf(args[i + 1]).doubleValue() / 6371
583 * 180.0 / Math.PI;
584 i++;
585 } else if(args[i].equalsIgnoreCase("-az")) {
586 azimuth = Double.valueOf(args[i + 1]).doubleValue();
587 i++;
588 } else if(args[i].equalsIgnoreCase("-baz")) {
589 backAzimuth = Double.valueOf(args[i + 1]).doubleValue();
590 i++;
591 } else if(args[i].equalsIgnoreCase("-o")) {
592 outFile = args[i + 1];
593 i++;
594 } else if(args[i].equalsIgnoreCase("-ph")) {
595 if(cmdLineArgPhase) {
596
597 toolProps.put("taup.phase.list",
598 toolProps.getProperty("taup.phase.list",
599 "")
600 + "," + args[i + 1]);
601 } else {
602
603 toolProps.put("taup.phase.list", args[i + 1]);
604 }
605 cmdLineArgPhase = true;
606 i++;
607 } else if(args[i].equalsIgnoreCase("-pf")) {
608 cmdLineArgPhaseFile = true;
609 toolProps.put("taup.phase.file", args[i + 1]);
610 i++;
611 } else if(i < args.length - 2) {
612 if(args[i].equalsIgnoreCase("-sta")
613 || args[i].equalsIgnoreCase("-station")) {
614 stationLat = Double.valueOf(args[i + 1]).doubleValue();
615 stationLon = Double.valueOf(args[i + 2]).doubleValue();
616 i += 2;
617 } else if(args[i].equalsIgnoreCase("-evt")
618 || args[i].equalsIgnoreCase("-event")) {
619 eventLat = Double.valueOf(args[i + 1]).doubleValue();
620 eventLon = Double.valueOf(args[i + 2]).doubleValue();
621 i += 2;
622 } else {
623
624
625
626
627 noComprendoArgs[numNoComprendoArgs++] = args[i];
628 }
629 } else {
630
631
632
633
634 noComprendoArgs[numNoComprendoArgs++] = args[i];
635 }
636 } else {
637
638 noComprendoArgs[numNoComprendoArgs++] = args[i];
639 }
640 i++;
641 }
642
643
644 if(cmdLineArgPhaseFile || cmdLineArgPhase) {
645 if(cmdLineArgPhaseFile && !cmdLineArgPhase) {
646 toolProps.remove("taup.phase.list");
647 }
648 if(!cmdLineArgPhaseFile && cmdLineArgPhase) {
649 toolProps.remove("taup.phase.file");
650 }
651 }
652 if(numNoComprendoArgs > 0) {
653 String[] temp = new String[numNoComprendoArgs];
654 System.arraycopy(noComprendoArgs, 0, temp, 0, numNoComprendoArgs);
655 return temp;
656 } else {
657 return new String[0];
658 }
659 }
660
661 public synchronized void sortArrivals() {
662 if(arrivals.size() < 2) { return; }
663 boolean sorted = false;
664 int i, k = 0;
665 Arrival currArrival, prevArrival;
666 while(!sorted) {
667 sorted = true;
668 currArrival = (Arrival)arrivals.elementAt(0);
669 for(int j = 0; j < arrivals.size() - 1; j++) {
670 prevArrival = currArrival;
671 currArrival = (Arrival)arrivals.elementAt(j + 1);
672 if(prevArrival.time > currArrival.time) {
673 sorted = false;
674 arrivals.setElementAt(currArrival, j);
675 arrivals.setElementAt(prevArrival, j + 1);
676 currArrival = prevArrival;
677 }
678 }
679 }
680 }
681
682 public void calculate(double degrees) throws TauModelException {
683 depthCorrect(getSourceDepth());
684 recalcPhases();
685 calcTime(degrees);
686 }
687
688 public void calcTime(double degrees) {
689 this.degrees = degrees;
690 SeismicPhase phase;
691 Arrival[] phaseArrivals;
692 arrivals.removeAllElements();
693 for(int phaseNum = 0; phaseNum < phases.size(); phaseNum++) {
694 phase = (SeismicPhase)phases.elementAt(phaseNum);
695 phase.setDEBUG(DEBUG);
696 phase.calcTime(degrees);
697 phaseArrivals = phase.getArrivals();
698 for(int i = 0; i < phaseArrivals.length; i++) {
699 arrivals.addElement(phaseArrivals[i]);
700 }
701 }
702 sortArrivals();
703 }
704
705 /***
706 * corrects the TauModel for the given source depth. It only performs the
707 * correction of the model is not already corrected to that depth.
708 */
709 public void depthCorrect(double depth) throws TauModelException {
710 if(tModDepth == null || tModDepth.getSourceDepth() != depth) {
711 tModDepth = tMod.depthCorrect(depth);
712 clearArrivals();
713 recalcPhases();
714 }
715 setSourceDepth(depth);
716 }
717
718 /***
719 * reclaulates the given phases using a possibly new or changed tau model.
720 * This should not need to be called by outside classes as it is called by
721 * depthCorrect, and calculate.
722 */
723 public synchronized void recalcPhases() {
724 SeismicPhase seismicPhase;
725 Vector newPhases = new Vector(phases.size());
726 boolean alreadyAdded;
727 String tempPhaseName;
728 for(int phaseNameNum = 0; phaseNameNum < phaseNames.size(); phaseNameNum++) {
729 tempPhaseName = ((PhaseName)phaseNames.elementAt(phaseNameNum)).name;
730 alreadyAdded = false;
731 for(int phaseNum = 0; phaseNum < phases.size(); phaseNum++) {
732 seismicPhase = (SeismicPhase)phases.elementAt(phaseNum);
733 if(seismicPhase.name.equals(tempPhaseName)) {
734 phases.removeElementAt(phaseNum);
735 if(seismicPhase.sourceDepth == depth
736 && seismicPhase.tMod.equals(tModDepth)) {
737
738 newPhases.addElement(seismicPhase);
739 alreadyAdded = true;
740 if(verbose) {
741 Alert.info(seismicPhase.toString());
742 }
743 break;
744 }
745 }
746 }
747 if(!alreadyAdded) {
748
749 try {
750 seismicPhase = new SeismicPhase(tempPhaseName, tModDepth);
751 seismicPhase.setDEBUG(DEBUG);
752 seismicPhase.init();
753 newPhases.addElement(seismicPhase);
754 if(verbose) {
755 Alert.info(seismicPhase.toString());
756 }
757 } catch(TauModelException e) {
758 Alert.warning("Error with phase=" + tempPhaseName,
759 e.getMessage() + "\nSkipping this phase");
760 } finally {
761 if(verbose) {
762 Alert.info("-----------------");
763 }
764 }
765 }
766 }
767 phases = newPhases;
768 }
769
770 public void printResult(DataOutputStream dos) throws IOException {
771 Writer s = new BufferedWriter(new OutputStreamWriter(dos));
772 printResult(s);
773 s.flush();
774 }
775
776 public void printResult(Writer out) throws IOException {
777 Arrival currArrival;
778 int maxNameLength = 5;
779 int maxPuristNameLength = 5;
780 for(int j = 0; j < arrivals.size(); j++) {
781 if(((Arrival)arrivals.elementAt(j)).name.length() > maxNameLength) {
782 maxNameLength = ((Arrival)arrivals.elementAt(j)).name.length();
783 }
784 if(((Arrival)arrivals.elementAt(j)).puristName.length() > maxPuristNameLength) {
785 maxPuristNameLength = ((Arrival)arrivals.elementAt(j)).puristName.length();
786 }
787 }
788 double moduloDist;
789 Format phaseFormat = new Format("%-" + maxNameLength + "s");
790 Format phasePuristFormat = new Format("%-" + maxPuristNameLength + "s");
791 if(!(onlyPrintRayP || onlyPrintTime)) {
792 out.write("\nModel: " + modelName + "\n");
793 out.write("Distance Depth " + phaseFormat.form("Phase")
794 + " Travel Ray Param Purist Purist\n");
795 out.write(" (deg) (km) " + phaseFormat.form("Name ")
796 + " Time (s) p (s/deg) Distance Name\n");
797 for(int i = 0; i < maxNameLength + maxPuristNameLength + 54; i++) {
798 out.write("-");
799 }
800 out.write("\n");
801 for(int j = 0; j < arrivals.size(); j++) {
802 currArrival = (Arrival)arrivals.elementAt(j);
803 out.write(outForms.formatDistance(currArrival.getModuloDistDeg())
804 + outForms.formatDepth(depth) + " ");
805 out.write(phaseFormat.form(currArrival.name));
806 out.write(" "
807 + outForms.formatTime(currArrival.time)
808 + " "
809 + outForms.formatRayParam(Math.PI / 180.0
810 * currArrival.rayParam) + " ");
811 out.write(outForms.formatDistance(currArrival.getDistDeg()));
812 if(currArrival.name.equals(currArrival.puristName)) {
813 out.write(" = ");
814 } else {
815 out.write(" * ");
816 }
817 out.write(phasePuristFormat.form(currArrival.puristName) + "\n");
818 }
819 } else if(onlyPrintTime) {
820 for(int j = 0; j < arrivals.size(); j++) {
821 currArrival = (Arrival)arrivals.elementAt(j);
822 out.write(String.valueOf((float)(currArrival.time)) + " ");
823 }
824 out.write("\n");
825 } else if(onlyPrintRayP) {
826 for(int j = 0; j < arrivals.size(); j++) {
827 currArrival = (Arrival)arrivals.elementAt(j);
828 out.write(String.valueOf((float)(Math.PI / 180.0 * currArrival.rayParam))
829 + " ");
830 }
831 out.write("\n");
832 }
833 out.write("\n");
834 }
835
836 /***
837 * preforms intialization of the tool. Properties are queried for the the
838 * default model to load, source depth to use, phases to use, etc. Note that
839 * because of the IO inherent in these operations, this method is not
840 * appropriate for Applets. Applets should load TauModels themselves and use
841 * the setTauModel(TauModel) method.
842 */
843 public void init() throws IOException {
844 if(phaseNames.size() == 0) {
845 if(toolProps.containsKey("taup.phase.file")) {
846 if(toolProps.containsKey("taup.phase.list")) {
847 parsePhaseList(toolProps.getProperty("taup.phase.list"));
848 }
849 try {
850 readPhaseFile(toolProps.getProperty("taup.phase.file"));
851 } catch(IOException e) {
852 Alert.warning("Caught IOException while attempting to reading phase file "
853 + toolProps.getProperty("taup.phase.file"),
854 e.getMessage());
855 if(phaseNames.size() <= 0) {
856 parsePhaseList(toolProps.getProperty("taup.phase.list",
857 "p,s,P,S,Pn,Sn,PcP,ScS,Pdiff,Sdiff,PKP,SKS,PKiKP,SKiKS,PKIKP,SKIKS"));
858 }
859 }
860 } else {
861 parsePhaseList(toolProps.getProperty("taup.phase.list",
862 "p,s,P,S,Pn,Sn,PcP,ScS,Pdiff,Sdiff,PKP,SKS,PKiKP,SKiKS,PKIKP,SKIKS"));
863 }
864 }
865 depth = Double.valueOf(toolProps.getProperty("taup.source.depth", "0.0"))
866 .doubleValue();
867 if(tMod == null
868 || tMod.sMod.vMod.getModelName() != toolProps.getProperty("taup.model.name",
869 "iasp91")) {
870 modelName = toolProps.getProperty("taup.model.name", "iasp91");
871 try {
872 readTauModel();
873 } catch(TauModelException ee) {
874 Alert.error("Caught TauModelException", ee.getMessage());
875 } catch(FileNotFoundException ee) {
876 Alert.error("Can't find saved model file for model "
877 + modelName + ".", "");
878 System.exit(1);
879 } catch(InvalidClassException ee) {
880 Alert.error("Model file "
881 + modelName
882 + " is not compatible with the current version.",
883 "Recreate using taup_create.");
884 System.exit(1);
885 }
886 }
887 if(outFile != null && outFile.length() != 0) {
888 dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(outFile)));
889 } else {
890 dos = new DataOutputStream(System.out);
891 }
892 }
893
894 public void printHelp() {
895 Alert.info("Enter:\nh for new depth\nr to recalculate\n"
896 + "p to append phases, \nc to clear phases\n"
897 + "l to list phases\n"
898 + "s for new station lat lon\ne for new event lat lon\n"
899 + "a for new azimuth\nb for new back azimuth\n"
900 + "m for new model or \nq to quit.\n");
901 }
902
903 public void start() throws IOException, TauModelException, TauPException {
904 boolean didDepthCorrect;
905 if((degrees != Double.MAX_VALUE || (stationLat != Double.MAX_VALUE
906 && stationLon != Double.MAX_VALUE
907 && eventLat != Double.MAX_VALUE && eventLon != Double.MAX_VALUE))) {
908
909 if(degrees == Double.MAX_VALUE) {
910 degrees = SphericalCoords.distance(stationLat,
911 stationLon,
912 eventLat,
913 eventLon);
914 azimuth = SphericalCoords.azimuth(eventLat,
915 eventLon,
916 stationLat,
917 stationLon);
918 backAzimuth = SphericalCoords.azimuth(stationLat,
919 stationLon,
920 eventLat,
921 eventLon);
922 }
923 depthCorrect(depth);
924 calculate(degrees);
925 printResult(dos);
926 } else {
927
928 long prevTime = 0;
929 long currTime;
930 char readMode = 'd';
931 double tempDepth = depth;
932 depthCorrect(depth);
933 StreamTokenizer tokenIn = new StreamTokenizer(new InputStreamReader(System.in));
934 tokenIn.parseNumbers();
935 tokenIn.wordChars(',', ',');
936 tokenIn.wordChars('_', '_');
937 tokenIn.wordChars('^', '^');
938 tokenIn.ordinaryChar('/');
939 tokenIn.wordChars('/', '/');
940 tokenIn.commentChar('#');
941 printHelp();
942 do {
943 switch(readMode){
944 case 'h':
945
946 System.out.print("Enter Depth: ");
947 tokenIn.nextToken();
948 tempDepth = tokenIn.nval;
949 if(tempDepth < 0.0
950 || tempDepth > tMod.getRadiusOfEarth()) {
951 Alert.warning("Depth must be >= 0.0 and <= tMod.getRadiusOfEarth().",
952 "depth = " + tempDepth
953 + " getRadiusOfEarth= "
954 + tMod.getRadiusOfEarth());
955 continue;
956 }
957 prevTime = System.currentTimeMillis();
958 depthCorrect(tempDepth);
959 currTime = System.currentTimeMillis();
960 if(verbose) {
961 Alert.info("depthCorrect time="
962 + (currTime - prevTime));
963 }
964 readMode = 'd';
965 break;
966 case 'd':
967
968 System.out.print("Enter Distance or Option [hrpclseabmq]: ");
969 tokenIn.nextToken();
970 if(tokenIn.ttype == StreamTokenizer.TT_NUMBER) {
971 degrees = tokenIn.nval;
972 if(DEBUG) {
973 Alert.info("degrees=" + degrees);
974 }
975 calculate(degrees);
976 printResult(dos);
977 } else {
978 if(tokenIn.ttype == tokenIn.TT_EOF
979 || (tokenIn.ttype == tokenIn.TT_WORD && (tokenIn.sval.equalsIgnoreCase("q")
980 || tokenIn.sval.equalsIgnoreCase("quit")
981 || tokenIn.sval.equalsIgnoreCase("exit") || tokenIn.sval.equalsIgnoreCase("bye")))) {
982 readMode = 'q';
983 } else if(tokenIn.ttype == tokenIn.TT_WORD) {
984 if(tokenIn.sval.equalsIgnoreCase("l")) {
985 readMode = 'l';
986 } else if(tokenIn.sval.equalsIgnoreCase("c")) {
987 readMode = 'c';
988 } else if(tokenIn.sval.equalsIgnoreCase("s")) {
989 readMode = 's';
990 } else if(tokenIn.sval.equalsIgnoreCase("e")) {
991 readMode = 'e';
992 } else if(tokenIn.sval.equalsIgnoreCase("a")) {
993 readMode = 'a';
994 } else if(tokenIn.sval.equalsIgnoreCase("b")) {
995 readMode = 'b';
996 } else if(tokenIn.sval.equalsIgnoreCase("r")) {
997 readMode = 'r';
998 } else if(tokenIn.sval.equalsIgnoreCase("p")) {
999 readMode = 'p';
1000 } else if(tokenIn.sval.equalsIgnoreCase("m")) {
1001 readMode = 'm';
1002 } else if(tokenIn.sval.equalsIgnoreCase("h")) {
1003 readMode = 'h';
1004 } else if(tokenIn.sval.equalsIgnoreCase("?")) {
1005 printHelp();
1006 } else {
1007 Alert.warning("I don't understand this option",
1008 tokenIn.sval);
1009 printHelp();
1010 }
1011 } else {
1012 printHelp();
1013 }
1014 }
1015 break;
1016 case 'r':
1017
1018 if(degrees != Double.MAX_VALUE) {
1019 calculate(degrees);
1020 printResult(dos);
1021 }
1022 readMode = 'd';
1023 break;
1024 case 'p':
1025
1026 System.out.print("Enter phases (ie P,p,PcP,S): ");
1027 tokenIn.ordinaryChars('0', '9');
1028 tokenIn.ordinaryChar('.');
1029 tokenIn.ordinaryChar('-');
1030 tokenIn.wordChars('0', '9');
1031 tokenIn.wordChars('.', '.');
1032 tokenIn.wordChars('-', '-');
1033 tokenIn.ordinaryChar(' ');
1034 tokenIn.wordChars(' ', ' ');
1035 tokenIn.nextToken();
1036 if(tokenIn.ttype == StreamTokenizer.TT_WORD) {
1037 parsePhaseList(tokenIn.sval);
1038 recalcPhases();
1039 } else {
1040 Alert.warning("Input phases not recognized.",
1041 "Please retry.");
1042 }
1043 tokenIn.parseNumbers();
1044 tokenIn.ordinaryChar(' ');
1045 tokenIn.whitespaceChars(' ', ' ');
1046 readMode = 'd';
1047 break;
1048 case 'l':
1049
1050 int numPhases = phaseNames.size();
1051 String output = numPhases + " phases.";
1052 Alert.info(output);
1053 output = "";
1054 for(int i = 0; i < numPhases; i++) {
1055 output += ((PhaseName)phaseNames.elementAt(i)).name;
1056 if(i < numPhases - 1) {
1057 output += ",";
1058 }
1059 }
1060 Alert.info(output);
1061 readMode = 'd';
1062 break;
1063 case 'c':
1064
1065 clearPhaseNames();
1066 readMode = 'p';
1067 break;
1068 case 'a':
1069
1070 System.out.print("Enter azimuth: ");
1071 tokenIn.nextToken();
1072 if(tokenIn.ttype == StreamTokenizer.TT_NUMBER) {
1073 azimuth = tokenIn.nval;
1074 stationLat = Double.MAX_VALUE;
1075 stationLon = Double.MAX_VALUE;
1076 if(DEBUG) {
1077 Alert.info("azimuth=" + azimuth);
1078 }
1079 } else {
1080 Alert.warning("Expected a number.", "got "
1081 + tokenIn + " instead.");
1082 printHelp();
1083 break;
1084 }
1085 if(eventLat == Double.MAX_VALUE
1086 || eventLon == Double.MAX_VALUE) {
1087 readMode = 'e';
1088 } else if(degrees == Double.MAX_VALUE) {
1089 readMode = 'd';
1090 } else {
1091 calculate(degrees);
1092 printResult(dos);
1093 }
1094 readMode = 'd';
1095 break;
1096 case 'b':
1097
1098
1099 System.out.print("Enter back azimuth: ");
1100 tokenIn.nextToken();
1101 if(tokenIn.ttype == StreamTokenizer.TT_NUMBER) {
1102 backAzimuth = tokenIn.nval;
1103 eventLat = Double.MAX_VALUE;
1104 eventLon = Double.MAX_VALUE;
1105 if(DEBUG) {
1106 Alert.info("backAzimuth=" + backAzimuth);
1107 }
1108 } else {
1109 Alert.warning("Expected a number.", "got "
1110 + tokenIn + " instead");
1111 printHelp();
1112 break;
1113 }
1114 if(stationLat == Double.MAX_VALUE
1115 || stationLon == Double.MAX_VALUE) {
1116 readMode = 's';
1117 } else if(degrees == Double.MAX_VALUE) {
1118 readMode = 'd';
1119 } else {
1120 calculate(degrees);
1121 printResult(dos);
1122 }
1123 readMode = 'd';
1124 break;
1125 case 'e':
1126
1127 System.out.print("Enter event lat and lon: ");
1128 tokenIn.nextToken();
1129 if(tokenIn.ttype == StreamTokenizer.TT_NUMBER) {
1130 eventLat = tokenIn.nval;
1131 if(DEBUG) {
1132 Alert.info("eventLat=" + eventLat);
1133 }
1134 tokenIn.nextToken();
1135 if(tokenIn.ttype == StreamTokenizer.TT_NUMBER) {
1136 eventLon = tokenIn.nval;
1137 if(DEBUG) {
1138 Alert.info("eventLon=" + eventLon);
1139 }
1140 } else {
1141 printHelp();
1142 }
1143 } else {
1144 printHelp();
1145 }
1146 if(stationLat != Double.MAX_VALUE
1147 && stationLon != Double.MAX_VALUE) {
1148 degrees = SphericalCoords.distance(stationLat,
1149 stationLon,
1150 eventLat,
1151 eventLon);
1152 azimuth = SphericalCoords.azimuth(eventLat,
1153 eventLon,
1154 stationLat,
1155 stationLon);
1156 backAzimuth = SphericalCoords.azimuth(stationLat,
1157 stationLon,
1158 eventLat,
1159 eventLon);
1160 calculate(degrees);
1161 printResult(dos);
1162 }
1163 readMode = 'd';
1164 break;
1165 case 's':
1166
1167 System.out.print("Enter station lat and lon: ");
1168 tokenIn.nextToken();
1169 if(tokenIn.ttype == StreamTokenizer.TT_NUMBER) {
1170 stationLat = tokenIn.nval;
1171 if(DEBUG) {
1172 Alert.info("stationLat=" + stationLat);
1173 }
1174 tokenIn.nextToken();
1175 if(tokenIn.ttype == StreamTokenizer.TT_NUMBER) {
1176 stationLon = tokenIn.nval;
1177 if(DEBUG) {
1178 Alert.info("stationLon=" + stationLon);
1179 }
1180 } else {
1181 printHelp();
1182 break;
1183 }
1184 } else {
1185 printHelp();
1186 break;
1187 }
1188 if(eventLat != Double.MAX_VALUE
1189 && eventLon != Double.MAX_VALUE) {
1190 degrees = SphericalCoords.distance(stationLat,
1191 stationLon,
1192 eventLat,
1193 eventLon);
1194 azimuth = SphericalCoords.azimuth(eventLat,
1195 eventLon,
1196 stationLat,
1197 stationLon);
1198 backAzimuth = SphericalCoords.azimuth(stationLat,
1199 stationLon,
1200 eventLat,
1201 eventLon);
1202 calculate(degrees);
1203 printResult(dos);
1204 }
1205 readMode = 'd';
1206 break;
1207 case 'm':
1208
1209 tokenIn.ordinaryChars('0', '9');
1210 tokenIn.wordChars('0', '9');
1211 tokenIn.ordinaryChars('.', '.');
1212 tokenIn.wordChars('.', '.');
1213 tokenIn.ordinaryChars('-', '-');
1214 tokenIn.wordChars('-', '-');
1215 String oldModelName = modelName;
1216 TauModel oldTMod = tMod;
1217 TauModel oldTModDepth = tModDepth;
1218 System.out.print("Enter model name: ");
1219 tokenIn.nextToken();
1220 if(tokenIn.ttype == StreamTokenizer.TT_WORD) {
1221 modelName = tokenIn.sval;
1222 }
1223 tokenIn.ordinaryChars('0', '9');
1224 tokenIn.ordinaryChars('.', '.');
1225 tokenIn.ordinaryChars('-', '-');
1226 tokenIn.parseNumbers();
1227 if(!modelName.equals(oldModelName)) {
1228 try {
1229 readTauModel();
1230 depthCorrect(depth);
1231 } catch(FileNotFoundException e) {
1232 Alert.warning("I can't find model file "
1233 + modelName, "Still using model "
1234 + oldModelName + ".");
1235 modelName = oldModelName;
1236 tMod = oldTMod;
1237 tModDepth = oldTModDepth;
1238 } catch(InvalidClassException ee) {
1239 Alert.warning("Model file "
1240 + modelName
1241 + " is not compatible with the current version.",
1242 "Recreate using taup_create. Still using model "
1243 + oldModelName + ".");
1244 modelName = oldModelName;
1245 tMod = oldTMod;
1246 tModDepth = oldTModDepth;
1247 }
1248 }
1249 readMode = 'd';
1250 break;
1251 case 'q':
1252 return;
1253 }
1254 } while(tokenIn.ttype == StreamTokenizer.TT_NUMBER
1255 || tokenIn.ttype != StreamTokenizer.TT_WORD
1256 || (tokenIn.ttype == StreamTokenizer.TT_WORD && !tokenIn.sval.equalsIgnoreCase("q")));
1257 }
1258 }
1259
1260 public void destroy() throws IOException {
1261 if(dos != null) {
1262 dos.close();
1263 }
1264 }
1265
1266 public void printStdUsageHead() {
1267 String className = this.getClass().getName();
1268 className = className.substring(className.lastIndexOf('.') + 1,
1269 className.length());
1270 Alert.info("Usage: " + className.toLowerCase() + " [arguments]");
1271 Alert.info(" or, for purists, java " + this.getClass().getName()
1272 + " [arguments]");
1273 Alert.info("\nArguments are:");
1274 }
1275
1276 /*** Prints the command line arguments common to all TauP tools. */
1277 public void printStdUsage() {
1278 printStdUsageHead();
1279 Alert.info("-ph phase list -- comma separated phase list\n"
1280 + "-pf phasefile -- file containing phases\n\n"
1281 + "-mod[el] modelname -- use velocity model \"modelname\" for calculations\n"
1282 + " Default is iasp91.\n\n"
1283 + "-h depth -- source depth in km\n\n"
1284 + "Distance is given by:\n\n"
1285 + "-deg degrees -- distance in degrees,\n"
1286 + "-km kilometers -- distance in kilometers,\n"
1287 + " assumes radius of earth is 6371km,\n\n"
1288 + "or by giving the station and event latitude and lonitude,\n"
1289 + " assumes a spherical earth,\n\n"
1290 + "-sta[tion] lat lon -- sets the station latitude and longitude\n"
1291 + "-evt lat lon -- sets the event latitude and longitude\n\n");
1292 }
1293
1294 public void printStdUsageTail() {
1295 Alert.info("\n-o outfile -- output is redirected to \"outfile\"\n"
1296 + "-debug -- enable debugging output\n"
1297 + "-verbose -- enable verbose output\n"
1298 + "-version -- print the version\n"
1299 + "-help -- print this out, but you already know that!\n");
1300 }
1301
1302 public void printUsage() {
1303 printStdUsage();
1304 Alert.info("-rayp -- only output the ray parameter\n"
1305 + "-time -- only output travel time");
1306 printStdUsageTail();
1307 }
1308
1309 /***
1310 * Allows TauP_Time to run as an application. Creates an instance of
1311 * TauP_Time. .
1312 */
1313 public static void main(String[] args) throws FileNotFoundException,
1314 IOException, StreamCorruptedException, ClassNotFoundException,
1315 OptionalDataException {
1316 BasicConfigurator.configure();
1317 try {
1318 long prevTime = 0;
1319 long currTime;
1320 prevTime = System.currentTimeMillis();
1321 TauP_Time tauPTime = new TauP_Time();
1322 String[] noComprendoArgs = tauPTime.parseCmdLineArgs(args);
1323 if(noComprendoArgs.length > 0) {
1324 for(int i = 0; i < noComprendoArgs.length; i++) {
1325 if(noComprendoArgs[i].equals("-help")
1326 || noComprendoArgs[i].equals("-version")) {
1327 System.exit(0);
1328 }
1329 }
1330 String outStringA = "I don't understand the following arguments, continuing:";
1331 String outStringB = "";
1332 for(int i = 0; i < noComprendoArgs.length; i++) {
1333 outStringB += noComprendoArgs[i] + " ";
1334 }
1335 Alert.warning(outStringA, outStringB);
1336 noComprendoArgs = null;
1337 }
1338 currTime = System.currentTimeMillis();
1339 prevTime = System.currentTimeMillis();
1340 tauPTime.init();
1341 currTime = System.currentTimeMillis();
1342 if(tauPTime.DEBUG) {
1343 Alert.info("taup model read time=" + (currTime - prevTime));
1344 }
1345 tauPTime.start();
1346 tauPTime.destroy();
1347 } catch(TauModelException e) {
1348 Alert.error("Caught TauModelException", e.getMessage());
1349 e.printStackTrace();
1350 } catch(TauPException e) {
1351 Alert.error("Caught TauPException", e.getMessage());
1352 e.printStackTrace();
1353 }
1354 }
1355 }