View Javadoc

1   /*
2    * The TauP Toolkit: Flexible Seismic Travel-Time and Raypath Utilities.
3    * Copyright (C) 1998-2000 University of South Carolina This program is free
4    * software; you can redistribute it and/or modify it under the terms of the GNU
5    * General Public License as published by the Free Software Foundation; either
6    * version 2 of the License, or (at your option) any later version. This program
7    * is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8    * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9    * PARTICULAR PURPOSE. See the GNU General Public License for more details. You
10   * should have received a copy of the GNU General Public License along with this
11   * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place -
12   * Suite 330, Boston, MA 02111-1307, USA. The current version can be found at <A
13   * HREF="www.seis.sc.edu">http://www.seis.sc.edu </A> Bug reports and comments
14   * should be directed to H. Philip Crotwell, crotwell@seis.sc.edu or Tom Owens,
15   * owens@seis.sc.edu
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     /* Constructors */
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     /* Get/Set methods */
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         // in case of empty phase list
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             // make sure not null string
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     /* Normal methods */
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('#'); // '#' means ignore to end of line
421         tokenIn.slashStarComments(true); // '/*...*/' means a comment
422         tokenIn.slashSlashComments(true); // '//' means ignore to end of line
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         // remove any empty phases, ie two commas next to each other
454         // should be replaced with one comma
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         // remove comma at begining
462         if(phaseList.charAt(0) == ',') {
463             if(phaseList.length() > 1) {
464                 phaseList = phaseList.substring(1);
465             } else {
466                 // phaseList is just a single comma, no phases, so just return
467                 return;
468             }
469         }
470         // and comma at end
471         if(phaseList.charAt(phaseList.length() - 1) == ',') {
472             // we know that the length is > 1 as if not then we would have
473             // returned from the previous if
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                 /* no optional dash argument, so just add the name. */
488                 appendPhaseName(phaseEntry);
489             } else {
490                 if(phaseSepIndex == phaseEntry.length() - 2
491                         && Character.isDigit(phaseEntry.charAt(phaseEntry.length() - 1))) {
492                     /*
493                      * There is an optional argument, so store it and the phase
494                      * name.
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      * parses the standard command line args for the taup package. Other tools
542      * that subclass this class will likely override this.
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                         // previous cmd line -ph so append
597                         toolProps.put("taup.phase.list",
598                                       toolProps.getProperty("taup.phase.list",
599                                                             "")
600                                               + "," + args[i + 1]);
601                     } else {
602                         // no previous cmd line -ph so replace defaults
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                          * I don't know how to interpret this argument, so pass
625                          * it back
626                          */
627                         noComprendoArgs[numNoComprendoArgs++] = args[i];
628                     }
629                 } else {
630                     /*
631                      * I don't know how to interpret this argument, so pass it
632                      * back
633                      */
634                     noComprendoArgs[numNoComprendoArgs++] = args[i];
635                 }
636             } else {
637                 /* I don't know how to interpret this argument, so pass it back */
638                 noComprendoArgs[numNoComprendoArgs++] = args[i];
639             }
640             i++;
641         }
642         // check to see if there were phases or a phase file as an argument.
643         // if so then dump the defaults
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                         // ok so copy to newPhases
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                 // didn't find it precomputed, so recalculate
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             /* enough info given on cmd line, so just do one calc. */
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             /* interactive mode... */
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                         // new source depth
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                         // new distance or option
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                         // recalulate
1018                         if(degrees != Double.MAX_VALUE) {
1019                             calculate(degrees);
1020                             printResult(dos);
1021                         }
1022                         readMode = 'd';
1023                         break;
1024                     case 'p':
1025                         // append phases
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                         // list phases
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                         // clear phases and then enter new phases
1065                         clearPhaseNames();
1066                         readMode = 'p';
1067                         break;
1068                     case 'a':
1069                         // event to station azimuth
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                         //event to station back azimuth (ie station to event
1098                         // azimuth)
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                         // event lat and lon
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                         // station lat and lon
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                         // change model
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 }