001 /*
002 * $Id: AddeSoundingAdapter.java,v 1.4 2012/02/19 17:35:40 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2012
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 *
012 * All Rights Reserved
013 *
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.
016 *
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 *
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025 * GNU Lesser Public License for more details.
026 *
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program. If not, see http://www.gnu.org/licenses.
029 */
030
031 package edu.wisc.ssec.mcidasv.data.adde;
032
033
034 import java.util.ArrayList;
035 import java.util.Collections;
036 import java.util.Map;
037 import java.util.StringTokenizer;
038
039 import edu.wisc.ssec.mcidas.McIDASUtil;
040 import edu.wisc.ssec.mcidas.adde.AddeException;
041 import edu.wisc.ssec.mcidas.adde.AddePointDataReader;
042
043 import visad.DateTime;
044 import visad.Unit;
045
046 import ucar.unidata.beans.NonVetoableProperty;
047 import ucar.unidata.data.sounding.SoundingAdapter;
048 import ucar.unidata.data.sounding.SoundingAdapterImpl;
049 import ucar.unidata.data.sounding.SoundingOb;
050 import ucar.unidata.data.sounding.SoundingStation;
051 import ucar.unidata.util.LogUtil;
052 import ucar.unidata.util.Misc;
053 import ucar.unidata.util.StringUtil;
054 import ucar.visad.UtcDate;
055 import ucar.visad.Util;
056 import ucar.visad.quantities.GeopotentialAltitude;
057
058 import edu.wisc.ssec.mcidasv.chooser.adde.AddeChooser;
059
060 /**
061 * Class for retrieving upper air data from an ADDE remote server. Creates
062 * a SoundingOb for each of the stations on the remote server for the
063 * latest available data.
064 */
065 public class AddeSoundingAdapter extends SoundingAdapterImpl implements SoundingAdapter {
066
067 /** observed or satellite sounding? */
068 private boolean satelliteSounding = false;
069
070 /** these are only really used for satellite soundings */
071 private String satelliteTime = "";
072 private String satellitePixel = "";
073
074 /** parameter identifier */
075 private static final String P_PARAM = "param";
076
077 /** number of obs identifier */
078 private static final String P_NUM = "num";
079
080 /** all obs identifier */
081 private static final String P_ALL = "all";
082
083 /** number of obs identifier */
084 private static final String P_POS = "pos";
085
086 /** group identifier */
087 private static final String P_GROUP = "group";
088
089 /** descriptor identifier */
090 private static final String P_DESCR = "descr";
091
092 /** select identifier */
093 private static final String P_SELECT = "select";
094
095 /** URL type identifier */
096 private static final String URL_ROOT = "/point";
097
098 /** URL protocol identifier */
099 private static final String URL_PROTOCOL = "adde";
100
101 /** server propert */
102 private NonVetoableProperty serverProperty;
103
104 /** mandatory data set property */
105 private NonVetoableProperty mandatoryDatasetProperty;
106
107 /** significant data set property */
108 private NonVetoableProperty significantDatasetProperty;
109
110 /** stations property */
111 private NonVetoableProperty stationsProperty;
112
113 /** sounding times property */
114 private NonVetoableProperty soundingTimesProperty;
115
116 /** mandatory data group name */
117 private String manGroup;
118
119 /** mandatory data descriptor */
120 private String manDescriptor;
121
122 /** sig data group name */
123 private String sigGroup = null;
124
125 /** sig data descriptor */
126 private String sigDescriptor = null;
127
128 /** use main hours only */
129 private boolean mainHours = false;
130
131 /** name of mandP pressure variable */
132 private String prMandPVar = "p";
133
134 /** name of mandP height variable */
135 private String htMandPVar = "z";
136
137 /** name of mandP temp variable */
138 private String tpMandPVar = "t";
139
140 /** name of mandP dewpoint variable */
141 private String tdMandPVar = "td";
142
143 /** name of mandP wind speed variable */
144 private String spdMandPVar = "spd";
145
146 /** name of mandP wind dir variable */
147 private String dirMandPVar = "dir";
148
149 /** name of day variable */
150 private String dayVar = "day";
151
152 /** name of time variable */
153 private String timeVar = "time";
154
155 /** name of station id variable */
156 private String idVar = "idn";
157
158 /** name of station latitude variable */
159 private String latVar = "lat";
160
161 /** name of station longitude variable */
162 private String lonVar = "lon";
163
164 /** name of station elevation variable */
165 private String eleVar = "zs";
166
167
168 /** server name */
169 private String server;
170
171 /** mandatory dataset name */
172 private String mandDataset;
173
174 /** significant dataset name */
175 private String sigDataset;
176
177 /** default server */
178 private String defaultServer = "adde.unidata.ucar.edu";
179
180 /** default mandatory data set */
181 private String defaultMandDataset = "rtptsrc/uppermand";
182
183 /** default significant dataset */
184 private String defaultSigDataset = "rtptsrc/uppersig";
185
186 /** Accounting information */
187 private static String user = "user";
188 private static String proj = "0";
189
190 protected boolean firstTime = true;
191 protected boolean retry = true;
192
193 /** Used to grab accounting information for a currently selected server. */
194 private AddeChooser addeChooser;
195 /**
196
197 * Construct an empty AddeSoundingAdapter
198 */
199 public AddeSoundingAdapter() {
200 super("AddeSoundingAdapter");
201 }
202
203 /**
204 * Retreive upper air data from a remote ADDE server using only
205 * mandatory data.
206 *
207 * @param server name or IP address of remote server
208 *
209 * @throws Exception (AddeException) if there is no data available or there
210 * is trouble connecting to the remote server
211 */
212 public AddeSoundingAdapter(String server) throws Exception {
213 this(server, null);
214 }
215
216 /**
217 * Retreive upper air data from a remote ADDE server using only
218 * mandatory data.
219 *
220 * @param server name or IP address of remote server
221 * @param dataset name of ADDE dataset (group/descriptor)
222 *
223 * @throws Exception (AddeException) if there is no data available or there
224 * is trouble connecting to the remote server
225 */
226 public AddeSoundingAdapter(String server, String dataset)
227 throws Exception {
228 this(server, dataset, null);
229 }
230
231
232
233 /**
234 * Retreive upper air data from a remote ADDE server using only
235 * mandatory data.
236 *
237 * @param server name or IP address of remote server
238 * @param mandDataset name of mandatory level upper air ADDE
239 * dataset (group/descriptor)
240 * @param sigDataset name of significant level upper air ADDE
241 * dataset (group/descriptor)
242 *
243 * @throws Exception (AddeException) if there is no data available
244 * or there is trouble connecting to the remote server
245 */
246 public AddeSoundingAdapter(String server, String mandDataset,
247 String sigDataset)
248 throws Exception {
249 this(server, mandDataset, sigDataset, false);
250 }
251
252 /**
253 * Retreive upper air data from a remote ADDE server using only
254 * mandatory data.
255 *
256 * @param server name or IP address of remote server
257 * @param mandDataset name of mandatory level upper air ADDE
258 * dataset (group/descriptor)
259 * @param sigDataset name of significant level upper air ADDE
260 * dataset (group/descriptor)
261 * @param mainHours only get data for main (00 & 12Z) hours
262 *
263 * @throws Exception (AddeException) if there is no data available
264 * or there is trouble connecting to the remote server
265 */
266 public AddeSoundingAdapter(String server, String mandDataset,
267 String sigDataset, boolean mainHours)
268 throws Exception {
269 this(server, mandDataset, sigDataset, false, null);
270 }
271
272
273 public AddeSoundingAdapter(String server, String mandDataset,
274 String sigDataset, boolean mainHours, AddeChooser chooser)
275 throws Exception {
276 super("AddeSoundingAdapter");
277 this.server = server;
278 this.mandDataset = mandDataset;
279 this.sigDataset = sigDataset;
280 this.mainHours = mainHours;
281 this.satelliteSounding = false;
282 this.satelliteTime = "";
283 this.satellitePixel = "";
284 this.addeChooser = chooser;
285 init();
286 }
287
288 public AddeSoundingAdapter(String server, String mandDataset,
289 String sigDataset, String satelliteTime, String satellitePixel, AddeChooser chooser)
290 throws Exception
291 {
292 super("AddeSoundingAdapter");
293 this.server = server;
294 this.mandDataset = mandDataset;
295 this.sigDataset = sigDataset;
296 this.mainHours = false;
297 this.satelliteSounding = true;
298 this.satelliteTime = satelliteTime;
299 this.satellitePixel = satellitePixel;
300 this.addeChooser = chooser;
301 init();
302 }
303
304 /**
305 * Initialize the class. Populate the variable list and get
306 * the server and dataset information.
307 *
308 * @throws Exception problem occurred
309 */
310 protected void init() throws Exception {
311 if (haveInitialized) {
312 return;
313 }
314 super.init();
315
316 getVariables();
317
318 if (server == null) {
319 server = defaultServer;
320 }
321
322 if (mandDataset == null) {
323 mandDataset = defaultMandDataset;
324 }
325
326 if (sigDataset == null) {
327 sigDataset = defaultSigDataset;
328 }
329
330 // set up the properties
331 addProperty(serverProperty = new NonVetoableProperty(this, "server"));
332 serverProperty.setValue(server);
333
334 addProperty(mandatoryDatasetProperty = new NonVetoableProperty(this,
335 "mandatoryDataset"));
336 mandatoryDatasetProperty.setValue(mandDataset);
337
338 addProperty(significantDatasetProperty =
339 new NonVetoableProperty(this, "significantDataset"));
340 significantDatasetProperty.setValue(sigDataset);
341
342 addProperty(stationsProperty = new NonVetoableProperty(this,
343 "stations"));
344 addProperty(soundingTimesProperty = new NonVetoableProperty(this,
345 "soundingTimes"));
346 loadStations();
347 }
348
349
350 /**
351 * Utility method that calls McIDASUtil.intBitsToString
352 * to get a string to compare to the given parameter s
353 *
354 * @param v integer string value
355 * @param s string to compare
356 * @return true if they are equal
357 */
358 private boolean intEqual(int v, String s) {
359 return (McIDASUtil.intBitsToString(v).equals(s));
360 }
361
362
363
364 /**
365 * Return the given String in single quotes
366 *
367 * @param s add single quotes to the string for select clauses
368 * @return single quoted string (ex: 'foo')
369 */
370 private String sQuote(String s) {
371 return "'" + s + "'";
372 }
373
374
375 /**
376 * Assemble the url from the given url argument array. This turns around
377 * and calls makeUrl, passing in the URL_ROOT ("/point") and the
378 * urlRoot to use.
379 *
380 * @param args URL arguments, key value pairs
381 * (ex: arg[0]=arg[1]&arg[2]=arg[3]...)
382 * @return associated URL
383 */
384 private String makeUrl(String[] args) {
385 return makeUrl(URL_ROOT, args);
386 }
387
388 /**
389 * Assemble the url from the given url root and url argument array.
390 * This returns:
391 * "URL_PROTOCOL://server urlRoot ?arg[0]=arg[1]&arg[2]=arg[3]...
392 *
393 * @param urlRoot root for the URL
394 * @param args key/value pair arguments
395 * @return ADDE URL
396 */
397 private String makeUrl(String urlRoot, String[] args) {
398 return Misc.makeUrl(URL_PROTOCOL, server, urlRoot, args);
399 }
400
401
402 /**
403 * Update this adapter for new data
404 */
405 public void update() {
406 checkInit();
407 try {
408 loadStations();
409 } catch (Exception exc) {
410 LogUtil.logException("Error updating AddeSoundingAdapter", exc);
411 }
412 }
413
414
415 /**
416 * Initialize the times, stations and soundings lists.
417 * Load the data into them.
418 *
419 * @throws AddeException error accessing the data
420 */
421
422 private void loadStations() {
423 times = new ArrayList(8);
424 stations = new ArrayList(100);
425 soundings = new ArrayList(100);
426 try {
427 if ((server != null) && (mandDataset != null)) {
428 loadStationsInner();
429 }
430 } catch (Exception excp) {
431 if (firstTime) {
432 String aes = excp.toString();
433 if ((aes.indexOf("Accounting data")) >= 0) {
434 if (addeChooser != null && addeChooser.canAccessServer()) {
435 Map<String, String> acctInfo = addeChooser.getAccountingInfo();
436 user = acctInfo.get("user");
437 proj = acctInfo.get("proj");
438 }
439 }
440 firstTime = false;
441 update();
442 }
443 }
444 stationsProperty.setValueAndNotifyListeners(stations);
445 soundingTimesProperty.setValueAndNotifyListeners(times);
446 }
447
448 private String getServer() {
449 return this.server;
450 }
451
452 /**
453 * Initialize the group and descriptor strings
454 */
455 private void initGroupAndDescriptors() {
456 if (manGroup == null) {
457 StringTokenizer tok = new StringTokenizer(mandDataset, "/");
458 if (tok.countTokens() != 2) {
459 throw new IllegalStateException(
460 "Illegal mandatory dataset name " + mandDataset);
461 }
462 manGroup = tok.nextToken();
463 manDescriptor = tok.nextToken();
464 }
465 if ((sigDataset != null) && (sigGroup == null)) {
466 StringTokenizer tok = new StringTokenizer(sigDataset, "/");
467 if (tok.countTokens() != 2) {
468 throw new IllegalStateException(
469 "Illegal significant dataset name " + mandDataset);
470 }
471 sigGroup = tok.nextToken();
472 sigDescriptor = tok.nextToken();
473 }
474 }
475
476
477 /**
478 * Actually do the work of loading the stations
479 *
480 * @throws AddeException problem accessing data
481 */
482 private void loadStationsInner() throws AddeException {
483 initGroupAndDescriptors();
484 String request = "";
485 if (!satelliteSounding) {
486 request = makeUrl(new String[] {
487 P_GROUP, manGroup, P_DESCR, manDescriptor, P_PARAM,
488 StringUtil.join(new String[] {
489 dayVar, timeVar, idVar, latVar, lonVar, eleVar
490 }), P_NUM, P_ALL, P_POS, P_ALL
491 }) + getManUserProj() + getStationsSelectString();
492 }
493 else {
494 request = makeUrl(new String[] {
495 P_GROUP, manGroup, P_DESCR, manDescriptor, P_PARAM,
496 StringUtil.join(new String[] {
497 dayVar, timeVar, idVar, latVar, lonVar
498 }), P_NUM, P_ALL, P_POS, P_ALL
499 }) + getManUserProj() + getStationsSelectString();
500 }
501 dbPrint(request);
502
503 //System.err.println("loading stations: " + request);
504
505 AddePointDataReader dataReader = new AddePointDataReader(request);
506 String[] units = dataReader.getUnits();
507 int[] scales = dataReader.getScales();
508 int[][] data = dataReader.getData();
509
510 for (int i = 0; i < data[0].length; i++) {
511 int day = data[0][i];
512 int time = data[1][i];
513 String wmoID = Integer.toString(data[2][i]);
514 double lat = scaleValue(data[3][i], scales[3]);
515 double lon = scaleValue(data[4][i], scales[4]);
516 lon = -lon; // change from McIDAS to eastPositive
517 double elev = 0;
518 if (!satelliteSounding)
519 elev = scaleValue(data[5][i], scales[5]);
520 try {
521 SoundingStation s = new SoundingStation(wmoID, lat, lon,
522 elev);
523 if ( !(stations.contains(s))) {
524 stations.add(s);
525 }
526 DateTime dt = new DateTime(McIDASUtil.mcDayTimeToSecs(day,
527 time));
528 soundings.add(new SoundingOb(s, dt));
529 if ( !times.contains(dt)) {
530 times.add(dt);
531 }
532 } catch (Exception vexcp) {
533 LogUtil.logException("Creating sounding", vexcp);
534 }
535 }
536 Collections.sort(times);
537 if (debug) {
538 System.out.println("Times:" + times);
539 }
540 }
541
542 /**
543 * Set the ADDE server name
544 *
545 * @param server server name or IP address
546 */
547 public void setSource(String server) {
548 this.server = server;
549 if (serverProperty != null) {
550 serverProperty.setValue(server);
551 }
552 }
553
554 /**
555 * Get the source of the data (server)
556 *
557 * @return server name or IP address
558 */
559 public String getSource() {
560 return server;
561 }
562
563
564 /**
565 * Set the mandatory data set name
566 *
567 * @param value mandatory data set name
568 */
569 public void setMandDataset(String value) {
570 mandDataset = value;
571 }
572
573 /**
574 * Set the mandatory data set name
575 *
576 * @return the mandatory data set name
577 */
578 public String getMandDataset() {
579 return mandDataset;
580 }
581
582
583 /**
584 * Set the significant data set name
585 *
586 * @param value the significant data set name
587 */
588 public void setSigDataset(String value) {
589 sigDataset = value;
590 }
591
592 /**
593 * Get the significant data set name
594 *
595 * @return the significant data set name
596 */
597 public String getSigDataset() {
598 return sigDataset;
599 }
600
601
602 /**
603 * Change behavior if we are looking at satellite soundings
604 */
605 public void setSatelliteSounding(boolean flag) {
606 satelliteSounding = flag;
607 }
608
609 /**
610 * Are we looking at satellite soundings?
611 */
612 public boolean getSatelliteSounding() {
613 return satelliteSounding;
614 }
615
616
617 /**
618 * Check to see if the RAOB has any data
619 *
620 * @param sound sounding to check
621 * @return a sounding with data
622 */
623 public SoundingOb initSoundingOb(SoundingOb sound) {
624 if ( !sound.hasData()) {
625 setRAOBData(sound);
626 }
627 return sound;
628 }
629
630 /**
631 * Make the select string that will get this observation
632 *
633 * @param sound sounding to use
634 * @return select string
635 */
636 private String makeSelectString(SoundingOb sound) {
637 return makeSelectString(sound.getStation().getIdentifier(),
638 sound.getTimestamp());
639 }
640
641
642 /**
643 * Make a select string for the given station id and date
644 *
645 * @param wmoId station id
646 * @param date time of data
647 * @return ADDE select clause for the given parameters
648 */
649 private String makeSelectString(String wmoId, DateTime date) {
650 String day = UtcDate.getYMD(date);
651 String time = UtcDate.getHHMM(date);
652 //int[] daytime = McIDASUtil.mcSecsToDayTime((long) date.getValue());
653 return new String(idVar + " " + wmoId + ";" + dayVar + " " + day
654 + ";" + timeVar + " " + time);
655 }
656
657 /**
658 * Fills in the data for the RAOB
659 *
660 * @param sound sounding ob to set
661 */
662 private void setRAOBData(SoundingOb sound) {
663
664 initGroupAndDescriptors();
665 int numLevels;
666 Unit pUnit = null,
667 tUnit = null,
668 tdUnit = null,
669 spdUnit = null,
670 dirUnit = null,
671 zUnit = null;
672 float p[], t[], td[], z[], spd[], dir[];
673 AddePointDataReader apdr;
674
675 String request = getMandatoryURL(sound);
676
677 dbPrint(request);
678 try {
679 if (sound.getMandatoryFile() != null) {
680 request = "file:" + sound.getMandatoryFile();
681 // System.err.println ("using fixed mandatory url:" + request);
682 }
683
684 apdr = new AddePointDataReader(request);
685 String[] params = apdr.getParams();
686 int[] scales = apdr.getScales();
687 String[] units = apdr.getUnits();
688 int[][] data = apdr.getData();
689
690 // Special case: GRET doesn't respond to SELECT DAY...
691 // Try again without it
692 if (satelliteSounding && data[0].length == 0) {
693 request = request.replaceAll("DAY [0-9-]+;?", "");
694 apdr = new AddePointDataReader(request);
695 params = apdr.getParams();
696 scales = apdr.getScales();
697 units = apdr.getUnits();
698 data = apdr.getData();
699 }
700
701 numLevels = data[0].length;
702 if (numLevels > 0) {
703 dbPrint("Num mand pressure levels = " + numLevels);
704 // Get the their units
705 pUnit = getUnit(units[0]);
706 // NB: geopotential altitudes stored in units of length
707 zUnit = GeopotentialAltitude.getGeopotentialUnit(
708 getUnit(units[1]));
709 tUnit = getUnit(units[2]);
710 tdUnit = getUnit(units[3]);
711 // Satellite soundings don't have spd or dir
712 if (units.length > 4) {
713 spdUnit = getUnit(units[4]);
714 dirUnit = getUnit(units[5]);
715 }
716 else {
717 spdUnit = getUnit("MPS");
718 dirUnit = getUnit("DEG");
719 }
720
721 // initialize the arrays
722 p = new float[numLevels];
723 z = new float[numLevels];
724 t = new float[numLevels];
725 td = new float[numLevels];
726 spd = new float[numLevels];
727 dir = new float[numLevels];
728
729 // fill the arrays
730 for (int i = 0; i < numLevels; i++) {
731 p[i] = (float) scaleValue(data[0][i], scales[0]);
732 z[i] = (float) scaleValue(data[1][i], scales[1]);
733 t[i] = (float) scaleValue(data[2][i], scales[2]);
734 td[i] = (float) scaleValue(data[3][i], scales[3]);
735 // Satellite soundings don't have spd or dir
736 if (data.length > 4 && scales.length > 4) {
737 spd[i] = (float) scaleValue(data[4][i], scales[4]);
738 dir[i] = (float) scaleValue(data[5][i], scales[5]);
739 }
740 else {
741 if (i==0) spd[i] = dir[i] = (float) 0;
742 else spd[i] = dir[i] = (float) scaleValue(McIDASUtil.MCMISSING, 0);
743 }
744 }
745 if (debug) {
746 System.out.println("P[" + pUnit + "]\t" + "Z[" + zUnit
747 + "]\t" + "T[" + tUnit + "]\t" + "TD["
748 + tdUnit + "]\t" + "SPD[" + spdUnit
749 + "]\t" + "DIR[" + dirUnit + "]");
750 for (int i = 0; i < numLevels; i++) {
751 System.out.println(p[i] + "\t" + z[i] + "\t" + t[i]
752 + "\t" + td[i] + "\t" + spd[i]
753 + "\t" + dir[i]);
754 }
755 }
756 sound.getRAOB().setMandatoryPressureProfile(pUnit, p, tUnit,
757 t, tdUnit, td, spdUnit, spd, dirUnit, dir, zUnit, z);
758 }
759 } catch (Exception e) {
760 LogUtil.logException(
761 "Unable to set mandatory pressure data for station "
762 + sound.getStation(), e);
763 }
764
765 // Done if we have no sig data
766 if ((sigGroup == null) || (sigDescriptor == null)) {
767 return;
768 }
769
770 request = getSigURL(sound);
771 dbPrint(request);
772
773 // get the sig data
774 try {
775 if (sound.getSigFile() != null) {
776 request = "file:" + sound.getSigFile();
777 // System.err.println ("using fixed sig url:" + request);
778 }
779
780 apdr = new AddePointDataReader(request);
781 String[] params = apdr.getParams();
782 int[] scales = apdr.getScales();
783 String[] units = apdr.getUnits();
784 int[][] data = apdr.getData();
785
786 numLevels = data[0].length;
787 if (numLevels > 0) {
788 // Determine how many of each kind of level
789 int numSigW = 0;
790 int numSigT = 0;
791 for (int i = 0; i < data[0].length; i++) {
792 if (intEqual(data[0][i], "SIGT")) {
793 numSigT++;
794 }
795 if (intEqual(data[0][i], "SIGW")) {
796 numSigW++;
797 }
798 }
799
800 dbPrint("Num sig temperature levels = " + numSigT);
801 dbPrint("Num sig wind levels = " + numSigW);
802
803
804 // Get the units & initialize the arrays
805 pUnit = getUnit("mb");
806 tUnit = getUnit("k");
807 tdUnit = getUnit("k");
808 // NB: geopotential altitudes stored in units of length
809 zUnit =
810 GeopotentialAltitude.getGeopotentialUnit(getUnit("m"));
811 spdUnit = getUnit("mps");
812 dirUnit = getUnit("deg");
813
814 p = new float[numSigT];
815 t = new float[numSigT];
816 td = new float[numSigT];
817 z = new float[numSigW];
818 spd = new float[numSigW];
819 dir = new float[numSigW];
820
821 // fill the arrays
822 int j = 0; // counter for sigT
823 int l = 0; // counter for sigW
824 for (int i = 0; i < numLevels; i++) {
825 if (intEqual(data[0][i], "SIGT")) {
826 p[j] = (float) scaleValue(data[3][i], 1);
827 t[j] = (float) scaleValue(data[1][i], 2);
828 td[j] = (float) scaleValue(data[2][i], 2);
829 j++;
830 } else if (intEqual(data[0][i], "SIGW")) {
831 z[l] = (data[3][i] == 0)
832 ? (float) ((SoundingStation) sound
833 .getStation()).getAltitudeAsDouble()
834 : (float) scaleValue(data[3][i], 0);
835 spd[l] = (float) scaleValue(data[2][i], 1);
836 dir[l] = (float) scaleValue(data[1][i], 0);
837 l++;
838 }
839 }
840 if (numSigT > 0) {
841 try {
842 if (debug) {
843 System.out.println("P[" + pUnit + "]\tT[" + tUnit
844 + "]\tTD[" + tdUnit + "]");
845 for (int i = 0; i < numSigT; i++) {
846 System.out.println(p[i] + "\t" + t[i] + "\t"
847 + td[i]);
848 }
849 }
850 sound.getRAOB().setSignificantTemperatureProfile(
851 pUnit, p, tUnit, t, tdUnit, td);
852 } catch (Exception e) {
853 LogUtil.logException(
854 "Unable to set significant temperature data for station "
855 + sound.getStation(), e);
856 }
857 }
858 if (numSigW > 0) {
859 try {
860 if (debug) {
861 System.out.println("Z[" + zUnit + "]\tSPD["
862 + spdUnit + "]\tDIR[" + dirUnit + "]");
863 for (int i = 0; i < numSigW; i++) {
864 System.out.println(z[i] + "\t" + spd[i]
865 + "\t" + dir[i]);
866 }
867 }
868 sound.getRAOB().setSignificantWindProfile(zUnit, z,
869 spdUnit, spd, dirUnit, dir);
870 } catch (Exception e) {
871 LogUtil.logException(
872 "Unable to set significant wind data for station "
873 + sound.getStation(), e);
874 }
875 }
876 }
877 } catch (Exception e) {
878 LogUtil.logException(
879 "Unable to retrieve significant level data for station "
880 + sound.getStation(), e);
881 }
882 }
883
884
885 /**
886 * scale the values returned from the server
887 *
888 * @param value value to scale
889 * @param scale scale factor
890 * @return scaled value
891 */
892 private double scaleValue(int value, int scale) {
893 return (value == McIDASUtil.MCMISSING)
894 ? Double.NaN
895 : (value / Math.pow(10.0, (double) scale));
896 }
897
898 /**
899 * Gets the units of the variable. Now just a passthrough to
900 * ucar.visad.Util.
901 *
902 * @param unitName unit name
903 * @return corresponding Unit or null if can't be decoded
904 * @see ucar.visad.Util#parseUnit(String)
905 */
906 private Unit getUnit(String unitName) {
907 try {
908 return Util.parseUnit(unitName);
909 } catch (Exception e) {}
910 return null;
911 }
912
913 /**
914 * Get a default value using this Adapter's prefix
915 *
916 * @param name name of property key
917 * @param dflt default value
918 * @return the default for that property or dflt if not in properties
919 */
920 private String getDflt(String name, String dflt) {
921 return getDflt("AddeSoundingAdapter.", name, dflt);
922 }
923
924 /**
925 * Determines the names of the variables in the netCDF file that
926 * should be used.
927 */
928 private void getVariables() {
929 // initialize the defaults for this object
930 try {
931 defaultServer = getDflt("serverName", defaultServer);
932 defaultMandDataset = getDflt("mandDataset", defaultMandDataset);
933 defaultSigDataset = getDflt("sigDataset", defaultSigDataset);
934 idVar = getDflt("stationIDVariable", idVar);
935 latVar = getDflt("latitudeVariable", latVar);
936 lonVar = getDflt("longitudeVariable", lonVar);
937 eleVar = getDflt("stationElevVariable", eleVar);
938 timeVar = getDflt("soundingTimeVariable", timeVar);
939 dayVar = getDflt("soundingDayVariable", dayVar);
940
941 prMandPVar = getDflt("mandPPressureVariable", prMandPVar);
942 htMandPVar = getDflt("mandPHeightVariable", htMandPVar);
943 tpMandPVar = getDflt("mandPTempVariable", tpMandPVar);
944 tdMandPVar = getDflt("mandPDewptVariable", tdMandPVar);
945 spdMandPVar = getDflt("mandPWindSpeedVariable", spdMandPVar);
946 dirMandPVar = getDflt("mandPWindDirVariable", dirMandPVar);
947
948 // Significant Temperature data
949 /*
950 numSigT = nc.get(getDflt("NetcdfSoundingAdapter.", "numSigTempLevels", "numSigT"));
951 if (numSigT != null) {
952 hasSigT = true;
953 prSigTVar = getDflt ("NetcdfSoundingAdapter.", "sigTPressureVariable", "prSigT");
954 tpSigTVar = getDflt ("NetcdfSoundingAdapter.", "sigTTempVariable", "tpSigT");
955 tdSigTVar = getDflt("NetcdfSoundingAdapter.", "sigTDewptVariable", "tdSigT");
956 }
957
958 // Significant Wind data
959 numSigW = nc.get(getDflt("NetcdfSoundingAdapter.", "numSigWindLevels", "numSigW"));
960 if (numSigW != null) {
961 hasSigW = true;
962 htSigWVar = getDflt ("NetcdfSoundingAdapter.", "sigWHeightVariable", "htSigW");
963 spdSigWVar = getDflt("NetcdfSoundingAdapter.", "sigWWindSpeedVariable", "wsSigW");
964 dirSigWVar = getDflt("NetcdfSoundingAdapter.", "sigWWindDirVariable", "wdSigW");
965 }
966 */
967 } catch (Exception e) {
968 System.out.println("Unable to initialize defaults file");
969 }
970 }
971
972 /**
973 * Get significant data ADDE user/project id for the data
974 * @return user/project string (ex: "id=idv proj=0")
975 */
976 private String getSigUserProj() {
977 return getUserProj(new String(sigGroup + "/"
978 + sigDescriptor).toUpperCase());
979 }
980
981 /**
982 * Make the mandatory levels URL for the given sounding
983 *
984 * @param sound sounding
985 *
986 * @return mandatory url
987 */
988 public String getMandatoryURL(SoundingOb sound) {
989 String select = makeSelectString(sound);
990 String paramString;
991 if (!satelliteSounding) {
992 paramString = StringUtil.join(new String[] {
993 prMandPVar, htMandPVar, tpMandPVar, tdMandPVar, spdMandPVar, dirMandPVar
994 });
995 }
996 else {
997 paramString = StringUtil.join(new String[] {
998 prMandPVar, htMandPVar, tpMandPVar, tdMandPVar
999 });
1000 }
1001 String request = makeUrl(new String[] {
1002 P_GROUP, manGroup, P_DESCR, manDescriptor, P_SELECT,
1003 sQuote(select), P_PARAM, paramString, P_NUM, P_ALL, P_POS, P_ALL
1004 }) + getManUserProj();
1005
1006 return request;
1007
1008 }
1009
1010 /**
1011 * Make the url for the significant levels for the sounding
1012 *
1013 * @param sound the sounding
1014 *
1015 * @return sig url
1016 */
1017 public String getSigURL(SoundingOb sound) {
1018 // If we haven't picked a sig dataset, act as though both are mandatory
1019 if (mandDataset.equals(sigDataset)) {
1020 return getMandatoryURL(sound);
1021 }
1022
1023 String select = makeSelectString(sound);
1024 String paramString;
1025 if (!satelliteSounding) {
1026 paramString = "type p1 p2 p3";
1027 }
1028 else {
1029 paramString = StringUtil.join(new String[] {
1030 prMandPVar, htMandPVar, tpMandPVar, tdMandPVar
1031 });
1032 }
1033 String request = makeUrl(new String[] {
1034 P_GROUP, sigGroup, P_DESCR, sigDescriptor, P_SELECT,
1035 sQuote(select), P_PARAM, paramString, P_NUM, P_ALL, P_POS, P_ALL
1036 }) + getSigUserProj();
1037
1038 return request;
1039 }
1040
1041
1042 /**
1043 * Get mandatory data ADDE user/project id for the data
1044 *
1045 * @return user/project string (ex: "id=idv proj=0")
1046 */
1047 private String getManUserProj() {
1048 return getUserProj(new String(manGroup + "/"
1049 + manDescriptor).toUpperCase());
1050 }
1051
1052 /**
1053 * Get the user/project string for the given key
1054 *
1055 * @param key group/descriptor
1056 *
1057 * @return user/project string (ex: "id=idv proj=0") for the specified
1058 * dataset
1059 */
1060 private String getUserProj(String key) {
1061 StringBuffer buf = new StringBuffer();
1062 buf.append("&proj=");
1063 buf.append(getDflt("", key.toUpperCase().trim() + ".proj", proj));
1064 buf.append("&user=");
1065 buf.append(getDflt("", key.toUpperCase().trim() + ".user", user));
1066 buf.append("&compress=gzip");
1067 //buf.append("&debug=true");
1068 return buf.toString();
1069 }
1070
1071 /**
1072 * Get the select string for use in loadStations
1073 *
1074 * @return select string
1075 */
1076 private String getStationsSelectString() {
1077 StringBuffer buf;
1078 if (!satelliteSounding) {
1079 if ( !mainHours) {
1080 return "";
1081 }
1082 buf = new StringBuffer();
1083 buf.append("&SELECT='");
1084 buf.append(timeVar + " 00,12'");
1085 }
1086 else {
1087 buf = new StringBuffer();
1088 buf.append("&SELECT='");
1089 buf.append(timeVar + " " + satelliteTime);
1090 if (!satellitePixel.equals("")) {
1091 buf.append("; " + idVar + " " + satellitePixel);
1092 }
1093 buf.append("'");
1094 }
1095 return buf.toString();
1096 }
1097
1098 /**
1099 * test by running java ucar.unidata.data.sounding.AddeSoundingAdapter
1100 *
1101 * @param args array of arguments. Takes up to 3 arguments as
1102 * "server mandatory dataset significant dataset"
1103 * Use "x" for any of these arguments to use the default.
1104 */
1105 public static void main(String[] args) {
1106 String server = "adde.unidata.ucar.edu";
1107 String manset = "rtptsrc/uppermand";
1108 String sigset = "rtptsrc/uppersig";
1109 if (args.length > 0) {
1110 server = ( !(args[0].equalsIgnoreCase("x")))
1111 ? args[0]
1112 : server;
1113 if (args.length > 1) {
1114 manset = ( !(args[1].equalsIgnoreCase("x")))
1115 ? args[1]
1116 : manset;
1117 }
1118 if (args.length > 2) {
1119 sigset = ( !(args[2].equalsIgnoreCase("x")))
1120 ? args[2]
1121 : sigset;
1122 }
1123 }
1124 // try {
1125 // AddeSoundingAdapter asa =
1126 // //new AddeSoundingAdapter(server, manset, sigset);
1127 // new AddeSoundingAdapter();
1128 /*
1129 Thread.sleep(5000);
1130 asa.setServer("hurri.kean.edu");
1131 Thread.sleep(5000);
1132 asa.setServer("adde.unidata.ucar.edu");
1133 Thread.sleep(5000);
1134 asa.setMandatoryDataset("blizzard/uppermand");
1135 */
1136 // }
1137 // catch (Exception me) {
1138 // System.out.println(me);
1139 // }
1140 }
1141
1142
1143 /**
1144 * The string representation
1145 * @return The string
1146 */
1147 public String toString() {
1148 return "SoundingAdapter:" + server;
1149
1150 }
1151
1152
1153
1154
1155
1156 }
1157