// $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.service.cherrypicks; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import edu.harvard.med.screensaver.db.DAOTransaction; import edu.harvard.med.screensaver.db.LibrariesDAO; import edu.harvard.med.screensaver.model.BusinessRuleViolationException; import edu.harvard.med.screensaver.model.Volume; import edu.harvard.med.screensaver.model.VolumeUnit; import edu.harvard.med.screensaver.model.cherrypicks.CherryPickAssayPlate; import edu.harvard.med.screensaver.model.cherrypicks.CherryPickRequest; import edu.harvard.med.screensaver.model.cherrypicks.LabCherryPick; import edu.harvard.med.screensaver.model.cherrypicks.RNAiCherryPickRequest; import edu.harvard.med.screensaver.model.cherrypicks.ScreenerCherryPick; import edu.harvard.med.screensaver.model.libraries.Copy; import edu.harvard.med.screensaver.model.libraries.CopyUsageType; import edu.harvard.med.screensaver.model.libraries.Library; import edu.harvard.med.screensaver.model.libraries.Plate; import edu.harvard.med.screensaver.model.libraries.PlateSize; import edu.harvard.med.screensaver.model.libraries.PlateStatus; import edu.harvard.med.screensaver.model.libraries.WellKey; import edu.harvard.med.screensaver.model.libraries.WellName; import edu.harvard.med.screensaver.model.users.AdministratorUser; import edu.harvard.med.screensaver.test.AbstractSpringPersistenceTest; import edu.harvard.med.screensaver.test.MakeDummyEntities; public class CherryPickRequestPlateMapperTest extends AbstractSpringPersistenceTest { // static members private static Logger log = Logger.getLogger(CherryPickRequestPlateMapperTest.class); // instance data members @Autowired protected LibrariesDAO librariesDao; @Autowired protected CherryPickRequestPlateMapper cherryPickRequestPlateMapper; @Autowired protected CherryPickRequestAllocator cherryPickRequestAllocator; private Volume _minimumSourceWellVolume = new Volume(5, VolumeUnit.MICROLITERS); // public constructors and methods public void testCherryPickPlateMapperWithoutKeepingSourcePlateCherryPicksTogether() { CherryPickRequest cherryPickRequest = initializeCherryPicks(false); assertEquals("assay plates count", 4, cherryPickRequest.getCherryPickAssayPlates().size()); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 0, 21, 1); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 22, 43, 2); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 44, 65, 3); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 66, 75, 4); CherryPickAssayPlate lastPlate = cherryPickRequest.getCherryPickAssayPlates().last(); for (int iCol = 0; iCol < PlateSize.WELLS_384.getColumns(); iCol++) { if (iCol == 2) { //assertColumnIsFull(cherryPickRequest, lastPlate, iCol); } else { assertColumnIsEmpty(cherryPickRequest, lastPlate, iCol); } } assertTrue(cherryPickRequestPlateMapper.getAssayPlatesRequiringSourcePlateReload(cherryPickRequest).isEmpty()); } public void testCherryPickPlateMapperKeepingSourcePlateCherryPicksTogether() { CherryPickRequest cherryPickRequest = initializeCherryPicks(true); assertEquals("assay plates count", 4, cherryPickRequest.getCherryPickAssayPlates().size()); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 0, 21, 1); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 22, 43, 2); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 44, 64, 3); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 65, 75, 4); CherryPickAssayPlate lastPlate = cherryPickRequest.getCherryPickAssayPlates().last(); for (int iCol = 0; iCol < PlateSize.WELLS_384.getColumns(); iCol++) { if (iCol == 2) { assertColumnIsFull(cherryPickRequest, lastPlate, iCol); } else { assertColumnIsEmpty(cherryPickRequest, lastPlate, iCol); } } assertTrue(cherryPickRequestPlateMapper.getAssayPlatesRequiringSourcePlateReload(cherryPickRequest).isEmpty()); } public CherryPickRequest initializeCherryPicks(final boolean keepSourcePlateCherryPicksTogether) { final CherryPickRequest[] result = new CherryPickRequest[1]; genericEntityDao.doInTransaction(new DAOTransaction() { public void runTransaction() { Library duplexLibrary = MakeDummyEntities.makeRNAiDuplexLibrary("Duplexes library", 1, 6, PlateSize.WELLS_384); makeLibraryCopy(duplexLibrary, "C", 10); makeLibraryCopy(duplexLibrary, "D", 10); genericEntityDao.persistEntity(duplexLibrary); genericEntityDao.flush(); // needed since cprAllocator.allocate() calls reload for each well, which must be in db (not just session) // create and allocate a cherry pick request, to force next cherry pick // request to allocate some cherry picks from alternate plate copies; // we need to allocate from multiple copies to test that sets of picks from // different copies are kept together on same cherry pick plate { CherryPickRequest earlierCherryPickRequest = MakeDummyEntities.createRNAiCherryPickRequest(1, new Volume(10)); ScreenerCherryPick dummyScreenerCherryPick = earlierCherryPickRequest.createScreenerCherryPick( librariesDao.findWell(new WellKey(1, "A01"))); // these cherry picks will force subsequent picks from the same well to be allocated from copy D Copy copyC = duplexLibrary.getCopy("C"); dummyScreenerCherryPick.createLabCherryPick(librariesDao.findWell(new WellKey(5, "A01"))).setAllocated(copyC); dummyScreenerCherryPick.createLabCherryPick(librariesDao.findWell(new WellKey(5, "A02"))).setAllocated(copyC); dummyScreenerCherryPick.createLabCherryPick(librariesDao.findWell(new WellKey(5, "A03"))).setAllocated(copyC); dummyScreenerCherryPick.createLabCherryPick(librariesDao.findWell(new WellKey(6, "A01"))).setAllocated(copyC); dummyScreenerCherryPick.createLabCherryPick(librariesDao.findWell(new WellKey(6, "A02"))).setAllocated(copyC); dummyScreenerCherryPick.createLabCherryPick(librariesDao.findWell(new WellKey(6, "A03"))).setAllocated(copyC); // due to the "minimal copy usage" allocation feature, we need force // at least one D copy well on library plate 5 to be depleted, so that all cherry picks // (in the next cpr) are not allocated exclusively from copy D; the // effect will be that future picks from the above wells will be // allocated from copy D, and all others from copy C. Copy copyD = duplexLibrary.getCopy("D"); dummyScreenerCherryPick.createLabCherryPick(librariesDao.findWell(new WellKey(5, "A24"))).setAllocated(copyD); genericEntityDao.saveOrUpdateEntity(earlierCherryPickRequest.getScreen()); genericEntityDao.flush(); // needed to make sure above allocations are in the database; allocate(), below, will query db (not just session) for existing well volume reservations } CherryPickRequest cherryPickRequest = MakeDummyEntities.createRNAiCherryPickRequest(2, new Volume(10)); cherryPickRequest.setKeepSourcePlateCherryPicksTogether(keepSourcePlateCherryPicksTogether); ScreenerCherryPick dummyScreenerCherryPick = cherryPickRequest.createScreenerCherryPick( librariesDao.findWell(new WellKey(1, "A01"))); cherryPickRequest.setRandomizedAssayPlateLayout(false); // all cherry picks will be laid out into columns 2 and 7 (zero-based) only, with 11 wells available per column, so 22 wells available per cherry pick plate Set<WellName> emptyWells = makeEmptyWellsFromColumnsAndRows(Arrays.asList(/*2,*/ 3, 4, 5, 6, /*7,*/ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 21), Arrays.asList(3), duplexLibrary); cherryPickRequest.addEmptyWellsOnAssayPlate(emptyWells); // cherry picks intended for plate 1 addLabCherryPicks(dummyScreenerCherryPick, 1, "A01", "A14"); // to assay plate 1, col 3 fully used and col 8 has 3 CPs addLabCherryPicks(dummyScreenerCherryPick, 2, "A01", "A08"); // to assay plate 1, fill the rest of col 8, leaving 1 well available // cherry picks intended for plate 2 addLabCherryPicks(dummyScreenerCherryPick, 3, "A01", "A16"); // to assay plate 2 addLabCherryPicks(dummyScreenerCherryPick, 4, "A01", "A06"); // to assay plate 2 (exactly full) // cherry picks intended for plate 3 addLabCherryPicks(dummyScreenerCherryPick, 5, "A01", "A24"); // C copies (21) to assay plate 3, D copies (3) to assay plate 4 // cherry picks intended for plate 4 addLabCherryPicks(dummyScreenerCherryPick, 6, "A01", "A08"); // both C (5) and D copies (3) to assay plate 4 assertEquals(76, cherryPickRequest.getLabCherryPicks().size()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLeadScreener()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLabHead()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen()); genericEntityDao.flush(); cherryPickRequestAllocator.allocate(cherryPickRequest); cherryPickRequestPlateMapper.generatePlateMapping(cherryPickRequest); result[0] = cherryPickRequest; } }); return result[0]; } /** * Tests the case where the wells from a single source plate are too numerous * to fit on even an empty assay plate (in which case we must map these wells * to two or more assay plates) */ public void testTooManySourcePlateWellsForAssayPlate() { genericEntityDao.doInTransaction(new DAOTransaction() { public void runTransaction() { Library duplexLibrary = MakeDummyEntities.makeRNAiDuplexLibrary("Duplexes library", 1, 1, PlateSize.WELLS_384); makeLibraryCopy(duplexLibrary, "C", 10); genericEntityDao.saveOrUpdateEntity(duplexLibrary); genericEntityDao.flush(); // needed since cprAllocator.allocate() calls reload for each well, which must be in db (not just session) CherryPickRequest cherryPickRequest = MakeDummyEntities.createRNAiCherryPickRequest(1, new Volume(10)); ScreenerCherryPick dummyScreenerCherryPick = cherryPickRequest.createScreenerCherryPick( librariesDao.findWell(new WellKey(1, "A01"))); cherryPickRequest.setRandomizedAssayPlateLayout(false); Set<Integer> emptyColumns = new HashSet<Integer>(); emptyColumns.addAll(Arrays.asList(/*2,*/ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 21)); cherryPickRequest.addEmptyWellsOnAssayPlate(makeEmptyWellsFromColumnsAndRows(emptyColumns, Lists.<Integer>newArrayList(), duplexLibrary)); addLabCherryPicks(dummyScreenerCherryPick, 1, "A01", "B04"); // enough to fill 2 assay plates completely, plus a 3rd, partially assertEquals(28, cherryPickRequest.getLabCherryPicks().size()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLeadScreener()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLabHead()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen()); genericEntityDao.flush(); cherryPickRequestAllocator.allocate(cherryPickRequest); cherryPickRequestPlateMapper.generatePlateMapping(cherryPickRequest); assertEquals("assay plates count", 3, cherryPickRequest.getCherryPickAssayPlates().size()); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 0, 11, 1); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 12, 23, 2); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 24, 27, 3); assertFalse(cherryPickRequestPlateMapper.getAssayPlatesRequiringSourcePlateReload(cherryPickRequest).isEmpty()); } }); } public void testRandomizedPlateMappingIsLeftConstrained() { genericEntityDao.doInTransaction(new DAOTransaction() { public void runTransaction() { Library library = MakeDummyEntities.makeRNAiDuplexLibrary("library", 1, 2, PlateSize.WELLS_384); makeLibraryCopy(library, "C", 10); genericEntityDao.saveOrUpdateEntity(library); genericEntityDao.flush(); // needed since cprAllocator.allocate() calls reload for each well, which must be in db (not just session) CherryPickRequest cherryPickRequest = MakeDummyEntities.createRNAiCherryPickRequest(1, new Volume(10)); ScreenerCherryPick dummyScreenerCherryPick1 = cherryPickRequest.createScreenerCherryPick(librariesDao.findWell(new WellKey(1, "A01"))); ScreenerCherryPick dummyScreenerCherryPick2 = cherryPickRequest.createScreenerCherryPick(librariesDao.findWell(new WellKey(2, "A01"))); cherryPickRequest.setRandomizedAssayPlateLayout(true); Set<Integer> emptyColumns = Sets.newHashSet(3); cherryPickRequest.addEmptyWellsOnAssayPlate(makeEmptyWellsFromColumnsAndRows(emptyColumns, Sets.<Integer>newHashSet(), library)); addLabCherryPicks(dummyScreenerCherryPick1, 1, "A01", "C24"); // create 72 cherry picks, to fill exactly 6 left-most available columns addLabCherryPicks(dummyScreenerCherryPick2, 2, "A01", "J12"); // create 228 cherry picks, to create an indivisible block of cherry picks that must be mapped to next plate genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLeadScreener()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLabHead()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen()); genericEntityDao.flush(); cherryPickRequestAllocator.allocate(cherryPickRequest); cherryPickRequestPlateMapper.generatePlateMapping(cherryPickRequest); assertEquals("assay plates count", 2, cherryPickRequest.getCherryPickAssayPlates().size()); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 0, 71, 1); assertColumnIsEmpty(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 0); assertColumnIsEmpty(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 1); assertColumnIsFull(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 2); assertColumnIsEmpty(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 3); assertColumnIsFull(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 4); assertColumnIsFull(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 5); assertColumnIsFull(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 6); assertColumnIsFull(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 7); assertColumnIsFull(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), 8); for (int iCol = 9; iCol < library.getPlateSize().getColumns(); ++iCol) { assertColumnIsEmpty(cherryPickRequest, cherryPickRequest.getCherryPickAssayPlates().first(), iCol); } } }); } /** * Test that all available wells on a cherry pick plate are being assigned to * exactly once. By "available wells" we mean any well that is not in the * "required empty columns", "required empty rows", "screener-requested * empty columns", and "screener-requested empty rows" sets. */ public void testCherryPickPlateIsFullyUtilized() { genericEntityDao.doInTransaction(new DAOTransaction() { public void runTransaction() { Library library = MakeDummyEntities.makeRNAiDuplexLibrary("library", 1, 1, PlateSize.WELLS_384); makeLibraryCopy(library, "C", 10); genericEntityDao.saveOrUpdateEntity(library); genericEntityDao.flush(); // needed since cprAllocator.allocate() calls reload for each well, which must be in db (not just session) RNAiCherryPickRequest cherryPickRequest = MakeDummyEntities.createRNAiCherryPickRequest(1, new Volume(10)); ScreenerCherryPick dummyScreenerCherryPick = cherryPickRequest.createScreenerCherryPick(librariesDao.findWell(new WellKey(1, "A01"))); cherryPickRequest.setRandomizedAssayPlateLayout(true); Set<Integer> emptyColumns = Sets.newHashSet(); emptyColumns.add(2); Set<Integer> emptyRows = Sets.newHashSet(); emptyRows.add(2); cherryPickRequest.addEmptyWellsOnAssayPlate(makeEmptyWellsFromColumnsAndRows(emptyColumns, emptyRows, library)); addLabCherryPicks(dummyScreenerCherryPick, 1, "A01", "I17"); // create 209 cherry picks, to fill all available wells on cherry pick plate genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLeadScreener()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLabHead()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen()); genericEntityDao.flush(); cherryPickRequestAllocator.allocate(cherryPickRequest); cherryPickRequestPlateMapper.generatePlateMapping(cherryPickRequest); TreeSet<LabCherryPick> sortedLabCherryPicks = new TreeSet<LabCherryPick>(new Comparator<LabCherryPick>() { public int compare(LabCherryPick o1, LabCherryPick o2) { return o1.getAssayPlateWellName().getName().compareTo(o2.getAssayPlateWellName().getName()); }}); sortedLabCherryPicks.addAll(cherryPickRequest.getLabCherryPicks()); assertEquals("assay plates count", 1, cherryPickRequest.getCherryPickAssayPlates().size()); assertLabCherryPicksOnAssayPlate(cherryPickRequest, 0, 209 - 1, 1); Set<WellName> usedWellNames = new HashSet<WellName>(); for (LabCherryPick labCherryPick : cherryPickRequest.getLabCherryPicks()) { log.debug("testing " + labCherryPick); assertEquals("lab cherry pick assigned to assay plate 0", 0, labCherryPick.getAssayPlate().getPlateOrdinal().intValue()); assertNotNull("lab cherry pick assigned to row", labCherryPick.getAssayPlateRow()); assertNotNull("lab cherry pick assigned to column", labCherryPick.getAssayPlateColumn()); assertFalse("lab cherry pick not assigned to a requested empty well", cherryPickRequest.getEmptyWellsOnAssayPlate().contains(new WellName(labCherryPick.getAssayPlateRow(), labCherryPick.getAssayPlateColumn()))); assertNotNull("lab cherry pick assigned to unused well", usedWellNames.contains(labCherryPick.getAssayPlateWellName())); usedWellNames.add(labCherryPick.getAssayPlateWellName()); } // test again, for good measure, via alternate method CherryPickAssayPlate plate = cherryPickRequest.getCherryPickAssayPlates().first(); for (int colIndex = 3; colIndex <= 21; colIndex++) { assertColumnIsFull(cherryPickRequest, plate, colIndex); } assertColumnIsEmpty(cherryPickRequest, plate, 0); assertColumnIsEmpty(cherryPickRequest, plate, 1); assertColumnIsEmpty(cherryPickRequest, plate, 2); assertColumnIsEmpty(cherryPickRequest, plate, 22); assertColumnIsEmpty(cherryPickRequest, plate, 23); } }); } public void testCherryPickPlatesWithOnlyEmptyWells() { final CherryPickRequest[] cherryPickRequestOut = new CherryPickRequest[1]; genericEntityDao.doInTransaction(new DAOTransaction() { public void runTransaction() { Library library = MakeDummyEntities.makeRNAiDuplexLibrary("library", 1, 1, PlateSize.WELLS_384); makeLibraryCopy(library, "C", 10); genericEntityDao.saveOrUpdateEntity(library); genericEntityDao.flush(); // needed since cprAllocator.allocate() calls reload for each well, which must be in db (not just session) RNAiCherryPickRequest cherryPickRequest = MakeDummyEntities.createRNAiCherryPickRequest(1, new Volume(10)); ScreenerCherryPick dummyScreenerCherryPick = cherryPickRequest.createScreenerCherryPick(librariesDao.findWell(new WellKey(1, "A01"))); cherryPickRequest.addEmptyWellsOnAssayPlate(makeEmptyWellsFromColumnsAndRows(Arrays.asList(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21), null, library)); addLabCherryPicks(dummyScreenerCherryPick, 1, "A01", "A01"); // create 1 cherry pick genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLeadScreener()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen().getLabHead()); genericEntityDao.saveOrUpdateEntity(cherryPickRequest.getScreen()); genericEntityDao.flush(); cherryPickRequestAllocator.allocate(cherryPickRequest); cherryPickRequestOut[0] = cherryPickRequest; } }); try { cherryPickRequestPlateMapper.generatePlateMapping(cherryPickRequestOut[0]); fail("expected BusinessRuleViolationException"); } catch (BusinessRuleViolationException e) { // success! } } private void assertColumnIsEmpty(CherryPickRequest cherryPickRequest, CherryPickAssayPlate assayPlate, int columnIndex) { for (LabCherryPick cherryPick : assayPlate.getLabCherryPicks()) { if (cherryPick.getAssayPlateColumn() == columnIndex) { fail("column " + columnIndex + " is empty on plate " + assayPlate.getName()); } } } private void assertColumnIsFull(CherryPickRequest cherryPickRequest, CherryPickAssayPlate assayPlate, int columnIndex) { Set<WellName> expectedUsedWellNames = new HashSet<WellName>(); for (int rowIndex = 0; rowIndex < assayPlate.getAssayPlateType().getPlateSize().getRows(); ++rowIndex) { WellName wellName = new WellName(rowIndex, columnIndex); if (!cherryPickRequest.getEmptyWellsOnAssayPlate().contains(wellName)) { expectedUsedWellNames.add(wellName); } } for (LabCherryPick labCherryPick : assayPlate.getLabCherryPicks()) { expectedUsedWellNames.remove(labCherryPick.getAssayPlateWellName()); } assertEquals("column " + columnIndex + " is full on plate " + assayPlate.getName(), Collections.<WellName>emptySet(), expectedUsedWellNames); } private void addLabCherryPicks(ScreenerCherryPick screenerCherryPick, int libraryPlateNumber, String firstWellNameStr, String lastWellNameStr) { WellName firstWellName = new WellName(firstWellNameStr); WellName lastWellName = new WellName(lastWellNameStr); PlateSize plateSize = screenerCherryPick.getScreenedWell().getLibrary().getPlateSize(); for (int iRow = firstWellName.getRowIndex(); iRow <= lastWellName.getRowIndex(); ++iRow) { int iColFirst; if (iRow == firstWellName.getRowIndex()) { iColFirst = firstWellName.getColumnIndex(); } else { iColFirst = 0; } int iColLast; if (iRow == lastWellName.getRowIndex()) { iColLast = lastWellName.getColumnIndex(); } else { iColLast = plateSize.getColumns() - 1; } for (int iCol = iColFirst; iCol <= iColLast; ++iCol) { screenerCherryPick.createLabCherryPick(librariesDao.findWell(new WellKey(libraryPlateNumber, new WellName(iRow, iCol)))); } } } // private methods /** * @param expectedAssayPlateNumber 1-based plate number */ private void assertLabCherryPicksOnAssayPlate(CherryPickRequest cherryPickRequest, int firstIndex, int lastIndex, int expectedAssayPlateNumber) { TreeSet<LabCherryPick> sortedCherryPicks = new TreeSet<LabCherryPick>(PlateMappingCherryPickComparator.getInstance()); sortedCherryPicks.addAll(cherryPickRequest.getLabCherryPicks()); List<LabCherryPick> indexedCherryPicks = new ArrayList<LabCherryPick>(sortedCherryPicks); for (int index = firstIndex; index <= lastIndex; index++) { String expectedAssayPlateName = String.format("Cherry Picker_%s (%s) CP%d Plate %02d of %d", cherryPickRequest.getScreen().getFacilityId(), cherryPickRequest.getScreen().getFacilityId(), cherryPickRequest.getEntityId(), expectedAssayPlateNumber, cherryPickRequest.getCherryPickAssayPlates().size()); LabCherryPick cherryPick = indexedCherryPicks.get(index); if (log.isDebugEnabled()) { log.debug("labCherryPick #" + index + " source_copy=" + cherryPick.getSourceCopy().getName() + " source_well=" + cherryPick.getSourceWell() + " plate=" + cherryPick.getAssayPlate().getPlateOrdinal() + " well=" + cherryPick.getAssayPlateWellName()); } assertEquals("cherry pick #" + index + " assay plate name", expectedAssayPlateName, cherryPick.getAssayPlate().getName()); } } /** * @param library * @param copyName * @param volume */ private void makeLibraryCopy(Library library, String copyName, int volume) { Copy copy = library.createCopy((AdministratorUser) library.getCreatedBy(), CopyUsageType.CHERRY_PICK_SOURCE_PLATES, copyName); for (Plate plate : copy.getPlates().values()) { plate.withWellVolume(new Volume(volume, VolumeUnit.MICROLITERS).add(_minimumSourceWellVolume)).withStatus(PlateStatus.AVAILABLE); } } private Set<WellName> makeEmptyWellsFromColumnsAndRows(Collection<Integer> emptyColumns, Collection<Integer> emptyRows, Library library) { Set<WellName> emptyWells = Sets.newHashSet(PlateSize.WELLS_384.getEdgeWellNames(2)); if (emptyColumns != null) { for (Integer emptyColumn : emptyColumns) { for (int emptyRow = 0; emptyRow <= library.getPlateSize().getRows(); ++emptyRow) { emptyWells.add(new WellName(emptyRow, emptyColumn)); } } } if (emptyRows != null) { for (int emptyColumn = 0; emptyColumn <= library.getPlateSize().getColumns(); ++emptyColumn) { for (Integer emptyRow : emptyRows) { emptyWells.add(new WellName(emptyRow, emptyColumn)); } } } return emptyWells; } }