240 lines
13 KiB
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");
|
|
}
|
|
}
|
|
|
|
}
|
|
|