diff --git a/orange-datamodel/src/main/java/com/hartwig/hmftools/datamodel/purple/ChromosomalRearrangements.java b/orange-datamodel/src/main/java/com/hartwig/hmftools/datamodel/purple/ChromosomalRearrangements.java new file mode 100644 index 0000000000..2755329c06 --- /dev/null +++ b/orange-datamodel/src/main/java/com/hartwig/hmftools/datamodel/purple/ChromosomalRearrangements.java @@ -0,0 +1,16 @@ +package com.hartwig.hmftools.datamodel.purple; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@Gson.TypeAdapters +@Value.Immutable +@Value.Style(passAnnotations = { NotNull.class, Nullable.class }) +public interface ChromosomalRearrangements +{ + boolean hasTrisomy1q(); + + boolean hasCodeletion1p19q(); +} diff --git a/orange-datamodel/src/main/java/com/hartwig/hmftools/datamodel/purple/PurpleRecord.java b/orange-datamodel/src/main/java/com/hartwig/hmftools/datamodel/purple/PurpleRecord.java index 01a7f249a9..5ad4d3d746 100644 --- a/orange-datamodel/src/main/java/com/hartwig/hmftools/datamodel/purple/PurpleRecord.java +++ b/orange-datamodel/src/main/java/com/hartwig/hmftools/datamodel/purple/PurpleRecord.java @@ -21,6 +21,9 @@ public interface PurpleRecord @NotNull PurpleCharacteristics characteristics(); + @NotNull + ChromosomalRearrangements chromosomalRearrangements(); + @NotNull List somaticDrivers(); diff --git a/orange-datamodel/src/test/resources/minimally.empty.orange.json b/orange-datamodel/src/test/resources/minimally.empty.orange.json index cc7aedc797..701b1f0186 100644 --- a/orange-datamodel/src/test/resources/minimally.empty.orange.json +++ b/orange-datamodel/src/test/resources/minimally.empty.orange.json @@ -86,7 +86,11 @@ "allSomaticGeneCopyNumbers": [], "allSomaticGainsLosses": [], "reportableSomaticGainsLosses": [], - "suspectGeneCopyNumbersWithLOH": [] + "suspectGeneCopyNumbersWithLOH": [], + "chromosomalRearrangements": { + "hasTrisomy1q": false, + "hasCodeletion1p19q": false + } }, "linx": { "allSomaticStructuralVariants": [], diff --git a/orange-datamodel/src/test/resources/minimally.populated.orange.json b/orange-datamodel/src/test/resources/minimally.populated.orange.json index 10627ac96f..6507319c6c 100644 --- a/orange-datamodel/src/test/resources/minimally.populated.orange.json +++ b/orange-datamodel/src/test/resources/minimally.populated.orange.json @@ -324,7 +324,11 @@ "maxCopyNumber": 1.2, "minMinorAlleleCopyNumber": 0.4 } - ] + ], + "chromosomalRearrangements": { + "hasTrisomy1q": false, + "hasCodeletion1p19q": false + } }, "linx": { "allSomaticStructuralVariants": [ diff --git a/orange-datamodel/src/test/resources/real.orange.json b/orange-datamodel/src/test/resources/real.orange.json index 687e101ec4..6fa1cbab49 100644 --- a/orange-datamodel/src/test/resources/real.orange.json +++ b/orange-datamodel/src/test/resources/real.orange.json @@ -2,8 +2,8 @@ "sampleId": "Test", "samplingDate": { "year": 2024, - "month": 8, - "day": 1 + "month": 9, + "day": 12 }, "experimentType": "WHOLE_GENOME", "configuredPrimaryTumor": [ @@ -736,7 +736,11 @@ ], "reportableGermlineFullLosses": [], "allGermlineLossOfHeterozygosities": [], - "reportableGermlineLossOfHeterozygosities": [] + "reportableGermlineLossOfHeterozygosities": [], + "chromosomalRearrangements": { + "hasTrisomy1q": false, + "hasCodeletion1p19q": false + } }, "linx": { "somaticDrivers": [ diff --git a/orange/README.md b/orange/README.md index cbb6ae1ca8..02b0260199 100644 --- a/orange/README.md +++ b/orange/README.md @@ -145,6 +145,9 @@ interesting and added to the report: A maximum of 10 additional gains (sorted by minimum copy number) and 10 additional losses are reported as potentially interesting: - For a band with more than one gene amplified, the gene with the highest minimum copy number is picked. - For a band with a loss that has no losses reported in this band already, an arbitrary gene is picked. +- Potentially interesting chromosomal rearrangements: + 1. 1q trisomy: In case 98% of 1q has copy number > 2.8 AND 90% of 1q has copy number < 3.5 + 2. 1p19q co-deletion: In case 98% of 1p and 98% of 19q have MACN < 0.2 - Other potentially relevant fusions. A maximum of 10 additional fusions (picked arbitrarily) are reported as potentially interesting: 1. Any fusion that is not reported and has a reported type other than NONE. 2. Any fusion in a gene that is configured as an oncogene in the driver gene panel. @@ -264,6 +267,7 @@ investigate potential causes for QC failure. - Upcoming: - Add presence of tumor stats to quality control page and to orange-datamodel - Ensure only exonic variants that are phased with reported variants are shown in 'potentially interesting' section + - Add potentially interesting chromosomal rearrangements (1q trisomy and 1p19q co-deletion) to report - [3.7.0](https://github.com/hartwigmedical/hmftools/releases/tag/orange-v3.7.0): - Add unreported reason to fusions in ORANGE - Add etiology information to signatures and sort by allocation diff --git a/orange/src/main/java/com/hartwig/hmftools/orange/algo/OrangeAlgo.java b/orange/src/main/java/com/hartwig/hmftools/orange/algo/OrangeAlgo.java index 4293d9350d..e20a6def0d 100644 --- a/orange/src/main/java/com/hartwig/hmftools/orange/algo/OrangeAlgo.java +++ b/orange/src/main/java/com/hartwig/hmftools/orange/algo/OrangeAlgo.java @@ -23,8 +23,6 @@ import com.hartwig.hmftools.common.drivercatalog.panel.DriverGene; import com.hartwig.hmftools.common.drivercatalog.panel.DriverGeneFile; import com.hartwig.hmftools.common.ensemblcache.EnsemblDataCache; -import com.hartwig.hmftools.common.metrics.BamFlagStats; -import com.hartwig.hmftools.common.metrics.BamMetricsSummary; import com.hartwig.hmftools.common.fusion.KnownFusionCache; import com.hartwig.hmftools.common.genome.refgenome.RefGenomeVersion; import com.hartwig.hmftools.common.hla.LilacSummaryData; @@ -32,6 +30,8 @@ import com.hartwig.hmftools.common.isofox.IsofoxDataLoader; import com.hartwig.hmftools.common.linx.LinxData; import com.hartwig.hmftools.common.linx.LinxDataLoader; +import com.hartwig.hmftools.common.metrics.BamFlagStats; +import com.hartwig.hmftools.common.metrics.BamMetricsSummary; import com.hartwig.hmftools.common.peach.PeachGenotype; import com.hartwig.hmftools.common.peach.PeachGenotypeFile; import com.hartwig.hmftools.common.pipeline.PipelineVersionFile; @@ -68,6 +68,7 @@ import com.hartwig.hmftools.orange.algo.plot.DummyPlotManager; import com.hartwig.hmftools.orange.algo.plot.FileBasedPlotManager; import com.hartwig.hmftools.orange.algo.plot.PlotManager; +import com.hartwig.hmftools.orange.algo.purple.ChromosomalRearrangementsDeterminer; import com.hartwig.hmftools.orange.algo.purple.GermlineGainLossFactory; import com.hartwig.hmftools.orange.algo.purple.GermlineLossOfHeterozygosityFactory; import com.hartwig.hmftools.orange.algo.purple.PurpleData; @@ -207,8 +208,10 @@ public OrangeRecord run(@NotNull OrangeConfig config) throws Exception PurpleVariantFactory purpleVariantFactory = new PurpleVariantFactory(pave); GermlineGainLossFactory germlineGainLossFactory = new GermlineGainLossFactory(ensemblDataCache); GermlineLossOfHeterozygosityFactory germlineLOHFactory = new GermlineLossOfHeterozygosityFactory(ensemblDataCache); + ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer = + ChromosomalRearrangementsDeterminer.createForRefGenomeVersion(config.refGenomeVersion()); PurpleInterpreter purpleInterpreter = new PurpleInterpreter(purpleVariantFactory, germlineGainLossFactory, - germlineLOHFactory, driverGenes, linx, chord, config.convertGermlineToSomatic()); + germlineLOHFactory, driverGenes, linx, chromosomalRearrangementsDeterminer, chord, config.convertGermlineToSomatic()); PurpleRecord purple = purpleInterpreter.interpret(purpleData); ImmuneEscapeRecord immuneEscape = ImmuneEscapeInterpreter.interpret(purple, linx); diff --git a/orange/src/main/java/com/hartwig/hmftools/orange/algo/purple/ChromosomalRearrangementsDeterminer.java b/orange/src/main/java/com/hartwig/hmftools/orange/algo/purple/ChromosomalRearrangementsDeterminer.java new file mode 100644 index 0000000000..d267b3874a --- /dev/null +++ b/orange/src/main/java/com/hartwig/hmftools/orange/algo/purple/ChromosomalRearrangementsDeterminer.java @@ -0,0 +1,107 @@ +package com.hartwig.hmftools.orange.algo.purple; + +import java.util.List; + +import com.google.common.annotations.VisibleForTesting; +import com.hartwig.hmftools.common.genome.refgenome.RefGenomeCoordinates; +import com.hartwig.hmftools.common.genome.refgenome.RefGenomeFunctions; +import com.hartwig.hmftools.common.purple.PurpleCopyNumber; +import com.hartwig.hmftools.datamodel.orange.OrangeRefGenomeVersion; + +import org.jetbrains.annotations.NotNull; + +public final class ChromosomalRearrangementsDeterminer +{ + @NotNull + private final RefGenomeCoordinates refGenomeCoordinates; + + @NotNull + public static ChromosomalRearrangementsDeterminer createForRefGenomeVersion(@NotNull final OrangeRefGenomeVersion refGenomeVersion) + { + return new ChromosomalRearrangementsDeterminer(resolveRefGenomeCoordinates(refGenomeVersion)); + } + + @VisibleForTesting + ChromosomalRearrangementsDeterminer(@NotNull final RefGenomeCoordinates refGenomeCoordinates) + { + this.refGenomeCoordinates = refGenomeCoordinates; + } + + private static final double LOWER_THRESHOLD_TRISOMY = 2.8; + private static final double UPPER_THRESHOLD_TRISOMY = 3.5; + private static final double THRESHOLD_DELETION = 0.2; + private static final double LOWER_LIMIT_PERCENTAGE_TRISOMY = 0.98; + private static final double UPPER_LIMIT_PERCENTAGE_TRISOMY = 0.90; + private static final double UPPER_LIMIT_PERCENTAGE_DELETION = 0.98; + + private static final String CHR_1 = "1"; + private static final String CHR_19 = "19"; + + public boolean determine1qTrisomy(@NotNull List allSomaticCopyNumbers) + { + int centromere1 = refGenomeCoordinates.centromere(CHR_1); + int length1QArm = refGenomeCoordinates.length(CHR_1) - centromere1; + int lengthAboveLowerThreshold = 0; + int lengthBelowUpperThreshold = 0; + + for(PurpleCopyNumber copyNumber : allSomaticCopyNumbers) + { + String chromosome = RefGenomeFunctions.stripChrPrefix(copyNumber.chromosome()); + if(chromosome.equals(CHR_1) && overlapsWithQArm(copyNumber, centromere1)) + { + int length = copyNumber.start() > centromere1 ? copyNumber.length() : copyNumber.end() - centromere1; + + if(copyNumber.averageTumorCopyNumber() > LOWER_THRESHOLD_TRISOMY) + { + lengthAboveLowerThreshold += length; + } + if(copyNumber.averageTumorCopyNumber() < UPPER_THRESHOLD_TRISOMY) + { + lengthBelowUpperThreshold += length; + } + } + } + + return (double) lengthAboveLowerThreshold / length1QArm > LOWER_LIMIT_PERCENTAGE_TRISOMY + && (double) lengthBelowUpperThreshold / length1QArm > UPPER_LIMIT_PERCENTAGE_TRISOMY; + } + + public boolean determine1p19qCodeletion(@NotNull List allSomaticCopyNumbers) + { + int centromere1 = refGenomeCoordinates.centromere(CHR_1); + int centromere19 = refGenomeCoordinates.centromere(CHR_19); + int length19QArm = refGenomeCoordinates.length(CHR_19) - centromere19; + int lengthDeletion1p = 0; + int lengthDeletionChr19 = 0; + + for(PurpleCopyNumber copyNumber : allSomaticCopyNumbers) + { + String chromosome = RefGenomeFunctions.stripChrPrefix(copyNumber.chromosome()); + if(chromosome.equals(CHR_1) && copyNumber.start() < centromere1 && copyNumber.minorAlleleCopyNumber() < THRESHOLD_DELETION) + { + int length = copyNumber.end() < centromere1 ? copyNumber.length() : centromere1 - copyNumber.start() + 1; + lengthDeletion1p += length; + } + if(chromosome.equals(CHR_19) && overlapsWithQArm(copyNumber, centromere19) + && copyNumber.minorAlleleCopyNumber() < THRESHOLD_DELETION) + { + int length = copyNumber.start() > centromere19 ? copyNumber.length() : copyNumber.end() - centromere19; + lengthDeletionChr19 += length; + } + } + + return (double) lengthDeletion1p / centromere1 > UPPER_LIMIT_PERCENTAGE_DELETION + && (double) lengthDeletionChr19 / length19QArm > UPPER_LIMIT_PERCENTAGE_DELETION; + } + + @NotNull + private static RefGenomeCoordinates resolveRefGenomeCoordinates(@NotNull OrangeRefGenomeVersion refGenomeVersion) + { + return refGenomeVersion == OrangeRefGenomeVersion.V38 ? RefGenomeCoordinates.COORDS_38 : RefGenomeCoordinates.COORDS_37; + } + + private static boolean overlapsWithQArm(@NotNull PurpleCopyNumber copyNumber, int centromere) + { + return copyNumber.start() > centromere || (copyNumber.start() <= centromere && centromere < copyNumber.end()); + } +} diff --git a/orange/src/main/java/com/hartwig/hmftools/orange/algo/purple/PurpleInterpreter.java b/orange/src/main/java/com/hartwig/hmftools/orange/algo/purple/PurpleInterpreter.java index 2874263270..c3cbb747d6 100644 --- a/orange/src/main/java/com/hartwig/hmftools/orange/algo/purple/PurpleInterpreter.java +++ b/orange/src/main/java/com/hartwig/hmftools/orange/algo/purple/PurpleInterpreter.java @@ -33,6 +33,8 @@ import com.hartwig.hmftools.datamodel.linx.LinxBreakendType; import com.hartwig.hmftools.datamodel.linx.LinxRecord; import com.hartwig.hmftools.datamodel.linx.LinxSvAnnotation; +import com.hartwig.hmftools.datamodel.purple.ChromosomalRearrangements; +import com.hartwig.hmftools.datamodel.purple.ImmutableChromosomalRearrangements; import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleCharacteristics; import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleFit; import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleGainLoss; @@ -68,6 +70,8 @@ public class PurpleInterpreter private final List driverGenes; @NotNull private final LinxRecord linx; + @NotNull + private final ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer; @Nullable private final ChordData chord; boolean convertGermlineToSomatic; @@ -75,7 +79,9 @@ public class PurpleInterpreter public PurpleInterpreter(@NotNull final PurpleVariantFactory purpleVariantFactory, @NotNull final GermlineGainLossFactory germlineGainLossFactory, @NotNull final GermlineLossOfHeterozygosityFactory germlineLossOfHeterozygosityFactory, - @NotNull final List driverGenes, @NotNull final LinxRecord linx, @Nullable final ChordData chord, + @NotNull final List driverGenes, @NotNull final LinxRecord linx, + @NotNull ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer, + @Nullable final ChordData chord, boolean convertGermlineToSomatic) { this.purpleVariantFactory = purpleVariantFactory; @@ -83,6 +89,7 @@ public PurpleInterpreter(@NotNull final PurpleVariantFactory purpleVariantFactor this.germlineLossOfHeterozygosityFactory = germlineLossOfHeterozygosityFactory; this.driverGenes = driverGenes; this.linx = linx; + this.chromosomalRearrangementsDeterminer = chromosomalRearrangementsDeterminer; this.chord = chord; this.convertGermlineToSomatic = convertGermlineToSomatic; } @@ -186,6 +193,7 @@ public PurpleRecord interpret(@NotNull PurpleData purple) .reportableGermlineFullLosses(reportableGermlineFullLosses) .allGermlineLossOfHeterozygosities(allGermlineLossOfHeterozygosities) .reportableGermlineLossOfHeterozygosities(reportableGermlineLossOfHeterozygosities) + .chromosomalRearrangements(createChromosomalRearrangements(purple, chromosomalRearrangementsDeterminer)) .build(); } @@ -444,4 +452,14 @@ private static PurpleCharacteristics createCharacteristics(@NotNull PurpleData p .svTumorMutationalBurden(purple.purityContext().svTumorMutationalBurden()) .build(); } + + @NotNull + private static ChromosomalRearrangements createChromosomalRearrangements(@NotNull PurpleData purple, + @NotNull ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer) + { + return ImmutableChromosomalRearrangements.builder() + .hasTrisomy1q(chromosomalRearrangementsDeterminer.determine1qTrisomy(purple.allSomaticCopyNumbers())) + .hasCodeletion1p19q(chromosomalRearrangementsDeterminer.determine1p19qCodeletion(purple.allSomaticCopyNumbers())) + .build(); + } } diff --git a/orange/src/main/java/com/hartwig/hmftools/orange/report/chapters/SomaticFindingsChapter.java b/orange/src/main/java/com/hartwig/hmftools/orange/report/chapters/SomaticFindingsChapter.java index a870c0e3d8..74b9267906 100644 --- a/orange/src/main/java/com/hartwig/hmftools/orange/report/chapters/SomaticFindingsChapter.java +++ b/orange/src/main/java/com/hartwig/hmftools/orange/report/chapters/SomaticFindingsChapter.java @@ -6,6 +6,7 @@ import com.hartwig.hmftools.datamodel.linx.FusionLikelihoodType; import com.hartwig.hmftools.datamodel.linx.LinxFusion; import com.hartwig.hmftools.datamodel.orange.OrangeRecord; +import com.hartwig.hmftools.datamodel.purple.ChromosomalRearrangements; import com.hartwig.hmftools.datamodel.purple.CopyNumberInterpretation; import com.hartwig.hmftools.datamodel.purple.PurpleDriver; import com.hartwig.hmftools.datamodel.purple.PurpleGainLoss; @@ -23,6 +24,7 @@ import com.hartwig.hmftools.orange.report.interpretation.PurpleQCInterpretation; import com.hartwig.hmftools.orange.report.interpretation.VariantDedup; import com.hartwig.hmftools.orange.report.tables.BreakendTable; +import com.hartwig.hmftools.orange.report.tables.ChromosomalRearrangementsTable; import com.hartwig.hmftools.orange.report.tables.DnaFusionTable; import com.hartwig.hmftools.orange.report.tables.GainLossTable; import com.hartwig.hmftools.orange.report.tables.HomozygousDisruptionTable; @@ -158,6 +160,7 @@ private void addSomaticAmpDels(@NotNull Document document) String nearDriverGainsTitle = "Potentially interesting near-driver amps"; String suspectGainsTitle = "Other regions with amps"; String suspectLossesTitle = "Regions with deletions in genes in other autosomal regions"; + String chromosomalRearrangementsTitle = "Potentially interesting chromosomal rearrangements"; if(PurpleQCInterpretation.isContaminated(report.purple().fit().qc())) { @@ -166,6 +169,7 @@ private void addSomaticAmpDels(@NotNull Document document) document.add(tables.createNotAvailable(nearDriverGainsTitle, contentWidth())); document.add(tables.createNotAvailable(suspectGainsTitle, contentWidth())); document.add(tables.createNotAvailable(suspectLossesTitle, contentWidth())); + document.add(tables.createNotAvailable(chromosomalRearrangementsTitle, contentWidth())); } else { @@ -190,6 +194,9 @@ private void addSomaticAmpDels(@NotNull Document document) List suspectLosses = selectLosses(report.purple().additionalSuspectSomaticGainsLosses()); String titleSuspectLosses = suspectLossesTitle + " (" + suspectLosses.size() + ")"; document.add(GainLossTable.build(titleSuspectLosses, contentWidth(), max10(suspectLosses), report.isofox(), reportResources)); + + ChromosomalRearrangements chromosomalRearrangements = report.purple().chromosomalRearrangements(); + document.add(ChromosomalRearrangementsTable.build(chromosomalRearrangementsTitle, contentWidth(), chromosomalRearrangements, reportResources)); } } diff --git a/orange/src/main/java/com/hartwig/hmftools/orange/report/tables/ChromosomalRearrangementsTable.java b/orange/src/main/java/com/hartwig/hmftools/orange/report/tables/ChromosomalRearrangementsTable.java new file mode 100644 index 0000000000..8056083ebd --- /dev/null +++ b/orange/src/main/java/com/hartwig/hmftools/orange/report/tables/ChromosomalRearrangementsTable.java @@ -0,0 +1,35 @@ +package com.hartwig.hmftools.orange.report.tables; + +import com.hartwig.hmftools.datamodel.purple.ChromosomalRearrangements; +import com.hartwig.hmftools.orange.report.ReportResources; +import com.hartwig.hmftools.orange.report.util.Cells; +import com.hartwig.hmftools.orange.report.util.Tables; +import com.itextpdf.layout.element.Cell; +import com.itextpdf.layout.element.Table; + +import org.apache.logging.log4j.util.Strings; +import org.jetbrains.annotations.NotNull; + +public final class ChromosomalRearrangementsTable +{ + @NotNull + public static Table build(@NotNull String title, float width, @NotNull ChromosomalRearrangements chromosomalRearrangements, + @NotNull ReportResources reportResources) + { + Cells cells = new Cells(reportResources); + Table table = Tables.createContent(width, + new float[] { 2, 1, 3 }, + new Cell[] { cells.createHeader("Chromosomal rearrangement"), cells.createHeader("Detected?"), + cells.createHeader(Strings.EMPTY) }); + + table.addCell(cells.createContent("1q trisomy")); + table.addCell(cells.createContent(chromosomalRearrangements.hasTrisomy1q() ? "Yes" : "No")); + table.addCell(cells.createContent(Strings.EMPTY)); + + table.addCell(cells.createContent("1p19q co-deletion")); + table.addCell(cells.createContent(chromosomalRearrangements.hasCodeletion1p19q() ? "Yes" : "No")); + table.addCell(cells.createContent(Strings.EMPTY)); + + return new Tables(reportResources).createWrapping(table, title); + } +} diff --git a/orange/src/main/resources/COLO829_Targeted_TumorOnly.orange.pdf b/orange/src/main/resources/COLO829_Targeted_TumorOnly.orange.pdf index 0c4b46a8a3..3aee50a69c 100644 Binary files a/orange/src/main/resources/COLO829_Targeted_TumorOnly.orange.pdf and b/orange/src/main/resources/COLO829_Targeted_TumorOnly.orange.pdf differ diff --git a/orange/src/main/resources/COLO829_WGS_TumorReference.orange.pdf b/orange/src/main/resources/COLO829_WGS_TumorReference.orange.pdf index 91b4c89618..c921360d71 100644 Binary files a/orange/src/main/resources/COLO829_WGS_TumorReference.orange.pdf and b/orange/src/main/resources/COLO829_WGS_TumorReference.orange.pdf differ diff --git a/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/ChromosomalRearrangementsDeterminerTest.java b/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/ChromosomalRearrangementsDeterminerTest.java new file mode 100644 index 0000000000..90e5b2c4cb --- /dev/null +++ b/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/ChromosomalRearrangementsDeterminerTest.java @@ -0,0 +1,132 @@ +package com.hartwig.hmftools.orange.algo.purple; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.Lists; +import com.hartwig.hmftools.common.genome.refgenome.RefGenomeCoordinates; +import com.hartwig.hmftools.common.purple.PurpleCopyNumber; +import com.hartwig.hmftools.common.purple.PurpleTestUtils; + +import org.jetbrains.annotations.NotNull; +import org.junit.Test; + +public class ChromosomalRearrangementsDeterminerTest +{ + private static final RefGenomeCoordinates REF_COORDINATES_V37 = RefGenomeCoordinates.COORDS_37; + private static final ChromosomalRearrangementsDeterminer CHROMOSOMAL_REARRANGEMENTS_DETERMINER_V37 = + new ChromosomalRearrangementsDeterminer(REF_COORDINATES_V37); + + private static final RefGenomeCoordinates REF_COORDINATES_38 = RefGenomeCoordinates.COORDS_38; + private static final ChromosomalRearrangementsDeterminer CHROMOSOMAL_REARRANGEMENTS_DETERMINER_V38 = + new ChromosomalRearrangementsDeterminer(REF_COORDINATES_38); + + @Test + public void canDetermine1qTrisomyV37() + { + int centromere1 = REF_COORDINATES_V37.centromere("1"); + int endChromosome1 = REF_COORDINATES_V37.length("1"); + canDetermine1qTrisomy(centromere1, endChromosome1, CHROMOSOMAL_REARRANGEMENTS_DETERMINER_V37); + } + + @Test + public void canDetermine1qTrisomyV38() + { + int centromere1 = REF_COORDINATES_38.centromere("chr1"); + int endChromosome1 = REF_COORDINATES_38.length("chr1"); + canDetermine1qTrisomy(centromere1, endChromosome1, CHROMOSOMAL_REARRANGEMENTS_DETERMINER_V38); + } + + @Test + public void canDetermine1p19qCoDeletionV37() + { + int centromere1 = REF_COORDINATES_V37.centromere("1"); + int centromere19 = REF_COORDINATES_V37.centromere("19"); + int endChromosome19 = REF_COORDINATES_V37.length("19"); + canDetermine1p19qCoDeletion(centromere1, centromere19, endChromosome19, CHROMOSOMAL_REARRANGEMENTS_DETERMINER_V37); + } + + @Test + public void canDetermine1p19qCoDeletionV38() + { + int centromere1 = REF_COORDINATES_38.centromere("chr1"); + int centromere19 = REF_COORDINATES_38.centromere("chr19"); + int endChromosome19 = REF_COORDINATES_38.length("chr19"); + canDetermine1p19qCoDeletion(centromere1, centromere19, endChromosome19, CHROMOSOMAL_REARRANGEMENTS_DETERMINER_V38); + } + + private static void canDetermine1qTrisomy(int centromere1, int endChromosome1, + ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer) + { + int stepSize = (endChromosome1 - centromere1) / 4; + List steps = createSteps(stepSize, centromere1 - 3000000, endChromosome1); + + List arm1Q = Lists.newArrayList( + copyNumber("1", steps.get(0), steps.get(1), 3), + copyNumber("1", steps.get(1) + 1, steps.get(2), 2.9), + copyNumber("1", steps.get(2) + 1, steps.get(3), 2.9) + ); + List with1qTrisomy = new ArrayList<>(arm1Q); + with1qTrisomy.add(copyNumber("1", steps.get(3) + 1, endChromosome1, 3.1)); + List without1qTrisomy = new ArrayList<>(arm1Q); + without1qTrisomy.add(copyNumber("1", steps.get(3) + 1, endChromosome1, 2.5)); + assertTrue(chromosomalRearrangementsDeterminer.determine1qTrisomy(with1qTrisomy)); + assertFalse(chromosomalRearrangementsDeterminer.determine1qTrisomy(without1qTrisomy)); + } + + private static void canDetermine1p19qCoDeletion(int centromere1, int centromere19, int endChromosome19, + ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer) + { + int stepSize1 = centromere1 / 4; + List steps1 = createSteps(stepSize1, 1, centromere1 + 3000000); + + int stepSize19 = (endChromosome19 - centromere1) / 4; + List steps19 = createSteps(stepSize19, centromere19 - 3000000, endChromosome19); + + List arm1p = Lists.newArrayList(copyNumber("1", 1, steps1.get(1), 0.1), copyNumber("1", + steps1.get(1) + 1, steps1.get(2), 0.15), copyNumber("1", steps1.get(2) + 1, steps1.get(3), 0.1)); + List arm19q = Lists.newArrayList(copyNumber("19", steps19.get(0), steps19.get(1), 0.1), copyNumber("19", + steps19.get(1) + 1, steps19.get(2), 0.15), copyNumber("19", steps19.get(2) + 1, steps19.get(3), 0.1)); + + List withDeletion1p = new ArrayList<>(arm1p); + withDeletion1p.add(copyNumber("1", steps1.get(3) + 1, centromere1 + 3000000, 0.1)); + List withoutDeletion1p = new ArrayList<>(arm1p); + withoutDeletion1p.add(copyNumber("1", steps1.get(3) + 1, centromere1 + 3000000, 0.9)); + + List withDeletion19q = new ArrayList<>(arm19q); + withDeletion19q.add(copyNumber("19", steps19.get(3) + 1, endChromosome19, 0.1)); + List withoutDeletion19q = new ArrayList<>(arm19q); + withoutDeletion19q.add(copyNumber("19", steps19.get(3) + 1, endChromosome19, 0.9)); + + List with1pDeletionAndWith19QDeletion = Lists.newArrayList(withDeletion1p); + with1pDeletionAndWith19QDeletion.addAll(withDeletion19q); + List with1pDeletionAndWithout19QDeletion = Lists.newArrayList(withDeletion1p); + with1pDeletionAndWithout19QDeletion.addAll(withoutDeletion19q); + List without1pDeletionAndWith19QDeletion = Lists.newArrayList(withoutDeletion1p); + without1pDeletionAndWith19QDeletion.addAll(withDeletion19q); + + assertTrue(chromosomalRearrangementsDeterminer.determine1p19qCodeletion(with1pDeletionAndWith19QDeletion)); + assertFalse(chromosomalRearrangementsDeterminer.determine1p19qCodeletion(with1pDeletionAndWithout19QDeletion)); + assertFalse(chromosomalRearrangementsDeterminer.determine1p19qCodeletion(without1pDeletionAndWith19QDeletion)); + } + + @NotNull + private static PurpleCopyNumber copyNumber(String chromosome, int start, int end, double copyNumber) + { + return PurpleTestUtils.createCopyNumber(chromosome, start, end, copyNumber).build(); + } + + @NotNull + private static List createSteps(int stepSize, int start, int end) + { + List steps = new ArrayList<>(); + for(int i = start; i < end; i += stepSize) + { + steps.add(i); + } + return steps; + } +} diff --git a/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/PurpleInterpreterTest.java b/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/PurpleInterpreterTest.java index 24a78fc660..9a911d84ba 100644 --- a/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/PurpleInterpreterTest.java +++ b/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/PurpleInterpreterTest.java @@ -24,6 +24,7 @@ import com.hartwig.hmftools.datamodel.linx.LinxBreakend; import com.hartwig.hmftools.datamodel.linx.LinxBreakendType; import com.hartwig.hmftools.datamodel.linx.LinxSvAnnotation; +import com.hartwig.hmftools.datamodel.orange.OrangeRefGenomeVersion; import com.hartwig.hmftools.datamodel.purple.PurpleRecord; import com.hartwig.hmftools.orange.algo.linx.LinxOrangeTestFactory; import com.hartwig.hmftools.orange.algo.linx.TestLinxInterpretationFactory; @@ -365,6 +366,8 @@ private static PurpleInterpreter createInterpreter(@NotNull EnsemblDataCache ens PurpleVariantFactory purpleVariantFactory = new PurpleVariantFactory(pave); GermlineGainLossFactory germlineGainLossFactory = new GermlineGainLossFactory(ensemblDataCache); GermlineLossOfHeterozygosityFactory germlineLossOfHeterozygosityFactory = new GermlineLossOfHeterozygosityFactory(ensemblDataCache); + ChromosomalRearrangementsDeterminer chromosomalRearrangementsDeterminer = + ChromosomalRearrangementsDeterminer.createForRefGenomeVersion(OrangeRefGenomeVersion.V37); return new PurpleInterpreter( purpleVariantFactory, @@ -372,6 +375,7 @@ private static PurpleInterpreter createInterpreter(@NotNull EnsemblDataCache ens germlineLossOfHeterozygosityFactory, Lists.newArrayList(), TestLinxInterpretationFactory.createMinimalTestLinxData(), + chromosomalRearrangementsDeterminer, null, false ); diff --git a/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/TestPurpleInterpretationFactory.java b/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/TestPurpleInterpretationFactory.java index 2780d5e634..573ed3838d 100644 --- a/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/TestPurpleInterpretationFactory.java +++ b/orange/src/test/java/com/hartwig/hmftools/orange/algo/purple/TestPurpleInterpretationFactory.java @@ -2,6 +2,8 @@ import static com.hartwig.hmftools.orange.algo.purple.TumorStatsFactoryTest.createMinimalTumorStatsBuilder; +import com.hartwig.hmftools.datamodel.purple.ChromosomalRearrangements; +import com.hartwig.hmftools.datamodel.purple.ImmutableChromosomalRearrangements; import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleCharacteristics; import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleFit; import com.hartwig.hmftools.datamodel.purple.ImmutablePurpleRecord; @@ -31,7 +33,8 @@ public static ImmutablePurpleRecord.Builder builder() return ImmutablePurpleRecord.builder() .fit(createMinimalTestFitData()) .tumorStats(createMinimalTumorStatsBuilder().build()) - .characteristics(createMinimalTestCharacteristicsData()); + .characteristics(createMinimalTestCharacteristicsData()) + .chromosomalRearrangements(createMinimalChromosomalRearrangements()); } @NotNull @@ -72,4 +75,13 @@ private static PurpleCharacteristics createMinimalTestCharacteristicsData() .svTumorMutationalBurden(0) .build(); } + + @NotNull + private static ChromosomalRearrangements createMinimalChromosomalRearrangements() + { + return ImmutableChromosomalRearrangements.builder() + .hasTrisomy1q(false) + .hasCodeletion1p19q(false) + .build(); + } }