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.*;
20  import java.util.Vector;
21  
22  /***
23   * Calculate pierce points for different branches using linear interpolation
24   * between known slowness samples. A pierce point is where a ray pierces a tau
25   * branch. This gives a (very) rough path through the model for a ray.
26   * 
27   * @version 1.1.3 Fri Apr 5 14:12:19 GMT 2002
28   * @author H. Philip Crotwell
29   */
30  public class TauP_Pierce extends TauP_Time {
31  
32      protected boolean onlyTurnPoints = false;
33  
34      protected boolean onlyRevPoints = false;
35  
36      protected boolean onlyUnderPoints = false;
37  
38      protected boolean onlyAddPoints = false;
39  
40      protected double[] addDepth = new double[0];
41  
42      protected TauP_Pierce() {
43          super();
44      }
45  
46      public TauP_Pierce(TauModel tMod) throws TauModelException {
47          super(tMod);
48      }
49  
50      public TauP_Pierce(String modelName) throws TauModelException {
51          super(modelName);
52      }
53  
54      // get/set methods
55      public void setOnlyTurnPoints(boolean onlyTurnPoints) {
56          this.onlyTurnPoints = onlyTurnPoints;
57      }
58  
59      public void setOnlyRevPoints(boolean onlyRevPoints) {
60          this.onlyRevPoints = onlyRevPoints;
61      }
62  
63      public void setOnlyUnderPoints(boolean onlyUnderPoints) {
64          this.onlyUnderPoints = onlyUnderPoints;
65      }
66  
67      public void setOnlyAddPoints(boolean onlyAddPoints) {
68          this.onlyAddPoints = onlyAddPoints;
69      }
70  
71      /***
72       * sets depths for additional pierce points, ie depths that are not really
73       * discontinuities in the model.
74       */
75      public void setAddDepths(String depthString) {
76          addDepth = parseAddDepthsList(depthString);
77      }
78  
79      public void appendAddDepths(String depthString) {
80          double[] newDepths = parseAddDepthsList(depthString);
81          double[] temp = new double[addDepth.length + newDepths.length];
82          System.arraycopy(addDepth, 0, temp, 0, addDepth.length);
83          System.arraycopy(newDepths, 0, temp, addDepth.length, newDepths.length);
84          addDepth = temp;
85      }
86  
87      protected double[] parseAddDepthsList(String depthList) {
88          int offset = 0;
89          int commaIndex;
90          String degEntry;
91          int numDepths = 0;
92          depthList = depthList.replace(' ', ',');
93          // remove any empty depths, ie two commas next to each other
94          // should be replaced with one comma
95          commaIndex = depthList.indexOf(",,", offset);
96          while(commaIndex != -1) {
97              depthList = depthList.substring(0, commaIndex)
98                      + depthList.substring(commaIndex + 1);
99              commaIndex = depthList.indexOf(",,", offset);
100         }
101         // remove comma at begining
102         if(depthList.charAt(0) == ',') {
103             if(depthList.length() > 1) {
104                 depthList = depthList.substring(1);
105             } else {
106                 // depthList is just a single comma, no depths, so just return
107                 return new double[0];
108             }
109         }
110         // and comma at end
111         if(depthList.charAt(depthList.length() - 1) == ',') {
112             // we know that the length is > 1 as if not then we would have
113             // returned from the previous if
114             depthList = depthList.substring(0, depthList.length() - 1);
115         }
116         double[] depthsFound = new double[depthList.length()];
117         while(offset < depthList.length()) {
118             commaIndex = depthList.indexOf(',', offset);
119             if(commaIndex != -1) {
120                 degEntry = depthList.substring(offset, commaIndex);
121                 depthsFound[numDepths] = Double.valueOf(degEntry).doubleValue();
122                 offset = commaIndex + 1;
123                 numDepths++;
124             } else {
125                 degEntry = depthList.substring(offset);
126                 depthsFound[numDepths] = Double.valueOf(degEntry).doubleValue();
127                 offset = depthList.length();
128                 numDepths++;
129             }
130         }
131         double[] temp = new double[numDepths];
132         System.arraycopy(depthsFound, 0, temp, 0, numDepths);
133         depthsFound = temp;
134         return depthsFound;
135     }
136 
137     /*** override depthCorrect so that we can put the pierce depths in. */
138     public void depthCorrect(double depth) throws TauModelException {
139         TauModel tModOrig = (TauModel)tMod.clone();
140         TauModel tModDepthOrig = tModDepth;
141         boolean mustRecalc = false;
142         // first see if tModDepth is correct as is
143         // first check to make sure source depth is the same, and then
144         // check to make sure each addDepth is in the model
145         if(tModDepth.sourceDepth == depth) {
146             if(addDepth != null) {
147                 double[] branchDepths = tModDepth.getBranchDepths();
148                 for(int i = 0; i < addDepth.length; i++) {
149                     for(int j = 0; j < branchDepths.length; j++) {
150                         if(addDepth[i] == branchDepths[j]) {
151                             // found it, so break and go to the next addDepth
152                             break;
153                         }
154                         // we only get here if we didn't find the depth as a
155                         // branch due to the break statement,
156                         // so this means we must recalculate
157                         mustRecalc = true;
158                     }
159                     if(mustRecalc) {
160                         // must recalculate, so break out of addDepth loop
161                         break;
162                     }
163                 }
164             }
165         } else {
166             // the depth isn't even the same so we must recalculate
167             mustRecalc = true;
168         }
169         if(mustRecalc) {
170             // must do the depth correction
171             tModDepth = null;
172         } else {
173             // no depth correction needed, so just do super() and return
174             super.depthCorrect(depth);
175             return;
176         }
177         try {
178             if(addDepth != null) {
179                 for(int i = 0; i < addDepth.length; i++) {
180                     tMod = tMod.splitBranch(addDepth[i]);
181                 }
182             }
183         } catch(TauModelException e) {
184             System.err.println("depthCorrect: caught TauModelException: "
185                     + e.getMessage() + "\nSkipping added depth"
186                     + " pierce points.");
187             tMod = tModOrig;
188             tMod = tModDepthOrig;
189         }
190         super.depthCorrect(depth);
191         tMod = tModOrig;
192     }
193 
194     public void calculate(double degrees) throws TauModelException {
195         depthCorrect(getSourceDepth());
196         recalcPhases();
197         clearArrivals();
198         calcPierce(degrees);
199     }
200 
201     /*** calculates the pierce points for phases at the given distance. */
202     protected void calcPierce(double degrees) {
203         this.degrees = degrees;
204         SeismicPhase phase;
205         Arrival[] phaseArrivals;
206         double calcDepth, calcTime, calcDist;
207         for(int phaseNum = 0; phaseNum < phases.size(); phaseNum++) {
208             phase = (SeismicPhase)phases.elementAt(phaseNum);
209             try {
210                 phase.setDEBUG(DEBUG);
211                 phase.calcTime(degrees);
212                 if(phase.hasArrivals()) {
213                     phase.calcPierce(tModDepth);
214                     phaseArrivals = phase.getArrivals();
215                     for(int i = 0; i < phaseArrivals.length; i++) {
216                         arrivals.addElement(phaseArrivals[i]);
217                     }
218                 }
219             } catch(TauModelException e) {
220                 System.err.println("Caught TauModelException: "
221                         + e.getMessage());
222                 System.err.println("Skipping phase " + phase.getName());
223             }
224         }
225     }
226 
227     public void printResult(Writer out) throws IOException {
228         double calcTime, calcDist;
229         double prevDepth, nextDepth;
230         double lat, lon;
231         Arrival currArrival;
232         String tempString;
233         boolean longWayRound = false;
234         for(int i = 0; i < arrivals.size(); i++) {
235             currArrival = (Arrival)arrivals.elementAt(i);
236             out.write("> " + currArrival.name + " at "
237                     + outForms.formatTime(currArrival.time) + " seconds at "
238                     + outForms.formatDistance(currArrival.getDistDeg())
239                     + " degrees for a "
240                     + outForms.formatDepth(currArrival.sourceDepth)
241                     + " km deep source in the " + modelName + " model.\n");
242             longWayRound = false;
243             if((currArrival.dist * 180 / Math.PI) % 360 > 180) {
244                 longWayRound = true;
245             }
246             prevDepth = currArrival.pierce[0].depth;
247             for(int j = 0; j < currArrival.pierce.length; j++) {
248                 calcTime = currArrival.pierce[j].time;
249                 calcDist = currArrival.pierce[j].dist * 180.0 / Math.PI;
250                 if(longWayRound && calcDist != 0.0) {
251                     calcDist *= -1.0;
252                 }
253                 if(j < currArrival.pierce.length - 1) {
254                     nextDepth = currArrival.pierce[j + 1].depth;
255                 } else {
256                     nextDepth = currArrival.pierce[j].depth;
257                 }
258                 if(!(onlyTurnPoints || onlyRevPoints || onlyUnderPoints || onlyAddPoints)
259                         || ((onlyAddPoints && isAddDepth(currArrival.pierce[j].depth))
260                                 || (onlyRevPoints && ((prevDepth - currArrival.pierce[j].depth)
261                                         * (currArrival.pierce[j].depth - nextDepth) < 0))
262                                 || (onlyTurnPoints && j != 0 && ((prevDepth - currArrival.pierce[j].depth) <= 0 && (currArrival.pierce[j].depth - nextDepth) >= 0)) || (onlyUnderPoints && ((prevDepth - currArrival.pierce[j].depth) >= 0 && (currArrival.pierce[j].depth - nextDepth) <= 0)))) {
263                     out.write(outForms.formatDistance(calcDist));
264                     out.write(outForms.formatDepth(currArrival.pierce[j].depth));
265                     out.write(outForms.formatDepth(currArrival.pierce[j].time));
266                     if(eventLat != Double.MAX_VALUE
267                             && eventLon != Double.MAX_VALUE
268                             && azimuth != Double.MAX_VALUE) {
269                         lat = SphericalCoords.latFor(eventLat,
270                                                      eventLon,
271                                                      calcDist,
272                                                      azimuth);
273                         lon = SphericalCoords.lonFor(eventLat,
274                                                      eventLon,
275                                                      calcDist,
276                                                      azimuth);
277                         out.write("  " + outForms.formatLatLon(lat) + "  "
278                                 + outForms.formatLatLon(lon));
279                     } else if(stationLat != Double.MAX_VALUE
280                             && stationLon != Double.MAX_VALUE
281                             && backAzimuth != Double.MAX_VALUE) {
282                         lat = SphericalCoords.latFor(stationLat,
283                                                      stationLon,
284                                                      degrees - calcDist,
285                                                      backAzimuth);
286                         lon = SphericalCoords.lonFor(stationLat,
287                                                      stationLon,
288                                                      degrees - calcDist,
289                                                      backAzimuth);
290                         out.write("  " + outForms.formatLatLon(lat) + "  "
291                                 + outForms.formatLatLon(lon));
292                     } else if(stationLat != Double.MAX_VALUE
293                             && stationLon != Double.MAX_VALUE
294                             && eventLat != Double.MAX_VALUE
295                             && eventLon != Double.MAX_VALUE) {
296                         azimuth = SphericalCoords.azimuth(eventLat,
297                                                           eventLon,
298                                                           stationLat,
299                                                           stationLon);
300                         backAzimuth = SphericalCoords.azimuth(stationLat,
301                                                               stationLon,
302                                                               eventLat,
303                                                               eventLon);
304                         lat = SphericalCoords.latFor(eventLat,
305                                                      eventLon,
306                                                      calcDist,
307                                                      azimuth);
308                         lon = SphericalCoords.lonFor(eventLat,
309                                                      eventLon,
310                                                      calcDist,
311                                                      azimuth);
312                         out.write("  " + outForms.formatLatLon(lat) + "  "
313                                 + outForms.formatLatLon(lon));
314                     }
315                     out.write("\n");
316                 }
317                 prevDepth = currArrival.pierce[j].depth;
318             }
319         }
320     }
321 
322     /***
323      * checks to see if the given depth has been "added" as a pierce point.
324      */
325     public synchronized boolean isAddDepth(double depth) {
326         for(int i = 0; i < addDepth.length; i++) {
327             if(depth == addDepth[i]) { return true; }
328         }
329         return false;
330     }
331 
332     /*** prints the known command line flags. */
333     public void printUsage() {
334         printStdUsage();
335         System.out.println("-az azimuth        -- sets the azimuth (event to station)\n"
336                 + "                      used to output lat and lon of pierce points\n"
337                 + "                      if the event lat lon and distance are also\n"
338                 + "                      given. Calculated if station and event\n"
339                 + "                      lat and lon are given.");
340         System.out.println("-baz backazimuth   -- sets the back azimuth (station to event)\n"
341                 + "                      used to output lat and lon of pierce points\n"
342                 + "                      if the station lat lon and distance are also\n"
343                 + "                      given. Calculated if station and event\n"
344                 + "                      lat and lon are given.\n");
345         System.out.println("-rev               -- only prints underside and bottom turn points, e.g. ^ and v");
346         System.out.println("-turn              -- only prints bottom turning points, e.g. v");
347         System.out.println("-under             -- only prints underside reflection points, e.g. ^\n");
348         System.out.println("-pierce depth      -- adds depth for calculating pierce points");
349         System.out.println("-nodiscon          -- only prints pierce points for the depths added with -pierce\n");
350         printStdUsageTail();
351     }
352 
353     public String[] parseCmdLineArgs(String[] args) throws IOException {
354         int i = 0;
355         String[] leftOverArgs;
356         int numNoComprendoArgs = 0;
357         File tempFile;
358         leftOverArgs = super.parseCmdLineArgs(args);
359         String[] noComprendoArgs = new String[leftOverArgs.length];
360         while(i < leftOverArgs.length) {
361             if(leftOverArgs[i].equalsIgnoreCase("-turn")) {
362                 onlyTurnPoints = true;
363             } else if(leftOverArgs[i].equalsIgnoreCase("-rev")) {
364                 onlyRevPoints = true;
365             } else if(leftOverArgs[i].equalsIgnoreCase("-under")) {
366                 onlyUnderPoints = true;
367             } else if(leftOverArgs[i].equalsIgnoreCase("-pierce")
368                     && i < leftOverArgs.length - 1) {
369                 appendAddDepths(leftOverArgs[i + 1]);
370                 i++;
371             } else if(leftOverArgs[i].equalsIgnoreCase("-nodiscon")) {
372                 onlyAddPoints = true;
373             } else if(leftOverArgs[i].equals("-help")) {
374                 noComprendoArgs[numNoComprendoArgs++] = leftOverArgs[i];
375             } else {
376                 noComprendoArgs[numNoComprendoArgs++] = leftOverArgs[i];
377             }
378             i++;
379         }
380         if(numNoComprendoArgs > 0) {
381             String[] temp = new String[numNoComprendoArgs];
382             System.arraycopy(noComprendoArgs, 0, temp, 0, numNoComprendoArgs);
383             return temp;
384         } else {
385             return new String[0];
386         }
387     }
388 
389     /***
390      * Allows TauP_Pierce to run as an application. Creates an instance of
391      * TauP_Pierce. .
392      */
393     public static void main(String[] args) throws FileNotFoundException,
394             IOException, StreamCorruptedException, ClassNotFoundException,
395             OptionalDataException {
396         try {
397             TauP_Pierce tauPPierce = new TauP_Pierce();
398             String[] noComprendoArgs = tauPPierce.parseCmdLineArgs(args);
399             if(noComprendoArgs.length > 0) {
400                 for(int i = 0; i < noComprendoArgs.length; i++) {
401                     if(noComprendoArgs[i].equals("-help")
402                             || noComprendoArgs[i].equals("-version")) {
403                         System.exit(0);
404                     }
405                 }
406                 System.out.println("I don't understand the following arguments, continuing:");
407                 for(int i = 0; i < noComprendoArgs.length; i++) {
408                     System.out.print(noComprendoArgs[i] + " ");
409                     if(noComprendoArgs[i].equals("-help")
410                             || noComprendoArgs[i].equals("-version")) {
411                         System.out.println();
412                         System.exit(0);
413                     }
414                 }
415                 System.out.println();
416                 noComprendoArgs = null;
417             }
418             if(tauPPierce.DEBUG) {
419                 System.out.println("Done reading " + tauPPierce.modelName);
420             }
421             tauPPierce.init();
422             tauPPierce.start();
423             tauPPierce.destroy();
424         } catch(TauModelException e) {
425             System.out.println("Caught TauModelException: " + e.getMessage());
426             e.printStackTrace();
427         } catch(TauPException e) {
428             System.out.println("Caught TauPException: " + e.getMessage());
429             e.printStackTrace();
430         }
431     }
432 }