// $HeadURL$
// $Id$
//
// Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.
package edu.harvard.med.screensaver.db;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import com.google.common.collect.Sets;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import edu.harvard.med.screensaver.io.screenresults.ScreenResultParserTest;
import edu.harvard.med.screensaver.model.libraries.Library;
import edu.harvard.med.screensaver.model.libraries.LibraryType;
import edu.harvard.med.screensaver.model.libraries.LibraryWellType;
import edu.harvard.med.screensaver.model.libraries.PlateSize;
import edu.harvard.med.screensaver.model.libraries.Well;
import edu.harvard.med.screensaver.model.libraries.WellKey;
import edu.harvard.med.screensaver.model.screenresults.AssayWell;
import edu.harvard.med.screensaver.model.screenresults.DataColumn;
import edu.harvard.med.screensaver.model.screenresults.PartitionedValue;
import edu.harvard.med.screensaver.model.screenresults.ResultValue;
import edu.harvard.med.screensaver.model.screenresults.ScreenResult;
import edu.harvard.med.screensaver.model.screens.Screen;
import edu.harvard.med.screensaver.model.screens.ScreenDataSharingLevel;
import edu.harvard.med.screensaver.model.screens.ScreenType;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.service.screens.ScreenDerivedPropertiesUpdater;
import edu.harvard.med.screensaver.test.AbstractSpringPersistenceTest;
import edu.harvard.med.screensaver.test.MakeDummyEntities;
/**
* @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a>
*/
@Transactional
public class ScreenResultDAOTest extends AbstractSpringPersistenceTest
{
private static final Logger log = Logger.getLogger(ScreenResultDAOTest.class);
@Autowired
protected ScreenResultsDAO screenResultsDao;
@Autowired
protected LibrariesDAO librariesDao;
@Autowired
protected ScreenDerivedPropertiesUpdater screenDerivedPropertiesUpdater;
@Transactional
public void testFindMutualPositiveColumns()
{
// To test, create 4 screens:
// 1. "my" screen
// 2. "others" screen w/no overlapping wells, but with some positives anyway
// 3. "others" screen w/overlapping wells, but no overlapping positives
// 4. "others" screen w/overlapping wells, with some overlapping positives
// the test should assert that the query only returns screen 4
// create My screen
Library library = MakeDummyEntities.makeDummyLibrary(1,ScreenType.SMALL_MOLECULE,1);
Iterator<Well> wellsIter = library.getWells()
.iterator();
Well overLapWell1 = wellsIter.next();
Well overLapWell2 = wellsIter.next();
Well overLapWell3 = wellsIter.next();
Well nonOverlapWell1 = wellsIter.next();
Well nonOverlapWell2 = wellsIter.next();
Screen myScreen = MakeDummyEntities.makeDummyScreen(0,
ScreenType.SMALL_MOLECULE);
myScreen.setDataSharingLevel(ScreenDataSharingLevel.MUTUAL_POSITIVES);
ScreenResult screenResult = myScreen.createScreenResult();
DataColumn col = screenResult.createDataColumn("col1")
.forReplicate(1);
col.makeBooleanPositiveIndicator();
AssayWell assayWell = screenResult.createAssayWell(overLapWell1);
ResultValue resultValue = col.createBooleanPositiveResultValue(assayWell, true, false);
assert resultValue.isPositive();
assayWell = screenResult.createAssayWell(overLapWell2);
resultValue = col.createBooleanPositiveResultValue(assayWell, false, false);
assert !resultValue.isPositive();
assayWell = screenResult.createAssayWell(overLapWell3);
resultValue = col.createBooleanPositiveResultValue(assayWell, true, false);
assert resultValue.isPositive();
Screen screenWithNoOverlaps = MakeDummyEntities.makeDummyScreen(1,
ScreenType.SMALL_MOLECULE);
screenWithNoOverlaps.setDataSharingLevel(ScreenDataSharingLevel.MUTUAL_POSITIVES);
screenResult = screenWithNoOverlaps.createScreenResult();
col = screenResult.createDataColumn("col2")
.forReplicate(1);
col.makeBooleanPositiveIndicator();
assayWell = screenResult.createAssayWell(nonOverlapWell1);
resultValue = col.createBooleanPositiveResultValue(assayWell, true, false);
assert resultValue.isPositive();
assayWell = screenResult.createAssayWell(nonOverlapWell2);
resultValue = col.createBooleanPositiveResultValue(assayWell, false, false);
assert !resultValue.isPositive();
Screen screenWithOverlapNegative = MakeDummyEntities.makeDummyScreen(2,
ScreenType.SMALL_MOLECULE);
screenWithOverlapNegative.setDataSharingLevel(ScreenDataSharingLevel.MUTUAL_POSITIVES);
screenResult = screenWithOverlapNegative.createScreenResult();
col = screenResult.createDataColumn("col1")
.forReplicate(1);
col.makeBooleanPositiveIndicator();
assayWell = screenResult.createAssayWell(overLapWell1);
resultValue = col.createBooleanPositiveResultValue(assayWell, false, false);
assert !resultValue.isPositive();
assayWell = screenResult.createAssayWell(overLapWell2);
resultValue = col.createBooleanPositiveResultValue(assayWell, false, false);
assert !resultValue.isPositive();
assayWell = screenResult.createAssayWell(nonOverlapWell2);
resultValue = col.createBooleanPositiveResultValue(assayWell, true, false);
assert resultValue.isPositive();
Screen screenWithOverlapNegative1 = MakeDummyEntities.makeDummyScreen(21,
ScreenType.SMALL_MOLECULE);
screenWithOverlapNegative1.setDataSharingLevel(ScreenDataSharingLevel.MUTUAL_POSITIVES);
screenResult = screenWithOverlapNegative1.createScreenResult();
// make positive that doesn't overlap
col = screenResult.createDataColumn("col1")
.forReplicate(1);
DataColumn positiveNonOverlapColumn = col;
col.makeBooleanPositiveIndicator();
assayWell = screenResult.createAssayWell(overLapWell2);
resultValue = col.createBooleanPositiveResultValue(assayWell, true, false);
assert resultValue.isPositive();
assayWell = screenResult.createAssayWell(overLapWell3);
resultValue = col.createBooleanPositiveResultValue(assayWell, false, false);
assert !resultValue.isPositive();
assayWell = screenResult.createAssayWell(nonOverlapWell2);
resultValue = col.createBooleanPositiveResultValue(assayWell, true, false);
assert resultValue.isPositive();
Screen screenWithOverlapPositive = MakeDummyEntities.makeDummyScreen(3,
ScreenType.SMALL_MOLECULE);
screenWithOverlapPositive.setDataSharingLevel(ScreenDataSharingLevel.MUTUAL_POSITIVES);
screenResult = screenWithOverlapPositive.createScreenResult();
// make a mutual positive column
DataColumn mutualColumn = screenResult.createDataColumn("col1").forReplicate(1);
col = mutualColumn;
col.makeBooleanPositiveIndicator();
assayWell = screenResult.createAssayWell(overLapWell1);
resultValue = col.createBooleanPositiveResultValue(assayWell, true, false); // this is the
// mutual positive
assert resultValue.isPositive();
assayWell = screenResult.createAssayWell(overLapWell2);
resultValue = col.createBooleanPositiveResultValue(assayWell, true, false);
assert resultValue.isPositive();
assayWell = screenResult.createAssayWell(overLapWell3);
resultValue = col.createBooleanPositiveResultValue(assayWell, false, false);
assert !resultValue.isPositive();
assayWell = screenResult.createAssayWell(nonOverlapWell2);
resultValue = col.createBooleanPositiveResultValue(assayWell, true, false);
assert resultValue.isPositive();
genericEntityDao.persistEntity(library);
genericEntityDao.persistEntity(myScreen);
genericEntityDao.persistEntity(screenWithNoOverlaps);
genericEntityDao.persistEntity(screenWithOverlapNegative);
genericEntityDao.persistEntity(screenWithOverlapNegative1);
genericEntityDao.persistEntity(screenWithOverlapPositive);
genericEntityDao.flush();
List<DataColumn> columns = screenResultsDao.findMutualPositiveColumns(myScreen.getScreenResult());
assertEquals("should only find one mutual column", 1, columns.size());
assertTrue("should contain the mutual column: " + mutualColumn,
columns.contains(mutualColumn));
assertFalse("should not contain the positiveNonOverlapColumn column: " +
positiveNonOverlapColumn,
columns.contains(positiveNonOverlapColumn));
}
public void testDerivedScreenResults()
{
int replicates = 3;
SortedSet<DataColumn> derivedColSet1 = new TreeSet<DataColumn>();
SortedSet<DataColumn> derivedColSet2 = new TreeSet<DataColumn>();
ScreenResult screenResult = ScreenResultParserTest.makeScreenResult();
for (int i = 0; i < replicates; i++) {
DataColumn col = screenResult.createDataColumn("col" + i).forReplicate(1).forPhenotype("human");
derivedColSet1.add(col);
if (i % 2 == 0) {
derivedColSet2.add(col);
}
}
DataColumn derivedCol1 = screenResult.createDataColumn("derivedCol1").forReplicate(1).forPhenotype("human");
for (DataColumn dataColumn : derivedColSet1) {
derivedCol1.addTypeDerivedFrom(dataColumn);
}
DataColumn derivedCol2 = screenResult.createDataColumn("derivedCol2").forReplicate(1).forPhenotype("human");
for (DataColumn dataColumn : derivedColSet2) {
derivedCol2.addTypeDerivedFrom(dataColumn);
}
genericEntityDao.saveOrUpdateEntity(screenResult.getScreen().getLeadScreener());
genericEntityDao.saveOrUpdateEntity(screenResult.getScreen().getLabHead());
genericEntityDao.saveOrUpdateEntity(screenResult.getScreen());
flushAndClear();
List<ScreenResult> screenResults = genericEntityDao.findAllEntitiesOfType(ScreenResult.class);
screenResult = screenResults.get(0);
SortedSet<DataColumn> dataColumns =
new TreeSet<DataColumn>(screenResult.getDataColumns());
DataColumn derivedCol = dataColumns.last();
Set<DataColumn> derivedFromSet = derivedCol.getTypesDerivedFrom();
assertEquals(derivedColSet2, derivedFromSet);
dataColumns.remove(derivedCol);
derivedCol = dataColumns.last();
derivedFromSet = derivedCol.getTypesDerivedFrom();
assertEquals(derivedColSet1, derivedFromSet);
}
// TODO: this unit test has been superceded by ScreenResultLoadedAndDeleterTest; should verify that all assertions tested here are duplicated there, and then remove this test
public void testDeleteScreenResult()
{
Library library = MakeDummyEntities.makeDummyLibrary(1, ScreenType.SMALL_MOLECULE, 1);
genericEntityDao.saveOrUpdateEntity(library);
Screen screen1 = MakeDummyEntities.makeDummyScreen(1);
MakeDummyEntities.makeDummyScreenResult(screen1, library);
screen1.setLibraryPlatesDataLoadedCount(1);
screen1.setMaxDataLoadedReplicateCount(2);
screen1.setMinDataLoadedReplicateCount(2);
genericEntityDao.saveOrUpdateEntity(screen1);
flushAndClear();
screen1 = genericEntityDao.findEntityByProperty(Screen.class, Screen.facilityId.getPropertyName(), "1");
screenDerivedPropertiesUpdater.updateScreeningStatistics(screen1);
flushAndClear();
screen1 = genericEntityDao.findEntityByProperty(Screen.class, Screen.facilityId.getPropertyName(), "1");
assertNotNull(screen1.getScreenResult());
screenResultsDao.deleteScreenResult(screen1.getScreenResult());
flushAndClear();
screen1 = genericEntityDao.findEntityByProperty(Screen.class, Screen.facilityId.getPropertyName(), "1", true);
assertNull(screen1.getScreenResult());
assertEquals(0, screen1.getLibraryPlatesDataLoadedCount());
assertNull(screen1.getMaxDataLoadedReplicateCount());
assertNull(screen1.getMinDataLoadedReplicateCount());
}
/**
* A ScreenResult's plateNumbers, wells, experimentWellCount, and positives
* properties should be updated when a ResultValue is added to a
* ScreenResult's DataColumn.
*/
public void testScreenResultDerivedPersistentValues()
{
SortedSet<AssayWell> expectedAssayWells = Sets.newTreeSet();
int expectedExperimentalWellCount = 0;
int expectedPositives = 0;
Screen screen = MakeDummyEntities.makeDummyScreen(1);
ScreenResult screenResult = screen.createScreenResult();
DataColumn col1 = screenResult.createDataColumn("DataColumn1");
col1.makePartitionPositiveIndicator();
DataColumn col2 = screenResult.createDataColumn("DataColumn2");
col2.makeBooleanPositiveIndicator();
Library library = new Library((AdministratorUser) screen.getCreatedBy(),
"library 1",
"lib1",
ScreenType.SMALL_MOLECULE,
LibraryType.COMMERCIAL,
1,
10,
PlateSize.WELLS_384);
for (int i = 1; i <= 10; ++i) {
int plateNumber = i;
Well well = library.createWell(new WellKey(plateNumber, "A01"), LibraryWellType.EXPERIMENTAL);
AssayWell assayWell = screenResult.createAssayWell(well);
expectedAssayWells.add(assayWell);
boolean exclude = i % 8 == 0;
boolean positive = i % 10 == 0;
PartitionedValue col1Value = PartitionedValue.values()[i % 4];
col1.createPartitionedPositiveResultValue(assayWell, col1Value, exclude);
col2.createBooleanPositiveResultValue(assayWell, positive, false);
if (well.getLibraryWellType() == LibraryWellType.EXPERIMENTAL) {
expectedExperimentalWellCount++;
if (!exclude && col1Value != PartitionedValue.NOT_POSITIVE) {
log.debug("result value " + col1Value + " is deemed a positive by this test");
++expectedPositives;
}
}
}
genericEntityDao.saveOrUpdateEntity(library);
genericEntityDao.saveOrUpdateEntity(screen.getLeadScreener());
genericEntityDao.saveOrUpdateEntity(screen.getLabHead());
genericEntityDao.saveOrUpdateEntity(screen);
flushAndClear();
screenDerivedPropertiesUpdater.updateScreeningStatistics(screen);
screen = genericEntityDao.findEntityByProperty(Screen.class, Screen.facilityId.getPropertyName(), "1");
assertEquals("wells", expectedAssayWells, screen.getScreenResult().getAssayWells());
assertEquals("experimental well count", expectedExperimentalWellCount, screen.getScreenResult().getExperimentalWellCount().intValue());
assertEquals("positives", expectedPositives, screen.getScreenResult().getDataColumnsList().get(0).getPositivesCount().intValue());
assertEquals("1 positives ",1, screen.getScreenResult().getDataColumnsList().get(1).getPositivesCount().intValue());
assertEquals("hit ratio",0.1,screen.getScreenResult().getDataColumnsList().get(1).getPositivesRatio().doubleValue(), 0.01);
}
public void testFindResultValuesByPlate()
{
final Screen screen = MakeDummyEntities.makeDummyScreen(1);
ScreenResult screenResult = screen.createScreenResult();
DataColumn col1 = screenResult.createDataColumn("Raw Value").makeNumeric(3);
DataColumn col2 = screenResult.createDataColumn("Derived Value").makeNumeric(3);
Library library = new Library((AdministratorUser) screen.getCreatedBy(),
"library 1",
"lib1",
ScreenType.SMALL_MOLECULE,
LibraryType.COMMERCIAL,
1,
10,
PlateSize.WELLS_384);
for (int iPlate = 1; iPlate <= 3; ++iPlate) {
int plateNumber = iPlate;
for (int iWell = 0; iWell < 10; ++iWell) {
Well well = library.createWell(new WellKey(plateNumber, "A" + (iWell + 1)), LibraryWellType.EXPERIMENTAL);
AssayWell assayWell = screenResult.createAssayWell(well);
col1.createResultValue(assayWell, (double) iWell);
col2.createResultValue(assayWell, iWell + 10.0);
}
}
genericEntityDao.saveOrUpdateEntity(library);
genericEntityDao.saveOrUpdateEntity(screen.getLeadScreener());
genericEntityDao.saveOrUpdateEntity(screen.getLabHead());
genericEntityDao.saveOrUpdateEntity(screen);
flushAndClear();
// test findResultValuesByPlate(Integer, DataColumn)
Map<WellKey,ResultValue> resultValues1 = screenResultsDao.findResultValuesByPlate(2, col1);
assertEquals("result values size", 10, resultValues1.size());
for (int iWell = 0; iWell < 10; ++iWell) {
ResultValue rv = resultValues1.get(new WellKey(2, 0, iWell));
assertEquals("rv.value", new Double(iWell), rv.getNumericValue());
}
}
}