diff --git a/src/PamController/settings/output/xml/PamguardXMLWriter.java b/src/PamController/settings/output/xml/PamguardXMLWriter.java index 72d54ac8..7058241b 100644 --- a/src/PamController/settings/output/xml/PamguardXMLWriter.java +++ b/src/PamController/settings/output/xml/PamguardXMLWriter.java @@ -437,7 +437,7 @@ public class PamguardXMLWriter implements PamSettings { * @param pamSettingsUnit * @return xml element */ - private Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit) { + public Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit) { int[] settingInds = findSettings(null, pamSettingsUnit.getUnitName()); PamSettings[] settingsObjects = null; @@ -462,7 +462,7 @@ public class PamguardXMLWriter implements PamSettings { * can be temporary settings objects when writing temporary settings from dialogs. * @return new XML element. */ - private Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit, PamSettings[] toWrite) { + public Element writeUnitSettings(Document doc, Element parent, PamSettings pamSettingsUnit, PamSettings[] toWrite) { Element moduleData = doc.createElement("MODULE"); moduleData.setAttribute("Java.class", pamSettingsUnit.getClass().getName()); moduleData.setAttribute("UnitType", pamSettingsUnit.getUnitType()); diff --git a/src/PamguardMVC/PamDataBlock.java b/src/PamguardMVC/PamDataBlock.java index f26f24c9..a3d147d1 100644 --- a/src/PamguardMVC/PamDataBlock.java +++ b/src/PamguardMVC/PamDataBlock.java @@ -3055,7 +3055,7 @@ public class PamDataBlock extends PamObservable { /** * Gets a data provider for Tethys. These will probably need - * to be bespoke, but for now will autogenerate based on the SALLogging information. + * to be bespoke, but for now will autogenerate based on the SQLLogging information. * @return the tethysDataProvider */ public TethysDataProvider getTethysDataProvider() { diff --git a/src/tethys/TethysControl.java b/src/tethys/TethysControl.java index c7744e3d..2c88e3d5 100644 --- a/src/tethys/TethysControl.java +++ b/src/tethys/TethysControl.java @@ -11,6 +11,7 @@ import javax.swing.JMenuItem; import PamController.PamControlledUnit; import PamController.PamController; import PamguardMVC.PamDataBlock; +import tethys.dbxml.DBXMLConnect; //import nilus.Deployment; //import nilus.Deployment.Instrument; import tethys.output.StreamExportParams; @@ -33,9 +34,20 @@ public class TethysControl extends PamControlledUnit { private TethysExportParams tethysExportParams = new TethysExportParams(); + private DBXMLConnect dbxmlConnect; public TethysControl(String unitName) { super(unitType, unitName); + dbxmlConnect = new DBXMLConnect(this); + } + + /** + * Get DBXML Connector. This class contains all the functions that are needed + * to talk to the database. + * @return DBXML functions. + */ + public DBXMLConnect getDbxmlConnect() { + return dbxmlConnect; } @Override diff --git a/src/tethys/dbxml/DBXMLConnect.java b/src/tethys/dbxml/DBXMLConnect.java index 154be543..c1613cd9 100644 --- a/src/tethys/dbxml/DBXMLConnect.java +++ b/src/tethys/dbxml/DBXMLConnect.java @@ -2,6 +2,12 @@ package tethys.dbxml; import tethys.TethysControl; +/** + * Class containing functions for managing the database connection. Opening, closing, + * writing, keeping track of performance, etc. + * @author Doug Gillespie, Katie O'Laughlin + * + */ public class DBXMLConnect { private TethysControl tethysControl; @@ -19,6 +25,6 @@ public class DBXMLConnect { } - // add whatever calls are necessary to set up schema's etc. + // add whatever calls are necessary ... } diff --git a/src/tethys/deployment/DeploymentHandler.java b/src/tethys/deployment/DeploymentHandler.java index 2d8dedb3..c5466966 100644 --- a/src/tethys/deployment/DeploymentHandler.java +++ b/src/tethys/deployment/DeploymentHandler.java @@ -67,8 +67,8 @@ public class DeploymentHandler { * Realistically, this list is always 0,1,2,etc or it goes horribly wrong ! */ // so write functions here to get information from the daqParams. - System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(), - daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak); +// System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(), +// daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak); /** * then there is the actual sampling. This is a bit harder to find. I thought it would be in the data map * but the datamap is a simple count of what's in the databasase which is not quite what we want. @@ -207,8 +207,8 @@ public class DeploymentHandler { * Realistically, this list is always 0,1,2,etc or it goes horribly wrong ! */ // so write functions here to get information from the daqParams. - System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(), - daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak); +// System.out.printf("Sample regime: %s input with rate %3.1fHz, %d channels, gain %3.1fdB, ADCp-p %3.1fV\n", daqParams.getDaqSystemType(), +// daqParams.getSampleRate(), daqParams.getNChannels(), daqParams.preamplifier.getGain(), daqParams.voltsPeak2Peak); /** * then there is the actual sampling. This is a bit harder to find. I thought it would be in the data map * but the datamap is a simple count of what's in the databasase which is not quite what we want. @@ -242,8 +242,8 @@ public class DeploymentHandler { } } - System.out.printf("Input map of sound data indicates data from %s to %s with %d starts and %d stops over %d files\n", - PamCalendar.formatDateTime(dataStart), PamCalendar.formatDateTime(dataEnd), nStart, nStop, nFile+1); +// System.out.printf("Input map of sound data indicates data from %s to %s with %d starts and %d stops over %d files\n", +// PamCalendar.formatDateTime(dataStart), PamCalendar.formatDateTime(dataEnd), nStart, nStop, nFile+1); } diff --git a/src/tethys/detection/DetectionGranularity.java b/src/tethys/detection/DetectionGranularity.java new file mode 100644 index 00000000..7380fb67 --- /dev/null +++ b/src/tethys/detection/DetectionGranularity.java @@ -0,0 +1,34 @@ +package tethys.detection; + +/** + * Class to help define what the granularity of exported detections + * documents should be. The entire document will be in memory, so it + * may be necessary to add many detections documents into the database + * for a single Deployment. + * @author dg50 + * + */ +public class DetectionGranularity { + + public enum GRANULARITY {NONE, BINARYFILE, TIME}; + + /** + * Type of granularity. Are data all in one lump, split by binary file or by time. + */ + GRANULARITY granularity = GRANULARITY.NONE; + + /** + * Granularity interval in seconds. Output system will try to round these + * to something with sensible boundaries. + * This field is only needed when using the GRANULARITY.TIME option. + */ + public long granularityIntervalSeconds; + + public DetectionGranularity(GRANULARITY granularity, long granularityIntervalSeconds) { + super(); + this.granularity = granularity; + this.granularityIntervalSeconds = granularityIntervalSeconds; + } + + +} diff --git a/src/tethys/detection/DetectionsHandler.java b/src/tethys/detection/DetectionsHandler.java new file mode 100644 index 00000000..4179d98f --- /dev/null +++ b/src/tethys/detection/DetectionsHandler.java @@ -0,0 +1,191 @@ +package tethys.detection; + +import java.util.ArrayList; +import java.util.List; + +import PamUtils.PamCalendar; +import PamguardMVC.PamDataBlock; +import PamguardMVC.PamDataUnit; +import PamguardMVC.dataSelector.DataSelector; +import dataMap.OfflineDataMap; +import dataMap.OfflineDataMapPoint; +import nilus.DataSourceType; +import nilus.Deployment; +import nilus.Detection; +import nilus.DetectionEffort; +import nilus.DetectionEffortKind; +import nilus.DetectionGroup; +import nilus.Detections; +import tethys.TethysControl; +import tethys.TethysTimeFuncs; +import tethys.detection.DetectionGranularity.GRANULARITY; +import tethys.output.StreamExportParams; +import tethys.output.TethysExportParams; +import tethys.pamdata.TethysDataProvider; + +public class DetectionsHandler { + + + private TethysControl tethysControl; + + public DetectionsHandler(TethysControl tethysControl) { + super(); + this.tethysControl = tethysControl; + } + + /** + * Here is where we export data for a specific data stream to Tethys. + * + * @param aDataBlock + * @param aDeployment + * @param tethysExportParams + * @param streamExportParams + */ + public boolean exportDetections(PamDataBlock aDataBlock, Deployment deployment, DetectionGranularity granularity, TethysExportParams tethysExportParams, + StreamExportParams streamExportParams) { + if (granularity == null || granularity.granularity == null) { + granularity = new DetectionGranularity(GRANULARITY.TIME, 3600); + } + switch (granularity.granularity) { + case BINARYFILE: + return exportByBinaryFile(aDataBlock, deployment, tethysExportParams, streamExportParams); + case NONE: + return exportEverything(aDataBlock, deployment, tethysExportParams, streamExportParams); + case TIME: + return exportByTimeChunk(aDataBlock, deployment, granularity.granularityIntervalSeconds, tethysExportParams, streamExportParams); + default: + break; + } + + return false; + + + } + + private boolean exportByBinaryFile(PamDataBlock dataBlock, Deployment deployment, + TethysExportParams tethysExportParams, StreamExportParams streamExportParams) { + long deploymentStart = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getAudioTimeStamp()); + long deploymentStop = TethysTimeFuncs.millisFromGregorianXML(deployment.getRecoveryDetails().getAudioTimeStamp()); + /* + * there should be a pretty good correspondence between the start of a binary file and the deploymentStart + * since they all derived from the same start clock. + */ + OfflineDataMap dataMap = dataBlock.getPrimaryDataMap(); + if (dataMap == null) { + return false; + } + List mapPoints = dataMap.getMapPoints(); + boolean ok = true; + for (OfflineDataMapPoint mapPoint : mapPoints) { + if (mapPoint.getEndTime() < deploymentStart) { + continue; + } + if (mapPoint.getStartTime() >= deploymentStop) { + continue; + } + ok &= loadAndExport(dataBlock, deployment, Math.max(deploymentStart, mapPoint.getStartTime()), + Math.min(deploymentStop, mapPoint.getEndTime()), tethysExportParams, streamExportParams); + } + + + return ok; + } + + private boolean exportEverything(PamDataBlock dataBlock, Deployment deployment, + TethysExportParams tethysExportParams, StreamExportParams streamExportParams) { + long deploymentStart = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getAudioTimeStamp()); + long deploymentStop = TethysTimeFuncs.millisFromGregorianXML(deployment.getRecoveryDetails().getAudioTimeStamp()); + return loadAndExport(dataBlock, deployment, deploymentStart, deploymentStop, tethysExportParams, streamExportParams); + } + + private boolean exportByTimeChunk(PamDataBlock dataBlock, Deployment deployment, long granularityIntervalSeconds, + TethysExportParams tethysExportParams, StreamExportParams streamExportParams) { + + long deploymentStart = TethysTimeFuncs.millisFromGregorianXML(deployment.getDeploymentDetails().getAudioTimeStamp()); + long deploymentStop = TethysTimeFuncs.millisFromGregorianXML(deployment.getRecoveryDetails().getAudioTimeStamp()); + long chunkMillis = granularityIntervalSeconds*1000; + long exportStart = deploymentStart / chunkMillis; + exportStart *= chunkMillis; + boolean ok = true; + while (exportStart < deploymentStop) { + ok &= loadAndExport(dataBlock, deployment, Math.max(deploymentStart, exportStart), + Math.min(deploymentStop, exportStart + chunkMillis), tethysExportParams, streamExportParams); + exportStart += chunkMillis; + } + + return ok; + } + +/** + * Load and export data for a given time period. This may be a complete deployment, it may be a short section. Do as told ! + * Hopefully data interval is small enough to hold all in memory - it needs to be if the document will fit in mempory, so should be OK + * @param dataBlock + * @param deployment + * @param max + * @param min + * @param tethysExportParams + * @param streamExportParams + */ + private boolean loadAndExport(PamDataBlock dataBlock, Deployment deployment, long startTimeMillis, long endTimeMillis, + TethysExportParams tethysExportParams, StreamExportParams streamExportParams) { + // load the data + dataBlock.loadViewerData(startTimeMillis, endTimeMillis, null); + DataSelector dataSelector = dataBlock.getDataSelector(tethysControl.getDataSelectName(), false); + /* + * for easier synching, get a copy of the data and also apply the data selector right away so that + * we've a list of exactly the right data. + */ + ArrayList data = dataBlock.getDataCopy(startTimeMillis, endTimeMillis, true, dataSelector); + /* + * Here, make Detection object and add the DetectionEffort data. + */ + TethysDataProvider dataProvider = dataBlock.getTethysDataProvider(); + Detections detections = new Detections(); + detections.setId(deployment.getId()); + detections.setDescription(dataProvider.getDescription(deployment, tethysExportParams)); + DataSourceType dataSource = new DataSourceType(); + dataSource.setDeploymentId(deployment.getId()); +// dataSource.setEnsembleId(""); ToDo + detections.setDataSource(dataSource); + detections.setAlgorithm(dataProvider.getAlgorithm()); + detections.setUserId("Unknown user"); + detections.setEffort(getDetectorEffort(deployment, startTimeMillis, endTimeMillis)); + DetectionGroup detectionGroup = new DetectionGroup(); + detections.setOnEffort(detectionGroup); + List detectionList = detectionGroup.getDetection(); + for (int i = 0; i < data.size(); i++) { + PamDataUnit dataUnit = data.get(i); + Detection detection = dataProvider.createDetection(dataUnit, tethysExportParams, streamExportParams); + if (detection != null) { + detectionList.add(detection); + } + } + System.out.printf("Exporting %d %s detections for time period %s to %s\n", detectionList.size(), dataBlock.getDataName(), + detections.getEffort().getStart().toString(), detections.getEffort().getEnd().toString()); + /* + * We should now have a fully populated Detections object, so write it to the database + * using functions in DBXMLConnect + */ + tethysControl.getDbxmlConnect(); // call whatever you need to call in here to write the Detections. + + + return true; + + } + +// private boolean exportByTimeChunk(PamDataBlock aDataBlock, Deployment deployment, long granularityIntervalSeconds, +// TethysExportParams tethysExportParams, StreamExportParams streamExportParams) { +// // TODO Auto-generated method stub +// return false; +// } + + private DetectionEffort getDetectorEffort(Deployment deployment, long effortStart, long effortEnd) { + DetectionEffort effort = new DetectionEffort(); + effort.setStart(TethysTimeFuncs.xmlGregCalFromMillis(effortStart)); + effort.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(effortEnd)); +// effort.set // no setter for DetectionEffortKind + List effortKinds = effort.getKind(); + return effort; + } + +} diff --git a/src/tethys/output/TethysExporter.java b/src/tethys/output/TethysExporter.java index c5396c3a..e9924250 100644 --- a/src/tethys/output/TethysExporter.java +++ b/src/tethys/output/TethysExporter.java @@ -35,6 +35,9 @@ import tethys.TethysControl; import tethys.dbxml.DBXMLConnect; import tethys.deployment.DeploymentHandler; import tethys.deployment.DeploymentRecoveryPair; +import tethys.detection.DetectionGranularity; +import tethys.detection.DetectionGranularity.GRANULARITY; +import tethys.detection.DetectionsHandler; import tethys.pamdata.TethysDataProvider; import tethys.pamdata.TethysSchema; @@ -202,6 +205,7 @@ public class TethysExporter { return false; } + ArrayList deploymentDocs = new ArrayList<>(); /* * This will become the main loop over deployment documents */ @@ -210,7 +214,7 @@ public class TethysExporter { Deployment deployment = deploymentHandler.createDeploymentDocument(i++, drd); // System.out.println(deployment.toString()); - + deploymentDocs.add(deployment); } @@ -220,13 +224,21 @@ public class TethysExporter { * go through the export params and call something for every data block that's * enabled. */ + DetectionsHandler detectionsHandler = new DetectionsHandler(tethysControl); ArrayList allDataBlocks = PamController.getInstance().getDataBlocks(); - for (PamDataBlock aDataBlock : allDataBlocks) { - StreamExportParams streamExportParams = tethysExportParams.getStreamParams(aDataBlock); - if (streamExportParams == null || !streamExportParams.selected) { - continue; // not interested in this one. + /** + * Outer loop is through deployemnt documents. Will then export detections within each + * deployment detector by detector + */ + for (Deployment aDeployment : deploymentDocs) { + for (PamDataBlock aDataBlock : allDataBlocks) { + StreamExportParams streamExportParams = tethysExportParams.getStreamParams(aDataBlock); + if (streamExportParams == null || !streamExportParams.selected) { + continue; // not interested in this one. + } + detectionsHandler.exportDetections(aDataBlock, aDeployment, + new DetectionGranularity(GRANULARITY.TIME, 3600), tethysExportParams, streamExportParams); } - exportDataStream(aDataBlock, tethysExportParams, streamExportParams); } /* * Then do whatever else is needed to complete the document. @@ -297,9 +309,9 @@ public class TethysExporter { for (int iPhone = 0; iPhone < hydrophones.size(); iPhone++) { Hydrophone aPhone = hydrophones.get(iPhone); double totalCal = -daqProcess.rawAmplitude2dB(1, iPhone, false); - System.out.printf( - "hydrophone %d has sensitivity %3.1fdB + gain %3.1fdB. Total calibration is %3.1fdB re1U/uPa\n", - iPhone, aPhone.getSensitivity(), aPhone.getPreampGain(), totalCal); +// System.out.printf( +// "hydrophone %d has sensitivity %3.1fdB + gain %3.1fdB. Total calibration is %3.1fdB re1U/uPa\n", +// iPhone, aPhone.getSensitivity(), aPhone.getPreampGain(), totalCal); } } @@ -308,112 +320,4 @@ public class TethysExporter { - /** - * Here is where we export data for a specific data stream to Tethys. - * - * @param aDataBlock - * @param tethysExportParams - * @param streamExportParams - */ - private void exportDataStream(PamDataBlock aDataBlock, TethysExportParams tethysExportParams, - StreamExportParams streamExportParams) { - /** - * This will probably need to be passed additional parameters and may also want - * to return something other than void in order to build a bigger Tethys - * document. - */ - /* - * Some examples of how to do whatever is needed to get schema and data out of - * PAMGuard. - */ - /* - * first we'll probably want a reference to the module containing the data. in - * principle this can't get null, since the datablock was found be searching in - * the other direction. - */ - PamControlledUnit pamControlledUnit = aDataBlock.getParentProcess().getPamControlledUnit(); - - TethysDataProvider dataProvider = aDataBlock.getTethysDataProvider(); - - PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter(); - - if (dataProvider == null) { - return; - } - - TethysSchema tethysSchema = dataProvider.getSchema(); - /* - * the schema should have a Document object in it. If we wanted to turn that - * into an XML string we can ... (though I'd assume that having the Document is - * more useful) - */ - String schemaXMLString = pamXMLWriter.getAsString(tethysSchema.getXsd(), false); - System.out.printf("Schema for %s is %s\n", aDataBlock.getDataName(), schemaXMLString); - - /* - * Get the XML settings for that datablock. This is (or should be the parameters - * that were controlling that module, with adequate data about upstream - * modules). I think this has to go somewhere into the Detections document. - */ - Document doc = pamXMLWriter.writeOneModule((PamSettings) pamControlledUnit, System.currentTimeMillis()); - String moduleXML = null; - if (doc != null) { - // this string should be XML of all the settings for the module controlling this - // datablock. - moduleXML = pamXMLWriter.getAsString(doc, true); // change to false to get smaller xml - System.out.printf("Module settings for datablock %s are:\n", moduleXML); - System.out.println(moduleXML); - } - - /** - * Now can go through the data. Probably, we'll want to go through all the data - * in the project, but we can hold off on that for now and just go for data that - * are in memory. We'll also have to think a lot about updating parts of the - * database which have been reprocessed - what we want to do, should eventually - * all be options set in the dialog and available within TethysExportParams For - * now though, we're just going to export data that are in memory. Once basic - * export is working, I can easily enough write something which will go through - * an entire data set, go through between two times, etc. - */ - // so this is a way of iterating through the data that are in memory, which will - // do for now .. - // do it with a data copy which can avoid synchronising the entire block for - // what may be a long time - // the copy function is itself synched, and is quite fast, so easier and safe - // this way - ArrayList dataCopy = aDataBlock.getDataCopy(); - DataSelector dataSelector = aDataBlock.getDataSelector(tethysControl.getDataSelectName(), false); - int nSkipped = 0; - int nExport = 0; - - for (PamDataUnit aData : dataCopy) { - /* - * see if we want this data unit. PAMGuard has a complicated system of data - * selectors specific to each data type. These are centrally managed so you - * don't need to worry too much about them. They are identified by name for each - * data stream and the behaviour here should follow the selections you made in - * the dialog. the data selection system allows different displays to show - * different data, so a stream can have many differently named selectors active - * at any one time, all doing different things in different parts of PAMGuard. - */ - if (dataSelector != null) { - if (dataSelector.scoreData(aData) <= 0) { - nSkipped++; - continue; // don't want this one. - } - } - - /* - * then we do whatever we need to do to convert this into something for Tethys - * this might happen in the tethysSchema object for each data stream ???? - */ - - nExport++; - } - - System.out.printf("Exported %d data units and skipped %d in %s", nExport, nSkipped, - aDataBlock.getLongDataName()); - - } - } diff --git a/src/tethys/pamdata/AutoTethysProvider.java b/src/tethys/pamdata/AutoTethysProvider.java index 52243cc9..48f0f36c 100644 --- a/src/tethys/pamdata/AutoTethysProvider.java +++ b/src/tethys/pamdata/AutoTethysProvider.java @@ -1,11 +1,32 @@ package tethys.pamdata; -import org.w3c.dom.Document; +import java.math.BigInteger; +import java.util.List; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import PamController.PamControlledUnit; +import PamController.PamSettings; +import PamController.PamguardVersionInfo; +import PamController.settings.output.xml.PamguardXMLWriter; +import PamUtils.XMLUtils; import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataUnit; +import PamguardMVC.PamProcess; import generalDatabase.DBSchemaWriter; import generalDatabase.SQLLogging; +import nilus.AlgorithmType; +import nilus.AlgorithmType.Parameters; +import nilus.Deployment; +import nilus.DescriptionType; +import nilus.Detection; +import nilus.SpeciesIDType; +import tethys.TethysTimeFuncs; +import tethys.output.StreamExportParams; +import tethys.output.TethysExportParams; /** * Automatically provides Tethys data based on the SQL database interface @@ -16,9 +37,13 @@ import generalDatabase.SQLLogging; public class AutoTethysProvider implements TethysDataProvider { private PamDataBlock pamDataBlock; + private PamProcess pamProcess; + private PamControlledUnit pamControlledUnit; public AutoTethysProvider(PamDataBlock pamDataBlock) { this.pamDataBlock = pamDataBlock; + pamProcess = pamDataBlock.getParentProcess(); + pamControlledUnit = pamProcess.getPamControlledUnit(); } @Override @@ -39,4 +64,131 @@ public class AutoTethysProvider implements TethysDataProvider { return null; } + @Override + public DescriptionType getDescription(Deployment deployment, TethysExportParams tethysExportParams) { + DescriptionType description = new DescriptionType(); + String fullUnitName = pamControlledUnit.getUnitType() + " " + pamControlledUnit.getUnitName(); + description.setAbstract(fullUnitName); + description.setObjectives(fullUnitName); + description.setMethod(pamControlledUnit.getUnitType()); + + return description; + } + + @Override + public AlgorithmType getAlgorithm() { + AlgorithmType algorithm = new AlgorithmType(); + algorithm.setMethod(this.getAlgorithmMethod()); + algorithm.setSoftware("PAMGuard"); + algorithm.setVersion(PamguardVersionInfo.version); + algorithm.setParameters(this.getAlgorithmParameters()); + + return algorithm; + } + + private Parameters getAlgorithmParameters() { + if (pamControlledUnit instanceof PamSettings == false) { + return null; + } + PamSettings pamSettings = (PamSettings) pamControlledUnit; + Parameters parameters = new Parameters(); + List paramList = parameters.getAny(); + Document doc = XMLUtils.createBlankDoc(); + PamguardXMLWriter pamXMLWriter = PamguardXMLWriter.getXMLWriter(); + Element dummyEl = doc.createElement("MODULES"); + doc.appendChild(dummyEl); + PamSettings[] settingsObjs = getSettingsObjects(); + if (settingsObjs == null) { + return null; + } + Element settingsEl = pamXMLWriter.writeUnitSettings(doc, dummyEl, pamSettings, settingsObjs); + if (settingsEl == null) { + return null; + } + dummyEl.appendChild(settingsEl); + NodeList childs = settingsEl.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { + Node el = childs.item(i); +// System.out.println(el.getNodeName()); + if (el instanceof Element) { + paramList.add((Element) el); + } + } + +// Document doc = pamXMLWriter.writeOneModule((PamSettings) pamControlledUnit, System.currentTimeMillis()); +// String moduleXML = null; + if (doc != null) { + // this string should be XML of all the settings for the module controlling this + // datablock. +// moduleXML = pamXMLWriter.getAsString(doc, true); // change to false to get smaller xml +// System.out.printf("Module settings for datablock %s are:\n", moduleXML); +// System.out.println(moduleXML); +// Element pamguard = doc.get("PAMGUARD"); +// Element modules = (Element) pamguard.getElementsByTagName("MODULES"); +// doc.get +// NodeList childs = doc.getChildNodes(); +// for (int i = 0; i < childs.getLength(); i++) { +// Node el = childs.item(i); +// System.out.println(el.getNodeName()); +// if (el instanceof Element) { +// paramList.add((Element) el); +// } +// } +// String moduleXML = pamXMLWriter.getAsString(doc, true); // change to false to get smaller xml +// System.out.printf("Module settings for datablock %s are:\n%s", this.pamDataBlock.getDataName(), moduleXML); + } + +// // try the old say +// Document doc2 = pamXMLWriter.writeOneModule((PamSettings) pamControlledUnit, System.currentTimeMillis()); +// String moduleXML = null; +// if (doc2 != null) { +// // this string should be XML of all the settings for the module controlling this +// // datablock. +// moduleXML = pamXMLWriter.getAsString(doc2, true); // change to false to get smaller xml +// System.out.printf("Module settings for datablock %s are:\n%s", pamDataBlock.getDataName(),moduleXML); +// } +// + + return parameters; + } + + private PamSettings[] getSettingsObjects() { + if (pamControlledUnit instanceof PamSettings) { + PamSettings[] settings = new PamSettings[1]; + settings[0] = (PamSettings) pamControlledUnit; + return settings; + } + return null; + } + + /** + * Algorithm method. Default is the module name. Can change to a paper citation + * by overriding this + * @return + */ + private String getAlgorithmMethod() { + return pamControlledUnit.getUnitType(); + } + + @Override + public Detection createDetection(PamDataUnit dataUnit, TethysExportParams tethysExportParams, + StreamExportParams streamExportParams) { + Detection detection = new Detection(); + detection.setStart(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getTimeMilliseconds())); + detection.setEnd(TethysTimeFuncs.xmlGregCalFromMillis(dataUnit.getEndTimeInMilliseconds())); + detection.setSpeciesId(getSpeciesIdType()); + /* + * NOTE: I use channel bitmaps throughout since detections are often made on multiple channels. + */ + detection.setChannel(BigInteger.valueOf(dataUnit.getChannelBitmap())); + + return detection; + } + + private SpeciesIDType getSpeciesIdType() { + SpeciesIDType species = new SpeciesIDType(); +// species.s + return species; + } + } diff --git a/src/tethys/pamdata/TethysDataProvider.java b/src/tethys/pamdata/TethysDataProvider.java index ffa7df67..e844675a 100644 --- a/src/tethys/pamdata/TethysDataProvider.java +++ b/src/tethys/pamdata/TethysDataProvider.java @@ -1,6 +1,12 @@ package tethys.pamdata; import PamguardMVC.PamDataUnit; +import nilus.AlgorithmType; +import nilus.Deployment; +import nilus.DescriptionType; +import nilus.Detection; +import tethys.output.StreamExportParams; +import tethys.output.TethysExportParams; /** * Any PAMGuard data stream which can provide Detection data to PAMGuard will @@ -28,5 +34,33 @@ public interface TethysDataProvider { * @return */ public TethysDataPoint getDataPoint(PamDataUnit pamDataUnit); + + + /** + * Get DescriptionType object to include in a Tethys Detections document. + * @param deployment + * @param tethysExportParams + * @return Tethys DescriptionType object, which contains infromation about detections + */ + public DescriptionType getDescription(Deployment deployment, TethysExportParams tethysExportParams); + + + /** + * Get Algorithm information for a Tethys Detections document + * @return Algorithm information + */ + public AlgorithmType getAlgorithm(); + + + /** + * Create a Tethys Detection object from a PamDataUnit.
+ * It's OK for this to return null if for some reason the unit shouldn't be stored. + * @param dataUnit PAMGuard data unit + * @param tethysExportParams + * @param streamExportParams + * @return Detection Tethys Detection object. + */ + public Detection createDetection(PamDataUnit dataUnit, TethysExportParams tethysExportParams, + StreamExportParams streamExportParams); }