From 8349862b8532f493f50949c1916f0f83a898323d Mon Sep 17 00:00:00 2001 From: tpylak <tpylak> Date: Tue, 1 Mar 2011 09:57:58 +0000 Subject: [PATCH] LMS-2081 a framework to register feature vectors from the jython dropbox SVN: 20167 --- .../DataSetRegistrationService.java | 2 +- .../dto/api/impl/FeatureDefinitionValues.java | 246 ++++++++++++++++++ .../impl/FeatureVectorDataSetInformation.java | 56 ++++ .../dss/etl/dto/api/impl/FeaturesBuilder.java | 64 +++++ .../dss/etl/dto/api/v1/FeatureDefinition.java | 120 +++++++++ .../dss/etl/dto/api/v1/IFeatureValues.java | 48 ++++ .../dss/etl/dto/api/v1/IFeaturesBuilder.java | 29 +++ .../CsvToCanonicalFeatureVector.java | 181 ++----------- .../etl/featurevector/FeatureValuesMap.java | 152 +++++++++++ .../FeatureVectorStorageProcessor.java | 58 ++++- .../featurevector/FeatureVectorUploader.java | 14 +- .../etl/jython/JythonPlateDataSetHandler.java | 121 +++++---- .../jython/SimpleImageDataSetRegistrator.java | 12 +- .../registrator/api/v1/impl/ImageDataSet.java | 3 +- .../dataaccess/ImgFeatureValuesDTO.java | 2 +- .../api/impl/FeatureDefinitionValuesTest.java | 112 ++++++++ 16 files changed, 997 insertions(+), 223 deletions(-) create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinitionValues.java create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSetInformation.java create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeaturesBuilder.java create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/FeatureDefinition.java create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureValues.java create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeaturesBuilder.java create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureValuesMap.java create mode 100644 screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinitionValuesTest.java diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationService.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationService.java index 3655d081169..9d75cd6791b 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationService.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetRegistrationService.java @@ -159,7 +159,7 @@ public class DataSetRegistrationService<T extends DataSetInformation> implements /** * Create a new transaction that atomically performs file operations and registers entities. */ - public IDataSetRegistrationTransaction transaction(File dataSetFile, + public DataSetRegistrationTransaction<T> transaction(File dataSetFile, IDataSetRegistrationDetailsFactory<T> detailsFactory) { File workingDirectory = dataSetFile.getParentFile(); diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinitionValues.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinitionValues.java new file mode 100644 index 00000000000..ff39220551b --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinitionValues.java @@ -0,0 +1,246 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeatureValues; +import ch.systemsx.cisd.openbis.dss.etl.featurevector.CanonicalFeatureVector; +import ch.systemsx.cisd.openbis.dss.etl.featurevector.FeatureValuesMap; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation; +import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateFeatureValues; +import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO; +import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureValuesDTO; +import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureVocabularyTermDTO; + +/** + * Values of one feature for all wells + the way to build this structure. + * + * @author Tomasz Pylak + */ +public class FeatureDefinitionValues implements IFeatureValues +{ + private final ImgFeatureDefDTO imgFeatureDefDTO; + + private final List<FeatureValuesMap> values; + + private FeatureValuesMap currentFeatureVector; + + public FeatureDefinitionValues(ImgFeatureDefDTO imgFeatureDefDTO) + { + this(imgFeatureDefDTO, new FeatureValuesMap(null, null)); + } + + public FeatureDefinitionValues(ImgFeatureDefDTO imgFeatureDefDTO, + FeatureValuesMap currentFeatureVector) + { + assert imgFeatureDefDTO != null : "featureDefinition is null"; + this.imgFeatureDefDTO = imgFeatureDefDTO; + this.values = new ArrayList<FeatureValuesMap>(); + this.currentFeatureVector = currentFeatureVector; + } + + public void setSeries(Double timeOrNull, Double depthOrNull) + { + flushCurrent(); + currentFeatureVector = new FeatureValuesMap(timeOrNull, depthOrNull); + } + + private void flushCurrent() + { + if (currentFeatureVector != null && currentFeatureVector.isEmpty() == false) + { + values.add(currentFeatureVector); + currentFeatureVector = null; + } + } + + /** + * @param well code of the well, e.g. A1 + * @param value value of the feature in the specified well + */ + public void addValue(String well, String value) + { + WellLocation wellPos = WellLocation.parseLocationStr(well); + addValueToCurrent(value, wellPos); + } + + /** + * @param wellRow row coordinate of the well, top-left well has (1,1) coordinates. + * @param wellColumn column coordinate of the well, top-left well has (1,1) coordinates. + * @param value value of the feature in the specified well + */ + public void addValue(int wellRow, int wellColumn, String value) + { + WellLocation wellPos = new WellLocation(wellRow, wellColumn); + addValueToCurrent(value, wellPos); + } + + private void addValueToCurrent(String value, WellLocation wellPos) + { + currentFeatureVector.addValue(value, wellPos); + } + + private void validate(Geometry plateGeometry) + { + for (FeatureValuesMap valuesMap : values) + { + valuesMap.validate(plateGeometry); + } + } + + // ----- converter + + /** @return feature vector in a canonical form with all the values added so far. */ + public CanonicalFeatureVector getCanonicalFeatureVector(Geometry plateGeometry) + { + flushCurrent(); + validate(plateGeometry); + + CanonicalFeatureVector canonicalFeatureVector = new CanonicalFeatureVector(); + canonicalFeatureVector.setFeatureDef(imgFeatureDefDTO); + + Set<String> uniqueValues = getUniqueAvailableValues(); + Map<String, Integer/* value sequence number */> termToSequanceMap = + fixVocabularyTermSequences(uniqueValues); + + List<ImgFeatureVocabularyTermDTO> vocabularyTerms = null; + List<Map<WellLocation, Float>> floatValuesList = tryCreateFloatValueList(); + if (floatValuesList == null) + { + floatValuesList = calculateWellTermsMappingList(termToSequanceMap); + vocabularyTerms = tryCreateVocabularyTerms(termToSequanceMap); + } + List<ImgFeatureValuesDTO> featureDTOs = createValueDTOs(plateGeometry, floatValuesList); + canonicalFeatureVector.setValues(featureDTOs); + canonicalFeatureVector.setVocabularyTerms(vocabularyTerms); + return canonicalFeatureVector; + } + + private List<ImgFeatureValuesDTO> createValueDTOs(Geometry plateGeometry, + List<Map<WellLocation, Float>> floatValuesList) + { + List<ImgFeatureValuesDTO> featureDTOs = new ArrayList<ImgFeatureValuesDTO>(); + for (int i = 0; i < values.size(); i++) + { + FeatureValuesMap featureValuesMap = values.get(i); + Map<WellLocation, Float> floatValues = floatValuesList.get(i); + ImgFeatureValuesDTO featureValuesDTO = + createFeatureValuesDTO(plateGeometry, featureValuesMap, floatValues); + featureDTOs.add(featureValuesDTO); + } + return featureDTOs; + } + + private static ImgFeatureValuesDTO createFeatureValuesDTO(Geometry plateGeometry, + FeatureValuesMap featureValuesMap, Map<WellLocation, Float> floatValues) + { + final PlateFeatureValues valuesValues = + convertColumnToByteArray(plateGeometry, floatValues); + ImgFeatureValuesDTO featureValuesDTO = + new ImgFeatureValuesDTO(featureValuesMap.tryGetTime(), + featureValuesMap.tryGetDepth(), valuesValues, 0); + return featureValuesDTO; + } + + private static PlateFeatureValues convertColumnToByteArray(Geometry geometry, + Map<WellLocation, Float> values) + { + final PlateFeatureValues featureValues = new PlateFeatureValues(geometry); + for (WellLocation loc : values.keySet()) + { + final Float value = values.get(loc); + featureValues.setForWellLocation(value, loc); + } + return featureValues; + } + + private List<Map<WellLocation, Float>> calculateWellTermsMappingList( + Map<String, Integer> termToSequanceMap) + { + List<Map<WellLocation, Float>> list = new ArrayList<Map<WellLocation, Float>>(); + for (FeatureValuesMap featureValuesMap : values) + { + Map<WellLocation, Float> floatValues = + featureValuesMap.calculateWellTermsMapping(termToSequanceMap); + list.add(floatValues); + } + return list; + } + + private List<Map<WellLocation, Float>> tryCreateFloatValueList() + { + List<Map<WellLocation, Float>> list = new ArrayList<Map<WellLocation, Float>>(); + for (FeatureValuesMap featureValuesMap : values) + { + Map<WellLocation, Float> floatValues = featureValuesMap.tryExtractFloatValues(); + if (floatValues == null) + { + return null; + } + list.add(floatValues); + } + return list; + } + + private static List<ImgFeatureVocabularyTermDTO> tryCreateVocabularyTerms( + Map<String, Integer> valueToSequanceMap) + { + if (valueToSequanceMap.isEmpty()) + { + return null; + } + List<ImgFeatureVocabularyTermDTO> vocabularyTerms = + new ArrayList<ImgFeatureVocabularyTermDTO>(); + for (Entry<String, Integer> entry : valueToSequanceMap.entrySet()) + { + vocabularyTerms.add(new ImgFeatureVocabularyTermDTO(entry.getKey(), entry.getValue())); + } + return vocabularyTerms; + } + + private static Map<String, Integer/* value sequence number */> fixVocabularyTermSequences( + Set<String> uniqueValues) + { + Map<String, Integer> valueToSequanceMap = new HashMap<String, Integer>(); + int sequenceNumber = 0; + for (String value : uniqueValues) + { + valueToSequanceMap.put(value, sequenceNumber++); + } + return valueToSequanceMap; + } + + private Set<String> getUniqueAvailableValues() + { + List<FeatureValuesMap> valuesMaps = values; + Set<String> uniqueValues = new HashSet<String>(); + for (FeatureValuesMap valuesMap : valuesMaps) + { + uniqueValues.addAll(valuesMap.getUniqueAvailableValues()); + } + return uniqueValues; + } + +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSetInformation.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSetInformation.java new file mode 100644 index 00000000000..01a79ed6ce9 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureVectorDataSetInformation.java @@ -0,0 +1,56 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl; + +import java.util.List; + +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; +import ch.systemsx.cisd.openbis.generic.shared.IServer; + +/** + * Extends {@link DataSetInformation} with information about images analysis on the well level + * (relevant for HCS). + * + * @author Tomasz Pylak + */ +public class FeatureVectorDataSetInformation extends DataSetInformation +{ + private static final long serialVersionUID = IServer.VERSION; + + private List<FeatureDefinitionValues> features; + + public FeatureVectorDataSetInformation() + { + } + + public List<FeatureDefinitionValues> getFeatures() + { + return features; + } + + public void setFeatures(List<FeatureDefinitionValues> features) + { + this.features = features; + } + + /** are all necessary fields filled? */ + public boolean isValid() + { + return features != null && features.size() > 0; + } + +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeaturesBuilder.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeaturesBuilder.java new file mode 100644 index 00000000000..7aecfaa1401 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeaturesBuilder.java @@ -0,0 +1,64 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl; + +import java.util.ArrayList; +import java.util.List; + +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.FeatureDefinition; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeatureValues; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeaturesBuilder; +import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO; + +/** + * Allows to define feature vectors of one image analysis dataset. + * + * @author Tomasz Pylak + */ +public class FeaturesBuilder implements IFeaturesBuilder +{ + private final List<FeatureDefinitionValues> featureDefinitionValuesList; + + public FeaturesBuilder() + { + this.featureDefinitionValuesList = new ArrayList<FeatureDefinitionValues>(); + } + + /** Defines a container to which values of the feature for each well can be added. */ + public IFeatureValues defineFeature(FeatureDefinition featureDefinition) + { + featureDefinition.ensureValid(); + FeatureDefinitionValues featureDefinitionValues = + new FeatureDefinitionValues(convert(featureDefinition)); + featureDefinitionValuesList.add(featureDefinitionValues); + return featureDefinitionValues; + } + + private static ImgFeatureDefDTO convert(FeatureDefinition featureDefinition) + { + ImgFeatureDefDTO dto = new ImgFeatureDefDTO(); + dto.setCode(featureDefinition.getCode()); + dto.setLabel(featureDefinition.getLabel()); + dto.setDescription(featureDefinition.getDescription()); + return dto; + } + + public List<FeatureDefinitionValues> getFeatureDefinitionValuesList() + { + return featureDefinitionValuesList; + } +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/FeatureDefinition.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/FeatureDefinition.java new file mode 100644 index 00000000000..9ca81d7402e --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/FeatureDefinition.java @@ -0,0 +1,120 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1; + +import org.apache.commons.lang.StringUtils; + +/** + * Definition of the feature. + * + * @author Tomasz Pylak + */ +public class FeatureDefinition +{ + private String code; + + private String label; + + private String description; + + public FeatureDefinition() + { + } + + /** Creates a feature definition, the label will be equal to the code. */ + public FeatureDefinition(String code) + { + this.code = code; + this.label = code; + } + + public String getCode() + { + return code; + } + + /** Sets the code of a feature. */ + public void setCode(String code) + { + this.code = code; + } + + public String getLabel() + { + return label; + } + + /** Sets the label of a feature. */ + public void setLabel(String label) + { + this.label = label; + } + + public String getDescription() + { + return description; + } + + /** Sets description of a feature. */ + public void setDescription(String description) + { + this.description = description; + } + + /** + * Validates that tile number, well and channel have been specified. + * + * @throws IllegalStateException if the object is not valid. + */ + public void ensureValid() + { + if (StringUtils.isBlank(code)) + { + throw new IllegalStateException("Code is not specified"); + } + if (StringUtils.isBlank(label)) + { + throw new IllegalStateException("Label is not specified"); + } + } + + @Override + public int hashCode() + { + return code.hashCode(); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + FeatureDefinition other = (FeatureDefinition) obj; + if (code == null) + { + return other.code == null; + } else + { + return code.equals(other.code); + } + } + +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureValues.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureValues.java new file mode 100644 index 00000000000..113829fd518 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeatureValues.java @@ -0,0 +1,48 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1; + +/** + * An interface which allows to define values of one feature. + * + * @author Tomasz Pylak + */ +public interface IFeatureValues +{ + /** + * Relevant only in cases where feature values for different timepoints and/or depth-scans are + * available. In other cases one does not have to call this method at all. + * <p> + * Sets the timepoint and/or the depth-scan values which will be used in all subsequent calls to + * {@link #addValue} until this method will be called again. + * </p> + */ + void setSeries(Double timeOrNull, Double depthOrNull); + + /** + * @param well code of the well, e.g. A1 + * @param value value of the feature in the specified well + */ + void addValue(String well, String value); + + /** + * @param wellRow row coordinate of the well, top-left well has (1,1) coordinates. + * @param wellColumn column coordinate of the well, top-left well has (1,1) coordinates. + * @param value value of the feature in the specified well + */ + void addValue(int wellRow, int wellColumn, String value); +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeaturesBuilder.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeaturesBuilder.java new file mode 100644 index 00000000000..c5df9d5a4ce --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/v1/IFeaturesBuilder.java @@ -0,0 +1,29 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.dto.api.v1; + +/** + * Allows to define feature vectors of one image analysis dataset. + * + * @author Tomasz Pylak + */ +public interface IFeaturesBuilder +{ + /** Defines a container to which values of the feature for each well can be added. */ + public IFeatureValues defineFeature(FeatureDefinition featureDefinition); + +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/CsvToCanonicalFeatureVector.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/CsvToCanonicalFeatureVector.java index 884288ba7b2..94fdc31e415 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/CsvToCanonicalFeatureVector.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/CsvToCanonicalFeatureVector.java @@ -18,24 +18,18 @@ package ch.systemsx.cisd.openbis.dss.etl.featurevector; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import ch.systemsx.cisd.common.shared.basic.utils.StringUtils; import ch.systemsx.cisd.common.utilities.Counters; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureDefinitionValues; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.DatasetFileLines; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.CodeAndLabelUtil; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CodeAndLabel; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation; -import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateFeatureValues; import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO; -import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureValuesDTO; -import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureVocabularyTermDTO; /** * Converts feature vectors from CSV files to CanonicaFeatureVector objects. @@ -53,8 +47,9 @@ public class CsvToCanonicalFeatureVector private final boolean isSplit; private final Set<String> columnsToBeIgnored; - - public CsvToCanonicalFeatureVectorConfiguration(FeatureVectorStorageProcessorConfiguration config) + + public CsvToCanonicalFeatureVectorConfiguration( + FeatureVectorStorageProcessorConfiguration config) { this(config.getWellRow(), config.getWellColumn(), config.getColumnsToBeIgnored()); } @@ -63,8 +58,9 @@ public class CsvToCanonicalFeatureVector { this(wellRow, wellColumn, Collections.<String> emptySet()); } - - public CsvToCanonicalFeatureVectorConfiguration(String wellRow, String wellColumn, Set<String> columnsToBeIgnored) + + public CsvToCanonicalFeatureVectorConfiguration(String wellRow, String wellColumn, + Set<String> columnsToBeIgnored) { this.wellRowColumn = wellRow; this.wellColumnColumn = wellColumn; @@ -87,7 +83,7 @@ public class CsvToCanonicalFeatureVector { return isSplit; } - + public boolean shouldColumnBeIgnored(String column) { return columnsToBeIgnored.contains(column); @@ -115,6 +111,12 @@ public class CsvToCanonicalFeatureVector private final int maxPlateGeometryCol; + public CsvToCanonicalFeatureVector(DatasetFileLines fileLines, + CsvToCanonicalFeatureVectorConfiguration config, Geometry plateGeometry) + { + this(fileLines, config, plateGeometry.getNumberOfRows(), plateGeometry.getNumberOfColumns()); + } + public CsvToCanonicalFeatureVector(DatasetFileLines fileLines, CsvToCanonicalFeatureVectorConfiguration config, int maxRow, int maxCol) { @@ -157,7 +159,6 @@ public class CsvToCanonicalFeatureVector private CanonicalFeatureVector convertColumnToFeatureVector(Geometry geometry, FeatureColumn column, Counters<String> counters) { - CanonicalFeatureVector featureVector = new CanonicalFeatureVector(); CodeAndLabel codeAndTitle = CodeAndLabelUtil.create(column.name); ImgFeatureDefDTO featureDef = new ImgFeatureDefDTO(); featureDef.setLabel(codeAndTitle.getLabel()); @@ -165,54 +166,8 @@ public class CsvToCanonicalFeatureVector String code = codeAndTitle.getCode(); int count = counters.count(code); featureDef.setCode(count == 1 ? code : code + count); - featureVector.setFeatureDef(featureDef); - - return setFeatureValues(featureVector, column, geometry); - } - - private CanonicalFeatureVector setFeatureValues(CanonicalFeatureVector featureVector, - FeatureColumn column, Geometry geometry) - { - Map<WellLocation, Float> floatValues = column.tryExtractFloatValues(); - List<ImgFeatureVocabularyTermDTO> vocabularyTerms = - new ArrayList<ImgFeatureVocabularyTermDTO>(); - if (floatValues == null) - { - VocabularyFeatureColumnValues vocabularyValues = column.extractVocabularyValues(); - - floatValues = vocabularyValues.getWellTermsMapping(); - vocabularyTerms = createVocabularyTerms(vocabularyValues.getValueToSequanceMap()); - } - final PlateFeatureValues valuesValues = convertColumnToByteArray(geometry, floatValues); - ImgFeatureValuesDTO values = new ImgFeatureValuesDTO(0., 0., valuesValues, 0); - - featureVector.setValues(Collections.singletonList(values)); - featureVector.setVocabularyTerms(vocabularyTerms); - return featureVector; - } - private List<ImgFeatureVocabularyTermDTO> createVocabularyTerms( - Map<String, Integer> valueToSequanceMap) - { - List<ImgFeatureVocabularyTermDTO> vocabularyTerms = - new ArrayList<ImgFeatureVocabularyTermDTO>(); - for (Entry<String, Integer> entry : valueToSequanceMap.entrySet()) - { - vocabularyTerms.add(new ImgFeatureVocabularyTermDTO(entry.getKey(), entry.getValue())); - } - return vocabularyTerms; - } - - private PlateFeatureValues convertColumnToByteArray(Geometry geometry, - Map<WellLocation, Float> values) - { - final PlateFeatureValues featureValues = new PlateFeatureValues(geometry); - for (WellLocation loc : values.keySet()) - { - final Float value = values.get(loc); - featureValues.setForWellLocation(value, loc); - } - return featureValues; + return column.createCanonicalFeatureVector(featureDef, geometry); } private void readLines() @@ -242,7 +197,7 @@ public class CsvToCanonicalFeatureVector String columnValue = line[column.index]; if (StringUtils.isBlank(columnValue) == false) { - column.values.put(well, columnValue); + column.addValue(well, columnValue); } } @@ -309,115 +264,33 @@ public class CsvToCanonicalFeatureVector private final boolean isWellName; - private final HashMap<WellLocation, String> values; + private final FeatureValuesMap values; private FeatureColumn(int index, String name, boolean isWellName) { this.index = index; this.name = name; this.isWellName = isWellName; - values = new HashMap<WellLocation, String>(); + values = new FeatureValuesMap(0., 0.); } - public boolean isEmpty() + public void addValue(WellLocation well, String columnValue) { - return values.isEmpty(); + values.addValue(columnValue, well); } - /** - * Tries to parse all values as float numbers. - * - * @return null if any column value cannot be parsed as float number. - */ - public Map<WellLocation, Float> tryExtractFloatValues() + public CanonicalFeatureVector createCanonicalFeatureVector(ImgFeatureDefDTO featureDef, + Geometry geometry) { - Map<WellLocation, Float> map = new HashMap<WellLocation, Float>(); - for (Entry<WellLocation, String> entry : values.entrySet()) - { - try - { - WellLocation wellLocation = entry.getKey(); - String value = entry.getValue(); - float floatValue = Float.parseFloat(value); - map.put(wellLocation, floatValue); - } catch (NumberFormatException ex) - { - return null; - } - } - return map; - } + FeatureDefinitionValues featureDefinitionValues = + new FeatureDefinitionValues(featureDef, values); - /** - * Assuming that all values come from the set fixed of vocabulary terms calculates the - * mapping from vocabulary term into a unique term sequence number.<br> - * Should be called when {@link #tryExtractFloatValues} returns null. - */ - public VocabularyFeatureColumnValues extractVocabularyValues() - { - return VocabularyFeatureColumnValues.create(values); + return featureDefinitionValues.getCanonicalFeatureVector(geometry); } - } - - private static final class VocabularyFeatureColumnValues - { - private final Map<String, Integer/* value sequence number */> valueToSequanceMap; - - private final Map<WellLocation, Float> wellTermsMapping; - - public static VocabularyFeatureColumnValues create(Map<WellLocation, String> values) - { - Map<String, Integer> valueToSequanceMap = fixVocabularyTermSequences(values); - - Map<WellLocation, Float> wellTermsMapping = new HashMap<WellLocation, Float>(); - for (Entry<WellLocation, String> entry : values.entrySet()) - { - WellLocation wellLocation = entry.getKey(); - String value = entry.getValue(); - int sequenceNumber = valueToSequanceMap.get(value); - wellTermsMapping.put(wellLocation, (float) sequenceNumber); - } - - return new VocabularyFeatureColumnValues(valueToSequanceMap, wellTermsMapping); - } - - private static Map<String, Integer/* value sequence number */> fixVocabularyTermSequences( - Map<WellLocation, String> values) - { - Set<String> uniqueValues = new HashSet<String>(); - for (String value : values.values()) - { - uniqueValues.add(value); - } - - Map<String, Integer> valueToSequanceMap = new HashMap<String, Integer>(); - int sequenceNumber = 0; - for (String value : uniqueValues) - { - valueToSequanceMap.put(value, sequenceNumber++); - } - return valueToSequanceMap; - } - - private VocabularyFeatureColumnValues(Map<String, Integer> valueToSequanceMap, - Map<WellLocation, Float> wellTermsMapping) - { - this.valueToSequanceMap = valueToSequanceMap; - this.wellTermsMapping = wellTermsMapping; - } - - /** mapping from term code to sequence number */ - public Map<String, Integer> getValueToSequanceMap() - { - return valueToSequanceMap; - } - - /** mapping between wells and integer sequence numbers of terms casted to floats */ - public Map<WellLocation, Float> getWellTermsMapping() + public boolean isEmpty() { - return wellTermsMapping; + return values.isEmpty(); } - } } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureValuesMap.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureValuesMap.java new file mode 100644 index 00000000000..f0ecb2d9031 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureValuesMap.java @@ -0,0 +1,152 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.featurevector; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation; + +/** + * Stores values of one feature for all wells (and optionally one chosen timepoint and/or + * depth-scan). + * + * @author Tomasz Pylak + */ +public class FeatureValuesMap +{ + private static final long serialVersionUID = 1L; + + private final Map<WellLocation, String> valuesMap; + + private final Double depthOrNull; + + private final Double timeOrNull; + + public FeatureValuesMap(Double timeOrNull, Double depthOrNull) + { + this.depthOrNull = depthOrNull; + this.timeOrNull = timeOrNull; + this.valuesMap = new HashMap<WellLocation, String>(); + } + + public Double tryGetDepth() + { + return depthOrNull; + } + + public Double tryGetTime() + { + return timeOrNull; + } + + /** Add a value for one well. */ + public void addValue(String value, WellLocation wellPos) + { + if (valuesMap.get(wellPos) != null) + { + throw new IllegalStateException("Value for the well " + wellPos + + " has been already defined!"); + } + valuesMap.put(wellPos, value); + } + + /** @return set of unique values of this feature (makes sense only for vocabulary terms). */ + public Set<String> getUniqueAvailableValues() + { + Set<String> uniqueValues = new HashSet<String>(); + for (String value : valuesMap.values()) + { + uniqueValues.add(value); + } + return uniqueValues; + } + + /** + * Tries to parse all values as float numbers. + * + * @return null if any column value cannot be parsed as float number. + */ + public Map<WellLocation, Float> tryExtractFloatValues() + { + Map<WellLocation, Float> map = new HashMap<WellLocation, Float>(); + for (Entry<WellLocation, String> entry : valuesMap.entrySet()) + { + try + { + WellLocation wellLocation = entry.getKey(); + String value = entry.getValue(); + float floatValue = Float.parseFloat(value); + map.put(wellLocation, floatValue); + } catch (NumberFormatException ex) + { + return null; + } + } + return map; + } + + /** + * Assuming that all values come from the set fixed of vocabulary terms calculates the mapping + * from vocabulary term into a unique term sequence number.<br> + * Should be called when {@link #tryExtractFloatValues} returns null. + * + * @return mapping between wells and integer sequence numbers of terms casted to floats + */ + public Map<WellLocation, Float> calculateWellTermsMapping( + Map<String, Integer> valueToSequanceMap) + { + Map<WellLocation, Float> wellTermsMapping = new HashMap<WellLocation, Float>(); + for (Entry<WellLocation, String> entry : valuesMap.entrySet()) + { + WellLocation wellLocation = entry.getKey(); + String value = entry.getValue(); + int sequenceNumber = valueToSequanceMap.get(value); + wellTermsMapping.put(wellLocation, (float) sequenceNumber); + } + return wellTermsMapping; + } + + public boolean isEmpty() + { + return valuesMap.isEmpty(); + } + + public void validate(Geometry plateGeometry) + { + for (WellLocation well : valuesMap.keySet()) + { + validate(well, plateGeometry); + } + } + + private static void validate(WellLocation wellPos, Geometry plateGeometry) + { + if (wellPos.getRow() > plateGeometry.getNumberOfRows() + || wellPos.getColumn() > plateGeometry.getNumberOfColumns()) + { + throw new IllegalStateException( + String.format( + "Feature value if defined for the well '%s' which is outside of the plate matrix '%s'", + wellPos, plateGeometry)); + } + } +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureVectorStorageProcessor.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureVectorStorageProcessor.java index a3d109a0bf6..ad920d80ebe 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureVectorStorageProcessor.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureVectorStorageProcessor.java @@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.dss.etl.featurevector; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Properties; @@ -33,6 +34,8 @@ import ch.systemsx.cisd.etlserver.DispatcherStorageProcessor.IDispatchableStorag import ch.systemsx.cisd.etlserver.ITypeExtractor; import ch.systemsx.cisd.openbis.dss.etl.HCSContainerDatasetInfo; import ch.systemsx.cisd.openbis.dss.etl.dataaccess.IImagingQueryDAO; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureDefinitionValues; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageDataSetInformation; import ch.systemsx.cisd.openbis.dss.etl.featurevector.CsvToCanonicalFeatureVector.CsvToCanonicalFeatureVectorConfiguration; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.DatasetFileLines; @@ -41,6 +44,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; import ch.systemsx.cisd.utils.CsvFileReaderHelper; @@ -101,17 +105,56 @@ public class FeatureVectorStorageProcessor extends AbstractDelegatingStorageProc throws IOException { HCSContainerDatasetInfo datasetInfo = createScreeningDatasetInfo(dataSetInformation); - DatasetFileLines fileLines = getDatasetFileLines(dataSet); - CsvToCanonicalFeatureVector convertor = - new CsvToCanonicalFeatureVector(fileLines, convertorConfig, - datasetInfo.getContainerRows(), datasetInfo.getContainerColumns()); - List<CanonicalFeatureVector> fvecs = convertor.convert(); + + List<CanonicalFeatureVector> fvecs = + extractCanonicalFeatureVectors(dataSet, dataSetInformation, + datasetInfo.getContainerGeometry()); dataAccessObject = createDAO(); FeatureVectorUploader uploader = new FeatureVectorUploader(dataAccessObject, datasetInfo); uploader.uploadFeatureVectors(fvecs); } + private List<CanonicalFeatureVector> extractCanonicalFeatureVectors(File dataSet, + DataSetInformation dataSetInformation, Geometry plateGeometry) throws IOException + { + if (dataSetInformation instanceof FeatureVectorDataSetInformation) + { + return extractCanonicalFeatureVectors( + (FeatureVectorDataSetInformation) dataSetInformation, plateGeometry); + } else + { + return extractCanonicalFeatureVectorsFromFile(dataSet, plateGeometry); + } + } + + private static List<CanonicalFeatureVector> extractCanonicalFeatureVectors( + FeatureVectorDataSetInformation dataSetInformation, Geometry plateGeometry) + { + List<FeatureDefinitionValues> featuresDefinitionValuesList = + dataSetInformation.getFeatures(); + + List<CanonicalFeatureVector> canonicalFeatureVectors = + new ArrayList<CanonicalFeatureVector>(); + for (FeatureDefinitionValues featureDefinitionValues : featuresDefinitionValuesList) + { + CanonicalFeatureVector canonicalFeatureVector = + featureDefinitionValues.getCanonicalFeatureVector(plateGeometry); + canonicalFeatureVectors.add(canonicalFeatureVector); + } + return canonicalFeatureVectors; + } + + private List<CanonicalFeatureVector> extractCanonicalFeatureVectorsFromFile(File dataSet, + Geometry plateGeometry) throws IOException + { + DatasetFileLines fileLines = getDatasetFileLines(dataSet); + CsvToCanonicalFeatureVector convertor = + new CsvToCanonicalFeatureVector(fileLines, convertorConfig, plateGeometry); + List<CanonicalFeatureVector> fvecs = convertor.convert(); + return fvecs; + } + private HCSContainerDatasetInfo createScreeningDatasetInfo(DataSetInformation dataSetInformation) { Sample sampleOrNull = tryFindSampleForDataSet(dataSetInformation); @@ -194,7 +237,10 @@ public class FeatureVectorStorageProcessor extends AbstractDelegatingStorageProc return CsvFileReaderHelper.getDatasetFileLines(file, configuration); } - /** Accepts all non-image datasets (and assumes they are single CSV files). */ + /** + * Accepts all non-image datasets (and assumes they are single CSV files or + * FeatureVectorDataSetInformation). + */ public boolean accepts(DataSetInformation dataSetInformation, File incomingDataSet) { return dataSetInformation instanceof ImageDataSetInformation == false; diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureVectorUploader.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureVectorUploader.java index 5d77e1cbf6e..b0caf06cff7 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureVectorUploader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/featurevector/FeatureVectorUploader.java @@ -118,14 +118,14 @@ public class FeatureVectorUploader void createFeatureVocabularyTerms() { List<ImgFeatureVocabularyTermDTO> terms = fvec.getVocabularyTerms(); - long featureDefId = fvec.getFeatureDef().getId(); - // The FK of the feature def are not yet valid. Patch them up. - for (ImgFeatureVocabularyTermDTO term : terms) - { - term.setFeatureDefId(featureDefId); - } - if (terms.size() > 0) + if (terms != null && terms.size() > 0) { + long featureDefId = fvec.getFeatureDef().getId(); + // The FK of the feature def are not yet valid. Patch them up. + for (ImgFeatureVocabularyTermDTO term : terms) + { + term.setFeatureDefId(featureDefId); + } dao.addFeatureVocabularyTerms(terms); } } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java index 765d3450d12..3f70572ad39 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/JythonPlateDataSetHandler.java @@ -10,19 +10,22 @@ import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationService; import ch.systemsx.cisd.etlserver.registrator.IDataSetRegistrationDetailsFactory; import ch.systemsx.cisd.etlserver.registrator.JythonTopLevelDataSetHandler; import ch.systemsx.cisd.etlserver.registrator.api.v1.IDataSet; -import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSet; import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSetRegistrationTransaction; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeatureVectorDataSetInformation; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.impl.FeaturesBuilder; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.BasicDataSetInformation; -import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.IFeaturesBuilder; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageDataSetInformation; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig; +import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; /** * Jython dropbox for HCS and Microscopy image datasets. * * @author Tomasz Pylak */ -public class JythonPlateDataSetHandler extends - JythonTopLevelDataSetHandler<ImageDataSetInformation> +public class JythonPlateDataSetHandler extends JythonTopLevelDataSetHandler<DataSetInformation> { public JythonPlateDataSetHandler(TopLevelDataSetRegistratorGlobalState globalState) { @@ -33,50 +36,97 @@ public class JythonPlateDataSetHandler extends * Create a screening specific factory available to the python script. */ @Override - protected IDataSetRegistrationDetailsFactory<ImageDataSetInformation> createObjectFactory( + protected IDataSetRegistrationDetailsFactory<DataSetInformation> createObjectFactory( PythonInterpreter interpreter) { return new JythonPlateDatasetFactory(getRegistratorState()); } - public static class JythonPlateDatasetFactory extends - JythonObjectFactory<ImageDataSetInformation> + public static class JythonPlateDatasetFactory extends JythonObjectFactory<DataSetInformation> { + private final IDataSetRegistrationDetailsFactory<ImageDataSetInformation> imageDatasetFactory; + + private final IDataSetRegistrationDetailsFactory<FeatureVectorDataSetInformation> featureVectorDatasetFactory; + public JythonPlateDatasetFactory(OmniscientTopLevelDataSetRegistratorState registratorState) { super(registratorState); + this.imageDatasetFactory = + new JythonObjectFactory<ImageDataSetInformation>(this.registratorState) + { + @Override + protected ImageDataSetInformation createDataSetInformation() + { + return new ImageDataSetInformation(); + } + }; + this.featureVectorDatasetFactory = + new JythonObjectFactory<FeatureVectorDataSetInformation>(this.registratorState) + { + @Override + protected FeatureVectorDataSetInformation createDataSetInformation() + { + return new FeatureVectorDataSetInformation(); + } + }; } + /** By default a starndard dataset is created. */ @Override - public DataSet<ImageDataSetInformation> createDataSet( - DataSetRegistrationDetails<ImageDataSetInformation> registrationDetails, - File stagingFile) + protected DataSetInformation createDataSetInformation() { - return new DataSet<ImageDataSetInformation>(registrationDetails, stagingFile); + return new DataSetInformation(); } - @Override - protected ImageDataSetInformation createDataSetInformation() + public DataSetRegistrationDetails<ImageDataSetInformation> createImageRegistrationDetails( + SimpleImageDataConfig imageDataSet, File incomingDatasetFolder) { - return new ImageDataSetInformation(); + return SimpleImageDataSetRegistrator.createImageDatasetDetails(imageDataSet, + incomingDatasetFolder, imageDatasetFactory); } - /** - * Factory method that creates a new registration details object for image datasets. - */ - public DataSetRegistrationDetails<ImageDataSetInformation> createImageRegistrationDetails() + /** a simple method to register the described image dataset in a separate transaction */ + public void registerImageDataset(SimpleImageDataConfig imageDataSet, + File incomingDatasetFolder, + DataSetRegistrationService<ImageDataSetInformation> service) { - DataSetRegistrationDetails<ImageDataSetInformation> registrationDetails = - new DataSetRegistrationDetails<ImageDataSetInformation>(); - ImageDataSetInformation dataSetInfo = new ImageDataSetInformation(); - setDatabaseInstance(dataSetInfo); - registrationDetails.setDataSetInformation(dataSetInfo); + DataSetRegistrationDetails<ImageDataSetInformation> imageDatasetDetails = + createImageRegistrationDetails(imageDataSet, incomingDatasetFolder); + DataSetRegistrationTransaction<ImageDataSetInformation> transaction = + service.transaction(incomingDatasetFolder, imageDatasetFactory); + IDataSet newDataset = transaction.createNewDataSet(imageDatasetDetails); + transaction.moveFile(incomingDatasetFolder.getPath(), newDataset); + transaction.commit(); + } + + // ---- + + public IFeaturesBuilder createFeaturesBuilder() + { + return new FeaturesBuilder(); + } + + public DataSetRegistrationDetails<FeatureVectorDataSetInformation> createFeatureVectorRegistrationDetails( + IFeaturesBuilder featureBuilder, File incomingDatasetFolder) + { + FeaturesBuilder myFeatureBuilder = (FeaturesBuilder) featureBuilder; + DataSetRegistrationDetails<FeatureVectorDataSetInformation> registrationDetails = + featureVectorDatasetFactory.createDataSetRegistrationDetails(); + FeatureVectorDataSetInformation featureVectorDataSet = + registrationDetails.getDataSetInformation(); + featureVectorDataSet.setFeatures(myFeatureBuilder.getFeatureDefinitionValuesList()); + registrationDetails + .setDataSetType(ScreeningConstants.DEFAULT_ANALYSIS_WELL_DATASET_TYPE); + registrationDetails.setMeasuredData(false); return registrationDetails; } /** * Factory method that creates a new registration details object for non-image datasets. + * + * @deprecated used only in Matt's dropbox to register analysis datasets. Will be removed. */ + @Deprecated public DataSetRegistrationDetails<BasicDataSetInformation> createBasicRegistrationDetails() { DataSetRegistrationDetails<BasicDataSetInformation> registrationDetails = @@ -86,30 +136,5 @@ public class JythonPlateDataSetHandler extends registrationDetails.setDataSetInformation(dataSetInfo); return registrationDetails; } - - public DataSetRegistrationDetails<ImageDataSetInformation> createImageRegistrationDetails( - SimpleImageDataConfig imageDataSet, File incomingDatasetFolder) - { - return SimpleImageDataSetRegistrator.createImageDatasetDetails(imageDataSet, - incomingDatasetFolder, this); - } - - /** a simple method to register the described image dataset */ - public void registerImageDataset(SimpleImageDataConfig imageDataSet, - File incomingDatasetFolder, - DataSetRegistrationService<ImageDataSetInformation> service) - { - DataSetRegistrationDetails<ImageDataSetInformation> imageDatasetDetails = - createImageRegistrationDetails(imageDataSet, incomingDatasetFolder); - IDataSetRegistrationDetailsFactory<ImageDataSetInformation> myself = this; - // TODO 2011-02-15, Tomasz Pylak: remove this casting - @SuppressWarnings("unchecked") - DataSetRegistrationTransaction<ImageDataSetInformation> transaction = - (DataSetRegistrationTransaction<ImageDataSetInformation>) service.transaction( - incomingDatasetFolder, myself); - IDataSet newDataset = transaction.createNewDataSet(imageDatasetDetails); - transaction.moveFile(incomingDatasetFolder.getPath(), newDataset); - transaction.commit(); - } } } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java index 365d4d1a5eb..14b7e70d7cd 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/jython/SimpleImageDataSetRegistrator.java @@ -25,13 +25,13 @@ import java.util.Set; import ch.systemsx.cisd.common.filesystem.FileOperations; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails; +import ch.systemsx.cisd.etlserver.registrator.IDataSetRegistrationDetailsFactory; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Channel; -import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageDataSetInformation; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageFileInfo; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.ImageMetadata; import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.Location; -import ch.systemsx.cisd.openbis.dss.etl.jython.JythonPlateDataSetHandler.JythonPlateDatasetFactory; +import ch.systemsx.cisd.openbis.dss.etl.dto.api.v1.SimpleImageDataConfig; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType; @@ -65,7 +65,8 @@ public class SimpleImageDataSetRegistrator } public static DataSetRegistrationDetails<ImageDataSetInformation> createImageDatasetDetails( - SimpleImageDataConfig imageDataSet, File incoming, JythonPlateDatasetFactory factory) + SimpleImageDataConfig imageDataSet, File incoming, + IDataSetRegistrationDetailsFactory<ImageDataSetInformation> factory) { return new SimpleImageDataSetRegistrator(imageDataSet).createImageDatasetDetails(incoming, factory); @@ -79,10 +80,11 @@ public class SimpleImageDataSetRegistrator } private DataSetRegistrationDetails<ImageDataSetInformation> createImageDatasetDetails( - File incoming, JythonPlateDatasetFactory factory) + File incoming, + IDataSetRegistrationDetailsFactory<ImageDataSetInformation> imageDatasetFactory) { DataSetRegistrationDetails<ImageDataSetInformation> registrationDetails = - factory.createImageRegistrationDetails(); + imageDatasetFactory.createDataSetRegistrationDetails(); ImageDataSetInformation imageDataset = registrationDetails.getDataSetInformation(); setImageDataset(incoming, imageDataset); setRegistrationDetails(registrationDetails, imageDataset); diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/registrator/api/v1/impl/ImageDataSet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/registrator/api/v1/impl/ImageDataSet.java index 6742975c87b..b83fb6d8393 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/registrator/api/v1/impl/ImageDataSet.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/etl/registrator/api/v1/impl/ImageDataSet.java @@ -28,7 +28,8 @@ import ch.systemsx.cisd.openbis.dss.etl.registrator.api.v1.IImageDataSet; * * @author Franz-Josef Elmer */ -// TODO 2011-02-02, Tomasz Pylak: We do not use it, is it really needed? For sure it's not complete. +// TODO 2011-02-02, Tomasz Pylak: make it complete and accessible through transactional framework. +// This is a stub now. public class ImageDataSet extends DataSet<ImageDataSetInformation> implements IImageDataSet { diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgFeatureValuesDTO.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgFeatureValuesDTO.java index a3c0800ab50..42c446be139 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgFeatureValuesDTO.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/imaging/dataaccess/ImgFeatureValuesDTO.java @@ -51,7 +51,7 @@ public class ImgFeatureValuesDTO extends AbstractHashable // All Data-Object classes must have a default constructor. } - public ImgFeatureValuesDTO(Double zInM, Double tInSec, PlateFeatureValues values, + public ImgFeatureValuesDTO(Double tInSec, Double zInM, PlateFeatureValues values, long featureDefId) { this.z = zInM; diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinitionValuesTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinitionValuesTest.java new file mode 100644 index 00000000000..06a68ba8f80 --- /dev/null +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/etl/dto/api/impl/FeatureDefinitionValuesTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2011 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.etl.dto.api.impl; + +import java.util.List; + +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.openbis.dss.etl.featurevector.CanonicalFeatureVector; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; +import ch.systemsx.cisd.openbis.plugin.screening.shared.dto.PlateFeatureValues; +import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureDefDTO; +import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureValuesDTO; +import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.dataaccess.ImgFeatureVocabularyTermDTO; + +/** + * Test of {@link FeatureDefinitionValues} + * + * @author Tomasz Pylak + */ +public class FeatureDefinitionValuesTest extends AssertJUnit +{ + @Test + public void test() + { + FeatureDefinitionValues def = new FeatureDefinitionValues(new ImgFeatureDefDTO()); + def.addValue("A1", "1.2"); + def.addValue("B2", "2.1"); + CanonicalFeatureVector vector = + def.getCanonicalFeatureVector(Geometry.createFromRowColDimensions(2, 2)); + assertNull(vector.getVocabularyTerms()); + assertEquals(1, vector.getValues().size()); + ImgFeatureValuesDTO featureValuesDTO = vector.getValues().get(0); + assertNull(featureValuesDTO.getT()); + assertNull(featureValuesDTO.getZ()); + PlateFeatureValues values = featureValuesDTO.getValues(); + assertEquals(1.2f, values.getForWellLocation(1, 1)); + assertEquals(2.1f, values.getForWellLocation(2, 2)); + assertTrue(Float.isNaN(values.getForWellLocation(2, 1))); + assertTrue(Float.isNaN(values.getForWellLocation(1, 2))); + } + + @Test + public void testTimepointsAndDepthScans() + { + FeatureDefinitionValues def = new FeatureDefinitionValues(new ImgFeatureDefDTO()); + def.setSeries(1.1, null); + def.addValue("A1", "1"); + def.setSeries(null, 2.2); + def.addValue("A1", "10"); + + CanonicalFeatureVector vector = + def.getCanonicalFeatureVector(Geometry.createFromRowColDimensions(1, 2)); + assertNull(vector.getVocabularyTerms()); + assertEquals(2, vector.getValues().size()); + + ImgFeatureValuesDTO featureValuesDTO = vector.getValues().get(0); + assertEquals(1.1d, featureValuesDTO.getT()); + assertNull(featureValuesDTO.getZ()); + PlateFeatureValues values = featureValuesDTO.getValues(); + assertEquals(1f, values.getForWellLocation(1, 1)); + assertTrue(Float.isNaN(values.getForWellLocation(1, 2))); + + featureValuesDTO = vector.getValues().get(1); + assertEquals(2.2d, featureValuesDTO.getZ()); + assertNull(featureValuesDTO.getT()); + values = featureValuesDTO.getValues(); + assertEquals(10f, values.getForWellLocation(1, 1)); + assertTrue(Float.isNaN(values.getForWellLocation(1, 2))); + } + + @Test + public void testVocabularyFeatures() + { + FeatureDefinitionValues def = new FeatureDefinitionValues(new ImgFeatureDefDTO()); + def.addValue("A1", "a"); + def.addValue("A2", "b"); + def.addValue("A3", "a"); + CanonicalFeatureVector vector = + def.getCanonicalFeatureVector(Geometry.createFromRowColDimensions(1, 3)); + List<ImgFeatureVocabularyTermDTO> terms = vector.getVocabularyTerms(); + assertNotNull(terms); + assertEquals(2, terms.size()); + assertEquals("a", terms.get(0).getCode()); + assertEquals("b", terms.get(1).getCode()); + + assertEquals(1, vector.getValues().size()); + ImgFeatureValuesDTO featureValuesDTO = vector.getValues().get(0); + assertNull(featureValuesDTO.getT()); + assertNull(featureValuesDTO.getZ()); + PlateFeatureValues values = featureValuesDTO.getValues(); + assertEquals(terms.get(0).getSequenceNumber(), (int) values.getForWellLocation(1, 1)); + assertEquals(terms.get(1).getSequenceNumber(), (int) values.getForWellLocation(1, 2)); + assertEquals(terms.get(0).getSequenceNumber(), (int) values.getForWellLocation(1, 3)); + } + +} \ No newline at end of file -- GitLab