Merge pull request #90 from broadinstitute/eb_allow_read_transform_ordering

Added the functionality to impose a relative ordering on ReadTransformer...
This commit is contained in:
Mark DePristo 2013-03-06 09:52:26 -08:00
commit 7d833256e8
5 changed files with 173 additions and 2 deletions

View File

@ -62,6 +62,9 @@ public class BQSRReadTransformer extends ReadTransformer {
private boolean enabled;
private BaseRecalibration bqsr = null;
@Override
public OrderingConstraint getOrderingConstraint() { return OrderingConstraint.MUST_BE_FIRST; }
@Override
public ApplicationTime initializeSub(final GenomeAnalysisEngine engine, final Walker walker) {
this.enabled = engine.hasBQSRArgumentSet();

View File

@ -372,7 +372,8 @@ public class GenomeAnalysisEngine {
* @param walker the walker we need to apply read transformers too
*/
public void initializeReadTransformers(final Walker walker) {
final List<ReadTransformer> activeTransformers = new ArrayList<ReadTransformer>();
// keep a list of the active read transformers sorted based on priority ordering
List<ReadTransformer> activeTransformers = new ArrayList<ReadTransformer>();
final ReadTransformersMode overrideMode = WalkerManager.getWalkerAnnotation(walker, ReadTransformersMode.class);
final ReadTransformer.ApplicationTime overrideTime = overrideMode != null ? overrideMode.ApplicationTime() : null;
@ -392,9 +393,41 @@ public class GenomeAnalysisEngine {
return readTransformers;
}
private void setReadTransformers(final List<ReadTransformer> readTransformers) {
/*
* Sanity checks that incompatible read transformers are not active together (and throws an exception if they are).
*
* @param readTransformers the active read transformers
*/
protected void checkActiveReadTransformers(final List<ReadTransformer> readTransformers) {
if ( readTransformers == null )
throw new IllegalArgumentException("read transformers cannot be null");
ReadTransformer sawMustBeFirst = null;
ReadTransformer sawMustBeLast = null;
for ( final ReadTransformer r : readTransformers ) {
if ( r.getOrderingConstraint() == ReadTransformer.OrderingConstraint.MUST_BE_FIRST ) {
if ( sawMustBeFirst != null )
throw new UserException.IncompatibleReadFiltersException(sawMustBeFirst.toString(), r.toString());
sawMustBeFirst = r;
} else if ( r.getOrderingConstraint() == ReadTransformer.OrderingConstraint.MUST_BE_LAST ) {
if ( sawMustBeLast != null )
throw new UserException.IncompatibleReadFiltersException(sawMustBeLast.toString(), r.toString());
sawMustBeLast = r;
}
}
}
protected void setReadTransformers(final List<ReadTransformer> readTransformers) {
if ( readTransformers == null )
throw new ReviewedStingException("read transformers cannot be null");
// sort them in priority order
Collections.sort(readTransformers, new ReadTransformer.ReadTransformerComparator());
// make sure we don't have an invalid set of active read transformers
checkActiveReadTransformers(readTransformers);
this.readTransformers = readTransformers;
}

View File

@ -31,6 +31,8 @@ import org.broadinstitute.sting.gatk.GenomeAnalysisEngine;
import org.broadinstitute.sting.gatk.walkers.Walker;
import org.broadinstitute.sting.utils.sam.GATKSAMRecord;
import java.util.Comparator;
/**
* Baseclass used to describe a read transformer like BAQ and BQSR
*
@ -65,6 +67,11 @@ abstract public class ReadTransformer {
protected ReadTransformer() {}
/*
* @return the ordering constraint for the given read transformer
*/
public OrderingConstraint getOrderingConstraint() { return OrderingConstraint.DO_NOT_CARE; }
/**
* Master initialization routine. Called to setup a ReadTransform, using it's overloaded initializeSub routine.
*
@ -166,4 +173,33 @@ abstract public class ReadTransformer {
*/
HANDLED_IN_WALKER
}
/*
* This enum specifies the constraints that the given read transformer has relative to any other read transformers being used
*/
public enum OrderingConstraint {
/*
* If 2 read transformers are both active and MUST_BE_FIRST, then an error will be generated
*/
MUST_BE_FIRST,
/*
* No constraints on the ordering for this read transformer
*/
DO_NOT_CARE,
/*
* If 2 read transformers are both active and MUST_BE_LAST, then an error will be generated
*/
MUST_BE_LAST
}
public static class ReadTransformerComparator implements Comparator<ReadTransformer> {
public int compare(final ReadTransformer r1, final ReadTransformer r2) {
if ( r1.getOrderingConstraint() == r2.getOrderingConstraint() )
return 0;
return ( r1.getOrderingConstraint() == OrderingConstraint.MUST_BE_FIRST || r2.getOrderingConstraint() == OrderingConstraint.MUST_BE_LAST ) ? -1 : 1;
}
}
}

View File

@ -75,6 +75,12 @@ public class UserException extends ReviewedStingException {
}
}
public static class IncompatibleReadFiltersException extends CommandLineException {
public IncompatibleReadFiltersException(final String filter1, final String filter2) {
super(String.format("Two read filters are enabled that are incompatible and cannot be used simultaneously: %s and %s", filter1, filter2));
}
}
public static class MalformedWalkerArgumentsException extends CommandLineException {
public MalformedWalkerArgumentsException(String message) {
super(String.format("Malformed walker argument: %s",message));

View File

@ -29,15 +29,23 @@ import org.broadinstitute.sting.BaseTest;
import org.broadinstitute.sting.commandline.ArgumentException;
import org.broadinstitute.sting.commandline.Tags;
import org.broadinstitute.sting.gatk.datasources.reads.SAMReaderID;
import org.broadinstitute.sting.gatk.iterators.ReadTransformer;
import org.broadinstitute.sting.gatk.walkers.Walker;
import org.broadinstitute.sting.gatk.walkers.readutils.PrintReads;
import org.broadinstitute.sting.utils.GenomeLocParser;
import org.broadinstitute.sting.utils.GenomeLocSortedSet;
import org.broadinstitute.sting.utils.exceptions.UserException;
import org.broadinstitute.sting.utils.sam.ArtificialSAMUtils;
import org.broadinstitute.sting.utils.sam.GATKSAMRecord;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Tests selected functionality in the GenomeAnalysisEngine class
@ -81,4 +89,89 @@ public class GenomeAnalysisEngineUnitTest extends BaseTest {
testEngine.validateSuppliedIntervals();
}
///////////////////////////////////////////////////
// Test the ReadTransformer ordering enforcement //
///////////////////////////////////////////////////
public static class TestReadTransformer extends ReadTransformer {
private OrderingConstraint orderingConstraint = OrderingConstraint.DO_NOT_CARE;
private boolean enabled;
protected TestReadTransformer(final OrderingConstraint orderingConstraint) {
this.orderingConstraint = orderingConstraint;
enabled = true;
}
// need this because PackageUtils will pick up this class as a possible ReadTransformer
protected TestReadTransformer() {
enabled = false;
}
@Override
public OrderingConstraint getOrderingConstraint() { return orderingConstraint; }
@Override
public ApplicationTime initializeSub(final GenomeAnalysisEngine engine, final Walker walker) { return ApplicationTime.HANDLED_IN_WALKER; }
@Override
public boolean enabled() { return enabled; }
@Override
public GATKSAMRecord apply(final GATKSAMRecord read) { return read; }
}
@DataProvider(name = "ReadTransformerData")
public Object[][] makeReadTransformerData() {
List<Object[]> tests = new ArrayList<Object[]>();
for ( final ReadTransformer.OrderingConstraint orderingConstraint1 : ReadTransformer.OrderingConstraint.values() ) {
for ( final ReadTransformer.OrderingConstraint orderingConstraint2 : ReadTransformer.OrderingConstraint.values() ) {
for ( final ReadTransformer.OrderingConstraint orderingConstraint3 : ReadTransformer.OrderingConstraint.values() ) {
tests.add(new Object[]{orderingConstraint1, orderingConstraint2, orderingConstraint3});
}
}
}
return tests.toArray(new Object[][]{});
}
@Test(dataProvider = "ReadTransformerData")
public void testReadTransformer(final ReadTransformer.OrderingConstraint oc1, final ReadTransformer.OrderingConstraint oc2, final ReadTransformer.OrderingConstraint oc3) {
final GenomeAnalysisEngine testEngine = new GenomeAnalysisEngine();
final List<ReadTransformer> readTransformers = new ArrayList<ReadTransformer>(3);
readTransformers.add(new TestReadTransformer(oc1));
readTransformers.add(new TestReadTransformer(oc2));
readTransformers.add(new TestReadTransformer(oc3));
final boolean shouldThrowException = numWithConstraint(ReadTransformer.OrderingConstraint.MUST_BE_FIRST, oc1, oc2, oc3) > 1 ||
numWithConstraint(ReadTransformer.OrderingConstraint.MUST_BE_LAST, oc1, oc2, oc3) > 1;
try {
testEngine.setReadTransformers(readTransformers);
Assert.assertFalse(shouldThrowException);
Assert.assertEquals(testEngine.getReadTransformers().size(), 3);
Assert.assertTrue(testEngine.getReadTransformers().get(1).getOrderingConstraint() != ReadTransformer.OrderingConstraint.MUST_BE_FIRST);
Assert.assertTrue(testEngine.getReadTransformers().get(2).getOrderingConstraint() != ReadTransformer.OrderingConstraint.MUST_BE_FIRST);
Assert.assertTrue(testEngine.getReadTransformers().get(0).getOrderingConstraint() != ReadTransformer.OrderingConstraint.MUST_BE_LAST);
Assert.assertTrue(testEngine.getReadTransformers().get(1).getOrderingConstraint() != ReadTransformer.OrderingConstraint.MUST_BE_LAST);
} catch (UserException.IncompatibleReadFiltersException e) {
Assert.assertTrue(shouldThrowException);
}
}
private int numWithConstraint(final ReadTransformer.OrderingConstraint target, final ReadTransformer.OrderingConstraint... constraints ) {
int count = 0;
for ( final ReadTransformer.OrderingConstraint constraint : constraints ) {
if ( constraint == target )
count++;
}
return count;
}
}