From 25ba1a6289df35af77d509760e5855c7632fc66f Mon Sep 17 00:00:00 2001
From: tpylak <tpylak>
Date: Mon, 18 Jul 2011 22:02:34 +0000
Subject: [PATCH] LMS-2395 material summary bug, LMS-2355 preparation
 refactoring (which also improves performance)

SVN: 22191
---
 .../BasicWellContentQueryResult.java          |  19 +-
 .../server/dataaccess/IWellReference.java     |  31 +
 .../dataaccess/WellContentQueryResult.java    |  18 +-
 .../server/logic/AbstractContentLoader.java   |  21 +-
 .../ExperimentFeatureVectorSummaryLoader.java | 301 ++--------
 .../MaterialFeatureVectorSummaryLoader.java   | 125 ++--
 ...erialFeaturesFromAllExperimentsLoader.java | 228 +-------
 .../server/logic/WellDataLoader.java          | 541 ++++++++++++++++++
 .../logic/WellReplicaSummaryCalculator.java   |   4 +-
 .../server/logic/dto/IWellExtendedData.java   |  40 --
 .../screening/server/logic/dto/WellData.java  |  13 +-
 .../server/logic/dto/WellExtendedData.java    |  27 +-
 .../basic/dto/MaterialSummarySettings.java    |  10 +-
 .../server/dataaccess/ScreeningDAOTest.java   |   2 +-
 ...aterialFeatureVectorSummaryLoaderTest.java |  23 +-
 .../server/logic}/WellDataCollection.java     |   9 +-
 .../WellReplicaSummaryCalculatorTest.java     |   3 +-
 17 files changed, 785 insertions(+), 630 deletions(-)
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/IWellReference.java
 create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellDataLoader.java
 delete mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/IWellExtendedData.java
 rename screening/{source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto => sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic}/WellDataCollection.java (79%)

diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/BasicWellContentQueryResult.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/BasicWellContentQueryResult.java
index 76182c72cab..ade4dffa60b 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/BasicWellContentQueryResult.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/BasicWellContentQueryResult.java
@@ -17,6 +17,8 @@
 package ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess;
 
 import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellReference;
 
 /**
  * Basic information about well content which allows to compute rankings.
@@ -24,13 +26,24 @@ import ch.rinn.restrictions.Private;
  * @author Tomasz Pylak
  */
 @Private
-public class BasicWellContentQueryResult
+public class BasicWellContentQueryResult implements IWellReference
 {
-    public String well_code;
+    private String well_code;
 
-    public String plate_perm_id;
+    private String plate_perm_id;
 
     public String exp_perm_id;
 
     public long material_content_id;
+
+    public String getPlatePermId()
+    {
+        return plate_perm_id;
+    }
+
+    public WellReference getWellReference()
+    {
+        WellLocation wellLocation = WellLocation.parseLocationStr(well_code);
+        return new WellReference(wellLocation, plate_perm_id);
+    }
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/IWellReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/IWellReference.java
new file mode 100644
index 00000000000..eb46139a5bd
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/IWellReference.java
@@ -0,0 +1,31 @@
+/*
+ * 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.plugin.screening.server.dataaccess;
+
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellReference;
+
+/**
+ * Allows to reference a well.
+ * 
+ * @author Tomasz Pylak
+ */
+public interface IWellReference
+{
+    String getPlatePermId();
+
+    WellReference getWellReference();
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/WellContentQueryResult.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/WellContentQueryResult.java
index fa5a0c7713e..1d3d174b821 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/WellContentQueryResult.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/WellContentQueryResult.java
@@ -17,12 +17,15 @@
 package ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess;
 
 import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellReference;
 
 /**
  * @author Tomasz Pylak
  */
 @Private
-public class WellContentQueryResult extends ExperimentReferenceQueryResult
+public class WellContentQueryResult extends ExperimentReferenceQueryResult implements
+        IWellReference
 {
     // well pointer
 
@@ -42,7 +45,7 @@ public class WellContentQueryResult extends ExperimentReferenceQueryResult
 
     public String plate_type_code;
 
-    public String plate_perm_id;
+    private String plate_perm_id;
 
     // a pointer to a material which was being searched for inside a well
 
@@ -55,4 +58,15 @@ public class WellContentQueryResult extends ExperimentReferenceQueryResult
 
     @Deprecated
     public String material_content_type_code;
+
+    public String getPlatePermId()
+    {
+        return plate_perm_id;
+    }
+
+    public WellReference getWellReference()
+    {
+        WellLocation wellLocation = WellLocation.parseLocationStr(well_code);
+        return new WellReference(wellLocation, plate_perm_id);
+    }
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/AbstractContentLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/AbstractContentLoader.java
index 2e4debdcaa4..b30a9b41855 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/AbstractContentLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/AbstractContentLoader.java
@@ -21,6 +21,7 @@ import java.util.Set;
 
 import net.lemnik.eodsql.QueryTool;
 
+import org.apache.commons.lang.time.StopWatch;
 import org.apache.log4j.Logger;
 
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
@@ -54,6 +55,8 @@ abstract class AbstractContentLoader
 
     protected final IDAOFactory daoFactory;
 
+    private IScreeningQuery screeningDao = null;
+
     protected AbstractContentLoader(Session session,
             IScreeningBusinessObjectFactory businessObjectFactory, IDAOFactory daoFactory)
     {
@@ -62,10 +65,14 @@ abstract class AbstractContentLoader
         this.daoFactory = daoFactory;
     }
 
-    protected static IScreeningQuery createDAO(IDAOFactory daoFactory)
+    protected IScreeningQuery getScreeningDAO()
     {
-        Connection connection = DatabaseContextUtils.getConnection(daoFactory);
-        return QueryTool.getQuery(connection, IScreeningQuery.class);
+        if (screeningDao == null)
+        {
+            Connection connection = DatabaseContextUtils.getConnection(daoFactory);
+            screeningDao = QueryTool.getQuery(connection, IScreeningQuery.class);
+        }
+        return screeningDao;
     }
 
     protected final ExperimentReference loadExperimentByPermId(String experimentPermId)
@@ -106,4 +113,12 @@ abstract class AbstractContentLoader
         return new FeatureVectorDatasetLoader(session, businessObjectFactory, null, plates,
                 analysisProcedureCriteria);
     }
+
+    protected final StopWatch createWatchAndStart()
+    {
+        StopWatch watch = new StopWatch();
+        watch.start();
+        return watch;
+    }
+
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ExperimentFeatureVectorSummaryLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ExperimentFeatureVectorSummaryLoader.java
index 121438dbc59..cacf849b982 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ExperimentFeatureVectorSummaryLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ExperimentFeatureVectorSummaryLoader.java
@@ -16,13 +16,9 @@
 
 package ch.systemsx.cisd.openbis.plugin.screening.server.logic;
 
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 import ch.systemsx.cisd.common.collections.CollectionUtils;
@@ -30,32 +26,20 @@ import ch.systemsx.cisd.common.collections.CollectionUtils.ICollectionMappingFun
 import ch.systemsx.cisd.common.collections.IKeyExtractor;
 import ch.systemsx.cisd.common.collections.TableMap;
 import ch.systemsx.cisd.common.collections.TableMap.UniqueKeyViolationStrategy;
-import ch.systemsx.cisd.openbis.generic.server.business.bo.materiallister.IMaterialLister;
-import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CodeAndLabel;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListOrSearchSampleCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListMaterialCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellData;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellExtendedData;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.WellDataLoader.MaterialIdSummaryAndFeatures;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialIdFeatureVectorSummary;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellDataCollection;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellExtendedData;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ExperimentFeatureVectorSummary;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ExperimentReference;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.FeatureVectorValues;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialFeatureVectorSummary;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialSummarySettings;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellReference;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.AnalysisProcedureCriteria;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.FeatureVectorLoader.WellFeatureCollection;
 
 /**
  * {@See #loadExperimentFeatureVectors}.
@@ -64,20 +48,6 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.FeatureVectorLoa
  */
 public class ExperimentFeatureVectorSummaryLoader extends AbstractContentLoader
 {
-
-    static class LoaderParameters
-    {
-        TechId experimentId;
-
-        AnalysisProcedureCriteria analysisProcedureCriteria;
-
-        LoaderParameters(TechId experimentId, AnalysisProcedureCriteria analysisProcedureCriteria)
-        {
-            this.experimentId = experimentId;
-            this.analysisProcedureCriteria = analysisProcedureCriteria;
-        }
-    }
-
     /**
      * Loads feature vectors summaries for all the materials in the specified experiment.
      */
@@ -86,57 +56,55 @@ public class ExperimentFeatureVectorSummaryLoader extends AbstractContentLoader
             TechId experimentId, AnalysisProcedureCriteria analysisProcedureCriteria,
             MaterialSummarySettings settings)
     {
-        LoaderParameters params = new LoaderParameters(experimentId, analysisProcedureCriteria);
         return new ExperimentFeatureVectorSummaryLoader(session, businessObjectFactory, daoFactory,
-                settings).loadExperimentFeatureVectors(params);
+                settings).loadExperimentFeatureVectors(experimentId, analysisProcedureCriteria);
     }
 
     protected final MaterialSummarySettings settings;
 
+    private final WellDataLoader wellDataLoader;
+
     protected ExperimentFeatureVectorSummaryLoader(Session session,
             IScreeningBusinessObjectFactory businessObjectFactory, IDAOFactory daoFactory,
             MaterialSummarySettings settings)
     {
         super(session, businessObjectFactory, daoFactory);
         this.settings = settings;
+        this.wellDataLoader =
+                new WellDataLoader(session, businessObjectFactory, daoFactory, settings);
     }
 
-    private ExperimentFeatureVectorSummary loadExperimentFeatureVectors(LoaderParameters params)
+    private ExperimentFeatureVectorSummary loadExperimentFeatureVectors(TechId experimentId,
+            AnalysisProcedureCriteria analysisProcedureCriteria)
     {
-        WellDataCollection wellDataCollection = tryLoadWellData(params);
-        ExperimentReference experiment = loadExperimentByTechId(params.experimentId);
 
-        if (wellDataCollection == null)
+        MaterialIdSummaryAndFeatures summaries =
+                wellDataLoader.tryCalculateExperimentFeatureVectorSummaries(experimentId,
+                        settings.getReplicaMaterialTypeSubstrings(), analysisProcedureCriteria,
+                        false);
+        ExperimentReference experiment = loadExperimentByTechId(experimentId);
+        if (summaries == null)
         {
             return createEmptySummary(experiment);
         }
-        List<MaterialFeatureVectorSummary> featureSummaries =
-                calculateReplicasFeatureVectorSummaries(wellDataCollection);
-
-        return new ExperimentFeatureVectorSummary(experiment, featureSummaries,
-                wellDataCollection.getFeatureDescriptions());
-    }
-
-    private List<MaterialFeatureVectorSummary> calculateReplicasFeatureVectorSummaries(
-            WellDataCollection wellDataCollection)
-    {
-        List<? extends IWellData> wellDataList = wellDataCollection.getWellDataList();
-        List<MaterialIdFeatureVectorSummary> summaries =
-                calculateReplicasFeatureVectorSummaries(wellDataList);
-        return enrichWithMaterial(summaries, wellDataCollection);
+        List<MaterialFeatureVectorSummary> enrichedFeatureSummaries =
+                enrichWithMaterials(summaries.getFeatureSummaries());
+        return new ExperimentFeatureVectorSummary(experiment, enrichedFeatureSummaries,
+                summaries.getFeatureNames());
     }
 
-    private final List<MaterialIdFeatureVectorSummary> calculateReplicasFeatureVectorSummaries(
-            List<? extends IWellData> wellDataList)
+    private List<MaterialFeatureVectorSummary> enrichWithMaterials(
+            List<MaterialIdFeatureVectorSummary> summaries)
     {
-        return WellReplicaSummaryCalculator.calculateReplicasFeatureVectorSummaries(wellDataList,
-                settings.getAggregationType(), false);
+        Set<Long> materialIds = extractMaterialIds(summaries);
+        List<Material> materials = fetchMaterials(materialIds);
+        return enrichWithMaterials(summaries, materials);
     }
 
-    private static List<MaterialFeatureVectorSummary> enrichWithMaterial(
-            List<MaterialIdFeatureVectorSummary> summaries, WellDataCollection wellDataCollection)
+    private static List<MaterialFeatureVectorSummary> enrichWithMaterials(
+            List<MaterialIdFeatureVectorSummary> summaries, List<Material> materials)
     {
-        final TableMap<Long, Material> materialMap = createMaterialMap(wellDataCollection);
+        final TableMap<Long, Material> materialMap = createMaterialMap(materials);
         return CollectionUtils
                 .map(summaries,
                         new ICollectionMappingFunction<MaterialFeatureVectorSummary, MaterialIdFeatureVectorSummary>()
@@ -149,6 +117,22 @@ public class ExperimentFeatureVectorSummaryLoader extends AbstractContentLoader
                             });
     }
 
