001/* 002 * Copyright (c) 2003-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.Vector; 034 035import ptolemy.actor.TypedAtomicActor; 036import ptolemy.actor.TypedIOPort; 037import ptolemy.data.ArrayToken; 038import ptolemy.data.StringToken; 039import ptolemy.data.type.ArrayType; 040import ptolemy.data.type.BaseType; 041import ptolemy.kernel.CompositeEntity; 042import ptolemy.kernel.util.IllegalActionException; 043import ptolemy.kernel.util.NameDuplicationException; 044import util.PersistentVector; 045 046/** 047 * <b>Name:</b> AddGrids.java<br/> 048 * <b>Purpose:</b> The purpose of this actor is to 'merge' multiple ASC grids. 049 * This differs from MergeGrid in that more than 2 grids can be merged. 050 * <p> 051 * Extent and cell size will match that of the first grid. The primary purpose 052 * is to combine stochastic grids to give a spatial distribution where more 053 * probable cells have larger values. Thus, cell values are added for all pixels 054 * in the input grid file list. 055 * </p> 056 * 057 * @author : Dan Higgins NCEAS UC Santa Barbara 058 * 059 */ 060 061public class AddGrids extends TypedAtomicActor { 062 int mergeOp = 1; // ADD 063 // input ports 064 /** 065 * A string array of filenames of grid files to be added 066 */ 067 public TypedIOPort gridFilenameArrayPort = new TypedIOPort(this, 068 "gridFilenameArrayPort", true, false); 069 070 /** 071 * The name to be given to the resulting output file 072 */ 073 public TypedIOPort mergedGridFileName = new TypedIOPort(this, 074 "mergedGridFileName", true, false); 075 076 /** 077 * The file name of the resulting grid (acts as a trigger when addition is 078 * complete) 079 */ 080 public TypedIOPort mergedGridFileResult = new TypedIOPort(this, 081 "mergedGridFileResult", false, true); 082 083 private Grid grid1; 084 private Grid grid2; 085 private Grid mergedGrid; 086 087 private static final int NEAREST_NEIGHBOR = 0; 088 private static final int INVERSE_DISTANCE = 1; 089 090 private Vector gridsVector; 091 092 public AddGrids(CompositeEntity container, String name) 093 throws NameDuplicationException, IllegalActionException { 094 super(container, name); 095 096 gridFilenameArrayPort.setTypeEquals(new ArrayType(BaseType.STRING)); 097 mergedGridFileName.setTypeEquals(BaseType.STRING); 098 mergedGridFileResult.setTypeEquals(BaseType.STRING); 099 100 gridsVector = new Vector(); 101 } 102 103 /** 104 * 105 */ 106 public void initialize() throws IllegalActionException { 107 108 } 109 110 /** 111 * 112 */ 113 public boolean prefire() throws IllegalActionException { 114 return super.prefire(); 115 } 116 117 /** 118 * 119 */ 120 public void fire() throws IllegalActionException { 121 super.fire(); 122 123 gridsVector = new Vector(); 124 if (gridFilenameArrayPort.getWidth() > 0) { 125 ArrayToken token = (ArrayToken) gridFilenameArrayPort.get(0); 126 // now iterate over all the filenames in the array 127 for (int i = 0; i < token.length(); i++) { 128 StringToken s_token = (StringToken) token.getElement(i); 129 String ascfilename = s_token.stringValue(); 130 gridsVector.addElement(ascfilename); 131 } 132 } 133 System.out.println("Array size: " + gridsVector.size()); 134 135 // assume at least 2 grids in the Vector 136 File grid1File = new File((String) gridsVector.elementAt(0)); 137 File grid2File = new File((String) gridsVector.elementAt(1)); 138 grid1 = new Grid(grid1File); 139 grid2 = new Grid(grid2File); 140 141 double minx = grid1.xllcorner; 142 double miny = grid1.yllcorner; 143 double maxx = grid1.xllcorner + grid1.ncols * grid1.delx; 144 double maxy = grid1.yllcorner + grid1.nrows * grid1.dely; 145 double new_cs = grid1.delx; // remember, delx and dely are equal! 146 int new_ncols = (int) ((maxx - minx) / new_cs); 147 int new_nrows = (int) ((maxy - miny) / new_cs); 148 149 mergedGrid = new Grid(new_ncols, new_nrows, new_cs, new_cs, minx, miny); 150 // new merged grid has now been created but no storage or values alloted 151 merge(NEAREST_NEIGHBOR, mergeOp); 152 // we have now added the first two grids 153 grid1.delete(); // get rid of unneeded data 154 grid2.delete(); 155 for (int k = 2; k < gridsVector.size(); k++) { 156 grid1 = mergedGrid; 157 mergedGrid = new Grid(new_ncols, new_nrows, new_cs, new_cs, minx, 158 miny); 159 grid2File = new File((String) gridsVector.elementAt(k)); 160 grid2 = new Grid(grid2File); 161 merge(NEAREST_NEIGHBOR, mergeOp); 162 grid1.delete(); // get rid of unneeded data 163 grid2.delete(); 164 } 165 166 StringToken outputFileToken = (StringToken) mergedGridFileName.get(0); 167 String outFileStr = outputFileToken.stringValue(); 168 mergedGrid.createAsc(outFileStr); 169 mergedGridFileResult.broadcast(new StringToken(outFileStr)); 170 } 171 172 /** 173 * Post fire the actor. Return false to indicate that the process has 174 * finished. If it returns true, the process will continue indefinitely. 175 * 176 * */ 177 public boolean postfire() throws IllegalActionException { 178 grid1.delete(); // remove potentially large data storage associated with 179 // grid1 180 grid2.delete(); // remove potentially large data storage associated with 181 // grid2 182 mergedGrid.delete(); // remove potentially large data storage associated 183 // with mergedGrid 184 return super.postfire(); 185 } 186 187 private void merge(int scalingAlgorithm, int mergeOperation) { 188 int nr = mergedGrid.nrows; 189 int nc = mergedGrid.ncols; 190 double ymin = mergedGrid.yllcorner; 191 double xmin = mergedGrid.xllcorner; 192 double dx = mergedGrid.delx; 193 double dy = mergedGrid.dely; 194 if (mergedGrid.inMemFlag && (mergedGrid.dataArray != null)) { 195 double[][] newDataArray = new double[nc][nr]; 196 mergedGrid.dataArray = newDataArray; 197 for (int j = 0; j < nr; j++) { 198 double yloc = ymin + nr * dy - j * dy; 199 for (int i = 0; i < nc; i++) { 200 double xloc = xmin + i * dx; 201 double val1 = grid1.interpValue(xloc, yloc, 202 scalingAlgorithm); 203 double val2 = grid2.interpValue(xloc, yloc, 204 scalingAlgorithm); 205 double val = getMergedValue(val1, val2, mergeOperation); 206 newDataArray[i][j] = val; 207 } 208 } 209 } else { // using PersistentVector for data storage 210 mergedGrid.pv = new PersistentVector(); 211 mergedGrid.pv.setFirstRow(6); 212 mergedGrid.pv.setFieldDelimiter("#x20"); 213 String[] rowvals = new String[nc]; 214 for (int j = 0; j < nr; j++) { 215 double yloc = ymin + nr * dy - j * dy; 216 for (int i = 0; i < nc; i++) { 217 double xloc = xmin + i * dx; 218 double val1 = grid1.interpValue(xloc, yloc, 219 scalingAlgorithm); 220 double val2 = grid2.interpValue(xloc, yloc, 221 scalingAlgorithm); 222 double val = getMergedValue(val1, val2, mergeOperation); 223 224 String valStr; 225 if (val > 1.0E100) { 226 valStr = Grid.NODATA_value_String; 227 } else { 228 valStr = (new Double(val)).toString(); 229 } 230 231 rowvals[i] = valStr; 232 } 233 mergedGrid.pv.addElement(rowvals); 234 rowvals = new String[nc]; // needed to make sure new object 235 // added to pv 236 } 237 } 238 } 239 240 private double getMergedValue(double val1, double val2, int mergeOperation) { 241 242 // if either grid point is a missing value, return a missing value 243 if ((val1 > 1.0e100) || (val2 > 1.0e100)) { 244 return 1.0e101; 245 } else { 246 return (val1 + val2); 247 } 248 } 249}