/** * Global Sensor Networks (GSN) Source Code * Copyright (c) 2006-2016, Ecole Polytechnique Federale de Lausanne (EPFL) * * This file is part of GSN. * * GSN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GSN 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GSN. If not, see <http://www.gnu.org/licenses/>. * * File: src/ch/epfl/gsn/vsensor/GridModelVS.java * * @author Julien Eberle * */ package ch.epfl.gsn.vsensor; import org.slf4j.LoggerFactory; import ch.epfl.gsn.Mappings; import ch.epfl.gsn.VirtualSensor; import ch.epfl.gsn.VirtualSensorInitializationFailedException; import ch.epfl.gsn.beans.DataField; import ch.epfl.gsn.beans.StreamElement; import ch.epfl.gsn.utils.models.AbstractModel; import ch.epfl.gsn.vsensor.AbstractVirtualSensor; import ch.epfl.gsn.vsensor.GridModelVS; import ch.epfl.gsn.vsensor.ModellingVirtualSensor; import org.slf4j.Logger; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.TreeMap; public class GridModelVS extends AbstractVirtualSensor { private static final transient Logger logger = LoggerFactory.getLogger(GridModelVS.class); private static final String PARAM_MODEL_VS = "model_VS"; private static final String PARAM_MODEL = "model_index"; private static final String PARAM_FIELD = "field"; private static final String PARAM_GRID_SIZE = "grid_size"; private static final String PARAM_CELL_SIZE = "cell_size"; private static final String PARAM_X = "x_bottomLeft"; private static final String PARAM_Y = "y_bottomLeft"; private AbstractModel modelVS = null; private String field = ""; private double x_BL = 0; private double y_BL = 0; private int gridSize = 0; private double cellSize = 0; private double XCellSize = 0; private double YCellSize = 0; public boolean initialize() { TreeMap<String, String> params = getVirtualSensorConfiguration().getMainClassInitialParams(); //get the model from the modelling virtual sensor String model_str = params.get(PARAM_MODEL_VS); String model_i_str = params.get(PARAM_MODEL); if (model_str == null) { logger.warn("Parameter \"" + PARAM_MODEL_VS + "\" not provided in Virtual Sensor file"); return false; } if (model_i_str == null) { model_i_str = "0"; } try { VirtualSensor vs = Mappings.getVSensorInstanceByVSName(model_str); if (vs == null){ logger.error("can't find VS: "+ model_str); return false; } AbstractVirtualSensor avs = vs.borrowVS(); if (avs instanceof ModellingVirtualSensor){ int modelIndex = Integer.parseInt(model_i_str.trim()); modelVS = ((ModellingVirtualSensor)avs).getModel(modelIndex); if (modelVS==null){ logger.error("Virtual Sensor " + model_str + " returned no model["+modelIndex+"]."); } }else{ logger.error("Virtual Sensor " + model_str + " is not a modelling Virtual Sensor."); return false; } vs.returnVS(avs); } catch (VirtualSensorInitializationFailedException e) { logger.error("Error loading the model["+model_i_str+"] from " + model_str); return false; } //get the field to query to build the grid (fields are converted to double) field = params.get(PARAM_FIELD); if (field == null) { logger.warn("Parameter \"" + PARAM_FIELD + "\" not provided in Virtual Sensor file"); return false; } //get the bottom-left corner longitude coordinate in degree String cx_str = params.get(PARAM_X); if (cx_str == null) { logger.warn("Parameter \"" + PARAM_X + "\" not provided in Virtual Sensor file"); return false; } else try { x_BL = Double.parseDouble(cx_str.trim()); } catch (NumberFormatException e) { logger.warn("Parameter \"" + PARAM_X + "\" incorrect in Virtual Sensor file"); return false; } //get the bottom-left corner latitude coordinate in degree String cy_str = params.get(PARAM_Y); if (cy_str == null) { logger.warn("Parameter \"" + PARAM_Y + "\" not provided in Virtual Sensor file"); return false; } else try { y_BL = Double.parseDouble(cy_str.trim()); } catch (NumberFormatException e) { logger.warn("Parameter \"" + PARAM_Y + "\" incorrect in Virtual Sensor file"); return false; } //get the number of cells of a side of the square grid String gridSize_str = params.get(PARAM_GRID_SIZE); if (gridSize_str == null) { logger.warn("Parameter \"" + PARAM_GRID_SIZE + "\" not provided in Virtual Sensor file"); return false; } else try { gridSize = Integer.parseInt(gridSize_str.trim()); } catch (NumberFormatException e) { logger.warn("Parameter \"" + PARAM_GRID_SIZE + "\" incorrect in Virtual Sensor file"); return false; } if (gridSize < 0) { logger.warn("Grid size should always be positive."); return false; } // get the size of a square cell in meter String cellSize_str = params.get(PARAM_CELL_SIZE); if (cellSize_str == null) { logger.warn("Parameter \"" + PARAM_CELL_SIZE + "\" not provided in Virtual Sensor file"); return false; } else try { cellSize = Double.parseDouble(cellSize_str.trim()); } catch (NumberFormatException e) { logger.warn("Parameter \"" + PARAM_CELL_SIZE + "\" incorrect in Virtual Sensor file"); return false; } if (cellSize < 0) { logger.warn("Cell size should always be positive."); return false; } //compute the width and height of a cell in degree (if the grid is too big, their maybe some deformation) YCellSize = cellSize *360.0 / (6356753*2*Math.PI); XCellSize = cellSize *360.0 / (6378137*Math.cos(Math.toRadians(y_BL))*2*Math.PI); return true; } public DataField[] getOutputFormat() { return new DataField[]{ new DataField("ncols", "int", "number of columns"), new DataField("nrows", "int", "number of rows"), new DataField("xllcorner", "double", "xll corner"), new DataField("yllcorner", "double", "yll corner"), new DataField("cellsize", "double", "cell size"), new DataField("nodata_value", "double", "no data value"), new DataField("grid", "binary", "raw data")}; } public void dataAvailable(String inputStreamName, StreamElement data) { DataField []fields = new DataField[]{new DataField("latitude","double"),new DataField("longitude","double")}; //filling the grid with predictions/extrapolations //if the model is slow to query this loop may take some time Double[][] rawData = new Double[gridSize][gridSize]; for (int j=0;j<gridSize;j++){ for(int k=0;k<gridSize;k++){ double[] pos = new double[]{y_BL+YCellSize * j, x_BL+XCellSize * k}; StreamElement se = new StreamElement(fields, new Serializable[]{pos[0],pos[1]}); StreamElement r = modelVS.query(se)[0]; Serializable s = r.getData(field); if (s instanceof Double){ rawData[gridSize-j-1][k] = (Double) r.getData(field); }else if(s instanceof Integer){ rawData[gridSize-j-1][k] = ((Integer) r.getData(field)).doubleValue(); }else if(s instanceof Boolean){ rawData[gridSize-j-1][k] = ((Boolean) r.getData(field)) ? 1.0 : 0.0; }else { rawData[gridSize-j-1][k] = 0.0; } } } //preparing the output Serializable[] stream = new Serializable[7]; try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(rawData); oos.flush(); oos.close(); bos.close(); stream[0] = new Integer(gridSize); stream[1] = new Integer(gridSize); stream[2] = new Double(x_BL); stream[3] = new Double(y_BL); stream[4] = new Double(cellSize); stream[5] = new Double(0); stream[6] = bos.toByteArray(); StreamElement se = new StreamElement(getOutputFormat(), stream, data.getTimeStamp()); dataProduced(se); } catch (IOException e) { logger.warn(e.getMessage(), e); } } public void dispose() { } }