From 547a9746e10e723accbc819bf5b9c4caef923b92 Mon Sep 17 00:00:00 2001 From: Mark Walker Date: Mon, 10 Jul 2023 12:50:44 -0400 Subject: [PATCH 1/2] Add support for breakend replacement alleles in SVCluster --- .../sv/cluster/CanonicalSVCollapser.java | 54 +++-- .../tools/walkers/sv/SVCluster.java | 7 +- .../cluster/CanonicalSVCollapserUnitTest.java | 218 ++++++++++++++++++ 3 files changed, 259 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapser.java b/src/main/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapser.java index 8521430932e..91e311025b5 100644 --- a/src/main/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapser.java +++ b/src/main/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapser.java @@ -175,12 +175,18 @@ public SVCallRecord collapse(final SVClusterEngine.OutputCluster cluster) { final List algorithms = collapseAlgorithms(items); final Map attributes = collapseAttributes(representative, items); - final List altAlleles = collapseAltAlleles(items); + final Boolean strandA = type == GATKSVVCFConstants.StructuralVariantAnnotationType.CNV ? null : representative.getStrandA(); + final Boolean strandB = type == GATKSVVCFConstants.StructuralVariantAnnotationType.CNV ? null : representative.getStrandB(); + final Allele refAllele = collapseRefAlleles(representative.getContigA(), start); + final List altAlleles; + if (type == GATKSVVCFConstants.StructuralVariantAnnotationType.BND) { + altAlleles = Collections.singletonList(constructBndAllele(strandA, representative.getStrandB(), representative.getContigB(), end, refAllele)); + } else { + altAlleles = collapseAltAlleles(items); + } final List alleles = collapseAlleles(altAlleles, refAllele); final List genotypes = harmonizeAltAlleles(altAlleles, collapseAllGenotypes(items, refAllele)); - final Boolean strandA = type == GATKSVVCFConstants.StructuralVariantAnnotationType.CNV ? null : representative.getStrandA(); - final Boolean strandB = type == GATKSVVCFConstants.StructuralVariantAnnotationType.CNV ? null : representative.getStrandB(); final Set filters = collapseFilters(items); final Double quality = collapseQuality(items); @@ -257,8 +263,22 @@ protected Allele collapseRefAlleles(final String contig, final int pos) { return Allele.create(bases[0], true); } + protected static Allele constructBndAllele(final Boolean strandA, final Boolean strandB, final String contigB, + final int posB, final Allele refAllele) { + Utils.validateArg(strandA != null, "First breakend strand cannot be null"); + Utils.validateArg(strandB != null, "Second breakend strand cannot be null"); + final String bracket = strandB ? "]" : "["; + final String str; + if (strandA) { + str = refAllele.getBaseString() + bracket + contigB + ":" + posB + bracket; + } else { + str = bracket + contigB + ":" + posB + bracket + refAllele.getBaseString(); + } + return Allele.create(str, false); + } + /** - * Collapses alternate alleles into a list of representative alleles. Note this supports sub-typed alleles such as + * Collapses symbolic alleles into a list of representative alleles. Note this supports sub-typed alleles such as * <INS:MEI>. If multiple alt alleles are found, the variant must either be a CNV or sub-typed alleles with the * same base symbol (e.g. <INS:MEI> and <INS:MEI:SVA> would result in <INS>). * @param items records whose alt alleles should be collapsed @@ -276,6 +296,11 @@ protected List collapseAltAlleles(final Collection items) } else if (altAlleles.size() == 1) { return Collections.singletonList(altAlleles.get(0)); } else { + for (final Allele a : altAlleles) { + if (!validateAltAllele(a)) { + throw new IllegalArgumentException("Cannot collapse non-symbolic allele: " + a.getDisplayString()); + } + } // Multiple non-ref alleles need collapsing // TODO does not search for subtypes e.g. int numCnvAlleles = 0; @@ -285,8 +310,7 @@ protected List collapseAltAlleles(final Collection items) if (a.equals(Allele.SV_SIMPLE_CNV)) { numCnvAlleles++; numMultiallelicAlleles++; - } - if (a.equals(Allele.SV_SIMPLE_DUP) || a.equals(Allele.SV_SIMPLE_DEL)) { + } else if (a.equals(Allele.SV_SIMPLE_DUP) || a.equals(Allele.SV_SIMPLE_DEL)) { numCnvAlleles++; } } @@ -307,11 +331,14 @@ protected List collapseAltAlleles(final Collection items) } else { throw new UnsupportedOperationException("Unimplemented alt allele summary strategy: " + altAlleleSummaryStrategy.name()); } - Utils.validate(collapsedAlleleTokens.length > 0, "Encountered multiple symbolic allele base symbols for non-CNV"); return Collections.singletonList(Allele.create("<" + String.join(":", collapsedAlleleTokens) + ">", false)); } } + protected boolean validateAltAllele(final Allele allele) { + return !allele.isReference() && allele.isSymbolic() && !allele.isBreakpoint() && !allele.isSingleBreakend(); + } + private String[] collapseAltAllelesCommon(final List alleles) { final List alleleTokens = alleles.stream() .map(GATKSVVariantContextUtils::getSymbolicAlleleSymbols) @@ -646,23 +673,22 @@ private SVCallRecord getRepresentativeIntervalItem(final Collection carrierCountComparator = Comparator.comparing(r -> -r.getCarrierGenotypeList().size()); - final Comparator distanceComparator = Comparator.comparing(r -> getDistance(r, starts, ends)); - final Comparator idComparator = Comparator.comparing(r -> getDistance(r, starts, ends)); // stabilizes order + final Comparator distanceComparator = Comparator.comparing(r -> getDistance(r.getPositionA(), r.getPositionB(), starts, ends)); + final Comparator idComparator = Comparator.comparing(r -> getDistance(r.getPositionA(), r.getPositionB(), starts, ends)); // stabilizes order return records.stream().min( carrierCountComparator .thenComparing(distanceComparator) .thenComparing(idComparator)).get(); } - private long getDistance(final SVCallRecord record, - final int[] starts, - final int[] ends) { + protected static long getDistance(final int posA, + final int posB, + final int[] starts, + final int[] ends) { long d = 0; - final int posA = record.getPositionA(); for (int j = 0; j < starts.length; j++) { d += FastMath.abs(starts[j] - posA); } - final int posB = record.getPositionB(); for (int j = 0; j < ends.length; j++) { d += FastMath.abs(ends[j] - posB); } diff --git a/src/main/java/org/broadinstitute/hellbender/tools/walkers/sv/SVCluster.java b/src/main/java/org/broadinstitute/hellbender/tools/walkers/sv/SVCluster.java index 03ac3093841..4e483652d3c 100644 --- a/src/main/java/org/broadinstitute/hellbender/tools/walkers/sv/SVCluster.java +++ b/src/main/java/org/broadinstitute/hellbender/tools/walkers/sv/SVCluster.java @@ -411,14 +411,9 @@ private void write(final boolean force) { } private VCFHeader createHeader() { - final VCFHeader header = new VCFHeader(getDefaultToolVCFHeaderLines(), samples); - header.setVCFHeaderVersion(VCFHeaderVersion.VCF4_2); + final VCFHeader header = new VCFHeader(getHeaderForVariants().getMetaDataInInputOrder(), samples); header.setSequenceDictionary(dictionary); - // Copy from inputs - getHeaderForVariants().getFormatHeaderLines().forEach(header::addMetaDataLine); - getHeaderForVariants().getInfoHeaderLines().forEach(header::addMetaDataLine); - // Required info lines header.addMetaDataLine(VCFStandardHeaderLines.getInfoLine(VCFConstants.END_KEY)); header.addMetaDataLine(GATKSVVCFHeaderLines.getInfoLine(GATKSVVCFConstants.SVLEN)); diff --git a/src/test/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapserUnitTest.java b/src/test/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapserUnitTest.java index 6a6d96448d8..fe34ea6f6eb 100644 --- a/src/test/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapserUnitTest.java +++ b/src/test/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapserUnitTest.java @@ -12,6 +12,7 @@ import org.broadinstitute.hellbender.tools.sv.SVCallRecord; import org.broadinstitute.hellbender.tools.sv.SVCallRecordUtils; import org.broadinstitute.hellbender.tools.sv.SVTestUtils; +import org.broadinstitute.hellbender.utils.variant.GATKSVVariantContextUtils; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -41,6 +42,10 @@ public class CanonicalSVCollapserUnitTest { SVTestUtils.hg38Reference, CanonicalSVCollapser.AltAlleleSummaryStrategy.COMMON_SUBTYPE, CanonicalSVCollapser.BreakpointSummaryStrategy.MEAN_START_MEAN_END); + private static final CanonicalSVCollapser collapserRepresentative = new CanonicalSVCollapser( + SVTestUtils.hg38Reference, + CanonicalSVCollapser.AltAlleleSummaryStrategy.COMMON_SUBTYPE, + CanonicalSVCollapser.BreakpointSummaryStrategy.REPRESENTATIVE); private static final CanonicalSVCollapser collapserSpecificAltAllele = new CanonicalSVCollapser( SVTestUtils.hg38Reference, CanonicalSVCollapser.AltAlleleSummaryStrategy.MOST_SPECIFIC_SUBTYPE, @@ -50,6 +55,103 @@ public class CanonicalSVCollapserUnitTest { private static final Allele SVA_INSERTION_ALLELE = Allele.create(""); private static final Allele LINE_INSERTION_ALLELE = Allele.create(""); + @DataProvider(name = "clusterData") + public Object[][] getClusterData() { + return new Object[][]{ + // One deletion + { + new SVClusterEngine.OutputCluster( + Lists.newArrayList( + SVTestUtils.makeRecord("record1", "chr1", 1000, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ) + ) + ), + SVTestUtils.makeRecord("record1", "chr1", 1000, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ) + }, + // Two deletions + { + new SVClusterEngine.OutputCluster( + Lists.newArrayList( + SVTestUtils.makeRecord("record1", "chr1", 1000, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ), + SVTestUtils.makeRecord("record2", "chr1", 1000, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ) + ) + ), + SVTestUtils.makeRecord("record1", "chr1", 1000, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ) + }, + // Breakends + { + new SVClusterEngine.OutputCluster( + Lists.newArrayList( + SVTestUtils.makeRecord("record1", "chr1", 1000, true, + "chr2", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.BND, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, GATKSVVariantContextUtils.BND_ALLELE), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, GATKSVVariantContextUtils.BND_ALLELE)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ), + SVTestUtils.makeRecord("record2", "chr1", 1000, true, + "chr2", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.BND, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, GATKSVVariantContextUtils.BND_ALLELE), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, GATKSVVariantContextUtils.BND_ALLELE)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ) + ) + ), + SVTestUtils.makeRecord("record1", "chr1", 1000, true, + "chr2", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.BND, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.create("N[chr2:2000[")), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.create("N[chr2:2000["))).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ) + } + }; + } + + @Test(dataProvider = "clusterData") + public void testCollapse(SVClusterEngine.OutputCluster cluster, SVCallRecord expected) { + SVCallRecord result = collapser.collapse(cluster); + SVTestUtils.assertEqualsExceptExcludedAttributes(result, expected, Collections.singletonList(GATKSVVCFConstants.CLUSTER_MEMBER_IDS_KEY)); + } + @DataProvider(name = "collapseRefAllelesTestData") public Object[][] collapseRefAllelesTestData() { return new Object[][]{ @@ -259,6 +361,44 @@ public void collapseAltAllelesTest(final List> recordGenotypeAllele Assert.assertEquals(sortedTestSpecific, sortedExpectedSpecific); } + @Test(expectedExceptions = IllegalArgumentException.class) + public void collapseInvalidAltAllelesTest() { + final List records = Lists.newArrayList( + SVTestUtils.newCallRecordWithAlleles( + Lists.newArrayList(Allele.REF_N, Allele.create("N[chr1:1[", false)), + Lists.newArrayList(Allele.REF_N, Allele.create("N[chr1:1[", false)), + GATKSVVCFConstants.StructuralVariantAnnotationType.INS, + 2, 2 + ), + SVTestUtils.newCallRecordWithAlleles( + Lists.newArrayList(Allele.REF_N, Allele.create("N[chr1:2[", false)), + Lists.newArrayList(Allele.REF_N, Allele.create("N[chr1:2[", false)), + GATKSVVCFConstants.StructuralVariantAnnotationType.INS, + 2, 2 + ) + ); + collapser.collapseAltAlleles(records); + } + + @DataProvider(name = "bndAlleleData") + public Object[][] bndAlleleData() { + return new Object[][] { + { true, true, "contigB", 10, "A", "A]contigB:10]" }, + { true, false, "contigB", 10, "T", "T[contigB:10[" }, + { false, true, "contigB", 20, "C", "]contigB:20]C" }, + { false, false, "contigB", 20, "G", "[contigB:20[G" }, + }; + } + + @Test(dataProvider = "bndAlleleData") + public void testConstructBndAllele(Boolean strandA, Boolean strandB, String contigB, int posB, + String refAlleleString, String expectedAlleleString) { + final Allele refAllele = Allele.create(refAlleleString, true); + final Allele expected = Allele.create(expectedAlleleString, false); + Allele result = CanonicalSVCollapser.constructBndAllele(strandA, strandB, contigB, posB, refAllele); + Assert.assertEquals(result, expected); + } + private static final String TEST_KEY_1 = "TEST_KEY_1"; private Map createGenotypeTestAttributes(final Integer expectedCopyNumber, final String testVal) { @@ -1291,6 +1431,84 @@ public void collapseIntervalTest(final String[] contigs, final int[] starts, fin collapseIntervalTestHelper(collapserMean, svtype, contigs, records, expectedMean); } + @Test + public void collapseIntervalRepresentativeTest() { + // Choose second record with more carriers + final List records = + Lists.newArrayList( + SVTestUtils.makeRecord("record1", "chr1", 1000, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ), + SVTestUtils.makeRecord("record2", "chr1", 1001, true, + "chr1", 2001, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ) + ); + final Pair result = collapserRepresentative.collapseInterval(records); + Assert.assertEquals((int) result.getLeft(), 1001); + Assert.assertEquals((int) result.getRight(), 2001); + + // record2 and record3 have the best carrier status, but choose second record which is closer to all others on average + final List records2 = + Lists.newArrayList( + SVTestUtils.makeRecord("record1", "chr1", 1000, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.REF_N)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ), + SVTestUtils.makeRecord("record2", "chr1", 999, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ), + SVTestUtils.makeRecord("record3", "chr1", 1005, true, + "chr1", 2000, false, GATKSVVCFConstants.StructuralVariantAnnotationType.DEL, + null, Collections.emptyList(), Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL), + Lists.newArrayList( + new GenotypeBuilder("sample1", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2), + new GenotypeBuilder("sample2", Lists.newArrayList(Allele.REF_N, Allele.SV_SIMPLE_DEL)).attribute(GATKSVVCFConstants.EXPECTED_COPY_NUMBER_FORMAT, 2) + ) + ) + ); + final Pair result2 = collapserRepresentative.collapseInterval(records2); + Assert.assertEquals((int) result2.getLeft(), 999); + Assert.assertEquals((int) result2.getRight(), 2000); + } + + @DataProvider(name = "distanceDataProvider") + public Object[][] distanceDataProvider() { + return new Object[][]{ + {5, 10, new int[]{0}, new int[]{0}, 15}, + {5, 10, new int[]{0}, new int[]{10}, 5}, + {5, 10, new int[]{5}, new int[]{0}, 10}, + {5, 10, new int[]{5}, new int[]{10}, 0}, + {5, 10, new int[]{1, 3, 7}, new int[]{9, 12}, 11}, + {0, 0, new int[]{0, 0, 0}, new int[]{0, 0}, 0}, + {-5, -10, new int[]{-1, -3, -7}, new int[]{-9, -12}, 11}, + }; + } + + @Test(dataProvider = "distanceDataProvider") + public void testGetDistance(int posA, int posB, int[] starts, int[] ends, long expectedDistance) { + final long actualDistance = CanonicalSVCollapser.getDistance(posA, posB, starts, ends); + Assert.assertEquals(actualDistance, expectedDistance); + } + private static void collapseIntervalTestHelper(final CanonicalSVCollapser collapser, final GATKSVVCFConstants.StructuralVariantAnnotationType svtype, final String[] contigs, From 85956ddb51c7b2f4edb5ad70754d5078ddb5475c Mon Sep 17 00:00:00 2001 From: Mark Walker Date: Tue, 11 Jul 2023 15:49:43 -0400 Subject: [PATCH 2/2] Reviewer suggestion --- .../hellbender/tools/sv/cluster/CanonicalSVCollapser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapser.java b/src/main/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapser.java index 91e311025b5..12d93a3baa2 100644 --- a/src/main/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapser.java +++ b/src/main/java/org/broadinstitute/hellbender/tools/sv/cluster/CanonicalSVCollapser.java @@ -181,7 +181,7 @@ public SVCallRecord collapse(final SVClusterEngine.OutputCluster cluster) { final Allele refAllele = collapseRefAlleles(representative.getContigA(), start); final List altAlleles; if (type == GATKSVVCFConstants.StructuralVariantAnnotationType.BND) { - altAlleles = Collections.singletonList(constructBndAllele(strandA, representative.getStrandB(), representative.getContigB(), end, refAllele)); + altAlleles = Collections.singletonList(constructBndAllele(strandA, strandB, representative.getContigB(), end, refAllele)); } else { altAlleles = collapseAltAlleles(items); }