Skip to content

Commit

Permalink
fix(reporter): fix matching diplotype-specific recommendations
Browse files Browse the repository at this point in the history
  • Loading branch information
whaleyr committed Aug 23, 2024
1 parent 1b1e332 commit 11fc7b4
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,12 @@ public boolean matchesGenotype(Genotype genotype) {
}
return genotype.getLookupKeys().stream().anyMatch(k -> RecommendationUtils.mapContains(k, getLookupKey()));
}

public boolean matchesDiplotype(Genotype genotype) {
if (getLookupKey() == null) {
return false;
}

return RecommendationUtils.mapContains(genotype.getDiplotypeKey(), getLookupKey());
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
package org.pharmgkb.pharmcat.reporter.model.result;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.*;
import java.util.stream.Collectors;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
Expand Down Expand Up @@ -90,6 +80,9 @@ public class Diplotype implements Comparable<Diplotype> {
@Expose
@SerializedName("phenotypeDataSource")
private DataSource m_phenotypeDataSource;
@Expose
@SerializedName("diplotypeKey")
private SortedMap<String,Double> m_diplotypeKey = new TreeMap<>(HaplotypeNameComparator.getComparator());


/**
Expand All @@ -109,6 +102,10 @@ public Diplotype(String gene, Haplotype h1, @Nullable Haplotype h2, Env env, Dat
m_allele2 = h2;
annotateDiplotype(env.getPhenotype(m_gene, source));
m_label = buildLabel(false);
addAlleleToDiplotypeKey(h1.getName());
if (h2 != null) {
addAlleleToDiplotypeKey(h2.getName());
}
}

public Diplotype(String gene, String hap1, @Nullable String hap2, Env env, DataSource source) {
Expand All @@ -118,6 +115,10 @@ public Diplotype(String gene, String hap1, @Nullable String hap2, Env env, DataS
m_allele2 = hap2 == null ? null : env.makeHaplotype(gene, hap2, source);
annotateDiplotype(env.getPhenotype(m_gene, source));
m_label = buildLabel(false);
addAlleleToDiplotypeKey(hap1);
if (hap2 != null) {
addAlleleToDiplotypeKey(hap2);
}
}

/**
Expand Down Expand Up @@ -344,6 +345,14 @@ public List<String> getLookupKeys() {
return m_lookupKeys;
}

public Map<String,Double> getDiplotypeKey() {
return m_diplotypeKey;
}

private void addAlleleToDiplotypeKey(String allele) {
m_diplotypeKey.compute(allele, (k, v) -> v == null ? 1 : v + 1);
}


/**
* True if this diplotype does not use allele function to assign phenotype but instead relies on the presence or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import com.google.gson.annotations.Expose;
Expand All @@ -22,6 +24,8 @@ public class Genotype implements Comparable<Genotype> {

private transient List<Map<String, Object>> m_lookupKeys;

private transient SortedMap<String, Object> m_diplotypeKey = new TreeMap<>();


/**
* Private constructor for GSON.
Expand Down Expand Up @@ -52,6 +56,8 @@ private void addDiplotype(Diplotype diplotype) {
}
m_diplotypes.add(diplotype);

m_diplotypeKey.put(diplotype.getGene(), diplotype.getDiplotypeKey());

if (m_lookupKeys == null) {
m_lookupKeys = diplotype.getLookupKeys().stream()
.map((k) -> {
Expand Down Expand Up @@ -109,6 +115,10 @@ public List<Map<String, Object>> getLookupKeys() {
return m_lookupKeys;
}

public Map<String, Object> getDiplotypeKey() {
return m_diplotypeKey;
}


/**
* Make a List of possible {@link Genotype} objects from different combinations of reporter diplotypes in the given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,20 @@ public boolean isFda() {
private void matchAnnotations(GuidelinePackage guidelinePackage, String drugName) {
HashMultimap<RecommendationAnnotation, Genotype> matchedGenotypes = HashMultimap.create();
for (Genotype genotype : m_recommendationGenotypes) {
guidelinePackage.getRecommendations().stream()
.filter(Objects::nonNull)
.filter(rec -> rec.appliesToDrug(drugName))
.filter(rec -> rec.matchesGenotype(genotype))
.forEach(rec -> matchedGenotypes.put(rec, genotype));
boolean matchedDiplotype = false;
for (RecommendationAnnotation rec : guidelinePackage.getRecommendations()) {
if (rec != null && rec.appliesToDrug(drugName) && rec.matchesDiplotype(genotype)) {
matchedGenotypes.put(rec, genotype);
matchedDiplotype = true;
}
}
if (!matchedDiplotype) {
guidelinePackage.getRecommendations().stream()
.filter(Objects::nonNull)
.filter(rec -> rec.appliesToDrug(drugName))
.filter(rec -> rec.matchesGenotype(genotype))
.forEach(rec -> matchedGenotypes.put(rec, genotype));
}
}
if (drugName.equals("warfarin") && m_source == PrescribingGuidanceSource.CPIC_GUIDELINE) {
AnnotationReport ann = AnnotationReport.forCpicWarfarin(m_recommendationGenotypes);
Expand Down
33 changes: 32 additions & 1 deletion src/test/java/org/pharmgkb/pharmcat/PipelineTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1701,8 +1701,11 @@ void testRecommendationExamples(TestInfo testInfo) throws Exception {
testWrapper.testMatchedAnnotations("flucloxacillin", PrescribingGuidanceSource.DPWG_GUIDELINE, 1);
testWrapper.testNoMatchFromSource("fluvoxamine", PrescribingGuidanceSource.CPIC_GUIDELINE);
testWrapper.testNoMatchFromSource("fluvoxamine", PrescribingGuidanceSource.DPWG_GUIDELINE);
testWrapper.testMatchedAnnotations("siponimod", 1);

// siponimod has DPWG & FDA recs, DPWG uses traditional matching and FDA uses diplotype-specific matching
testWrapper.testMatchedAnnotations("siponimod", 2);
testWrapper.testAnyMatchFromSource("siponimod", PrescribingGuidanceSource.DPWG_GUIDELINE);
testWrapper.testAnyMatchFromSource("siponimod", PrescribingGuidanceSource.FDA_LABEL);

testWrapper.testMatchedAnnotations("carbamazepine", PrescribingGuidanceSource.CPIC_GUIDELINE, 3);
testWrapper.testMatchedAnnotations("carbamazepine", PrescribingGuidanceSource.DPWG_GUIDELINE, 1);
Expand Down Expand Up @@ -2381,6 +2384,34 @@ void testOutsideSinglePositionCalls(TestInfo testInfo) throws Exception {
}


/**
* This test ensures diplotype-specific recommendations override more generic phenotype-specific ones.
* Specifically, phenytoin has a recommendation for "poor metabolizers" which *2/*2 will match. However, it also has a
* recommendation for *2/*2 specifically which should "override" the poor metabolizer recommendation for this specific
* diplotype.
*/
@Test
void testDiplotypeOverrideRecommendation(TestInfo testInfo) throws Exception {
PipelineWrapper testWrapper = new PipelineWrapper(testInfo, false);
testWrapper.getVcfBuilder()
.reference("CYP2C9")
.variation("CYP2C9", "rs1799853", "T", "T");
testWrapper.execute();

testWrapper.testCalledByMatcher("CYP2C9");
testWrapper.testPrintCpicCalls( "CYP2C9", "*2/*2");
testWrapper.testSourceDiplotypes(DataSource.CPIC, "CYP2C9", List.of("*2/*2"));
testWrapper.testSourceDiplotypes(DataSource.DPWG, "CYP2C9", List.of("*2/*2"));

DrugReport phenytoin = testWrapper.getContext().getDrugReport(PrescribingGuidanceSource.DPWG_GUIDELINE, "phenytoin");
assertNotNull(phenytoin);
List<AnnotationReport> recs = phenytoin.getGuidelines().stream().flatMap((g) -> g.getAnnotations().stream()).toList();
assertEquals(1, recs.size());
AnnotationReport matchingRec = recs.get(0);
assertEquals("DPWG-PA166299254", recs.get(0).getLocalId());
}


@Test
void testDuplicateEntrySecondIsBad(TestInfo testInfo) throws Exception {
PipelineWrapper testWrapper = new PipelineWrapper(testInfo, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,13 @@ void testMapContains() {
// changing the value for key that exists in both maps should break containment
mapA.put("key1", "valueChanged");
assertFalse(RecommendationUtils.mapContains(mapA, mapB));

Map<String, Object> mapC = new HashMap<>();
Map<String, Object> mapD = new HashMap<>();
mapC.put("key1", Map.of("a1", 2));
mapC.put("key2", Map.of("a2", 2));
mapD.put("key1", Map.of("a1", 2));

assertTrue(RecommendationUtils.mapContains(mapC, mapD));
}
}

0 comments on commit 11fc7b4

Please sign in to comment.