+    private List<Material> fetchMaterials(Set<Long> materialIds)
+    {
+        return businessObjectFactory.createMaterialLister(session).list(
+                new ListMaterialCriteria(materialIds), true);
+    }
+
+    private static Set<Long> extractMaterialIds(List<MaterialIdFeatureVectorSummary> summaries)
+    {
+        Set<Long> ids = new HashSet<Long>();
+        for (MaterialIdFeatureVectorSummary summary : summaries)
+        {
+            ids.add(summary.getMaterial());
+        }
+        return ids;
+    }
+
     private static MaterialFeatureVectorSummary convert(MaterialIdFeatureVectorSummary summary,
             TableMap<Long, Material> materialMap)
     {
@@ -157,58 +141,15 @@ public class ExperimentFeatureVectorSummaryLoader extends AbstractContentLoader
     }
 
     private static TableMap<Long/* material id */, Material> createMaterialMap(
-            WellDataCollection wellDataCollection)
+            List<Material> materials)
     {
-        List<Material> materials =
-                CollectionUtils.map(wellDataCollection.getWellDataList(),
-                        new ICollectionMappingFunction<Material, IWellExtendedData>()
-                            {
-                                public Material map(IWellExtendedData wellData)
-                                {
-                                    return wellData.getMaterial();
-                                }
-                            });
         return new TableMap<Long, Material>(materials, new IKeyExtractor<Long, Material>()
             {
                 public Long getKey(Material material)
                 {
                     return material.getId();
                 }
-            }, UniqueKeyViolationStrategy.KEEP_FIRST);
-    }
-
-    protected final WellDataCollection tryLoadWellData(LoaderParameters params)
-    {
-        ISampleLister sampleLister = businessObjectFactory.createSampleLister(session);
-        List<Sample> plates =
-                sampleLister.list(createExperientCriteria(params.experimentId.getId()));
-        List<Sample> wells = sampleLister.list(createWellsCriteria(plates));
-        if (wells.isEmpty())
-        {
-            return null; // no wells in this experiment
-        }
-        enrichWithMaterialProperties(wells);
-
-        Set<PlateIdentifier> plateIdentifiers = extractIdentifiers(plates);
-        WellFeatureCollection<FeatureVectorValues> featureVectorsCollection =
-                tryLoadWellSingleFeatureVectors(plateIdentifiers, params.analysisProcedureCriteria);
-        if (featureVectorsCollection == null)
-        {
-            return null; // no feature vector datasets connected to plates in this experiment
-        }
-
-        List<IWellExtendedData> wellDataList = asWellData(wells, featureVectorsCollection);
-        return new WellDataCollection(wellDataList,
-                featureVectorsCollection.getFeatureCodesAndLabels());
-    }
-
-    private WellFeatureCollection<FeatureVectorValues> tryLoadWellSingleFeatureVectors(
-            Set<PlateIdentifier> plateIdentifiers,
-            AnalysisProcedureCriteria analysisProcedureCriteria)
-    {
-        return new WellFeatureCollectionLoader(session, businessObjectFactory, daoFactory)
-                .tryLoadWellSingleFeatureVectors(plateIdentifiers, settings.getFeatureCodes(),
-                        analysisProcedureCriteria);
+            }, UniqueKeyViolationStrategy.ERROR);
     }
 
     private static ExperimentFeatureVectorSummary createEmptySummary(ExperimentReference experiment)
@@ -217,156 +158,4 @@ public class ExperimentFeatureVectorSummaryLoader extends AbstractContentLoader
         List<CodeAndLabel> featureDescriptions = Collections.emptyList();
         return new ExperimentFeatureVectorSummary(experiment, materialsSummary, featureDescriptions);
     }
