/* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ // // TCData.java // // Version 3 April 2001 package visad.bom; import visad.*; import visad.util.Util; import java.rmi.RemoteException; public class TCData { // this is the actual TC data object FieldImpl data = null; // Time static RealType rtTime = RealType.Time; // Location static RealType rtConfidence; static RealType rtLat; static RealType rtLon; static RealType rtError; static RealType rtLocationStyle; static RealTupleType locationTuple; static FunctionType locationFunction; // Intensity static RealType rtWindMean; static RealType rtWindGust; static RealType rtCentralPressure; static RealType rtCategory; static RealType rtIntensityStyle; // Size static RealType rtGaleRadius; static RealType rtStormRadius; static RealType rtHurricaneRadius; static RealType rtRadiusOfMaximumWinds; static RealType rtSizeStyle; // Structure static RealType rtDepth; static RealType rtEyeDiameter; static RealType rtPressureOfLastClosedIsobar; static RealType rtStructureStyle; // Track static RealType rtTrackID; static TextType ttTrackType; static TextType ttTrackName; static RealType rtBaseDateTime; static RealType rtCreateDateTime; static TextType ttTrackStyle; static TupleType ttTrack; static FunctionType ftId2Track; // Disturbance static RealType rtDisturbanceID; static TextType ttCountry; static TextType ttState; static RealType rtYear; static RealType rtNumber; static TextType ttHistoricalName; static RealType rtOpenDate; static RealType rtCloseDate; static RealType rtArchiveMode; static RealType rtRealtimeMode; static TupleType ttDisturbance; static FunctionType ftId2Disturbance; static FunctionType mtTC; public TCData() throws VisADException { if (mtTC == null) { rtTime = RealType.Time; // Location rtConfidence = RealType.getRealType("CONFIDENCE", null, null); rtLat = RealType.Latitude; rtLon = RealType.Longitude; rtError = RealType.getRealType("ERROR", null, null); rtLocationStyle = RealType.getRealType("LOCATIONSTYLE", null, null); // Intensity rtWindMean = RealType.getRealType("WINDMEAN", null, null); rtWindGust = RealType.getRealType("WINDGUST", null, null); rtCentralPressure = RealType.getRealType("CENTRALPRESSURE", null, null); rtCategory = RealType.getRealType("CATEGORY", null, null); rtIntensityStyle = RealType.getRealType("INTENSITYSTYLE", null, null); // Size rtGaleRadius = RealType.getRealType("GALERADIUS", null, null); rtStormRadius = RealType.getRealType("STORMRADIUS", null, null); rtHurricaneRadius = RealType.getRealType("HURRICANERADIUS", null, null); rtRadiusOfMaximumWinds = RealType.getRealType("RADIUSOFMAXIMUMWINDS", null, null); rtSizeStyle = RealType.getRealType("SIZESTYLE", null, null); // Structure rtDepth = RealType.getRealType("DEPTH", null, null); rtEyeDiameter = RealType.getRealType("EYEDIAMETER", null, null); rtPressureOfLastClosedIsobar = RealType.getRealType("PRESSUREOFLASTCLOSEDISOBAR", null, null); rtStructureStyle = RealType.getRealType("STRUCTURESTYLE", null, null); RealTupleType locationTuple = new RealTupleType(new RealType[] {rtLat, rtLon, rtError, rtConfidence, rtLocationStyle, rtWindMean, rtWindGust, rtCentralPressure, rtCategory, rtIntensityStyle, rtGaleRadius, rtStormRadius, rtHurricaneRadius, rtRadiusOfMaximumWinds, rtSizeStyle, rtDepth, rtEyeDiameter, rtPressureOfLastClosedIsobar, rtStructureStyle }); locationFunction = new FunctionType(rtTime, locationTuple); // Track rtTrackID = RealType.getRealType("TRACKID", null, null); ttTrackType = TextType.getTextType("TRACKTYPE"); ttTrackName = TextType.getTextType("TRACKNAME"); rtBaseDateTime = RealType.getRealType("BASEDATETIME", null, null); rtCreateDateTime = RealType.getRealType("CREATEDATETIME", null, null); ttTrackStyle = TextType.getTextType("TRACKSTYLE"); ttTrack = new TupleType(new MathType[] {ttTrackType, ttTrackName, rtBaseDateTime, rtCreateDateTime, ttTrackStyle, locationFunction}); ftId2Track = new FunctionType(rtTrackID, ttTrack); // Disturbance rtDisturbanceID = RealType.getRealType("DISTURBANCEID", null, null); ttCountry = TextType.getTextType("COUNTRY"); ttState = TextType.getTextType("STATE"); ttHistoricalName = TextType.getTextType("HISTORICALNAME"); rtYear = RealType.getRealType("YEAR", null, null); rtNumber = RealType.getRealType("NUM", null, null); rtOpenDate = RealType.getRealType("OPENDATE", null, null); rtCloseDate = RealType.getRealType("CLOSEDATE", null, null); rtArchiveMode = RealType.getRealType("ARCHIVEMODE", null, null); rtRealtimeMode = RealType.getRealType("REALTIMEMODE", null, null); TupleType ttDisturbance = new TupleType(new MathType[] {ttCountry, ttState, rtYear, rtNumber, ttHistoricalName, rtOpenDate, rtCloseDate, rtArchiveMode, rtRealtimeMode, ftId2Track}); FunctionType ftId2Disturbance = new FunctionType(rtDisturbanceID, ttDisturbance); mtTC = ftId2Disturbance; } } public FieldImpl getData() { return data; } public MathType getType() { return mtTC; } public synchronized void addLocation(int disturbanceID, int trackID, double time, RealTuple location) throws VisADException, RemoteException { addToTrack(disturbanceID, trackID, time, 5, locationFunction, location); } /* public synchronized void addIntensity(int disturbanceID, int trackID, double time, RealTuple intensity) throws VisADException, RemoteException { addToTrack(disturbanceID, trackID, time, 6, intensityFunction, intensity); } public synchronized void addSize(int disturbanceID, int trackID, double time, RealTuple size) throws VisADException, RemoteException { addToTrack(disturbanceID, trackID, time, 7, sizeFunction, size); } public synchronized void addSteering(int disturbanceID, int trackID, double time, RealTuple steering) throws VisADException, RemoteException { addToTrack(disturbanceID, trackID, time, 8, steeringFunction, steering); } */ private void addToTrack(int disturbanceID, int trackID, double time, int tuple_index, FunctionType function_type, RealTuple rt) throws VisADException, RemoteException { Tuple disturbance = getDisturbance(disturbanceID); if (disturbance == null) { throw new VisADException("invalid disturbanceID"); } Tuple track = getTrack(trackID, disturbance); if (track == null) { throw new VisADException("invalid trackID"); } FlatField field = (FlatField) track.getComponent(tuple_index); Gridded1DDoubleSet set = (Gridded1DDoubleSet) field.getDomainSet(); double[][] times = set.getDoubles(false); int length = set.getLength(); double[][] new_times = new double[1][length + 1]; float[][] values = field.getFloats(false); int dim = values.length; float[][] new_values = new float[dim][length + 1]; int k = 0; int m = -1; for (int i=0; i<length+1; i++) { if (Util.isApproximatelyEqual(time, times[0][k])) { throw new VisADException("time " + time + " already used"); } else if (m < 0 && time < times[0][k]) { new_times[0][i] = time; // mark as missing until new_field.setSample(m, rt) call for (int j=0; j<dim; j++) new_values[j][i] = Float.NaN; m = i; } else { new_times[0][i] = times[0][k]; for (int j=0; j<dim; j++) new_values[j][i] = values[j][k]; k++; } } Gridded1DDoubleSet new_set = new Gridded1DDoubleSet(rtTime, new_times, length + 1); FlatField new_field = new FlatField(function_type, new_set); new_field.setSamples(new_values, false); new_field.setSample(m, rt); Data[] comps = new Data[] {track.getComponent(0), track.getComponent(1), track.getComponent(2), track.getComponent(3), track.getComponent(4), track.getComponent(5)}; // track.getComponent(6), // track.getComponent(7), // track.getComponent(8)}; comps[tuple_index] = new_field; Tuple new_track = new Tuple(new Data[] {comps[0], comps[1], comps[2], comps[3], comps[4], comps[5]}); // comps[6], comps[7], comps[8]}); setTrack(trackID, new_track, disturbance); setDisturbance(disturbanceID, disturbance); } public static FieldImpl makeTrackField(int trackID, Tuple track) throws VisADException, RemoteException { float fid = (float) trackID; Gridded1DSet set = new Gridded1DSet(rtTrackID, new float[][] {{fid}}, 1); FieldImpl field = new FieldImpl(ftId2Track, set); //au.gov.bom.fdb.debug.Debug.println(field); //au.gov.bom.fdb.debug.Debug.println(track); field.setSample(0, track); return field; } public synchronized void addTrack(int disturbanceID, int trackID, Tuple track) throws VisADException, RemoteException { Tuple disturbance = getDisturbance(disturbanceID); if (disturbance == null) { throw new VisADException("invalid disturbanceID"); } FieldImpl field = (FieldImpl) disturbance.getComponent(9); // desired field has MathType ftId2Track; // now we want to add a particular track to this field // in an analagous manner to adding a disturbance (ie the addDisturbance method) /* wlh comments: // not necessary since field is mutable // so merge find* methods into get* methods and eliminate set* methods **** // setDisturbance(disturbanceID, disturbance); */ float fid = (float) trackID; FieldImpl new_field = null; if (field == null) { Gridded1DSet set = new Gridded1DSet(rtTrackID, new float[][] {{fid}}, 1); new_field = new FieldImpl(ftId2Track, set); new_field.setSample(0, track); } else { Gridded1DSet set = (Gridded1DSet) field.getDomainSet(); float[][] ids = set.getSamples(false); int length = set.getLength(); float[][] new_ids = new float[1][length + 1]; int k = 0; int m = -1; for (int i=0; i<length+1; i++) { if (fid == ids[0][k]) { throw new VisADException("trackID " + trackID + " already used"); } else if (m < 0 && fid < ids[0][k]) { new_ids[0][i] = fid; m = i; } else { new_ids[0][i] = ids[0][k]; k++; } } Gridded1DSet new_set = new Gridded1DSet(rtTrackID, new_ids, length + 1); new_field = new FieldImpl(ftId2Track, new_set); k = 0; for (int i=0; i<length+1; i++) { if (i == m) { new_field.setSample(i, track, false); } else { new_field.setSample(i, field.getSample(k), false); k++; } } } Tuple new_disturbance = new Tuple(new Data[] {disturbance.getComponent(0), disturbance.getComponent(1), disturbance.getComponent(2), disturbance.getComponent(3), disturbance.getComponent(4), disturbance.getComponent(5), disturbance.getComponent(6), disturbance.getComponent(7), disturbance.getComponent(8), new_field}); setDisturbance(disturbanceID, new_disturbance); } public synchronized void addDisturbance(int disturbanceID, Tuple disturbance) throws VisADException, RemoteException { float fid = (float) disturbanceID; if (data == null) { Gridded1DSet set = new Gridded1DSet(rtDisturbanceID, new float[][] {{fid}}, 1); data = new FieldImpl(mtTC, set); data.setSample(0, disturbance); } else { Gridded1DSet set = (Gridded1DSet) data.getDomainSet(); float[][] ids = set.getSamples(false); int length = set.getLength(); float[][] new_ids = new float[1][length + 1]; int k = 0; int m = -1; for (int i=0; i<length+1; i++) { if (fid == ids[0][k]) { throw new VisADException("disturbanceID " + disturbanceID + " already used"); } else if (m < 0 && fid < ids[0][k]) { new_ids[0][i] = fid; m = i; } else { new_ids[0][i] = ids[0][k]; k++; } } Gridded1DSet new_set = new Gridded1DSet(rtDisturbanceID, new_ids, length + 1); FieldImpl new_data = new FieldImpl(mtTC, new_set); k = 0; for (int i=0; i<length+1; i++) { if (i == m) { new_data.setSample(i, disturbance, false); } else { new_data.setSample(i, data.getSample(k), false); k++; } } data = new_data; } } private Tuple getDisturbance(int disturbanceID) throws VisADException, RemoteException { int index = findDisturbance(disturbanceID); if (index < 0) return null; else return (Tuple) data.getSample(index); } private void setDisturbance(int disturbanceID, Tuple disturbance) throws VisADException, RemoteException { int index = findDisturbance(disturbanceID); if (index >= 0) data.setSample(index, disturbance); } private int findDisturbance(int disturbanceID) throws VisADException, RemoteException { if (data == null) { return -1; } Gridded1DSet set = (Gridded1DSet) data.getDomainSet(); float[][] ids = set.getSamples(false); int length = set.getLength(); float fid = disturbanceID; for (int i=0; i<length; i++) { if (ids[0][i] == fid) return i; } return -1; } private Tuple getTrack(int trackID, Tuple disturbance) throws VisADException, RemoteException { int index = findTrack(trackID, disturbance); if (index < 0) return null; else { FieldImpl field = (FieldImpl) disturbance.getComponent(9); return (Tuple) field.getSample(index); } } private void setTrack(int trackID, Tuple track, Tuple disturbance) throws VisADException, RemoteException { int index = findTrack(trackID, disturbance); if (index >= 0) { FieldImpl field = (FieldImpl) disturbance.getComponent(9); field.setSample(index, track); } } private int findTrack(int trackID, Tuple disturbance) throws VisADException, RemoteException { if (disturbance == null) { return -1; } FieldImpl field = (FieldImpl) disturbance.getComponent(9); if (field == null) { return -1; } Gridded1DSet set = (Gridded1DSet) field.getDomainSet(); float[][] ids = set.getSamples(false); int length = set.getLength(); float fid = trackID; for (int i=0; i<length; i++) { if (ids[0][i] == fid) return i; } return -1; } public static Tuple makeDisturbance(String country, String state, int year, int number, String historical_name, double open_date, double close_date, int archive_mode, int realtime_mode, FieldImpl tracks) throws VisADException, RemoteException { return new Tuple(new DataImpl[] {new Text(ttCountry, country), new Text(ttState, state), new Real(rtYear, year), new Real(rtNumber, number), new Text(ttHistoricalName, historical_name), new Real(rtOpenDate, open_date), new Real(rtCloseDate, close_date), new Real(rtArchiveMode, archive_mode), new Real(rtRealtimeMode, realtime_mode), tracks}); } public static Tuple makeTrack(String track_type, String track_name, // jk Feb 2001 // int base_date_time, int create_date_time, String display_type, double base_date_time, double create_date_time, String display_type, FlatField locations) throws VisADException, RemoteException { //jk : allow for null sizes // if (sizes == null) sizes = TCData.makeMissingSizes(); // if (steerings == null) steerings = TCData.makeMissingSteerings(); // should also have same test for locations & intensities & steerings // + methods makeMissingLocations and makeMissingIntensities ? return new Tuple(new DataImpl[] {new Text(ttTrackType, track_type), new Text(ttTrackName, track_name), new Real(rtBaseDateTime, base_date_time), new Real(rtCreateDateTime, create_date_time), new Text(ttTrackStyle, display_type), locations}); } /** * jk: * create a flatfield of Disturbance (Tropical Cyclone) Sizes * with values set to "missing" * This allows for the case when the database has no entries yet, * but means we can still create some TCData * */ /* public static FlatField makeMissingSizes() throws VisADException, RemoteException { // // make a SIZE and store in the FlatField ffSizes // double[] daTimes = {Double.NaN}; int[] iaSizeIds = {-1}; float[] faGale_radii = {Float.NaN}; float[] faStorm_radii = {Float.NaN}; float[] faHurricane_radii = {Float.NaN}; float[] faRadii_of_maximum_winds = {Float.NaN}; int[] iaSizeStyles = {-1}; FlatField ffSizes = TCData.makeSizes( daTimes, iaSizeIds, faGale_radii, faStorm_radii, faHurricane_radii, faRadii_of_maximum_winds, iaSizeStyles); return ffSizes; } */ public static FlatField makeLocations(double[] times, float[] lats, float[] lons, float[] errors, int[] confidence, int[] location_styles, float[] wind_means, float[] wind_gusts, float[] central_pressures, int[] categories, int[] intensityStyle, float[] gale_radii, float[] storm_radii, float[] hurricane_radii, float[] radii_of_maximum_winds, int[] size_styles, float[] depth, float[] eyeDiameter, float[] pressureOfLastClosedIsobar, int[] structureStyle) throws VisADException, RemoteException { if (times == null || lats == null || lons == null || errors == null || confidence == null || location_styles == null || wind_means == null || wind_gusts == null || central_pressures == null || categories == null || intensityStyle == null || gale_radii == null || storm_radii == null || hurricane_radii == null || radii_of_maximum_winds == null || size_styles == null || depth == null || eyeDiameter == null || pressureOfLastClosedIsobar == null || structureStyle == null) { throw new VisADException("arguments may not be null"); } int length = times.length; if (lats.length != length || lons.length != length || errors.length != length || confidence.length != length || location_styles.length != length) { throw new VisADException("argument lengths must match"); } int[] permute = QuickSort.sort(times); Gridded1DDoubleSet set = new Gridded1DDoubleSet(rtTime, new double[][] {times}, length); FlatField field = new FlatField(locationFunction, set); float[] plats = new float[length]; float[] plons = new float[length]; float[] perrors = new float[length]; float[] pconfidence = new float[length]; float[] pLocation_styles = new float[length]; float[] pwind_means = new float[length]; float[] pwind_gusts = new float[length]; float[] pcentral_pressures = new float[length]; float[] pcategories = new float[length]; float[] pIntensityStyle = new float[length]; float[] pgale_radii = new float[length]; float[] pstorm_radii = new float[length]; float[] phurricane_radii = new float[length]; float[] pradii_of_maximum_winds = new float[length]; float[] psize_styles = new float[length]; float[] pdepth = new float[length]; float[] pEyeDiameter = new float[length]; float[] pPressureOfLastClosedIsobar = new float[length]; float[] pStructureStyle = new float[length]; for (int i=0; i<length; i++) { plats[i] = lats[permute[i]]; plons[i] = lons[permute[i]]; perrors[i] = errors[permute[i]]; pconfidence[i] = confidence[permute[i]]; pLocation_styles[i] = location_styles[permute[i]]; pwind_means[i] = wind_means[permute[i]]; pwind_gusts[i] = wind_gusts[permute[i]]; pcentral_pressures[i] = central_pressures[permute[i]]; pcategories[i] = categories[permute[i]]; pIntensityStyle[i] = intensityStyle[permute[i]]; pgale_radii[i] = gale_radii[permute[i]]; pstorm_radii[i] = storm_radii[permute[i]]; phurricane_radii[i] = hurricane_radii[permute[i]]; pradii_of_maximum_winds[i] = radii_of_maximum_winds[permute[i]]; psize_styles[i] = (size_styles[permute[i]] < 0) ? Float.NaN : size_styles[permute[i]]; pdepth[i] = depth[permute[i]]; pEyeDiameter[i] = eyeDiameter[permute[i]]; pPressureOfLastClosedIsobar[i] = pressureOfLastClosedIsobar[permute[i]]; pStructureStyle[i] = structureStyle[permute[i]]; } float[][] values = {plats, plons, perrors, pconfidence, pLocation_styles, pwind_means, pwind_gusts, pcentral_pressures, pcategories, pIntensityStyle, pgale_radii, pstorm_radii, phurricane_radii, pradii_of_maximum_winds, psize_styles, pdepth, pEyeDiameter, pPressureOfLastClosedIsobar, pStructureStyle }; field.setSamples(values, false); return field; } /** * create a bunch of "intensities" which are measurements of * the intensity of a Tropical Cyclone at particular times * * input: arrays of times, ids, wind_means... * output: a field of mathType intensityFunction, which is represented by: * (time -> intensityTuple) */ /* public static FlatField makeMissingSteerings() throws VisADException, RemoteException { double[] daTimes = {Double.NaN}; int[] iaSteeringIds = {-1}; float[] faSteering_directions = {Float.NaN}; int[] iaSteeringStyles = {-1}; FlatField ffSteerings = TCData.makeSteerings( daTimes, iaSteeringIds, faSteering_directions, iaSteeringStyles); return ffSteerings; } */ public static void main(String[] args) throws VisADException, RemoteException { MathType mtTC; TCData data = new TCData(); mtTC = data.getType(); System.out.println("MathType:\n" + mtTC); /* C:\jamesk\java\tc\visad\bom>java visad.bom.TCDataTest MathType: (DISTURBANCEID -> (COUNTRY(Text), STATE(Text), YEAR, NUM, HISTORICALNAME(Text), OPENDATE, CLOSEDATE, ARCHIVEMODE, REALTIMEMODE, (TRACKID -> (TRACKTYPE(Text), TRACKNAME(Text), BASEDATETIME, CREATEDATETIME, TRACKSTYLE(Text), (Time -> (Latitude, Longitude, ERROR, CONFIDENCE, LOCATIONSTYLE, WINDMEAN, WINDGUST, CENTRALPRESSURE, CATEGORY, INTENSITYSTYLE, GALERADIUS, STORMRADIUS, HURRICANERADIUS, RADIUSOFMAXIMUMWINDS, SIZESTYLE, DEPTH, EYEDIAMETER, PRESSUREOFLASTCLOSEDISOBAR, STRUCTURESTYLE)))))) was: doll% java visad.bom.TCData MathType: (DisturbanceID -> (Country(Text), State(Text), Year, Number, HistoricalName(Text), OpenDate, CloseDate, ArchiveMode, RealtimeMode, (TrackID -> (TrackType(Text), TrackName(Text), BaseDateTime, CreateDateTime, TrackStyle(Text), (Time -> (LocationID, Latitude, Longitude, Error, LocationStyle)), (Time -> (IntensityID, WindMean, WindGust, CentralPressure, Category)), (Time -> (SizeID, GaleRadius, StormRadius, HurricaneRadius, RadiusOfMaximumWinds, SizeStyle)), (Time -> (SteeringID, SteeringDirection, SteeringStyle)))))) */ } }