/** * 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/GridModelDataPredictVS.java * * @author Sofiane Sarni * @author Julien Eberle * */ package ch.epfl.gsn.vsensor; import org.slf4j.LoggerFactory; import ch.epfl.gsn.beans.DataField; import ch.epfl.gsn.beans.StreamElement; import ch.epfl.gsn.utils.models.ModelLoader; import ch.epfl.gsn.vsensor.AbstractVirtualSensor; import ch.epfl.gsn.vsensor.BridgeVirtualSensor; import org.slf4j.Logger; import weka.core.Attribute; import weka.core.FastVector; import weka.core.Instance; import weka.core.Instances; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.TreeMap; public class GridModelDataPredictVS extends AbstractVirtualSensor { private static final transient Logger logger = LoggerFactory.getLogger(BridgeVirtualSensor.class); private static final String PARAM_MODEL = "model"; private static final String PARAM_CLASS_INDEX = "class_index"; private static final String PARAM_GRID_SIZE = "grid_size"; private static final String PARAM_CELL_SIZE = "cell_size"; private String model = ""; private Instances dataset; private int classIndex = 0; private ModelLoader ms; private int gridSize = 0; private double cellSize = 0; private FastVector att = new FastVector(); public boolean initialize() { TreeMap<String, String> params = getVirtualSensorConfiguration().getMainClassInitialParams(); String model_str = params.get(PARAM_MODEL); if (model_str == null) { logger.warn("Parameter \"" + PARAM_MODEL + "\" not provided in Virtual Sensor file"); return false; } else { model = model_str.trim(); } String classIndex_str = params.get(PARAM_CLASS_INDEX); if (classIndex_str == null) { logger.warn("Parameter \"" + PARAM_CLASS_INDEX + "\" not provided in Virtual Sensor file"); return false; } else try { classIndex = Integer.parseInt(classIndex_str.trim()); } catch (NumberFormatException e) { logger.warn("Parameter \"" + PARAM_CLASS_INDEX + "\" incorrect in Virtual Sensor file"); return false; } if (classIndex < 0) { logger.warn("Class index should always be positive."); return false; } 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; } 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; } ms = new ModelLoader(model); 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) { //mapping the input stream to an instance and setting its dataset String[] dfn = data.getFieldNames().clone(); Byte[] dft = data.getFieldTypes().clone(); Serializable[] da = data.getData().clone(); data = new StreamElement(dfn, dft, da, data.getTimeStamp()); Instance i = instanceFromStream(data); if (att.size() == 0){ att = attFromStream(data); } dataset = new Instances("input",att,0); dataset.setClassIndex(classIndex); if(i != null){ dataset.add(i); i = dataset.firstInstance(); boolean success = true; //extracting latitude/longitude Double center_lat = i.value(1); Double center_long = i.value(2); //filling the grid with predictions/extrapolations Double[][] rawData = new Double[gridSize][gridSize]; for (int j=0;j<gridSize;j++){ for(int k=0;k<gridSize;k++){ i.setValue(1, center_lat - (cellSize*gridSize/2) + cellSize * j); i.setValue(2, center_long - (cellSize*gridSize/2) + cellSize * k); rawData[j][k] = ms.predict(i); success = success && (rawData[j][k] != null); } } //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(center_lat - (cellSize*gridSize/2)); stream[3] = new Double(center_long - (cellSize*gridSize/2)); stream[4] = new Double(cellSize); stream[5] = new Double(0); stream[6] = bos.toByteArray(); } catch (IOException e) { logger.warn(e.getMessage(), e); success = false; } if(success){ StreamElement se = new StreamElement(getOutputFormat(), stream, data.getTimeStamp()); dataProduced(se); }else{ logger.warn("Prediction error. Something get wrong with the prediction."); } }else{ logger.warn("Predicting instance has wrong attibutes, please check the model and the inputs."); } } /*public boolean dataFromWeb ( String command, String[] paramNames, Serializable[] paramValues ) { try{ if(command.equalsIgnoreCase("model")){ for (int j=0;j<paramNames.length;j++){ if(paramNames[j].equalsIgnoreCase("model")){ ms = new ModelLoader(paramValues[j].toString()); } } } return true; }catch(Exception e){ return false; } }*/ private FastVector attFromStream(StreamElement data) { FastVector fv = new FastVector(); for (int i=0;i<data.getFieldNames().length;i++){ Attribute a = new Attribute(data.getFieldNames()[i]); fv.addElement(a); } return fv; } private Instance instanceFromStream(StreamElement data) { try{ Instance i = new Instance(data.getFieldNames().length); for(int j=0;j<data.getFieldNames().length;j++){ i.setValue(j, ((Double)data.getData()[j])); } //scaling specific to opensense data!! should be put in the parameters? i.setValue(0, i.value(0)/1400.0); i.setValue(2, i.value(2)/50); i.setValue(3, i.value(3)/100.0); i.setValue(4, i.value(4)/100.0 - 4); return i; }catch(Exception e){ return null; } } public void dispose() { } }