-
-    private void enrichWithMaterialProperties(List<Sample> samples)
-    {
-        IMaterialLister materialLister = businessObjectFactory.createMaterialLister(session);
-        List<Material> containedMaterials = extractMaterialsWithDuplicates(samples);
-        materialLister.enrichWithProperties(containedMaterials);
-    }
-
-    private static List<Material> extractMaterialsWithDuplicates(List<Sample> samples)
-    {
-        List<Material> materials = new ArrayList<Material>();
-        for (Sample sample : samples)
-        {
-            materials.addAll(extractMaterials(sample));
-        }
-        return materials;
-    }
-
-    private static Collection<? extends Material> extractMaterials(Sample sample)
-    {
-        List<Material> materials = new ArrayList<Material>();
-        List<IEntityProperty> properties = sample.getProperties();
-        for (IEntityProperty property : properties)
-        {
-            Material material = property.getMaterial();
-            if (material != null)
-            {
-                materials.add(material);
-            }
-        }
-        return materials;
-    }
-
-    private List<IWellExtendedData> asWellData(List<Sample> wells,
-            WellFeatureCollection<FeatureVectorValues> featureVectorsCollection)
-    {
-        Map<WellReference, FeatureVectorValues> featureVectors =
-                createWellToFeatureVectorMap(featureVectorsCollection);
-        List<String> orderedFeatureLabels = featureVectorsCollection.getFeatureLabels();
-        List<IWellExtendedData> wellDataList = new ArrayList<IWellExtendedData>();
-        for (Sample well : wells)
-        {
-            IWellExtendedData wellData =
-                    tryCreateWellData(well, featureVectors, orderedFeatureLabels);
-            if (wellData != null)
-            {
-                wellDataList.add(wellData);
-            }
-        }
-        return wellDataList;
-    }
-
-    private IWellExtendedData tryCreateWellData(Sample well,
-            Map<WellReference, FeatureVectorValues> featureVectorsMap,
-            List<String> orderedFeatureLabels)
-    {
-        final float[] featureVectorNumbers =
-                tryExtractFeatureVectorValues(well, featureVectorsMap, orderedFeatureLabels);
-        if (featureVectorNumbers == null)
-        {
-            return null;
-        }
-        final Material replicaMaterial = tryFindReplicaMaterial(well, settings);
-        if (replicaMaterial == null)
-        {
-            return null;
-        }
-        return new WellExtendedData(replicaMaterial.getId(), featureVectorNumbers, well,
-                replicaMaterial);
-    }
-
-    private static Material tryFindReplicaMaterial(Sample well, MaterialSummarySettings settings)
-    {
-        String replicaMatrialTypePattern =
-                ScreeningUtils.asJavaRegExpr(settings.getReplicaMatrialTypeSubstrings());
-        if (replicaMatrialTypePattern == null)
-        {
-            return null;
-        }
-        for (Material material : extractMaterials(well))
-        {
-            if (material.getEntityType().getCode().matches(replicaMatrialTypePattern))
-            {
-                return material;
-            }
-        }
-        return null;
-    }
-
-    private static float[] tryExtractFeatureVectorValues(Sample well,
-            Map<WellReference, FeatureVectorValues> featureVectorsMap,
-            List<String> orderedFeatureLabels)
-    {
-        WellReference wellReference = asWellReference(well);
-        FeatureVectorValues featureVector = featureVectorsMap.get(wellReference);
-        if (featureVector == null)
-        {
-            return null;
-        }
-        return WellFeatureCollectionLoader.asFeatureVectorValues(featureVector);
-    }
-
-    private static WellReference asWellReference(Sample well)
-    {
-        WellLocation location =
-                ScreeningUtils.tryCreateLocationFromMatrixCoordinate(well.getSubCode());
-        WellReference wellReference = new WellReference(location, well.getContainer().getPermId());
-        return wellReference;
-    }
-
-    private static Set<PlateIdentifier> extractIdentifiers(List<Sample> plates)
-    {
-        Set<PlateIdentifier> idents = new HashSet<PlateIdentifier>();
-        for (Sample plate : plates)
-        {
-            idents.add(PlateIdentifier.createFromPermId(plate.getPermId()));
-        }
-        return idents;
-    }
-
-    private static ListOrSearchSampleCriteria createWellsCriteria(List<Sample> plates)
-    {
-        Collection<Long> plateIds = new ArrayList<Long>();
-        for (Sample plate : plates)
-        {
-            plateIds.add(plate.getId());
-        }
-        ListOrSearchSampleCriteria criteria =
-                new ListOrSearchSampleCriteria(
-                        ListOrSearchSampleCriteria.createForContainers(plateIds));
-        return criteria;
-    }
-
-    private static ListOrSearchSampleCriteria createExperientCriteria(long expId)
-    {
-        return new ListOrSearchSampleCriteria(
-                ListOrSearchSampleCriteria.createForExperiment(new TechId(expId)));
-    }
-
-    private static Map<WellReference, FeatureVectorValues> createWellToFeatureVectorMap(
-            WellFeatureCollection<FeatureVectorValues> featureVectors)
-    {
-        Map<WellReference, FeatureVectorValues> wellToFeatureVectorMap =
-                new HashMap<WellReference, FeatureVectorValues>();
-        for (FeatureVectorValues featureValues : featureVectors.getFeatures())
-        {
-            WellReference wellReference = featureValues.getWellReference();
-            wellToFeatureVectorMap.put(wellReference, featureValues);
-        }
-        return wellToFeatureVectorMap;
-    }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoader.java
index 75b8031116b..f3d20c0efe6 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoader.java
@@ -29,21 +29,21 @@ import ch.systemsx.cisd.common.collections.IKeyExtractor;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CodeAndLabel;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityPropertiesHolder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellData;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellExtendedData;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.WellDataLoader.MaterialIdSummaryAndFeatures;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialAllReplicasFeatureVectors;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialBiologicalReplicateFeatureVector;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialIdFeatureVectorSummary;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialTechnicalReplicateFeatureVector;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellDataCollection;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellExtendedData;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialBiologicalReplicateFeatureSummary;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialReplicaFeatureSummary;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialReplicaFeatureSummaryResult;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialReplicaSummaryAggregationType;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialSummarySettings;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.AnalysisProcedureCriteria;
 
 /**
  * For the specified material in the specified experiment loads feature vectors (details and
@@ -52,7 +52,7 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialSummar
  * 
  * @author Tomasz Pylak
  */
