diff --git a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngine.java b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngine.java index 6e2343d5d..c67ca5d35 100644 --- a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngine.java +++ b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngine.java @@ -34,6 +34,7 @@ import htsjdk.samtools.reference.ReferenceSequenceFile; import htsjdk.variant.vcf.VCFConstants; import org.apache.log4j.Logger; import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection; +import org.broadinstitute.gatk.engine.filters.DisableableReadFilter; import org.broadinstitute.gatk.utils.downsampling.DownsampleType; import org.broadinstitute.gatk.utils.ValidationExclusion; import org.broadinstitute.gatk.engine.datasources.reads.*; @@ -354,7 +355,7 @@ public class GenomeAnalysisEngine { final List filters = new LinkedList<>(); // First add the user requested filters - if (this.getArguments().readGroupBlackList != null && this.getArguments().readGroupBlackList.size() > 0) + if (this.getArguments().readGroupBlackList != null && !this.getArguments().readGroupBlackList.isEmpty()) filters.add(new ReadGroupBlackListFilter(this.getArguments().readGroupBlackList)); for(final String filterName: this.getArguments().readFilters) filters.add(this.getFilterManager().createByName(filterName)); @@ -363,6 +364,20 @@ public class GenomeAnalysisEngine { // users need to apply filters that fix up reads that would be removed by default walker filters filters.addAll(WalkerManager.getReadFilters(walker,this.getFilterManager())); + // disable user-specified read filters, if allowed + for(final String filterName: this.getArguments().disabledReadFilters) { + ReadFilter filterToDisable = this.getFilterManager().createByName(filterName); + if (! (filterToDisable instanceof DisableableReadFilter)) + throw new IllegalStateException(filterToDisable + " cannot be disabled"); + + // so we're not trying to modify the list we're iterating over + List filtersCopy = new ArrayList<>(filters); + for (ReadFilter filter : filtersCopy) { + if (filter.getClass() == filterToDisable.getClass()) + filters.remove(filter); + } + } + return Collections.unmodifiableList(filters); } diff --git a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/WalkerManager.java b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/WalkerManager.java index 81e22c247..0660cb015 100644 --- a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/WalkerManager.java +++ b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/WalkerManager.java @@ -25,6 +25,7 @@ package org.broadinstitute.gatk.engine; +import org.broadinstitute.gatk.engine.filters.DisableableReadFilter; import org.broadinstitute.gatk.engine.walkers.*; import org.broadinstitute.gatk.utils.commandline.Hidden; import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource; @@ -420,12 +421,20 @@ public class WalkerManager extends PluginManager { public static Collection> getReadFilterTypes(Class walkerClass) { List> filterTypes = new ArrayList>(); while(walkerClass != null) { + // Add the read filters in the ReadFilters annotation if(walkerClass.isAnnotationPresent(ReadFilters.class)) { for ( Class c : walkerClass.getAnnotation(ReadFilters.class).value() ) { if( !filterTypes.contains(c) ) filterTypes.add(c); } } + // Remove read filters in the DisabledReadFilters annotation + if(walkerClass.isAnnotationPresent(DisabledReadFilters.class)) { + for ( Class c : walkerClass.getAnnotation(DisabledReadFilters.class).value() ) { + if ( filterTypes.contains(c) ) + filterTypes.remove(c); + } + } walkerClass = walkerClass.getSuperclass(); } return filterTypes; diff --git a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/arguments/GATKArgumentCollection.java b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/arguments/GATKArgumentCollection.java index 5b6ae51f5..a796a22de 100644 --- a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/arguments/GATKArgumentCollection.java +++ b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/arguments/GATKArgumentCollection.java @@ -117,11 +117,14 @@ public class GATKArgumentCollection { * documentation. Note that the read name format is e.g. MalformedReadFilter, but at the command line the filter * name should be given without the Filter suffix; e.g. -rf MalformedRead (NOT -rf MalformedReadFilter, which is not * recognized by the program). Note also that some read filters are applied by default for some analysis tools; this - * is specified in each tool's documentation. The default filters cannot be disabled. + * is specified in each tool's documentation. The default filters can only be disabled if they are DisableableReadFilters. */ @Argument(fullName = "read_filter", shortName = "rf", doc = "Filters to apply to reads before analysis", required = false) public final List readFilters = new ArrayList<>(); + @Argument(fullName = "disable_read_filter", shortName = "drf", doc = "Read filters to disable", required = false) + public final List disabledReadFilters = new ArrayList<>(); + @ArgumentCollection public IntervalArgumentCollection intervalArguments = new IntervalArgumentCollection(); /** diff --git a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/filters/DisableableReadFilter.java b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/filters/DisableableReadFilter.java new file mode 100644 index 000000000..9c44be3de --- /dev/null +++ b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/filters/DisableableReadFilter.java @@ -0,0 +1,35 @@ +/* +* Copyright (c) 2012 The Broad Institute +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +package org.broadinstitute.gatk.engine.filters; + +import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature; +import org.broadinstitute.gatk.utils.help.HelpConstants; + +@DocumentedGATKFeature( + groupName = HelpConstants.DOCS_CAT_RF, + summary = "A ReadFilter which can be disabled by using the --disable_read_filter parameter" ) +public abstract class DisableableReadFilter extends ReadFilter { +} diff --git a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/filters/DuplicateReadFilter.java b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/filters/DuplicateReadFilter.java index 52861e257..aa45b250a 100644 --- a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/filters/DuplicateReadFilter.java +++ b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/filters/DuplicateReadFilter.java @@ -59,7 +59,7 @@ import htsjdk.samtools.SAMRecord; * @since Dec 9, 2009 */ -public class DuplicateReadFilter extends ReadFilter { +public class DuplicateReadFilter extends DisableableReadFilter { public boolean filterOut( final SAMRecord read ) { return read.getDuplicateReadFlag(); } diff --git a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/walkers/DisabledReadFilters.java b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/walkers/DisabledReadFilters.java new file mode 100644 index 000000000..ccf09fd40 --- /dev/null +++ b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/walkers/DisabledReadFilters.java @@ -0,0 +1,41 @@ +/* +* Copyright (c) 2012 The Broad Institute +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, +* copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following +* conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +package org.broadinstitute.gatk.engine.walkers; + +import htsjdk.samtools.filter.SamRecordFilter; + +import java.lang.annotation.*; + +/** + * An annotation to describe which inherited ReadFilters to disable + */ +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface DisabledReadFilters { + public Class[] value() default {}; +} diff --git a/public/gatk-engine/src/test/java/org/broadinstitute/gatk/engine/EngineFeaturesIntegrationTest.java b/public/gatk-engine/src/test/java/org/broadinstitute/gatk/engine/EngineFeaturesIntegrationTest.java index 65605fec3..bfa3bfbc3 100644 --- a/public/gatk-engine/src/test/java/org/broadinstitute/gatk/engine/EngineFeaturesIntegrationTest.java +++ b/public/gatk-engine/src/test/java/org/broadinstitute/gatk/engine/EngineFeaturesIntegrationTest.java @@ -32,6 +32,7 @@ import org.broadinstitute.gatk.utils.commandline.*; import org.broadinstitute.gatk.utils.contexts.AlignmentContext; import org.broadinstitute.gatk.utils.contexts.ReferenceContext; import org.broadinstitute.gatk.engine.filters.MappingQualityUnavailableFilter; +import org.broadinstitute.gatk.engine.filters.DuplicateReadFilter; import org.broadinstitute.gatk.utils.refdata.RefMetaDataTracker; import org.broadinstitute.gatk.utils.collections.Pair; import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException; @@ -150,8 +151,9 @@ public class EngineFeaturesIntegrationTest extends WalkerTest { // // -------------------------------------------------------------------------------- - @ReadFilters({MappingQualityUnavailableFilter.class}) - public static class DummyReadWalkerWithMapqUnavailableFilter extends ReadWalker { + @ReadFilters({MappingQualityUnavailableFilter.class, DuplicateReadFilter.class}) + @DisabledReadFilters({DuplicateReadFilter.class}) + public static class DummyReadWalkerWithFilters extends ReadWalker { @Output PrintStream out; @@ -179,11 +181,27 @@ public class EngineFeaturesIntegrationTest extends WalkerTest { @Test(enabled = true) public void testUserReadFilterAppliedBeforeWalker() { WalkerTestSpec spec = new WalkerTestSpec("-R " + b37KGReference + " -I " + privateTestDir + "allMAPQ255.bam" - + " -T DummyReadWalkerWithMapqUnavailableFilter -o %s -L MT -rf ReassignMappingQuality", + + " -T DummyReadWalkerWithFilters -o %s -L MT -rf ReassignMappingQuality", 1, Arrays.asList("ecf27a776cdfc771defab1c5d19de9ab")); executeTest("testUserReadFilterAppliedBeforeWalker", spec); } + @Test(enabled = true) + public void testUserReadFilterDisabledAppliedBeforeWalker() { + WalkerTestSpec spec = new WalkerTestSpec("-R " + b37KGReference + " -I " + privateTestDir + "allMAPQ255.bam" + + " -T DummyReadWalkerWithFilters -o %s -L MT -drf DuplicateRead", + 1, Arrays.asList("897316929176464ebc9ad085f31e7284")); + executeTest("testUserReadFilterDisabledAppliedBeforeWalker", spec); + } + + @Test( enabled = true, expectedExceptions = RuntimeException.class ) + public void testUserReadFilterDisabledAppliedBeforeWalkerException() { + WalkerTestSpec spec = new WalkerTestSpec("-R " + b37KGReference + " -I " + privateTestDir + "allMAPQ255.bam" + + " -T DummyReadWalkerWithFilters -o %s -L MT -drf ReassignMappingQuality", + 1, Arrays.asList("")); + executeTest("testUserReadFilterDisabledAppliedBeforeWalkerException", spec); + } + @Test public void testNegativeCompress() { testBadCompressArgument(-1);