From 8a78414432226daceccccb4b38463c0826fb0f19 Mon Sep 17 00:00:00 2001 From: David Roazen Date: Mon, 11 Jul 2011 12:10:11 -0400 Subject: [PATCH 02/83] Removed TileCovariate as a dependency for AnalyzeCovariates.jar --- public/packages/AnalyzeCovariates.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/public/packages/AnalyzeCovariates.xml b/public/packages/AnalyzeCovariates.xml index 1862d6cbb..7e31934df 100644 --- a/public/packages/AnalyzeCovariates.xml +++ b/public/packages/AnalyzeCovariates.xml @@ -10,7 +10,6 @@ - From 86890c63574eba41bbbce6c52e2614f6c81b6f27 Mon Sep 17 00:00:00 2001 From: Christopher Hartl Date: Mon, 11 Jul 2011 16:16:15 -0400 Subject: [PATCH 04/83] N and K (in binomial probability) got switched in RFA Walker with the last commit. No longer will NaNs be produced. Added: TableToVCF. Kind of a longer-term project, but there are lots of variant calls available in a weird tabular format. I used this to convert Ju Et Al small indels to VCF. I'll check against the 1000G ASN superpopulation calls to see if we see a good amount of recapitulation, and if so, i'll put them in unvalidated comparisons. Minor chances to the TableCodec and TableFeatures to allow for this (the codec can sometimes drop a column, and the feature now allows you to grab on to its header). --- .../sting/gatk/refdata/features/table/TableCodec.java | 0 .../sting/gatk/refdata/features/table/TableFeature.java | 6 +++++- .../broadinstitute/sting/utils/variantcontext/Allele.java | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) mode change 100644 => 100755 public/java/src/org/broadinstitute/sting/gatk/refdata/features/table/TableCodec.java mode change 100644 => 100755 public/java/src/org/broadinstitute/sting/gatk/refdata/features/table/TableFeature.java diff --git a/public/java/src/org/broadinstitute/sting/gatk/refdata/features/table/TableCodec.java b/public/java/src/org/broadinstitute/sting/gatk/refdata/features/table/TableCodec.java old mode 100644 new mode 100755 diff --git a/public/java/src/org/broadinstitute/sting/gatk/refdata/features/table/TableFeature.java b/public/java/src/org/broadinstitute/sting/gatk/refdata/features/table/TableFeature.java old mode 100644 new mode 100755 index 6ff0384a0..4b4ebe450 --- a/public/java/src/org/broadinstitute/sting/gatk/refdata/features/table/TableFeature.java +++ b/public/java/src/org/broadinstitute/sting/gatk/refdata/features/table/TableFeature.java @@ -55,10 +55,14 @@ public class TableFeature implements Feature { } public List getAllValues() { - return getValuesTo(values.size()-1); + return getValuesTo(values.size()); } public List getValuesTo(int columnPosition) { return values.subList(0,columnPosition); } + + public List getHeader() { + return keys; + } } diff --git a/public/java/src/org/broadinstitute/sting/utils/variantcontext/Allele.java b/public/java/src/org/broadinstitute/sting/utils/variantcontext/Allele.java index a9ba46159..901de6fae 100755 --- a/public/java/src/org/broadinstitute/sting/utils/variantcontext/Allele.java +++ b/public/java/src/org/broadinstitute/sting/utils/variantcontext/Allele.java @@ -108,7 +108,7 @@ public class Allele implements Comparable { this.bases = bases; if ( ! acceptableAlleleBases(bases) ) - throw new IllegalArgumentException("Unexpected base in allele bases " + new String(bases)); + throw new IllegalArgumentException("Unexpected base in allele bases \'" + new String(bases)+"\'"); } private Allele(String bases, boolean isRef) { From e3748675dbd518042ad67cfc653c7f1a5f89b327 Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Mon, 11 Jul 2011 17:40:45 -0400 Subject: [PATCH 05/83] Support for VCF 4.1 header counts --- .../annotator/DepthPerAlleleBySample.java | 3 +- .../ReadDepthAndAllelicFractionBySample.java | 5 +- .../gatk/walkers/annotator/SampleList.java | 3 +- .../utils/codecs/vcf/StandardVCFWriter.java | 11 +-- .../codecs/vcf/VCFCompoundHeaderLine.java | 91 +++++++++++++++---- .../sting/utils/codecs/vcf/VCFConstants.java | 2 + .../utils/codecs/vcf/VCFFormatHeaderLine.java | 4 + .../utils/codecs/vcf/VCFHeaderLineCount.java | 8 ++ .../utils/codecs/vcf/VCFInfoHeaderLine.java | 4 + 9 files changed, 101 insertions(+), 30 deletions(-) create mode 100644 public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFHeaderLineCount.java diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/DepthPerAlleleBySample.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/DepthPerAlleleBySample.java index 754d28dfd..ee66b50ee 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/DepthPerAlleleBySample.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/DepthPerAlleleBySample.java @@ -1,5 +1,6 @@ package org.broadinstitute.sting.gatk.walkers.annotator; +import org.broadinstitute.sting.utils.codecs.vcf.VCFHeaderLineCount; import org.broadinstitute.sting.utils.variantcontext.Allele; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; @@ -142,5 +143,5 @@ public class DepthPerAlleleBySample implements GenotypeAnnotation, StandardAnnot // public String getIndelBases() public List getKeyNames() { return Arrays.asList("AD"); } - public List getDescriptions() { return Arrays.asList(new VCFFormatHeaderLine(getKeyNames().get(0), VCFCompoundHeaderLine.UNBOUNDED, VCFHeaderLineType.Integer, "Allelic depths for the ref and alt alleles in the order listed")); } + public List getDescriptions() { return Arrays.asList(new VCFFormatHeaderLine(getKeyNames().get(0), VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "Allelic depths for the ref and alt alleles in the order listed")); } } \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ReadDepthAndAllelicFractionBySample.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ReadDepthAndAllelicFractionBySample.java index f287549bb..a670532af 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ReadDepthAndAllelicFractionBySample.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ReadDepthAndAllelicFractionBySample.java @@ -29,6 +29,7 @@ import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.walkers.annotator.interfaces.GenotypeAnnotation; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; +import org.broadinstitute.sting.utils.codecs.vcf.VCFHeaderLineCount; import org.broadinstitute.sting.utils.pileup.ReadBackedPileup; import org.broadinstitute.sting.utils.pileup.PileupElement; import org.broadinstitute.sting.utils.pileup.ReadBackedExtendedEventPileup; @@ -200,8 +201,8 @@ public class ReadDepthAndAllelicFractionBySample implements GenotypeAnnotation { 1, VCFHeaderLineType.Integer, "Total read depth per sample, including MQ0"), - new VCFFormatHeaderLine(getKeyNames().get(1), - VCFCompoundHeaderLine.UNBOUNDED, + new VCFFormatHeaderLine(getKeyNames().get(1), + VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Float, "Fractions of reads (excluding MQ0 from both ref and alt) supporting each reported alternative allele, per sample")); } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/SampleList.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/SampleList.java index 82f16be42..e2fd2a3d4 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/SampleList.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/SampleList.java @@ -25,6 +25,7 @@ package org.broadinstitute.sting.gatk.walkers.annotator; +import org.broadinstitute.sting.utils.codecs.vcf.VCFHeaderLineCount; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.utils.codecs.vcf.VCFHeaderLineType; @@ -65,5 +66,5 @@ public class SampleList implements InfoFieldAnnotation { public List getKeyNames() { return Arrays.asList("Samples"); } - public List getDescriptions() { return Arrays.asList(new VCFInfoHeaderLine("Samples", VCFInfoHeaderLine.UNBOUNDED, VCFHeaderLineType.String, "List of polymorphic samples")); } + public List getDescriptions() { return Arrays.asList(new VCFInfoHeaderLine("Samples", VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.String, "List of polymorphic samples")); } } diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java index 31251c089..230773310 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java @@ -360,14 +360,7 @@ public class StandardVCFWriter implements VCFWriter { if ( !entry.getValue().equals("") ) { int numVals = 1; VCFInfoHeaderLine metaData = mHeader.getInfoHeaderLine(key); - if ( metaData != null ) - numVals = metaData.getCount(); - - // take care of unbounded encoding - if ( numVals == VCFInfoHeaderLine.UNBOUNDED ) - numVals = 1; - - if ( numVals > 0 ) { + if ( metaData != null && (metaData.getCountType() != VCFHeaderLineCount.INTEGER || metaData.getCount() > 0) ) { mWriter.write("="); mWriter.write(entry.getValue()); } @@ -423,7 +416,7 @@ public class StandardVCFWriter implements VCFWriter { VCFFormatHeaderLine metaData = mHeader.getFormatHeaderLine(key); if ( metaData != null ) { - int numInFormatField = metaData.getCount(); + int numInFormatField = metaData.getCount(vc.getAlternateAlleles().size()); if ( numInFormatField > 1 && val.equals(VCFConstants.MISSING_VALUE_v4) ) { // If we have a missing field but multiple values are expected, we need to construct a new string with all fields. // For example, if Number=2, the string has to be ".,." diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCompoundHeaderLine.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCompoundHeaderLine.java index a799161ad..49f9ab184 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCompoundHeaderLine.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCompoundHeaderLine.java @@ -24,6 +24,8 @@ package org.broadinstitute.sting.utils.codecs.vcf; +import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; + import java.util.Arrays; import java.util.LinkedHashMap; import java.util.Map; @@ -43,26 +45,43 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF // the field types private String name; - private int count; + private int count = -1; + private VCFHeaderLineCount countType; private String description; private VCFHeaderLineType type; // access methods public String getName() { return name; } - public int getCount() { return count; } public String getDescription() { return description; } public VCFHeaderLineType getType() { return type; } + public VCFHeaderLineCount getCountType() { return countType; } + public int getCount() { + if ( countType != VCFHeaderLineCount.INTEGER ) + throw new ReviewedStingException("Asking for header line count when type is not an integer"); + return count; + } - // - public void setNumberToUnbounded() { this.count = UNBOUNDED; } + // utility method + public int getCount(int numAltAlleles) { + int myCount; + switch ( countType ) { + case INTEGER: myCount = count; break; + case UNBOUNDED: myCount = -1; break; + case A: myCount = numAltAlleles; break; + case G: myCount = ((numAltAlleles + 1) * (numAltAlleles + 2) / 2); break; + default: throw new ReviewedStingException("Unknown count type: " + countType); + } + return myCount; + } + + public void setNumberToUnbounded() { + countType = VCFHeaderLineCount.UNBOUNDED; + count = -1; + } // our type of line, i.e. format, info, etc private final SupportedHeaderLineType lineType; - // line numerical values are allowed to be unbounded (or unknown), which is - // marked with a dot (.) - public static final int UNBOUNDED = -1; // the value we store internally for unbounded types - /** * create a VCF format header line * @@ -74,6 +93,7 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF protected VCFCompoundHeaderLine(String name, int count, VCFHeaderLineType type, String description, SupportedHeaderLineType lineType) { super(lineType.toString(), ""); this.name = name; + this.countType = VCFHeaderLineCount.INTEGER; this.count = count; this.type = type; this.description = description; @@ -81,6 +101,24 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF validate(); } + /** + * create a VCF format header line + * + * @param name the name for this header line + * @param count the count type for this header line + * @param type the type for this header line + * @param description the description for this header line + */ + protected VCFCompoundHeaderLine(String name, VCFHeaderLineCount count, VCFHeaderLineType type, String description, SupportedHeaderLineType lineType) { + super(lineType.toString(), ""); + this.name = name; + this.countType = count; + this.type = type; + this.description = description; + this.lineType = lineType; + validate(); + } + /** * create a VCF format header line * @@ -92,9 +130,22 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF super(lineType.toString(), ""); Map mapping = VCFHeaderLineTranslator.parseLine(version,line, Arrays.asList("ID","Number","Type","Description")); name = mapping.get("ID"); - count = (version == VCFHeaderVersion.VCF4_0 || version == VCFHeaderVersion.VCF4_1) ? - mapping.get("Number").equals(VCFConstants.UNBOUNDED_ENCODING_v4) ? UNBOUNDED : Integer.valueOf(mapping.get("Number")) : - mapping.get("Number").equals(VCFConstants.UNBOUNDED_ENCODING_v3) ? UNBOUNDED : Integer.valueOf(mapping.get("Number")); + count = -1; + final String numberStr = mapping.get("Number"); + if ( numberStr.equals(VCFConstants.PER_ALLELE_COUNT) ) { + countType = VCFHeaderLineCount.A; + } else if ( numberStr.equals(VCFConstants.PER_GENOTYPE_COUNT) ) { + countType = VCFHeaderLineCount.G; + } else if ( ((version == VCFHeaderVersion.VCF4_0 || version == VCFHeaderVersion.VCF4_1) && + numberStr.equals(VCFConstants.UNBOUNDED_ENCODING_v4)) || + ((version == VCFHeaderVersion.VCF3_2 || version == VCFHeaderVersion.VCF3_3) && + numberStr.equals(VCFConstants.UNBOUNDED_ENCODING_v3)) ) { + countType = VCFHeaderLineCount.UNBOUNDED; + } else { + countType = VCFHeaderLineCount.INTEGER; + count = Integer.valueOf(numberStr); + + } type = VCFHeaderLineType.valueOf(mapping.get("Type")); if (type == VCFHeaderLineType.Flag && !allowFlagValues()) throw new IllegalArgumentException("Flag is an unsupported type for this kind of field"); @@ -121,7 +172,15 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF protected String toStringEncoding() { Map map = new LinkedHashMap(); map.put("ID", name); - map.put("Number", count == UNBOUNDED ? VCFConstants.UNBOUNDED_ENCODING_v4 : count); + Object number; + switch ( countType ) { + case A: number = VCFConstants.PER_ALLELE_COUNT; break; + case G: number = VCFConstants.PER_GENOTYPE_COUNT; break; + case UNBOUNDED: number = VCFConstants.UNBOUNDED_ENCODING_v4; break; + case INTEGER: + default: number = count; + } + map.put("Number", number); map.put("Type", type); map.put("Description", description); return lineType.toString() + "=" + VCFHeaderLine.toStringEncoding(map); @@ -136,15 +195,13 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF if ( !(o instanceof VCFCompoundHeaderLine) ) return false; VCFCompoundHeaderLine other = (VCFCompoundHeaderLine)o; - return name.equals(other.name) && - count == other.count && - description.equals(other.description) && - type == other.type && - lineType == other.lineType; + return equalsExcludingDescription(other) && + description.equals(other.description); } public boolean equalsExcludingDescription(VCFCompoundHeaderLine other) { return count == other.count && + countType == other.countType && type == other.type && lineType == other.lineType && name.equals(other.name); diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFConstants.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFConstants.java index 695c46c27..91cf86c70 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFConstants.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFConstants.java @@ -99,6 +99,8 @@ public final class VCFConstants { public static final String MISSING_DEPTH_v3 = "-1"; public static final String UNBOUNDED_ENCODING_v4 = "."; public static final String UNBOUNDED_ENCODING_v3 = "-1"; + public static final String PER_ALLELE_COUNT = "A"; + public static final String PER_GENOTYPE_COUNT = "G"; public static final String EMPTY_ALLELE = "."; public static final String EMPTY_GENOTYPE = "./."; public static final double MAX_GENOTYPE_QUAL = 99.0; diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFormatHeaderLine.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFormatHeaderLine.java index 352be3e97..f68cb670b 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFormatHeaderLine.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFormatHeaderLine.java @@ -16,6 +16,10 @@ public class VCFFormatHeaderLine extends VCFCompoundHeaderLine { throw new IllegalArgumentException("Flag is an unsupported type for format fields"); } + public VCFFormatHeaderLine(String name, VCFHeaderLineCount count, VCFHeaderLineType type, String description) { + super(name, count, type, description, SupportedHeaderLineType.INFO); + } + protected VCFFormatHeaderLine(String line, VCFHeaderVersion version) { super(line, version, SupportedHeaderLineType.FORMAT); } diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFHeaderLineCount.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFHeaderLineCount.java new file mode 100644 index 000000000..d615c7c78 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFHeaderLineCount.java @@ -0,0 +1,8 @@ +package org.broadinstitute.sting.utils.codecs.vcf; + +/** + * the count encodings we use for fields in VCF header lines + */ +public enum VCFHeaderLineCount { + INTEGER, A, G, UNBOUNDED; +} diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFInfoHeaderLine.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFInfoHeaderLine.java index 135a5c1a1..9b20f38a1 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFInfoHeaderLine.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFInfoHeaderLine.java @@ -13,6 +13,10 @@ public class VCFInfoHeaderLine extends VCFCompoundHeaderLine { super(name, count, type, description, SupportedHeaderLineType.INFO); } + public VCFInfoHeaderLine(String name, VCFHeaderLineCount count, VCFHeaderLineType type, String description) { + super(name, count, type, description, SupportedHeaderLineType.INFO); + } + protected VCFInfoHeaderLine(String line, VCFHeaderVersion version) { super(line, version, SupportedHeaderLineType.INFO); } From e93052a51e88ddb77c8ce71cf6a14a449ca3b1aa Mon Sep 17 00:00:00 2001 From: Khalid Shakir Date: Mon, 11 Jul 2011 19:17:58 -0400 Subject: [PATCH 06/83] When generating the QGraph, don't regenerate if there aren't scatter/gather jobs. Fixed a display issue with the number of milliseconds that Queue has tried to contact LSF. --- .../sting/queue/engine/QGraph.scala | 44 ++++++++++--------- .../queue/engine/lsf/Lsf706JobRunner.scala | 6 +-- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/public/scala/src/org/broadinstitute/sting/queue/engine/QGraph.scala b/public/scala/src/org/broadinstitute/sting/queue/engine/QGraph.scala index bfcc4d48c..8ed3f84c1 100755 --- a/public/scala/src/org/broadinstitute/sting/queue/engine/QGraph.scala +++ b/public/scala/src/org/broadinstitute/sting/queue/engine/QGraph.scala @@ -138,30 +138,32 @@ class QGraph extends Logging { validate() if (running && numMissingValues == 0) { - logger.info("Generating scatter gather jobs.") val scatterGathers = jobGraph.edgeSet.filter(edge => scatterGatherable(edge)) + if (!scatterGathers.isEmpty) { + logger.info("Generating scatter gather jobs.") - var addedFunctions = List.empty[QFunction] - for (scatterGather <- scatterGathers) { - val functions = scatterGather.asInstanceOf[FunctionEdge] - .function.asInstanceOf[ScatterGatherableFunction] - .generateFunctions() - addedFunctions ++= functions + var addedFunctions = List.empty[QFunction] + for (scatterGather <- scatterGathers) { + val functions = scatterGather.asInstanceOf[FunctionEdge] + .function.asInstanceOf[ScatterGatherableFunction] + .generateFunctions() + addedFunctions ++= functions + } + + logger.info("Removing original jobs.") + this.jobGraph.removeAllEdges(scatterGathers) + prune() + + logger.info("Adding scatter gather jobs.") + addedFunctions.foreach(function => if (running) this.add(function)) + + logger.info("Regenerating graph.") + fill + val scatterGatherDotFile = if (settings.expandedDotFile != null) settings.expandedDotFile else settings.dotFile + if (scatterGatherDotFile != null) + renderToDot(scatterGatherDotFile) + validate() } - - logger.info("Removing original jobs.") - this.jobGraph.removeAllEdges(scatterGathers) - prune() - - logger.info("Adding scatter gather jobs.") - addedFunctions.foreach(function => if (running) this.add(function)) - - logger.info("Regenerating graph.") - fill - val scatterGatherDotFile = if (settings.expandedDotFile != null) settings.expandedDotFile else settings.dotFile - if (scatterGatherDotFile != null) - renderToDot(scatterGatherDotFile) - validate() } } diff --git a/public/scala/src/org/broadinstitute/sting/queue/engine/lsf/Lsf706JobRunner.scala b/public/scala/src/org/broadinstitute/sting/queue/engine/lsf/Lsf706JobRunner.scala index 57d133dfe..ac2f036b4 100644 --- a/public/scala/src/org/broadinstitute/sting/queue/engine/lsf/Lsf706JobRunner.scala +++ b/public/scala/src/org/broadinstitute/sting/queue/engine/lsf/Lsf706JobRunner.scala @@ -286,11 +286,11 @@ object Lsf706JobRunner extends Logging { // LSB_SHAREDIR/cluster_name/logdir/lsb.acct (man bacct) // LSB_SHAREDIR/cluster_name/logdir/lsb.events (man bhist) logger.debug("Job Id %s status / exitStatus / exitInfo: ??? / ??? / ???".format(runner.jobId)) - val unknownStatusSeconds = (System.currentTimeMillis - runner.lastStatusUpdate) - if (unknownStatusSeconds > (unknownStatusMaxSeconds * 1000L)) { + val unknownStatusMillis = (System.currentTimeMillis - runner.lastStatusUpdate) + if (unknownStatusMillis > (unknownStatusMaxSeconds * 1000L)) { // Unknown status has been returned for a while now. runner.updateStatus(RunnerStatus.FAILED) - logger.error("Unable to read LSF status for %d minutes: job id %d: %s".format(unknownStatusSeconds/60, runner.jobId, runner.function.description)) + logger.error("Unable to read LSF status for %0.2f minutes: job id %d: %s".format(unknownStatusMillis/(60 * 1000D), runner.jobId, runner.function.description)) } } From 5e593793af43153e844f69c0f0df367b1d56a658 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Mon, 11 Jul 2011 23:10:27 -0400 Subject: [PATCH 07/83] DiffEngine utility function simpleDiffFiles printSummaryReport now uses GATKReport for nice formating Moved print formatting arguments into inner class provided to printing functions themselves, not the class BAMDiffableReader only reads 1000 entries to avoid performance issue. Work around for BAM files with non-unique names Uncommented all of the incorrectly commented out CombineVariants integrationtests BaseTest now uses DiffEngine to provide inline differences to VCF and BAM files --- .../org/broadinstitute/sting/BaseTest.java | 15 +- .../CombineVariantsIntegrationTest.java | 142 +++++++++--------- 2 files changed, 83 insertions(+), 74 deletions(-) diff --git a/public/java/test/org/broadinstitute/sting/BaseTest.java b/public/java/test/org/broadinstitute/sting/BaseTest.java index b469c8a41..b3e422ba9 100755 --- a/public/java/test/org/broadinstitute/sting/BaseTest.java +++ b/public/java/test/org/broadinstitute/sting/BaseTest.java @@ -4,6 +4,7 @@ import org.apache.commons.io.FileUtils; import org.apache.log4j.*; import org.apache.log4j.spi.LoggingEvent; import org.broadinstitute.sting.commandline.CommandLineUtils; +import org.broadinstitute.sting.gatk.walkers.diffengine.DiffEngine; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; import org.testng.Assert; @@ -334,11 +335,14 @@ public abstract class BaseTest { if (parameterize || expectedMD5.equals("")) { // Don't assert - } else { - Assert.assertEquals(filemd5sum, expectedMD5, name + " Mismatching MD5s"); + } else if ( filemd5sum.equals(expectedMD5) ) { System.out.println(String.format(" => %s PASSED", name)); + } else { + Assert.fail(String.format("%s has mismatching MD5s: expected=%s observed=%s", name, expectedMD5, filemd5sum)); } + + return filemd5sum; } @@ -381,7 +385,12 @@ public abstract class BaseTest { System.out.printf("##### Path to calculated file (MD5=%s): %s%n", filemd5sum, pathToFileMD5File); System.out.printf("##### Diff command: diff %s %s%n", pathToExpectedMD5File, pathToFileMD5File); - // todo -- add support for simple inline display of the first N differences for text file + // inline differences + DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(System.out, 20, 10, 0); + boolean success = DiffEngine.simpleDiffFiles(new File(pathToExpectedMD5File), new File(pathToFileMD5File), params); + if ( success ) + System.out.printf("Note that the above list is not comprehensive. At most 20 lines of output, and 10 specific differences will be listed. Please use -T DiffObjects -R public/testdata/exampleFASTA.fasta -m %s -t %s to explore the differences more freely%n", + pathToExpectedMD5File, pathToFileMD5File); } } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/CombineVariantsIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/CombineVariantsIntegrationTest.java index 33a20f7b5..600718aa0 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/CombineVariantsIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/CombineVariantsIntegrationTest.java @@ -34,76 +34,76 @@ import java.util.Arrays; * Tests CombineVariants */ public class CombineVariantsIntegrationTest extends WalkerTest { -// public static String baseTestString(String args) { -// return "-T CombineVariants -NO_HEADER -L 1:1-50,000,000 -o %s -R " + b36KGReference + args; -// } -// -// public void test1InOut(String file, String md5, boolean vcf3) { -// test1InOut(file, md5, "", vcf3); -// } -// -// public void test1InOut(String file, String md5, String args, boolean vcf3) { -// WalkerTestSpec spec = new WalkerTestSpec( -// baseTestString(" -priority v1 -B:v1,VCF" + (vcf3 ? "3 " : " ") + validationDataLocation + file + args), -// 1, -// Arrays.asList(md5)); -// executeTest("testInOut1--" + file, spec); -// } -// -// public void combine2(String file1, String file2, String args, String md5, boolean vcf3) { -// WalkerTestSpec spec = new WalkerTestSpec( -// baseTestString(" -priority v1,v2 -B:v1,VCF" + (vcf3 ? "3 " : " ") + validationDataLocation + file1 + " -B:v2,VCF" + (vcf3 ? "3 " : " ") + validationDataLocation + file2 + args), -// 1, -// Arrays.asList(md5)); -// executeTest("combine2 1:" + new File(file1).getName() + " 2:" + new File(file2).getName(), spec); -// } -// -// public void combineSites(String args, String md5) { -// String file1 = "1000G_omni2.5.b37.sites.vcf"; -// String file2 = "hapmap_3.3.b37.sites.vcf"; -// WalkerTestSpec spec = new WalkerTestSpec( -// "-T CombineVariants -NO_HEADER -o %s -R " + b37KGReference -// + " -L 1:1-10,000,000 -B:omni,VCF " + validationDataLocation + file1 -// + " -B:hm3,VCF " + validationDataLocation + file2 + args, -// 1, -// Arrays.asList(md5)); -// executeTest("combineSites 1:" + new File(file1).getName() + " 2:" + new File(file2).getName() + " args = " + args, spec); -// } -// -// -// @Test public void test1SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "2117fff6e0d182cd20be508e9661829c", true); } -// @Test public void test2SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "2cfaf7af3dd119df08b8a9c1f72e2f93", " -setKey foo", true); } -// @Test public void test3SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "1474ac0fde2ce42a3c24f1c97eab333e", " -setKey null", true); } -// @Test public void testOfficialCEUPilotCalls() { test1InOut("CEU.trio.2010_03.genotypes.vcf.gz", "7fc66df048a0ab08cf507906e1d4a308", false); } // official project VCF files in tabix format -// -// @Test public void test1Indel1() { test1InOut("CEU.dindel.vcf4.trio.2010_06.indel.genotypes.vcf", "ec9715f53dbf4531570557c212822f12", false); } -// @Test public void test1Indel2() { test1InOut("CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "f1072be5f5c6ee810276d9ca6537224d", false); } -// -// @Test public void combineTrioCalls() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "YRI.trio.2010_03.genotypes.vcf.gz", "", "b77a1eec725201d9d8e74ee0c45638d3", false); } // official project VCF files in tabix format -// @Test public void combineTrioCallsMin() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "YRI.trio.2010_03.genotypes.vcf.gz", " -minimalVCF", "802977fdfd2f4905b501bb06800f60af", false); } // official project VCF files in tabix format -// @Test public void combine2Indels() { combine2("CEU.dindel.vcf4.trio.2010_06.indel.genotypes.vcf", "CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "", "a67157287dd2b24b5cdf7ebf8fcbbe9a", false); } -// -// @Test public void combineSNPsAndIndels() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "", "e1f4718a179f1196538a33863da04f53", false); } -// -// @Test public void uniqueSNPs() { combine2("pilot2.snps.vcf4.genotypes.vcf", "yri.trio.gatk_glftrio.intersection.annotated.filtered.chr1.vcf", "", "b3783384b7c8e877b971033e90beba48", true); } -// -// @Test public void omniHM3Union() { combineSites(" -filteredRecordsMergeType KEEP_IF_ANY_UNFILTERED", "902e541c87caa72134db6293fc46f0ad"); } -// @Test public void omniHM3Intersect() { combineSites(" -filteredRecordsMergeType KEEP_IF_ALL_UNFILTERED", "f339ad4bb5863b58b9c919ce7d040bb9"); } -// -// @Test public void threeWayWithRefs() { -// WalkerTestSpec spec = new WalkerTestSpec( -// baseTestString(" -B:NA19240_BGI,VCF "+validationDataLocation+"NA19240.BGI.RG.vcf" + -// " -B:NA19240_ILLUMINA,VCF "+validationDataLocation+"NA19240.ILLUMINA.RG.vcf" + -// " -B:NA19240_WUGSC,VCF "+validationDataLocation+"NA19240.WUGSC.RG.vcf" + -// " -B:denovoInfo,VCF "+validationDataLocation+"yri_merged_validation_data_240610.annotated.b36.vcf" + -// " -setKey centerSet" + -// " -filteredRecordsMergeType KEEP_IF_ANY_UNFILTERED" + -// " -priority NA19240_BGI,NA19240_ILLUMINA,NA19240_WUGSC,denovoInfo" + -// " -genotypeMergeOptions UNIQUIFY -L 1"), -// 1, -// Arrays.asList("a07995587b855f3214fb71940bf23c0f")); -// executeTest("threeWayWithRefs", spec); -// } + public static String baseTestString(String args) { + return "-T CombineVariants -NO_HEADER -L 1:1-50,000,000 -o %s -R " + b36KGReference + args; + } + + public void test1InOut(String file, String md5, boolean vcf3) { + test1InOut(file, md5, "", vcf3); + } + + public void test1InOut(String file, String md5, String args, boolean vcf3) { + WalkerTestSpec spec = new WalkerTestSpec( + baseTestString(" -priority v1 -B:v1,VCF" + (vcf3 ? "3 " : " ") + validationDataLocation + file + args), + 1, + Arrays.asList(md5)); + executeTest("testInOut1--" + file, spec); + } + + public void combine2(String file1, String file2, String args, String md5, boolean vcf3) { + WalkerTestSpec spec = new WalkerTestSpec( + baseTestString(" -priority v1,v2 -B:v1,VCF" + (vcf3 ? "3 " : " ") + validationDataLocation + file1 + " -B:v2,VCF" + (vcf3 ? "3 " : " ") + validationDataLocation + file2 + args), + 1, + Arrays.asList(md5)); + executeTest("combine2 1:" + new File(file1).getName() + " 2:" + new File(file2).getName(), spec); + } + + public void combineSites(String args, String md5) { + String file1 = "1000G_omni2.5.b37.sites.vcf"; + String file2 = "hapmap_3.3.b37.sites.vcf"; + WalkerTestSpec spec = new WalkerTestSpec( + "-T CombineVariants -NO_HEADER -o %s -R " + b37KGReference + + " -L 1:1-10,000,000 -B:omni,VCF " + validationDataLocation + file1 + + " -B:hm3,VCF " + validationDataLocation + file2 + args, + 1, + Arrays.asList(md5)); + executeTest("combineSites 1:" + new File(file1).getName() + " 2:" + new File(file2).getName() + " args = " + args, spec); + } + + + @Test public void test1SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "2117fff6e0d182cd20be508e9661829c", true); } + @Test public void test2SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "2cfaf7af3dd119df08b8a9c1f72e2f93", " -setKey foo", true); } + @Test public void test3SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "1474ac0fde2ce42a3c24f1c97eab333e", " -setKey null", true); } + @Test public void testOfficialCEUPilotCalls() { test1InOut("CEU.trio.2010_03.genotypes.vcf.gz", "7fc66df048a0ab08cf507906e1d4a308", false); } // official project VCF files in tabix format + + @Test public void test1Indel1() { test1InOut("CEU.dindel.vcf4.trio.2010_06.indel.genotypes.vcf", "ec9715f53dbf4531570557c212822f12", false); } + @Test public void test1Indel2() { test1InOut("CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "f1072be5f5c6ee810276d9ca6537224d", false); } + + @Test public void combineTrioCalls() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "YRI.trio.2010_03.genotypes.vcf.gz", "", "b77a1eec725201d9d8e74ee0c45638d3", false); } // official project VCF files in tabix format + @Test public void combineTrioCallsMin() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "YRI.trio.2010_03.genotypes.vcf.gz", " -minimalVCF", "802977fdfd2f4905b501bb06800f60af", false); } // official project VCF files in tabix format + @Test public void combine2Indels() { combine2("CEU.dindel.vcf4.trio.2010_06.indel.genotypes.vcf", "CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "", "a67157287dd2b24b5cdf7ebf8fcbbe9a", false); } + + @Test public void combineSNPsAndIndels() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "", "e1f4718a179f1196538a33863da04f53", false); } + + @Test public void uniqueSNPs() { combine2("pilot2.snps.vcf4.genotypes.vcf", "yri.trio.gatk_glftrio.intersection.annotated.filtered.chr1.vcf", "", "b3783384b7c8e877b971033e90beba48", true); } + + @Test public void omniHM3Union() { combineSites(" -filteredRecordsMergeType KEEP_IF_ANY_UNFILTERED", "902e541c87caa72134db6293fc46f0ad"); } + @Test public void omniHM3Intersect() { combineSites(" -filteredRecordsMergeType KEEP_IF_ALL_UNFILTERED", "f339ad4bb5863b58b9c919ce7d040bb9"); } + + @Test public void threeWayWithRefs() { + WalkerTestSpec spec = new WalkerTestSpec( + baseTestString(" -B:NA19240_BGI,VCF "+validationDataLocation+"NA19240.BGI.RG.vcf" + + " -B:NA19240_ILLUMINA,VCF "+validationDataLocation+"NA19240.ILLUMINA.RG.vcf" + + " -B:NA19240_WUGSC,VCF "+validationDataLocation+"NA19240.WUGSC.RG.vcf" + + " -B:denovoInfo,VCF "+validationDataLocation+"yri_merged_validation_data_240610.annotated.b36.vcf" + + " -setKey centerSet" + + " -filteredRecordsMergeType KEEP_IF_ANY_UNFILTERED" + + " -priority NA19240_BGI,NA19240_ILLUMINA,NA19240_WUGSC,denovoInfo" + + " -genotypeMergeOptions UNIQUIFY -L 1"), + 1, + Arrays.asList("a07995587b855f3214fb71940bf23c0f")); + executeTest("threeWayWithRefs", spec); + } // complex examples with filtering, indels, and multiple alleles @@ -119,7 +119,7 @@ public class CombineVariantsIntegrationTest extends WalkerTest { executeTest("combineComplexSites 1:" + new File(file1).getName() + " 2:" + new File(file2).getName() + " args = " + args, spec); } - @Test public void complexTestFull() { combineComplexSites("", "64b991fd3850f83614518f7d71f0532f"); } +// @Test public void complexTestFull() { combineComplexSites("", "64b991fd3850f83614518f7d71f0532f"); } @Test public void complexTestMinimal() { combineComplexSites(" -minimalVCF", "0db9ef50fe54b60426474273d7c7fa99"); } @Test public void complexTestSitesOnly() { combineComplexSites(" -sites_only", "d20acb3d53ba0a02ce92d540ebeda2a9"); } @Test public void complexTestSitesOnlyMinimal() { combineComplexSites(" -sites_only -minimalVCF", "8d1b3d120515f8b56b5a0d10bc5da713"); } From 893cc2e103e25daf01018c86382869ddac0e1f4a Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Mon, 11 Jul 2011 23:15:08 -0400 Subject: [PATCH 08/83] Making the package public, so there's no dependances from public -> private --- .../walkers/diffengine/BAMDiffableReader.java | 122 +++++ .../gatk/walkers/diffengine/DiffElement.java | 118 +++++ .../gatk/walkers/diffengine/DiffEngine.java | 423 ++++++++++++++++++ .../gatk/walkers/diffengine/DiffNode.java | 239 ++++++++++ .../walkers/diffengine/DiffObjectsWalker.java | 113 +++++ .../gatk/walkers/diffengine/DiffValue.java | 90 ++++ .../walkers/diffengine/DiffableReader.java | 50 +++ .../gatk/walkers/diffengine/Difference.java | 58 +++ .../walkers/diffengine/VCFDiffableReader.java | 119 +++++ 9 files changed, 1332 insertions(+) create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/BAMDiffableReader.java create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffElement.java create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffValue.java create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/Difference.java create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/BAMDiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/BAMDiffableReader.java new file mode 100644 index 000000000..f7a395d9d --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/BAMDiffableReader.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +import net.sf.samtools.*; +import net.sf.samtools.util.BlockCompressedInputStream; +import org.broad.tribble.readers.AsciiLineReader; +import org.broad.tribble.readers.LineReader; +import org.broadinstitute.sting.utils.codecs.vcf.VCFCodec; +import org.broadinstitute.sting.utils.codecs.vcf.VCFHeader; +import org.broadinstitute.sting.utils.variantcontext.Genotype; +import org.broadinstitute.sting.utils.variantcontext.VariantContext; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.zip.GZIPInputStream; + + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 1:09 PM + * + * Class implementing diffnode reader for VCF + */ +public class BAMDiffableReader implements DiffableReader { + private final static int MAX_RECORDS_TO_READ = 1000; + @Override + public String getName() { return "BAM"; } + + @Override + public DiffElement readFromFile(File file) { + final SAMFileReader reader = new SAMFileReader(file, null); // null because we don't want it to look for the index + reader.setValidationStringency(SAMFileReader.ValidationStringency.SILENT); + + DiffNode root = DiffNode.rooted(file.getName()); + SAMRecordIterator iterator = reader.iterator(); + + int count = 0; + while ( iterator.hasNext() ) { + if ( count++ > MAX_RECORDS_TO_READ ) + break; + final SAMRecord record = iterator.next(); + + // name is the read name + first of pair + String name = record.getReadName().replace('.', '_'); + if ( record.getReadPairedFlag() ) { + name += record.getFirstOfPairFlag() ? "_1" : "_2"; + } + + DiffNode readRoot = DiffNode.empty(name, root); + + // add fields + readRoot.add("NAME", record.getReadName()); + readRoot.add("FLAGS", record.getFlags()); + readRoot.add("RNAME", record.getReferenceName()); + readRoot.add("POS", record.getAlignmentStart()); + readRoot.add("MAPQ", record.getMappingQuality()); + readRoot.add("CIGAR", record.getCigarString()); + readRoot.add("RNEXT", record.getMateReferenceName()); + readRoot.add("PNEXT", record.getMateAlignmentStart()); + readRoot.add("TLEN", record.getInferredInsertSize()); + readRoot.add("SEQ", record.getReadString()); + readRoot.add("QUAL", record.getBaseQualityString()); + + for ( SAMRecord.SAMTagAndValue xt : record.getAttributes() ) { + readRoot.add(xt.tag, xt.value); + } + + // add record to root + if ( ! root.hasElement(name) ) + // protect ourselves from malformed files + root.add(readRoot); + } + + reader.close(); + + return root.getBinding(); + } + + @Override + public boolean canRead(File file) { + final byte[] BAM_MAGIC = "BAM\1".getBytes(); + final byte[] buffer = new byte[BAM_MAGIC.length]; + try { + FileInputStream fstream = new FileInputStream(file); + new BlockCompressedInputStream(fstream).read(buffer,0,BAM_MAGIC.length); + return Arrays.equals(buffer, BAM_MAGIC); + } catch ( IOException e ) { + return false; + } catch ( net.sf.samtools.FileTruncatedException e ) { + return false; + } + } +} diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffElement.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffElement.java new file mode 100644 index 000000000..eff24bb88 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffElement.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +import com.google.java.contract.*; +import org.broadinstitute.sting.utils.Utils; +import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 12:55 PM + * + * An interface that must be implemented to allow us to calculate differences + * between structured objects + */ +@Invariant({ + "name != null", + "value != null", + "parent != null || name.equals(\"ROOT\")", + "value == null || value.getBinding() == this"}) +public class DiffElement { + public final static DiffElement ROOT = new DiffElement(); + + final private String name; + final private DiffElement parent; + final private DiffValue value; + + /** + * For ROOT only + */ + private DiffElement() { + this.name = "ROOT"; + this.parent = null; + this.value = new DiffValue(this, "ROOT"); + } + + @Requires({"name != null", "parent != null", "value != null"}) + public DiffElement(String name, DiffElement parent, DiffValue value) { + if ( name.equals("ROOT") ) throw new IllegalArgumentException("Cannot use reserved name ROOT"); + this.name = name; + this.parent = parent; + this.value = value; + this.value.setBinding(this); + } + + @Ensures({"result != null"}) + public String getName() { + return name; + } + + public DiffElement getParent() { + return parent; + } + + @Ensures({"result != null"}) + public DiffValue getValue() { + return value; + } + + public boolean isRoot() { return this == ROOT; } + + @Ensures({"result != null"}) + @Override + public String toString() { + return getName() + "=" + getValue().toString(); + } + + public String toString(int offset) { + return (offset > 0 ? Utils.dupString(' ', offset) : 0) + getName() + "=" + getValue().toString(offset); + } + + @Ensures({"result != null"}) + public final String fullyQualifiedName() { + if ( isRoot() ) + return ""; + else if ( parent.isRoot() ) + return name; + else + return parent.fullyQualifiedName() + "." + name; + } + + @Ensures({"result != null"}) + public String toOneLineString() { + return getName() + "=" + getValue().toOneLineString(); + } + + @Ensures({"result != null"}) + public DiffNode getValueAsNode() { + if ( getValue().isCompound() ) + return (DiffNode)getValue(); + else + throw new ReviewedStingException("Illegal request conversion of a DiffValue into a DiffNode: " + this); + } +} diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java new file mode 100644 index 000000000..ba2713bff --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +import com.google.java.contract.Requires; +import org.apache.log4j.Logger; +import org.broadinstitute.sting.gatk.report.GATKReport; +import org.broadinstitute.sting.gatk.report.GATKReportTable; +import org.broadinstitute.sting.gatk.walkers.varianteval.stratifications.VariantStratifier; +import org.broadinstitute.sting.utils.Utils; +import org.broadinstitute.sting.utils.classloader.PluginManager; +import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; +import org.broadinstitute.sting.utils.exceptions.UserException; + +import java.io.File; +import java.io.PrintStream; +import java.util.*; + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 12:51 PM + * A generic engine for comparing tree-structured objects + */ +public class DiffEngine { + final protected static Logger logger = Logger.getLogger(DiffEngine.class); + + private final Map readers = new HashMap(); + + public DiffEngine() { + loadDiffableReaders(); + } + + // -------------------------------------------------------------------------------- + // + // difference calculation + // + // -------------------------------------------------------------------------------- + + public List diff(DiffElement master, DiffElement test) { + DiffValue masterValue = master.getValue(); + DiffValue testValue = test.getValue(); + + if ( masterValue.isCompound() && masterValue.isCompound() ) { + return diff(master.getValueAsNode(), test.getValueAsNode()); + } else if ( masterValue.isAtomic() && testValue.isAtomic() ) { + return diff(masterValue, testValue); + } else { + // structural difference in types. one is node, other is leaf + return Arrays.asList(new Difference(master, test)); + } + } + + public List diff(DiffNode master, DiffNode test) { + Set allNames = new HashSet(master.getElementNames()); + allNames.addAll(test.getElementNames()); + List diffs = new ArrayList(); + + for ( String name : allNames ) { + DiffElement masterElt = master.getElement(name); + DiffElement testElt = test.getElement(name); + if ( masterElt == null && testElt == null ) { + throw new ReviewedStingException("BUG: unexceptedly got two null elements for field: " + name); + } else if ( masterElt == null || testElt == null ) { // if either is null, we are missing a value + // todo -- should one of these be a special MISSING item? + diffs.add(new Difference(masterElt, testElt)); + } else { + diffs.addAll(diff(masterElt, testElt)); + } + } + + return diffs; + } + + public List diff(DiffValue master, DiffValue test) { + if ( master.getValue().equals(test.getValue()) ) { + return Collections.emptyList(); + } else { + return Arrays.asList(new Difference(master.getBinding(), test.getBinding())); + } + } + + // -------------------------------------------------------------------------------- + // + // Summarizing differences + // + // -------------------------------------------------------------------------------- + + /** + * Emits a summary of the diffs to out. Suppose you have the following three differences: + * + * A.X.Z:1!=2 + * A.Y.Z:3!=4 + * B.X.Z:5!=6 + * + * The above is the itemized list of the differences. The summary looks for common differences + * in the name hierarchy, counts those shared elements, and emits the differences that occur + * in order of decreasing counts. + * + * So, in the above example, what are the shared elements? + * + * A.X.Z and B.X.Z share X.Z, so there's a *.X.Z with count 2 + * A.X.Z, A.Y.Z, and B.X.Z all share *.*.Z, with count 3 + * Each of A.X.Z, A.Y.Z, and B.X.Z are individually unique, with count 1 + * + * So we would emit the following summary: + * + * *.*.Z: 3 + * *.X.Z: 2 + * A.X.Z: 1 [specific difference: 1!=2] + * A.Y.Z: 1 [specific difference: 3!=4] + * B.X.Z: 1 [specific difference: 5!=6] + * + * The algorithm to accomplish this calculation is relatively simple. Start with all of the + * concrete differences. For each pair of differences A1.A2....AN and B1.B2....BN: + * + * find the longest common subsequence Si.Si+1...SN where Ai = Bi = Si + * If i == 0, then there's no shared substructure + * If i > 0, then generate the summarized value X = *.*...Si.Si+1...SN + * if X is a known summary, increment it's count, otherwise set its count to 1 + * + * Not that only pairs of the same length are considered as potentially equivalent + * + * @param params determines how we display the items + * @param diffs + */ + public void reportSummarizedDifferences(List diffs, SummaryReportParams params ) { + printSummaryReport(summarizeDifferences(diffs), params ); + } + + public List summarizeDifferences(List diffs) { + List diffPaths = new ArrayList(diffs.size()); + + for ( Difference diff1 : diffs ) { + diffPaths.add(diffNameToPath(diff1.getFullyQualifiedName())); + } + + return summarizedDifferencesOfPaths(diffPaths); + } + + final protected static String[] diffNameToPath(String diffName) { + return diffName.split("\\."); + } + + protected List summarizedDifferencesOfPaths(List diffPaths) { + Map summaries = new HashMap(); + + // create the initial set of differences + for ( int i = 0; i < diffPaths.size(); i++ ) { + for ( int j = 0; j <= i; j++ ) { + String[] diffPath1 = diffPaths.get(i); + String[] diffPath2 = diffPaths.get(j); + if ( diffPath1.length == diffPath2.length ) { + int lcp = longestCommonPostfix(diffPath1, diffPath2); + String path = lcp > 0 ? summarizedPath(diffPath2, lcp) : Utils.join(".", diffPath2); + addSummary(summaries, path, true); + } + } + } + + // count differences + for ( String[] diffPath : diffPaths ) { + for ( SummarizedDifference sumDiff : summaries.values() ) { + if ( sumDiff.matches(diffPath) ) + addSummary(summaries, sumDiff.getPath(), false); + } + } + + List sortedSummaries = new ArrayList(summaries.values()); + Collections.sort(sortedSummaries); + return sortedSummaries; + } + + private static void addSummary(Map summaries, String path, boolean onlyCatalog) { + if ( summaries.containsKey(path) ) { + if ( ! onlyCatalog ) + summaries.get(path).incCount(); + } else { + SummarizedDifference sumDiff = new SummarizedDifference(path); + summaries.put(sumDiff.getPath(), sumDiff); + } + } + + protected void printSummaryReport(List sortedSummaries, SummaryReportParams params ) { + GATKReport report = new GATKReport(); + final String tableName = "diffences"; + report.addTable(tableName, "Summarized differences between the master and test files.\nSee http://www.broadinstitute.org/gsa/wiki/index.php/DiffObjectsWalker_and_SummarizedDifferences for more information"); + GATKReportTable table = report.getTable(tableName); + table.addPrimaryKey("Difference", true); + table.addColumn("NumberOfOccurrences", 0); + + int count = 0, count1 = 0; + for ( SummarizedDifference diff : sortedSummaries ) { + if ( diff.getCount() < params.minSumDiffToShow ) + // in order, so break as soon as the count is too low + break; + + if ( params.maxItemsToDisplay != 0 && count++ > params.maxItemsToDisplay ) + break; + + if ( diff.getCount() == 1 ) { + count1++; + if ( params.maxCountOneItems != 0 && count1 > params.maxCountOneItems ) + break; + } + + table.set(diff.getPath(), "NumberOfOccurrences", diff.getCount()); + } + + table.write(params.out); + } + + protected static int longestCommonPostfix(String[] diffPath1, String[] diffPath2) { + int i = 0; + for ( ; i < diffPath1.length; i++ ) { + int j = diffPath1.length - i - 1; + if ( ! diffPath1[j].equals(diffPath2[j]) ) + break; + } + return i; + } + + /** + * parts is [A B C D] + * commonPostfixLength: how many parts are shared at the end, suppose its 2 + * We want to create a string *.*.C.D + * + * @param parts + * @param commonPostfixLength + * @return + */ + protected static String summarizedPath(String[] parts, int commonPostfixLength) { + int stop = parts.length - commonPostfixLength; + if ( stop > 0 ) parts = parts.clone(); + for ( int i = 0; i < stop; i++ ) { + parts[i] = "*"; + } + return Utils.join(".", parts); + } + + /** + * TODO -- all of the algorithms above should use SummarizedDifference instead + * TODO -- of some SummarizedDifferences and some low-level String[] + */ + public static class SummarizedDifference implements Comparable { + final String path; // X.Y.Z + final String[] parts; + int count = 0; + + public SummarizedDifference(String path) { + this.path = path; + this.parts = diffNameToPath(path); + } + + public void incCount() { count++; } + + public int getCount() { + return count; + } + + /** + * The fully qualified path object A.B.C etc + * @return + */ + public String getPath() { + return path; + } + + /** + * @return the length of the parts of this summary + */ + public int length() { + return this.parts.length; + } + + /** + * Returns true if the string parts matches this summary. Matches are + * must be equal() everywhere where this summary isn't *. + * @param otherParts + * @return + */ + public boolean matches(String[] otherParts) { + if ( otherParts.length != length() ) + return false; + + // TODO optimization: can start at right most non-star element + for ( int i = 0; i < length(); i++ ) { + String part = parts[i]; + if ( ! part.equals("*") && ! part.equals(otherParts[i]) ) + return false; + } + + return true; + } + + @Override + public String toString() { + return String.format("%s:%d", getPath(), getCount()); + } + + @Override + public int compareTo(SummarizedDifference other) { + // sort first highest to lowest count, then by lowest to highest path + int countCmp = Integer.valueOf(count).compareTo(other.count); + return countCmp != 0 ? -1 * countCmp : path.compareTo(other.path); + } + + + } + + // -------------------------------------------------------------------------------- + // + // plugin manager + // + // -------------------------------------------------------------------------------- + + public void loadDiffableReaders() { + List> drClasses = new PluginManager( DiffableReader.class ).getPlugins(); + + logger.info("Loading diffable modules:"); + for (Class drClass : drClasses ) { + logger.info("\t" + drClass.getSimpleName()); + + try { + DiffableReader dr = drClass.newInstance(); + readers.put(dr.getName(), dr); + } catch (InstantiationException e) { + throw new ReviewedStingException("Unable to instantiate module '" + drClass.getSimpleName() + "'"); + } catch (IllegalAccessException e) { + throw new ReviewedStingException("Illegal access error when trying to instantiate '" + drClass.getSimpleName() + "'"); + } + } + } + + protected Map getReaders() { + return readers; + } + + protected DiffableReader getReader(String name) { + return readers.get(name); + } + + /** + * Returns a reader appropriate for this file, or null if no such reader exists + * @param file + * @return + */ + public DiffableReader findReaderForFile(File file) { + for ( DiffableReader reader : readers.values() ) + if (reader.canRead(file) ) + return reader; + + return null; + } + + /** + * Returns true if reader appropriate for this file, or false if no such reader exists + * @param file + * @return + */ + public boolean canRead(File file) { + return findReaderForFile(file) != null; + } + + public DiffElement createDiffableFromFile(File file) { + DiffableReader reader = findReaderForFile(file); + if ( reader == null ) + throw new UserException("Unsupported file type: " + file); + else + return reader.readFromFile(file); + } + + public static boolean simpleDiffFiles(File masterFile, File testFile, DiffEngine.SummaryReportParams params) { + DiffEngine diffEngine = new DiffEngine(); + + if ( diffEngine.canRead(masterFile) && diffEngine.canRead(testFile) ) { + DiffElement master = diffEngine.createDiffableFromFile(masterFile); + DiffElement test = diffEngine.createDiffableFromFile(testFile); + List diffs = diffEngine.diff(master, test); + diffEngine.reportSummarizedDifferences(diffs, params); + return true; + } else { + return false; + } + } + + public static class SummaryReportParams { + PrintStream out = System.out; + int maxItemsToDisplay = 0; + int maxCountOneItems = 0; + int minSumDiffToShow = 0; + + public SummaryReportParams(PrintStream out, int maxItemsToDisplay, int maxCountOneItems, int minSumDiffToShow) { + this.out = out; + this.maxItemsToDisplay = maxItemsToDisplay; + this.maxCountOneItems = maxCountOneItems; + this.minSumDiffToShow = minSumDiffToShow; + } + } +} diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java new file mode 100644 index 000000000..0720e18c0 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +import com.google.java.contract.Requires; +import org.broadinstitute.sting.utils.Utils; +import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; + +import java.util.*; + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 12:55 PM + * + * An interface that must be implemented to allow us to calculate differences + * between structured objects + */ +public class DiffNode extends DiffValue { + private Map getElementMap() { + return (Map)super.getValue(); + } + private static Map emptyElements() { return new HashMap(); } + + private DiffNode(Map elements) { + super(elements); + } + + private DiffNode(DiffElement binding, Map elements) { + super(binding, elements); + } + + // --------------------------------------------------------------------------- + // + // constructors + // + // --------------------------------------------------------------------------- + + public static DiffNode rooted(String name) { + return empty(name, DiffElement.ROOT); + } + + public static DiffNode empty(String name, DiffElement parent) { + DiffNode df = new DiffNode(emptyElements()); + DiffElement elt = new DiffElement(name, parent, df); + df.setBinding(elt); + return df; + } + + public static DiffNode empty(String name, DiffValue parent) { + return empty(name, parent.getBinding()); + } + + // --------------------------------------------------------------------------- + // + // accessors + // + // --------------------------------------------------------------------------- + + @Override + public boolean isAtomic() { return false; } + + public Collection getElementNames() { + return getElementMap().keySet(); + } + + public Collection getElements() { + return getElementMap().values(); + } + + private Collection getElements(boolean atomicOnly) { + List elts = new ArrayList(); + for ( DiffElement elt : getElements() ) + if ( (atomicOnly && elt.getValue().isAtomic()) || (! atomicOnly && elt.getValue().isCompound())) + elts.add(elt); + return elts; + } + + public Collection getAtomicElements() { + return getElements(true); + } + + public Collection getCompoundElements() { + return getElements(false); + } + + public DiffElement getElement(String name) { + for ( DiffElement elt : getElements() ) + if ( elt.getName().equals(name) ) + return elt; + return null; + } + + /** + * Returns true if name is bound in this node + * @param name + * @return + */ + public boolean hasElement(String name) { + return getElement(name) != null; + } + + // --------------------------------------------------------------------------- + // + // add + // + // --------------------------------------------------------------------------- + + @Requires("elt != null") + public void add(DiffElement elt) { + if ( getElementMap().containsKey(elt.getName()) ) + throw new IllegalArgumentException("Attempting to rebind already existing binding: " + elt + " node=" + this); + getElementMap().put(elt.getName(), elt); + } + + @Requires("elt != null") + public void add(DiffValue elt) { + add(elt.getBinding()); + } + + @Requires("elts != null") + public void add(Collection elts) { + for ( DiffElement e : elts ) + add(e); + } + + public void add(String name, Object value) { + add(new DiffElement(name, this.getBinding(), new DiffValue(value))); + } + + // --------------------------------------------------------------------------- + // + // toString + // + // --------------------------------------------------------------------------- + + @Override + public String toString() { + return toString(0); + } + + @Override + public String toString(int offset) { + String off = offset > 0 ? Utils.dupString(' ', offset) : ""; + StringBuilder b = new StringBuilder(); + + b.append("(").append("\n"); + Collection atomicElts = getAtomicElements(); + for ( DiffElement elt : atomicElts ) { + b.append(elt.toString(offset + 2)).append('\n'); + } + + for ( DiffElement elt : getCompoundElements() ) { + b.append(elt.toString(offset + 4)).append('\n'); + } + b.append(off).append(")").append("\n"); + + return b.toString(); + } + + @Override + public String toOneLineString() { + StringBuilder b = new StringBuilder(); + + b.append('('); + List parts = new ArrayList(); + for ( DiffElement elt : getElements() ) + parts.add(elt.toOneLineString()); + b.append(Utils.join(" ", parts)); + b.append(')'); + + return b.toString(); + } + + // -------------------------------------------------------------------------------- + // + // fromString and toOneLineString + // + // -------------------------------------------------------------------------------- + + public static DiffElement fromString(String tree) { + return fromString(tree, DiffElement.ROOT); + } + + /** + * Doesn't support full tree structure parsing + * @param tree + * @param parent + * @return + */ + private static DiffElement fromString(String tree, DiffElement parent) { + // X=(A=A B=B C=(D=D)) + String[] parts = tree.split("=", 2); + if ( parts.length != 2 ) + throw new ReviewedStingException("Unexpected tree structure: " + tree + " parts=" + parts); + String name = parts[0]; + String value = parts[1]; + + if ( value.length() == 0 ) + throw new ReviewedStingException("Illegal tree structure: " + value + " at " + tree); + + if ( value.charAt(0) == '(' ) { + if ( ! value.endsWith(")") ) + throw new ReviewedStingException("Illegal tree structure. Missing ): " + value + " at " + tree); + String subtree = value.substring(1, value.length()-1); + DiffNode rec = DiffNode.empty(name, parent); + String[] subParts = subtree.split(" "); + for ( String subPart : subParts ) { + rec.add(fromString(subPart, rec.getBinding())); + } + return rec.getBinding(); + } else { + return new DiffValue(name, parent, value).getBinding(); + } + } +} diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java new file mode 100644 index 000000000..a08108db2 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +import org.apache.xmlbeans.impl.tool.Diff; +import org.broadinstitute.sting.commandline.Argument; +import org.broadinstitute.sting.commandline.Output; +import org.broadinstitute.sting.gatk.contexts.AlignmentContext; +import org.broadinstitute.sting.gatk.contexts.ReferenceContext; +import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; +import org.broadinstitute.sting.gatk.walkers.Requires; +import org.broadinstitute.sting.gatk.walkers.RodWalker; + +import java.io.File; +import java.io.PrintStream; +import java.util.List; + +/** + * Compares two record-oriented files, itemizing specific difference between equivalent + * records in the two files. Reports both itemized and summarized differences. + * @author Mark DePristo + * @version 0.1 + */ +@Requires(value={}) +public class DiffObjectsWalker extends RodWalker { + @Output(doc="File to which results should be written",required=true) + protected PrintStream out; + + @Argument(fullName="maxRecords", shortName="M", doc="Max. number of records to process", required=false) + int MAX_RECORDS = 0; + + @Argument(fullName="maxCount1Records", shortName="M1", doc="Max. number of records occuring exactly once in the file to process", required=false) + int MAX_COUNT1_RECORDS = 0; + + @Argument(fullName="minCountForDiff", shortName="MCFD", doc="Min number of observations for a records to display", required=false) + int minCountForDiff = 1; + + @Argument(fullName="showItemizedDifferences", shortName="SID", doc="Should we enumerate all differences between the files?", required=false) + boolean showItemizedDifferences = false; + + @Argument(fullName="master", shortName="m", doc="Master file: expected results", required=true) + File masterFile; + + @Argument(fullName="test", shortName="t", doc="Test file: new results to compare to the master file", required=true) + File testFile; + + final DiffEngine diffEngine = new DiffEngine(); + + @Override + public void initialize() { + + } + + @Override + public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) { + return 0; + } + + @Override + public Integer reduceInit() { + return 0; + } + + @Override + public Integer reduce(Integer counter, Integer sum) { + return counter + sum; + } + + @Override + public void onTraversalDone(Integer sum) { + out.printf("Reading master file %s%n", masterFile); + DiffElement master = diffEngine.createDiffableFromFile(masterFile); + out.printf("Reading test file %s%n", testFile); + DiffElement test = diffEngine.createDiffableFromFile(testFile); + +// out.printf("Master diff objects%n"); +// out.println(master.toString()); +// out.printf("Test diff objects%n"); +// out.println(test.toString()); + + List diffs = diffEngine.diff(master, test); + if ( showItemizedDifferences ) { + out.printf("Itemized results%n"); + for ( Difference diff : diffs ) + out.printf("DIFF: %s%n", diff.toString()); + } + + DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(out, MAX_RECORDS, MAX_COUNT1_RECORDS, minCountForDiff); + diffEngine.reportSummarizedDifferences(diffs, params); + } +} \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffValue.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffValue.java new file mode 100644 index 000000000..7245e9e8d --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffValue.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +import org.broadinstitute.sting.utils.Utils; + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 12:55 PM + * + * An interface that must be implemented to allow us to calculate differences + * between structured objects + */ +public class DiffValue { + private DiffElement binding = null; + final private Object value; + + public DiffValue(Object value) { + this.value = value; + } + + public DiffValue(DiffElement binding, Object value) { + this.binding = binding; + this.value = value; + } + + public DiffValue(DiffValue parent, Object value) { + this(parent.getBinding(), value); + } + + public DiffValue(String name, DiffElement parent, Object value) { + this.binding = new DiffElement(name, parent, this); + this.value = value; + } + + public DiffValue(String name, DiffValue parent, Object value) { + this(name, parent.getBinding(), value); + } + + public DiffElement getBinding() { + return binding; + } + + protected void setBinding(DiffElement binding) { + this.binding = binding; + } + + public Object getValue() { + return value; + } + + public String toString() { + return getValue().toString(); + } + + public String toString(int offset) { + return toString(); + } + + public String toOneLineString() { + return getValue().toString(); + } + + public boolean isAtomic() { return true; } + public boolean isCompound() { return ! isAtomic(); } +} diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java new file mode 100644 index 000000000..84c2eed10 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +import com.google.java.contract.Ensures; +import com.google.java.contract.Requires; + +import java.io.File; + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 1:09 PM + * + * Interface for readers creating diffable objects from a file + */ +public interface DiffableReader { + @Ensures("result != null") + public String getName(); + + @Ensures("result != null") + @Requires("file != null") + public DiffElement readFromFile(File file); + + @Requires("file != null") + public boolean canRead(File file); +} diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/Difference.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/Difference.java new file mode 100644 index 000000000..6627a4cc5 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/Difference.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 12:53 PM + * + * Represents a specific difference between two specific DiffElements + */ +public class Difference { + DiffElement master, test; + + public Difference(DiffElement master, DiffElement test) { + if ( master == null && test == null ) throw new IllegalArgumentException("Master and test both cannot be null"); + this.master = master; + this.test = test; + } + + public String toString() { + return String.format("%s:%s!=%s", + getFullyQualifiedName(), + getOneLineString(master), + getOneLineString(test)); + } + + public String getFullyQualifiedName() { + return (master == null ? test : master).fullyQualifiedName(); + } + + private static String getOneLineString(DiffElement elt) { + return elt == null ? "MISSING" : elt.getValue().toOneLineString(); + } +} diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java new file mode 100644 index 000000000..743178538 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +import org.broad.tribble.readers.AsciiLineReader; +import org.broad.tribble.readers.LineReader; +import org.broadinstitute.sting.utils.codecs.vcf.VCFCodec; +import org.broadinstitute.sting.utils.codecs.vcf.VCFConstants; +import org.broadinstitute.sting.utils.codecs.vcf.VCFHeader; +import org.broadinstitute.sting.utils.variantcontext.Genotype; +import org.broadinstitute.sting.utils.variantcontext.VariantContext; + +import java.io.*; +import java.util.Arrays; +import java.util.Map; +import java.util.zip.GZIPInputStream; + + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 1:09 PM + * + * Class implementing diffnode reader for VCF + */ +public class VCFDiffableReader implements DiffableReader { + @Override + public String getName() { return "VCF"; } + + @Override + public DiffElement readFromFile(File file) { + DiffNode root = DiffNode.rooted(file.getName()); + try { + LineReader lineReader = new AsciiLineReader(new FileInputStream(file)); + VCFCodec vcfCodec = new VCFCodec(); + VCFHeader header = (VCFHeader)vcfCodec.readHeader(lineReader); + + String line = lineReader.readLine(); + while ( line != null ) { + VariantContext vc = (VariantContext)vcfCodec.decode(line); + String name = vc.getChr() + ":" + vc.getStart(); + DiffNode vcRoot = DiffNode.empty(name, root); + + // add fields + vcRoot.add("CHROM", vc.getChr()); + vcRoot.add("POS", vc.getStart()); + vcRoot.add("ID", vc.hasID() ? vc.getID() : VCFConstants.MISSING_VALUE_v4); + vcRoot.add("REF", vc.getReference()); + vcRoot.add("ALT", vc.getAlternateAlleles()); + vcRoot.add("QUAL", vc.hasNegLog10PError() ? vc.getNegLog10PError() * 10 : VCFConstants.MISSING_VALUE_v4); + vcRoot.add("FILTER", vc.getFilters()); + + // add info fields + for (Map.Entry attribute : vc.getAttributes().entrySet()) { + if ( ! attribute.getKey().startsWith("_") && ! attribute.getKey().equals(VariantContext.ID_KEY)) + vcRoot.add(attribute.getKey(), attribute.getValue()); + } + + for (Genotype g : vc.getGenotypes().values() ) { + DiffNode gRoot = DiffNode.empty(g.getSampleName(), vcRoot); + gRoot.add("GT", g.getGenotypeString()); + gRoot.add("GQ", g.hasNegLog10PError() ? g.getNegLog10PError() * 10 : VCFConstants.MISSING_VALUE_v4 ); + + for (Map.Entry attribute : g.getAttributes().entrySet()) { + if ( ! attribute.getKey().startsWith("_") ) + gRoot.add(attribute.getKey(), attribute.getValue()); + } + + vcRoot.add(gRoot); + } + + root.add(vcRoot); + line = lineReader.readLine(); + } + + lineReader.close(); + } catch ( IOException e ) { + return null; + } + + return root.getBinding(); + } + + @Override + public boolean canRead(File file) { + try { + final String VCF4_HEADER = "##fileformat=VCFv4"; + char[] buff = new char[VCF4_HEADER.length()]; + new FileReader(file).read(buff, 0, VCF4_HEADER.length()); + String firstLine = new String(buff); + return firstLine.startsWith(VCF4_HEADER); + } catch ( IOException e ) { + return false; + } + } +} From d7d15019dd543decffa2169f074b123633fe5984 Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Tue, 12 Jul 2011 01:16:21 -0400 Subject: [PATCH 09/83] Adding support for other simple header line types (e.g. ALT) and cleaning up the interface a bit. --- .../walkers/annotator/ChromosomeCounts.java | 5 +- .../walkers/genotyper/UnifiedGenotyper.java | 17 +++- .../utils/codecs/vcf/StandardVCFWriter.java | 3 +- .../utils/codecs/vcf/VCFAltHeaderLine.java | 28 +++++++ .../codecs/vcf/VCFCompoundHeaderLine.java | 3 + .../utils/codecs/vcf/VCFFilterHeaderLine.java | 48 +---------- .../utils/codecs/vcf/VCFFormatHeaderLine.java | 2 +- .../utils/codecs/vcf/VCFSimpleHeaderLine.java | 81 +++++++++++++++++++ .../sting/utils/codecs/vcf/VCFUtils.java | 15 ---- 9 files changed, 135 insertions(+), 67 deletions(-) create mode 100644 public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFAltHeaderLine.java create mode 100644 public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFSimpleHeaderLine.java diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ChromosomeCounts.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ChromosomeCounts.java index 143722d7c..ed10d2072 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ChromosomeCounts.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ChromosomeCounts.java @@ -25,6 +25,7 @@ package org.broadinstitute.sting.gatk.walkers.annotator; +import org.broadinstitute.sting.utils.codecs.vcf.VCFHeaderLineCount; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.utils.codecs.vcf.VCFHeaderLineType; import org.broadinstitute.sting.utils.codecs.vcf.VCFInfoHeaderLine; @@ -41,8 +42,8 @@ import java.util.*; public class ChromosomeCounts implements InfoFieldAnnotation, StandardAnnotation { private String[] keyNames = { VCFConstants.ALLELE_NUMBER_KEY, VCFConstants.ALLELE_COUNT_KEY, VCFConstants.ALLELE_FREQUENCY_KEY }; - private VCFInfoHeaderLine[] descriptions = { new VCFInfoHeaderLine(VCFConstants.ALLELE_FREQUENCY_KEY, -1, VCFHeaderLineType.Float, "Allele Frequency, for each ALT allele, in the same order as listed"), - new VCFInfoHeaderLine(VCFConstants.ALLELE_COUNT_KEY, -1, VCFHeaderLineType.Integer, "Allele count in genotypes, for each ALT allele, in the same order as listed"), + private VCFInfoHeaderLine[] descriptions = { new VCFInfoHeaderLine(VCFConstants.ALLELE_FREQUENCY_KEY, VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Float, "Allele Frequency, for each ALT allele, in the same order as listed"), + new VCFInfoHeaderLine(VCFConstants.ALLELE_COUNT_KEY, VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "Allele count in genotypes, for each ALT allele, in the same order as listed"), new VCFInfoHeaderLine(VCFConstants.ALLELE_NUMBER_KEY, 1, VCFHeaderLineType.Integer, "Total number of alleles in called genotypes") }; public Map annotate(RefMetaDataTracker tracker, ReferenceContext ref, Map stratifiedContexts, VariantContext vc) { diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyper.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyper.java index 7a765c602..fe0084a19 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyper.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyper.java @@ -37,7 +37,6 @@ import org.broadinstitute.sting.gatk.datasources.rmd.ReferenceOrderedDataSource; import org.broadinstitute.sting.utils.*; import org.broadinstitute.sting.utils.baq.BAQ; import org.broadinstitute.sting.commandline.*; -import org.broadinstitute.sting.utils.codecs.vcf.VCFUtils; import java.util.*; import java.io.PrintStream; @@ -158,7 +157,7 @@ public class UnifiedGenotyper extends LocusWalker getSupportedHeaderStrings() { + Set result = new HashSet(); + result.add(new VCFFormatHeaderLine(VCFConstants.GENOTYPE_KEY, 1, VCFHeaderLineType.String, "Genotype")); + result.add(new VCFFormatHeaderLine(VCFConstants.GENOTYPE_QUALITY_KEY, 1, VCFHeaderLineType.Float, "Genotype Quality")); + result.add(new VCFFormatHeaderLine(VCFConstants.DEPTH_KEY, 1, VCFHeaderLineType.Integer, "Read Depth (only filtered reads used for calling)")); + result.add(new VCFFormatHeaderLine(VCFConstants.PHRED_GENOTYPE_LIKELIHOODS_KEY, VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Float, "Normalized, Phred-scaled likelihoods for AA,AB,BB genotypes where A=ref and B=alt; if site is not biallelic, number of likelihoods if n*(n+1)/2")); + + return result; + } + /** * Compute at a given locus. * diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java index 230773310..f4996b487 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java @@ -358,9 +358,8 @@ public class StandardVCFWriter implements VCFWriter { mWriter.write(key); if ( !entry.getValue().equals("") ) { - int numVals = 1; VCFInfoHeaderLine metaData = mHeader.getInfoHeaderLine(key); - if ( metaData != null && (metaData.getCountType() != VCFHeaderLineCount.INTEGER || metaData.getCount() > 0) ) { + if ( metaData == null || metaData.getCountType() != VCFHeaderLineCount.INTEGER || metaData.getCount() != 0 ) { mWriter.write("="); mWriter.write(entry.getValue()); } diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFAltHeaderLine.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFAltHeaderLine.java new file mode 100644 index 000000000..a9de949d8 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFAltHeaderLine.java @@ -0,0 +1,28 @@ +package org.broadinstitute.sting.utils.codecs.vcf; + +/** + * @author ebanks + * A class representing a key=value entry for ALT fields in the VCF header + */ +public class VCFAltHeaderLine extends VCFSimpleHeaderLine { + + /** + * create a VCF filter header line + * + * @param name the name for this header line + * @param description the description for this header line + */ + public VCFAltHeaderLine(String name, String description) { + super(name, description, SupportedHeaderLineType.ALT); + } + + /** + * create a VCF info header line + * + * @param line the header line + * @param version the vcf header version + */ + protected VCFAltHeaderLine(String line, VCFHeaderVersion version) { + super(line, version, SupportedHeaderLineType.ALT); + } +} \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCompoundHeaderLine.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCompoundHeaderLine.java index 49f9ab184..bb822f2ed 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCompoundHeaderLine.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCompoundHeaderLine.java @@ -89,6 +89,7 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF * @param count the count for this header line * @param type the type for this header line * @param description the description for this header line + * @param lineType the header line type */ protected VCFCompoundHeaderLine(String name, int count, VCFHeaderLineType type, String description, SupportedHeaderLineType lineType) { super(lineType.toString(), ""); @@ -108,6 +109,7 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF * @param count the count type for this header line * @param type the type for this header line * @param description the description for this header line + * @param lineType the header line type */ protected VCFCompoundHeaderLine(String name, VCFHeaderLineCount count, VCFHeaderLineType type, String description, SupportedHeaderLineType lineType) { super(lineType.toString(), ""); @@ -124,6 +126,7 @@ public abstract class VCFCompoundHeaderLine extends VCFHeaderLine implements VCF * * @param line the header line * @param version the VCF header version + * @param lineType the header line type * */ protected VCFCompoundHeaderLine(String line, VCFHeaderVersion version, SupportedHeaderLineType lineType) { diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFilterHeaderLine.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFilterHeaderLine.java index 9176fc16e..418b80074 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFilterHeaderLine.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFilterHeaderLine.java @@ -1,19 +1,10 @@ package org.broadinstitute.sting.utils.codecs.vcf; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; - - /** * @author ebanks * A class representing a key=value entry for FILTER fields in the VCF header */ -public class VCFFilterHeaderLine extends VCFHeaderLine implements VCFNamedHeaderLine { - - private String name; - private String description; - +public class VCFFilterHeaderLine extends VCFSimpleHeaderLine { /** * create a VCF filter header line @@ -22,12 +13,7 @@ public class VCFFilterHeaderLine extends VCFHeaderLine implements VCFNamedHeader * @param description the description for this header line */ public VCFFilterHeaderLine(String name, String description) { - super("FILTER", ""); - this.name = name; - this.description = description; - - if ( name == null || description == null ) - throw new IllegalArgumentException(String.format("Invalid VCFCompoundHeaderLine: key=%s name=%s desc=%s", super.getKey(), name, description )); + super(name, description, SupportedHeaderLineType.FILTER); } /** @@ -37,34 +23,6 @@ public class VCFFilterHeaderLine extends VCFHeaderLine implements VCFNamedHeader * @param version the vcf header version */ protected VCFFilterHeaderLine(String line, VCFHeaderVersion version) { - super("FILTER", ""); - Map mapping = VCFHeaderLineTranslator.parseLine(version,line, Arrays.asList("ID","Description")); - name = mapping.get("ID"); - description = mapping.get("Description"); - if ( description == null && ALLOW_UNBOUND_DESCRIPTIONS ) // handle the case where there's no description provided - description = UNBOUND_DESCRIPTION; - } - - protected String toStringEncoding() { - Map map = new LinkedHashMap(); - map.put("ID", name); - map.put("Description", description); - return "FILTER=" + VCFHeaderLine.toStringEncoding(map); - } - - public boolean equals(Object o) { - if ( !(o instanceof VCFFilterHeaderLine) ) - return false; - VCFFilterHeaderLine other = (VCFFilterHeaderLine)o; - return name.equals(other.name) && - description.equals(other.description); - } - - public String getName() { - return name; - } - - public String getDescription() { - return description; + super(line, version, SupportedHeaderLineType.FILTER); } } \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFormatHeaderLine.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFormatHeaderLine.java index f68cb670b..474c8dd14 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFormatHeaderLine.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFFormatHeaderLine.java @@ -17,7 +17,7 @@ public class VCFFormatHeaderLine extends VCFCompoundHeaderLine { } public VCFFormatHeaderLine(String name, VCFHeaderLineCount count, VCFHeaderLineType type, String description) { - super(name, count, type, description, SupportedHeaderLineType.INFO); + super(name, count, type, description, SupportedHeaderLineType.FORMAT); } protected VCFFormatHeaderLine(String line, VCFHeaderVersion version) { diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFSimpleHeaderLine.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFSimpleHeaderLine.java new file mode 100644 index 000000000..152043f28 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFSimpleHeaderLine.java @@ -0,0 +1,81 @@ +package org.broadinstitute.sting.utils.codecs.vcf; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; + + +/** + * @author ebanks + * A class representing a key=value entry for simple VCF header types + */ +public abstract class VCFSimpleHeaderLine extends VCFHeaderLine implements VCFNamedHeaderLine { + + public enum SupportedHeaderLineType { + FILTER, ALT; + } + + private String name; + private String description; + + // our type of line, i.e. filter, alt, etc + private final SupportedHeaderLineType lineType; + + + /** + * create a VCF filter header line + * + * @param name the name for this header line + * @param description the description for this header line + * @param lineType the header line type + */ + public VCFSimpleHeaderLine(String name, String description, SupportedHeaderLineType lineType) { + super(lineType.toString(), ""); + this.lineType = lineType; + this.name = name; + this.description = description; + + if ( name == null || description == null ) + throw new IllegalArgumentException(String.format("Invalid VCFSimpleHeaderLine: key=%s name=%s desc=%s", super.getKey(), name, description )); + } + + /** + * create a VCF info header line + * + * @param line the header line + * @param version the vcf header version + * @param lineType the header line type + */ + protected VCFSimpleHeaderLine(String line, VCFHeaderVersion version, SupportedHeaderLineType lineType) { + super(lineType.toString(), ""); + this.lineType = lineType; + Map mapping = VCFHeaderLineTranslator.parseLine(version,line, Arrays.asList("ID","Description")); + name = mapping.get("ID"); + description = mapping.get("Description"); + if ( description == null && ALLOW_UNBOUND_DESCRIPTIONS ) // handle the case where there's no description provided + description = UNBOUND_DESCRIPTION; + } + + protected String toStringEncoding() { + Map map = new LinkedHashMap(); + map.put("ID", name); + map.put("Description", description); + return lineType.toString() + "=" + VCFHeaderLine.toStringEncoding(map); + } + + public boolean equals(Object o) { + if ( !(o instanceof VCFSimpleHeaderLine) ) + return false; + VCFSimpleHeaderLine other = (VCFSimpleHeaderLine)o; + return name.equals(other.name) && + description.equals(other.description); + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } +} \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFUtils.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFUtils.java index ecede068e..4037f75b9 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFUtils.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFUtils.java @@ -180,19 +180,4 @@ public class VCFUtils { return new HashSet(map.values()); } - - /** - * return a set of supported format lines; what we currently support for output in the genotype fields of a VCF - * @return a set of VCF format lines - */ - public static Set getSupportedHeaderStrings() { - Set result = new HashSet(); - result.add(new VCFFormatHeaderLine(VCFConstants.GENOTYPE_KEY, 1, VCFHeaderLineType.String, "Genotype")); - result.add(new VCFFormatHeaderLine(VCFConstants.GENOTYPE_QUALITY_KEY, 1, VCFHeaderLineType.Float, "Genotype Quality")); - result.add(new VCFFormatHeaderLine(VCFConstants.DEPTH_KEY, 1, VCFHeaderLineType.Integer, "Read Depth (only filtered reads used for calling)")); - result.add(new VCFFormatHeaderLine(VCFConstants.PHRED_GENOTYPE_LIKELIHOODS_KEY, -1, VCFHeaderLineType.Float, "Normalized, Phred-scaled likelihoods for AA,AB,BB genotypes where A=ref and B=alt; if site is not biallelic, number of likelihoods if n*(n+1)/2")); - - return result; - } - } \ No newline at end of file From f313e14e4ef2c3f933505bb16527313ce09e618c Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Tue, 12 Jul 2011 08:50:58 -0400 Subject: [PATCH 10/83] Now deletes the dump directory on ant clean Moving diffengine tests from private to public --- build.xml | 1 + .../diffengine/DiffEngineUnitTest.java | 229 ++++++++++++++++ .../walkers/diffengine/DiffNodeUnitTest.java | 249 ++++++++++++++++++ .../diffengine/DiffableReaderUnitTest.java | 143 ++++++++++ .../diffengine/DifferenceUnitTest.java | 95 +++++++ 5 files changed, 717 insertions(+) create mode 100644 public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngineUnitTest.java create mode 100644 public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNodeUnitTest.java create mode 100644 public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java create mode 100644 public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DifferenceUnitTest.java diff --git a/build.xml b/build.xml index 80627fae0..068c69316 100644 --- a/build.xml +++ b/build.xml @@ -981,6 +981,7 @@ + diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngineUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngineUnitTest.java new file mode 100644 index 000000000..cd6c3598a --- /dev/null +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngineUnitTest.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2011, 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. + */ + +// our package +package org.broadinstitute.sting.gatk.walkers.diffengine; + + +// the imports for unit testing. + +import org.broadinstitute.sting.BaseTest; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.*; + +/** + * Basic unit test for DifferableReaders in reduced reads + */ +public class DiffEngineUnitTest extends BaseTest { + DiffEngine engine; + + @BeforeClass(enabled = true) + public void createDiffEngine() { + engine = new DiffEngine(); + } + + // -------------------------------------------------------------------------------- + // + // Difference testing routines + // + // -------------------------------------------------------------------------------- + + private class DifferenceTest extends TestDataProvider { + public DiffElement tree1, tree2; + public List differences; + + private DifferenceTest(String tree1, String tree2) { + this(tree1, tree2, Collections.emptyList()); + } + + private DifferenceTest(String tree1, String tree2, String difference) { + this(tree1, tree2, Arrays.asList(difference)); + } + + private DifferenceTest(String tree1, String tree2, List differences) { + super(DifferenceTest.class); + this.tree1 = DiffNode.fromString(tree1); + this.tree2 = DiffNode.fromString(tree2); + this.differences = differences; + } + + public String toString() { + return String.format("tree1=%s tree2=%s diff=%s", + tree1.toOneLineString(), tree2.toOneLineString(), differences); + } + } + + @DataProvider(name = "trees") + public Object[][] createTrees() { + new DifferenceTest("A=X", "A=X"); + new DifferenceTest("A=X", "A=Y", "A:X!=Y"); + new DifferenceTest("A=X", "B=X", Arrays.asList("A:X!=MISSING", "B:MISSING!=X")); + new DifferenceTest("A=(X=1)", "B=(X=1)", Arrays.asList("A:(X=1)!=MISSING", "B:MISSING!=(X=1)")); + new DifferenceTest("A=(X=1)", "A=(X=1)"); + new DifferenceTest("A=(X=1 Y=2)", "A=(X=1 Y=2)"); + new DifferenceTest("A=(X=1 Y=2 B=(Z=3))", "A=(X=1 Y=2 B=(Z=3))"); + new DifferenceTest("A=(X=1)", "A=(X=2)", "A.X:1!=2"); + new DifferenceTest("A=(X=1 Y=2 B=(Z=3))", "A=(X=1 Y=2 B=(Z=4))", "A.B.Z:3!=4"); + new DifferenceTest("A=(X=1)", "A=(X=1 Y=2)", "A.Y:MISSING!=2"); + new DifferenceTest("A=(X=1 Y=2 B=(Z=3))", "A=(X=1 Y=2)", "A.B:(Z=3)!=MISSING"); + return DifferenceTest.getTests(DifferenceTest.class); + } + + @Test(enabled = true, dataProvider = "trees") + public void testDiffs(DifferenceTest test) { + logger.warn("Test tree1: " + test.tree1.toOneLineString()); + logger.warn("Test tree2: " + test.tree2.toOneLineString()); + + List diffs = engine.diff(test.tree1, test.tree2); + logger.warn("Test expected diff : " + test.differences); + logger.warn("Observed diffs : " + diffs); + } + + // -------------------------------------------------------------------------------- + // + // Low-level routines for summarizing differences + // + // -------------------------------------------------------------------------------- + + @Test(enabled = true) + public void testLongestCommonPostfix() { + testLongestCommonPostfixHelper("A", "A", 1); + testLongestCommonPostfixHelper("A", "B", 0); + testLongestCommonPostfixHelper("A.B", "A.B", 2); + testLongestCommonPostfixHelper("A.B.C", "A.B.C", 3); + testLongestCommonPostfixHelper("A.B.C", "X.B.C", 2); + testLongestCommonPostfixHelper("A.B.C", "X.Y.C", 1); + testLongestCommonPostfixHelper("A.B.C", "X.Y.Z", 0); + testLongestCommonPostfixHelper("A.B.C", "A.X.C", 1); + testLongestCommonPostfixHelper("A.B.C", "A.X.Z", 0); + testLongestCommonPostfixHelper("A.B.C", "A.B.Z", 0); + } + + public void testLongestCommonPostfixHelper(String p1, String p2, int expected) { + String[] parts1 = p1.split("\\."); + String[] parts2 = p2.split("\\."); + int obs = DiffEngine.longestCommonPostfix(parts1, parts2); + Assert.assertEquals(obs, expected, "p1=" + p1 + " p2=" + p2 + " failed"); + } + + @Test(enabled = true, dependsOnMethods = "testLongestCommonPostfix") + public void testSummarizePath() { + testSummarizePathHelper("A", "A", "A"); + testSummarizePathHelper("A", "B", "*"); + testSummarizePathHelper("A.B", "A.B", "A.B"); + testSummarizePathHelper("A.B", "X.B", "*.B"); + testSummarizePathHelper("A.B", "X.Y", "*.*"); + testSummarizePathHelper("A.B.C", "A.B.C", "A.B.C"); + testSummarizePathHelper("A.B.C", "X.B.C", "*.B.C"); + testSummarizePathHelper("A.B.C", "X.Y.C", "*.*.C"); + testSummarizePathHelper("A.B.C", "X.Y.Z", "*.*.*"); + testSummarizePathHelper("A.B.C", "A.X.C", "*.*.C"); + testSummarizePathHelper("A.B.C", "A.X.Z", "*.*.*"); + testSummarizePathHelper("A.B.C", "A.B.Z", "*.*.*"); + } + + public void testSummarizePathHelper(String p1, String p2, String expected) { + String[] parts1 = DiffEngine.diffNameToPath(p1); + String[] parts2 = DiffEngine.diffNameToPath(p2); + int obs = DiffEngine.longestCommonPostfix(parts1, parts2); + String path = DiffEngine.summarizedPath(parts2, obs); + Assert.assertEquals(path, expected, "p1=" + p1 + " p2=" + p2 + " failed"); + } + + // -------------------------------------------------------------------------------- + // + // High-level difference summary + // + // -------------------------------------------------------------------------------- + + private class SummarizeDifferenceTest extends TestDataProvider { + List diffs = new ArrayList(); + List expecteds = new ArrayList(); + + public SummarizeDifferenceTest() { super(SummarizeDifferenceTest.class); } + + public SummarizeDifferenceTest addDiff(String... diffsToAdd) { + diffs.addAll(Arrays.asList(diffsToAdd)); + return this; + } + + public SummarizeDifferenceTest addSummary(String... expectedSummary) { + expecteds.addAll(Arrays.asList(expectedSummary)); + return this; + } + + public String toString() { + return String.format("diffs=%s => expected=%s", diffs, expecteds); + } + + public void test() { + List diffPaths = new ArrayList(diffs.size()); + for ( String diff : diffs ) { diffPaths.add(DiffEngine.diffNameToPath(diff)); } + + List sumDiffs = engine.summarizedDifferencesOfPaths(diffPaths); + + Assert.assertEquals(sumDiffs.size(), expecteds.size(), "Unexpected number of summarized differences: " + sumDiffs); + + for ( int i = 0; i < sumDiffs.size(); i++ ) { + DiffEngine.SummarizedDifference sumDiff = sumDiffs.get(i); + String expected = expecteds.get(i); + String[] pathCount = expected.split(":"); + String path = pathCount[0]; + int count = Integer.valueOf(pathCount[1]); + Assert.assertEquals(sumDiff.getPath(), path, "Unexpected path at: " + expected + " obs=" + sumDiff + " all=" + sumDiffs); + Assert.assertEquals(sumDiff.getCount(), count, "Unexpected counts at: " + expected + " obs=" + sumDiff + " all=" + sumDiffs); + } + } + } + + @DataProvider(name = "summaries") + public Object[][] createSummaries() { + new SummarizeDifferenceTest().addDiff("A", "A").addSummary("A:2"); + new SummarizeDifferenceTest().addDiff("A", "B").addSummary("A:1", "B:1"); + new SummarizeDifferenceTest().addDiff("A", "A", "A").addSummary("A:3"); + new SummarizeDifferenceTest().addDiff("A", "A", "A", "B").addSummary("A:3", "B:1"); + new SummarizeDifferenceTest().addDiff("A", "A", "A", "B", "B").addSummary("A:3", "B:2"); + new SummarizeDifferenceTest().addDiff("A", "A", "A", "B", "B", "C").addSummary("A:3", "B:2", "C:1"); + new SummarizeDifferenceTest().addDiff("A.X", "A.X").addSummary("A.X:2"); + new SummarizeDifferenceTest().addDiff("A.X", "A.X", "B.X").addSummary("*.X:3", "A.X:2", "B.X:1"); + new SummarizeDifferenceTest().addDiff("A.X", "A.X", "B.X", "B.X").addSummary("*.X:4", "A.X:2", "B.X:2"); + new SummarizeDifferenceTest().addDiff("A.B.C", "X.B.C").addSummary("*.B.C:2", "A.B.C:1", "X.B.C:1"); + new SummarizeDifferenceTest().addDiff("A.B.C", "X.Y.C", "X.Y.C").addSummary("*.*.C:3", "X.Y.C:2", "A.B.C:1"); + new SummarizeDifferenceTest().addDiff("A.B.C", "A.X.C", "X.Y.C").addSummary("*.*.C:3", "A.B.C:1", "A.X.C:1", "X.Y.C:1"); + new SummarizeDifferenceTest().addDiff("A.B.C", "A.X.C", "B.X.C").addSummary("*.*.C:3", "*.X.C:2", "A.B.C:1", "A.X.C:1", "B.X.C:1"); + new SummarizeDifferenceTest().addDiff("A.B.C", "A.X.C", "B.X.C", "B.X.C").addSummary("*.*.C:4", "*.X.C:3", "B.X.C:2", "A.B.C:1", "A.X.C:1"); + + return SummarizeDifferenceTest.getTests(SummarizeDifferenceTest.class); + } + + + @Test(enabled = true, dependsOnMethods = "testSummarizePath", dataProvider = "summaries") + public void testSummarizeDifferences(SummarizeDifferenceTest test) { + test.test(); + } +} \ No newline at end of file diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNodeUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNodeUnitTest.java new file mode 100644 index 000000000..534416d29 --- /dev/null +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNodeUnitTest.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2011, 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. + */ + +// our package +package org.broadinstitute.sting.gatk.walkers.diffengine; + + +// the imports for unit testing. + + +import org.broadinstitute.sting.BaseTest; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.*; + +/** + * Basic unit test for DifferableReaders in reduced reads + */ +public class DiffNodeUnitTest extends BaseTest { + // Data is: + // MY_ROOT + // fields: A=A, B=B + // nodes: C, D + // C: fields: E=E, nodes: none + // D: fields: F=F, G=G, nodes: none + static DiffNode MY_ROOT = DiffNode.rooted("MY_ROOT"); + static DiffValue Value_A = new DiffValue("A", MY_ROOT, "A"); + static DiffValue Value_B = new DiffValue("B", MY_ROOT, "B"); + static DiffNode NODE_C = DiffNode.empty("C", MY_ROOT); + static DiffNode NODE_D = DiffNode.empty("D", MY_ROOT); + static DiffValue Value_E = new DiffValue("E", NODE_C, "E"); + static DiffValue Value_F = new DiffValue("F", NODE_D, "F"); + static DiffValue Value_G = new DiffValue("G", NODE_D, "G"); + + static { + MY_ROOT.add(Value_A); + MY_ROOT.add(Value_B); + MY_ROOT.add(NODE_C); + MY_ROOT.add(NODE_D); + NODE_C.add(Value_E); + NODE_D.add(Value_F); + NODE_D.add(Value_G); + } + + + // -------------------------------------------------------------------------------- + // + // Element testing routines + // + // -------------------------------------------------------------------------------- + + private class ElementTest extends TestDataProvider { + public DiffElement elt; + public String name; + public String fullName; + public DiffElement parent; + + private ElementTest(DiffValue elt, DiffValue parent, String name, String fullName) { + this(elt.getBinding(), parent.getBinding(), name, fullName); + } + + private ElementTest(DiffElement elt, DiffElement parent, String name, String fullName) { + super(ElementTest.class); + this.elt = elt; + this.name = name; + this.fullName = fullName; + this.parent = parent; + } + + public String toString() { + return String.format("ElementTest elt=%s name=%s fullName=%s parent=%s", + elt.toOneLineString(), name, fullName, parent.getName()); + } + } + + @DataProvider(name = "elementdata") + public Object[][] createElementData() { + new ElementTest(MY_ROOT.getBinding(), DiffElement.ROOT, "MY_ROOT", "MY_ROOT"); + new ElementTest(NODE_C, MY_ROOT, "C", "MY_ROOT.C"); + new ElementTest(NODE_D, MY_ROOT, "D", "MY_ROOT.D"); + new ElementTest(Value_A, MY_ROOT, "A", "MY_ROOT.A"); + new ElementTest(Value_B, MY_ROOT, "B", "MY_ROOT.B"); + new ElementTest(Value_E, NODE_C, "E", "MY_ROOT.C.E"); + new ElementTest(Value_F, NODE_D, "F", "MY_ROOT.D.F"); + new ElementTest(Value_G, NODE_D, "G", "MY_ROOT.D.G"); + return TestDataProvider.getTests(ElementTest.class); + } + + @Test(enabled = true, dataProvider = "elementdata") + public void testElementMethods(ElementTest test) { + Assert.assertNotNull(test.elt.getName()); + Assert.assertNotNull(test.elt.getParent()); + Assert.assertEquals(test.elt.getName(), test.name); + Assert.assertEquals(test.elt.getParent(), test.parent); + Assert.assertEquals(test.elt.fullyQualifiedName(), test.fullName); + } + + // -------------------------------------------------------------------------------- + // + // DiffValue testing routines + // + // -------------------------------------------------------------------------------- + + private class LeafTest extends TestDataProvider { + public DiffValue diffvalue; + public Object value; + + private LeafTest(DiffValue diffvalue, Object value) { + super(LeafTest.class); + this.diffvalue = diffvalue; + this.value = value; + } + + public String toString() { + return String.format("LeafTest diffvalue=%s value=%s", diffvalue.toOneLineString(), value); + } + } + + @DataProvider(name = "leafdata") + public Object[][] createLeafData() { + new LeafTest(Value_A, "A"); + new LeafTest(Value_B, "B"); + new LeafTest(Value_E, "E"); + new LeafTest(Value_F, "F"); + new LeafTest(Value_G, "G"); + return TestDataProvider.getTests(LeafTest.class); + } + + @Test(enabled = true, dataProvider = "leafdata") + public void testLeafMethods(LeafTest test) { + Assert.assertNotNull(test.diffvalue.getValue()); + Assert.assertEquals(test.diffvalue.getValue(), test.value); + } + + // -------------------------------------------------------------------------------- + // + // Node testing routines + // + // -------------------------------------------------------------------------------- + + private class NodeTest extends TestDataProvider { + public DiffNode node; + public Set fields; + public Set subnodes; + public Set allNames; + + private NodeTest(DiffNode node, List fields, List subnodes) { + super(NodeTest.class); + this.node = node; + this.fields = new HashSet(fields); + this.subnodes = new HashSet(subnodes); + this.allNames = new HashSet(fields); + allNames.addAll(subnodes); + } + + public String toString() { + return String.format("NodeTest node=%s fields=%s subnodes=%s", + node.toOneLineString(), fields, subnodes); + } + } + + @DataProvider(name = "nodedata") + public Object[][] createData1() { + new NodeTest(MY_ROOT, Arrays.asList("A", "B"), Arrays.asList("C", "D")); + new NodeTest(NODE_C, Arrays.asList("E"), Collections.emptyList()); + new NodeTest(NODE_D, Arrays.asList("F", "G"), Collections.emptyList()); + return TestDataProvider.getTests(NodeTest.class); + } + + @Test(enabled = true, dataProvider = "nodedata") + public void testNodeAccessors(NodeTest test) { + Assert.assertNotNull(test.node.getElements()); + + for ( String name : test.allNames ) { + DiffElement elt = test.node.getElement(name); + Assert.assertNotNull(elt, "Failed to find field " + elt + " in " + test.node); + Assert.assertEquals(elt.getName(), name); + Assert.assertEquals(elt.getValue().isAtomic(), test.fields.contains(name), "Failed atomic/compound expectation: " + test.node); + } + } + + // NOTE: add routines are being implicitly tested by the creation of the data structures + + @Test(enabled = true, dataProvider = "nodedata") + public void testCounts(NodeTest test) { + Assert.assertEquals(test.node.getElements().size(), test.allNames.size()); + Assert.assertEquals(test.node.getElementNames(), test.allNames); + } + + // -------------------------------------------------------------------------------- + // + // fromString testing routines + // + // -------------------------------------------------------------------------------- + + private class FromStringTest extends TestDataProvider { + public String string; + public DiffElement expected; + + private FromStringTest(String string, DiffElement expected) { + super(FromStringTest.class); + this.string = string; + this.expected = expected; + } + + public String toString() { + return String.format("FromStringTest string=%s expected=%s", string, expected.toOneLineString()); + } + } + + @DataProvider(name = "fromstringdata") + public Object[][] createFromData() { + new FromStringTest("A=A", Value_A.getBinding()); + new FromStringTest("B=B", Value_B.getBinding()); + new FromStringTest("C=(E=E)", NODE_C.getBinding()); + new FromStringTest("D=(F=F G=G)", NODE_D.getBinding()); + return TestDataProvider.getTests(FromStringTest.class); + } + + @Test(enabled = true, dataProvider = "fromstringdata") + public void parseFromString(FromStringTest test) { + logger.warn("Testing from string: " + test.string); + DiffElement elt = DiffNode.fromString(test.string); + Assert.assertEquals(elt.toOneLineString(), test.expected.toOneLineString()); + } +} \ No newline at end of file diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java new file mode 100644 index 000000000..5738b643f --- /dev/null +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2011, 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. + */ + +// our package +package org.broadinstitute.sting.gatk.walkers.diffengine; + + +// the imports for unit testing. + + +import net.sf.samtools.SAMRecord; +import org.broadinstitute.sting.BaseTest; +import org.broadinstitute.sting.utils.variantcontext.Allele; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.*; + +/** + * Basic unit test for DifferableReaders in reduced reads + */ +public class DiffableReaderUnitTest extends BaseTest { + DiffEngine engine; + + File vcfFile = new File(testDir + "diffTestMaster.vcf"); + File bamFile = new File(testDir + "exampleBAM.bam"); + + @BeforeClass(enabled = true) + public void createDiffEngine() { + engine = new DiffEngine(); + } + + @Test(enabled = true) + public void testPluggableDiffableReaders() { + logger.warn("testPluggableDiffableReaders"); + Map readers = engine.getReaders(); + Assert.assertNotNull(readers); + Assert.assertTrue(readers.size() > 0); + Assert.assertNotNull(readers.get("VCF")); + for ( Map.Entry e : engine.getReaders().entrySet() ) { + logger.warn("Found diffable reader: " + e.getKey()); + Assert.assertEquals(e.getValue().getName(), e.getKey()); + Assert.assertEquals(e.getValue(), engine.getReader(e.getKey())); + } + } + + private static void testLeaf(DiffNode rec, String field, Object expected) { + DiffElement value = rec.getElement(field); + Assert.assertNotNull(value, "Expected to see leaf named " + field + " in rec " + rec); + Assert.assertEquals(value.getValue().getValue(), expected, "Expected to leaf named " + field + " to have value " + expected + " in rec " + rec); + } + + @Test(enabled = true, dependsOnMethods = "testPluggableDiffableReaders") + public void testVCF1() { + logger.warn("testVCF1"); + DiffableReader vcfReader = engine.getReader("VCF"); + Assert.assertTrue(vcfReader.canRead(vcfFile)); + Assert.assertFalse(vcfReader.canRead(bamFile)); + + DiffElement diff = vcfReader.readFromFile(vcfFile); + Assert.assertNotNull(diff); + + Assert.assertEquals(diff.getName(), vcfFile.getName()); + Assert.assertSame(diff.getParent(), DiffElement.ROOT); + + DiffNode node = diff.getValueAsNode(); + Assert.assertEquals(node.getElements().size(), 9); + + // chr1 2646 rs62635284 G A 0.15 PASS AC=2;AF=1.00;AN=2 GT:AD:DP:GL:GQ 1/1:53,75:3:-12.40,-0.90,-0.00:9.03 + DiffNode rec1 = node.getElement("chr1:2646").getValueAsNode(); + testLeaf(rec1, "CHROM", "chr1"); + testLeaf(rec1, "POS", 2646); + testLeaf(rec1, "ID", "rs62635284"); + testLeaf(rec1, "REF", Allele.create("G", true)); + testLeaf(rec1, "ALT", new HashSet(Arrays.asList(Allele.create("A")))); + testLeaf(rec1, "QUAL", 0.15); + testLeaf(rec1, "FILTER", Collections.emptySet()); + testLeaf(rec1, "AC", "2"); + testLeaf(rec1, "AF", "1.00"); + testLeaf(rec1, "AN", "2"); + } + + @Test(enabled = true, dependsOnMethods = "testPluggableDiffableReaders") + public void testBAM() { + logger.warn("testBAM"); + DiffableReader bamReader = engine.getReader("BAM"); + Assert.assertTrue(bamReader.canRead(bamFile)); + Assert.assertFalse(bamReader.canRead(vcfFile)); + + DiffElement diff = bamReader.readFromFile(bamFile); + Assert.assertNotNull(diff); + + Assert.assertEquals(diff.getName(), bamFile.getName()); + Assert.assertSame(diff.getParent(), DiffElement.ROOT); + + DiffNode node = diff.getValueAsNode(); + Assert.assertEquals(node.getElements().size(), 33); + + // 30PPJAAXX090125:1:42:512:1817#0 99 chr1 200 0 76M = + // 255 -130 ACCCTAACCCTAACCCTAACCCTAACCATAACCCTAAGACTAACCCTAAACCTAACCCTCATAATCGAAATACAAC + // BBBBC@C?AABCBB<63>=B@>+B9-9+)2B8,+@327B5A>90((>-+''3?(/'''A)(''19('7.,**%)3: + // PG:Z:0 RG:Z:exampleBAM.bam SM:Z:exampleBAM.bam + + DiffNode rec1 = node.getElement("30PPJAAXX090125:1:42:512:1817#0_1").getValueAsNode(); + testLeaf(rec1, "NAME", "30PPJAAXX090125:1:42:512:1817#0"); + testLeaf(rec1, "FLAGS", 99); + testLeaf(rec1, "RNAME", "chr1"); + testLeaf(rec1, "POS", 200); + testLeaf(rec1, "MAPQ", 0); + testLeaf(rec1, "CIGAR", "76M"); + testLeaf(rec1, "RNEXT", "chr1"); + testLeaf(rec1, "PNEXT", 255); + testLeaf(rec1, "TLEN", -130); + testLeaf(rec1, "SEQ", "ACCCTAACCCTAACCCTAACCCTAACCATAACCCTAAGACTAACCCTAAACCTAACCCTCATAATCGAAATACAAC"); + testLeaf(rec1, "QUAL", "BBBBC@C?AABCBB<63>=B@>+B9-9+)2B8,+@327B5A>90((>-+''3?(/'''A)(''19('7.,**%)3:"); + testLeaf(rec1, "PG", "0"); + testLeaf(rec1, "RG", "exampleBAM.bam"); + testLeaf(rec1, "SM", "exampleBAM.bam"); + } +} \ No newline at end of file diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DifferenceUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DifferenceUnitTest.java new file mode 100644 index 000000000..da272ec30 --- /dev/null +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DifferenceUnitTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, 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. + */ + +// our package +package org.broadinstitute.sting.gatk.walkers.diffengine; + + +// the imports for unit testing. + + +import org.broadinstitute.sting.BaseTest; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Basic unit test for DifferableReaders in reduced reads + */ +public class DifferenceUnitTest extends BaseTest { + // -------------------------------------------------------------------------------- + // + // testing routines + // + // -------------------------------------------------------------------------------- + + private class DifferenceTest extends TestDataProvider { + public DiffElement tree1, tree2; + public String difference; + + private DifferenceTest(String tree1, String tree2, String difference) { + this(DiffNode.fromString(tree1), DiffNode.fromString(tree2), difference); + } + + private DifferenceTest(DiffElement tree1, DiffElement tree2, String difference) { + super(DifferenceTest.class); + this.tree1 = tree1; + this.tree2 = tree2; + this.difference = difference; + } + + public String toString() { + return String.format("tree1=%s tree2=%s diff=%s", + tree1 == null ? "null" : tree1.toOneLineString(), + tree2 == null ? "null" : tree2.toOneLineString(), + difference); + } + } + + @DataProvider(name = "data") + public Object[][] createTrees() { + new DifferenceTest("A=X", "A=Y", "A:X!=Y"); + new DifferenceTest("A=Y", "A=X", "A:Y!=X"); + new DifferenceTest(DiffNode.fromString("A=X"), null, "A:X!=MISSING"); + new DifferenceTest(null, DiffNode.fromString("A=X"), "A:MISSING!=X"); + return DifferenceTest.getTests(DifferenceTest.class); + } + + @Test(enabled = true, dataProvider = "data") + public void testDiffToString(DifferenceTest test) { + logger.warn("Test tree1: " + (test.tree1 == null ? "null" : test.tree1.toOneLineString())); + logger.warn("Test tree2: " + (test.tree2 == null ? "null" : test.tree2.toOneLineString())); + logger.warn("Test expected diff : " + test.difference); + Difference diff = new Difference(test.tree1, test.tree2); + logger.warn("Observed diffs : " + diff); + Assert.assertEquals(diff.toString(), test.difference, "Observed diff string " + diff + " not equal to expected difference string " + test.difference ); + + } +} \ No newline at end of file From 8056a3fe89046d942c4b656ff8138283e0235769 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Tue, 12 Jul 2011 08:52:31 -0400 Subject: [PATCH 11/83] getElement() now uses O(1) get from hash instead of linear O(n) search. Enables us to read large files easily. --- .../sting/gatk/walkers/diffengine/DiffNode.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java index 0720e18c0..3e1be8609 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java @@ -107,11 +107,13 @@ public class DiffNode extends DiffValue { return getElements(false); } + /** + * Returns the element bound to name, or null if no such binding exists + * @param name + * @return + */ public DiffElement getElement(String name) { - for ( DiffElement elt : getElements() ) - if ( elt.getName().equals(name) ) - return elt; - return null; + return getElementMap().get(name); } /** From 05212aea62b2f78f7a739257bac86fd0b16d2c5b Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Tue, 12 Jul 2011 08:53:19 -0400 Subject: [PATCH 12/83] reader now takes an argument for the maximum number of elements to read from the file. --- .../walkers/diffengine/BAMDiffableReader.java | 5 ++--- .../gatk/walkers/diffengine/DiffEngine.java | 7 ++++++- .../walkers/diffengine/DiffObjectsWalker.java | 17 ++++++++++------- .../gatk/walkers/diffengine/DiffableReader.java | 2 +- .../walkers/diffengine/VCFDiffableReader.java | 10 ++++++++-- .../diffengine/DiffableReaderUnitTest.java | 4 ++-- 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/BAMDiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/BAMDiffableReader.java index f7a395d9d..a5ebf27bb 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/BAMDiffableReader.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/BAMDiffableReader.java @@ -51,12 +51,11 @@ import java.util.zip.GZIPInputStream; * Class implementing diffnode reader for VCF */ public class BAMDiffableReader implements DiffableReader { - private final static int MAX_RECORDS_TO_READ = 1000; @Override public String getName() { return "BAM"; } @Override - public DiffElement readFromFile(File file) { + public DiffElement readFromFile(File file, int maxElementsToRead) { final SAMFileReader reader = new SAMFileReader(file, null); // null because we don't want it to look for the index reader.setValidationStringency(SAMFileReader.ValidationStringency.SILENT); @@ -65,7 +64,7 @@ public class BAMDiffableReader implements DiffableReader { int count = 0; while ( iterator.hasNext() ) { - if ( count++ > MAX_RECORDS_TO_READ ) + if ( count++ > maxElementsToRead && maxElementsToRead != -1) break; final SAMRecord record = iterator.next(); diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java index ba2713bff..54a7a464d 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java @@ -385,12 +385,17 @@ public class DiffEngine { return findReaderForFile(file) != null; } + public DiffElement createDiffableFromFile(File file) { + return createDiffableFromFile(file, -1); + } + + public DiffElement createDiffableFromFile(File file, int maxElementsToRead) { DiffableReader reader = findReaderForFile(file); if ( reader == null ) throw new UserException("Unsupported file type: " + file); else - return reader.readFromFile(file); + return reader.readFromFile(file, maxElementsToRead); } public static boolean simpleDiffFiles(File masterFile, File testFile, DiffEngine.SummaryReportParams params) { diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java index a08108db2..fe411b195 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java @@ -48,11 +48,14 @@ public class DiffObjectsWalker extends RodWalker { @Output(doc="File to which results should be written",required=true) protected PrintStream out; - @Argument(fullName="maxRecords", shortName="M", doc="Max. number of records to process", required=false) - int MAX_RECORDS = 0; + @Argument(fullName="maxObjectsToRead", shortName="motr", doc="Max. number of objects to read from the files. -1 [default] means unlimited", required=false) + int MAX_OBJECTS_TO_READ = -1; - @Argument(fullName="maxCount1Records", shortName="M1", doc="Max. number of records occuring exactly once in the file to process", required=false) - int MAX_COUNT1_RECORDS = 0; + @Argument(fullName="maxDiffs", shortName="M", doc="Max. number of diffs to process", required=false) + int MAX_DIFFS = 0; + + @Argument(fullName="maxCount1Diffs", shortName="M1", doc="Max. number of diffs occuring exactly once in the file to process", required=false) + int MAX_COUNT1_DIFFS = 0; @Argument(fullName="minCountForDiff", shortName="MCFD", doc="Min number of observations for a records to display", required=false) int minCountForDiff = 1; @@ -91,9 +94,9 @@ public class DiffObjectsWalker extends RodWalker { @Override public void onTraversalDone(Integer sum) { out.printf("Reading master file %s%n", masterFile); - DiffElement master = diffEngine.createDiffableFromFile(masterFile); + DiffElement master = diffEngine.createDiffableFromFile(masterFile, MAX_OBJECTS_TO_READ); out.printf("Reading test file %s%n", testFile); - DiffElement test = diffEngine.createDiffableFromFile(testFile); + DiffElement test = diffEngine.createDiffableFromFile(testFile, MAX_OBJECTS_TO_READ); // out.printf("Master diff objects%n"); // out.println(master.toString()); @@ -107,7 +110,7 @@ public class DiffObjectsWalker extends RodWalker { out.printf("DIFF: %s%n", diff.toString()); } - DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(out, MAX_RECORDS, MAX_COUNT1_RECORDS, minCountForDiff); + DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(out, MAX_DIFFS, MAX_COUNT1_DIFFS, minCountForDiff); diffEngine.reportSummarizedDifferences(diffs, params); } } \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java index 84c2eed10..af5771c55 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java @@ -43,7 +43,7 @@ public interface DiffableReader { @Ensures("result != null") @Requires("file != null") - public DiffElement readFromFile(File file); + public DiffElement readFromFile(File file, int maxElementsToRead); @Requires("file != null") public boolean canRead(File file); diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java index 743178538..06d14366f 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java @@ -51,15 +51,21 @@ public class VCFDiffableReader implements DiffableReader { public String getName() { return "VCF"; } @Override - public DiffElement readFromFile(File file) { + public DiffElement readFromFile(File file, int maxElementsToRead) { DiffNode root = DiffNode.rooted(file.getName()); try { LineReader lineReader = new AsciiLineReader(new FileInputStream(file)); VCFCodec vcfCodec = new VCFCodec(); - VCFHeader header = (VCFHeader)vcfCodec.readHeader(lineReader); + + // must be read as state is stored in reader itself + vcfCodec.readHeader(lineReader); String line = lineReader.readLine(); + int count = 0; while ( line != null ) { + if ( count++ > maxElementsToRead && maxElementsToRead != -1) + break; + VariantContext vc = (VariantContext)vcfCodec.decode(line); String name = vc.getChr() + ":" + vc.getStart(); DiffNode vcRoot = DiffNode.empty(name, root); diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java index 5738b643f..baa2f0383 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java @@ -80,7 +80,7 @@ public class DiffableReaderUnitTest extends BaseTest { Assert.assertTrue(vcfReader.canRead(vcfFile)); Assert.assertFalse(vcfReader.canRead(bamFile)); - DiffElement diff = vcfReader.readFromFile(vcfFile); + DiffElement diff = vcfReader.readFromFile(vcfFile, -1); Assert.assertNotNull(diff); Assert.assertEquals(diff.getName(), vcfFile.getName()); @@ -110,7 +110,7 @@ public class DiffableReaderUnitTest extends BaseTest { Assert.assertTrue(bamReader.canRead(bamFile)); Assert.assertFalse(bamReader.canRead(vcfFile)); - DiffElement diff = bamReader.readFromFile(bamFile); + DiffElement diff = bamReader.readFromFile(bamFile, -1); Assert.assertNotNull(diff); Assert.assertEquals(diff.getName(), bamFile.getName()); From cfe43e3971327ff26ef9087e31b4294d4a98d99c Mon Sep 17 00:00:00 2001 From: Guillermo del Angel Date: Tue, 12 Jul 2011 13:43:46 -0400 Subject: [PATCH 14/83] Bug fix for Genotype given alleles: if we are in INDEL mode ignore SNPs and MNPs instead of emitting an empty site with alleles but no annotations --- .../genotyper/UnifiedGenotyperEngine.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperEngine.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperEngine.java index 4c9080884..6fc972b5d 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperEngine.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperEngine.java @@ -634,17 +634,27 @@ public class UnifiedGenotyperEngine { if (vcInput == null) return null; - if (vcInput.isSNP() && ( UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.BOTH || UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.SNP)) - return GenotypeLikelihoodsCalculationModel.Model.SNP; + // todo - no support to genotype MNP's yet + if (vcInput.isMNP()) + return null; + + if (vcInput.isSNP()) { + if (( UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.BOTH || UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.SNP)) + return GenotypeLikelihoodsCalculationModel.Model.SNP; + else + // ignore SNP's if user chose INDEL mode + return null; + } else if ((vcInput.isIndel() || vcInput.isMixed()) && (UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.BOTH || UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.INDEL)) return GenotypeLikelihoodsCalculationModel.Model.INDEL; - } else { + } + else { // todo - this assumes SNP's take priority when BOTH is selected, should do a smarter way once extended events are removed if( UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.BOTH || UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.SNP) return GenotypeLikelihoodsCalculationModel.Model.SNP; else if (UAC.GLmodel == GenotypeLikelihoodsCalculationModel.Model.INDEL) return GenotypeLikelihoodsCalculationModel.Model.INDEL; - } + } } return null; } From 73735863b0fbff0e7dc5ee789f2e075ead13f7fa Mon Sep 17 00:00:00 2001 From: Ryan Poplin Date: Tue, 12 Jul 2011 13:55:21 -0400 Subject: [PATCH 15/83] Fix for the case of requesting genotype for a sample that doesn't exist in a VariantContext --- .../sting/utils/variantcontext/VariantContext.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java b/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java index 5787b591f..da80a3431 100755 --- a/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java +++ b/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java @@ -867,7 +867,10 @@ public class VariantContext implements Feature { // to enable tribble intergrati for ( String name : sampleNames ) { if ( map.containsKey(name) ) throw new IllegalArgumentException("Duplicate names detected in requested samples " + sampleNames); - map.put(name, getGenotype(name)); + final Genotype g = getGenotype(name); + if ( g != null ) { + map.put(name, g); + } } return map; From a2597e7f00824b37174a648da7c648938f5c4886 Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Tue, 12 Jul 2011 14:11:53 -0400 Subject: [PATCH 16/83] This commit incorporates several different changes that each pretty much break all the VCF-based integration tests, so I bunched them all together. We now officially emit VCF4.1 files (woo hoo), which means that the VCF headers are now all different (header version is 4.1 plus counts for some of the annotations are 'A' or 'G'). Also, I've added a Read Filter for reads with MQ=255 ('unavailable' in the SAM spec) and have applied this to the UG and the RMS MQ annotation. --- .../MappingQualityUnavailableReadFilter.java | 43 +++++++++++++++++ ...java => MappingQualityZeroReadFilter.java} | 5 +- .../annotator/AlleleBalanceBySample.java | 2 +- .../walkers/annotator/ChromosomeCounts.java | 4 +- .../annotator/MappingQualityRankSumTest.java | 7 ++- .../gatk/walkers/annotator/NBaseCount.java | 2 +- .../walkers/annotator/RMSMappingQuality.java | 7 ++- .../gatk/walkers/annotator/RankSumTest.java | 5 +- .../walkers/genotyper/UnifiedGenotyper.java | 5 +- .../indels/RealignerTargetCreator.java | 4 +- .../indels/SomaticIndelDetectorWalker.java | 2 +- .../phasing/ReadBackedPhasingWalker.java | 4 +- .../recalibration/CountCovariatesWalker.java | 4 +- .../sting/utils/QualityUtils.java | 4 ++ .../utils/codecs/vcf/StandardVCFWriter.java | 6 +-- .../VariantAnnotatorIntegrationTest.java | 28 +++++------ .../GenomicAnnotatorIntegrationTest.java | 6 +-- .../walkers/beagle/BeagleIntegrationTest.java | 6 +-- .../VariantFiltrationIntegrationTest.java | 22 ++++----- .../UnifiedGenotyperIntegrationTest.java | 48 +++++++++---------- .../ReadBackedPhasingIntegrationTest.java | 12 ++--- ...ntRecalibrationWalkersIntegrationTest.java | 2 +- .../CombineVariantsIntegrationTest.java | 34 ++++++------- .../LiftoverVariantsIntegrationTest.java | 6 +-- .../SelectVariantsIntegrationTest.java | 8 ++-- .../VCFStreamingIntegrationTest.java | 2 +- .../VariantsToVCFIntegrationTest.java | 8 ++-- .../VariantContextIntegrationTest.java | 2 +- 28 files changed, 169 insertions(+), 119 deletions(-) create mode 100644 public/java/src/org/broadinstitute/sting/gatk/filters/MappingQualityUnavailableReadFilter.java rename public/java/src/org/broadinstitute/sting/gatk/filters/{ZeroMappingQualityReadFilter.java => MappingQualityZeroReadFilter.java} (90%) diff --git a/public/java/src/org/broadinstitute/sting/gatk/filters/MappingQualityUnavailableReadFilter.java b/public/java/src/org/broadinstitute/sting/gatk/filters/MappingQualityUnavailableReadFilter.java new file mode 100644 index 000000000..cecbedda8 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/filters/MappingQualityUnavailableReadFilter.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009 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.sting.gatk.filters; + +import net.sf.picard.util.QualityUtil; +import net.sf.samtools.SAMRecord; +import org.broadinstitute.sting.utils.QualityUtils; + +/** + * Filter out mapping quality zero reads. + * + * @author ebanks + * @version 0.1 + */ + +public class MappingQualityUnavailableReadFilter extends ReadFilter { + public boolean filterOut(SAMRecord rec) { + return (rec.getMappingQuality() == QualityUtils.MAPPING_QUALITY_UNAVAILABLE); + } +} + diff --git a/public/java/src/org/broadinstitute/sting/gatk/filters/ZeroMappingQualityReadFilter.java b/public/java/src/org/broadinstitute/sting/gatk/filters/MappingQualityZeroReadFilter.java similarity index 90% rename from public/java/src/org/broadinstitute/sting/gatk/filters/ZeroMappingQualityReadFilter.java rename to public/java/src/org/broadinstitute/sting/gatk/filters/MappingQualityZeroReadFilter.java index 7e6fc5e82..e49d4117c 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/filters/ZeroMappingQualityReadFilter.java +++ b/public/java/src/org/broadinstitute/sting/gatk/filters/MappingQualityZeroReadFilter.java @@ -24,17 +24,16 @@ package org.broadinstitute.sting.gatk.filters; -import net.sf.picard.filter.SamRecordFilter; import net.sf.samtools.SAMRecord; /** - * Filter out zero mapping quality reads. + * Filter out mapping quality zero reads. * * @author hanna * @version 0.1 */ -public class ZeroMappingQualityReadFilter extends ReadFilter { +public class MappingQualityZeroReadFilter extends ReadFilter { public boolean filterOut(SAMRecord rec) { return (rec.getMappingQuality() == 0); } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/AlleleBalanceBySample.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/AlleleBalanceBySample.java index 0be737897..51d290763 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/AlleleBalanceBySample.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/AlleleBalanceBySample.java @@ -62,5 +62,5 @@ public class AlleleBalanceBySample implements GenotypeAnnotation, ExperimentalAn public List getKeyNames() { return Arrays.asList("AB"); } - public List getDescriptions() { return Arrays.asList(new VCFFormatHeaderLine(getKeyNames().get(0), -1, VCFHeaderLineType.Float, "Allele balance for each het genotype")); } + public List getDescriptions() { return Arrays.asList(new VCFFormatHeaderLine(getKeyNames().get(0), 1, VCFHeaderLineType.Float, "Allele balance for each het genotype")); } } \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ChromosomeCounts.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ChromosomeCounts.java index ed10d2072..f3ec2b1df 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ChromosomeCounts.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/ChromosomeCounts.java @@ -42,8 +42,8 @@ import java.util.*; public class ChromosomeCounts implements InfoFieldAnnotation, StandardAnnotation { private String[] keyNames = { VCFConstants.ALLELE_NUMBER_KEY, VCFConstants.ALLELE_COUNT_KEY, VCFConstants.ALLELE_FREQUENCY_KEY }; - private VCFInfoHeaderLine[] descriptions = { new VCFInfoHeaderLine(VCFConstants.ALLELE_FREQUENCY_KEY, VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Float, "Allele Frequency, for each ALT allele, in the same order as listed"), - new VCFInfoHeaderLine(VCFConstants.ALLELE_COUNT_KEY, VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.Integer, "Allele count in genotypes, for each ALT allele, in the same order as listed"), + private VCFInfoHeaderLine[] descriptions = { new VCFInfoHeaderLine(VCFConstants.ALLELE_FREQUENCY_KEY, VCFHeaderLineCount.A, VCFHeaderLineType.Float, "Allele Frequency, for each ALT allele, in the same order as listed"), + new VCFInfoHeaderLine(VCFConstants.ALLELE_COUNT_KEY, VCFHeaderLineCount.A, VCFHeaderLineType.Integer, "Allele count in genotypes, for each ALT allele, in the same order as listed"), new VCFInfoHeaderLine(VCFConstants.ALLELE_NUMBER_KEY, 1, VCFHeaderLineType.Integer, "Total number of alleles in called genotypes") }; public Map annotate(RefMetaDataTracker tracker, ReferenceContext ref, Map stratifiedContexts, VariantContext vc) { diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/MappingQualityRankSumTest.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/MappingQualityRankSumTest.java index 11f86b972..8260a5a81 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/MappingQualityRankSumTest.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/MappingQualityRankSumTest.java @@ -1,5 +1,6 @@ package org.broadinstitute.sting.gatk.walkers.annotator; +import org.broadinstitute.sting.utils.QualityUtils; import org.broadinstitute.sting.utils.variantcontext.Allele; import org.broadinstitute.sting.utils.codecs.vcf.VCFHeaderLineType; import org.broadinstitute.sting.utils.codecs.vcf.VCFInfoHeaderLine; @@ -21,7 +22,7 @@ public class MappingQualityRankSumTest extends RankSumTest { protected void fillQualsFromPileup(byte ref, byte alt, ReadBackedPileup pileup, List refQuals, List altQuals) { for ( final PileupElement p : pileup ) { - if( isUsableBase(p) && p.getMappingQual() < 254 ) { // 254 and 255 are special mapping qualities used as a code by aligners + if ( isUsableBase(p) ) { if ( p.getBase() == ref ) { refQuals.add((double)p.getMappingQual()); } else if ( p.getBase() == alt ) { @@ -34,7 +35,7 @@ public class MappingQualityRankSumTest extends RankSumTest { // equivalent is whether indel likelihoods for reads corresponding to ref allele are more likely than reads corresponding to alt allele ? HashMap> indelLikelihoodMap = IndelGenotypeLikelihoodsCalculationModel.getIndelLikelihoodMap(); for (final PileupElement p: pileup) { - if (indelLikelihoodMap.containsKey(p) && p.getMappingQual() < 254) { + if (indelLikelihoodMap.containsKey(p) && p.getMappingQual() != 0 && p.getMappingQual() != QualityUtils.MAPPING_QUALITY_UNAVAILABLE) { // retrieve likelihood information corresponding to this read LinkedHashMap el = indelLikelihoodMap.get(p); // by design, first element in LinkedHashMap was ref allele @@ -54,8 +55,6 @@ public class MappingQualityRankSumTest extends RankSumTest { refQuals.add((double)p.getMappingQual()); else if (altLikelihood > refLikelihood + INDEL_LIKELIHOOD_THRESH) altQuals.add((double)p.getMappingQual()); - - } } } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/NBaseCount.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/NBaseCount.java index ba3e2cc8b..3b64abfff 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/NBaseCount.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/NBaseCount.java @@ -47,5 +47,5 @@ public class NBaseCount implements InfoFieldAnnotation { public List getKeyNames() { return Arrays.asList("PercentNBaseSolid"); } - public List getDescriptions() { return Arrays.asList(new VCFInfoHeaderLine("PercentNBaseSolid", 4, VCFHeaderLineType.Float, "Percentage of N bases in the pileup (counting only SOLiD reads)")); } + public List getDescriptions() { return Arrays.asList(new VCFInfoHeaderLine("PercentNBaseSolid", 1, VCFHeaderLineType.Float, "Percentage of N bases in the pileup (counting only SOLiD reads)")); } } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/RMSMappingQuality.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/RMSMappingQuality.java index 6e80c7555..1ef7ccd0b 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/RMSMappingQuality.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/RMSMappingQuality.java @@ -1,5 +1,6 @@ package org.broadinstitute.sting.gatk.walkers.annotator; +import org.broadinstitute.sting.utils.QualityUtils; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.utils.codecs.vcf.VCFConstants; import org.broadinstitute.sting.utils.codecs.vcf.VCFHeaderLineType; @@ -38,8 +39,10 @@ public class RMSMappingQuality implements InfoFieldAnnotation, StandardAnnotatio pileup = context.getBasePileup(); if (pileup != null) { - for (PileupElement p : pileup ) - qualities[index++] = p.getRead().getMappingQuality(); + for (PileupElement p : pileup ) { + if ( p.getMappingQual() != QualityUtils.MAPPING_QUALITY_UNAVAILABLE ) + qualities[index++] = p.getMappingQual(); + } } } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/RankSumTest.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/RankSumTest.java index 1a967293f..f00abd6a1 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/RankSumTest.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/annotator/RankSumTest.java @@ -106,6 +106,9 @@ public abstract class RankSumTest implements InfoFieldAnnotation, StandardAnnota protected abstract void fillIndelQualsFromPileup(ReadBackedPileup pileup, List refQuals, List altQuals); protected static boolean isUsableBase( final PileupElement p ) { - return !( p.isDeletion() || p.getMappingQual() == 0 || ((int)p.getQual()) < 6 ); // need the unBAQed quality score here + return !( p.isDeletion() || + p.getMappingQual() == 0 || + p.getMappingQual() == QualityUtils.MAPPING_QUALITY_UNAVAILABLE || + ((int)p.getQual()) < QualityUtils.MIN_USABLE_Q_SCORE ); // need the unBAQed quality score here } } \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyper.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyper.java index fe0084a19..fc8a5819a 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyper.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyper.java @@ -25,6 +25,7 @@ package org.broadinstitute.sting.gatk.walkers.genotyper; +import org.broadinstitute.sting.gatk.filters.MappingQualityUnavailableReadFilter; import org.broadinstitute.sting.utils.codecs.vcf.*; import org.broadinstitute.sting.gatk.contexts.*; import org.broadinstitute.sting.gatk.filters.BadMateFilter; @@ -47,7 +48,7 @@ import java.io.PrintStream; * multi-sample data. The user can choose from several different incorporated calculation models. */ @BAQMode(QualityMode = BAQ.QualityMode.ADD_TAG, ApplicationTime = BAQ.ApplicationTime.ON_INPUT) -@ReadFilters( {BadMateFilter.class} ) +@ReadFilters( {BadMateFilter.class, MappingQualityUnavailableReadFilter.class} ) @Reference(window=@Window(start=-200,stop=200)) @By(DataSource.REFERENCE) @Downsample(by=DownsampleType.BY_SAMPLE, toCoverage=250) @@ -175,7 +176,7 @@ public class UnifiedGenotyper extends LocusWalker { // @Output // PrintStream out; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java index e59b29502..4833a6cad 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java @@ -32,7 +32,7 @@ import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.utils.variantcontext.VariantContextUtils; import org.broadinstitute.sting.gatk.datasources.sample.Sample; -import org.broadinstitute.sting.gatk.filters.ZeroMappingQualityReadFilter; +import org.broadinstitute.sting.gatk.filters.MappingQualityZeroReadFilter; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.refdata.ReferenceOrderedDatum; import org.broadinstitute.sting.gatk.walkers.*; @@ -58,7 +58,7 @@ import static org.broadinstitute.sting.utils.codecs.vcf.VCFUtils.getVCFHeadersFr @Requires(value = {DataSource.READS, DataSource.REFERENCE}, referenceMetaData = @RMD(name = "variant", type = ReferenceOrderedDatum.class)) @By(DataSource.READS) -@ReadFilters({ZeroMappingQualityReadFilter.class}) +@ReadFilters({MappingQualityZeroReadFilter.class}) // Filter out all reads with zero mapping quality public class ReadBackedPhasingWalker extends RodWalker { diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/CountCovariatesWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/CountCovariatesWalker.java index ee504b6e7..6673bec92 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/CountCovariatesWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/CountCovariatesWalker.java @@ -34,7 +34,7 @@ import org.broadinstitute.sting.commandline.Output; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.datasources.rmd.ReferenceOrderedDataSource; -import org.broadinstitute.sting.gatk.filters.ZeroMappingQualityReadFilter; +import org.broadinstitute.sting.gatk.filters.MappingQualityZeroReadFilter; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.refdata.utils.GATKFeature; import org.broadinstitute.sting.gatk.walkers.*; @@ -75,7 +75,7 @@ import java.util.Map; @BAQMode(ApplicationTime = BAQ.ApplicationTime.FORBIDDEN) @By( DataSource.READS ) // Only look at covered loci, not every loci of the reference file -@ReadFilters( {ZeroMappingQualityReadFilter.class} ) // Filter out all reads with zero mapping quality +@ReadFilters( {MappingQualityZeroReadFilter.class} ) // Filter out all reads with zero mapping quality @Requires( {DataSource.READS, DataSource.REFERENCE, DataSource.REFERENCE_BASES} ) // This walker requires both -I input.bam and -R reference.fasta @PartitionBy(PartitionType.LOCUS) public class CountCovariatesWalker extends LocusWalker implements TreeReducible { diff --git a/public/java/src/org/broadinstitute/sting/utils/QualityUtils.java b/public/java/src/org/broadinstitute/sting/utils/QualityUtils.java index 23054e95f..fad2320fc 100755 --- a/public/java/src/org/broadinstitute/sting/utils/QualityUtils.java +++ b/public/java/src/org/broadinstitute/sting/utils/QualityUtils.java @@ -9,9 +9,13 @@ import net.sf.samtools.SAMUtils; * @author Kiran Garimella */ public class QualityUtils { + public final static byte MAX_QUAL_SCORE = SAMUtils.MAX_PHRED_SCORE; public final static double MIN_REASONABLE_ERROR = 0.0001; public final static byte MAX_REASONABLE_Q_SCORE = 40; + public final static byte MIN_USABLE_Q_SCORE = 6; + + public final static int MAPPING_QUALITY_UNAVAILABLE = 255; /** * Private constructor. No instantiating this class! diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java index f4996b487..a8bf74707 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java @@ -123,12 +123,10 @@ public class StandardVCFWriter implements VCFWriter { try { // the file format field needs to be written first - mWriter.write(VCFHeader.METADATA_INDICATOR + VCFHeaderVersion.VCF4_0.getFormatString() + "=" + VCFHeaderVersion.VCF4_0.getVersionString() + "\n"); + mWriter.write(VCFHeader.METADATA_INDICATOR + VCFHeaderVersion.VCF4_1.getFormatString() + "=" + VCFHeaderVersion.VCF4_1.getVersionString() + "\n"); for ( VCFHeaderLine line : mHeader.getMetaData() ) { - if ( line.getKey().equals(VCFHeaderVersion.VCF4_0.getFormatString()) || - line.getKey().equals(VCFHeaderVersion.VCF3_3.getFormatString()) || - line.getKey().equals(VCFHeaderVersion.VCF3_2.getFormatString()) ) + if ( VCFHeaderVersion.isFormatString(line.getKey()) ) continue; // are the records filtered (so we know what to put in the FILTER column of passing records) ? diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/annotator/VariantAnnotatorIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/annotator/VariantAnnotatorIntegrationTest.java index 6ba6926c6..e6300e6c9 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/annotator/VariantAnnotatorIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/annotator/VariantAnnotatorIntegrationTest.java @@ -15,7 +15,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testHasAnnotsNotAsking1() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -I " + validationDataLocation + "low_coverage_CEU.chr1.10k-11k.bam -L 1:10,020,000-10,021,000", 1, - Arrays.asList("4cc077eb3d343e6b7ba12bff86ebe347")); + Arrays.asList("8a105fa5eebdfffe7326bc5b3d8ffd1c")); executeTest("test file has annotations, not asking for annotations, #1", spec); } @@ -23,7 +23,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testHasAnnotsNotAsking2() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -B:variant,VCF3 " + validationDataLocation + "vcfexample3.vcf -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -L 1:10,000,000-10,050,000", 1, - Arrays.asList("1de8e943fbf55246ebd19efa32f22a58")); + Arrays.asList("964f1016ec9a3c55333f62dd834c14d6")); executeTest("test file has annotations, not asking for annotations, #2", spec); } @@ -31,7 +31,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testHasAnnotsAsking1() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -G \"Standard\" -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -I " + validationDataLocation + "low_coverage_CEU.chr1.10k-11k.bam -L 1:10,020,000-10,021,000", 1, - Arrays.asList("93c110e45fd4aedb044a8a5501e23336")); + Arrays.asList("8e7de435105499cd71ffc099e268a83e")); executeTest("test file has annotations, asking for annotations, #1", spec); } @@ -39,7 +39,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testHasAnnotsAsking2() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -G \"Standard\" -B:variant,VCF3 " + validationDataLocation + "vcfexample3.vcf -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -L 1:10,000,000-10,050,000", 1, - Arrays.asList("f5cb45910ed719f46159f9f71acaecf4")); + Arrays.asList("64b6804cb1e27826e3a47089349be581")); executeTest("test file has annotations, asking for annotations, #2", spec); } @@ -47,7 +47,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testNoAnnotsNotAsking1() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -B:variant,VCF3 " + validationDataLocation + "vcfexample2empty.vcf -I " + validationDataLocation + "low_coverage_CEU.chr1.10k-11k.bam -L 1:10,020,000-10,021,000", 1, - Arrays.asList("4b48e7d095ef73e3151542ea976ecd89")); + Arrays.asList("42ccee09fa9f8c58f4a0d4f1139c094f")); executeTest("test file doesn't have annotations, not asking for annotations, #1", spec); } @@ -55,7 +55,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testNoAnnotsNotAsking2() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -B:variant,VCF3 " + validationDataLocation + "vcfexample3empty.vcf -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -L 1:10,000,000-10,050,000", 1, - Arrays.asList("28dfbfd178aca071b948cd3dc2365357")); + Arrays.asList("f2ddfa8105c290b1f34b7a261a02a1ac")); executeTest("test file doesn't have annotations, not asking for annotations, #2", spec); } @@ -63,7 +63,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testNoAnnotsAsking1() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -G \"Standard\" -B:variant,VCF3 " + validationDataLocation + "vcfexample2empty.vcf -I " + validationDataLocation + "low_coverage_CEU.chr1.10k-11k.bam -L 1:10,020,000-10,021,000", 1, - Arrays.asList("a330a5bc3ee72a51dbeb7e6c97a0db99")); + Arrays.asList("fd1ffb669800c2e07df1e2719aa38e49")); executeTest("test file doesn't have annotations, asking for annotations, #1", spec); } @@ -71,7 +71,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testNoAnnotsAsking2() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -G \"Standard\" -B:variant,VCF3 " + validationDataLocation + "vcfexample3empty.vcf -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -L 1:10,000,000-10,050,000", 1, - Arrays.asList("3a31d1ef471acfb881a2dec7963fe3f4")); + Arrays.asList("09f8e840770a9411ff77508e0ed0837f")); executeTest("test file doesn't have annotations, asking for annotations, #2", spec); } @@ -79,7 +79,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testOverwritingHeader() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -G \"Standard\" -B:variant,VCF " + validationDataLocation + "vcfexample4.vcf -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -L 1:10,001,292", 1, - Arrays.asList("a63fd8ff7bafbd46b7f009144a7c2ad1")); + Arrays.asList("78d2c19f8107d865970dbaf3e12edd92")); executeTest("test overwriting header", spec); } @@ -87,7 +87,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testNoReads() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -G \"Standard\" -B:variant,VCF3 " + validationDataLocation + "vcfexample3empty.vcf -BTI variant", 1, - Arrays.asList("36378f1245bb99d902fbfe147605bc42")); + Arrays.asList("16e3a1403fc376320d7c69492cad9345")); executeTest("not passing it any reads", spec); } @@ -95,7 +95,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testDBTagWithDbsnp() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -D " + GATKDataLocation + "dbsnp_129_b36.rod -G \"Standard\" -B:variant,VCF3 " + validationDataLocation + "vcfexample3empty.vcf -BTI variant", 1, - Arrays.asList("0257a1cc3c703535b2d3c5046bf88ab7")); + Arrays.asList("3da8ca2b6bdaf6e92d94a8c77a71313d")); executeTest("getting DB tag with dbSNP", spec); } @@ -103,7 +103,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testDBTagWithHapMap() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -B:compH3,VCF " + validationDataLocation + "fakeHM3.vcf -G \"Standard\" -B:variant,VCF3 " + validationDataLocation + "vcfexample3empty.vcf -BTI variant", 1, - Arrays.asList("2d7c73489dcf0db433bebdf79a068764")); + Arrays.asList("1bc01c5b3bd0b7aef75230310c3ce688")); executeTest("getting DB tag with HM3", spec); } @@ -111,13 +111,13 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { public void testUsingExpression() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -B:foo,VCF " + validationDataLocation + "targetAnnotations.vcf -G \"Standard\" -B:variant,VCF3 " + validationDataLocation + "vcfexample3empty.vcf -E foo.AF -BTI variant", 1, - Arrays.asList("2f6efd08d818faa1eb0631844437c64a")); + Arrays.asList("e9c0d832dc6b4ed06c955060f830c140")); executeTest("using expression", spec); } @Test public void testTabixAnnotations() { - final String MD5 = "6c7a6a1c0027bf82656542a9b2671a35"; + final String MD5 = "13269d5a2e16f06fd755cc0fb9271acf"; for ( String file : Arrays.asList("CEU.exon.2010_03.sites.vcf", "CEU.exon.2010_03.sites.vcf.gz")) { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -A HomopolymerRun -B:variant,VCF " + validationDataLocation + "/" + file + " -BTI variant -NO_HEADER", 1, diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/annotator/genomicannotator/GenomicAnnotatorIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/annotator/genomicannotator/GenomicAnnotatorIntegrationTest.java index c4f6d5ebc..c75a5b2dc 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/annotator/genomicannotator/GenomicAnnotatorIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/annotator/genomicannotator/GenomicAnnotatorIntegrationTest.java @@ -29,7 +29,7 @@ public class GenomicAnnotatorIntegrationTest extends WalkerTest { */ - String[] md5WithDashSArg = {"3d3b61a83c1189108eabb2df04218099"}; + String[] md5WithDashSArg = {"efba4ce1641cfa2ef88a64395f2ebce8"}; WalkerTestSpec specWithSArg = new WalkerTestSpec( "-T GenomicAnnotator -R " + b36KGReference + " -B:variant,vcf3 /humgen/gsa-hpprojects/GATK/data/Annotations/examples/CEU_hapmap_nogt_23_subset.vcf" + @@ -58,7 +58,7 @@ public class GenomicAnnotatorIntegrationTest extends WalkerTest { "-o %s" ), 1, - Arrays.asList("caa562160733aa638e1ba413ede209ae") + Arrays.asList("772fc3f43b70770ec6c6acbb8bbbd4c0") ); executeTest("testGenomicAnnotatorOnIndels", testOnIndels); } @@ -76,7 +76,7 @@ public class GenomicAnnotatorIntegrationTest extends WalkerTest { "-o %s" ), 1, - Arrays.asList("a4cf76f08fa90284b6988a464b6e0c17") + Arrays.asList("081ade7f3d2d3c5f19cb1e8651a626f3") ); executeTest("testGenomicAnnotatorOnSNPsAndIndels", testOnSNPsAndIndels); } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/beagle/BeagleIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/beagle/BeagleIntegrationTest.java index 70c34e729..fef1b6e64 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/beagle/BeagleIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/beagle/BeagleIntegrationTest.java @@ -41,7 +41,7 @@ public class BeagleIntegrationTest extends WalkerTest { "-B:beagleR2,BEAGLE " + beagleValidationDataLocation + "inttestbgl.r2 " + "-B:beagleProbs,BEAGLE " + beagleValidationDataLocation + "inttestbgl.gprobs " + "-B:beaglePhased,BEAGLE " + beagleValidationDataLocation + "inttestbgl.phased " + - "-o %s -NO_HEADER", 1, Arrays.asList("6bccee48ad2f06ba5a8c774fed444478")); + "-o %s -NO_HEADER", 1, Arrays.asList("3531451e84208264104040993889aaf4")); executeTest("test BeagleOutputToVCF", spec); } @@ -60,7 +60,7 @@ public class BeagleIntegrationTest extends WalkerTest { "-T ProduceBeagleInput -B:variant,VCF /humgen/gsa-hpprojects/GATK/data/Validation_Data/NA12878_HSQ_chr22_14-16m.vcf "+ "-B:validation,VCF /humgen/gsa-hpprojects/GATK/data/Validation_Data/NA12878_OMNI_chr22_14-16m.vcf "+ "-L 22:14000000-16000000 -o %s -bvcf %s -bs 0.8 -valp 0.98 -R /humgen/1kg/reference/human_g1k_v37.fasta -NO_HEADER ",2, - Arrays.asList("660986891b30cdc937e0f2a3a5743faa","223fb977e8db567dcaf632c6ee51f294")); + Arrays.asList("660986891b30cdc937e0f2a3a5743faa","e96ddd51da9f4a797b2aa8c20e404166")); executeTest("test BeagleInputWithBootstrap",spec); } @@ -72,7 +72,7 @@ public class BeagleIntegrationTest extends WalkerTest { "-B:beagleR2,beagle /humgen/gsa-hpprojects/GATK/data/Validation_Data/EUR_beagle_in_test.r2 "+ "-B:beagleProbs,beagle /humgen/gsa-hpprojects/GATK/data/Validation_Data/EUR_beagle_in_test.gprobs.bgl "+ "-B:beaglePhased,beagle /humgen/gsa-hpprojects/GATK/data/Validation_Data/EUR_beagle_in_test.phased.bgl "+ - "-L 20:1-70000 -o %s -NO_HEADER ",1,Arrays.asList("24b88ef8cdf6e347daab491f0256be5a")); + "-L 20:1-70000 -o %s -NO_HEADER ",1,Arrays.asList("8dd6ec53994fb46c5c22af8535d22965")); executeTest("testBeagleChangesSitesToRef",spec); } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/filters/VariantFiltrationIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/filters/VariantFiltrationIntegrationTest.java index 3d75fdc44..7bec67d2e 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/filters/VariantFiltrationIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/filters/VariantFiltrationIntegrationTest.java @@ -16,7 +16,7 @@ public class VariantFiltrationIntegrationTest extends WalkerTest { public void testNoAction() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("4cc077eb3d343e6b7ba12bff86ebe347")); + Arrays.asList("8a105fa5eebdfffe7326bc5b3d8ffd1c")); executeTest("test no action", spec); } @@ -24,7 +24,7 @@ public class VariantFiltrationIntegrationTest extends WalkerTest { public void testClusteredSnps() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -window 10 -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("ada5540bb3d9b6eb8f1337ba01e90a94")); + Arrays.asList("27b13f179bb4920615dff3a32730d845")); executeTest("test clustered SNPs", spec); } @@ -32,17 +32,17 @@ public class VariantFiltrationIntegrationTest extends WalkerTest { public void testMasks() { WalkerTestSpec spec1 = new WalkerTestSpec( baseTestString() + " -mask foo -B:mask,VCF3 " + validationDataLocation + "vcfexample2.vcf -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("b0fcac4af3526e3b2a37602ab4c0e6ae")); + Arrays.asList("578f9e774784c25871678e6464fd212b")); executeTest("test mask all", spec1); WalkerTestSpec spec2 = new WalkerTestSpec( baseTestString() + " -mask foo -B:mask,VCF " + validationDataLocation + "vcfMask.vcf -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("b64baabe905a5d197cc1ab594147d3d5")); + Arrays.asList("bfa86a674aefca1b13d341cb14ab3c4f")); executeTest("test mask some", spec2); WalkerTestSpec spec3 = new WalkerTestSpec( baseTestString() + " -mask foo -maskExtend 10 -B:mask,VCF " + validationDataLocation + "vcfMask.vcf -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("0eff92fe72024d535c44b98e1e9e1993")); + Arrays.asList("5939f80d14b32d88587373532d7b90e5")); executeTest("test mask extend", spec3); } @@ -50,7 +50,7 @@ public class VariantFiltrationIntegrationTest extends WalkerTest { public void testFilter1() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -filter 'DoC < 20 || FisherStrand > 20.0' -filterName foo -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("7a40795147cbfa92941489d7239aad92")); + Arrays.asList("45219dbcfb6f81bba2ea0c35f5bfd368")); executeTest("test filter #1", spec); } @@ -58,7 +58,7 @@ public class VariantFiltrationIntegrationTest extends WalkerTest { public void testFilter2() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " -filter 'AlleleBalance < 70.0 && FisherStrand == 1.4' -filterName bar -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("e9dd4991b1e325847c77d053dfe8ee54")); + Arrays.asList("c95845e817da7352b9b72bc9794f18fb")); executeTest("test filter #2", spec); } @@ -66,7 +66,7 @@ public class VariantFiltrationIntegrationTest extends WalkerTest { public void testFilterWithSeparateNames() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " --filterName ABF -filter 'AlleleBalance < 0.7' --filterName FSF -filter 'FisherStrand == 1.4' -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("9ded2cce63b8d97550079047051d80a3")); + Arrays.asList("b8cdd7f44ff1a395e0a9b06a87e1e530")); executeTest("test filter with separate names #2", spec); } @@ -74,12 +74,12 @@ public class VariantFiltrationIntegrationTest extends WalkerTest { public void testGenotypeFilters() { WalkerTestSpec spec1 = new WalkerTestSpec( baseTestString() + " -G_filter 'GQ == 0.60' -G_filterName foo -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("6696e3f65a62ce912230d47cdb0c129b")); + Arrays.asList("96b61e4543a73fe725e433f007260039")); executeTest("test genotype filter #1", spec1); WalkerTestSpec spec2 = new WalkerTestSpec( baseTestString() + " -G_filter 'AF == 0.04 && isHomVar == 1' -G_filterName foo -B:variant,VCF3 " + validationDataLocation + "vcfexample2.vcf -L 1:10,020,000-10,021,000", 1, - Arrays.asList("26e5b4ee954c9e0b5eb044afd4b88ee9")); + Arrays.asList("6c8112ab17ce39c8022c891ae73bf38e")); executeTest("test genotype filter #2", spec2); } @@ -87,7 +87,7 @@ public class VariantFiltrationIntegrationTest extends WalkerTest { public void testDeletions() { WalkerTestSpec spec = new WalkerTestSpec( baseTestString() + " --filterExpression 'QUAL < 100' --filterName foo -B:variant,VCF " + validationDataLocation + "twoDeletions.vcf", 1, - Arrays.asList("e63b58be33c9126ad6cc55489aac539b")); + Arrays.asList("569546fd798afa0e65c5b61b440d07ac")); executeTest("test deletions", spec); } } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperIntegrationTest.java index 20fa7719f..1f23d262e 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/genotyper/UnifiedGenotyperIntegrationTest.java @@ -28,7 +28,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { public void testMultiSamplePilot1() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( baseCommand + " -I " + validationDataLocation + "low_coverage_CEU.chr1.10k-11k.bam -o %s -L 1:10,022,000-10,025,000", 1, - Arrays.asList("258e1954e6ae55c89abc6a716e19cbe0")); + Arrays.asList("c97829259463d04b0159591bb6fb44af")); executeTest("test MultiSample Pilot1", spec); } @@ -54,12 +54,12 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { public void testWithAllelesPassedIn() { WalkerTest.WalkerTestSpec spec1 = new WalkerTest.WalkerTestSpec( baseCommand + " --genotyping_mode GENOTYPE_GIVEN_ALLELES -B:alleles,vcf " + validationDataLocation + "allelesForUG.vcf -I " + validationDataLocation + "pilot2_daughters.chr20.10k-11k.bam -o %s -L 20:10,000,000-10,025,000", 1, - Arrays.asList("edeb1db288a24baff59575ceedd94243")); + Arrays.asList("2b69667f4770e8c0c894066b7f27e440")); executeTest("test MultiSample Pilot2 with alleles passed in", spec1); WalkerTest.WalkerTestSpec spec2 = new WalkerTest.WalkerTestSpec( baseCommand + " --output_mode EMIT_ALL_SITES --genotyping_mode GENOTYPE_GIVEN_ALLELES -B:alleles,vcf " + validationDataLocation + "allelesForUG.vcf -I " + validationDataLocation + "pilot2_daughters.chr20.10k-11k.bam -o %s -L 20:10,000,000-10,025,000", 1, - Arrays.asList("581990130d90071b084024f4cd7caf91")); + Arrays.asList("b77fe007c2a97fcd59dfd5eef94d8b95")); executeTest("test MultiSample Pilot2 with alleles passed in and emitting all sites", spec2); } @@ -67,7 +67,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { public void testSingleSamplePilot2() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( baseCommand + " -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -o %s -L 1:10,000,000-10,100,000", 1, - Arrays.asList("d120db27d694a6da32367cc4fb5770fa")); + Arrays.asList("ee8a5e63ddd470726a749e69c0c20f60")); executeTest("test SingleSample Pilot2", spec); } @@ -77,7 +77,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { // // -------------------------------------------------------------------------------------------------------------- - private final static String COMPRESSED_OUTPUT_MD5 = "75e5c430ed39f79f24e375037a388dc4"; + private final static String COMPRESSED_OUTPUT_MD5 = "ef31654a2b85b9b2d3bba4f4a75a17b6"; @Test public void testCompressedOutput() { @@ -107,7 +107,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { // Note that we need to turn off any randomization for this to work, so no downsampling and no annotations - String md5 = "a29615dd37222a11b8dadd341b53e43c"; + String md5 = "46868a9c4134651c54535fb46b408aee"; WalkerTest.WalkerTestSpec spec1 = new WalkerTest.WalkerTestSpec( baseCommand + " -dt NONE -G none -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -o %s -L 1:10,000,000-10,075,000", 1, @@ -138,9 +138,9 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { @Test public void testCallingParameters() { HashMap e = new HashMap(); - e.put( "--min_base_quality_score 26", "93e6269e38db9bc1732555e9969e3648" ); - e.put( "--min_mapping_quality_score 26", "64be99183c100caed4aa5f8bad64c7e9" ); - e.put( "--p_nonref_model GRID_SEARCH", "0592fe33f705ad8e2f13619fcf157805" ); + e.put( "--min_base_quality_score 26", "5043c9a101e691602eb7a3f9704bdf20" ); + e.put( "--min_mapping_quality_score 26", "71a833eb8fd93ee62ae0d5a430f27940" ); + e.put( "--p_nonref_model GRID_SEARCH", "ddf443e9dcadef367476b26b4d52c134" ); for ( Map.Entry entry : e.entrySet() ) { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( @@ -153,9 +153,9 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { @Test public void testOutputParameter() { HashMap e = new HashMap(); - e.put( "-sites_only", "1483e637dc0279935a7f90d136d147bb" ); - e.put( "--output_mode EMIT_ALL_CONFIDENT_SITES", "adcd91bc7dae8020df8caf1a30060e98" ); - e.put( "--output_mode EMIT_ALL_SITES", "b708acc2fa40f336bcd2d0c70091e07e" ); + e.put( "-sites_only", "eaad6ceb71ab94290650a70bea5ab951" ); + e.put( "--output_mode EMIT_ALL_CONFIDENT_SITES", "05bf7db8a3d19ef4a3d14772c90b732f" ); + e.put( "--output_mode EMIT_ALL_SITES", "e4b86740468d7369f0156550855586c7" ); for ( Map.Entry entry : e.entrySet() ) { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( @@ -169,12 +169,12 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { public void testConfidence() { WalkerTest.WalkerTestSpec spec1 = new WalkerTest.WalkerTestSpec( baseCommand + " -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -o %s -L 1:10,000,000-10,010,000 -stand_call_conf 10 ", 1, - Arrays.asList("64be99183c100caed4aa5f8bad64c7e9")); + Arrays.asList("71a833eb8fd93ee62ae0d5a430f27940")); executeTest("test confidence 1", spec1); WalkerTest.WalkerTestSpec spec2 = new WalkerTest.WalkerTestSpec( baseCommand + " -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -o %s -L 1:10,000,000-10,010,000 -stand_emit_conf 10 ", 1, - Arrays.asList("e76ca54232d02f0d92730e1affeb804e")); + Arrays.asList("79968844dc3ddecb97748c1acf2984c7")); executeTest("test confidence 2", spec2); } @@ -186,8 +186,8 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { @Test public void testHeterozyosity() { HashMap e = new HashMap(); - e.put( 0.01, "18d37f7f107853b5e32c757b4e143205" ); - e.put( 1.0 / 1850, "2bcb90ce2f7542bf590f7612018fae8e" ); + e.put( 0.01, "4e878664f61d2d800146d3762303fde1" ); + e.put( 1.0 / 1850, "9204caec095ff5e63ca21a10b6fab453" ); for ( Map.Entry entry : e.entrySet() ) { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( @@ -211,7 +211,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { " -o %s" + " -L 1:10,000,000-10,100,000", 1, - Arrays.asList("825f05b31b5bb7e82231a15c7e4e2b0d")); + Arrays.asList("1a58ec52df545f946f80cc16c5736a91")); executeTest(String.format("test multiple technologies"), spec); } @@ -230,7 +230,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { " -L 1:10,000,000-10,100,000" + " -baq CALCULATE_AS_NECESSARY", 1, - Arrays.asList("0919ab7e513c377610e23a67d33608fa")); + Arrays.asList("62d0f6d9de344ce68ce121c13b1e78b1")); executeTest(String.format("test calling with BAQ"), spec); } @@ -244,7 +244,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { " -L 1:10,000,000-10,100,000" + " -baq OFF", 1, - Arrays.asList("825f05b31b5bb7e82231a15c7e4e2b0d")); + Arrays.asList("1a58ec52df545f946f80cc16c5736a91")); executeTest(String.format("test calling with BAQ OFF"), spec); } @@ -263,7 +263,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { " -o %s" + " -L 1:10,000,000-10,500,000", 1, - Arrays.asList("cb37348c41b8181be829912730f747e1")); + Arrays.asList("631ae1f1eb6bc4c1a4136b8495250536")); executeTest(String.format("test indel caller in SLX"), spec); } @@ -278,7 +278,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { " -minIndelCnt 1" + " -L 1:10,000,000-10,100,000", 1, - Arrays.asList("ca5b6a5fb53ae401b146cc3044f454f2")); + Arrays.asList("fd556585c79e2b892a5976668f45aa43")); executeTest(String.format("test indel caller in SLX witn low min allele count"), spec); } @@ -291,7 +291,7 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { " -o %s" + " -L 1:10,000,000-10,500,000", 1, - Arrays.asList("ca4343a4ab6d3cce94ce61d7d1910f81")); + Arrays.asList("9cd56feedd2787919e571383889fde70")); executeTest(String.format("test indel calling, multiple technologies"), spec); } @@ -301,14 +301,14 @@ public class UnifiedGenotyperIntegrationTest extends WalkerTest { WalkerTest.WalkerTestSpec spec1 = new WalkerTest.WalkerTestSpec( baseCommandIndels + " --genotyping_mode GENOTYPE_GIVEN_ALLELES -B:alleles,vcf " + validationDataLocation + "indelAllelesForUG.vcf -I " + validationDataLocation + "pilot2_daughters.chr20.10k-11k.bam -o %s -L 20:10,000,000-10,100,000", 1, - Arrays.asList("3f555b53e9dd14cf7cdf96c24e322364")); + Arrays.asList("315e1b78d7a403d7fcbcf0caa8c496b8")); executeTest("test MultiSample Pilot2 indels with alleles passed in", spec1); WalkerTest.WalkerTestSpec spec2 = new WalkerTest.WalkerTestSpec( baseCommandIndels + " --output_mode EMIT_ALL_SITES --genotyping_mode GENOTYPE_GIVEN_ALLELES -B:alleles,vcf " + validationDataLocation + "indelAllelesForUG.vcf -I " + validationDataLocation + "pilot2_daughters.chr20.10k-11k.bam -o %s -L 20:10,000,000-10,100,000", 1, - Arrays.asList("1b9764b783acf7822edc58e6822eef5b")); + Arrays.asList("cf89e0c54f14482a23c105b73a333d8a")); executeTest("test MultiSample Pilot2 indels with alleles passed in and emitting all sites", spec2); } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingIntegrationTest.java index 0ed16967a..1bf3e579f 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingIntegrationTest.java @@ -26,7 +26,7 @@ public class ReadBackedPhasingIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "phasing_test_chr20_332341_1332503.bam", "phasing_test_chr20_332341_1332503.vcf", 20000, 10, 10) + " -L chr20:332341-382503", 1, - Arrays.asList("6020a68bbec97fcd87819c10cd4e2470")); + Arrays.asList("9568ba0b6624b97ac55a59bdee2d9150")); executeTest("MAX 10 het sites [TEST ONE]; require PQ >= 10", spec); } @@ -36,7 +36,7 @@ public class ReadBackedPhasingIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "phasing_test_chr20_332341_1332503.bam", "phasing_test_chr20_332341_1332503.vcf", 20000, 10, 10) + " -L chr20:1232503-1332503", 1, - Arrays.asList("712c2145df4756c9a15758865d8007b5")); + Arrays.asList("ce65194c24fe83b0ec90faa6c8e6109a")); executeTest("MAX 10 het sites [TEST TWO]; require PQ >= 10", spec); } @@ -46,7 +46,7 @@ public class ReadBackedPhasingIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "phasing_test_chr20_332341_1332503.bam", "phasing_test_chr20_332341_1332503.vcf", 20000, 2, 30) + " -L chr20:332341-382503", 1, - Arrays.asList("297e0896e4761529d979f40f5ad694db")); + Arrays.asList("02d134fd544613b1e5dd7f7197fc3753")); executeTest("MAX 2 het sites [TEST THREE]; require PQ >= 30", spec); } @@ -56,7 +56,7 @@ public class ReadBackedPhasingIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "phasing_test_chr20_332341_1332503.bam", "phasing_test_chr20_332341_1332503.vcf", 20000, 5, 100) + " -L chr20:332341-382503", 1, - Arrays.asList("52a17f14692d726d3b726cf0ae7f2a09")); + Arrays.asList("2f7ec9904fc054c2ba1a7db05eb29334")); executeTest("MAX 5 het sites [TEST FOUR]; require PQ >= 100", spec); } @@ -66,7 +66,7 @@ public class ReadBackedPhasingIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "phasing_test_chr20_332341_1332503.bam", "phasing_test_chr20_332341_1332503.vcf", 1000, 7, 10) + " -L chr20:332341-482503", 1, - Arrays.asList("af768f7958b8f4599c2374f1cc2fc613")); + Arrays.asList("da7a31725f229d1782dd3049848730aa")); executeTest("MAX 7 het sites [TEST FIVE]; require PQ >= 10; cacheWindow = 1000", spec); } @@ -76,7 +76,7 @@ public class ReadBackedPhasingIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "phasing_test_chr20_332341_1332503.bam", "phasing_test_chr20_332341_1332503.vcf", 20000, 10, 10) + " -L chr20:652810-681757", 1, - Arrays.asList("3dd886672f59a47908b94136d0427bb0")); + Arrays.asList("e9d35cb88089fb0e8ae6678bfaeeac8c")); executeTest("MAX 10 het sites [TEST SIX]; require PQ >= 10; cacheWindow = 20000; has inconsistent sites", spec); } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantrecalibration/VariantRecalibrationWalkersIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantrecalibration/VariantRecalibrationWalkersIntegrationTest.java index 9600046da..2fec2e70f 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantrecalibration/VariantRecalibrationWalkersIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantrecalibration/VariantRecalibrationWalkersIntegrationTest.java @@ -27,7 +27,7 @@ public class VariantRecalibrationWalkersIntegrationTest extends WalkerTest { VRTest lowPass = new VRTest("phase1.projectConsensus.chr20.raw.snps.vcf", "d33212a84368e821cbedecd4f59756d6", // tranches "4652dca41222bebdf9d9fda343b2a835", // recal file - "5350b1a4c1250cf3b77ca45327c04711"); // cut VCF + "243a397a33a935fcaccd5deb6d16f0c0"); // cut VCF @DataProvider(name = "VRTest") public Object[][] createData1() { diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/CombineVariantsIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/CombineVariantsIntegrationTest.java index 600718aa0..daaab9425 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/CombineVariantsIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/CombineVariantsIntegrationTest.java @@ -71,24 +71,24 @@ public class CombineVariantsIntegrationTest extends WalkerTest { } - @Test public void test1SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "2117fff6e0d182cd20be508e9661829c", true); } - @Test public void test2SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "2cfaf7af3dd119df08b8a9c1f72e2f93", " -setKey foo", true); } - @Test public void test3SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "1474ac0fde2ce42a3c24f1c97eab333e", " -setKey null", true); } - @Test public void testOfficialCEUPilotCalls() { test1InOut("CEU.trio.2010_03.genotypes.vcf.gz", "7fc66df048a0ab08cf507906e1d4a308", false); } // official project VCF files in tabix format + @Test public void test1SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "c608b9fc1e36dba6cebb4f259883f9f0", true); } + @Test public void test2SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "20caad94411d6ab48153b214de916df8", " -setKey foo", true); } + @Test public void test3SNP() { test1InOut("pilot2.snps.vcf4.genotypes.vcf", "004f3065cb1bc2ce2f9afd695caf0b48", " -setKey null", true); } + @Test public void testOfficialCEUPilotCalls() { test1InOut("CEU.trio.2010_03.genotypes.vcf.gz", "c9c901ff9ef2a982624b203a8086dff0", false); } // official project VCF files in tabix format - @Test public void test1Indel1() { test1InOut("CEU.dindel.vcf4.trio.2010_06.indel.genotypes.vcf", "ec9715f53dbf4531570557c212822f12", false); } - @Test public void test1Indel2() { test1InOut("CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "f1072be5f5c6ee810276d9ca6537224d", false); } + @Test public void test1Indel1() { test1InOut("CEU.dindel.vcf4.trio.2010_06.indel.genotypes.vcf", "7593be578d4274d672fc22fced38012b", false); } + @Test public void test1Indel2() { test1InOut("CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "1cd467863c4e948fadd970681552d57e", false); } - @Test public void combineTrioCalls() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "YRI.trio.2010_03.genotypes.vcf.gz", "", "b77a1eec725201d9d8e74ee0c45638d3", false); } // official project VCF files in tabix format - @Test public void combineTrioCallsMin() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "YRI.trio.2010_03.genotypes.vcf.gz", " -minimalVCF", "802977fdfd2f4905b501bb06800f60af", false); } // official project VCF files in tabix format - @Test public void combine2Indels() { combine2("CEU.dindel.vcf4.trio.2010_06.indel.genotypes.vcf", "CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "", "a67157287dd2b24b5cdf7ebf8fcbbe9a", false); } + @Test public void combineTrioCalls() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "YRI.trio.2010_03.genotypes.vcf.gz", "", "1d5a021387a8a86554db45a29f66140f", false); } // official project VCF files in tabix format + @Test public void combineTrioCallsMin() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "YRI.trio.2010_03.genotypes.vcf.gz", " -minimalVCF", "20163d60f18a46496f6da744ab5cc0f9", false); } // official project VCF files in tabix format + @Test public void combine2Indels() { combine2("CEU.dindel.vcf4.trio.2010_06.indel.genotypes.vcf", "CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "", "5b82f37df1f5ba40f0474d71c94142ec", false); } - @Test public void combineSNPsAndIndels() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "", "e1f4718a179f1196538a33863da04f53", false); } + @Test public void combineSNPsAndIndels() { combine2("CEU.trio.2010_03.genotypes.vcf.gz", "CEU.dindel.vcf4.low_coverage.2010_06.indel.genotypes.vcf", "", "c58dca482bf97069eac6d9f1a07a2cba", false); } - @Test public void uniqueSNPs() { combine2("pilot2.snps.vcf4.genotypes.vcf", "yri.trio.gatk_glftrio.intersection.annotated.filtered.chr1.vcf", "", "b3783384b7c8e877b971033e90beba48", true); } + @Test public void uniqueSNPs() { combine2("pilot2.snps.vcf4.genotypes.vcf", "yri.trio.gatk_glftrio.intersection.annotated.filtered.chr1.vcf", "", "89f55abea8f59e39d1effb908440548c", true); } - @Test public void omniHM3Union() { combineSites(" -filteredRecordsMergeType KEEP_IF_ANY_UNFILTERED", "902e541c87caa72134db6293fc46f0ad"); } - @Test public void omniHM3Intersect() { combineSites(" -filteredRecordsMergeType KEEP_IF_ALL_UNFILTERED", "f339ad4bb5863b58b9c919ce7d040bb9"); } + @Test public void omniHM3Union() { combineSites(" -filteredRecordsMergeType KEEP_IF_ANY_UNFILTERED", "4836086891f6cbdd40eebef3076d215a"); } + @Test public void omniHM3Intersect() { combineSites(" -filteredRecordsMergeType KEEP_IF_ALL_UNFILTERED", "6a34b5d743efda8b2f3b639f3a2f5de8"); } @Test public void threeWayWithRefs() { WalkerTestSpec spec = new WalkerTestSpec( @@ -101,7 +101,7 @@ public class CombineVariantsIntegrationTest extends WalkerTest { " -priority NA19240_BGI,NA19240_ILLUMINA,NA19240_WUGSC,denovoInfo" + " -genotypeMergeOptions UNIQUIFY -L 1"), 1, - Arrays.asList("a07995587b855f3214fb71940bf23c0f")); + Arrays.asList("8b78339ccf7a5a5a837f79e88a3a38e5")); executeTest("threeWayWithRefs", spec); } @@ -120,7 +120,7 @@ public class CombineVariantsIntegrationTest extends WalkerTest { } // @Test public void complexTestFull() { combineComplexSites("", "64b991fd3850f83614518f7d71f0532f"); } - @Test public void complexTestMinimal() { combineComplexSites(" -minimalVCF", "0db9ef50fe54b60426474273d7c7fa99"); } - @Test public void complexTestSitesOnly() { combineComplexSites(" -sites_only", "d20acb3d53ba0a02ce92d540ebeda2a9"); } - @Test public void complexTestSitesOnlyMinimal() { combineComplexSites(" -sites_only -minimalVCF", "8d1b3d120515f8b56b5a0d10bc5da713"); } + @Test public void complexTestMinimal() { combineComplexSites(" -minimalVCF", "df96cb3beb2dbb5e02f80abec7d3571e"); } + @Test public void complexTestSitesOnly() { combineComplexSites(" -sites_only", "f72a178137e25dbe0b931934cdc0079d"); } + @Test public void complexTestSitesOnlyMinimal() { combineComplexSites(" -sites_only -minimalVCF", "f704caeaaaed6711943014b847fe381a"); } } \ No newline at end of file diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/LiftoverVariantsIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/LiftoverVariantsIntegrationTest.java index d32ab6282..82c894c6f 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/LiftoverVariantsIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/LiftoverVariantsIntegrationTest.java @@ -40,7 +40,7 @@ public class LiftoverVariantsIntegrationTest extends WalkerTest { WalkerTestSpec spec = new WalkerTestSpec( "-T LiftoverVariants -o %s -R " + b36KGReference + " -B:variant,vcf3 " + validationDataLocation + "yri.trio.gatk_glftrio.intersection.annotated.filtered.chr1.500.noheader.vcf -chain " + validationDataLocation + "b36ToHg19.broad.over.chain -dict /seq/references/Homo_sapiens_assembly19/v0/Homo_sapiens_assembly19.dict", 1, - Arrays.asList("37e23efd7d6471fc0f807b31ccafe0eb")); + Arrays.asList("70aeaca5b74cc7ba8e2da7b71ff0fbfd")); executeTest("test b36 to hg19", spec); } @@ -49,7 +49,7 @@ public class LiftoverVariantsIntegrationTest extends WalkerTest { WalkerTestSpec spec = new WalkerTestSpec( "-T LiftoverVariants -o %s -R " + b36KGReference + " -B:variant,vcf3 " + validationDataLocation + "yri.trio.gatk_glftrio.intersection.annotated.filtered.chr1.500.noheader.unsortedSamples.vcf -chain " + validationDataLocation + "b36ToHg19.broad.over.chain -dict /seq/references/Homo_sapiens_assembly19/v0/Homo_sapiens_assembly19.dict", 1, - Arrays.asList("b6ef4a2f026fd3843aeb9ed764a66921")); + Arrays.asList("3fd7ec2dc4064ef410786276b0dc9d08")); executeTest("test b36 to hg19, unsorted samples", spec); } @@ -58,7 +58,7 @@ public class LiftoverVariantsIntegrationTest extends WalkerTest { WalkerTestSpec spec = new WalkerTestSpec( "-T LiftoverVariants -o %s -R " + hg18Reference + " -B:variant,vcf " + validationDataLocation + "liftover_test.vcf -chain " + validationDataLocation + "hg18ToHg19.broad.over.chain -dict /seq/references/Homo_sapiens_assembly19/v0/Homo_sapiens_assembly19.dict", 1, - Arrays.asList("3275373b3c44ad14a270b50664b3f8a3")); + Arrays.asList("ab2c6254225d7e2ecf52eee604d5673b")); executeTest("test hg18 to hg19, unsorted", spec); } } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/SelectVariantsIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/SelectVariantsIntegrationTest.java index e18287a21..b5f41542e 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/SelectVariantsIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/SelectVariantsIntegrationTest.java @@ -18,7 +18,7 @@ public class SelectVariantsIntegrationTest extends WalkerTest { WalkerTestSpec spec = new WalkerTestSpec( baseTestString(" -sn A -se '[CDH]' -sf " + samplesFile + " -env -ef -select 'DP < 250' -B:variant,VCF3 " + testfile + " -NO_HEADER"), 1, - Arrays.asList("1b9d551298dc048c7d36b60440ff4d50") + Arrays.asList("d18516c1963802e92cb9e425c0b75fd6") ); executeTest("testComplexSelection--" + testfile, spec); @@ -31,7 +31,7 @@ public class SelectVariantsIntegrationTest extends WalkerTest { WalkerTestSpec spec = new WalkerTestSpec( baseTestString(" -sn A -sn B -sn C -B:variant,VCF3 " + testfile + " -NO_HEADER"), 1, - Arrays.asList("5ba7536a0819421b330350a160e4261a") + Arrays.asList("b74038779fe6485dbb8734ae48178356") ); executeTest("testRepeatedLineSelection--" + testfile, spec); @@ -44,7 +44,7 @@ public class SelectVariantsIntegrationTest extends WalkerTest { WalkerTestSpec spec = new WalkerTestSpec( "-T SelectVariants -R " + hg19Reference + " -sn NA12878 -disc myvar -L 20:1012700-1020000 -B:variant,VCF " + b37hapmapGenotypes + " -B:myvar,VCF " + testFile + " -o %s -NO_HEADER", 1, - Arrays.asList("97621ae8f29955eedfc4e0be3515fcb9") + Arrays.asList("78e6842325f1f1bc9ab30d5e7737ee6e") ); executeTest("testDiscordance--" + testFile, spec); @@ -57,7 +57,7 @@ public class SelectVariantsIntegrationTest extends WalkerTest { WalkerTestSpec spec = new WalkerTestSpec( "-T SelectVariants -R " + hg19Reference + " -sn NA12878 -conc hapmap -L 20:1012700-1020000 -B:hapmap,VCF " + b37hapmapGenotypes + " -B:variant,VCF " + testFile + " -o %s -NO_HEADER", 1, - Arrays.asList("a0ae016fdffcbe7bfb99fd3dbc311407") + Arrays.asList("d2ba3ea30a810f6f0fbfb1b643292b6a") ); executeTest("testConcordance--" + testFile, spec); diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VCFStreamingIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VCFStreamingIntegrationTest.java index cf0673ee6..d7efe4212 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VCFStreamingIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VCFStreamingIntegrationTest.java @@ -60,7 +60,7 @@ public class VCFStreamingIntegrationTest extends WalkerTest { " --NO_HEADER" + " -o %s", 1, - Arrays.asList("debbbf3e661b6857cc8d99ff7635bb1d") + Arrays.asList("658f580f7a294fd334bd897102616fed") ); executeTest("testSimpleVCFStreaming", spec); diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCFIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCFIntegrationTest.java index 64d0db14b..8421076c9 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCFIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCFIntegrationTest.java @@ -20,7 +20,7 @@ public class VariantsToVCFIntegrationTest extends WalkerTest { @Test public void testVariantsToVCFUsingGeliInput() { List md5 = new ArrayList(); - md5.add("bd15d98adc76b5798e3bbeff3f936feb"); + md5.add("815b82fff92aab41c209eedce2d7e7d9"); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-R " + b36KGReference + @@ -38,7 +38,7 @@ public class VariantsToVCFIntegrationTest extends WalkerTest { @Test public void testGenotypesToVCFUsingGeliInput() { List md5 = new ArrayList(); - md5.add("acd15d3f85bff5b545bc353e0e23cc6e"); + md5.add("22336ee9c12aa222ce29c3c5babca7d0"); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-R " + b36KGReference + @@ -56,7 +56,7 @@ public class VariantsToVCFIntegrationTest extends WalkerTest { @Test public void testGenotypesToVCFUsingHapMapInput() { List md5 = new ArrayList(); - md5.add("6f34528569f8cf5941cb365fa77288c1"); + md5.add("9bedaa7670b86a07be5191898c3727cf"); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-R " + b36KGReference + @@ -73,7 +73,7 @@ public class VariantsToVCFIntegrationTest extends WalkerTest { @Test public void testGenotypesToVCFUsingVCFInput() { List md5 = new ArrayList(); - md5.add("d8316fc1b9d8e954a58940354119a32e"); + md5.add("cc215edec9ca28e5c79ab1b67506f9f7"); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-R " + b36KGReference + diff --git a/public/java/test/org/broadinstitute/sting/utils/variantcontext/VariantContextIntegrationTest.java b/public/java/test/org/broadinstitute/sting/utils/variantcontext/VariantContextIntegrationTest.java index 5d42f8d0c..a344817a0 100755 --- a/public/java/test/org/broadinstitute/sting/utils/variantcontext/VariantContextIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/utils/variantcontext/VariantContextIntegrationTest.java @@ -49,7 +49,7 @@ public class VariantContextIntegrationTest extends WalkerTest { WalkerTestSpec spec = new WalkerTestSpec( cmdRoot + " -NO_HEADER -B:vcf,VCF3 " + validationDataLocation + "yri.trio.gatk_glftrio.intersection.annotated.filtered.chr1.500.vcf -L 1:1-1000000 -o %s --outputVCF %s", 2, // just one output file - Arrays.asList("e3c35d0c4b5d4935c84a270f9df0951f", "e6673737acbb6bfabfcd92c4b2268241")); + Arrays.asList("e3c35d0c4b5d4935c84a270f9df0951f", "ff91731213fd0bbdc200ab6fd1c93e63")); executeTest("testToVCF", spec); } From ccedd6ff4c942c20c1a57f6a6bf65c5cb63b6e16 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Tue, 12 Jul 2011 15:20:28 -0400 Subject: [PATCH 17/83] Difference is now the general form -- used to be SummarizedDifference. The old Difference class is now a subclass of Difference that includes pointers to specific the master and test DiffElements. Added a size() function that calculates the number of elements tree from a DiffElement. --- .../gatk/walkers/diffengine/DiffElement.java | 4 + .../gatk/walkers/diffengine/DiffEngine.java | 142 +++++------------- .../gatk/walkers/diffengine/DiffNode.java | 7 + .../walkers/diffengine/DiffObjectsWalker.java | 7 +- .../gatk/walkers/diffengine/DiffValue.java | 1 + .../gatk/walkers/diffengine/Difference.java | 83 +++++++--- .../diffengine/SpecificDifference.java | 59 ++++++++ .../diffengine/DiffEngineUnitTest.java | 6 +- .../diffengine/DifferenceUnitTest.java | 2 +- 9 files changed, 176 insertions(+), 135 deletions(-) create mode 100644 public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/SpecificDifference.java diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffElement.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffElement.java index eff24bb88..4c3f7bd95 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffElement.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffElement.java @@ -115,4 +115,8 @@ public class DiffElement { else throw new ReviewedStingException("Illegal request conversion of a DiffValue into a DiffNode: " + this); } + + public int size() { + return 1 + getValue().size(); + } } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java index 54a7a464d..6d85df71d 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java @@ -24,11 +24,9 @@ package org.broadinstitute.sting.gatk.walkers.diffengine; -import com.google.java.contract.Requires; import org.apache.log4j.Logger; import org.broadinstitute.sting.gatk.report.GATKReport; import org.broadinstitute.sting.gatk.report.GATKReportTable; -import org.broadinstitute.sting.gatk.walkers.varianteval.stratifications.VariantStratifier; import org.broadinstitute.sting.utils.Utils; import org.broadinstitute.sting.utils.classloader.PluginManager; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; @@ -60,7 +58,7 @@ public class DiffEngine { // // -------------------------------------------------------------------------------- - public List diff(DiffElement master, DiffElement test) { + public List diff(DiffElement master, DiffElement test) { DiffValue masterValue = master.getValue(); DiffValue testValue = test.getValue(); @@ -70,14 +68,14 @@ public class DiffEngine { return diff(masterValue, testValue); } else { // structural difference in types. one is node, other is leaf - return Arrays.asList(new Difference(master, test)); + return Arrays.asList(new SpecificDifference(master, test)); } } - public List diff(DiffNode master, DiffNode test) { + public List diff(DiffNode master, DiffNode test) { Set allNames = new HashSet(master.getElementNames()); allNames.addAll(test.getElementNames()); - List diffs = new ArrayList(); + List diffs = new ArrayList(); for ( String name : allNames ) { DiffElement masterElt = master.getElement(name); @@ -86,7 +84,7 @@ public class DiffEngine { throw new ReviewedStingException("BUG: unexceptedly got two null elements for field: " + name); } else if ( masterElt == null || testElt == null ) { // if either is null, we are missing a value // todo -- should one of these be a special MISSING item? - diffs.add(new Difference(masterElt, testElt)); + diffs.add(new SpecificDifference(masterElt, testElt)); } else { diffs.addAll(diff(masterElt, testElt)); } @@ -95,11 +93,11 @@ public class DiffEngine { return diffs; } - public List diff(DiffValue master, DiffValue test) { + public List diff(DiffValue master, DiffValue test) { if ( master.getValue().equals(test.getValue()) ) { return Collections.emptyList(); } else { - return Arrays.asList(new Difference(master.getBinding(), test.getBinding())); + return Arrays.asList(new SpecificDifference(master.getBinding(), test.getBinding())); } } @@ -147,64 +145,68 @@ public class DiffEngine { * @param params determines how we display the items * @param diffs */ - public void reportSummarizedDifferences(List diffs, SummaryReportParams params ) { + public void reportSummarizedDifferences(List diffs, SummaryReportParams params ) { printSummaryReport(summarizeDifferences(diffs), params ); } - public List summarizeDifferences(List diffs) { - List diffPaths = new ArrayList(diffs.size()); - - for ( Difference diff1 : diffs ) { - diffPaths.add(diffNameToPath(diff1.getFullyQualifiedName())); - } - - return summarizedDifferencesOfPaths(diffPaths); + public List summarizeDifferences(List diffs) { + return summarizedDifferencesOfPaths(diffs); } final protected static String[] diffNameToPath(String diffName) { return diffName.split("\\."); } - protected List summarizedDifferencesOfPaths(List diffPaths) { - Map summaries = new HashMap(); + protected List summarizedDifferencesOfPathsFromString(List singletonDiffs) { + List diffs = new ArrayList(); + + for ( String diff : singletonDiffs ) { + diffs.add(new Difference(diff)); + } + + return summarizedDifferencesOfPaths(diffs); + } + + protected List summarizedDifferencesOfPaths(List singletonDiffs) { + Map summaries = new HashMap(); // create the initial set of differences - for ( int i = 0; i < diffPaths.size(); i++ ) { + for ( int i = 0; i < singletonDiffs.size(); i++ ) { for ( int j = 0; j <= i; j++ ) { - String[] diffPath1 = diffPaths.get(i); - String[] diffPath2 = diffPaths.get(j); - if ( diffPath1.length == diffPath2.length ) { - int lcp = longestCommonPostfix(diffPath1, diffPath2); - String path = lcp > 0 ? summarizedPath(diffPath2, lcp) : Utils.join(".", diffPath2); + Difference diffPath1 = singletonDiffs.get(i); + Difference diffPath2 = singletonDiffs.get(j); + if ( diffPath1.length() == diffPath2.length() ) { + int lcp = longestCommonPostfix(diffPath1.getParts(), diffPath2.getParts()); + String path = lcp > 0 ? summarizedPath(diffPath2.getParts(), lcp) : diffPath2.getPath(); addSummary(summaries, path, true); } } } // count differences - for ( String[] diffPath : diffPaths ) { - for ( SummarizedDifference sumDiff : summaries.values() ) { - if ( sumDiff.matches(diffPath) ) + for ( Difference diffPath : singletonDiffs ) { + for ( Difference sumDiff : summaries.values() ) { + if ( sumDiff.matches(diffPath.getParts()) ) addSummary(summaries, sumDiff.getPath(), false); } } - List sortedSummaries = new ArrayList(summaries.values()); + List sortedSummaries = new ArrayList(summaries.values()); Collections.sort(sortedSummaries); return sortedSummaries; } - private static void addSummary(Map summaries, String path, boolean onlyCatalog) { + private static void addSummary(Map summaries, String path, boolean onlyCatalog) { if ( summaries.containsKey(path) ) { if ( ! onlyCatalog ) summaries.get(path).incCount(); } else { - SummarizedDifference sumDiff = new SummarizedDifference(path); + Difference sumDiff = new Difference(path); summaries.put(sumDiff.getPath(), sumDiff); } } - protected void printSummaryReport(List sortedSummaries, SummaryReportParams params ) { + protected void printSummaryReport(List sortedSummaries, SummaryReportParams params ) { GATKReport report = new GATKReport(); final String tableName = "diffences"; report.addTable(tableName, "Summarized differences between the master and test files.\nSee http://www.broadinstitute.org/gsa/wiki/index.php/DiffObjectsWalker_and_SummarizedDifferences for more information"); @@ -213,7 +215,7 @@ public class DiffEngine { table.addColumn("NumberOfOccurrences", 0); int count = 0, count1 = 0; - for ( SummarizedDifference diff : sortedSummaries ) { + for ( Difference diff : sortedSummaries ) { if ( diff.getCount() < params.minSumDiffToShow ) // in order, so break as soon as the count is too low break; @@ -261,76 +263,6 @@ public class DiffEngine { return Utils.join(".", parts); } - /** - * TODO -- all of the algorithms above should use SummarizedDifference instead - * TODO -- of some SummarizedDifferences and some low-level String[] - */ - public static class SummarizedDifference implements Comparable { - final String path; // X.Y.Z - final String[] parts; - int count = 0; - - public SummarizedDifference(String path) { - this.path = path; - this.parts = diffNameToPath(path); - } - - public void incCount() { count++; } - - public int getCount() { - return count; - } - - /** - * The fully qualified path object A.B.C etc - * @return - */ - public String getPath() { - return path; - } - - /** - * @return the length of the parts of this summary - */ - public int length() { - return this.parts.length; - } - - /** - * Returns true if the string parts matches this summary. Matches are - * must be equal() everywhere where this summary isn't *. - * @param otherParts - * @return - */ - public boolean matches(String[] otherParts) { - if ( otherParts.length != length() ) - return false; - - // TODO optimization: can start at right most non-star element - for ( int i = 0; i < length(); i++ ) { - String part = parts[i]; - if ( ! part.equals("*") && ! part.equals(otherParts[i]) ) - return false; - } - - return true; - } - - @Override - public String toString() { - return String.format("%s:%d", getPath(), getCount()); - } - - @Override - public int compareTo(SummarizedDifference other) { - // sort first highest to lowest count, then by lowest to highest path - int countCmp = Integer.valueOf(count).compareTo(other.count); - return countCmp != 0 ? -1 * countCmp : path.compareTo(other.path); - } - - - } - // -------------------------------------------------------------------------------- // // plugin manager @@ -404,7 +336,7 @@ public class DiffEngine { if ( diffEngine.canRead(masterFile) && diffEngine.canRead(testFile) ) { DiffElement master = diffEngine.createDiffableFromFile(masterFile); DiffElement test = diffEngine.createDiffableFromFile(testFile); - List diffs = diffEngine.diff(master, test); + List diffs = diffEngine.diff(master, test); diffEngine.reportSummarizedDifferences(diffs, params); return true; } else { diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java index 3e1be8609..2f48de2d3 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffNode.java @@ -153,6 +153,13 @@ public class DiffNode extends DiffValue { add(new DiffElement(name, this.getBinding(), new DiffValue(value))); } + public int size() { + int count = 0; + for ( DiffElement value : getElements() ) + count += value.size(); + return count; + } + // --------------------------------------------------------------------------- // // toString diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java index fe411b195..ecb836af9 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffObjectsWalker.java @@ -24,7 +24,6 @@ package org.broadinstitute.sting.gatk.walkers.diffengine; -import org.apache.xmlbeans.impl.tool.Diff; import org.broadinstitute.sting.commandline.Argument; import org.broadinstitute.sting.commandline.Output; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; @@ -95,18 +94,20 @@ public class DiffObjectsWalker extends RodWalker { public void onTraversalDone(Integer sum) { out.printf("Reading master file %s%n", masterFile); DiffElement master = diffEngine.createDiffableFromFile(masterFile, MAX_OBJECTS_TO_READ); + out.printf(" Read %d objects%n", master.size()); out.printf("Reading test file %s%n", testFile); DiffElement test = diffEngine.createDiffableFromFile(testFile, MAX_OBJECTS_TO_READ); + out.printf(" Read %d objects%n", test.size()); // out.printf("Master diff objects%n"); // out.println(master.toString()); // out.printf("Test diff objects%n"); // out.println(test.toString()); - List diffs = diffEngine.diff(master, test); + List diffs = diffEngine.diff(master, test); if ( showItemizedDifferences ) { out.printf("Itemized results%n"); - for ( Difference diff : diffs ) + for ( SpecificDifference diff : diffs ) out.printf("DIFF: %s%n", diff.toString()); } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffValue.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffValue.java index 7245e9e8d..3750496a1 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffValue.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffValue.java @@ -87,4 +87,5 @@ public class DiffValue { public boolean isAtomic() { return true; } public boolean isCompound() { return ! isAtomic(); } + public int size() { return 1; } } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/Difference.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/Difference.java index 6627a4cc5..efc6ef160 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/Difference.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/Difference.java @@ -24,35 +24,72 @@ package org.broadinstitute.sting.gatk.walkers.diffengine; -/** - * Created by IntelliJ IDEA. - * User: depristo - * Date: 7/4/11 - * Time: 12:53 PM - * - * Represents a specific difference between two specific DiffElements - */ -public class Difference { - DiffElement master, test; +public class Difference implements Comparable { + final String path; // X.Y.Z + final String[] parts; + int count = 0; - public Difference(DiffElement master, DiffElement test) { - if ( master == null && test == null ) throw new IllegalArgumentException("Master and test both cannot be null"); - this.master = master; - this.test = test; + public Difference(String path) { + this.path = path; + this.parts = DiffEngine.diffNameToPath(path); } + public String[] getParts() { + return parts; + } + + public void incCount() { count++; } + + public int getCount() { + return count; + } + + /** + * The fully qualified path object A.B.C etc + * @return + */ + public String getPath() { + return path; + } + + /** + * @return the length of the parts of this summary + */ + public int length() { + return this.parts.length; + } + + /** + * Returns true if the string parts matches this summary. Matches are + * must be equal() everywhere where this summary isn't *. + * @param otherParts + * @return + */ + public boolean matches(String[] otherParts) { + if ( otherParts.length != length() ) + return false; + + // TODO optimization: can start at right most non-star element + for ( int i = 0; i < length(); i++ ) { + String part = parts[i]; + if ( ! part.equals("*") && ! part.equals(otherParts[i]) ) + return false; + } + + return true; + } + + @Override public String toString() { - return String.format("%s:%s!=%s", - getFullyQualifiedName(), - getOneLineString(master), - getOneLineString(test)); + return String.format("%s:%d", getPath(), getCount()); } - public String getFullyQualifiedName() { - return (master == null ? test : master).fullyQualifiedName(); + @Override + public int compareTo(Difference other) { + // sort first highest to lowest count, then by lowest to highest path + int countCmp = Integer.valueOf(count).compareTo(other.count); + return countCmp != 0 ? -1 * countCmp : path.compareTo(other.path); } - private static String getOneLineString(DiffElement elt) { - return elt == null ? "MISSING" : elt.getValue().toOneLineString(); - } + } diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/SpecificDifference.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/SpecificDifference.java new file mode 100644 index 000000000..2fe9b47f8 --- /dev/null +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/SpecificDifference.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, 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.sting.gatk.walkers.diffengine; + +/** + * Created by IntelliJ IDEA. + * User: depristo + * Date: 7/4/11 + * Time: 12:53 PM + * + * Represents a specific difference between two specific DiffElements + */ +public class SpecificDifference extends Difference { + DiffElement master, test; + + public SpecificDifference(DiffElement master, DiffElement test) { + super(createName(master, test)); + if ( master == null && test == null ) throw new IllegalArgumentException("Master and test both cannot be null"); + this.master = master; + this.test = test; + } + + public String toString() { + return String.format("%s:%s!=%s", + getPath(), + getOneLineString(master), + getOneLineString(test)); + } + + private static String createName(DiffElement master, DiffElement test) { + return (master == null ? test : master).fullyQualifiedName(); + } + + private static String getOneLineString(DiffElement elt) { + return elt == null ? "MISSING" : elt.getValue().toOneLineString(); + } +} diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngineUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngineUnitTest.java index cd6c3598a..96dfec6e8 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngineUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngineUnitTest.java @@ -99,7 +99,7 @@ public class DiffEngineUnitTest extends BaseTest { logger.warn("Test tree1: " + test.tree1.toOneLineString()); logger.warn("Test tree2: " + test.tree2.toOneLineString()); - List diffs = engine.diff(test.tree1, test.tree2); + List diffs = engine.diff(test.tree1, test.tree2); logger.warn("Test expected diff : " + test.differences); logger.warn("Observed diffs : " + diffs); } @@ -185,12 +185,12 @@ public class DiffEngineUnitTest extends BaseTest { List diffPaths = new ArrayList(diffs.size()); for ( String diff : diffs ) { diffPaths.add(DiffEngine.diffNameToPath(diff)); } - List sumDiffs = engine.summarizedDifferencesOfPaths(diffPaths); + List sumDiffs = engine.summarizedDifferencesOfPathsFromString(diffs); Assert.assertEquals(sumDiffs.size(), expecteds.size(), "Unexpected number of summarized differences: " + sumDiffs); for ( int i = 0; i < sumDiffs.size(); i++ ) { - DiffEngine.SummarizedDifference sumDiff = sumDiffs.get(i); + Difference sumDiff = sumDiffs.get(i); String expected = expecteds.get(i); String[] pathCount = expected.split(":"); String path = pathCount[0]; diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DifferenceUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DifferenceUnitTest.java index da272ec30..64579a01b 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DifferenceUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DifferenceUnitTest.java @@ -87,7 +87,7 @@ public class DifferenceUnitTest extends BaseTest { logger.warn("Test tree1: " + (test.tree1 == null ? "null" : test.tree1.toOneLineString())); logger.warn("Test tree2: " + (test.tree2 == null ? "null" : test.tree2.toOneLineString())); logger.warn("Test expected diff : " + test.difference); - Difference diff = new Difference(test.tree1, test.tree2); + SpecificDifference diff = new SpecificDifference(test.tree1, test.tree2); logger.warn("Observed diffs : " + diff); Assert.assertEquals(diff.toString(), test.difference, "Observed diff string " + diff + " not equal to expected difference string " + test.difference ); From 5077c94d85929bad35fcc00bbeab0b8036aabe4a Mon Sep 17 00:00:00 2001 From: Ryan Poplin Date: Tue, 12 Jul 2011 15:39:07 -0400 Subject: [PATCH 19/83] Adding MappingQualityUnavailableReadFilter to the SNP and indel CountCovariates --- .../recalibration/CountCovariatesWalker.java | 3 +- .../RecalibrationWalkersIntegrationTest.java | 91 +++---------------- 2 files changed, 15 insertions(+), 79 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/CountCovariatesWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/CountCovariatesWalker.java index 6673bec92..c21f548b3 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/CountCovariatesWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/CountCovariatesWalker.java @@ -27,6 +27,7 @@ package org.broadinstitute.sting.gatk.walkers.recalibration; import org.broad.tribble.bed.BEDCodec; import org.broad.tribble.dbsnp.DbSNPCodec; +import org.broadinstitute.sting.gatk.filters.MappingQualityUnavailableReadFilter; import org.broadinstitute.sting.utils.codecs.vcf.VCF3Codec; import org.broadinstitute.sting.utils.codecs.vcf.VCFCodec; import org.broadinstitute.sting.commandline.Gather; @@ -75,7 +76,7 @@ import java.util.Map; @BAQMode(ApplicationTime = BAQ.ApplicationTime.FORBIDDEN) @By( DataSource.READS ) // Only look at covered loci, not every loci of the reference file -@ReadFilters( {MappingQualityZeroReadFilter.class} ) // Filter out all reads with zero mapping quality +@ReadFilters( {MappingQualityZeroReadFilter.class, MappingQualityUnavailableReadFilter.class} ) // Filter out all reads with zero or unavailable mapping quality @Requires( {DataSource.READS, DataSource.REFERENCE, DataSource.REFERENCE_BASES} ) // This walker requires both -I input.bam and -R reference.fasta @PartitionBy(PartitionType.LOCUS) public class CountCovariatesWalker extends LocusWalker implements TreeReducible { diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/recalibration/RecalibrationWalkersIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/recalibration/RecalibrationWalkersIntegrationTest.java index b0f76229b..129161da3 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/recalibration/RecalibrationWalkersIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/recalibration/RecalibrationWalkersIntegrationTest.java @@ -19,9 +19,9 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { public void testCountCovariates1() { HashMap e = new HashMap(); e.put( validationDataLocation + "NA12892.SLX.SRP000031.2009_06.selected.bam", "7b5832d4b2a23b8ef2bb639eb59bfa88" ); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SOLID.bam", "f4f8a49bb5764d2a8f61e055f64dcce4"); + e.put( validationDataLocation + "NA19240.chr1.BFAST.SOLID.bam", "9c006f8e9fb5752b1c139f5a8cc7ea88"); e.put( validationDataLocation + "NA12873.454.SRP000031.2009_06.chr1.10_20mb.bam", "e6f7b4ab9aa291022e0ba8b7dbe4c77e" ); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.bam", "570506533f079d738d70934dfe1c02cd" ); + e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.bam", "e6b98af01c5a08e4954b79ec42db6fc3" ); for ( String parallelism : Arrays.asList("", " -nt 4")) { for ( Map.Entry entry : e.entrySet() ) { @@ -53,9 +53,9 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { public void testTableRecalibrator1() { HashMap e = new HashMap(); e.put( validationDataLocation + "NA12892.SLX.SRP000031.2009_06.selected.bam", "0278cce4cfdab869dc0c11d6852a984b" ); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SOLID.bam", "344d4252143df8c2cce6b568747553a5"); + e.put( validationDataLocation + "NA19240.chr1.BFAST.SOLID.bam", "6797d7ffa4ef6c48413719ba32696ccf"); e.put( validationDataLocation + "NA12873.454.SRP000031.2009_06.chr1.10_20mb.bam", "2bb3374dde131791d7638031ae3b3e10" ); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.bam", "064c4a7bdd23974c3a9c5f924540df76" ); + e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.bam", "1f9d8944b73169b367cb83b0d22e5432" ); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -107,7 +107,7 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { @Test public void testTableRecalibratorMaxQ70() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SOLID.bam", "344d4252143df8c2cce6b568747553a5" ); + e.put( validationDataLocation + "NA12892.SLX.SRP000031.2009_06.selected.bam", "0278cce4cfdab869dc0c11d6852a984b" ); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -133,12 +133,10 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { } } - - @Test public void testCountCovariatesSolidIndelsRemoveRefBias() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA19240.chr1.BFAST.SOLID.bam", "0a6cdb9611e5880ea6611205080aa267" ); + e.put( validationDataLocation + "NA19240.chr1.BFAST.SOLID.bam", "c9ea5f995e1e2b7a5688533e678dcedc" ); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -164,7 +162,7 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { @Test public void testTableRecalibratorSolidIndelsRemoveRefBias() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA19240.chr1.BFAST.SOLID.bam", "9bc7e1ad223ba759fe5e8ddb4c07369c" ); + e.put( validationDataLocation + "NA19240.chr1.BFAST.SOLID.bam", "993fae4270e7e1e15986f270acf247af" ); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -189,13 +187,10 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { } } - - - @Test public void testCountCovariatesVCF() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SOLID.bam", "3700eaf567e4937f442fc777a226d6ad"); + e.put( validationDataLocation + "NA12892.SLX.SRP000031.2009_06.selected.bam", "170f0c3cc4b8d72c539136effeec9a16"); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -219,7 +214,7 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { @Test public void testCountCovariatesBED() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SOLID.bam", "6803891a3398821fc8a37e19ea8e5a00"); + e.put( validationDataLocation + "NA12892.SLX.SRP000031.2009_06.selected.bam", "b460478d9683e827784e42bc352db8bb"); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -243,7 +238,7 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { @Test public void testCountCovariatesVCFPlusDBsnp() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SOLID.bam", "f224c42fbc4026db973ccc91265ab5c7"); + e.put( validationDataLocation + "NA12892.SLX.SRP000031.2009_06.selected.bam", "a3d892bd60d8f679affda3c1e3af96c1"); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -268,69 +263,10 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { } } - @Test - public void testCountCovariatesNoReadGroups() { - HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12762.SOLID.SRP000031.2009_07.chr1.10_20mb.bam", "c024e03f019aeceaf364fa58c8295ad8" ); - - for ( Map.Entry entry : e.entrySet() ) { - String bam = entry.getKey(); - String md5 = entry.getValue(); - - WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-R " + b36KGReference + - " --DBSNP " + GATKDataLocation + "dbsnp_129_b36.rod" + - " -T CountCovariates" + - " -I " + bam + - " -L 1:10,000,000-10,200,000" + - " -cov ReadGroupCovariate" + - " -cov QualityScoreCovariate" + - " -cov CycleCovariate" + - " -cov DinucCovariate" + - " --default_read_group DefaultReadGroup" + - " --default_platform illumina" + - " --solid_recal_mode SET_Q_ZERO" + - " -recalFile %s", - 1, // just one output file - Arrays.asList(md5)); - List result = executeTest("testCountCovariatesNoReadGroups", spec).getFirst(); - paramsFilesNoReadGroupTest.put(bam, result.get(0).getAbsolutePath()); - } - } - - @Test - public void testTableRecalibratorNoReadGroups() { - HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12762.SOLID.SRP000031.2009_07.chr1.10_20mb.bam", "1eefbe7ac0376fc1ed1392d85242171e" ); - - for ( Map.Entry entry : e.entrySet() ) { - String bam = entry.getKey(); - String md5 = entry.getValue(); - String paramsFile = paramsFilesNoReadGroupTest.get(bam); - System.out.printf("PARAMS FOR %s is %s%n", bam, paramsFile); - if ( paramsFile != null ) { - WalkerTestSpec spec = new WalkerTestSpec( - "-R " + b36KGReference + - " -T TableRecalibration" + - " -I " + bam + - " -L 1:10,100,000-10,300,000" + - " -o %s" + - " --no_pg_tag" + - " --solid_recal_mode SET_Q_ZERO" + - " --default_read_group DefaultReadGroup" + - " --default_platform illumina" + - " -recalFile " + paramsFile, - 1, // just one output file - Arrays.asList(md5)); - executeTest("testTableRecalibratorNoReadGroups", spec); - } - } - } - @Test public void testCountCovariatesNoIndex() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.noindex.bam", "cfc31bb6f51436d1c3b34f62bb801dc8" ); + e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.noindex.bam", "284ccac1f8fe485e52c86333cac7c2d4" ); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -356,7 +292,7 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { @Test public void testTableRecalibratorNoIndex() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.noindex.bam", "83b848a16034c2fb423d1bb0f5be7784" ); + e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.noindex.bam", "c167799c2d9cab815d7c9b23337f162e" ); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); @@ -380,11 +316,10 @@ public class RecalibrationWalkersIntegrationTest extends WalkerTest { } } - @Test public void testCountCovariatesFailWithoutDBSNP() { HashMap e = new HashMap(); - e.put( validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SOLID.bam", ""); + e.put( validationDataLocation + "NA12892.SLX.SRP000031.2009_06.selected.bam", ""); for ( Map.Entry entry : e.entrySet() ) { String bam = entry.getKey(); From 6007eea3ffba2e459ec6bf0a1c66c0a017fe0a62 Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Wed, 13 Jul 2011 09:56:08 -0400 Subject: [PATCH 25/83] Allowing VCF records without GTs in vf4.1 --- .../utils/codecs/vcf/StandardVCFWriter.java | 41 +++++++++++++------ .../sting/utils/codecs/vcf/VCF3Codec.java | 13 +++--- .../sting/utils/codecs/vcf/VCFCodec.java | 28 ++++++------- .../sting/utils/variantcontext/Genotype.java | 35 +++++++++++++--- .../utils/variantcontext/VariantContext.java | 8 ++-- 5 files changed, 83 insertions(+), 42 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java index a8bf74707..f7d09f16d 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java @@ -32,6 +32,7 @@ import org.broad.tribble.index.IndexFactory; import org.broad.tribble.util.LittleEndianOutputStream; import org.broad.tribble.util.ParsingUtils; import org.broad.tribble.util.PositionalStream; +import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.utils.variantcontext.Allele; import org.broadinstitute.sting.utils.variantcontext.Genotype; @@ -300,10 +301,7 @@ public class StandardVCFWriter implements VCFWriter { } else { List genotypeAttributeKeys = new ArrayList(); if ( vc.hasGenotypes() ) { - genotypeAttributeKeys.add(VCFConstants.GENOTYPE_KEY); - for ( String key : calcVCFGenotypeKeys(vc) ) { - genotypeAttributeKeys.add(key); - } + genotypeAttributeKeys.addAll(calcVCFGenotypeKeys(vc)); } else if ( mHeader.hasGenotypingData() ) { // this needs to be done in case all samples are no-calls genotypeAttributeKeys.add(VCFConstants.GENOTYPE_KEY); @@ -387,16 +385,22 @@ public class StandardVCFWriter implements VCFWriter { continue; } - writeAllele(g.getAllele(0), alleleMap); - for (int i = 1; i < g.getPloidy(); i++) { - mWriter.write(g.isPhased() ? VCFConstants.PHASED : VCFConstants.UNPHASED); - writeAllele(g.getAllele(i), alleleMap); - } - List attrs = new ArrayList(genotypeFormatKeys.size()); for ( String key : genotypeFormatKeys ) { - if ( key.equals(VCFConstants.GENOTYPE_KEY) ) + + if ( key.equals(VCFConstants.GENOTYPE_KEY) ) { + if ( !g.isAvailable() ) { + throw new ReviewedStingException("GTs cannot be missing for some samples if they are available for others in the record"); + } + + writeAllele(g.getAllele(0), alleleMap); + for (int i = 1; i < g.getPloidy(); i++) { + mWriter.write(g.isPhased() ? VCFConstants.PHASED : VCFConstants.UNPHASED); + writeAllele(g.getAllele(i), alleleMap); + } + continue; + } Object val = g.hasAttribute(key) ? g.getAttribute(key) : VCFConstants.MISSING_VALUE_v4; @@ -488,10 +492,13 @@ public class StandardVCFWriter implements VCFWriter { private static List calcVCFGenotypeKeys(VariantContext vc) { Set keys = new HashSet(); + boolean sawGoodGT = false; boolean sawGoodQual = false; boolean sawGenotypeFilter = false; for ( Genotype g : vc.getGenotypes().values() ) { keys.addAll(g.getAttributes().keySet()); + if ( g.isAvailable() ) + sawGoodGT = true; if ( g.hasNegLog10PError() ) sawGoodQual = true; if (g.isFiltered() && g.isCalled()) @@ -504,7 +511,17 @@ public class StandardVCFWriter implements VCFWriter { if (sawGenotypeFilter) keys.add(VCFConstants.GENOTYPE_FILTER_KEY); - return ParsingUtils.sortList(new ArrayList(keys)); + List sortedList = ParsingUtils.sortList(new ArrayList(keys)); + + // make sure the GT is first + if ( sawGoodGT ) { + List newList = new ArrayList(sortedList.size()+1); + newList.add(VCFConstants.GENOTYPE_KEY); + newList.addAll(sortedList); + sortedList = newList; + } + + return sortedList; } diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCF3Codec.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCF3Codec.java index f3c99e963..c29f2ba8b 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCF3Codec.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCF3Codec.java @@ -141,8 +141,6 @@ public class VCF3Codec extends AbstractVCFCodec { boolean missing = i >= GTValueSplitSize; if (gtKey.equals(VCFConstants.GENOTYPE_KEY)) { - if (i != 0) - generateException("Saw GT at position " + i + ", but it must be at the first position for genotypes"); genotypeAlleleLocation = i; } else if (gtKey.equals(VCFConstants.GENOTYPE_QUALITY_KEY)) { GTQual = missing ? parseQual(VCFConstants.MISSING_VALUE_v4) : parseQual(GTValueArray[i]); @@ -156,12 +154,13 @@ public class VCF3Codec extends AbstractVCFCodec { } } - // check to make sure we found a gentoype field - if (genotypeAlleleLocation < 0) generateException("Unable to find required field GT for the record; we don't yet support a missing GT field"); + // check to make sure we found a genotype field + if ( genotypeAlleleLocation < 0 ) + generateException("Unable to find the GT field for the record; the GT field is required"); + if ( genotypeAlleleLocation > 0 ) + generateException("Saw GT field at position " + genotypeAlleleLocation + ", but it must be at the first position for genotypes"); - // todo -- assuming allele list length in the single digits is bad. Fix me. - // Check for > 1 for haploid genotypes - boolean phased = GTValueArray[genotypeAlleleLocation].length() > 1 && GTValueArray[genotypeAlleleLocation].charAt(1) == '|'; + boolean phased = GTValueArray[genotypeAlleleLocation].indexOf(VCFConstants.PHASED) != -1; // add it to the list try { diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCodec.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCodec.java index 0fb2940bb..05fff5d9e 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCodec.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFCodec.java @@ -145,8 +145,6 @@ public class VCFCodec extends AbstractVCFCodec { // todo -- all of these on the fly parsing of the missing value should be static constants if (gtKey.equals(VCFConstants.GENOTYPE_KEY)) { - if (i != 0) - generateException("Saw GT at position " + i + ", but it must be at the first position for genotypes"); genotypeAlleleLocation = i; } else if (gtKey.equals(VCFConstants.GENOTYPE_QUALITY_KEY)) { GTQual = missing ? parseQual(VCFConstants.MISSING_VALUE_v4) : parseQual(GTValueArray[i]); @@ -160,22 +158,24 @@ public class VCFCodec extends AbstractVCFCodec { } } - // check to make sure we found a gentoype field - // TODO -- This is no longer required in v4.1 - if (genotypeAlleleLocation < 0) generateException("Unable to find required field GT for the record; we don't yet support a missing GT field"); + // check to make sure we found a genotype field if we are a VCF4.0 file + if ( version == VCFHeaderVersion.VCF4_0 && genotypeAlleleLocation == -1 ) + generateException("Unable to find the GT field for the record; the GT field is required in VCF4.0"); + if ( genotypeAlleleLocation > 0 ) + generateException("Saw GT field at position " + genotypeAlleleLocation + ", but it must be at the first position for genotypes when present"); - // todo -- assuming allele list length in the single digits is bad. Fix me. - // Check for > 1 for haploid genotypes - boolean phased = GTValueArray[genotypeAlleleLocation].length() > 1 && GTValueArray[genotypeAlleleLocation].charAt(1) == '|'; + List GTalleles = (genotypeAlleleLocation == -1 ? null : parseGenotypeAlleles(GTValueArray[genotypeAlleleLocation], alleles, alleleMap)); + boolean phased = genotypeAlleleLocation != -1 && GTValueArray[genotypeAlleleLocation].indexOf(VCFConstants.PHASED) != -1; // add it to the list try { - genotypes.put(sampleName, new Genotype(sampleName, - parseGenotypeAlleles(GTValueArray[genotypeAlleleLocation], alleles, alleleMap), - GTQual, - genotypeFilters, - gtAttributes, - phased)); + genotypes.put(sampleName, + new Genotype(sampleName, + GTalleles, + GTQual, + genotypeFilters, + gtAttributes, + phased)); } catch (TribbleException e) { throw new TribbleException.InternalCodecException(e.getMessage() + ", at position " + chr+":"+pos); } diff --git a/public/java/src/org/broadinstitute/sting/utils/variantcontext/Genotype.java b/public/java/src/org/broadinstitute/sting/utils/variantcontext/Genotype.java index 3a87f1196..0b5976c3c 100755 --- a/public/java/src/org/broadinstitute/sting/utils/variantcontext/Genotype.java +++ b/public/java/src/org/broadinstitute/sting/utils/variantcontext/Genotype.java @@ -3,6 +3,7 @@ package org.broadinstitute.sting.utils.variantcontext; import org.broad.tribble.util.ParsingUtils; import org.broadinstitute.sting.utils.codecs.vcf.VCFConstants; +import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; import java.util.*; @@ -19,12 +20,14 @@ public class Genotype { protected InferredGeneticContext commonInfo; public final static double NO_NEG_LOG_10PERROR = InferredGeneticContext.NO_NEG_LOG_10PERROR; protected List alleles = null; // new ArrayList(); + protected Type type = null; protected boolean isPhased = false; - private boolean filtersWereAppliedToContext; + protected boolean filtersWereAppliedToContext; public Genotype(String sampleName, List alleles, double negLog10PError, Set filters, Map attributes, boolean isPhased) { - this.alleles = Collections.unmodifiableList(alleles); + if ( alleles != null ) + this.alleles = Collections.unmodifiableList(alleles); commonInfo = new InferredGeneticContext(sampleName, negLog10PError, filters, attributes); filtersWereAppliedToContext = filters != null; this.isPhased = isPhased; @@ -66,6 +69,9 @@ public class Genotype { } public List getAlleles(Allele allele) { + if ( getType() == Type.UNAVAILABLE ) + throw new ReviewedStingException("Requesting alleles for an UNAVAILABLE genotype"); + List al = new ArrayList(); for ( Allele a : alleles ) if ( a.equals(allele) ) @@ -75,6 +81,8 @@ public class Genotype { } public Allele getAllele(int i) { + if ( getType() == Type.UNAVAILABLE ) + throw new ReviewedStingException("Requesting alleles for an UNAVAILABLE genotype"); return alleles.get(i); } @@ -89,10 +97,21 @@ public class Genotype { NO_CALL, HOM_REF, HET, - HOM_VAR + HOM_VAR, + UNAVAILABLE } public Type getType() { + if ( type == null ) { + type = determineType(); + } + return type; + } + + protected Type determineType() { + if ( alleles == null ) + return Type.UNAVAILABLE; + Allele firstAllele = alleles.get(0); if ( firstAllele.isNoCall() ) { @@ -122,7 +141,8 @@ public class Genotype { * @return true if this genotype is not actually a genotype but a "no call" (e.g. './.' in VCF) */ public boolean isNoCall() { return getType() == Type.NO_CALL; } - public boolean isCalled() { return getType() != Type.NO_CALL; } + public boolean isCalled() { return getType() != Type.NO_CALL && getType() != Type.UNAVAILABLE; } + public boolean isAvailable() { return getType() != Type.UNAVAILABLE; } // // Useful methods for getting genotype likelihoods for a genotype object, if present @@ -157,8 +177,8 @@ public class Genotype { } public void validate() { - if ( alleles == null ) throw new IllegalArgumentException("BUG: alleles cannot be null in setAlleles"); - if ( alleles.size() == 0) throw new IllegalArgumentException("BUG: alleles cannot be of size 0 in setAlleles"); + if ( alleles == null ) return; + if ( alleles.size() == 0) throw new IllegalArgumentException("BUG: alleles cannot be of size 0"); int nNoCalls = 0; for ( Allele allele : alleles ) { @@ -175,6 +195,9 @@ public class Genotype { } public String getGenotypeString(boolean ignoreRefState) { + if ( alleles == null ) + return null; + // Notes: // 1. Make sure to use the appropriate separator depending on whether the genotype is phased // 2. If ignoreRefState is true, then we want just the bases of the Alleles (ignoring the '*' indicating a ref Allele) diff --git a/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java b/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java index da80a3431..92c5d648b 100755 --- a/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java +++ b/public/java/src/org/broadinstitute/sting/utils/variantcontext/VariantContext.java @@ -1206,9 +1206,11 @@ public class VariantContext implements Feature { // to enable tribble intergrati if ( ! name.equals(g.getSampleName()) ) throw new IllegalStateException("Bound sample name " + name + " does not equal the name of the genotype " + g.getSampleName()); - for ( Allele gAllele : g.getAlleles() ) { - if ( ! hasAllele(gAllele) && gAllele.isCalled() ) - throw new IllegalStateException("Allele in genotype " + gAllele + " not in the variant context " + alleles); + if ( g.isAvailable() ) { + for ( Allele gAllele : g.getAlleles() ) { + if ( ! hasAllele(gAllele) && gAllele.isCalled() ) + throw new IllegalStateException("Allele in genotype " + gAllele + " not in the variant context " + alleles); + } } } } From 797c50e6894f5e5fd341c3b002610301173c269a Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Wed, 13 Jul 2011 10:01:23 -0400 Subject: [PATCH 26/83] Fixing integration tests I broke yesterday; removing batch merging test since we don't support that anymore. --- .../phasing/MergeMNPsIntegrationTest.java | 6 +-- ...gatingAlternateAllelesIntegrationTest.java | 6 +-- .../BatchMergeIntegrationTest.java | 46 ------------------- 3 files changed, 6 insertions(+), 52 deletions(-) delete mode 100755 public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/BatchMergeIntegrationTest.java diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/MergeMNPsIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/MergeMNPsIntegrationTest.java index 3f87fc1a2..c88eac149 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/MergeMNPsIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/MergeMNPsIntegrationTest.java @@ -23,7 +23,7 @@ public class MergeMNPsIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "merging_test_chr20_556259_756570.vcf", 1) + " -L chr20:556259-756570", 1, - Arrays.asList("e312b7d3854d5b2834a370659514a813")); + Arrays.asList("7f11f7f75d1526077f0173c7ed1fc6c4")); executeTest("Merge MNP sites within genomic distance of 1 [TEST ONE]", spec); } @@ -33,7 +33,7 @@ public class MergeMNPsIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "merging_test_chr20_556259_756570.vcf", 10) + " -L chr20:556259-756570", 1, - Arrays.asList("681f50e45f1d697370d2c355df2e18bc")); + Arrays.asList("53dd312468296826bdd3c22387390c88")); executeTest("Merge MNP sites within genomic distance of 10 [TEST TWO]", spec); } @@ -43,7 +43,7 @@ public class MergeMNPsIntegrationTest extends WalkerTest { baseTestString(hg18Reference, "merging_test_chr20_556259_756570.vcf", 100) + " -L chr20:556259-756570", 1, - Arrays.asList("0bccb0ef928a108418246bec01098083")); + Arrays.asList("e26f92d2fb9f4eaeac7f9d8ee27410ee")); executeTest("Merge MNP sites within genomic distance of 100 [TEST THREE]", spec); } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/MergeSegregatingAlternateAllelesIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/MergeSegregatingAlternateAllelesIntegrationTest.java index 009048c10..f855c1dd3 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/MergeSegregatingAlternateAllelesIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/phasing/MergeSegregatingAlternateAllelesIntegrationTest.java @@ -23,7 +23,7 @@ public class MergeSegregatingAlternateAllelesIntegrationTest extends WalkerTest baseTestString(hg18Reference, "merging_test_chr20_556259_756570.vcf", 1) + " -L chr20:556259-756570", 1, - Arrays.asList("e16f957d888054ae0518e25660295241")); + Arrays.asList("af5e1370822551c0c6f50f23447dc627")); executeTest("Merge sites within genomic distance of 1 [TEST ONE]", spec); } @@ -33,7 +33,7 @@ public class MergeSegregatingAlternateAllelesIntegrationTest extends WalkerTest baseTestString(hg18Reference, "merging_test_chr20_556259_756570.vcf", 10) + " -L chr20:556259-756570", 1, - Arrays.asList("122a482090677c7619c2105d44e00d11")); + Arrays.asList("dd8c44ae1ef059a7fe85399467e102eb")); executeTest("Merge sites within genomic distance of 10 [TEST TWO]", spec); } @@ -43,7 +43,7 @@ public class MergeSegregatingAlternateAllelesIntegrationTest extends WalkerTest baseTestString(hg18Reference, "merging_test_chr20_556259_756570.vcf", 100) + " -L chr20:556259-756570", 1, - Arrays.asList("bc6a8c8a42bb2601db98e88e9ad74748")); + Arrays.asList("f81fd72ecaa57b3215406fcea860bcc5")); executeTest("Merge sites within genomic distance of 100 [TEST THREE]", spec); } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/BatchMergeIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/BatchMergeIntegrationTest.java deleted file mode 100755 index 7e1d86105..000000000 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/BatchMergeIntegrationTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2010, 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.sting.gatk.walkers.variantutils; - -import org.broadinstitute.sting.WalkerTest; -import org.testng.annotations.Test; - -import java.io.File; -import java.util.Arrays; - -public class BatchMergeIntegrationTest extends WalkerTest { - @Test - public void testBatchMerge1() { - String bam = validationDataLocation + "NA12878.HiSeq.b37.chr20.10_11mb.bam"; - String alleles = validationDataLocation + "batch.merge.alleles.vcf"; - WalkerTestSpec spec = new WalkerTestSpec( - "-T UnifiedGenotyper -NO_HEADER -BTI alleles -stand_call_conf 0.0 -glm BOTH -G none -nsl -gt_mode GENOTYPE_GIVEN_ALLELES -out_mode EMIT_ALL_SITES -o %s -R " + b37KGReference - + " -B:alleles,VCF " + alleles - + " -I " + bam, - 1, - Arrays.asList("f4ed8f4ef2cba96823c06e90e9d0de35")); - executeTest("testBatchMerge UG genotype given alleles:" + new File(bam).getName() + " with " + new File(alleles).getName(), spec); - } -} \ No newline at end of file From fa3ff5350800f1449b6e4e5f365cf2b745906932 Mon Sep 17 00:00:00 2001 From: Menachem Fromer Date: Wed, 13 Jul 2011 11:58:16 -0400 Subject: [PATCH 30/83] Filters should only be applied to the new VC if the old VC had filters applied --- .../sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java index e59b29502..af24035c8 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java @@ -220,6 +220,9 @@ public class ReadBackedPhasingWalker extends RodWalker Date: Wed, 13 Jul 2011 14:40:01 -0400 Subject: [PATCH 32/83] Don't output source and ref header lines anymore. Short-term motivation for this is that I'd like this tool when run on a VCF to emit the exact same VCF. Long-term motivation is that these tags should be output by the VCF writer itself for all tools. --- .../walkers/variantutils/VariantsToVCF.java | 4 +-- .../utils/codecs/vcf/VCFIntegrationTest.java | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 public/java/test/org/broadinstitute/sting/utils/codecs/vcf/VCFIntegrationTest.java diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCF.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCF.java index 7eb49da34..79134b553 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCF.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCF.java @@ -199,8 +199,8 @@ public class VariantsToVCF extends RodWalker { // setup the header fields Set hInfo = new HashSet(); hInfo.addAll(VCFUtils.getHeaderFields(getToolkit())); - hInfo.add(new VCFHeaderLine("source", "VariantsToVCF")); - hInfo.add(new VCFHeaderLine("reference", getToolkit().getArguments().referenceFile.getName())); + //hInfo.add(new VCFHeaderLine("source", "VariantsToVCF")); + //hInfo.add(new VCFHeaderLine("reference", getToolkit().getArguments().referenceFile.getName())); allowedGenotypeFormatStrings.add(VCFConstants.GENOTYPE_KEY); for ( VCFHeaderLine field : hInfo ) { diff --git a/public/java/test/org/broadinstitute/sting/utils/codecs/vcf/VCFIntegrationTest.java b/public/java/test/org/broadinstitute/sting/utils/codecs/vcf/VCFIntegrationTest.java new file mode 100644 index 000000000..32ff25c7b --- /dev/null +++ b/public/java/test/org/broadinstitute/sting/utils/codecs/vcf/VCFIntegrationTest.java @@ -0,0 +1,28 @@ +package org.broadinstitute.sting.utils.codecs.vcf; + +import org.broadinstitute.sting.WalkerTest; +import org.testng.annotations.Test; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +public class VCFIntegrationTest extends WalkerTest { + + @Test + public void testReadingAndWritingWitHNoChanges() { + + String md5ofInputVCF = "a990ba187a69ca44cb9bc2bb44d00447"; + String testVCF = validationDataLocation + "vcf4.1.example.vcf"; + + String baseCommand = "-R " + b37KGReference + " -NO_HEADER -o %s "; + + String test1 = baseCommand + "-T VariantAnnotator -BTI variant -B:variant,vcf " + testVCF; + WalkerTestSpec spec1 = new WalkerTestSpec(test1, 1, Arrays.asList(md5ofInputVCF)); + List result = executeTest("Test Variant Annotator with no changes", spec1).getFirst(); + + String test2 = baseCommand + "-T VariantsToVCF -B:variant,vcf " + result.get(0).getAbsolutePath(); + WalkerTestSpec spec2 = new WalkerTestSpec(test2, 1, Arrays.asList(md5ofInputVCF)); + executeTest("Test Variants To VCF from new output", spec2); + } +} From df996a1a738208dac7c42b24645f747304b3de7f Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Wed, 13 Jul 2011 14:53:58 -0400 Subject: [PATCH 33/83] more progress report for the Data Processing Pipeline. Bam lists can now have empty lines, comments and whitespaces anywhere. --- .../qscripts/DataProcessingPipeline.scala | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala index f9369ee3f..d6caabd23 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala @@ -147,13 +147,22 @@ class DataProcessingPipeline extends QScript { } } + println("\n\n*** DEBUG ***\n") // Creating one file for each sample in the dataset val sampleBamFiles = scala.collection.mutable.Map.empty[String, File] for ((sample, flist) <- sampleTable) { + + println(sample + ":") + for (f <- flist) + println (f) + println() + val sampleFileName = new File(qscript.outputDir + qscript.projectName + "." + sample + ".bam") sampleBamFiles(sample) = sampleFileName add(joinBams(flist, sampleFileName)) } + println("*** DEBUG ***\n\n") + return sampleBamFiles.toMap } @@ -211,8 +220,10 @@ class DataProcessingPipeline extends QScript { if (in.toString.endsWith("bam")) return List(in) var l: List[File] = List() - for (bam <- fromFile(in).getLines) - l :+= new File(bam) + for (bam <- fromFile(in).getLines) { + if (!bam.startsWith("#") && !bam.isEmpty) + l :+= new File(bam.trim) + } return l } @@ -234,9 +245,6 @@ class DataProcessingPipeline extends QScript { // Generate a BAM file per sample joining all per lane files if necessary val sampleBamFiles: Map[String, File] = createSampleFiles(bams, realignedBams) - - println("nContigs: " + nContigs) - // Final output list of processed bam files var cohortList: List[File] = List() @@ -244,6 +252,7 @@ class DataProcessingPipeline extends QScript { println("\nFound the following samples: ") for ((sample, file) <- sampleBamFiles) println("\t" + sample + " -> " + file) + println("\n") // If this is a 'knowns only' indel realignment run, do it only once for all samples. val globalIntervals = new File(outputDir + projectName + ".intervals") From bb0e3a26fcf2a0c99ee0e70c46fb6359b3720a40 Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Wed, 13 Jul 2011 14:57:21 -0400 Subject: [PATCH 34/83] Added integration test for VCF writing. Also, bug fix for writing the GT-free records. --- .../sting/utils/codecs/vcf/StandardVCFWriter.java | 7 ++++--- .../variantutils/VariantsToVCFIntegrationTest.java | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java index f7d09f16d..e7ddac185 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/StandardVCFWriter.java @@ -444,9 +444,10 @@ public class StandardVCFWriter implements VCFWriter { break; } - for (String s : attrs ) { - mWriter.write(VCFConstants.GENOTYPE_FIELD_SEPARATOR); - mWriter.write(s); + for (int i = 0; i < attrs.size(); i++) { + if ( i > 0 || genotypeFormatKeys.contains(VCFConstants.GENOTYPE_KEY) ) + mWriter.write(VCFConstants.GENOTYPE_FIELD_SEPARATOR); + mWriter.write(attrs.get(i)); } } } diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCFIntegrationTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCFIntegrationTest.java index 8421076c9..8c96c1e11 100755 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCFIntegrationTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/variantutils/VariantsToVCFIntegrationTest.java @@ -20,7 +20,7 @@ public class VariantsToVCFIntegrationTest extends WalkerTest { @Test public void testVariantsToVCFUsingGeliInput() { List md5 = new ArrayList(); - md5.add("815b82fff92aab41c209eedce2d7e7d9"); + md5.add("4accae035d271b35ee2ec58f403c68c6"); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-R " + b36KGReference + @@ -38,7 +38,7 @@ public class VariantsToVCFIntegrationTest extends WalkerTest { @Test public void testGenotypesToVCFUsingGeliInput() { List md5 = new ArrayList(); - md5.add("22336ee9c12aa222ce29c3c5babca7d0"); + md5.add("71e8c98d7c3a73b6287ecc339086fe03"); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-R " + b36KGReference + @@ -56,7 +56,7 @@ public class VariantsToVCFIntegrationTest extends WalkerTest { @Test public void testGenotypesToVCFUsingHapMapInput() { List md5 = new ArrayList(); - md5.add("9bedaa7670b86a07be5191898c3727cf"); + md5.add("f343085305e80c7a2493422e4eaad983"); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-R " + b36KGReference + @@ -73,7 +73,7 @@ public class VariantsToVCFIntegrationTest extends WalkerTest { @Test public void testGenotypesToVCFUsingVCFInput() { List md5 = new ArrayList(); - md5.add("cc215edec9ca28e5c79ab1b67506f9f7"); + md5.add("86f02e2e764ba35854cff2aa05a1fdd8"); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-R " + b36KGReference + From 66c652d687ec5b5e15b33255441e31b775d20c3c Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Thu, 14 Jul 2011 11:56:10 -0400 Subject: [PATCH 41/83] Added some extra error checks in the VCF codec. Now that we've moved this back into the GATK, changed some of the standard exceptions to be USerErrors (instead of TribbleExceptions). --- .../utils/codecs/vcf/AbstractVCFCodec.java | 25 ++++++++++--------- .../sting/utils/exceptions/UserException.java | 10 ++++++++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/AbstractVCFCodec.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/AbstractVCFCodec.java index 01344a117..710127f7a 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/AbstractVCFCodec.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/AbstractVCFCodec.java @@ -7,6 +7,8 @@ import org.broad.tribble.NameAwareCodec; import org.broad.tribble.TribbleException; import org.broad.tribble.readers.LineReader; import org.broad.tribble.util.ParsingUtils; +import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; +import org.broadinstitute.sting.utils.exceptions.UserException; import org.broadinstitute.sting.utils.variantcontext.Allele; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; @@ -96,6 +98,9 @@ public abstract class AbstractVCFCodec implements FeatureCodec, NameAwareCodec, for ( String str : headerStrings ) { if ( !str.startsWith(VCFHeader.METADATA_INDICATOR) ) { String[] strings = str.substring(1).split(VCFConstants.FIELD_SEPARATOR); + if ( strings.length < VCFHeader.HEADER_FIELDS.values().length ) + throw new TribbleException.InvalidHeader("there are not enough columns present in the header line: " + str); + int arrayIndex = 0; for (VCFHeader.HEADER_FIELDS field : VCFHeader.HEADER_FIELDS.values()) { try { @@ -159,12 +164,11 @@ public abstract class AbstractVCFCodec implements FeatureCodec, NameAwareCodec, } private Feature reallyDecode(String line) { - try { // the same line reader is not used for parsing the header and parsing lines, if we see a #, we've seen a header line if (line.startsWith(VCFHeader.HEADER_INDICATOR)) return null; // our header cannot be null, we need the genotype sample names and counts - if (header == null) throw new IllegalStateException("VCF Header cannot be null when decoding a record"); + if (header == null) throw new ReviewedStingException("VCF Header cannot be null when decoding a record"); if (parts == null) parts = new String[Math.min(header.getColumnCount(), NUM_STANDARD_FIELDS+1)]; @@ -174,17 +178,18 @@ public abstract class AbstractVCFCodec implements FeatureCodec, NameAwareCodec, // if we have don't have a header, or we have a header with no genotyping data check that we have eight columns. Otherwise check that we have nine (normal colummns + genotyping data) if (( (header == null || (header != null && !header.hasGenotypingData())) && nParts != NUM_STANDARD_FIELDS) || (header != null && header.hasGenotypingData() && nParts != (NUM_STANDARD_FIELDS + 1)) ) - throw new IllegalArgumentException("There aren't enough columns for line " + line + " (we expected " + (header == null ? NUM_STANDARD_FIELDS : NUM_STANDARD_FIELDS + 1) + - " tokens, and saw " + nParts + " )"); + throw new UserException.MalformedVCF("there aren't enough columns for line " + line + " (we expected " + (header == null ? NUM_STANDARD_FIELDS : NUM_STANDARD_FIELDS + 1) + + " tokens, and saw " + nParts + " )", lineNo); return parseVCFLine(parts); - } catch (TribbleException e) { - throw new TribbleException.InvalidDecodeLine(e.getMessage(), line); - } } protected void generateException(String message) { - throw new TribbleException.InvalidDecodeLine(message, lineNo); + throw new UserException.MalformedVCF(message, lineNo); + } + + private static void generateException(String message, int lineNo) { + throw new UserException.MalformedVCF(message, lineNo); } /** @@ -472,10 +477,6 @@ public abstract class AbstractVCFCodec implements FeatureCodec, NameAwareCodec, return true; } - private static void generateException(String message, int lineNo) { - throw new TribbleException.InvalidDecodeLine(message, lineNo); - } - private static int computeForwardClipping(List unclippedAlleles, String ref) { boolean clipping = true; // Note that the computation of forward clipping here is meant only to see whether there is a common diff --git a/public/java/src/org/broadinstitute/sting/utils/exceptions/UserException.java b/public/java/src/org/broadinstitute/sting/utils/exceptions/UserException.java index 0be4bec91..17c4a7df4 100755 --- a/public/java/src/org/broadinstitute/sting/utils/exceptions/UserException.java +++ b/public/java/src/org/broadinstitute/sting/utils/exceptions/UserException.java @@ -154,6 +154,16 @@ public class UserException extends ReviewedStingException { } } + public static class MalformedVCF extends UserException { + public MalformedVCF(String message, String line) { + super(String.format("The provided VCF file is malformed at line %s: %s", line, message)); + } + + public MalformedVCF(String message, int lineNo) { + super(String.format("The provided VCF file is malformed at line nmber %d: %s", lineNo, message)); + } + } + public static class ReadMissingReadGroup extends MalformedBAM { public ReadMissingReadGroup(SAMRecord read) { super(read, String.format("Read %s is either missing the read group or its read group is not defined in the BAM header, both of which are required by the GATK. Please use http://www.broadinstitute.org/gsa/wiki/index.php/ReplaceReadGroups to fix this problem", read.getReadName())); From ed6beae1f3769c247b9a4fc80121985baad6443f Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Thu, 14 Jul 2011 13:55:35 -0400 Subject: [PATCH 42/83] Adding headers to diffable reading for VCFs --- .../gatk/walkers/diffengine/VCFDiffableReader.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java index 06d14366f..5677574bd 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java @@ -26,16 +26,12 @@ package org.broadinstitute.sting.gatk.walkers.diffengine; import org.broad.tribble.readers.AsciiLineReader; import org.broad.tribble.readers.LineReader; -import org.broadinstitute.sting.utils.codecs.vcf.VCFCodec; -import org.broadinstitute.sting.utils.codecs.vcf.VCFConstants; -import org.broadinstitute.sting.utils.codecs.vcf.VCFHeader; +import org.broadinstitute.sting.utils.codecs.vcf.*; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import java.io.*; -import java.util.Arrays; import java.util.Map; -import java.util.zip.GZIPInputStream; /** @@ -58,7 +54,11 @@ public class VCFDiffableReader implements DiffableReader { VCFCodec vcfCodec = new VCFCodec(); // must be read as state is stored in reader itself - vcfCodec.readHeader(lineReader); + VCFHeader header = (VCFHeader)vcfCodec.readHeader(lineReader); + for ( VCFHeaderLine headerLine : header.getMetaData() ) { + final String key = (headerLine instanceof VCFNamedHeaderLine ? headerLine.getKey() + "." + ((VCFNamedHeaderLine) headerLine).getName() : headerLine.getKey()); + root.add(key, headerLine.toString()); + } String line = lineReader.readLine(); int count = 0; From 9540df69986c16112b5fdd57efebf72846d86424 Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Thu, 14 Jul 2011 14:00:19 -0400 Subject: [PATCH 43/83] Oops, forgot to update unit test --- .../sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java index baa2f0383..a0cb47770 100644 --- a/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReaderUnitTest.java @@ -87,7 +87,7 @@ public class DiffableReaderUnitTest extends BaseTest { Assert.assertSame(diff.getParent(), DiffElement.ROOT); DiffNode node = diff.getValueAsNode(); - Assert.assertEquals(node.getElements().size(), 9); + Assert.assertEquals(node.getElements().size(), 10); // chr1 2646 rs62635284 G A 0.15 PASS AC=2;AF=1.00;AN=2 GT:AD:DP:GL:GQ 1/1:53,75:3:-12.40,-0.90,-0.00:9.03 DiffNode rec1 = node.getElement("chr1:2646").getValueAsNode(); From 5ffeddd3b1ac5f83d6018dad0a178ae785a4dc39 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Thu, 14 Jul 2011 14:45:16 -0400 Subject: [PATCH 44/83] better to use _ instead of ., as this is a special case later. --- .../sting/gatk/walkers/diffengine/VCFDiffableReader.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java index 5677574bd..a812babaf 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/VCFDiffableReader.java @@ -56,7 +56,9 @@ public class VCFDiffableReader implements DiffableReader { // must be read as state is stored in reader itself VCFHeader header = (VCFHeader)vcfCodec.readHeader(lineReader); for ( VCFHeaderLine headerLine : header.getMetaData() ) { - final String key = (headerLine instanceof VCFNamedHeaderLine ? headerLine.getKey() + "." + ((VCFNamedHeaderLine) headerLine).getName() : headerLine.getKey()); + String key = headerLine.getKey(); + if ( headerLine instanceof VCFNamedHeaderLine ) + key += "_" + ((VCFNamedHeaderLine) headerLine).getName(); root.add(key, headerLine.toString()); } From c0bbeb23ba0200d80f940a395ddc019fdb61f093 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Thu, 14 Jul 2011 15:12:28 -0400 Subject: [PATCH 45/83] Now providing more information when the index on the fly isn't equal to the one created by reading the file from disk. --- .../test/org/broadinstitute/sting/WalkerTest.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/public/java/test/org/broadinstitute/sting/WalkerTest.java b/public/java/test/org/broadinstitute/sting/WalkerTest.java index dacaf2738..d65f4ec34 100755 --- a/public/java/test/org/broadinstitute/sting/WalkerTest.java +++ b/public/java/test/org/broadinstitute/sting/WalkerTest.java @@ -26,7 +26,9 @@ package org.broadinstitute.sting; import org.apache.commons.lang.StringUtils; +import org.broad.tribble.FeatureCodec; import org.broad.tribble.Tribble; +import org.broad.tribble.index.Index; import org.broad.tribble.index.IndexFactory; import org.broadinstitute.sting.utils.codecs.vcf.VCFCodec; import org.broadinstitute.sting.gatk.CommandLineExecutable; @@ -64,10 +66,19 @@ public class WalkerTest extends BaseTest { } System.out.println("Verifying on-the-fly index " + indexFile + " for test " + name + " using file " + resultFile); - Assert.assertTrue(IndexFactory.onDiskIndexEqualToNewlyCreatedIndex(resultFile, indexFile, new VCFCodec()), "Index on disk from indexing on the fly not equal to the index created after the run completed"); + Index indexFromOutputFile = IndexFactory.createIndex(resultFile, new VCFCodec()); + Index dynamicIndex = IndexFactory.loadIndex(indexFile.getAbsolutePath()); + + if ( ! indexFromOutputFile.equals(dynamicIndex) ) { + Assert.fail(String.format("Index on disk from indexing on the fly not equal to the index created after the run completed. FileIndex %s vs. on-the-fly %s%n", + indexFromOutputFile.getProperties(), + dynamicIndex.getProperties())); + } } } + + public List assertMatchingMD5s(final String name, List resultFiles, List expectedMD5s) { List md5s = new ArrayList(); for (int i = 0; i < resultFiles.size(); i++) { From 9f5180ab053d7116b194f2ef09b5f157dbeb4cca Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Thu, 14 Jul 2011 16:42:17 -0400 Subject: [PATCH 46/83] Recalibrates a list of bam files allowing multiple bams to be recalibrated out of a single 'mother' queue job. --- .../qscripts/RecalibrateBaseQualities.scala | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala index dc9ae0f4b..88c7f5ff7 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala @@ -3,6 +3,7 @@ package org.broadinstitute.sting.queue.qscripts import org.broadinstitute.sting.queue.QScript import org.broadinstitute.sting.queue.extensions.gatk._ import net.sf.samtools.SAMFileReader +import io.Source._ /** * Created by IntelliJ IDEA. @@ -37,21 +38,35 @@ class RecalibrateBaseQualities extends QScript { return samReader.getFileHeader.getSequenceDictionary.getSequences.size() } + // Reads a BAM LIST file and creates a scala list with all the files + def createListFromFile(in: File):List[File] = { + if (in.toString.endsWith("bam")) + return List(in) + var l: List[File] = List() + for (bam <- fromFile(in).getLines) + l :+= new File(bam) + return l + } + def script = { - nContigs = getNumberOfContigs(input) + val bamList = createListFromFile(input) + nContigs = getNumberOfContigs(bamList(0)) - val recalFile1: File = swapExt(input, ".bam", ".recal1.csv") - val recalFile2: File = swapExt(input, ".bam", ".recal2.csv") - val recalBam: File = swapExt(input, ".bam", ".recal.bam") - val path1: String = input + "before" - val path2: String = input + "after" - - add(cov(input, recalFile1), - recal(input, recalFile1, recalBam), - cov(recalBam, recalFile2), - analyzeCovariates(recalFile1, path1), - analyzeCovariates(recalFile2, path2)) + for (bam <- bamList) { + + val recalFile1: File = swapExt(bam, ".bam", ".recal1.csv") + val recalFile2: File = swapExt(bam, ".bam", ".recal2.csv") + val recalBam: File = swapExt(bam, ".bam", ".recal.bam") + val path1: String = bam + "before" + val path2: String = bam + "after" + + add(cov(bam, recalFile1), + recal(bam, recalFile1, recalBam), + cov(recalBam, recalFile2), + analyzeCovariates(recalFile1, path1), + analyzeCovariates(recalFile2, path2)) + } } trait CommandLineGATKArgs extends CommandLineGATK { From 09ffe277ae7d3418f75510cabe65e6c9a8fa8f25 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Thu, 14 Jul 2011 17:09:35 -0400 Subject: [PATCH 47/83] Added a qscripts util package with some utility functions commonly shared across queue scripts. Refactored some of my public scripts to use it in an effort to make queue scripts more reusable and "supportable". --- .../qscripts/DataProcessingPipeline.scala | 38 ++---------- .../qscripts/RecalibrateBaseQualities.scala | 20 +----- .../sting/queue/qscripts/utils/Utils.scala | 62 +++++++++++++++++++ 3 files changed, 71 insertions(+), 49 deletions(-) create mode 100644 public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala index f9369ee3f..e62b1b926 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala @@ -4,13 +4,13 @@ import org.broadinstitute.sting.queue.extensions.gatk._ import org.broadinstitute.sting.queue.QScript import org.broadinstitute.sting.queue.function.ListWriterFunction -import scala.io.Source._ import collection.JavaConversions._ import org.broadinstitute.sting.gatk.walkers.indels.IndelRealigner.ConsensusDeterminationModel import org.broadinstitute.sting.queue.extensions.picard._ -import net.sf.samtools.{SAMFileReader, SAMReadGroupRecord} +import net.sf.samtools.{SAMFileReader} import net.sf.samtools.SAMFileHeader.SortOrder +import org.broadinstitute.sting.queue.qscripts.utils.Utils class DataProcessingPipeline extends QScript { qscript => @@ -103,18 +103,6 @@ class DataProcessingPipeline extends QScript { val ds: String) {} - // Utility function to check if there are multiple samples in a BAM file (currently we can't deal with that) - def hasMultipleSamples(readGroups: java.util.List[SAMReadGroupRecord]): Boolean = { - var sample: String = "" - for (r <- readGroups) { - if (sample.isEmpty) - sample = r.getSample - else if (sample != r.getSample) - return true; - } - return false - } - // Utility function to merge all bam files of similar samples. Generates one BAM file per sample. // It uses the sample information on the header of the input BAM files. // @@ -135,7 +123,7 @@ class DataProcessingPipeline extends QScript { // only allow one sample per file. Bam files with multiple samples would require pre-processing of the file // with PrintReads to separate the samples. Tell user to do it himself! - assert(!hasMultipleSamples(readGroups), "The pipeline requires that only one sample is present in a BAM file. Please separate the samples in " + bam) + assert(!Utils.hasMultipleSamples(readGroups), "The pipeline requires that only one sample is present in a BAM file. Please separate the samples in " + bam) // Fill out the sample table with the readgroups in this file for (rg <- readGroups) { @@ -157,12 +145,6 @@ class DataProcessingPipeline extends QScript { return sampleBamFiles.toMap } - // Checks how many contigs are in the dataset. Uses the BAM file header information. - def getNumberOfContigs(bamFile: File): Int = { - val samReader = new SAMFileReader(new File(bamFile)) - return samReader.getFileHeader.getSequenceDictionary.getSequences.size() - } - // Rebuilds the Read Group string to give BWA def addReadGroups(inBam: File, outBam: File, samReader: SAMFileReader) { val readGroups = samReader.getFileHeader.getReadGroups @@ -206,15 +188,7 @@ class DataProcessingPipeline extends QScript { return realignedBams } - // Reads a BAM LIST file and creates a scala list with all the files - def createListFromFile(in: File):List[File] = { - if (in.toString.endsWith("bam")) - return List(in) - var l: List[File] = List() - for (bam <- fromFile(in).getLines) - l :+= new File(bam) - return l - } + @@ -226,8 +200,8 @@ class DataProcessingPipeline extends QScript { def script = { // keep a record of the number of contigs in the first bam file in the list - val bams = createListFromFile(input) - nContigs = getNumberOfContigs(bams(0)) + val bams = Utils.createListFromFile(input) + nContigs = Utils.getNumberOfContigs(bams(0)) val realignedBams = if (useBWApe || useBWAse) {performAlignment(bams)} else {bams} diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala index 88c7f5ff7..b2960f150 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala @@ -4,6 +4,7 @@ import org.broadinstitute.sting.queue.QScript import org.broadinstitute.sting.queue.extensions.gatk._ import net.sf.samtools.SAMFileReader import io.Source._ +import org.broadinstitute.sting.queue.qscripts.utils.Utils /** * Created by IntelliJ IDEA. @@ -33,25 +34,10 @@ class RecalibrateBaseQualities extends QScript { val queueLogDir: String = ".qlog/" var nContigs: Int = 0 - def getNumberOfContigs(bamFile: File): Int = { - val samReader = new SAMFileReader(new File(bamFile)) - return samReader.getFileHeader.getSequenceDictionary.getSequences.size() - } - - // Reads a BAM LIST file and creates a scala list with all the files - def createListFromFile(in: File):List[File] = { - if (in.toString.endsWith("bam")) - return List(in) - var l: List[File] = List() - for (bam <- fromFile(in).getLines) - l :+= new File(bam) - return l - } - def script = { - val bamList = createListFromFile(input) - nContigs = getNumberOfContigs(bamList(0)) + val bamList = Utils.createListFromFile(input) + nContigs = Utils.getNumberOfContigs(bamList(0)) for (bam <- bamList) { diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala new file mode 100644 index 000000000..ff94744ee --- /dev/null +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala @@ -0,0 +1,62 @@ +package org.broadinstitute.sting.queue.qscripts.utils + +import java.io.File +import io.Source._ +import net.sf.samtools.{SAMReadGroupRecord, SAMFileReader} + +import collection.JavaConversions._ + + +/** + * Created by IntelliJ IDEA. + * User: carneiro + * Date: 7/14/11 + * Time: 4:57 PM + * To change this template use File | Settings | File Templates. + */ + +object Utils { + + /** + * Takes a bam list file and produces a scala list with each file allowing the bam list + * to have empty lines and comment lines (lines starting with #). + */ + def createListFromFile(in: File):List[File] = { + // If the file provided ends with .bam, it is not a bam list, we treat it as a single file. + // and return a list with only this file. + if (in.toString.endsWith(".bam")) + return List(in) + + var list: List[File] = List() + for (bam <- fromFile(in).getLines) + if (!bam.startsWith("#") && !bam.isEmpty ) + list :+= new File(bam.trim()) + list + } + + /** + * Returns the number of contigs in the BAM file header. + */ + + def getNumberOfContigs(bamFile: File): Int = { + val samReader = new SAMFileReader(new File(bamFile)) + samReader.getFileHeader.getSequenceDictionary.getSequences.size() + } + + /** + * Check if there are multiple samples in a BAM file + */ + + def hasMultipleSamples(readGroups: java.util.List[SAMReadGroupRecord]): Boolean = { + var sample: String = "" + for (r <- readGroups) { + if (sample.isEmpty) + sample = r.getSample + else if (sample != r.getSample) + return true; + } + false + } + + +} \ No newline at end of file From 43c6a8565bfe77e4c50317a3e8858b754d4afcba Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Thu, 14 Jul 2011 17:10:44 -0400 Subject: [PATCH 48/83] looks better now. --- .../org/broadinstitute/sting/queue/qscripts/utils/Utils.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala index ff94744ee..1189b376c 100644 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala @@ -37,7 +37,6 @@ object Utils { /** * Returns the number of contigs in the BAM file header. */ - def getNumberOfContigs(bamFile: File): Int = { val samReader = new SAMFileReader(new File(bamFile)) samReader.getFileHeader.getSequenceDictionary.getSequences.size() @@ -46,7 +45,6 @@ object Utils { /** * Check if there are multiple samples in a BAM file */ - def hasMultipleSamples(readGroups: java.util.List[SAMReadGroupRecord]): Boolean = { var sample: String = "" for (r <- readGroups) { From a670d6420ad586b7138326b994822ce1f6682629 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Fri, 15 Jul 2011 14:31:43 -0400 Subject: [PATCH 51/83] Refactoring Qscript utils into queue general utils package. --- .../sting/queue/qscripts/DataProcessingPipeline.scala | 4 ++-- .../sting/queue/qscripts/RecalibrateBaseQualities.scala | 4 +--- .../org/broadinstitute/sting/queue/util}/Utils.scala | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) rename public/scala/{qscript/org/broadinstitute/sting/queue/qscripts/utils => src/org/broadinstitute/sting/queue/util}/Utils.scala (96%) diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala index e62b1b926..40ac43a81 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala @@ -7,10 +7,10 @@ import org.broadinstitute.sting.queue.function.ListWriterFunction import collection.JavaConversions._ import org.broadinstitute.sting.gatk.walkers.indels.IndelRealigner.ConsensusDeterminationModel import org.broadinstitute.sting.queue.extensions.picard._ -import net.sf.samtools.{SAMFileReader} +import net.sf.samtools.SAMFileReader import net.sf.samtools.SAMFileHeader.SortOrder -import org.broadinstitute.sting.queue.qscripts.utils.Utils +import org.broadinstitute.sting.queue.util.Utils class DataProcessingPipeline extends QScript { qscript => diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala index b2960f150..8ba880291 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala @@ -2,9 +2,7 @@ package org.broadinstitute.sting.queue.qscripts import org.broadinstitute.sting.queue.QScript import org.broadinstitute.sting.queue.extensions.gatk._ -import net.sf.samtools.SAMFileReader -import io.Source._ -import org.broadinstitute.sting.queue.qscripts.utils.Utils +import org.broadinstitute.sting.queue.util.Utils /** * Created by IntelliJ IDEA. diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala b/public/scala/src/org/broadinstitute/sting/queue/util/Utils.scala similarity index 96% rename from public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala rename to public/scala/src/org/broadinstitute/sting/queue/util/Utils.scala index 1189b376c..5b80503a3 100644 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/utils/Utils.scala +++ b/public/scala/src/org/broadinstitute/sting/queue/util/Utils.scala @@ -1,4 +1,4 @@ -package org.broadinstitute.sting.queue.qscripts.utils +package org.broadinstitute.sting.queue.util import java.io.File import io.Source._ From 7b7d40d5d97461f3b4cf71bf7b6efc0695a97f91 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Fri, 15 Jul 2011 14:34:50 -0400 Subject: [PATCH 52/83] A better name for the qscript utilities. Throw here every method you find yourself repeatedly implementing in your qscripts! Refactoring appropriately. --- .../sting/queue/qscripts/DataProcessingPipeline.scala | 8 ++++---- .../sting/queue/qscripts/RecalibrateBaseQualities.scala | 6 +++--- .../sting/queue/util/{Utils.scala => QScriptUtils.scala} | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) rename public/scala/src/org/broadinstitute/sting/queue/util/{Utils.scala => QScriptUtils.scala} (98%) diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala index 40ac43a81..050604b4e 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala @@ -10,7 +10,7 @@ import org.broadinstitute.sting.queue.extensions.picard._ import net.sf.samtools.SAMFileReader import net.sf.samtools.SAMFileHeader.SortOrder -import org.broadinstitute.sting.queue.util.Utils +import org.broadinstitute.sting.queue.util.QScriptUtils class DataProcessingPipeline extends QScript { qscript => @@ -123,7 +123,7 @@ class DataProcessingPipeline extends QScript { // only allow one sample per file. Bam files with multiple samples would require pre-processing of the file // with PrintReads to separate the samples. Tell user to do it himself! - assert(!Utils.hasMultipleSamples(readGroups), "The pipeline requires that only one sample is present in a BAM file. Please separate the samples in " + bam) + assert(!QScriptUtils.hasMultipleSamples(readGroups), "The pipeline requires that only one sample is present in a BAM file. Please separate the samples in " + bam) // Fill out the sample table with the readgroups in this file for (rg <- readGroups) { @@ -200,8 +200,8 @@ class DataProcessingPipeline extends QScript { def script = { // keep a record of the number of contigs in the first bam file in the list - val bams = Utils.createListFromFile(input) - nContigs = Utils.getNumberOfContigs(bams(0)) + val bams = QScriptUtils.createListFromFile(input) + nContigs = QScriptUtils.getNumberOfContigs(bams(0)) val realignedBams = if (useBWApe || useBWAse) {performAlignment(bams)} else {bams} diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala index 8ba880291..56ca36925 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala @@ -2,7 +2,7 @@ package org.broadinstitute.sting.queue.qscripts import org.broadinstitute.sting.queue.QScript import org.broadinstitute.sting.queue.extensions.gatk._ -import org.broadinstitute.sting.queue.util.Utils +import org.broadinstitute.sting.queue.util.QScriptUtils /** * Created by IntelliJ IDEA. @@ -34,8 +34,8 @@ class RecalibrateBaseQualities extends QScript { def script = { - val bamList = Utils.createListFromFile(input) - nContigs = Utils.getNumberOfContigs(bamList(0)) + val bamList = QScriptUtils.createListFromFile(input) + nContigs = QScriptUtils.getNumberOfContigs(bamList(0)) for (bam <- bamList) { diff --git a/public/scala/src/org/broadinstitute/sting/queue/util/Utils.scala b/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala similarity index 98% rename from public/scala/src/org/broadinstitute/sting/queue/util/Utils.scala rename to public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala index 5b80503a3..e2f1f1608 100644 --- a/public/scala/src/org/broadinstitute/sting/queue/util/Utils.scala +++ b/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala @@ -15,7 +15,7 @@ import collection.JavaConversions._ * To change this template use File | Settings | File Templates. */ -object Utils { +object QScriptUtils { /** * Takes a bam list file and produces a scala list with each file allowing the bam list From 224d373997e0f4775207654ad4e246caad6c9aac Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Fri, 15 Jul 2011 15:19:10 -0400 Subject: [PATCH 56/83] No need to double overload the file constructor --- .../src/org/broadinstitute/sting/queue/util/QScriptUtils.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala b/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala index e2f1f1608..9fb4fa30d 100644 --- a/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala +++ b/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala @@ -38,7 +38,7 @@ object QScriptUtils { * Returns the number of contigs in the BAM file header. */ def getNumberOfContigs(bamFile: File): Int = { - val samReader = new SAMFileReader(new File(bamFile)) + val samReader = new SAMFileReader(bamFile) samReader.getFileHeader.getSequenceDictionary.getSequences.size() } From 72f4cf9c0ecbd8608d207ee59a5e5bd36a395be8 Mon Sep 17 00:00:00 2001 From: Menachem Fromer Date: Fri, 15 Jul 2011 17:44:31 -0400 Subject: [PATCH 67/83] Walker to perform deterministic annotation of phasing by transmission (to be compatible with RBP's definition of consecutive pairwise phasing) --- .../sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java index 1d9616aac..fbe6e5b5a 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/phasing/ReadBackedPhasingWalker.java @@ -242,7 +242,7 @@ public class ReadBackedPhasingWalker extends RodWalker KEYS_TO_KEEP_IN_REDUCED_VCF = new HashSet(Arrays.asList("PQ")); + private static final Set KEYS_TO_KEEP_IN_REDUCED_VCF = new HashSet(Arrays.asList(PQ_KEY)); private VariantContext reduceVCToSamples(VariantContext vc, List samplesToPhase) { // for ( String sample : samplesToPhase ) From 1e4798d5d0303df6b9cd42e9f7f2d30956004668 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Fri, 15 Jul 2011 19:34:14 -0400 Subject: [PATCH 70/83] Added targets to build.xml to re-run only tests that have failed (integration, unit, performance or pipeline tests). This is very useful and easy. After running any test (for example ant integrationtest) and seeing failures, you can rerun ONLY THE TESTS THAT FAILED by using one of the following commands: ant failed-integration ant failed-pipeline ant failed-test ant failed-performance obviously matching whatever tests you were running and got failures on. This should run only the failed tests, and you can keep using this command until you have fixed everything. (Thanks to David Roazen for major help with ANT) --- build.xml | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/build.xml b/build.xml index 986d89213..91eb1f8e9 100644 --- a/build.xml +++ b/build.xml @@ -785,6 +785,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -819,6 +863,22 @@ + + + + + + + + + + + + + + + + From fd1df31ef0ab60ec735ff5692132441224a02659 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Fri, 15 Jul 2011 19:39:42 -0400 Subject: [PATCH 71/83] changing the output directory names for Analyze Covariates --- .../sting/queue/qscripts/RecalibrateBaseQualities.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala index 56ca36925..fca420816 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/RecalibrateBaseQualities.scala @@ -42,8 +42,8 @@ class RecalibrateBaseQualities extends QScript { val recalFile1: File = swapExt(bam, ".bam", ".recal1.csv") val recalFile2: File = swapExt(bam, ".bam", ".recal2.csv") val recalBam: File = swapExt(bam, ".bam", ".recal.bam") - val path1: String = bam + "before" - val path2: String = bam + "after" + val path1: String = bam + ".before" + val path2: String = bam + ".after" add(cov(bam, recalFile1), recal(bam, recalFile1, recalBam), @@ -83,7 +83,7 @@ class RecalibrateBaseQualities extends QScript { case class analyzeCovariates (inRecalFile: File, outPath: String) extends AnalyzeCovariates { this.resources = R this.recal_file = inRecalFile - this.output_dir = outPath.toString + this.output_dir = outPath this.analysisName = queueLogDir + inRecalFile + ".analyze_covariates" this.jobName = queueLogDir + inRecalFile + ".analyze_covariates" } From ed55182a4c5553eb517569567e5193a12eb7e68a Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Sat, 16 Jul 2011 00:09:00 -0400 Subject: [PATCH 72/83] Removing Broad specific paths from parameters and making them required. This should make it unambiguous for people inside and outside the Broad to use the DataProcessingPipeline (as per request in the GetSatisfaction) --- .../qscripts/DataProcessingPipeline.scala | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala index 050604b4e..4d4499990 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala @@ -3,10 +3,11 @@ package org.broadinstitute.sting.queue.qscripts import org.broadinstitute.sting.queue.extensions.gatk._ import org.broadinstitute.sting.queue.QScript import org.broadinstitute.sting.queue.function.ListWriterFunction +import org.broadinstitute.sting.queue.extensions.picard._ +import org.broadinstitute.sting.gatk.walkers.indels.IndelRealigner.ConsensusDeterminationModel +import org.broadinstitute.sting.utils.baq.BAQ.CalculationMode import collection.JavaConversions._ -import org.broadinstitute.sting.gatk.walkers.indels.IndelRealigner.ConsensusDeterminationModel -import org.broadinstitute.sting.queue.extensions.picard._ import net.sf.samtools.SAMFileReader import net.sf.samtools.SAMFileHeader.SortOrder @@ -29,6 +30,11 @@ class DataProcessingPipeline extends QScript { @Input(doc="Reference fasta file", fullName="reference", shortName="R", required=true) var reference: File = _ + @Input(doc="dbsnp ROD to use (must be in VCF format)", fullName="dbsnp", shortName="D", required=true) + var dbSNP: File = _ + + @Input(doc="extra VCF files to use as reference indels for Indel Realignment", fullName="extra_indels", shortName="indels", required=true) + var indels: File = _ /**************************************************************************** @@ -42,12 +48,6 @@ class DataProcessingPipeline extends QScript { @Input(doc="The path to the binary of bwa (usually BAM files have already been mapped - but if you want to remap this is the option)", fullName="path_to_bwa", shortName="bwa", required=false) var bwaPath: File = _ - @Input(doc="dbsnp ROD to use (must be in VCF format)", fullName="dbsnp", shortName="D", required=false) - var dbSNP: File = new File("/humgen/gsa-hpprojects/GATK/data/dbsnp_132_b37.leftAligned.vcf") - - @Input(doc="extra VCF files to use as reference indels for Indel Realignment", fullName="extra_indels", shortName="indels", required=false) - var indels: File = new File("/humgen/gsa-hpprojects/GATK/data/Comparisons/Unvalidated/AFR+EUR+ASN+1KG.dindel_august_release_merged_pilot1.20110126.sites.vcf") - @Input(doc="the project name determines the final output (BAM file) base name. Example NA12878 yields NA12878.processed.bam", fullName="project", shortName="p", required=false) var projectName: String = "project" @@ -295,7 +295,7 @@ class DataProcessingPipeline extends QScript { this.targetIntervals = tIntervals this.out = outBam this.rodBind :+= RodBind("dbsnp", "VCF", dbSNP) - this.rodBind :+= RodBind("indels", "VCF", qscript.indels) + this.rodBind :+= RodBind("indels", "VCF", indels) this.consensusDeterminationModel = consensusDeterminationModel this.compress = 0 this.scatterCount = nContigs @@ -318,7 +318,7 @@ class DataProcessingPipeline extends QScript { case class recal (inBam: File, inRecalFile: File, outBam: File) extends TableRecalibration with CommandLineGATKArgs { this.input_file :+= inBam this.recal_file = inRecalFile - this.baq = org.broadinstitute.sting.utils.baq.BAQ.CalculationMode.CALCULATE_AS_NECESSARY + this.baq = CalculationMode.CALCULATE_AS_NECESSARY this.out = outBam if (!qscript.intervalString.isEmpty()) this.intervalsString ++= List(qscript.intervalString) else if (qscript.intervals != null) this.intervals :+= qscript.intervals From dd92a14b40b6270cf093b38830aab3987b8d0d25 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Sat, 16 Jul 2011 00:23:35 -0400 Subject: [PATCH 73/83] Made extra indel VCF optional but DBSNP mandatory. --- .../queue/qscripts/DataProcessingPipeline.scala | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala index 4d4499990..d55b86d69 100755 --- a/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala +++ b/public/scala/qscript/org/broadinstitute/sting/queue/qscripts/DataProcessingPipeline.scala @@ -33,10 +33,6 @@ class DataProcessingPipeline extends QScript { @Input(doc="dbsnp ROD to use (must be in VCF format)", fullName="dbsnp", shortName="D", required=true) var dbSNP: File = _ - @Input(doc="extra VCF files to use as reference indels for Indel Realignment", fullName="extra_indels", shortName="indels", required=true) - var indels: File = _ - - /**************************************************************************** * Optional Parameters ****************************************************************************/ @@ -45,6 +41,10 @@ class DataProcessingPipeline extends QScript { // @Input(doc="path to Picard's SortSam.jar (if re-aligning a previously processed BAM file)", fullName="path_to_sort_jar", shortName="sort", required=false) // var sortSamJar: File = _ // + + @Input(doc="extra VCF files to use as reference indels for Indel Realignment", fullName="extra_indels", shortName="indels", required=false) + var indels: File = _ + @Input(doc="The path to the binary of bwa (usually BAM files have already been mapped - but if you want to remap this is the option)", fullName="path_to_bwa", shortName="bwa", required=false) var bwaPath: File = _ @@ -284,7 +284,8 @@ class DataProcessingPipeline extends QScript { this.out = outIntervals this.mismatchFraction = 0.0 this.rodBind :+= RodBind("dbsnp", "VCF", dbSNP) - this.rodBind :+= RodBind("indels", "VCF", indels) + if (!indels.isEmpty) + this.rodBind :+= RodBind("indels", "VCF", indels) this.scatterCount = nContigs this.analysisName = queueLogDir + outIntervals + ".target" this.jobName = queueLogDir + outIntervals + ".target" @@ -295,7 +296,8 @@ class DataProcessingPipeline extends QScript { this.targetIntervals = tIntervals this.out = outBam this.rodBind :+= RodBind("dbsnp", "VCF", dbSNP) - this.rodBind :+= RodBind("indels", "VCF", indels) + if (!indels.isEmpty) + this.rodBind :+= RodBind("indels", "VCF", indels) this.consensusDeterminationModel = consensusDeterminationModel this.compress = 0 this.scatterCount = nContigs From 5e7bc862a34d7366c168209261ea5aedb812c790 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Sat, 16 Jul 2011 08:51:21 -0400 Subject: [PATCH 74/83] Rev tribble to include new equal() method that prints out details of why two indices are not the same. --- .../{tribble-3.jar => tribble-4.jar} | Bin 258609 -> 286423 bytes .../{tribble-3.xml => tribble-4.xml} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename settings/repository/org.broad/{tribble-3.jar => tribble-4.jar} (69%) rename settings/repository/org.broad/{tribble-3.xml => tribble-4.xml} (58%) diff --git a/settings/repository/org.broad/tribble-3.jar b/settings/repository/org.broad/tribble-4.jar similarity index 69% rename from settings/repository/org.broad/tribble-3.jar rename to settings/repository/org.broad/tribble-4.jar index f0ab44a05fb969693b20757be8d29b18f3b611a6..1f82f3cc05b8f02f117506269a8b96110cff591a 100644 GIT binary patch delta 50001 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 diff --git a/settings/repository/org.broad/tribble-3.xml b/settings/repository/org.broad/tribble-4.xml similarity index 58% rename from settings/repository/org.broad/tribble-3.xml rename to settings/repository/org.broad/tribble-4.xml index c35358331..07235efb0 100644 --- a/settings/repository/org.broad/tribble-3.xml +++ b/settings/repository/org.broad/tribble-4.xml @@ -1,4 +1,4 @@ - From eacf205f4079e55ed03dd248cbb8c1a41491c01e Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Sat, 16 Jul 2011 09:22:34 -0400 Subject: [PATCH 76/83] Tests needed to be updated to reflect the code reorg of tribble. --- .../org/broadinstitute/sting/WalkerTest.java | 21 +++++++++++-------- .../codecs/vcf/IndexFactoryUnitTest.java | 3 ++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/public/java/test/org/broadinstitute/sting/WalkerTest.java b/public/java/test/org/broadinstitute/sting/WalkerTest.java index d65f4ec34..a39fa37fe 100755 --- a/public/java/test/org/broadinstitute/sting/WalkerTest.java +++ b/public/java/test/org/broadinstitute/sting/WalkerTest.java @@ -65,19 +65,22 @@ public class WalkerTest extends BaseTest { throw new StingException("Found an index created for file " + resultFile + " but we can only validate VCF files. Extend this code!"); } - System.out.println("Verifying on-the-fly index " + indexFile + " for test " + name + " using file " + resultFile); - Index indexFromOutputFile = IndexFactory.createIndex(resultFile, new VCFCodec()); - Index dynamicIndex = IndexFactory.loadIndex(indexFile.getAbsolutePath()); - - if ( ! indexFromOutputFile.equals(dynamicIndex) ) { - Assert.fail(String.format("Index on disk from indexing on the fly not equal to the index created after the run completed. FileIndex %s vs. on-the-fly %s%n", - indexFromOutputFile.getProperties(), - dynamicIndex.getProperties())); - } + assertOnDiskIndexEqualToNewlyCreatedIndex(indexFile, name, resultFile); } } + public static void assertOnDiskIndexEqualToNewlyCreatedIndex(final File indexFile, final String name, final File resultFile) { + System.out.println("Verifying on-the-fly index " + indexFile + " for test " + name + " using file " + resultFile); + Index indexFromOutputFile = IndexFactory.createIndex(resultFile, new VCFCodec()); + Index dynamicIndex = IndexFactory.loadIndex(indexFile.getAbsolutePath()); + + if ( ! indexFromOutputFile.equals(dynamicIndex) ) { + Assert.fail(String.format("Index on disk from indexing on the fly not equal to the index created after the run completed. FileIndex %s vs. on-the-fly %s%n", + indexFromOutputFile.getProperties(), + dynamicIndex.getProperties())); + } + } public List assertMatchingMD5s(final String name, List resultFiles, List expectedMD5s) { List md5s = new ArrayList(); diff --git a/public/java/test/org/broadinstitute/sting/utils/codecs/vcf/IndexFactoryUnitTest.java b/public/java/test/org/broadinstitute/sting/utils/codecs/vcf/IndexFactoryUnitTest.java index 2f6b589f4..68a2ecf8d 100755 --- a/public/java/test/org/broadinstitute/sting/utils/codecs/vcf/IndexFactoryUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/utils/codecs/vcf/IndexFactoryUnitTest.java @@ -4,6 +4,7 @@ import org.broad.tribble.Tribble; import org.broad.tribble.index.*; import org.broad.tribble.iterators.CloseableTribbleIterator; import org.broad.tribble.source.BasicFeatureSource; +import org.broadinstitute.sting.WalkerTest; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.testng.Assert; import org.testng.annotations.Test; @@ -75,7 +76,7 @@ public class IndexFactoryUnitTest { // test that the input index is the same as the one created from the identical input file // test that the dynamic index is the same as the output index, which is equal to the input index - Assert.assertTrue(IndexFactory.onDiskIndexEqualToNewlyCreatedIndex(outputFile, outputFileIndex, new VCFCodec())); + WalkerTest.assertOnDiskIndexEqualToNewlyCreatedIndex(outputFileIndex, "unittest", outputFile); } } } From 07b875c7796972eff2c56c662f198821a5c4e659 Mon Sep 17 00:00:00 2001 From: David Roazen Date: Sat, 16 Jul 2011 09:57:46 -0400 Subject: [PATCH 77/83] Renaming the updated tribble jar file to match the svn revision number. --- .../org.broad/{tribble-4.jar => tribble-14.jar} | Bin .../org.broad/{tribble-4.xml => tribble-14.xml} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename settings/repository/org.broad/{tribble-4.jar => tribble-14.jar} (100%) rename settings/repository/org.broad/{tribble-4.xml => tribble-14.xml} (57%) diff --git a/settings/repository/org.broad/tribble-4.jar b/settings/repository/org.broad/tribble-14.jar similarity index 100% rename from settings/repository/org.broad/tribble-4.jar rename to settings/repository/org.broad/tribble-14.jar diff --git a/settings/repository/org.broad/tribble-4.xml b/settings/repository/org.broad/tribble-14.xml similarity index 57% rename from settings/repository/org.broad/tribble-4.xml rename to settings/repository/org.broad/tribble-14.xml index 07235efb0..f2116324a 100644 --- a/settings/repository/org.broad/tribble-4.xml +++ b/settings/repository/org.broad/tribble-14.xml @@ -1,4 +1,4 @@ - From 2b55d5b7c0dfca0abd09ab810206d5a437d598ec Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Sat, 16 Jul 2011 16:45:55 -0400 Subject: [PATCH 78/83] Test tribble library where equals() ignores time stamps. --- settings/repository/org.broad/tribble-14.jar | Bin 286423 -> 286358 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/settings/repository/org.broad/tribble-14.jar b/settings/repository/org.broad/tribble-14.jar index 1f82f3cc05b8f02f117506269a8b96110cff591a..a0313df326217a5b1820cd7e7d6c029c8129e326 100644 GIT binary patch delta 6171 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 delta 6319 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 Date: Sun, 17 Jul 2011 10:14:23 -0400 Subject: [PATCH 79/83] Moved the varianteval/tags/DataPoint.java and varianteval/tags/Analysis.java to varianteval/utils. This allows rsync to see these files with the -C option, as tags is some kind of reserved CVS keyword. --- .../gatk/walkers/varianteval/VariantEvalWalker.java | 5 ++--- .../walkers/varianteval/evaluators/CompOverlap.java | 4 ++-- .../walkers/varianteval/evaluators/CountVariants.java | 4 ++-- .../varianteval/evaluators/GenotypeConcordance.java | 4 ++-- .../evaluators/GenotypePhasingEvaluator.java | 7 +++---- .../varianteval/evaluators/IndelLengthHistogram.java | 4 ++-- .../varianteval/evaluators/IndelMetricsByAC.java | 4 ++-- .../varianteval/evaluators/IndelStatistics.java | 4 ++-- .../evaluators/MendelianViolationEvaluator.java | 10 ++-------- .../varianteval/evaluators/PrintMissingComp.java | 4 ++-- .../varianteval/evaluators/SimpleMetricsByAC.java | 7 +++---- .../varianteval/evaluators/ThetaVariantEvaluator.java | 4 ++-- .../varianteval/evaluators/TiTvVariantEvaluator.java | 4 ++-- .../varianteval/evaluators/ValidationReport.java | 5 ++--- .../varianteval/evaluators/VariantQualityScore.java | 4 ++-- .../walkers/varianteval/{tags => util}/Analysis.java | 2 +- .../varianteval/util/AnalysisModuleScanner.java | 2 -- .../walkers/varianteval/{tags => util}/DataPoint.java | 2 +- .../walkers/varianteval/util/VariantEvalUtils.java | 3 --- 19 files changed, 34 insertions(+), 49 deletions(-) rename public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/{tags => util}/Analysis.java (80%) rename public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/{tags => util}/DataPoint.java (77%) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/VariantEvalWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/VariantEvalWalker.java index 15d808ebe..c9c5e09a8 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/VariantEvalWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/VariantEvalWalker.java @@ -20,7 +20,7 @@ import org.broadinstitute.sting.gatk.walkers.TreeReducible; import org.broadinstitute.sting.gatk.walkers.Window; import org.broadinstitute.sting.gatk.walkers.varianteval.evaluators.VariantEvaluator; import org.broadinstitute.sting.gatk.walkers.varianteval.stratifications.VariantStratifier; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.gatk.walkers.varianteval.util.*; import org.broadinstitute.sting.gatk.walkers.variantrecalibration.Tranche; import org.broadinstitute.sting.gatk.walkers.variantrecalibration.VariantRecalibrator; @@ -30,10 +30,9 @@ import org.broadinstitute.sting.utils.exceptions.StingException; import org.broadinstitute.sting.utils.exceptions.UserException; import org.broadinstitute.sting.gatk.walkers.varianteval.util.TableType; import org.broadinstitute.sting.utils.codecs.vcf.VCFUtils; -import net.sf.picard.reference.FastaSequenceFile; import net.sf.picard.reference.IndexedFastaSequenceFile; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; -import net.sf.picard.reference.ReferenceSequence; + import java.io.FileNotFoundException; import java.io.File; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/CompOverlap.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/CompOverlap.java index 76db330ed..85373baa8 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/CompOverlap.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/CompOverlap.java @@ -1,12 +1,12 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.Allele; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; /** * The Broad Institute diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/CountVariants.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/CountVariants.java index c4277adc9..befb2ff13 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/CountVariants.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/CountVariants.java @@ -1,12 +1,12 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; @Analysis(description = "Counts different classes of variants in the sample") diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/GenotypeConcordance.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/GenotypeConcordance.java index 4b56cf130..58803c9d0 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/GenotypeConcordance.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/GenotypeConcordance.java @@ -1,14 +1,14 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; import org.apache.log4j.Logger; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.utils.codecs.vcf.VCFConstants; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; import org.broadinstitute.sting.utils.exceptions.StingException; import org.broadinstitute.sting.utils.exceptions.UserException; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/GenotypePhasingEvaluator.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/GenotypePhasingEvaluator.java index 3d14dd0e5..407b71893 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/GenotypePhasingEvaluator.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/GenotypePhasingEvaluator.java @@ -1,6 +1,7 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; import org.apache.log4j.Logger; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.*; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; @@ -9,10 +10,8 @@ import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.walkers.phasing.AllelePair; import org.broadinstitute.sting.gatk.walkers.phasing.ReadBackedPhasingWalker; import org.broadinstitute.sting.gatk.walkers.varianteval.VariantEvalWalker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; -import org.broadinstitute.sting.gatk.walkers.varianteval.util.NewEvaluationContext; -import org.broadinstitute.sting.gatk.walkers.varianteval.util.TableType; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.GenomeLoc; import org.broadinstitute.sting.utils.MathUtils; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelLengthHistogram.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelLengthHistogram.java index 5daf33a9f..f7f9fce0c 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelLengthHistogram.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelLengthHistogram.java @@ -1,11 +1,11 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; import org.broadinstitute.sting.gatk.walkers.varianteval.util.TableType; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelMetricsByAC.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelMetricsByAC.java index eca6c5193..dd4bb492e 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelMetricsByAC.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelMetricsByAC.java @@ -1,12 +1,12 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.walkers.varianteval.VariantEvalWalker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.gatk.walkers.varianteval.util.TableType; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelStatistics.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelStatistics.java index 48b06d532..1bd420e0a 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelStatistics.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/IndelStatistics.java @@ -1,13 +1,13 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.walkers.varianteval.VariantEvalWalker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.gatk.walkers.varianteval.util.TableType; import org.broadinstitute.sting.utils.IndelUtils; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/MendelianViolationEvaluator.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/MendelianViolationEvaluator.java index 85e0b5889..16ec74433 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/MendelianViolationEvaluator.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/MendelianViolationEvaluator.java @@ -1,22 +1,16 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; -import org.broadinstitute.sting.utils.variantcontext.Allele; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.walkers.varianteval.VariantEvalWalker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.utils.MendelianViolation; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * Mendelian violation detection and counting *

diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/PrintMissingComp.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/PrintMissingComp.java index 7d54d0df8..e83914ef8 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/PrintMissingComp.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/PrintMissingComp.java @@ -24,12 +24,12 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; @Analysis(name = "PrintMissingComp", description = "the overlap between eval and comp sites") public class PrintMissingComp extends VariantEvaluator { diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/SimpleMetricsByAC.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/SimpleMetricsByAC.java index deed05508..395309975 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/SimpleMetricsByAC.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/SimpleMetricsByAC.java @@ -1,5 +1,6 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.*; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; @@ -8,11 +9,9 @@ import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.walkers.varianteval.VariantEvalWalker; import org.broadinstitute.sting.gatk.walkers.varianteval.stratifications.Degeneracy; import org.broadinstitute.sting.gatk.walkers.varianteval.stratifications.Sample; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; -import org.broadinstitute.sting.gatk.walkers.varianteval.util.StateKey; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; -import org.broadinstitute.sting.gatk.walkers.varianteval.util.TableType; import java.util.ArrayList; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/ThetaVariantEvaluator.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/ThetaVariantEvaluator.java index 89c67cfe9..f9cda5e0b 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/ThetaVariantEvaluator.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/ThetaVariantEvaluator.java @@ -1,13 +1,13 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.Allele; import org.broadinstitute.sting.utils.variantcontext.Genotype; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/TiTvVariantEvaluator.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/TiTvVariantEvaluator.java index 8811dc001..deeafd851 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/TiTvVariantEvaluator.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/TiTvVariantEvaluator.java @@ -1,12 +1,12 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.utils.variantcontext.VariantContextUtils; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.utils.BaseUtils; @Analysis(description = "Ti/Tv Variant Evaluator") diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/ValidationReport.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/ValidationReport.java index 405f35635..756427581 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/ValidationReport.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/ValidationReport.java @@ -1,14 +1,13 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.Allele; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.utils.codecs.vcf.VCFConstants; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; -import org.broadinstitute.sting.utils.variantcontext.VariantContextUtils; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; import java.util.*; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/VariantQualityScore.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/VariantQualityScore.java index 4af14810b..29a61e27a 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/VariantQualityScore.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/evaluators/VariantQualityScore.java @@ -25,14 +25,14 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.evaluators; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.Analysis; +import org.broadinstitute.sting.gatk.walkers.varianteval.util.DataPoint; import org.broadinstitute.sting.utils.variantcontext.Allele; import org.broadinstitute.sting.utils.variantcontext.VariantContext; import org.broadinstitute.sting.gatk.contexts.AlignmentContext; import org.broadinstitute.sting.gatk.contexts.ReferenceContext; import org.broadinstitute.sting.utils.variantcontext.VariantContextUtils; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.gatk.walkers.varianteval.util.TableType; import org.broadinstitute.sting.utils.collections.Pair; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/tags/Analysis.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/Analysis.java similarity index 80% rename from public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/tags/Analysis.java rename to public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/Analysis.java index 129d5a95d..2b37ce210 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/tags/Analysis.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/Analysis.java @@ -1,4 +1,4 @@ -package org.broadinstitute.sting.gatk.walkers.varianteval.tags; +package org.broadinstitute.sting.gatk.walkers.varianteval.util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/AnalysisModuleScanner.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/AnalysisModuleScanner.java index c8d917040..db44e9e28 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/AnalysisModuleScanner.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/AnalysisModuleScanner.java @@ -23,8 +23,6 @@ package org.broadinstitute.sting.gatk.walkers.varianteval.util; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.utils.exceptions.ReviewedStingException; import java.lang.annotation.Annotation; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/tags/DataPoint.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/DataPoint.java similarity index 77% rename from public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/tags/DataPoint.java rename to public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/DataPoint.java index 3ba448049..396843252 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/tags/DataPoint.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/DataPoint.java @@ -1,4 +1,4 @@ -package org.broadinstitute.sting.gatk.walkers.varianteval.tags; +package org.broadinstitute.sting.gatk.walkers.varianteval.util; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/VariantEvalUtils.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/VariantEvalUtils.java index b8e45e462..eabd2e588 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/VariantEvalUtils.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/varianteval/util/VariantEvalUtils.java @@ -7,15 +7,12 @@ import org.broadinstitute.sting.utils.variantcontext.VariantContextUtils; import org.broadinstitute.sting.gatk.refdata.RefMetaDataTracker; import org.broadinstitute.sting.gatk.report.GATKReport; import org.broadinstitute.sting.gatk.report.GATKReportTable; -import org.broadinstitute.sting.gatk.walkers.Walker; import org.broadinstitute.sting.gatk.walkers.varianteval.VariantEvalWalker; import org.broadinstitute.sting.gatk.walkers.varianteval.evaluators.StandardEval; import org.broadinstitute.sting.gatk.walkers.varianteval.evaluators.VariantEvaluator; import org.broadinstitute.sting.gatk.walkers.varianteval.stratifications.RequiredStratification; import org.broadinstitute.sting.gatk.walkers.varianteval.stratifications.StandardStratification; import org.broadinstitute.sting.gatk.walkers.varianteval.stratifications.VariantStratifier; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.Analysis; -import org.broadinstitute.sting.gatk.walkers.varianteval.tags.DataPoint; import org.broadinstitute.sting.utils.classloader.PluginManager; import org.broadinstitute.sting.utils.exceptions.StingException; import org.broadinstitute.sting.utils.exceptions.UserException; From a5bfcb1ed9f4ee0f5a94a744bd9e31bbd8d254a2 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Sun, 17 Jul 2011 10:25:34 -0400 Subject: [PATCH 80/83] V15 is broken. Going up to v16 in a second. --- .../{tribble-14.jar => tribble-15.jar} | Bin 286358 -> 286159 bytes .../{tribble-14.xml => tribble-15.xml} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename settings/repository/org.broad/{tribble-14.jar => tribble-15.jar} (89%) rename settings/repository/org.broad/{tribble-14.xml => tribble-15.xml} (59%) diff --git a/settings/repository/org.broad/tribble-14.jar b/settings/repository/org.broad/tribble-15.jar similarity index 89% rename from settings/repository/org.broad/tribble-14.jar rename to settings/repository/org.broad/tribble-15.jar index a0313df326217a5b1820cd7e7d6c029c8129e326..4e89047f49d774453a2ae61d036a21a7d4270d09 100644 GIT binary patch delta 12091 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 RVUZBM%8lWU30VjS{ePbyo$&ww delta 12360 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 z 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 diff --git a/settings/repository/org.broad/tribble-14.xml b/settings/repository/org.broad/tribble-15.xml similarity index 59% rename from settings/repository/org.broad/tribble-14.xml rename to settings/repository/org.broad/tribble-15.xml index f2116324a..e23eec339 100644 --- a/settings/repository/org.broad/tribble-14.xml +++ b/settings/repository/org.broad/tribble-15.xml @@ -1,4 +1,4 @@ - From 1af76736b9dc41da345df90648ec5d74ade03f70 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Sun, 17 Jul 2011 11:41:34 -0400 Subject: [PATCH 81/83] Guarantees that the list of files will always be in the same order. --- .../src/org/broadinstitute/sting/queue/util/QScriptUtils.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala b/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala index 9fb4fa30d..99aaa9474 100644 --- a/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala +++ b/public/scala/src/org/broadinstitute/sting/queue/util/QScriptUtils.scala @@ -31,7 +31,7 @@ object QScriptUtils { for (bam <- fromFile(in).getLines) if (!bam.startsWith("#") && !bam.isEmpty ) list :+= new File(bam.trim()) - list + list.sortWith(_.compareTo(_) < 0) } /** From 4db2b13e9ebd54f832d05f885d7ec8946118fb70 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Sun, 17 Jul 2011 13:05:04 -0400 Subject: [PATCH 82/83] Rev tribble. Just added more documentation for diffEngine and pointer to new wiki: http://www.broadinstitute.org/gsa/wiki/index.php/DiffEngine --- .../gatk/walkers/diffengine/DiffEngine.java | 2 +- .../walkers/diffengine/DiffableReader.java | 15 +++++++++++++++ .../org/broadinstitute/sting/WalkerTest.java | 2 +- settings/repository/org.broad/tribble-15.jar | Bin 286159 -> 0 bytes .../{tribble-15.xml => tribble-16.xml} | 0 5 files changed, 17 insertions(+), 2 deletions(-) delete mode 100644 settings/repository/org.broad/tribble-15.jar rename settings/repository/org.broad/{tribble-15.xml => tribble-16.xml} (100%) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java index 6d85df71d..2f87a900a 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffEngine.java @@ -209,7 +209,7 @@ public class DiffEngine { protected void printSummaryReport(List sortedSummaries, SummaryReportParams params ) { GATKReport report = new GATKReport(); final String tableName = "diffences"; - report.addTable(tableName, "Summarized differences between the master and test files.\nSee http://www.broadinstitute.org/gsa/wiki/index.php/DiffObjectsWalker_and_SummarizedDifferences for more information"); + report.addTable(tableName, "Summarized differences between the master and test files.\nSee http://www.broadinstitute.org/gsa/wiki/index.php/DiffEngine for more information"); GATKReportTable table = report.getTable(tableName); table.addPrimaryKey("Difference", true); table.addColumn("NumberOfOccurrences", 0); diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java index af5771c55..a117206f1 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/diffengine/DiffableReader.java @@ -39,12 +39,27 @@ import java.io.File; */ public interface DiffableReader { @Ensures("result != null") + /** + * Return the name of this DiffableReader type. For example, the VCF reader returns 'VCF' and the + * bam reader 'BAM' + */ public String getName(); @Ensures("result != null") @Requires("file != null") + /** + * Read up to maxElementsToRead DiffElements from file, and return them. + */ public DiffElement readFromFile(File file, int maxElementsToRead); + /** + * Return true if the file can be read into DiffElement objects with this reader. This should + * be uniquely true/false for all readers, as the system will use the first reader that can read the + * file. This routine should never throw an exception. The VCF reader, for example, looks at the + * first line of the file for the ##format=VCF4.1 header, and the BAM reader for the BAM_MAGIC value + * @param file + * @return + */ @Requires("file != null") public boolean canRead(File file); } diff --git a/public/java/test/org/broadinstitute/sting/WalkerTest.java b/public/java/test/org/broadinstitute/sting/WalkerTest.java index a39fa37fe..22635dfa3 100755 --- a/public/java/test/org/broadinstitute/sting/WalkerTest.java +++ b/public/java/test/org/broadinstitute/sting/WalkerTest.java @@ -75,7 +75,7 @@ public class WalkerTest extends BaseTest { Index indexFromOutputFile = IndexFactory.createIndex(resultFile, new VCFCodec()); Index dynamicIndex = IndexFactory.loadIndex(indexFile.getAbsolutePath()); - if ( ! indexFromOutputFile.equals(dynamicIndex) ) { + if ( ! indexFromOutputFile.equalsIgnoreTimestamp(dynamicIndex) ) { Assert.fail(String.format("Index on disk from indexing on the fly not equal to the index created after the run completed. FileIndex %s vs. on-the-fly %s%n", indexFromOutputFile.getProperties(), dynamicIndex.getProperties())); diff --git a/settings/repository/org.broad/tribble-15.jar b/settings/repository/org.broad/tribble-15.jar deleted file mode 100644 index 4e89047f49d774453a2ae61d036a21a7d4270d09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286159 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 diff --git a/settings/repository/org.broad/tribble-15.xml b/settings/repository/org.broad/tribble-16.xml similarity index 100% rename from settings/repository/org.broad/tribble-15.xml rename to settings/repository/org.broad/tribble-16.xml From 35ec82a467b3e739c98bc700c4765d9f0a0be17a Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Sun, 17 Jul 2011 13:08:08 -0400 Subject: [PATCH 83/83] Oops, need this --- settings/repository/org.broad/tribble-16.jar | Bin 0 -> 286215 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 settings/repository/org.broad/tribble-16.jar diff --git a/settings/repository/org.broad/tribble-16.jar b/settings/repository/org.broad/tribble-16.jar new file mode 100644 index 0000000000000000000000000000000000000000..331f28ec34a8d1b63d30a02cd396595e3abe6353 GIT binary patch literal 286215 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 literal 0 HcmV?d00001