-public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorSummaryLoader
+public class MaterialFeatureVectorSummaryLoader extends AbstractContentLoader
 {
     /**
      * For comments {@See MaterialFeatureVectorSummaryLoader}.
@@ -165,40 +165,56 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
 
     // ----------------------
 
+    private final MaterialSummarySettings settings;
+
+    private final WellDataLoader wellDataLoader;
+
     @Private
     MaterialFeatureVectorSummaryLoader(Session session,
             IScreeningBusinessObjectFactory businessObjectFactory, IDAOFactory daoFactory,
             MaterialSummarySettings settings)
     {
-        super(session, businessObjectFactory, daoFactory, settings);
+        super(session, businessObjectFactory, daoFactory);
+        this.settings = settings;
+        this.wellDataLoader =
+                new WellDataLoader(session, businessObjectFactory, daoFactory, settings);
+
     }
 
     private MaterialAllReplicasFeatureVectors tryLoadMaterialFeatureVectors(TechId materialId,
             TechId experimentId)
     {
-        // TODO KE: 2011-07-15 this should also be changed
-        LoaderParameters params = new LoaderParameters(experimentId, null);
-        WellDataCollection experimentWells = tryLoadWellData(params);
-        if (experimentWells == null)
+        // TODO KE: 2011-07-15 specify analysis procedure
+        AnalysisProcedureCriteria analysisProcedureCriteria =
+                AnalysisProcedureCriteria.createAllProcedures();
+        MaterialIdSummaryAndFeatures summaries =
+                wellDataLoader.tryCalculateExperimentFeatureVectorSummaries(experimentId,
+                        analysisProcedureCriteria, materialId, true);
+        if (summaries == null)
         {
             return null;
         }
-        return tryLoadMaterialFeatureVectors(materialId, experimentWells);
-    }
-
-    @Private
-    MaterialAllReplicasFeatureVectors tryLoadMaterialFeatureVectors(TechId materialId,
-            WellDataCollection experimentWells)
-    {
-        List<IWellExtendedData> experimentWellsData = experimentWells.getWellDataList();
         MaterialIdFeatureVectorSummary materialGeneralSummary =
-                tryCalculateMaterialSummary(materialId, experimentWellsData);
+                tryFindMaterialSummary(materialId, summaries.getFeatureSummaries());
         if (materialGeneralSummary == null)
         {
             return null;
         }
-        List<IWellExtendedData> materialWellsData =
-                filterWellsByMaterial(experimentWellsData, materialId);
+        List<WellExtendedData> materialWellsData =
+                wellDataLoader.tryLoadWellData(materialId, experimentId, analysisProcedureCriteria);
+        if (materialWellsData == null)
+        {
+            return null;
+        }
+        return createMaterialFeatureVectors(materialId, materialWellsData, materialGeneralSummary,
+                summaries.getFeatureNames());
+    }
+
+    @Private
+    MaterialAllReplicasFeatureVectors createMaterialFeatureVectors(TechId materialId,
+            List<WellExtendedData> materialWellsData,
+            MaterialIdFeatureVectorSummary materialGeneralSummary, List<CodeAndLabel> featureNames)
+    {
         ReplicateSequenceProvider replicaSequences =
                 new ReplicateSequenceProvider(materialWellsData,
                         settings.getBiologicalReplicatePropertyTypeCodes());
@@ -208,14 +224,14 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
         List<MaterialTechnicalReplicateFeatureVector> replicas =
                 filterDirectTechnicalReplicas(materialWellsData, replicaSequences);
 
-        return new MaterialAllReplicasFeatureVectors(experimentWells.getFeatureDescriptions(),
-                materialGeneralSummary, subgroups, replicas);
+        return new MaterialAllReplicasFeatureVectors(featureNames, materialGeneralSummary,
+                subgroups, replicas);
     }
 
     private List<MaterialBiologicalReplicateFeatureVector> createBiologicalReplicates(
-            List<IWellExtendedData> materialWells, ReplicateSequenceProvider replicaSequences)
+            List<WellExtendedData> materialWells, ReplicateSequenceProvider replicaSequences)
     {
-        GroupByMap<Integer, IWellExtendedData> biologicalReplicateMap =
+        GroupByMap<Integer, WellExtendedData> biologicalReplicateMap =
                 groupByBiologicalReplicate(materialWells, replicaSequences);
 
         List<MaterialBiologicalReplicateFeatureVector> subgroups =
@@ -223,7 +239,7 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
         MaterialReplicaSummaryAggregationType aggregationType = settings.getAggregationType();
         for (Integer biologicalReplicateSeq : replicaSequences.getBiologicalReplicateSequences())
         {
-            List<IWellExtendedData> technicalReplicateWells =
+            List<WellExtendedData> technicalReplicateWells =
                     biologicalReplicateMap.getOrDie(biologicalReplicateSeq);
             MaterialBiologicalReplicateFeatureVector subgroup =
                     createBiologicalReplicate(technicalReplicateWells, replicaSequences,
@@ -234,7 +250,7 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
     }
 
     private MaterialBiologicalReplicateFeatureVector createBiologicalReplicate(
-            List<IWellExtendedData> technicalReplicateWells,
+            List<WellExtendedData> technicalReplicateWells,
             ReplicateSequenceProvider replicaSequences,
             MaterialReplicaSummaryAggregationType aggregationType)
     {
@@ -248,37 +264,28 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
                 aggregationType, subgroupLabel);
     }
 
-    private String getSubgroupLabel(List<IWellExtendedData> subgroupWellDataList,
+    private String getSubgroupLabel(List<WellExtendedData> subgroupWellDataList,
             ReplicateSequenceProvider replicaSequences)
     {
         assert subgroupWellDataList.size() > 0 : "empty subgroup";
         // all wells belong to the same subgroup, so it does not matter which one we take
-        Sample well = subgroupWellDataList.get(0).getWell();
+        IEntityPropertiesHolder well = subgroupWellDataList.get(0);
 
         String label = replicaSequences.tryGetBiologicalReplicateLabel(well);
         assert label != null : "no biological replicates!";
         return label;
     }
 
-    private MaterialIdFeatureVectorSummary tryCalculateMaterialSummary(TechId materialId,
-            List<? extends IWellData> experimentWellDataList)
-    {
-        List<MaterialIdFeatureVectorSummary> featureSummaries =
-                WellReplicaSummaryCalculator.calculateReplicasFeatureVectorSummaries(
-                        experimentWellDataList, settings.getAggregationType(), true);
-        return tryFindMaterialSummary(materialId, featureSummaries);
-    }
-
     // chooses wells which have no information about which biological replicate they are
     private static List<MaterialTechnicalReplicateFeatureVector> filterDirectTechnicalReplicas(
-            List<IWellExtendedData> materialWellDataList,
+            List<WellExtendedData> materialWellDataList,
             final ReplicateSequenceProvider replicaSequences)
     {
-        List<IWellExtendedData> directTechnicalReplicas =
+        List<WellExtendedData> directTechnicalReplicas =
                 CollectionUtils.filter(materialWellDataList,
-                        new ICollectionFilter<IWellExtendedData>()
+                        new ICollectionFilter<WellExtendedData>()
                             {
-                                public boolean isPresent(IWellExtendedData element)
+                                public boolean isPresent(WellExtendedData element)
                                 {
                                     return replicaSequences.isBiologicalReplicate(element) == false;
                                 }
@@ -288,11 +295,11 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
     }
 
     private static List<MaterialTechnicalReplicateFeatureVector> createTechnicalReplicates(
-            List<IWellExtendedData> wells, final ReplicateSequenceProvider replicaSequences)
+            List<WellExtendedData> wells, final ReplicateSequenceProvider replicaSequences)
     {
         List<MaterialTechnicalReplicateFeatureVector> replicas =
                 new ArrayList<MaterialTechnicalReplicateFeatureVector>();
-        for (IWellExtendedData wellData : wells)
+        for (WellExtendedData wellData : wells)
         {
             int replicaSequenceNumber = replicaSequences.getTechnicalReplicateSequence(wellData);
             MaterialTechnicalReplicateFeatureVector featureVector =
@@ -304,12 +311,12 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
     }
 
     private static void sortByTechnicalReplicateSequence(
-            List<IWellExtendedData> materialWellDataList,
+            List<WellExtendedData> materialWellDataList,
             final ReplicateSequenceProvider replicaSequences)
     {
-        Collections.sort(materialWellDataList, new Comparator<IWellExtendedData>()
+        Collections.sort(materialWellDataList, new Comparator<WellExtendedData>()
             {
-                public int compare(IWellExtendedData w1, IWellExtendedData w2)
+                public int compare(WellExtendedData w1, WellExtendedData w2)
                 {
                     Integer replicaSequenceNumber1 =
                             replicaSequences.getTechnicalReplicateSequence(w1);
@@ -320,33 +327,19 @@ public class MaterialFeatureVectorSummaryLoader extends ExperimentFeatureVectorS
             });
     }
 
-    private static List<IWellExtendedData> filterWellsByMaterial(
-            List<IWellExtendedData> wellDataList, final TechId materialTechId)
-    {
-        final Long materialId = materialTechId.getId();
-        return CollectionUtils.filter(wellDataList, new ICollectionFilter<IWellExtendedData>()
-            {
-                public boolean isPresent(IWellExtendedData element)
-                {
-                    return materialId.equals(element.getReplicaMaterialId());
-                }
-            });
-    }
-
     /**
      * A subgroup can be e.g. oligo or compound concentration.
      */
-    private GroupByMap<Integer, IWellExtendedData> groupByBiologicalReplicate(
-            List<IWellExtendedData> materialWellDataList,
+    private GroupByMap<Integer, WellExtendedData> groupByBiologicalReplicate(
+            List<WellExtendedData> materialWellDataList,
             final ReplicateSequenceProvider replicaSequences)
     {
         return GroupByMap.create(materialWellDataList,
-                new IKeyExtractor<Integer, IWellExtendedData>()
+                new IKeyExtractor<Integer, WellExtendedData>()
                     {
-                        public Integer getKey(IWellExtendedData wellData)
+                        public Integer getKey(WellExtendedData wellData)
                         {
-                            return replicaSequences.tryGetBiologicalReplicateSequence(wellData
-                                    .getWell());
+                            return replicaSequences.tryGetBiologicalReplicateSequence(wellData);
                         }
                     });
     }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeaturesFromAllExperimentsLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeaturesFromAllExperimentsLoader.java
index 2e72507c65d..71b827dc71a 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeaturesFromAllExperimentsLoader.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeaturesFromAllExperimentsLoader.java
@@ -18,11 +18,7 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 import org.apache.commons.lang.time.StopWatch;
 
@@ -34,21 +30,11 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory;
-import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.BasicWellContentQueryResult;
 import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.ExperimentReferenceQueryResult;
 import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.IScreeningQuery;
-import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.PatternMatchingUtils;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellData;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialIdFeatureVectorSummary;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellData;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ExperimentReference;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.FeatureVectorValues;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialSimpleFeatureVectorSummary;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialSummarySettings;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellReference;
-import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.FeatureVectorLoader.WellFeatureCollection;
 
 /**
  * Finds all experiments where the given material is present and calculates summaries for feature
@@ -65,18 +51,17 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa
             IDAOFactory daoFactory, TechId materialId, TechId projectTechIdOrNull,
             MaterialSummarySettings settings)
     {
-        IScreeningQuery dao = createDAO(daoFactory);
+        MaterialFeaturesFromAllExperimentsLoader loader =
+                new MaterialFeaturesFromAllExperimentsLoader(session, businessObjectFactory,
+                        daoFactory, settings);
         List<ExperimentReference> experiments =
-                fetchExperiments(materialId, projectTechIdOrNull, dao);
-
-        return new MaterialFeaturesFromAllExperimentsLoader(session, businessObjectFactory,
-                daoFactory, dao, settings).loadMaterialFeatureVectorsFromAllAssays(materialId,
-                experiments);
+                loader.fetchExperiments(materialId, projectTechIdOrNull);
+        return loader.loadMaterialFeatureVectorsFromAllAssays(materialId, experiments);
     }
 
-    private static List<ExperimentReference> fetchExperiments(TechId materialId,
-            TechId projectTechIdOrNull, IScreeningQuery dao)
+    private List<ExperimentReference> fetchExperiments(TechId materialId, TechId projectTechIdOrNull)
     {
+        IScreeningQuery dao = getScreeningDAO();
         List<ExperimentReferenceQueryResult> experimentRefs;
         if (projectTechIdOrNull == null)
         {
@@ -111,42 +96,15 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa
                 exp.exp_type_code, exp.proj_code, exp.space_code);
     }
 
-    private final MaterialSummarySettings settings;
-
-    private final IScreeningQuery screeningQuery;
+    private final WellDataLoader wellDataLoader;
 
     private MaterialFeaturesFromAllExperimentsLoader(Session session,
             IScreeningBusinessObjectFactory businessObjectFactory, IDAOFactory daoFactory,
-            IScreeningQuery screeningQuery, MaterialSummarySettings settings)
+            MaterialSummarySettings settings)
     {
         super(session, businessObjectFactory, daoFactory);
-        this.settings = settings;
-        this.screeningQuery = screeningQuery;
-    }
-
-    private List<BasicWellContentQueryResult> fetchWellLocations(
-            List<ExperimentReference> experiments)
-    {
-        StopWatch watch = createWatchAndStart();
-        String materialTypePattern =
-                PatternMatchingUtils.asPostgresSimilarExpression(settings
-                        .getReplicaMatrialTypeSubstrings());
-        List<BasicWellContentQueryResult> wells =
-                screeningQuery.getPlateLocationsForExperiment(extractIds(experiments),
-                        materialTypePattern);
-        operationLog.info("[" + watch.getTime() + " msec] Fetching " + wells.size() + " wells.");
-        return wells;
-    }
-
-    private static long[] extractIds(List<ExperimentReference> experiments)
-    {
-        long[] ids = new long[experiments.size()];
-        int i = 0;
-        for (ExperimentReference experiment : experiments)
-        {
-            ids[i++] = experiment.getId();
-        }
-        return ids;
+        this.wellDataLoader =
+                new WellDataLoader(session, businessObjectFactory, daoFactory, settings);
     }
 
     /**
@@ -182,7 +140,8 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa
                 operationLog.info(String.format("Processing %d experiments with %d datasets: %s",
                         experimentsBatch.size(), datasetsInBatch, experimentsBatch));
                 List<MaterialSimpleFeatureVectorSummary> batchSummaries =
-                        loadMaterialFeatureVectorsFromAllAssaysBatch(materialId, experimentsBatch);
+                        wellDataLoader.loadMaterialFeatureVectorsFromAllAssaysBatch(materialId,
+                                experimentsBatch);
                 summaries.addAll(batchSummaries);
                 experimentsBatch.clear();
                 datasetsInBatch = 0;
@@ -194,54 +153,6 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa
         return summaries;
     }
 
-    // load all experiments in a constant number of selects
-    private List<MaterialSimpleFeatureVectorSummary> loadMaterialFeatureVectorsFromAllAssaysBatch(
-            TechId materialId, List<ExperimentReference> experiments)
-    {
-        List<MaterialSimpleFeatureVectorSummary> summaries =
-                new ArrayList<MaterialSimpleFeatureVectorSummary>();
-        StopWatch watch = createWatchAndStart();
-        int totalWellsLoaded = 0;
-        int totalFeatureVectorsLoaded = 0;
-
-        List<BasicWellContentQueryResult> allWells = fetchWellLocations(experiments);
-        totalWellsLoaded += allWells.size();
-        Set<PlateIdentifier> plates = extractPlates(allWells);
-        WellFeatureCollection<FeatureVectorValues> allWellFeaturesOrNull =
-                tryLoadWellSingleFeatureVectors(plates);
-
-        if (allWellFeaturesOrNull == null)
-        {
-            addEmptySummaries(summaries, experiments);
-        } else
-        {
-            for (ExperimentReference experiment : experiments)
-            {
-                totalFeatureVectorsLoaded += allWellFeaturesOrNull.getFeatures().size();
-                Map<WellReference, Long/* material id */> wellToMaterialMap =
-                        createWellToMaterialMapForExperiment(allWells, experiment);
-
-                MaterialSimpleFeatureVectorSummary summary =
-                        calculateExperimentFeatureVectorSummary(materialId, experiment,
-                                allWellFeaturesOrNull, wellToMaterialMap);
-                summaries.add(summary);
-            }
-        }
-        operationLog.info(String.format(
-                "[%d msec] Experiments batch: %d, wells loaded: %d, feature vectors: %d.",
-                watch.getTime(), experiments.size(), totalWellsLoaded, totalFeatureVectorsLoaded));
-        return summaries;
-    }
-
-    private void addEmptySummaries(List<MaterialSimpleFeatureVectorSummary> summaries,
-            List<ExperimentReference> experiments)
-    {
-        for (ExperimentReference experiment : experiments)
-        {
-            summaries.add(new MaterialSimpleFeatureVectorSummary(experiment));
-        }
-    }
-
     private int countAnalysisDatasets(ExperimentReference experiment)
     {
         List<TechId> experiments = Arrays.asList(new TechId(experiment.getId()));
@@ -250,117 +161,4 @@ public class MaterialFeaturesFromAllExperimentsLoader extends AbstractContentLoa
         return ScreeningUtils.filterImageAnalysisDatasets(datasets).size();
     }
 
