001/*
002 * Copyright (c) 2004-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.ecoinformatics.seek.gis.java_gis;
031
032import java.io.File;
033import java.util.Hashtable;
034
035import ptolemy.actor.lib.SequenceActor;
036import ptolemy.actor.lib.Transformer;
037import ptolemy.data.BooleanToken;
038import ptolemy.data.DoubleToken;
039import ptolemy.data.IntToken;
040import ptolemy.data.StringToken;
041import ptolemy.data.expr.FileParameter;
042import ptolemy.data.expr.Parameter;
043import ptolemy.data.expr.StringParameter;
044import ptolemy.data.type.BaseType;
045import ptolemy.kernel.CompositeEntity;
046import ptolemy.kernel.Port;
047import ptolemy.kernel.util.IllegalActionException;
048import ptolemy.kernel.util.InternalErrorException;
049import ptolemy.kernel.util.NameDuplicationException;
050
051/**
052 * <p>
053 * This actor converts an ascii raster grid file into another ascii grid file
054 * with different extent and cell spacing A ASC grid file is read as input. (The
055 * file name(s) are connected to the input port.)<br/>
056 * The xllcorner, yllcorner, cellsize, numrows and numcols of the desired grid
057 * are also input and a new ASC file is created. Algorithms are disk based
058 * meaning that very large rasters can be handled.
059 * </p>
060 * 
061 * <p>
062 * The input is a multiport so multiple input file names can be attached to that
063 * port. Multiple tokens are output in a sequence if multiple input filenames
064 * are attached. Token consumption and production rates are automatically
065 * calculated
066 * </p>
067 * 
068 * <p>
069 * A useExistingFile boolean parameter has been added. When true, the actor
070 * checks to see if the output file already exists. If it does, it is just sent
071 * to the output port without repeating the calculation.
072 * </p>
073 */
074public class GridRescaler extends Transformer implements SequenceActor {
075
076        /**
077         * The x-value of the lower left corner of the output grid Usually this is a
078         * longitude. This is input as a string and converted to a double.
079         */
080        public Parameter xllcorner;
081
082        /**
083         * The y-value of the lower left corner of the output grid Usually this is a
084         * latitude. This is input as a string and converted to a double.
085         */
086        public Parameter yllcorner;
087
088        /**
089         * The cell size of the output grid. The grid is assumed square so that x
090         * and y grid sizes are equal and converted to a double..
091         */
092        public Parameter cellsize;
093
094        /**
095         * The number of rows (cells in the y-direction) in the output grid. This
096         * determines the extent of y-values in the grid when combined with the cell
097         * size This is input as a string and converted to a integer.
098         */
099        public Parameter numrows;
100
101        /**
102         * The number of columns (cells in the x-direction) in the output grid. This
103         * determines the extent of x-values in the grid when combined with the cell
104         * size This is input as a string and converted to a integer.
105         */
106        public Parameter numcols;
107
108        /**
109         * This is the algoritm to be used in calculating cell values in the output
110         * grid from the values in the input grid Currently there are two choices:
111         * 'Nearest Neighbor' or 'Inverse Distance Weighted'
112         */
113        public StringParameter algorithm;
114
115        /**
116         * This is the name to be given to the output file. If left empty, the input
117         * file name plus a suffix (".out"+i) will be used for output file names
118         * Note that the input port is a multiport so multiple input can be
119         * converted in a single firing. If this parameter is a directory name,
120         * output file(s) will be placed in that directory
121         */
122        public FileParameter outputFilename;
123
124        /**
125         * Boolean setting to determine whether or not to use currently existing
126         * output file, if it exists
127         */
128        public Parameter useExistingFile;
129
130        /**
131         * Boolean setting to determine whether or not to use disk for storing grid
132         * data rather than putting all data in RAM arrays
133         */
134        public Parameter useDisk;
135
136        private Parameter output_tokenProductionRate;
137        private Parameter input_tokenConsumptionRate;
138        private Grid inputGrid;
139        private Grid newg;
140
141        private boolean finished;
142        private String prevAscFilename = "";
143        private String prevOutFilename = "";
144        private String cachedLine = "";
145        private Hashtable header = null;
146
147        private int algorithmToUse = _NEAREST_NEIGHBOR;
148        private static final int _NEAREST_NEIGHBOR = 0;
149        private static final int _INVERSE_DISTANCE = 1;
150
151        /**
152         * constructor
153         * 
154         *@param container
155         *            The container.
156         *@param name
157         *            The name of this actor.
158         *@exception IllegalActionException
159         *                If the actor cannot be contained by the proposed
160         *                container.
161         *@exception NameDuplicationException
162         *                If the container already has an actor with this name.
163         */
164        public GridRescaler(CompositeEntity container, String name)
165                        throws NameDuplicationException, IllegalActionException {
166                super(container, name);
167
168                xllcorner = new Parameter(this, "xllcorner");
169                yllcorner = new Parameter(this, "yllcorner");
170                cellsize = new Parameter(this, "cellsize");
171                numrows = new Parameter(this, "numrows");
172                numcols = new Parameter(this, "numcols");
173
174                algorithm = new StringParameter(this, "algorithm");
175                algorithm.setExpression("Nearest Neighbor");
176                algorithm.addChoice("Nearest Neighbor");
177                algorithm.addChoice("Inverse Distance");
178
179                input.setMultiport(true);
180                output_tokenProductionRate = new Parameter(output,
181                                "tokenProductionRate");
182                output_tokenProductionRate.setExpression("0");
183                outputFilename = new FileParameter(this, "outputFileName");
184
185                useExistingFile = new Parameter(this, "use Existing File");
186                useExistingFile.setTypeEquals(BaseType.BOOLEAN);
187                useExistingFile.setToken(BooleanToken.FALSE);
188
189                useDisk = new Parameter(this, "use disk storage (for large grids)");
190                useDisk.setTypeEquals(BaseType.BOOLEAN);
191                useDisk.setToken(BooleanToken.TRUE);
192
193        }
194
195        /**
196         * Resets the output token production rate based on width of input port
197         */
198        public void connectionsChanged(Port port) {
199                super.connectionsChanged(port);
200                if (port == input) {
201                        try {
202                                output_tokenProductionRate.setToken(new IntToken(input
203                                                .getWidth()));
204                                // NOTE: schedule is invalidated automatically already
205                                // by the changed connections.
206                        } catch (IllegalActionException ex) {
207                                throw new InternalErrorException(this, ex,
208                                                "Failed to set the token production rate of the "
209                                                                + "output port");
210                        }
211                }
212        }
213
214        /**
215         * Creates rescaled ascii grid for each input grid using the input
216         * parameters Uses the 'Grid' class that is disk-based, thus allowing very
217         * large grids.
218         * 
219         *@exception IllegalActionException
220         *                If there is no director.
221         */
222        public void fire() throws IllegalActionException {
223                boolean calculateFlag = true;
224                super.fire();
225                try {
226                        String ascfilename = null;
227                        String ascOutfilename = null;
228                        String ascfileshortname = null;
229                        String temp = "";
230                        int width = input.getWidth();
231
232                        boolean useExistingFileValue = ((BooleanToken) useExistingFile
233                                        .getToken()).booleanValue();
234                        boolean useDiskValue = ((BooleanToken) useDisk.getToken())
235                                        .booleanValue();
236
237                        for (int iii = 0; iii < width; iii++) {
238                                ascfilename = ((StringToken) input.get(iii)).stringValue();
239                                System.out.println("ascfilename: " + ascfilename);
240                                if (ascfilename.indexOf("/") > -1) {
241                                        ascfileshortname = ascfilename.substring(ascfilename
242                                                        .lastIndexOf("/") + 1, ascfilename.length());
243                                } else if (ascfilename.indexOf("\\") > -1) {
244                                        ascfileshortname = ascfilename.substring(ascfilename
245                                                        .lastIndexOf("\\") + 1, ascfilename.length());
246                                } else {
247                                        ascfileshortname = ascfilename;
248                                }
249                                System.out.println("ascfileshortname: " + ascfileshortname);
250                                temp = outputFilename.stringValue();
251                                if (temp.trim().length() == 0) {
252                                        temp = ascfilename;
253                                        int dotloc = temp.lastIndexOf(".");
254                                        temp = temp.substring(0, dotloc);
255                                        temp = temp + ".out" + iii;
256                                        outputFilename.setExpression(temp);
257                                        ascOutfilename = outputFilename.asFile().getPath();
258                                } else { // check to see if the output file is a dir
259                                        File of = outputFilename.asFile();
260                                        if (of.isDirectory()) {
261                                                temp = ascfileshortname;
262                                                int dotloc = temp.lastIndexOf(".");
263                                                temp = temp.substring(0, dotloc);
264                                                temp = temp + ".out" + iii;
265                                                ascOutfilename = of.getPath() + "/" + temp;
266                                        } else {
267                                                ascOutfilename = outputFilename.asFile().getPath();
268                                        }
269                                }
270                                if (useExistingFileValue) {
271                                        // check to see if output file
272                                        File of1 = outputFilename.asFile();
273                                        if (of1.exists()) {
274                                                if (of1.isFile()) {
275                                                        calculateFlag = false;
276                                                }
277                                        }
278                                }
279
280                                System.out.println("ascOutfilename: " + ascOutfilename);
281
282                                File file = new File(ascfilename);
283
284                                if (file.exists()) {
285                                        if (calculateFlag) {
286                                                inputGrid = new Grid(file, !useDiskValue); // a 'false'
287                                                                                                                                        // !useDiskValue
288                                                                                                                                        // forces
289                                                                                                                                        // the use
290                                                                                                                                        // of disk
291                                                                                                                                        // rather
292                                                                                                                                        // than RAM
293                                                System.out.println("nrows: " + inputGrid.nrows);
294                                                System.out.println("ncols: " + inputGrid.ncols);
295                                                System.out.println("delx: " + inputGrid.delx);
296                                                System.out.println("dely: " + inputGrid.dely);
297                                                //
298                                                int nrows;
299                                                try {
300                                                        nrows = ((IntToken) numrows.getToken()).intValue();
301                                                } catch (Exception w) {
302                                                        nrows = 50;
303                                                }
304
305                                                int ncols;
306                                                try {
307                                                        ncols = ((IntToken) numcols.getToken()).intValue();
308                                                } catch (Exception w) {
309                                                        ncols = 50;
310                                                }
311
312                                                double xmin;
313                                                try {
314                                                        xmin = ((DoubleToken) xllcorner.getToken())
315                                                                        .doubleValue();
316                                                } catch (Exception w) {
317                                                        xmin = 0.0;
318                                                }
319
320                                                double ymin;
321                                                try {
322                                                        ymin = ((DoubleToken) yllcorner.getToken())
323                                                                        .doubleValue();
324                                                } catch (Exception w) {
325                                                        ymin = 0.0;
326                                                }
327
328                                                double cs;
329                                                try {
330                                                        cs = ((DoubleToken) cellsize.getToken())
331                                                                        .doubleValue();
332                                                } catch (Exception w) {
333                                                        cs = 1.0;
334                                                }
335                                                temp = algorithm.stringValue();
336                                                if (temp.equals("Inverse Distance")) {
337                                                        algorithmToUse = _INVERSE_DISTANCE;
338                                                } else {
339                                                        algorithmToUse = _NEAREST_NEIGHBOR;
340                                                }
341                                                newg = inputGrid.rescale(nrows, ncols, cs, cs, xmin,
342                                                                ymin, algorithmToUse);
343                                                newg.createAsc(ascOutfilename);
344                                                System.out.println("ready to send: " + ascOutfilename);
345
346                                        }
347                                        output.broadcast(new StringToken(ascOutfilename));
348                                } else {
349                                        throw new IllegalActionException("Input file "
350                                                        + ascfilename + " does not exist.");
351                                }
352                        }
353                } catch (Exception eee) {
354                        throw new IllegalActionException("Problem Reading File");
355                }
356        }
357
358        /**
359         * Post fire the actor. Return false to indicate that the process has
360         * finished. If it returns true, the process will continue indefinitely.
361         * 
362         *       */
363        public boolean postfire() throws IllegalActionException {
364                if (inputGrid != null) {
365                        inputGrid.delete();
366                        newg.delete();
367                }
368                return super.postfire();
369        }
370
371        /**
372         * Pre fire the actor. Calls the super class's prefire in case something is
373         * set there.
374         * 
375         *       *@exception IllegalActionException
376         */
377        public boolean prefire() throws IllegalActionException {
378                return super.prefire();
379        }
380
381}