diff --git a/src/main/java/org/broadinstitute/hellbender/tools/sv/concordance/SVConcordanceAnnotator.java b/src/main/java/org/broadinstitute/hellbender/tools/sv/concordance/SVConcordanceAnnotator.java index 222cf91099f..930da02fdfb 100644 --- a/src/main/java/org/broadinstitute/hellbender/tools/sv/concordance/SVConcordanceAnnotator.java +++ b/src/main/java/org/broadinstitute/hellbender/tools/sv/concordance/SVConcordanceAnnotator.java @@ -27,13 +27,21 @@ public class SVConcordanceAnnotator { protected final Logger logger = LogManager.getLogger(this.getClass()); private final GenotypeConcordanceScheme scheme; - final boolean useTruthAf; + private final Set samples; /** - * @param useTruthAf annotate truth allele counts using original truth record attributes (AF/AC/AN) + * Default constructor where all eval record samples will be used for concordance. */ - public SVConcordanceAnnotator(final boolean useTruthAf) { - this.useTruthAf = useTruthAf; + public SVConcordanceAnnotator() { + this(null); + } + + /** + * Annotator restricted to specific samples. + * @param samples samples to include for concordance computations. If null, all samples in eval records will be used. + */ + public SVConcordanceAnnotator(final Set samples) { + this.samples = samples; this.scheme = new SVGenotypeConcordanceScheme(); } @@ -48,23 +56,26 @@ public SVCallRecord annotate(final ClosestSVFinder.ClosestPair pair) { final ArrayList newGenotypes = new ArrayList<>(evalGenotypes.size()); final GenotypeConcordanceCounts counts = new GenotypeConcordanceCounts(); final boolean isCnv = evalRecord.getType() == GATKSVVCFConstants.StructuralVariantAnnotationType.CNV; - Integer numCnvMatches = 0; + int numCnvMatches = 0; + int numValidCnvComparisons = 0; for (final String sample : evalGenotypes.getSampleNames()) { GenotypeBuilder builder = new GenotypeBuilder(evalGenotypes.get(sample)); - if (isCnv) { - final Boolean result = cnvGenotypesMatch(sample, evalRecord, truthRecord); - builder = builder.attribute(GATKSVVCFConstants.TRUTH_CN_EQUAL_FORMAT, result == null ? null : result.booleanValue() ? 1 : 0); - if (result == null) { - // Null this metric if we encounter any null results - numCnvMatches = null; - } else if (numCnvMatches != null && result.booleanValue()) { - numCnvMatches++; + if (samples == null || samples.contains(sample)) { + if (isCnv) { + final Boolean result = copyNumbersMatch(sample, evalRecord, truthRecord); + builder = builder.attribute(GATKSVVCFConstants.TRUTH_CN_EQUAL_FORMAT, result == null ? null : result.booleanValue() ? 1 : 0); + if (result != null) { + numValidCnvComparisons++; + if (result.booleanValue()) { + numCnvMatches++; + } + } + } else { + final GenotypeConcordanceStates.TruthAndCallStates states = getStates(sample, evalRecord, truthRecord); + counts.increment(states); + builder = builder.attribute(GenotypeConcordance.CONTINGENCY_STATE_TAG, + scheme.getContingencyStateString(states.truthState, states.callState)); } - } else { - final GenotypeConcordanceStates.TruthAndCallStates states = getStates(sample, evalRecord, truthRecord); - counts.increment(states); - builder = builder.attribute(GenotypeConcordance.CONTINGENCY_STATE_TAG, - scheme.getContingencyStateString(states.truthState, states.callState)); } newGenotypes.add(builder.make()); } @@ -76,54 +87,66 @@ public SVCallRecord annotate(final ClosestSVFinder.ClosestPair pair) { attributes.put(Concordance.TRUTH_STATUS_VCF_ATTRIBUTE, variantStatus.getAbbreviation()); if (isCnv) { - final Double cnvConcordance = numCnvMatches == null ? null : newGenotypes.isEmpty() ? Double.NaN : numCnvMatches / (double) newGenotypes.size(); + final Double cnvConcordance = numValidCnvComparisons == 0 ? null : numCnvMatches / (double) numValidCnvComparisons; attributes.put(GATKSVVCFConstants.COPY_NUMBER_CONCORDANCE_INFO, cnvConcordance); } else if (truthRecord != null) { final GenotypeConcordanceSummaryMetrics metrics = new GenotypeConcordanceSummaryMetrics(VariantContext.Type.SYMBOLIC, counts, "truth", "eval", true); - attributes.put(GATKSVVCFConstants.GENOTYPE_CONCORDANCE_INFO, metrics.GENOTYPE_CONCORDANCE); - attributes.put(GATKSVVCFConstants.NON_REF_GENOTYPE_CONCORDANCE_INFO, metrics.NON_REF_GENOTYPE_CONCORDANCE); - attributes.put(GATKSVVCFConstants.HET_PPV_INFO, metrics.HET_PPV); - attributes.put(GATKSVVCFConstants.HET_SENSITIVITY_INFO, metrics.HET_SENSITIVITY); - attributes.put(GATKSVVCFConstants.HOMVAR_PPV_INFO, metrics.HOMVAR_PPV); - attributes.put(GATKSVVCFConstants.HOMVAR_SENSITIVITY_INFO, metrics.HOMVAR_SENSITIVITY); - attributes.put(GATKSVVCFConstants.VAR_PPV_INFO, metrics.VAR_PPV); - attributes.put(GATKSVVCFConstants.VAR_SENSITIVITY_INFO, metrics.VAR_SENSITIVITY); - attributes.put(GATKSVVCFConstants.VAR_SPECIFICITY_INFO, metrics.VAR_SPECIFICITY); + attributes.put(GATKSVVCFConstants.GENOTYPE_CONCORDANCE_INFO, Double.isNaN(metrics.GENOTYPE_CONCORDANCE) ? null : metrics.GENOTYPE_CONCORDANCE); + attributes.put(GATKSVVCFConstants.NON_REF_GENOTYPE_CONCORDANCE_INFO, Double.isNaN(metrics.NON_REF_GENOTYPE_CONCORDANCE) ? null : metrics.NON_REF_GENOTYPE_CONCORDANCE); + attributes.put(GATKSVVCFConstants.HET_PPV_INFO, Double.isNaN(metrics.HET_PPV) ? null : metrics.HET_PPV); + attributes.put(GATKSVVCFConstants.HET_SENSITIVITY_INFO, Double.isNaN(metrics.HET_SENSITIVITY) ? null : metrics.HET_SENSITIVITY); + attributes.put(GATKSVVCFConstants.HOMVAR_PPV_INFO, Double.isNaN(metrics.HOMVAR_PPV) ? null : metrics.HOMVAR_PPV); + attributes.put(GATKSVVCFConstants.HOMVAR_SENSITIVITY_INFO, Double.isNaN(metrics.HOMVAR_SENSITIVITY) ? null : metrics.HOMVAR_SENSITIVITY); + attributes.put(GATKSVVCFConstants.VAR_PPV_INFO, Double.isNaN(metrics.VAR_PPV) ? null : metrics.VAR_PPV); + attributes.put(GATKSVVCFConstants.VAR_SENSITIVITY_INFO, Double.isNaN(metrics.VAR_SENSITIVITY) ? null : metrics.VAR_SENSITIVITY); + attributes.put(GATKSVVCFConstants.VAR_SPECIFICITY_INFO, Double.isNaN(metrics.VAR_SPECIFICITY) ? null : metrics.VAR_SPECIFICITY); } if (evalRecord.getType() != GATKSVVCFConstants.StructuralVariantAnnotationType.CNV) { - // Compute allele frequency in eval - final SVAlleleCounter counter = new SVAlleleCounter(evalRecord.getAltAlleles(), evalRecord.getGenotypes()); - attributes.put(VCFConstants.ALLELE_COUNT_KEY, counter.getCounts()); - attributes.put(VCFConstants.ALLELE_FREQUENCY_KEY, counter.getFrequencies()); - attributes.put(VCFConstants.ALLELE_NUMBER_KEY, counter.getNumber()); + if (!evalRecord.getAllSamples().isEmpty() && !hasAlleleFrequencyAnnotations(evalRecord)) { + // Compute allele frequency in eval + final SVAlleleCounter counter = new SVAlleleCounter(evalRecord.getAltAlleles(), evalRecord.getGenotypes()); + attributes.put(VCFConstants.ALLELE_COUNT_KEY, counter.getCounts()); + attributes.put(VCFConstants.ALLELE_FREQUENCY_KEY, counter.getFrequencies()); + attributes.put(VCFConstants.ALLELE_NUMBER_KEY, counter.getNumber()); + } // Add in truth AF if (truthRecord == null) { attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO, null); attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO, null); attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO, null); - } else if (useTruthAf) { - // Use AF - final Map truthAttr = truthRecord.getAttributes(); - attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO, - truthAttr.get(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO)); - attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO, - truthAttr.get(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO)); - attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO, - truthAttr.get(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO)); } else { - // Calculate truth AF - final SVAlleleCounter truthCounter = new SVAlleleCounter(evalRecord.getAltAlleles(), truthRecord.getGenotypes()); - attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO, truthCounter.getCounts()); - attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO, truthCounter.getFrequencies()); - attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO, truthCounter.getNumber()); + if (hasAlleleFrequencyAnnotations(truthRecord)) { + // Use AF + final Map truthAttr = truthRecord.getAttributes(); + attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO, + truthAttr.get(VCFConstants.ALLELE_COUNT_KEY)); + attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO, + truthAttr.get(VCFConstants.ALLELE_FREQUENCY_KEY)); + attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO, + truthAttr.get(VCFConstants.ALLELE_NUMBER_KEY)); + } else { + // Calculate truth AF + final SVAlleleCounter truthCounter = new SVAlleleCounter(evalRecord.getAltAlleles(), truthRecord.getGenotypes()); + attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO, truthCounter.getCounts()); + attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO, truthCounter.getFrequencies()); + attributes.put(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO, truthCounter.getNumber()); + } } } return SVCallRecordUtils.copyCallWithNewAttributes(recordWithGenotypes, attributes); } + private boolean hasAlleleFrequencyAnnotations(final SVCallRecord record) { + Utils.nonNull(record); + final Map attr = record.getAttributes(); + return (attr.containsKey(VCFConstants.ALLELE_COUNT_KEY) && attr.get(VCFConstants.ALLELE_COUNT_KEY) != null) + && (attr.containsKey(VCFConstants.ALLELE_FREQUENCY_KEY) && attr.get(VCFConstants.ALLELE_FREQUENCY_KEY) != null) + && (attr.containsKey(VCFConstants.ALLELE_NUMBER_KEY) && attr.get(VCFConstants.ALLELE_NUMBER_KEY) != null); + } + /** * Get truth/call states for the genotypes of the given sample */ @@ -144,21 +167,24 @@ private GenotypeConcordanceStates.TruthAndCallStates getStates(final String samp /** * Returns whether the copy state of the given sample's genotype matches. Only use for multi-allelic CNVs. */ - public Boolean cnvGenotypesMatch(final String sample, final SVCallRecord eval, final SVCallRecord truth) { + protected Boolean copyNumbersMatch(final String sample, final SVCallRecord eval, final SVCallRecord truth) { Utils.nonNull(sample); - Utils.nonNull(eval); - Utils.validateArg(eval.getType() == GATKSVVCFConstants.StructuralVariantAnnotationType.CNV, "Expected CNV evaluation variant"); - if (truth == null) { + if (eval == null || truth == null) { return null; } final Genotype evalGenotype = eval.getGenotypes().get(sample); - final int evalCopyNumber = VariantContextGetters.getAttributeAsInt(evalGenotype, GATKSVVCFConstants.COPY_NUMBER_FORMAT, -1); final Genotype truthGenotype = truth.getGenotypes().get(sample); - if (evalGenotype.hasExtendedAttribute(GATKSVVCFConstants.COPY_NUMBER_FORMAT) != truthGenotype.hasExtendedAttribute(GATKSVVCFConstants.COPY_NUMBER_FORMAT)) { - throw new IllegalArgumentException("One genotype for sample " + sample + " has CN but the other does not"); + if (evalGenotype == null || truthGenotype == null) { + return null; } - final int copyNumber = VariantContextGetters.getAttributeAsInt(truthGenotype, GATKSVVCFConstants.COPY_NUMBER_FORMAT, -1); - return copyNumber == evalCopyNumber; + final boolean evalHasCn = evalGenotype.hasExtendedAttribute(GATKSVVCFConstants.COPY_NUMBER_FORMAT); + final boolean truthHasCn = truthGenotype.hasExtendedAttribute(GATKSVVCFConstants.COPY_NUMBER_FORMAT); + if (!evalHasCn || !truthHasCn) { + return null; + } + final int evalCopyNumber = VariantContextGetters.getAttributeAsInt(evalGenotype, GATKSVVCFConstants.COPY_NUMBER_FORMAT, -1); + final int truthCopyNumber = VariantContextGetters.getAttributeAsInt(truthGenotype, GATKSVVCFConstants.COPY_NUMBER_FORMAT, -1); + return truthCopyNumber == evalCopyNumber; } @VisibleForTesting diff --git a/src/main/java/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance.java b/src/main/java/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance.java index 0c91302a4db..848c9610875 100644 --- a/src/main/java/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance.java +++ b/src/main/java/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance.java @@ -42,11 +42,12 @@ *
  • Genotype concordance
  • * * - * after meeting minimum overlap criteria. Evaluation variants that are sucessfully matched are annotated with - * genotype concordance metrics, including allele frequency of the truth variant. See output header for descriptions - * of the specific fields. Note that genotypes of samples that are present in the evaluation VCF but not the truth - * VCF are assumed to be no-calls for concordance. For multi-allelic CNVs, only a copy state concordance metric is - * annotated. + * after meeting minimum overlap criteria. Evaluation VCF variants that are sucessfully matched are annotated with + * genotype concordance metrics, including allele frequency of the truth variant. Concordance metrics are computed + * on the intersection of sample sets of the two VCFs, but all other annotations including variant truth status + * and allele frequency use all records and samples available. See output header for descriptions + * of the specific fields. For multi-allelic CNVs, only a copy state concordance metric is + * annotated. Allele frequencies will be recalculated automatically if unavailable in the provided VCFs. * *

    Inputs

    * @@ -55,7 +56,7 @@ * Evaluation VCF * *
  • - * Truth VCF (equal set or subset of samples) + * Truth VCF *
  • * * @@ -97,18 +98,6 @@ public final class SVConcordance extends AbstractConcordanceWalker { ) private GATKPath outputFile; - /** - * By default, truth allele frequencies are calculated on the fly using the evaluation record's allele number as the - * denominator. This option forces the tool to use the allele frequency annotations (AF/AN/AC) of the closest- - * matching truth variant record (by min distance to both breakpoints) for truth allele frequency annotations. - */ - @Argument( - doc = "Use allele frequency annotations from the truth vcf from the best-matching record.", - fullName = USE_TRUTH_AF_LONG_NAME, - optional = true - ) - private boolean useTruthAf = false; - @ArgumentCollection private final SVClusterEngineArgumentsCollection clusterParameterArgs = new SVClusterEngineArgumentsCollection(); @@ -131,28 +120,23 @@ public void onTraversalStart() { if (dictionary == null) { throw new UserException("Reference sequence dictionary required"); } - validateHeaders(); linkage = new SVConcordanceLinkage(dictionary); linkage.setDepthOnlyParams(clusterParameterArgs.getDepthParameters()); linkage.setMixedParams(clusterParameterArgs.getMixedParameters()); linkage.setEvidenceParams(clusterParameterArgs.getPESRParameters()); - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(useTruthAf); + // Concordance computations should be done on common samples only + final Set commonSamples = Sets.intersection( + new HashSet<>(getEvalHeader().getGenotypeSamples()), + new HashSet<>(getTruthHeader().getGenotypeSamples())); + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(commonSamples); engine = new ClosestSVFinder(linkage, collapser::annotate, dictionary); writer = createVCFWriter(outputFile); writer.writeHeader(createHeader(getEvalHeader())); } - private void validateHeaders() { - final Set truthSamples = new HashSet<>(getTruthHeader().getSampleNamesInOrder()); - final Set evalSamples = new HashSet<>(getEvalHeader().getSampleNamesInOrder()); - if (!Sets.difference(truthSamples, evalSamples).isEmpty()) { - throw new UserException.BadInput("Truth vcf samples must be a subset of eval vcf samples"); - } - } - @Override public Object onTraversalSuccess() { flushClusters(true); diff --git a/src/test/java/org/broadinstitute/hellbender/tools/sv/SVTestUtils.java b/src/test/java/org/broadinstitute/hellbender/tools/sv/SVTestUtils.java index 6e2a07300bb..4b882f92fd7 100644 --- a/src/test/java/org/broadinstitute/hellbender/tools/sv/SVTestUtils.java +++ b/src/test/java/org/broadinstitute/hellbender/tools/sv/SVTestUtils.java @@ -357,7 +357,14 @@ public static List buildBiallelicListWithPloidy(final Allele altAllele, public static SVCallRecord newCallRecordWithAlleles(final List genotypeAlleles, final List variantAlleles, final GATKSVVCFConstants.StructuralVariantAnnotationType svtype, final Integer expectedCopyNumber, final Integer copyNumber) { - GenotypeBuilder builder = new GenotypeBuilder("sample").alleles(genotypeAlleles); + return newCallRecordWithAllelesAndSampleName("sample", genotypeAlleles, variantAlleles, svtype, expectedCopyNumber, copyNumber); + } + + public static SVCallRecord newCallRecordWithAllelesAndSampleName(final String sample, + final List genotypeAlleles, final List variantAlleles, + final GATKSVVCFConstants.StructuralVariantAnnotationType svtype, final Integer expectedCopyNumber, + final Integer copyNumber) { + GenotypeBuilder builder = new GenotypeBuilder(sample).alleles(genotypeAlleles); if (expectedCopyNumber != null) { builder = builder.attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, expectedCopyNumber); } @@ -380,6 +387,17 @@ public static SVCallRecord newNamedDeletionRecordWithAttributes(final String id, attributes); } + public static SVCallRecord newNamedDeletionRecordWithAttributesAndGenotypes(final String id, + final List genotypes, + final Map attributes) { + return new SVCallRecord(id, "chr1", 100, true, "chr1", 199, false, + GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, null, + 100, Collections.singletonList(GATKSVVCFConstants.DEPTH_ALGORITHM), + Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + genotypes, + attributes); + } + public static final Map keyValueArraysToMap(final String[] keys, final Object[] values) { final Map map = new HashMap<>(); for (int i = 0; i < keys.length; i++) { @@ -388,14 +406,6 @@ public static final Map keyValueArraysToMap(final String[] keys, return map; } - // Note that strands may not be valid - public static SVCallRecord newCallRecordWithLengthAndTypeAndChrom2(final Integer length, final GATKSVVCFConstants.StructuralVariantAnnotationType svtype, final String chrom2) { - final int positionB = length == null ? 1 : CoordMath.getEnd(1, length); - return new SVCallRecord("", "chr1", 1, getValidTestStrandA(svtype), chrom2, positionB, getValidTestStrandB(svtype), - svtype, null, length, PESR_ONLY_ALGORITHM_LIST, Collections.emptyList(), Collections.emptyList(), - Collections.emptyMap()); - } - // Note that strands may not be valid public static SVCallRecord newCallRecordWithLengthAndType(final Integer length, final GATKSVVCFConstants.StructuralVariantAnnotationType svtype) { final int positionB = length == null ? 1 : CoordMath.getEnd(1, length); @@ -404,12 +414,6 @@ public static SVCallRecord newCallRecordWithLengthAndType(final Integer length, Collections.emptyMap()); } - public static SVCallRecord newDeletionCallRecordWithId(final String id) { - return new SVCallRecord(id, "chr1", 1, true, "chr1", 100, false, - GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, null, 100, PESR_ONLY_ALGORITHM_LIST, Collections.emptyList(), - Collections.emptyList(), Collections.emptyMap()); - } - public static SVCallRecord newDeletionCallRecordWithIdAndAlgorithms(final String id, final List algorithms) { return new SVCallRecord(id, "chr1", 1, true, "chr1", 100, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, null, 100, algorithms, Collections.emptyList(), diff --git a/src/test/java/org/broadinstitute/hellbender/tools/sv/concordance/ClosestSVFinderTest.java b/src/test/java/org/broadinstitute/hellbender/tools/sv/concordance/ClosestSVFinderTest.java index 7f603cdf5f1..5cda584e640 100644 --- a/src/test/java/org/broadinstitute/hellbender/tools/sv/concordance/ClosestSVFinderTest.java +++ b/src/test/java/org/broadinstitute/hellbender/tools/sv/concordance/ClosestSVFinderTest.java @@ -26,7 +26,7 @@ private static void assertConcordanceMembers(final SVCallRecord record, final St @Test public void testMetrics() { final SVConcordanceLinkage linkage = new SVConcordanceLinkage(SVTestUtils.hg38Dict); - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(false); + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(); final ClosestSVFinder engine = new ClosestSVFinder(linkage, collapser::annotate, SVTestUtils.hg38Dict); final SVCallRecord eval1 = SVTestUtils.makeRecord( @@ -148,7 +148,7 @@ public void testMetrics() { @Test public void testClustering() { final SVConcordanceLinkage linkage = new SVConcordanceLinkage(SVTestUtils.hg38Dict); - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(false); + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(); final ClosestSVFinder engine = new ClosestSVFinder(linkage, collapser::annotate, SVTestUtils.hg38Dict); final SVCallRecord eval1 = SVTestUtils.makeRecord( @@ -315,7 +315,7 @@ public Object[][] testCNVMatchesData() { public void testCNVMatches(final int evalCopyNumber, final int truthCopyNumber, final boolean expectMatch, final Double expectedConcordance) { final SVConcordanceLinkage linkage = new SVConcordanceLinkage(SVTestUtils.hg38Dict); - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(false); + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(); final ClosestSVFinder engine = new ClosestSVFinder(linkage, collapser::annotate, SVTestUtils.hg38Dict); final SVCallRecord eval = SVTestUtils.makeRecord( diff --git a/src/test/java/org/broadinstitute/hellbender/tools/sv/concordance/SVConcordanceAnnotatorTest.java b/src/test/java/org/broadinstitute/hellbender/tools/sv/concordance/SVConcordanceAnnotatorTest.java index ea377529be6..0093a93c1c6 100644 --- a/src/test/java/org/broadinstitute/hellbender/tools/sv/concordance/SVConcordanceAnnotatorTest.java +++ b/src/test/java/org/broadinstitute/hellbender/tools/sv/concordance/SVConcordanceAnnotatorTest.java @@ -4,6 +4,7 @@ import htsjdk.variant.variantcontext.Allele; import htsjdk.variant.variantcontext.Genotype; import htsjdk.variant.variantcontext.GenotypeBuilder; +import htsjdk.variant.vcf.VCFConstants; import org.broadinstitute.hellbender.tools.spark.sv.utils.GATKSVVCFConstants; import org.broadinstitute.hellbender.tools.sv.SVCallRecord; import org.broadinstitute.hellbender.tools.sv.SVTestUtils; @@ -15,6 +16,8 @@ import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; public class SVConcordanceAnnotatorTest { @@ -192,15 +195,31 @@ public void testMatchCnvNonNull( truthCopyNumber ); - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(false); - final boolean actual = collapser.cnvGenotypesMatch(sample, evalRecord, truthRecord); + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(); + final boolean actual = collapser.copyNumbersMatch(sample, evalRecord, truthRecord); Assert.assertEquals(actual, expected); } @Test public void testMatchCnvNull() { final String sample = "sample"; - final SVCallRecord evalRecord = SVTestUtils.newCallRecordWithAlleles( + final SVCallRecord record = SVTestUtils.newCallRecordWithAlleles( + Arrays.asList(Allele.NO_CALL, Allele.NO_CALL), + SVTestUtils.getCNVAlleles(GATKSVVCFConstants.StructuralVariantAnnotationType.CNV), + GATKSVVCFConstants.StructuralVariantAnnotationType.CNV, + 2, + 2 + ); + + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(); + + // Null records in null call + Assert.assertNull(collapser.copyNumbersMatch(sample, record, null)); + Assert.assertNull(collapser.copyNumbersMatch(sample, null, record)); + + + final SVCallRecord recordNoSample = SVTestUtils.newCallRecordWithAllelesAndSampleName( + "sample2", Arrays.asList(Allele.NO_CALL, Allele.NO_CALL), SVTestUtils.getCNVAlleles(GATKSVVCFConstants.StructuralVariantAnnotationType.CNV), GATKSVVCFConstants.StructuralVariantAnnotationType.CNV, @@ -208,10 +227,24 @@ public void testMatchCnvNull() { 2 ); - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(false); + // Null call if sample not found + Assert.assertNull(collapser.copyNumbersMatch(sample, recordNoSample, recordNoSample)); + Assert.assertNull(collapser.copyNumbersMatch(sample, record, recordNoSample)); + Assert.assertNull(collapser.copyNumbersMatch(sample, recordNoSample, record)); + + final SVCallRecord recordNoCn = SVTestUtils.newCallRecordWithAllelesAndSampleName( + sample, + Arrays.asList(Allele.NO_CALL, Allele.NO_CALL), + SVTestUtils.getCNVAlleles(GATKSVVCFConstants.StructuralVariantAnnotationType.CNV), + GATKSVVCFConstants.StructuralVariantAnnotationType.CNV, + 2, + null + ); - // Null truth results in null call - Assert.assertNull(collapser.cnvGenotypesMatch(sample, evalRecord, null)); + // Null call if CN not found + Assert.assertNull(collapser.copyNumbersMatch(sample, recordNoCn, recordNoCn)); + Assert.assertNull(collapser.copyNumbersMatch(sample, record, recordNoCn)); + Assert.assertNull(collapser.copyNumbersMatch(sample, recordNoCn, record)); } @DataProvider(name = "testGetStateFromGenotypeData") @@ -256,7 +289,7 @@ public Object[][] testGetStateFromGenotypeData() { public void testGetStateFromGenotype(final Allele[] genotypeAlleles, final GenotypeConcordanceStates.TruthState expectedTruthState) { final Genotype genotype = alleleArrayToGenotype(genotypeAlleles, null, null); - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(false); + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(); final GenotypeConcordanceStates.TruthState actualTruthState = collapser.getTruthState(genotype); Assert.assertEquals(actualTruthState, expectedTruthState); @@ -281,17 +314,105 @@ public void testGetStateFromGenotype(final Allele[] genotypeAlleles, @Test public void testGetTruthNullGenotypeState() { - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(false); + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(); final GenotypeConcordanceStates.TruthState actualTruthState = collapser.getTruthState(null); Assert.assertEquals(actualTruthState, GenotypeConcordanceStates.TruthState.NO_CALL); } @Test(expectedExceptions = IllegalArgumentException.class) public void testGetNullEvalGenotypeState() { - final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(false); + final SVConcordanceAnnotator collapser = new SVConcordanceAnnotator(); collapser.getEvalState(null); } + @Test + public void testAnnotateEvalKeepAF() { + final Map evalAttr = new HashMap<>(); + evalAttr.put(VCFConstants.ALLELE_NUMBER_KEY, 200); + evalAttr.put(VCFConstants.ALLELE_COUNT_KEY, 3); + evalAttr.put(VCFConstants.ALLELE_FREQUENCY_KEY, 3./200.); + final GenotypeBuilder builder = new GenotypeBuilder().alleles(Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)); + final SVCallRecord evalRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("eval", Collections.singletonList(builder.make()), evalAttr); + final SVCallRecord truthRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("truth", Collections.singletonList(builder.make()), Collections.emptyMap()); + final ClosestSVFinder.ClosestPair pair = new ClosestSVFinder.ClosestPair(evalRecord, truthRecord); + final SVCallRecord result = new SVConcordanceAnnotator().annotate(pair); + Assert.assertTrue(result.getAttributes().containsKey(VCFConstants.ALLELE_NUMBER_KEY)); + Assert.assertTrue(result.getAttributes().containsKey(VCFConstants.ALLELE_COUNT_KEY)); + Assert.assertTrue(result.getAttributes().containsKey(VCFConstants.ALLELE_FREQUENCY_KEY)); + Assert.assertEquals(result.getAttributes().get(VCFConstants.ALLELE_NUMBER_KEY), evalAttr.get(VCFConstants.ALLELE_NUMBER_KEY)); + Assert.assertEquals(result.getAttributes().get(VCFConstants.ALLELE_COUNT_KEY), evalAttr.get(VCFConstants.ALLELE_COUNT_KEY)); + Assert.assertEquals(result.getAttributes().get(VCFConstants.ALLELE_FREQUENCY_KEY), evalAttr.get(VCFConstants.ALLELE_FREQUENCY_KEY)); + } + + @Test + public void testAnnotateEvalComputeAF() { + final GenotypeBuilder builder = new GenotypeBuilder().alleles(Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)); + final SVCallRecord evalRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("eval", Collections.singletonList(builder.make()), Collections.emptyMap()); + final SVCallRecord truthRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("truth", Collections.singletonList(builder.make()), Collections.emptyMap()); + final ClosestSVFinder.ClosestPair pair = new ClosestSVFinder.ClosestPair(evalRecord, truthRecord); + final SVCallRecord result = new SVConcordanceAnnotator().annotate(pair); + Assert.assertTrue(result.getAttributes().containsKey(VCFConstants.ALLELE_NUMBER_KEY)); + Assert.assertTrue(result.getAttributes().containsKey(VCFConstants.ALLELE_COUNT_KEY)); + Assert.assertTrue(result.getAttributes().containsKey(VCFConstants.ALLELE_FREQUENCY_KEY)); + Assert.assertEquals(result.getAttributes().get(VCFConstants.ALLELE_NUMBER_KEY), Integer.valueOf(2)); + Assert.assertEquals((int[]) result.getAttributes().get(VCFConstants.ALLELE_COUNT_KEY), new int[]{1}); + Assert.assertEquals((double[]) result.getAttributes().get(VCFConstants.ALLELE_FREQUENCY_KEY), new double[]{1/2.0}); + } + + @Test + public void testAnnotateCopyTruthAF() { + final Map truthAttr = new HashMap<>(); + truthAttr.put(VCFConstants.ALLELE_NUMBER_KEY, 200); + truthAttr.put(VCFConstants.ALLELE_COUNT_KEY, 3); + truthAttr.put(VCFConstants.ALLELE_FREQUENCY_KEY, 3./200.); + final GenotypeBuilder builder = new GenotypeBuilder().alleles(Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)); + final SVCallRecord evalRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("eval", Collections.singletonList(builder.make()), Collections.emptyMap()); + final SVCallRecord truthRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("truth", Collections.singletonList(builder.make()), truthAttr); + final ClosestSVFinder.ClosestPair pair = new ClosestSVFinder.ClosestPair(evalRecord, truthRecord); + final SVCallRecord result = new SVConcordanceAnnotator().annotate(pair); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO)); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO)); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO)); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO), truthAttr.get(VCFConstants.ALLELE_NUMBER_KEY)); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO), truthAttr.get(VCFConstants.ALLELE_COUNT_KEY)); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO), truthAttr.get(VCFConstants.ALLELE_FREQUENCY_KEY)); + } + + @Test + public void testAnnotateCalculateTruthAF() { + final GenotypeBuilder builder = new GenotypeBuilder().alleles(Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)); + final SVCallRecord evalRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("eval", Collections.singletonList(builder.make()), Collections.emptyMap()); + final SVCallRecord truthRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("truth", Collections.singletonList(builder.make()), Collections.emptyMap()); + final ClosestSVFinder.ClosestPair pair = new ClosestSVFinder.ClosestPair(evalRecord, truthRecord); + final SVCallRecord result = new SVConcordanceAnnotator().annotate(pair); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO)); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO)); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO)); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO), Integer.valueOf(2)); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO), new int[]{1}); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO), new double[]{1/2.0}); + } + + @Test + public void testAnnotateOverwriteTruthAF() { + // Should overwrite existing TRUTH_AF annotations + final Map evalAttr = new HashMap<>(); + evalAttr.put(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO, 200); + evalAttr.put(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO, 3); + evalAttr.put(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO, 1./200.); + final GenotypeBuilder builder = new GenotypeBuilder().alleles(Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)); + final SVCallRecord evalRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("eval", Collections.singletonList(builder.make()), Collections.emptyMap()); + final SVCallRecord truthRecord = SVTestUtils.newNamedDeletionRecordWithAttributesAndGenotypes("truth", Collections.singletonList(builder.make()), Collections.emptyMap()); + final ClosestSVFinder.ClosestPair pair = new ClosestSVFinder.ClosestPair(evalRecord, truthRecord); + final SVCallRecord result = new SVConcordanceAnnotator().annotate(pair); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO)); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO)); + Assert.assertTrue(result.getAttributes().containsKey(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO)); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_NUMBER_INFO), Integer.valueOf(2)); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_COUNT_INFO), new int[]{1}); + Assert.assertEquals(result.getAttributes().get(GATKSVVCFConstants.TRUTH_ALLELE_FREQUENCY_INFO), new double[]{1/2.0}); + } + private Genotype alleleArrayToGenotype(final Allele[] allelesArr, final Integer expectedCopyNumber, final Integer copyNumber) { diff --git a/src/test/java/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordanceIntegrationTest.java b/src/test/java/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordanceIntegrationTest.java index 9d272477a98..eca32b971a7 100644 --- a/src/test/java/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordanceIntegrationTest.java +++ b/src/test/java/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordanceIntegrationTest.java @@ -75,7 +75,7 @@ public void testRefPanel() { linkage.setDepthOnlyParams(depthParameters); linkage.setMixedParams(mixedParameters); linkage.setEvidenceParams(pesrParameters); - final SVConcordanceAnnotator annotator = new SVConcordanceAnnotator(false); + final SVConcordanceAnnotator annotator = new SVConcordanceAnnotator(); final List inputEvalVariants = VariantContextTestUtils.readEntireVCFIntoMemory(evalVcfPath).getValue() .stream().map(SVCallRecordUtils::create).collect(Collectors.toList()); @@ -227,4 +227,122 @@ public void testSelf() { } } } + + @Test + public void testSelfTruthSubset() { + + // Run a vcf against itself but subsetted to fewer samples and variants + + final File output = createTempFile("concord", ".vcf"); + final String evalVcfPath = getToolTestDataDir() + "ref_panel_1kg.cleaned.gatk.chr22_chrY.vcf.gz"; + final String truthVcfPath = getToolTestDataDir() + "ref_panel_1kg.cleaned.gatk.chr22_chrY.sample_subset.vcf.gz"; + + final ArgumentsBuilder args = new ArgumentsBuilder() + .addOutput(output) + .add(StandardArgumentDefinitions.SEQUENCE_DICTIONARY_NAME, GATKBaseTest.FULL_HG38_DICT) + .add(AbstractConcordanceWalker.EVAL_VARIANTS_LONG_NAME, evalVcfPath) + .add(AbstractConcordanceWalker.TRUTH_VARIANTS_LONG_NAME, truthVcfPath); + + runCommandLine(args, SVConcordance.class.getSimpleName()); + assertPerfectConcordance(output, evalVcfPath); + } + + @Test + public void testSelfEvalSubset() { + + // Run a vcf against itself but with extra samples and variants + + final File output = createTempFile("concord", ".vcf"); + final String evalVcfPath = getToolTestDataDir() + "ref_panel_1kg.cleaned.gatk.chr22_chrY.sample_subset.vcf.gz"; + final String truthVcfPath = getToolTestDataDir() + "ref_panel_1kg.cleaned.gatk.chr22_chrY.vcf.gz"; + + final ArgumentsBuilder args = new ArgumentsBuilder() + .addOutput(output) + .add(StandardArgumentDefinitions.SEQUENCE_DICTIONARY_NAME, GATKBaseTest.FULL_HG38_DICT) + .add(AbstractConcordanceWalker.EVAL_VARIANTS_LONG_NAME, evalVcfPath) + .add(AbstractConcordanceWalker.TRUTH_VARIANTS_LONG_NAME, truthVcfPath); + + runCommandLine(args, SVConcordance.class.getSimpleName()); + assertPerfectConcordance(output, evalVcfPath); + } + + private void assertPerfectConcordance(final File output, final String evalVcfPath) { + + final Pair> outputVcf = VariantContextTestUtils.readEntireVCFIntoMemory(output.getAbsolutePath()); + + final SAMSequenceDictionary dictionary = SVTestUtils.hg38Dict; + final ClusteringParameters depthParameters = ClusteringParameters.createDepthParameters(0.5, 2000, 0); + final ClusteringParameters mixedParameters = ClusteringParameters.createMixedParameters(0.1, 2000, 0); + final ClusteringParameters pesrParameters = ClusteringParameters.createPesrParameters(0.1, 500, 0); + final SVConcordanceLinkage linkage = new SVConcordanceLinkage(dictionary); + linkage.setDepthOnlyParams(depthParameters); + linkage.setMixedParams(mixedParameters); + linkage.setEvidenceParams(pesrParameters); + + final Comparator idComparator = Comparator.comparing(VariantContext::getID); + + final List inputVariants = VariantContextTestUtils.readEntireVCFIntoMemory(evalVcfPath).getValue() + .stream() + .sorted(idComparator) + .collect(Collectors.toList()); + final List outputVariants = outputVcf.getValue().stream().sorted(idComparator).collect(Collectors.toList()); + + Assert.assertEquals(outputVariants.size(), inputVariants.size()); + for (int i = 0; i < outputVariants.size(); i++) { + final VariantContext outputVariant = outputVariants.get(i); + final VariantContext expectedVariant = inputVariants.get(i); + Assert.assertEquals(outputVariant.getID(), expectedVariant.getID()); + Assert.assertEquals(outputVariant.getContig(), expectedVariant.getContig()); + Assert.assertEquals(outputVariant.getStart(), expectedVariant.getStart()); + Assert.assertEquals(outputVariant.getEnd(), expectedVariant.getEnd()); + Assert.assertEquals(outputVariant.getAlleles(), expectedVariant.getAlleles()); + final String svtype = outputVariant.getAttributeAsString(GATKSVVCFConstants.SVTYPE, "test_default"); + Assert.assertEquals(svtype, expectedVariant.getAttributeAsString(GATKSVVCFConstants.SVTYPE, "expected_default")); + // check the variant matched itself with perfect concordance + if (outputVariant.getAttributeAsString(Concordance.TRUTH_STATUS_VCF_ATTRIBUTE, "test_default") == ConcordanceState.TRUE_POSITIVE.getAbbreviation()) { + Assert.assertEquals(outputVariant.getAttributeAsString(GATKSVVCFConstants.TRUTH_VARIANT_ID_INFO, ""), outputVariant.getID()); + if (svtype.equals(GATKSVVCFConstants.StructuralVariantAnnotationType.CNV.toString())) { + MathUtilsUnitTest.assertEqualsDoubleSmart(outputVariant.getAttributeAsDouble(GATKSVVCFConstants.COPY_NUMBER_CONCORDANCE_INFO, -1.), 1.0, TOLERANCE); + } else { + MathUtilsUnitTest.assertEqualsDoubleSmart(outputVariant.getAttributeAsDouble(GATKSVVCFConstants.GENOTYPE_CONCORDANCE_INFO, -1.), 1.0, TOLERANCE); + } + } + } + } + + @Test + public void testSitesOnly() { + final File output = createTempFile("concord_sites_only", ".vcf"); + final String evalVcfPath = getToolTestDataDir() + "ref_panel_1kg.cleaned.gatk.chr22_chrY.sites_only.vcf.gz"; + final String truthVcfPath = getToolTestDataDir() + "ref_panel_1kg.raw_calls.chr22_chrY.sites_only.vcf.gz"; + + final ArgumentsBuilder args = new ArgumentsBuilder() + .addOutput(output) + .add(StandardArgumentDefinitions.SEQUENCE_DICTIONARY_NAME, GATKBaseTest.FULL_HG38_DICT) + .add(SVClusterEngineArgumentsCollection.DEPTH_SAMPLE_OVERLAP_FRACTION_NAME, 0) + .add(SVClusterEngineArgumentsCollection.DEPTH_INTERVAL_OVERLAP_FRACTION_NAME, 0.5) + .add(SVClusterEngineArgumentsCollection.DEPTH_BREAKEND_WINDOW_NAME, 2000) + .add(SVClusterEngineArgumentsCollection.MIXED_SAMPLE_OVERLAP_FRACTION_NAME, 0) + .add(SVClusterEngineArgumentsCollection.MIXED_INTERVAL_OVERLAP_FRACTION_NAME, 0.1) + .add(SVClusterEngineArgumentsCollection.MIXED_BREAKEND_WINDOW_NAME, 2000) + .add(SVClusterEngineArgumentsCollection.PESR_SAMPLE_OVERLAP_FRACTION_NAME, 0) + .add(SVClusterEngineArgumentsCollection.PESR_INTERVAL_OVERLAP_FRACTION_NAME, 0.1) + .add(SVClusterEngineArgumentsCollection.PESR_BREAKEND_WINDOW_NAME, 500) + .add(AbstractConcordanceWalker.TRUTH_VARIANTS_LONG_NAME, truthVcfPath) + .add(AbstractConcordanceWalker.EVAL_VARIANTS_SHORT_NAME, evalVcfPath); + + + runCommandLine(args, SVConcordance.class.getSimpleName()); + + final Pair> outputVcf = VariantContextTestUtils.readEntireVCFIntoMemory(output.getAbsolutePath()); + final List inputEvalVariants = VariantContextTestUtils.readEntireVCFIntoMemory(evalVcfPath).getValue() + .stream().map(SVCallRecordUtils::create).collect(Collectors.toList()); + Assert.assertEquals(outputVcf.getValue().size(), inputEvalVariants.size()); + final long numTruePositives = outputVcf.getValue().stream().filter(v -> v.getAttributeAsString(Concordance.TRUTH_STATUS_VCF_ATTRIBUTE, "").equals(ConcordanceState.TRUE_POSITIVE.getAbbreviation())).count(); + Assert.assertEquals((int) numTruePositives, 1104); + for (final VariantContext variant: outputVcf.getValue()) { + // Concordance can't be calculated for sites-only + Assert.assertTrue(variant.getAttributeAsString(GATKSVVCFConstants.GENOTYPE_CONCORDANCE_INFO, ".").equals(".")); + } + } } diff --git a/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sample_subset.vcf.gz b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sample_subset.vcf.gz new file mode 100644 index 00000000000..6f130a07606 Binary files /dev/null and b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sample_subset.vcf.gz differ diff --git a/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sample_subset.vcf.gz.tbi b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sample_subset.vcf.gz.tbi new file mode 100644 index 00000000000..bf5f3441154 Binary files /dev/null and b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sample_subset.vcf.gz.tbi differ diff --git a/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sites_only.vcf.gz b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sites_only.vcf.gz new file mode 100644 index 00000000000..2c40150944d Binary files /dev/null and b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sites_only.vcf.gz differ diff --git a/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sites_only.vcf.gz.tbi b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sites_only.vcf.gz.tbi new file mode 100644 index 00000000000..75f3f01f96f Binary files /dev/null and b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.cleaned.gatk.chr22_chrY.sites_only.vcf.gz.tbi differ diff --git a/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.raw_calls.chr22_chrY.sites_only.vcf.gz b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.raw_calls.chr22_chrY.sites_only.vcf.gz new file mode 100644 index 00000000000..16c3e7bd27b Binary files /dev/null and b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.raw_calls.chr22_chrY.sites_only.vcf.gz differ diff --git a/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.raw_calls.chr22_chrY.sites_only.vcf.gz.tbi b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.raw_calls.chr22_chrY.sites_only.vcf.gz.tbi new file mode 100644 index 00000000000..0d0eaf8fb44 Binary files /dev/null and b/src/test/resources/org/broadinstitute/hellbender/tools/walkers/sv/SVConcordance/ref_panel_1kg.raw_calls.chr22_chrY.sites_only.vcf.gz.tbi differ