-    private StopWatch createWatchAndStart()
-    {
-        StopWatch watch = new StopWatch();
-        watch.start();
-        return watch;
-    }
-
-    private static Map<WellReference, Long/* material id */> createWellToMaterialMapForExperiment(
-            List<BasicWellContentQueryResult> wells, ExperimentReference experiment)
-    {
-        Map<WellReference, Long> wellToMaterialMap = new HashMap<WellReference, Long>();
-        for (BasicWellContentQueryResult well : wells)
-        {
-            if (belongsToExperiment(well, experiment))
-            {
-                WellReference wellReference = createWellReference(well);
-                wellToMaterialMap.put(wellReference, well.material_content_id);
-            }
-        }
-        return wellToMaterialMap;
-    }
-
-    private static boolean belongsToExperiment(BasicWellContentQueryResult well,
-            ExperimentReference experiment)
-    {
-        return well.exp_perm_id.equals(experiment.getPermId());
-    }
-
-    private static WellReference createWellReference(BasicWellContentQueryResult well)
-    {
-        WellLocation wellLocation = WellLocation.parseLocationStr(well.well_code);
-        return new WellReference(wellLocation, well.plate_perm_id);
-    }
-
-    /**
-     * @param experimentWellToMaterialMap wells belonging to the specified experiment
-     * @param allFeatures all features, not only for the specified experiment but possibly also for
-     *            few others
-     */
-    private MaterialSimpleFeatureVectorSummary calculateExperimentFeatureVectorSummary(
-            TechId materialId, ExperimentReference experiment,
-            WellFeatureCollection<FeatureVectorValues> allFeatures,
-            Map<WellReference, Long> experimentWellToMaterialMap)
-    {
-        // we have to calculate summaries for all materials in the experiment to get the right
-        // ranking of the specified material
-        List<IWellData> experimentWellData =
-                createWellData(experimentWellToMaterialMap, allFeatures.getFeatures());
-        List<MaterialIdFeatureVectorSummary> experimentSummaries =
-                WellReplicaSummaryCalculator.calculateReplicasFeatureVectorSummaries(
-                        experimentWellData, settings.getAggregationType(), false);
-
-        // select the summary of the right material
-        MaterialIdFeatureVectorSummary materialSummary =
-                findMaterialSummary(materialId, experimentSummaries);
-        return new MaterialSimpleFeatureVectorSummary(experiment,
-                allFeatures.getFeatureCodesAndLabels(), materialSummary.getFeatureVectorSummary(),
-                materialSummary.getFeatureVectorRanks());
-    }
-
-    private MaterialIdFeatureVectorSummary findMaterialSummary(TechId materialId,
-            List<MaterialIdFeatureVectorSummary> summaries)
-    {
-        for (MaterialIdFeatureVectorSummary summary : summaries)
-        {
-            if (summary.getMaterial().equals(materialId.getId()))
-            {
-                return summary;
-            }
-        }
-        throw new IllegalStateException("It should not happen: no summary found for material "
-                + materialId);
-    }
-
-    // connects each well with a material with its feature vector
-    private static List<IWellData> createWellData(
-            Map<WellReference, Long/* material id */> experimentWellToMaterialMap,
-            List<FeatureVectorValues> allFeatures)
-    {
-        List<IWellData> experimentWellDataList = new ArrayList<IWellData>();
-        for (FeatureVectorValues feature : allFeatures)
-        {
-            Long materialId = experimentWellToMaterialMap.get(feature.getWellReference());
-            if (materialId != null)
-            {
-                float[] values = WellFeatureCollectionLoader.asFeatureVectorValues(feature);
-                IWellData wellData = new WellData(materialId, values);
-                experimentWellDataList.add(wellData);
-            }
-        }
-        return experimentWellDataList;
-    }
-
-    private static Set<PlateIdentifier> extractPlates(List<BasicWellContentQueryResult> allWells)
-    {
-        Set<PlateIdentifier> plates = new HashSet<PlateIdentifier>();
-        for (BasicWellContentQueryResult well : allWells)
-        {
-            String platePermId = well.plate_perm_id;
-            PlateIdentifier plateIdent = PlateIdentifier.createFromPermId(platePermId);
-            plates.add(plateIdent);
-        }
-        return plates;
-    }
-
-    private WellFeatureCollection<FeatureVectorValues> tryLoadWellSingleFeatureVectors(
-            Set<PlateIdentifier> plateIdentifiers)
-    {
-        // TODO KE: 2011-07-15 specify analysis procedure here ?
-        return new WellFeatureCollectionLoader(session, businessObjectFactory, daoFactory)
-                .tryLoadWellSingleFeatureVectors(plateIdentifiers, settings.getFeatureCodes(), null);
-    }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellDataLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellDataLoader.java
new file mode 100644
index 00000000000..24c755ace32
--- /dev/null
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellDataLoader.java
@@ -0,0 +1,541 @@
+/*
+ * 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.plugin.screening.server.logic;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.lemnik.eodsql.DataIterator;
+
+import org.apache.commons.lang.time.StopWatch;
+
+import ch.systemsx.cisd.common.collections.CollectionUtils;
+import ch.systemsx.cisd.common.collections.CollectionUtils.ICollectionFilter;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IMaterialBO;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.materiallister.IMaterialLister;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CodeAndLabel;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListOrSearchSampleCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.BasicWellContentQueryResult;
+import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.IWellReference;
+import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.PatternMatchingUtils;
+import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.WellContentQueryResult;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellData;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialIdFeatureVectorSummary;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellData;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellExtendedData;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ExperimentReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.FeatureVectorValues;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialSimpleFeatureVectorSummary;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialSummarySettings;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellReference;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellSearchCriteria.AnalysisProcedureCriteria;
+import ch.systemsx.cisd.openbis.plugin.screening.shared.imaging.FeatureVectorLoader.WellFeatureCollection;
+
+/**
+ * Loads well's feature vectors and materials and calculates summaries.
+ * 
+ * @author Tomasz Pylak
+ */
+class WellDataLoader extends AbstractContentLoader
+{
+    private final MaterialSummarySettings settings;
+
+    public WellDataLoader(Session session, IScreeningBusinessObjectFactory businessObjectFactory,
+            IDAOFactory daoFactory, MaterialSummarySettings settings)
+    {
+        super(session, businessObjectFactory, daoFactory);
+        this.settings = settings;
+    }
+
+    /**
+     * Loads feature vectors of each well with the specified material in the specified experiment.
+     */
+    public List<WellExtendedData> tryLoadWellData(TechId materialId, TechId experimentId,
+            AnalysisProcedureCriteria analysisProcedureCriteria)
+    {
+        List<WellContentQueryResult> wells =
+                getPlateLocationsForMaterialId(materialId, experimentId);
+        List<WellData> wellsData =
+                tryCreateWellDataForMaterial(wells, materialId, analysisProcedureCriteria);
+        if (wellsData == null)
+        {
+            return null;
+        }
+        Map<WellReference, Sample> wellRefToSampleMap = loadEnrichedWellSamples(wells);
+        return createWellExtendedData(wellsData, wellRefToSampleMap);
+    }
+
+    private List<WellContentQueryResult> getPlateLocationsForMaterialId(TechId materialId,
+            TechId experimentId)
+    {
+        DataIterator<WellContentQueryResult> wellsIterator =
+                getScreeningDAO().getPlateLocationsForMaterialId(materialId.getId(),
+                        experimentId.getId());
+
+        List<WellContentQueryResult> wells = new ArrayList<WellContentQueryResult>();
+        for (WellContentQueryResult well : wellsIterator)
+        {
+            wells.add(well);
+        }
+        return wells;
+    }
+
+    private Map<WellReference, Sample> loadEnrichedWellSamples(
+            Iterable<WellContentQueryResult> wells)
+    {
+        Set<Long> wellIds = extractWellIds(wells);
+        List<Sample> wellSamples = loadSamplesWithMaterialPropertiesEnriched(wellIds);
+        return asWellRefToSampleMap(wellSamples, wells);
+    }
+
+    private List<WellData> tryCreateWellDataForMaterial(Iterable<WellContentQueryResult> wells,
+            TechId materialId, AnalysisProcedureCriteria analysisProcedureCriteria)
+    {
+        WellFeatureCollection<FeatureVectorValues> allWellFeatures =
+                tryLoadWellSingleFeatureVectors(wells, analysisProcedureCriteria);
+        if (allWellFeatures == null)
+        {
+            return null;
+        }
+        List<FeatureVectorValues> features = allWellFeatures.getFeatures();
+        Map<WellReference, Long> dummyMaterialMap = createDummyMaterialMap(wells, materialId);
+        return createWellData(dummyMaterialMap, features);
+    }
+
+    private Map<WellReference, Long/* material id */> createDummyMaterialMap(
+            Iterable<WellContentQueryResult> wells, TechId materialId)
+    {
+        Map<WellReference, Long> experimentWellToMaterialMap = new HashMap<WellReference, Long>();
+        for (WellContentQueryResult well : wells)
+        {
+            WellReference wellReference = well.getWellReference();
+            experimentWellToMaterialMap.put(wellReference, materialId.getId());
+        }
+        return experimentWellToMaterialMap;
+    }
+
+    private static Map<WellReference, Sample> asWellRefToSampleMap(List<Sample> wellSamples,
+            Iterable<WellContentQueryResult> wells)
+    {
+        Map<WellReference, Sample> wellRefToSampleMap = new HashMap<WellReference, Sample>();
+        Map<Long, Sample> idToSampleMap = asSampleIdMap(wellSamples);
+        for (WellContentQueryResult well : wells)
+        {
+            Sample sample = idToSampleMap.get(well.well_id);
+            wellRefToSampleMap.put(well.getWellReference(), sample);
+        }
+        return wellRefToSampleMap;
+    }
+
+    private List<WellExtendedData> createWellExtendedData(List<WellData> wellsData,
+            final Map<WellReference, Sample> wellRefToSampleMap)
+    {
+        return CollectionUtils.map(wellsData,
+                new CollectionUtils.ICollectionMappingFunction<WellExtendedData, WellData>()
+                    {
+                        public WellExtendedData map(WellData wellData)
+                        {
+                            WellReference wellReference = wellData.tryGetWellReference();
+                            assert wellReference != null : "wellReference not available for "
+                                    + wellData;
+                            Sample wellSample = wellRefToSampleMap.get(wellReference);
+                            assert wellSample != null : "Cannot find a sample for " + wellReference;
+
+                            return new WellExtendedData(wellData, wellSample);
+                        }
+                    });
+    }
+
+    private static Map<Long, Sample> asSampleIdMap(List<Sample> samples)
+    {
+        Map<Long/* sample id */, Sample> map = new HashMap<Long, Sample>();
+        for (Sample sample : samples)
+        {
+            map.put(sample.getId(), sample);
+        }
+        return map;
+    }
+
+    private List<Sample> loadSamplesWithMaterialPropertiesEnriched(Set<Long> wellIds)
+    {
+        ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(wellIds);
+        ISampleLister sampleLister = businessObjectFactory.createSampleLister(session);
+        List<Sample> wellSamples = sampleLister.list(criteria);
+
+        IMaterialLister materialLister = businessObjectFactory.createMaterialLister(session);
+        List<Material> containedMaterials = getMaterialsWithDuplicates(wellSamples);
+        materialLister.enrichWithProperties(containedMaterials);
+
+        return wellSamples;
+    }
+
+    /**
+     * Return *all* material objects contained in the wells as list. The list can contained
+     * different objects representing the same entity in the database, but we need the duplication
+     * to be able to populate an object graph with wells correctly.
+     */
+    private static List<Material> getMaterialsWithDuplicates(List<Sample> samples)
+    {
+        List<Material> materials = new ArrayList<Material>();
+        for (Sample sample : samples)
+        {
+            for (IEntityProperty property : sample.getProperties())
+            {
+                Material materialOrNull = property.getMaterial();
+                if (materialOrNull != null)
+                {
+                    materials.add(materialOrNull);
+                }
+            }
+        }
+        return materials;
+    }
+
+    private static Set<Long> extractWellIds(Iterable<WellContentQueryResult> wells)
+    {
+        Set<Long> ids = new HashSet<Long>();
+        for (WellContentQueryResult well : wells)
+        {
+            ids.add(well.well_id);
+        }
+        return ids;
+    }
+
+    /**
+     * Calculates summaries of feature vectors for each experiment and a specified material. Uses a
+     * constant number of selects.
+     */
+    public List<MaterialSimpleFeatureVectorSummary> loadMaterialFeatureVectorsFromAllAssaysBatch(
+            TechId materialId, List<ExperimentReference> experiments)
+    {
+        List<MaterialSimpleFeatureVectorSummary> summaries =
+                new ArrayList<MaterialSimpleFeatureVectorSummary>();
+        StopWatch watch = createWatchAndStart();
+        int totalWellsLoaded = 0;
+        int totalFeatureVectorsLoaded = 0;
+
+        List<BasicWellContentQueryResult> allWells =
+                fetchWellLocations(materialId, extractIds(experiments));
+        totalWellsLoaded += allWells.size();
+        // TODO KE: 2011-07-15 specify analysis procedure here
+        WellFeatureCollection<FeatureVectorValues> allWellFeaturesOrNull =
+                tryLoadWellSingleFeatureVectors(allWells,
+                        AnalysisProcedureCriteria.createAllProcedures());
+
+        if (allWellFeaturesOrNull == null)
+        {
+            addEmptySummaries(summaries, experiments);
+        } else
+        {
+            for (ExperimentReference experiment : experiments)
+            {
+                totalFeatureVectorsLoaded += allWellFeaturesOrNull.getFeatures().size();
+                List<BasicWellContentQueryResult> experimentWells =
+                        filterExperimentWells(allWells, experiment.getPermId());
+                List<MaterialIdFeatureVectorSummary> experimentSummaries =
+                        calculateExperimentFeatureVectorSummaries(experimentWells,
+                                allWellFeaturesOrNull, false);
+
+                MaterialSimpleFeatureVectorSummary summary =
+                        findExperimentFeatureVectorSummary(materialId, experiment,
+                                allWellFeaturesOrNull.getFeatureCodesAndLabels(),
+                                experimentSummaries);
+                summaries.add(summary);
+            }
+        }
+        operationLog.info(String.format(
+                "[%d msec] Experiments batch: %d, wells loaded: %d, feature vectors: %d.",
+                watch.getTime(), experiments.size(), totalWellsLoaded, totalFeatureVectorsLoaded));
+        return summaries;
+    }
+
+    private static long[] extractIds(List<ExperimentReference> experiments)
+    {
+        long[] ids = new long[experiments.size()];
+        int i = 0;
+        for (ExperimentReference experiment : experiments)
+        {
+            ids[i++] = experiment.getId();
+        }
+        return ids;
+    }
+
+    private void addEmptySummaries(List<MaterialSimpleFeatureVectorSummary> summaries,
+            List<ExperimentReference> experiments)
+    {
+        for (ExperimentReference experiment : experiments)
+        {
+            summaries.add(new MaterialSimpleFeatureVectorSummary(experiment));
+        }
+    }
+
+    /**
+     * Fetches wells containing materials of the same type as the specified one in chosen
+     * experiment.
+     */
+    private List<BasicWellContentQueryResult> fetchWellLocations(TechId materialId,
+            TechId experimentId)
+    {
+        return fetchWellLocations(materialId, new long[]
+            { experimentId.getId() });
+    }
+
+    /**
+     * Fetches wells containing materials of the same type as the specified one in chosen
+     * experiments.
+     */
+    private List<BasicWellContentQueryResult> fetchWellLocations(TechId materialId,
+            long[] experimentIds)
+    {
+        String materialTypeCode = fetchMaterialTypeCode(materialId);
+        return fetchWellLocations(materialTypeCode, experimentIds);
+    }
+
+    private List<BasicWellContentQueryResult> fetchWellLocations(String materialTypeCodePattern,
+            long[] experimentIds)
+    {
+        StopWatch watch = createWatchAndStart();
+        List<BasicWellContentQueryResult> wells =
+                getScreeningDAO().getPlateLocationsForExperiment(experimentIds,
+                        materialTypeCodePattern);
+        operationLog.info("[" + watch.getTime() + " msec] Fetching " + wells.size() + " wells.");
+        return wells;
+    }
+
+    private List<MaterialIdFeatureVectorSummary> calculateExperimentFeatureVectorSummaries(
+            Iterable<BasicWellContentQueryResult> wells,
+            WellFeatureCollection<FeatureVectorValues> allWellFeatures, boolean calculateDeviations)
+    {
+        List<? extends IWellData> experimentWellData = createWellData(wells, allWellFeatures);
+
+        // We have to calculate summaries for all materials in the experiment to get the
+        // right ranking of the specified material.
+        return calculateExperimentFeatureVectorSummaries(experimentWellData, calculateDeviations);
+    }
+
+    private List<WellData> createWellData(Iterable<BasicWellContentQueryResult> wells,
+            WellFeatureCollection<FeatureVectorValues> allWellFeatures)
+    {
+        Map<WellReference, Long/* material id */> wellToMaterialMap =
+                createWellToMaterialMap(wells);
+        return createWellData(wellToMaterialMap, allWellFeatures.getFeatures());
+    }
+
+    private String fetchMaterialTypeCode(TechId materialId)
+    {
+        IMaterialBO materialBO = businessObjectFactory.createMaterialBO(session);
+        materialBO.loadDataByTechId(materialId);
+        return materialBO.getMaterial().getEntityType().getCode();
+    }
+
+    // NOTE: if there are 2 materials in a well, a random one will be chosen
+    private static Map<WellReference, Long/* material id */> createWellToMaterialMap(
+            Iterable<BasicWellContentQueryResult> wells)
+    {
+        Map<WellReference, Long> wellToMaterialMap = new HashMap<WellReference, Long>();
+        for (BasicWellContentQueryResult well : wells)
+        {
+            WellReference wellReference = well.getWellReference();
+            wellToMaterialMap.put(wellReference, well.material_content_id);
+        }
+        return wellToMaterialMap;
+    }
+
+    private static List<BasicWellContentQueryResult> filterExperimentWells(
+            List<BasicWellContentQueryResult> wells, final String experimentPermId)
+    {
+        return CollectionUtils.filter(wells, new ICollectionFilter<BasicWellContentQueryResult>()
+            {
+                public boolean isPresent(BasicWellContentQueryResult well)
+                {
+                    return belongsToExperiment(well, experimentPermId);
+                }
+            });
+    }
+
+    private static boolean belongsToExperiment(BasicWellContentQueryResult well,
+            String experimentPermId)
+    {
+        return well.exp_perm_id.equals(experimentPermId);
+    }
+
+    private MaterialSimpleFeatureVectorSummary findExperimentFeatureVectorSummary(
+            TechId materialId, ExperimentReference experiment, List<CodeAndLabel> features,
+            List<MaterialIdFeatureVectorSummary> experimentSummaries)
+    {
+        // select the summary of the right material
+        MaterialIdFeatureVectorSummary materialSummary =
+                findMaterialSummary(materialId, experimentSummaries);
+        return new MaterialSimpleFeatureVectorSummary(experiment, features,
+                materialSummary.getFeatureVectorSummary(), materialSummary.getFeatureVectorRanks());
+    }
+
+    private List<MaterialIdFeatureVectorSummary> calculateExperimentFeatureVectorSummaries(
+            List<? extends IWellData> experimentWellData, boolean calculateDeviations)
+    {
+        return WellReplicaSummaryCalculator.calculateReplicasFeatureVectorSummaries(
+                experimentWellData, settings.getAggregationType(), calculateDeviations);
+    }
+
+    private static MaterialIdFeatureVectorSummary findMaterialSummary(TechId materialId,
+            List<MaterialIdFeatureVectorSummary> summaries)
+    {
+        for (MaterialIdFeatureVectorSummary summary : summaries)
+        {
+            if (summary.getMaterial().equals(materialId.getId()))
+            {
+                return summary;
+            }
+        }
+        throw new IllegalStateException("It should not happen: no summary found for material "
+                + materialId);
+    }
+
+    // connects each well with a material with its feature vector
+    private static List<WellData> createWellData(
+            Map<WellReference, Long/* material id */> experimentWellToMaterialMap,
+            List<FeatureVectorValues> allFeatures)
+    {
+        List<WellData> experimentWellDataList = new ArrayList<WellData>();
+        for (FeatureVectorValues feature : allFeatures)
+        {
+            WellReference wellReference = feature.getWellReference();
+            Long materialId = experimentWellToMaterialMap.get(wellReference);
+            if (materialId != null)
+            {
+                float[] values = WellFeatureCollectionLoader.asFeatureVectorValues(feature);
+                WellData wellData = new WellData(materialId, values, wellReference);
+                experimentWellDataList.add(wellData);
+            }
+        }
+        return experimentWellDataList;
+    }
+
+    private static Set<PlateIdentifier> extractPlates(Iterable<? extends IWellReference> allWells)
+    {
+        Set<PlateIdentifier> plates = new HashSet<PlateIdentifier>();
+        for (IWellReference well : allWells)
+        {
+            String platePermId = well.getPlatePermId();
+            PlateIdentifier plateIdent = PlateIdentifier.createFromPermId(platePermId);
+            plates.add(plateIdent);
+        }
+        return plates;
+    }
+
+    private WellFeatureCollection<FeatureVectorValues> tryLoadWellSingleFeatureVectors(
+            Iterable<? extends IWellReference> allWells,
+            AnalysisProcedureCriteria analysisProcedureCriteria)
+    {
+        Set<PlateIdentifier> plates = extractPlates(allWells);
+        return tryLoadWellSingleFeatureVectors(plates, analysisProcedureCriteria);
+    }
+
+    private WellFeatureCollection<FeatureVectorValues> tryLoadWellSingleFeatureVectors(
+            Set<PlateIdentifier> plates, AnalysisProcedureCriteria analysisProcedureCriteria)
+    {
+        return new WellFeatureCollectionLoader(session, businessObjectFactory, daoFactory)
+                .tryLoadWellSingleFeatureVectors(plates, settings.getFeatureCodes(),
+                        analysisProcedureCriteria);
+    }
+
+    /**
+     * Calculates summaries of feature vectors for each material of the specified type in the given
+     * experiment.
+     */
+    public MaterialIdSummaryAndFeatures tryCalculateExperimentFeatureVectorSummaries(
+            TechId experimentId, String[] replicaMaterialTypeSubstrings,
+            AnalysisProcedureCriteria analysisProcedureCriteria, boolean calculateDeviations)
+    {
+        String typePatterns =
+                PatternMatchingUtils.asPostgresSimilarExpression(settings
+                        .getReplicaMaterialTypeSubstrings());
+        List<BasicWellContentQueryResult> wells = fetchWellLocations(typePatterns, new long[]
+            { experimentId.getId() });
+        return tryCalculateExperimentFeatureVectorSummaries(wells, analysisProcedureCriteria,
+                calculateDeviations);
+    }
+
+    /**
+     * Calculates summaries of feature vectors for each material in the given experiment. A material
+     * of one well is chosen by filtering materials of the same type as the specified one.
+     */
+    public MaterialIdSummaryAndFeatures tryCalculateExperimentFeatureVectorSummaries(
+            TechId experimentId, AnalysisProcedureCriteria analysisProcedureCriteria,
+            TechId materialId, boolean calculateDeviations)
+    {
+        List<BasicWellContentQueryResult> wells = fetchWellLocations(materialId, experimentId);
+        return tryCalculateExperimentFeatureVectorSummaries(wells, analysisProcedureCriteria,
+                calculateDeviations);
+    }
+
+    private MaterialIdSummaryAndFeatures tryCalculateExperimentFeatureVectorSummaries(
+            List<BasicWellContentQueryResult> wells,
+            AnalysisProcedureCriteria analysisProcedureCriteria, boolean calculateDeviations)
+    {
+        WellFeatureCollection<FeatureVectorValues> allWellFeatures =
+                tryLoadWellSingleFeatureVectors(wells, analysisProcedureCriteria);
+
+        if (allWellFeatures == null)
+        {
+            return null;
+        }
+        List<MaterialIdFeatureVectorSummary> featureSummaries =
+                calculateExperimentFeatureVectorSummaries(wells, allWellFeatures,
+                        calculateDeviations);
+        return new MaterialIdSummaryAndFeatures(featureSummaries,
+                allWellFeatures.getFeatureCodesAndLabels());
+    }
+
+    static class MaterialIdSummaryAndFeatures
+    {
+        private final List<MaterialIdFeatureVectorSummary> featureSummaries;
+
+        private final List<CodeAndLabel> featureNames;
+
+        public MaterialIdSummaryAndFeatures(List<MaterialIdFeatureVectorSummary> featureSummaries,
+                List<CodeAndLabel> featureNames)
+        {
+            this.featureSummaries = featureSummaries;
+            this.featureNames = featureNames;
+        }
+
+        public List<MaterialIdFeatureVectorSummary> getFeatureSummaries()
+        {
+            return featureSummaries;
+        }
+
+        public List<CodeAndLabel> getFeatureNames()
+        {
+            return featureNames;
+        }
+    }
+
+}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellReplicaSummaryCalculator.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellReplicaSummaryCalculator.java
index 0168e77b0ba..d04db25a867 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellReplicaSummaryCalculator.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellReplicaSummaryCalculator.java
@@ -30,7 +30,7 @@ import ch.systemsx.cisd.common.collections.GroupByMap;
 import ch.systemsx.cisd.common.collections.IKeyExtractor;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellData;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialIdFeatureVectorSummary;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellExtendedData;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellData;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialReplicaSummaryAggregationType;
 
 /**
@@ -196,7 +196,7 @@ public class WellReplicaSummaryCalculator
         {
             Long replicaId = entry.getKey();
             float[] aggregates = entry.getValue().getAggregates();
-            IWellData summaryWellData = new WellExtendedData(replicaId, aggregates, null, null);
+            IWellData summaryWellData = new WellData(replicaId, aggregates, null);
             summaryWellDataList.add(summaryWellData);
         }
         return summaryWellDataList;
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/IWellExtendedData.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/IWellExtendedData.java
deleted file mode 100644
index b7b821b2fa5..00000000000
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/IWellExtendedData.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.plugin.screening.server.logic.dto;
-
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityPropertiesHolder;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
-
-/**
- * Enriches interface to access well feature vector with well sample and material metadata.
- * 
- * @author Tomasz Pylak
- */
-public interface IWellExtendedData extends IEntityPropertiesHolder, IWellData
-{
-    /** Well sample for which the data are provided. */
-    Sample getWell();
-
-    /**
-     * Material in the well which allowed to find replicates (e.g. gene or compound).<br>
-     * Note: if the replicaId is the same for two wellData then the returned material is also the
-     * same.
-     */
-    Material getMaterial();
-
-}
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellData.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellData.java
index 3dc98d7fbd3..aa0f33b76d6 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellData.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellData.java
@@ -18,6 +18,8 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto;
 
 import java.util.Arrays;
 
