ecological-engine-geospatia.../src/main/java/org/gcube/dataanalysis/geo/vti/EstimateFishingActivity.java

240 lines
13 KiB
Java

package org.gcube.dataanalysis.geo.vti;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.gcube.contentmanagement.graphtools.utils.DateGuesser;
import org.gcube.contentmanagement.lexicalmatcher.utils.AnalysisLogger;
import org.gcube.dataanalysis.ecoengine.configuration.AlgorithmConfiguration;
import org.gcube.dataanalysis.ecoengine.datatypes.ColumnType;
import org.gcube.dataanalysis.ecoengine.datatypes.DatabaseType;
import org.gcube.dataanalysis.ecoengine.datatypes.InputTable;
import org.gcube.dataanalysis.ecoengine.datatypes.enumtypes.TableTemplates;
import org.gcube.dataanalysis.ecoengine.utils.DatabaseFactory;
import org.gcube.dataanalysis.ecoengine.utils.DatabaseUtils;
import org.gcube.dataanalysis.ecoengine.utils.IOHelper;
import org.gcube.dataanalysis.ecoengine.utils.Tuple;
import org.gcube.dataanalysis.geo.vti.vesselsprocessing.Bathymetry;
import org.gcube.dataanalysis.geo.vti.vesselsprocessing.FishingHoursCalculator;
import org.gcube.dataanalysis.geo.vti.vesselsprocessing.VTIClassificator;
public class EstimateFishingActivity extends GridCWP2Coordinates{
static String VesselsIDColumn = "VesselsIDColumn";
static String VesselsSpeedsColumn = "VesselsSpeedsColumn";
static String VesselsTimestampsColumn = "VesselsTimestampsColumn";
static String VesselsLatitudesColumn = "VesselsLatitudesColumn";
static String VesselsLongitudesColumn = "VesselsLongitudesColumn";
@Override
protected void setInputParameters() {
List<TableTemplates> templates = new ArrayList<TableTemplates>();
templates.add(TableTemplates.GENERIC);
InputTable tinput = new InputTable(templates, inputTableParameter, "The table to which the algorithm will add information");
inputs.add(tinput);
ColumnType Dimension1 = new ColumnType(inputTableParameter, VesselsIDColumn, "A column containing (anonymised) unique vessels identifiers", "vessel_id", false);
ColumnType Dimension2 = new ColumnType(inputTableParameter, VesselsSpeedsColumn, "The column containing vessels speeds", "speed", false);
ColumnType Dimension3 = new ColumnType(inputTableParameter, VesselsTimestampsColumn, "The column containing the time stamp of the vessels transmitted information (preferred in the following format: MM/dd/yyyy HH:mm:ss a)", "datetime", false);
ColumnType Dimension4 = new ColumnType(inputTableParameter, VesselsLatitudesColumn, "The column containing vessels latitudes", "y", false);
ColumnType Dimension5 = new ColumnType(inputTableParameter, VesselsLongitudesColumn, "The column containing vessels longitudes", "x", false);
inputs.add(Dimension1);
inputs.add(Dimension2);
inputs.add(Dimension3);
inputs.add(Dimension4);
inputs.add(Dimension5);
IOHelper.addStringInput(inputs, outputTableParameter, "The name of the output table", "fish_");
DatabaseType.addDefaultDBPars(inputs);
}
@Override
public String getDescription() {
return "An algorithm that estimates activity hours (fishing or other) from vessels trajectories, " +
"adds bathymetry information to the table and classifies (point-by-point) fishing activity of the involved vessels according to two algorithms: " +
"one based on speed (activity_class_speed output column) and the other based on speed and bathymetry (activity_class_speed_bath output column). " +
"The algorithm produces new columns containing this information. " +
"This algorithm is based on the paper 'Deriving Fishing Monthly Effort and Caught Species' (Coro et al. 2013, in proc. of OCEANS - Bergen, 2013 MTS/IEEE). ";
}
@Override
protected void process() throws Exception {
status = 0;
AnalysisLogger.setLogger(config.getConfigPath() + AlgorithmConfiguration.defaultLoggerFile);
long t0 = System.currentTimeMillis();
String table = IOHelper.getInputParameter(config, inputTableParameter);
outTable = ("fish_" + UUID.randomUUID()).replace("-", "");
outTableLabel = IOHelper.getInputParameter(config, outputTableParameter);
AnalysisLogger.getLogger().debug("EstimateFishingActivity: received parameters: " + config.getGeneralProperties());
AnalysisLogger.getLogger().debug("EstimateFishingActivity: input table: "+ table +" outputTable: " + outTable + " outLabel: " + outTableLabel);
status = 10;
try{
addInformationColumsToTable(table);
AnalysisLogger.getLogger().debug("EstimateFishingActivity: finished in "+(System.currentTimeMillis()-t0)+" ms");
} catch (Throwable e) {
throw new Exception(e.getMessage());
} finally {
status = 100;
}
}
public void addInformationColumsToTable(String table) throws Exception{
AnalysisLogger.getLogger().debug("EstimateFishingActivity: initializing connection");
long t0 = System.currentTimeMillis();
try {
connection = DatabaseUtils.initDBSession(config);
AnalysisLogger.getLogger().debug("EstimateFishingActivity: database: " + config.getDatabaseURL());
// create a new output table
AnalysisLogger.getLogger().debug("EstimateFishingActivity: dropping table " + outTable + " if exists");
try {
DatabaseFactory.executeSQLUpdate(DatabaseUtils.dropTableStatement(outTable), connection);
} catch (Exception e) {
AnalysisLogger.getLogger().debug("EstimateFishingActivity: table " + outTable + " does not exist yet");
}
AnalysisLogger.getLogger().debug("EstimateFishingActivity: creating the new table " + outTable);
DatabaseFactory.executeSQLUpdate(DatabaseUtils.createBlankTableFromAnotherStatement(table, outTable), connection);
AnalysisLogger.getLogger().debug("EstimateFishingActivity: adding new columns to " + outTable);
DatabaseFactory.executeSQLUpdate(DatabaseUtils.addColumnStatement(outTable, "activity_hours", "real"), connection);
DatabaseFactory.executeSQLUpdate(DatabaseUtils.addColumnStatement(outTable, "bathymetry", "real"), connection);
DatabaseFactory.executeSQLUpdate(DatabaseUtils.addColumnStatement(outTable, "activity_class_speed", "character varying"), connection);
DatabaseFactory.executeSQLUpdate(DatabaseUtils.addColumnStatement(outTable, "activity_class_speed_bath", "character varying"), connection);
AnalysisLogger.getLogger().debug("EstimateFishingActivity: getting columns from " + outTable);
// get columns names
List<Object> names = DatabaseFactory.executeSQLQuery(DatabaseUtils.getColumnsNamesStatement(outTable), connection);
StringBuffer colnames = new StringBuffer();
int nnames = names.size();
for (int i = 0; i < nnames; i++) {
colnames.append(names.get(i));
if (i < nnames - 1)
colnames.append(",");
}
AnalysisLogger.getLogger().debug("EstimateFishingActivity: columns are: " + colnames.toString());
AnalysisLogger.getLogger().debug("EstimateFishingActivity: taking chunks ... ");
List<Object> vessels = DatabaseFactory.executeSQLQuery("select distinct "+config.getParam(VesselsIDColumn)+" from "+table, connection);
int nvessels = vessels.size();
int k=0;
//error check
if (config.getParam(VesselsIDColumn)==null || config.getParam(VesselsSpeedsColumn)==null || config.getParam(VesselsTimestampsColumn)==null || config.getParam(VesselsLongitudesColumn)==null || config.getParam(VesselsLatitudesColumn)==null)
throw new Exception ("Error with input parameters, please check that all the required inputs have been provided.");
for (Object vesselrow:vessels){
String vesselID = ""+vesselrow;
AnalysisLogger.getLogger().debug("EstimateFishingActivity: Analysing vessel "+vesselID+" "+(k+1)+" of "+nvessels);
//extract single vessel trajectory information
String selectTrajectory = "select *, "+
"\""+config.getParam(VesselsIDColumn)+"\""+" as fhv01,"+
"\""+config.getParam(VesselsSpeedsColumn)+"\""+" as fhv02,"+
"\""+config.getParam(VesselsTimestampsColumn)+"\""+" as fhv03,"+
"\""+config.getParam(VesselsLongitudesColumn)+"\""+" as fhv04,"+
"\""+config.getParam(VesselsLatitudesColumn)+"\""+" as fhv05 "+
" from "+table+
" where "+"CAST(\""+config.getParam(VesselsIDColumn)+"\" as integer)"+" ="+vesselID+" order by CAST("+"\""+config.getParam(VesselsTimestampsColumn)+"\""+" as timestamp)";
AnalysisLogger.getLogger().debug("EstimateFishingActivity: EstimateFishingActivity: Select trajectory: "+selectTrajectory);
List<Object> vesselTrajectory = DatabaseFactory.executeSQLQuery(selectTrajectory, connection);
int nvesselpoints = vesselTrajectory.size();
String[] vesselIDs = new String[nvesselpoints];
Date[] timeStamps = new Date[nvesselpoints];
java.awt.geom.Point2D.Double [] coordinates = new java.awt.geom.Point2D.Double[nvesselpoints];
Tuple<String>[] bathspeedpairs = new Tuple [nvesselpoints];
String[] speeds = new String[nvesselpoints];
AnalysisLogger.getLogger().debug("EstimateFishingActivity: EstimateFishingActivity: building information: "+selectTrajectory);
int i=0;
for (Object trajectorrow:vesselTrajectory){
Object[] trajectvector = (Object[]) trajectorrow;
int lenvector = trajectvector.length;
vesselIDs[i] = ""+trajectvector[lenvector-5];
speeds[i] = ""+trajectvector[lenvector-4];
timeStamps[i] = DateGuesser.convertDate(""+trajectvector[lenvector-3]).getTime();
if (timeStamps[i]==null)
throw new Exception ("Cannot parse time "+trajectvector[lenvector-3]+" for vessel "+vesselIDs[i]+". please try specifying time as MM/dd/yy KK:mm:ss a");
if (i==0){
String pattern = DateGuesser.getPattern(""+trajectvector[lenvector-3]);
AnalysisLogger.getLogger().debug("EstimateFishingActivity: sample time conversion: original "+trajectvector[lenvector-3]+" guessed: "+timeStamps[i]+" pattern: "+pattern);
}
try{
coordinates [i] = new java.awt.geom.Point2D.Double(Double.parseDouble(""+trajectvector[lenvector-2]),Double.parseDouble(""+trajectvector[lenvector-1]));
}catch(Exception e){
AnalysisLogger.getLogger().debug("EstimateFishingActivity: Warning - wrong coordinates: "+trajectvector[lenvector-2]+","+trajectvector[lenvector-1]);
coordinates [i] = new java.awt.geom.Point2D.Double(0,0);
}
i++;
}
AnalysisLogger.getLogger().debug("EstimateFishingActivity: estimating fishing hours");
double [] hours = FishingHoursCalculator.calculateFishingHours(vesselIDs, timeStamps);
AnalysisLogger.getLogger().debug("EstimateFishingActivity: estimating bathymetry");
short [] bathymetry = null;
try{
String bathpath=new File(config.getConfigPath(),"gebco_08.nc").getAbsolutePath();
AnalysisLogger.getLogger().debug("EstimateFishingActivity: searching bathymetry in "+bathpath);
Bathymetry bathymetryprocessor = new Bathymetry(bathpath);
bathymetry = bathymetryprocessor.compute(coordinates);
}catch(Exception e){
AnalysisLogger.getLogger().debug("EstimateFishingActivity: Error - Bathymetry resource not available for the service "+e.getLocalizedMessage());
throw new Exception("Error - Bathymetry resource not available for the service");
}
for (int g=0;g<nvesselpoints;g++){
bathspeedpairs[g]=new Tuple<String>(""+speeds[g],""+bathymetry[g]);
}
AnalysisLogger.getLogger().debug("EstimateFishingActivity: classifying routes");
Tuple<Integer>[] classifications = VTIClassificator.classify(bathspeedpairs);
AnalysisLogger.getLogger().debug("EstimateFishingActivity:building rows for the final table");
List<String[]> stringrows = new ArrayList<String[]>();
i=0;
for (Object trajectorrow:vesselTrajectory){
Object[] trajectvector = (Object[]) trajectorrow;
String[] extendedrow = new String[nnames];
for(int j=0;j<nnames-4;j++){
extendedrow[j]=""+trajectvector[j];
}
extendedrow[nnames-4] = ""+hours[i];
extendedrow[nnames-3] = ""+bathymetry[i];
extendedrow[nnames-2] = ""+VTIClassificator.speedClassification(classifications[i].getElements().get(0));
extendedrow[nnames-1] = ""+VTIClassificator.bathymetryClassification(classifications[i].getElements().get(1));
stringrows.add(extendedrow);
i++;
}
AnalysisLogger.getLogger().debug("EstimateFishingActivity: inserting chunks into the table "+outTable);
// write the vector into the table
DatabaseUtils.insertChunksIntoTable(outTable, colnames.toString(), stringrows, nvesselpoints, connection, true);
AnalysisLogger.getLogger().debug("EstimateFishingActivity: inserting chunks done!");
k++;
}
AnalysisLogger.getLogger().debug("EstimateFishingActivity: finished");
} catch (Throwable e) {
e.printStackTrace();
AnalysisLogger.getLogger().debug("EstimateFishingActivity : ERROR!: " + e.getLocalizedMessage());
try {
AnalysisLogger.getLogger().debug("EstimateFishingActivity: dropping " + outTable);
DatabaseFactory.executeSQLUpdate(DatabaseUtils.dropTableStatement(outTable), connection);
} catch (Exception e1) {
AnalysisLogger.getLogger().debug("EstimateFishingActivity: could not drop " + outTable);
}
throw new Exception(e.getMessage());
} finally {
shutdown();
AnalysisLogger.getLogger().debug("EstimateFishingActivity finished in " + (System.currentTimeMillis() - t0) + " ms");
}
}
}