Skip to content

Commit

Permalink
Add support for detections datasets
Browse files Browse the repository at this point in the history
  • Loading branch information
paytoncain committed Aug 5, 2024
1 parent ff63d07 commit bb3a86c
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public abstract class BasePackage<T> implements AbstractObject, TimeRange, Calib
private final Path otherPath;
private final Path documentsPath;
private final Path calibrationDocumentsPath;
private final Path navigationPath;
private final Path navigationPath; // TODO: Remove this
@NotNull
private final Path sourcePath;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class MobileMarineLocation implements MarineLocation {
private final String vessel;
@NotBlank
private final String locationDerivationDescription;

// TODO: Add file list (List<Path>)

@Override
public MobileMarineLocation setSeaArea(String seaArea) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public class MobileMarineLocationTranslator implements LocationDetailTranslator
private final String seaArea;
private final String vessel;
private final String locationDerivationDescription;
// TODO: Add file list mapping (String, value is semi-colon delimited): file-1.txt;file-2.txt;file-3.txt

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import edu.colorado.cires.pace.data.object.dataset.base.metadata.QualityLevel;
import edu.colorado.cires.pace.data.object.dataset.base.metadata.TimeRange;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import lombok.Builder;
import lombok.Data;
Expand All @@ -20,6 +21,7 @@ public class DataQualityEntry implements TimeRange, FrequencyRange {
private final Float maxFrequency;
private final QualityLevel qualityLevel;
private final String comments;
private final List<Integer> channelNumbers;
@Builder.Default
private final List<Integer> channelNumbers = Collections.emptyList();

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class PassivePackerDatasetDetails {
private final String modelEnd;
private final String frequency;
private final String dataComment;
private final String species;
private final String scientificName;


}
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@
import edu.colorado.cires.pace.data.object.dataset.soundClips.SoundClipsPackage;
import edu.colorado.cires.pace.data.object.dataset.soundLevelMetrics.SoundLevelMetricsPackage;
import edu.colorado.cires.pace.data.object.dataset.soundPropagationModels.SoundPropagationModelsPackage;
import edu.colorado.cires.pace.data.object.detectionType.DetectionType;
import edu.colorado.cires.pace.data.object.position.Position;
import edu.colorado.cires.pace.data.object.sensor.audio.AudioSensor;
import edu.colorado.cires.pace.data.object.sensor.base.Sensor;
import edu.colorado.cires.pace.data.object.sensor.depth.DepthSensor;
import edu.colorado.cires.pace.data.object.sensor.other.OtherSensor;
import edu.colorado.cires.pace.datastore.DatastoreException;
import edu.colorado.cires.pace.repository.DetectionTypeRepository;
import edu.colorado.cires.pace.repository.NotFoundException;
import edu.colorado.cires.pace.repository.OrganizationRepository;
import edu.colorado.cires.pace.repository.PersonRepository;
Expand All @@ -73,11 +75,14 @@ public class PassivePackerFactory {
private final PersonRepository personRepository;
private final OrganizationRepository organizationRepository;
private final SensorRepository sensorRepository;
private final DetectionTypeRepository detectionTypeRepository;

public PassivePackerFactory(PersonRepository personRepository, OrganizationRepository organizationRepository, SensorRepository sensorRepository) {
public PassivePackerFactory(PersonRepository personRepository, OrganizationRepository organizationRepository, SensorRepository sensorRepository,
DetectionTypeRepository detectionTypeRepository) {
this.personRepository = personRepository;
this.organizationRepository = organizationRepository;
this.sensorRepository = sensorRepository;
this.detectionTypeRepository = detectionTypeRepository;
}

public PassivePackerPackage createPackage(Package aPackage) throws NotFoundException, DatastoreException {
Expand Down Expand Up @@ -115,6 +120,10 @@ public PassivePackerPackage createPackage(Package aPackage) throws NotFoundExcep
passivePackerPackage = passivePackerPackage.toBuilder()
.qualityDetails(getQualityDetails(soundLevelMetricsPackage))
.build();
} else if (aPackage instanceof DetectionsPackage detectionsPackage) {
passivePackerPackage = passivePackerPackage.toBuilder()
.qualityDetails(getQualityDetails(detectionsPackage))
.build();
}

return passivePackerPackage;
Expand Down Expand Up @@ -234,7 +243,7 @@ private String getDeployType(LocationDetail locationDetail) {
return null;
}

private PassivePackerDatasetDetails getDatasetDetails(Package aPackage) {
private PassivePackerDatasetDetails getDatasetDetails(Package aPackage) throws NotFoundException, DatastoreException {
PassivePackerDatasetDetails datasetDetails = PassivePackerDatasetDetails.builder()
.type(aPackage.getProcessingLevel().name())
.subType(subtypeFromPackage(aPackage))
Expand Down Expand Up @@ -284,6 +293,35 @@ private PassivePackerDatasetDetails getDatasetDetails(Package aPackage) {
.modelEnd(serializeDateTime(soundPropagationModelsPackage.getEndTime()))
.frequency(String.valueOf(soundPropagationModelsPackage.getModeledFrequency()))
.build();
} else if (aPackage instanceof DetectionsPackage detectionsPackage) {
String sourceName = detectionsPackage.getSoundSource();
String species = null;
String scientificName = null;

if (sourceName != null) {
DetectionType detectionType = detectionTypeRepository.getByUniqueField(sourceName);

species = detectionType.getSource();
scientificName = detectionType.getScienceName();
}

datasetDetails = datasetDetails.toBuilder()
.dataFiles(String.valueOf(detectionsPackage.getSourcePath()))
.analysisStart(serializeDateTime(detectionsPackage.getStartTime()))
.analysisEnd(serializeDateTime(detectionsPackage.getEndTime()))
.analysisTimeZone(String.valueOf(detectionsPackage.getAnalysisTimeZone()))
.analysisEffort(String.valueOf(detectionsPackage.getAnalysisEffort()))
.minAnalysisFrequency(String.valueOf(detectionsPackage.getMinFrequency()))
.maxAnalysisFrequency(String.valueOf(detectionsPackage.getMaxFrequency()))
.analysisSampleRate(String.valueOf(detectionsPackage.getSampleRate()))
.species(species)
.scientificName(scientificName)
.softwareName(detectionsPackage.getSoftwareNames())
.softwareVersion(detectionsPackage.getSoftwareVersions())
.protocolReference(detectionsPackage.getSoftwareProtocolCitation())
.processingStatement(detectionsPackage.getSoftwareProcessingDescription())
.softwareStatement(detectionsPackage.getSoftwareDescription())
.build();
}

return datasetDetails;
Expand Down Expand Up @@ -337,7 +375,7 @@ private PassivePackerCalibrationInfo getCalibrationInfo(Package aPackage) {
}

PassivePackerCalibrationInfo calibrationInfo = PassivePackerCalibrationInfo.builder()
.calDate(String.valueOf(calDate))
.calDate(calDate == null ? null : String.valueOf(calDate))
.calState(calState)
.calDocsPath(aPackage.getCalibrationDocumentsPath().toString())
.comment(aPackage.getCalibrationDescription())
Expand All @@ -350,7 +388,8 @@ private PassivePackerCalibrationInfo getCalibrationInfo(Package aPackage) {
.gain(String.valueOf(audioDataPackage.getGain()))
.calDate2(calDate2 == null ? null : String.valueOf(calDate2))
.build();
} else if (aPackage instanceof SoundClipsPackage || aPackage instanceof SoundLevelMetricsPackage || aPackage instanceof SoundPropagationModelsPackage) {
} else if (aPackage instanceof SoundClipsPackage || aPackage instanceof SoundLevelMetricsPackage
|| aPackage instanceof SoundPropagationModelsPackage || aPackage instanceof DetectionsPackage) {
calibrationInfo = calibrationInfo.toBuilder()
.calState(aPackage.getPreDeploymentCalibrationDate() != null ? "Calibration applied before processing" : "Not calibrated / not applicable")
.calDate(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@
import edu.colorado.cires.pace.data.object.dataset.base.metadata.location.StationaryMarineLocation;
import edu.colorado.cires.pace.data.object.dataset.base.metadata.location.StationaryTerrestrialLocation;
import edu.colorado.cires.pace.data.object.dataset.base.metadata.translator.DataQualityEntry;
import edu.colorado.cires.pace.data.object.dataset.detections.DetectionsPackage;
import edu.colorado.cires.pace.data.object.dataset.passivePacker.PassivePackerPackage;
import edu.colorado.cires.pace.data.object.dataset.soundClips.SoundClipsPackage;
import edu.colorado.cires.pace.data.object.dataset.soundLevelMetrics.SoundLevelMetricsPackage;
import edu.colorado.cires.pace.data.object.dataset.soundPropagationModels.SoundPropagationModelsPackage;
import edu.colorado.cires.pace.data.object.detectionType.DetectionType;
import edu.colorado.cires.pace.data.object.position.Position;
import edu.colorado.cires.pace.data.object.sensor.audio.AudioSensor;
import edu.colorado.cires.pace.data.object.sensor.depth.DepthSensor;
import edu.colorado.cires.pace.data.object.sensor.other.OtherSensor;
import edu.colorado.cires.pace.datastore.DatastoreException;
import edu.colorado.cires.pace.repository.DetectionTypeRepository;
import edu.colorado.cires.pace.repository.NotFoundException;
import edu.colorado.cires.pace.repository.OrganizationRepository;
import edu.colorado.cires.pace.repository.PersonRepository;
Expand All @@ -58,13 +61,15 @@ class PassivePackerFactoryTest {

private final ObjectMapper objectMapper = SerializationUtils.createObjectMapper()
.configure(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS, false) // for testing only
.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true)
.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_SNAKE_CASE);

private final PersonRepository personRepository = mock(PersonRepository.class);
private final OrganizationRepository organizationRepository = mock(OrganizationRepository.class);
private final SensorRepository sensorRepository = mock(SensorRepository.class);
private final DetectionTypeRepository detectionTypeRepository = mock(DetectionTypeRepository.class);

private final PassivePackerFactory factory = new PassivePackerFactory(personRepository, organizationRepository, sensorRepository);
private final PassivePackerFactory factory = new PassivePackerFactory(personRepository, organizationRepository, sensorRepository, detectionTypeRepository);

@BeforeEach
void beforeEach() throws NotFoundException, DatastoreException {
Expand Down Expand Up @@ -110,6 +115,11 @@ void beforeEach() throws NotFoundException, DatastoreException {
.sensorType("sensor type")
.properties("sensor properties")
.build());

when(detectionTypeRepository.getByUniqueField("Blue whale")).thenReturn(DetectionType.builder()
.source("Blue whale")
.scienceName("Balaenoptera musculus")
.build());
}

@Test
Expand Down Expand Up @@ -255,6 +265,62 @@ void testCPODPrePostDeploymentCalibrated() throws IOException, NotFoundException
)
);
}

@Test
void testDetections() throws NotFoundException, DatastoreException, IOException {
assertEquals(
objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(
objectMapper.readValue(new File("src/test/resources/detections.json"), PassivePackerPackage.class)
),
objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(
factory.createPackage(createDetectionsPackage(createStationaryMarineLocation(), null))
)
);
}

private Package createDetectionsPackage(LocationDetail locationDetail, LocalDate preDeploymentCalibrationDate) {
return createBasePackage(locationDetail).toInheritingType(DetectionsPackage.builder()).toBuilder()
.processingLevel(ProcessingLevel.Product)
.preDeploymentCalibrationDate(preDeploymentCalibrationDate)
.postDeploymentCalibrationDate(null)
.soundSource("Blue whale")
.qualityAnalyst("Chuck Anderson")
.qualityEntries(List.of(
DataQualityEntry.builder()
.qualityLevel(QualityLevel.good)
.minFrequency(0f)
.maxFrequency(500f)
.startTime(LocalDateTime.of(2011, 1, 1, 13, 0, 0))
.endTime(LocalDateTime.of(2011, 1, 1, 15, 0,0))
.comments("quality comments")
.channelNumbers(List.of(1, 2))
.build(),
DataQualityEntry.builder()
.qualityLevel(QualityLevel.unusable)
.minFrequency(1f)
.maxFrequency(20f)
.startTime(LocalDateTime.of(2011, 1, 6, 13, 0, 0))
.endTime(LocalDateTime.of(2012, 1, 8, 13, 0, 0))
.comments("quality comments 2")
.channelNumbers(List.of(2))
.build()
)).qualityAnalysisMethod("quality method")
.qualityAnalysisObjectives("quality objectives")
.qualityAssessmentDescription("quality assessment description")
.startTime(LocalDateTime.of(2010, 1, 1, 13, 0, 0))
.endTime(LocalDateTime.of(2011, 1, 2, 13, 0, 0))
.analysisTimeZone(6)
.analysisEffort(20)
.minFrequency(200f)
.maxFrequency(400f)
.sampleRate(20000f)
.softwareNames("software name")
.softwareVersions("software version")
.softwareProtocolCitation("protocol citation")
.softwareDescription("software statement")
.softwareProcessingDescription("software processing description")
.build();
}

private Package createSoundPropagationModelsPackage(LocationDetail locationDetail, LocalDate preDeploymentCalibrationDate) {
return createBasePackage(locationDetail).toInheritingType(SoundPropagationModelsPackage.builder()).toBuilder()
Expand Down Expand Up @@ -285,7 +351,7 @@ private Package createSoundClipsPackage(LocationDetail locationDetail, LocalDate
.softwareProcessingDescription("software processing description")
.processingLevel(ProcessingLevel.Product)
.audioStartTime(LocalDateTime.of(2010, 1, 1, 13, 0, 0))
.audioEndTime(LocalDateTime.of(2010, 1, 1, 13, 10, 0))
.audioEndTime(LocalDateTime.of(2010, 1, 1, 13, 30, 0))
.build();
}

Expand Down
Loading

0 comments on commit bb3a86c

Please sign in to comment.