+import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellReference;
+
 /**
  * The simplest implementation of {@Link IWellData}.
  * 
@@ -29,10 +31,14 @@ public class WellData implements IWellData
 
     private final float[] featureVector;
 
-    public WellData(long replicaId, float[] featureVector)
+    private final WellReference wellReferenceOrNull;
+
+    /** @param wellReferenceOrNull null if these are aggregated data */
+    public WellData(long replicaId, float[] featureVector, WellReference wellReferenceOrNull)
     {
         this.featureVector = featureVector;
         this.replicaId = replicaId;
+        this.wellReferenceOrNull = wellReferenceOrNull;
     }
 
     public long getReplicaMaterialId()
@@ -45,6 +51,11 @@ public class WellData implements IWellData
         return featureVector;
     }
 
+    public WellReference tryGetWellReference()
+    {
+        return wellReferenceOrNull;
+    }
+
     @Override
     public String toString()
     {
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellExtendedData.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellExtendedData.java
index 32e62f85443..825e925243c 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellExtendedData.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellExtendedData.java
@@ -18,36 +18,36 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto;
 
 import java.util.List;
 
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityPropertiesHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 
 /**
- * The simplest implementation of {@Link IWellExtendedData}.
+ * Enriches {@link IWellData} interface with well sample.
+ * metadata.
  * 
  * @author Tomasz Pylak
  */
-public class WellExtendedData extends WellData implements IWellExtendedData
+public class WellExtendedData extends WellData implements IEntityPropertiesHolder
 {
-    private Sample well;
+    private final Sample well;
 
-    private final Material material;
-
-    public WellExtendedData(long replicaId, float[] featureVector, Sample well, Material material)
+    public WellExtendedData(WellData wellData, Sample well)
     {
-        super(replicaId, featureVector);
+        super(wellData.getReplicaMaterialId(), wellData.getFeatureVector(), wellData
+                .tryGetWellReference());
         this.well = well;
-        this.material = material;
     }
 
+    /** Properties of the well sample for which the data are provided. */
     public Sample getWell()
     {
         return well;
     }
 
-    public Material getMaterial()
+    public Long getId()
     {
-        return material;
+        return well.getId();
     }
 
     public List<IEntityProperty> getProperties()
@@ -55,9 +55,4 @@ public class WellExtendedData extends WellData implements IWellExtendedData
         return well.getProperties();
     }
 
-    public Long getId()
-    {
-        return well.getId();
-    }
-
 }
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/MaterialSummarySettings.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/MaterialSummarySettings.java
index 3c05eae5d5a..08aceb09feb 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/MaterialSummarySettings.java
+++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/MaterialSummarySettings.java
@@ -30,8 +30,8 @@ public class MaterialSummarySettings implements ISerializable
     private static final long serialVersionUID = ServiceVersionHolder.VERSION;
 
     /**
-     * the name of a material property type that can be rendered as a link to a details view. TODO
-     * KE: this should be part of the display settings ?!
+     * The name of a material property type that can be rendered as a link to a details view when a
+     * material is shown.
      */
     private String materialDetailsPropertyType;
 
@@ -39,8 +39,8 @@ public class MaterialSummarySettings implements ISerializable
 
     private String[] replicaMatrialTypeSubstrings;
 
-    // well property codes which links to the material which determins which biological replicate it
-    // is, e.g. siRNA or compound
+    // well property codes which links to the material which determines which biological replicate
+    // it is, e.g. siRNA or compound
     private List<String> biologicalReplicatePropertyTypeCodes;
 
     private MaterialReplicaSummaryAggregationType aggregationType;
@@ -55,7 +55,7 @@ public class MaterialSummarySettings implements ISerializable
         this.featureCodes = featureCodes;
     }
 
-    public String[] getReplicaMatrialTypeSubstrings()
+    public String[] getReplicaMaterialTypeSubstrings()
     {
         return replicaMatrialTypeSubstrings;
     }
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/ScreeningDAOTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/ScreeningDAOTest.java
index 1b06ae8365d..4ea1b80c18b 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/ScreeningDAOTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/dataaccess/ScreeningDAOTest.java
@@ -178,7 +178,7 @@ public class ScreeningDAOTest extends AbstractScreeningDAOTest
     {
         List<BasicWellContentQueryResult> locations =
                 EntityListingTestUtils.asList(query.getPlateLocationsForExperiment(new long[]
-                    { 1, 2 }, "%GENE%"));
+                    { 1, 2 }, "GENE"));
         AssertJUnit.assertEquals(0, locations.size());
 
         List<ExperimentReferenceQueryResult> experiments = query.getExperimentsWithMaterial(1);
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoaderTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoaderTest.java
index 709c5b62848..9bf4efbf043 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoaderTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/MaterialFeatureVectorSummaryLoaderTest.java
@@ -35,12 +35,10 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellExtendedData;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialAllReplicasFeatureVectors;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialBiologicalReplicateFeatureVector;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialIdFeatureVectorSummary;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellData;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellExtendedData;
-import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellDataCollection;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialReplicaSummaryAggregationType;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialSummarySettings;
 
@@ -61,7 +59,7 @@ public class MaterialFeatureVectorSummaryLoaderTest extends AssertJUnit
         settings.setAggregationType(MaterialReplicaSummaryAggregationType.MEDIAN);
         settings.setBiologicalReplicatePropertyTypeCodes(SIRNA_PROPERTY_TYPE_CODE);
         int replId = 0;
-        List<IWellExtendedData> wellDataList = Arrays.asList(
+        List<WellExtendedData> wellDataList = Arrays.asList(
         // repl. 1 group 1
                 createSIRNAWellData(replId, 1, 10, 100),
 
@@ -80,18 +78,13 @@ public class MaterialFeatureVectorSummaryLoaderTest extends AssertJUnit
                 createSIRNAWellData(replId + 2, 1, 0, 500));
         List<CodeAndLabel> featuresDesc =
                 Arrays.asList(new CodeAndLabel("A", "A"), new CodeAndLabel("B", "B"));
-        WellDataCollection wellDataCollection = new WellDataCollection(wellDataList, featuresDesc);
 
         MaterialAllReplicasFeatureVectors featureVectors =
                 new MaterialFeatureVectorSummaryLoader(null, null, null, settings)
-                        .tryLoadMaterialFeatureVectors(new TechId(replId), wellDataCollection);
+                        .createMaterialFeatureVectors(new TechId(replId), wellDataList, null,
+                                featuresDesc);
 
-        MaterialIdFeatureVectorSummary generalSummary = featureVectors.getGeneralSummary();
-        assertArraysEqual(new float[]
-            { 65, 650 }, generalSummary.getFeatureVectorSummary());
-        assertArraysEqual(new int[]
-            { 2, 3 }, generalSummary.getFeatureVectorRanks());
-        assertEquals(replId, generalSummary.getMaterial().longValue());
+        assertNull(featureVectors.getGeneralSummary());
 
         assertEquals(featuresDesc, featureVectors.getFeatureDescriptions());
         int groupId = 1;
@@ -120,7 +113,7 @@ public class MaterialFeatureVectorSummaryLoaderTest extends AssertJUnit
 
     }
 
-    private static IWellExtendedData createSIRNAWellData(long replicaId, long siRNAId,
+    private static WellExtendedData createSIRNAWellData(long replicaId, long siRNAId,
             float... featureValues)
     {
         MaterialEntityProperty subgroupProperty = new MaterialEntityProperty();
@@ -135,7 +128,7 @@ public class MaterialFeatureVectorSummaryLoaderTest extends AssertJUnit
         return createWellData(replicaId, subgroupProperty, featureValues);
     }
 
-    private static IWellExtendedData createWellData(long replicaId,
+    private static WellExtendedData createWellData(long replicaId,
             IEntityProperty subgroupProperty, float... featureValues)
     {
         Material material = new Material();
@@ -147,6 +140,6 @@ public class MaterialFeatureVectorSummaryLoaderTest extends AssertJUnit
         material.setProperties(properties);
         well.setProperties(properties);
 
-        return new WellExtendedData(replicaId, featureValues, well, material);
+        return new WellExtendedData(new WellData(replicaId, featureValues, null), well);
     }
 }
\ No newline at end of file
diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellDataCollection.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellDataCollection.java
similarity index 79%
rename from screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellDataCollection.java
rename to screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellDataCollection.java
index 16bb94d2ad3..3053ff786e5 100644
--- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/dto/WellDataCollection.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellDataCollection.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto;
+package ch.systemsx.cisd.openbis.plugin.screening.server.logic;
 
 import java.util.List;
 
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CodeAndLabel;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellExtendedData;
 
 /**
  * List of well data and description of each feature.
@@ -27,19 +28,19 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CodeAndLabel;
  */
 public class WellDataCollection
 {
-    private final List<IWellExtendedData> wellDataList;
+    private final List<WellExtendedData> wellDataList;
 
     // has the same length as feature vectors in all wells
     private final List<CodeAndLabel> featureDescriptions;
 
-    public WellDataCollection(List<IWellExtendedData> wellDataList,
+    public WellDataCollection(List<WellExtendedData> wellDataList,
             List<CodeAndLabel> featureDescriptions)
     {
         this.wellDataList = wellDataList;
         this.featureDescriptions = featureDescriptions;
     }
 
-    public List<IWellExtendedData> getWellDataList()
+    public List<WellExtendedData> getWellDataList()
     {
         return wellDataList;
     }
diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellReplicaSummaryCalculatorTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellReplicaSummaryCalculatorTest.java
index e7e6a9ff2ac..8951f6191e0 100644
--- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellReplicaSummaryCalculatorTest.java
+++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/WellReplicaSummaryCalculatorTest.java
@@ -33,6 +33,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.WellReplicaSummaryCalculator.SummaryFeatureVector;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.IWellData;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.MaterialIdFeatureVectorSummary;
+import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellData;
 import ch.systemsx.cisd.openbis.plugin.screening.server.logic.dto.WellExtendedData;
 import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.MaterialReplicaSummaryAggregationType;
 
@@ -206,7 +207,7 @@ public class WellReplicaSummaryCalculatorTest extends AssertJUnit
     {
         Material material = new Material();
         material.setId(replicaId);
-        return new WellExtendedData(replicaId, featureValues, null, material);
+        return new WellExtendedData(new WellData(replicaId, featureValues, null), null);
     }
 
     private List<MaterialIdFeatureVectorSummary> calculate(List<IWellData> wellDataList)
-- 
GitLab