From cabf9b6871e86a87e1849245033a14219052f0a1 Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Sat, 22 Jun 2024 17:14:42 +0200 Subject: [PATCH] more validations --- docs/cases/PMID_29127725.txt | 36 ++++ .../output/PPKtBuildingBlockGenerator.java | 4 + .../english/PPKtEnglishBuildingBlocks.java | 32 ++- .../impl/english/PpktIndividualEnglish.java | 184 +----------------- .../english/PpktPhenotypicFeatureEnglish.java | 2 +- .../PPKtEnglishBuildingBlocksTest.java | 22 +++ .../english/PpktIndividualEnglishTest.java | 6 +- 7 files changed, 95 insertions(+), 191 deletions(-) create mode 100644 docs/cases/PMID_29127725.txt create mode 100644 src/test/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PPKtEnglishBuildingBlocksTest.java diff --git a/docs/cases/PMID_29127725.txt b/docs/cases/PMID_29127725.txt new file mode 100644 index 0000000..14b5908 --- /dev/null +++ b/docs/cases/PMID_29127725.txt @@ -0,0 +1,36 @@ +[source] +pmid = PMID:29127725 +title = A loss-of-function homozygous mutation in DDX59 implicates a conserved DEAD-box RNA helicase in nervous system development and function +[diagnosis] +disease_id = OMIM:174300 +disease_label = Orofaciodigital syndrome V +[text] +Patient 1 was the first born from healthy parents, non-consanguineous for their account. +Family history was unremarkable, except for three prior spontaneous +miscarriages. The pregnancy was complicated by intrauterine growth +retardation. Delivery at term was normal, with a weight at birth of +2,350 g (<3rd centile), length of 47 cm (3rd centile), and occipital– +frontal circumference of 32 cm (5th centile). APGAR scores were 6 and +9 at 1 and 5 min, respectively. He had bilateral postaxial extra-digits +on his hands that were surgically removed in his late childhood. He +also had bilateral cutaneous syndactyly of fingers 2–5, clinodactyly of +the fifth fingers, and fingertip pads. His lower limbs were normal. Since +the first months of life, he developed generalized seizures, which were +controlled by anticonvulsant drugs. Developmental milestones were +delayed and the patient showed cognitive difficulties during childhood, +with an I.Q. of 70 (Terman-Merril scale) measured at the age +of 9 years. For these reasons, he has undergone developmental and +speech therapies since the age of 3 years. At the age of 17 years, his +height was 165 cm (3rd centile), weight was 67 kg (50th centile), and +head circumference 53 cm (10th centile). He had distinctive facial features, +including prominent thick eyebrows, malocclusion, high-arched +palate, and rounded prominent jaw (Figure 1G and H). +A cerebral magnetic resonance imaging (MRI) disclosed thinning of the cerebral cortex +in front of the ventricular collateral trigone (not shown). +Wakefulness electroencephalograms showed diffuse high amplitude slow +waves intermingled with sharp waves or spikes. Since early adulthood +he started to complain of migraine. As part of his neurological presentation, +he also presented lower limbs weakness and some walking difficulties. At the age of 30, after an episode of loss of consciousness +associated with generalized seizures, he underwent a follow-up brain +MRI scan, which showed diffuse white matter signal abnormalities and +multifocal cortical–subcortical infarcts involving both cerebral hemispheres (Figure 1P and Q). diff --git a/src/main/java/org/monarchinitiative/phenopacket2prompt/output/PPKtBuildingBlockGenerator.java b/src/main/java/org/monarchinitiative/phenopacket2prompt/output/PPKtBuildingBlockGenerator.java index 57283bb..7202781 100644 --- a/src/main/java/org/monarchinitiative/phenopacket2prompt/output/PPKtBuildingBlockGenerator.java +++ b/src/main/java/org/monarchinitiative/phenopacket2prompt/output/PPKtBuildingBlockGenerator.java @@ -1,6 +1,8 @@ package org.monarchinitiative.phenopacket2prompt.output; +import org.monarchinitiative.phenopacket2prompt.model.Iso8601Age; + /** * Provide the "building blocks" (i.e., text fragments) needed to generate the * texts in the various languages. @@ -127,4 +129,6 @@ public interface PPKtBuildingBlockGenerator { String asMiddleAge(); String asLateOnset(); + + String fromIso(Iso8601Age ppktAge); } diff --git a/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PPKtEnglishBuildingBlocks.java b/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PPKtEnglishBuildingBlocks.java index 785d5ea..f597bfe 100644 --- a/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PPKtEnglishBuildingBlocks.java +++ b/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PPKtEnglishBuildingBlocks.java @@ -1,7 +1,11 @@ package org.monarchinitiative.phenopacket2prompt.output.impl.english; +import org.monarchinitiative.phenopacket2prompt.model.Iso8601Age; import org.monarchinitiative.phenopacket2prompt.output.PPKtBuildingBlockGenerator; +import java.util.ArrayList; +import java.util.List; + public class PPKtEnglishBuildingBlocks implements PPKtBuildingBlockGenerator { @@ -20,6 +24,26 @@ public String years(int y) { return y>1 ? "years" : "year"; } + + + @Override + public String fromIso(Iso8601Age ppktAge) { + List components = new ArrayList<>(); + int y = ppktAge.getYears(); + int m = ppktAge.getMonths(); + int d = ppktAge.getDays(); + if (y > 0) { + components.add(String.format("%d %s", y, years(y))); + } + if (m > 0) { + components.add(String.format("%d %s", m, months(y))); + } + if (d > 0) { + components.add(String.format("%d %s", d, days(y))); + } + return String.join(" ", components); + } + @Override public String yearsOld(int y) { return String.format("%d-year-old", y); @@ -42,7 +66,7 @@ public String monthDayOld(int m, int d) { } else if (d==0) { return monthsOld(m); } - return String.format("%d-%s, %d-%s old", m, months(m), d, days(d)); + return String.format("%d-month, %d-day old", m, d); } @Override @@ -51,9 +75,9 @@ public String yearsMonthsDaysOld(int y, int m, int d) { return monthDayOld(m,d); } if (d==0) { - return String.format("%d-%s, %d-%s old", y, years(y), m, months(m)); + return String.format("%d-year, %d-month old", y, m); } - return String.format("%d-%s, %d-%s, %d-%s old", y, years(y), m, months(m), d, days(d)); + return String.format("%d-year, %d-month, %d-day old", y, m, d); } @Override @@ -299,4 +323,6 @@ public String asMiddleAge() { public String asLateOnset() { return "During old age"; } + + } diff --git a/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktIndividualEnglish.java b/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktIndividualEnglish.java index fb042c8..d521cba 100644 --- a/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktIndividualEnglish.java +++ b/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktIndividualEnglish.java @@ -218,21 +218,6 @@ private String iso8601individualDescription(PhenopacketSex psex, Iso8601Age iso8 } - private String iso8601individualDescriptionAsA(PhenopacketSex psex, Iso8601Age iAge) { - String onsetWithSex = iso8601individualDescription(psex, iAge); - return String.format("as a %s", onsetWithSex); - } - - private String hpoOnsetAsA(PhenopacketSex psex, HpoOnsetAge hpoOnsetTermAge) { - String onsetWithSex = hpoOnsetIndividualDescription(psex, hpoOnsetTermAge); - final Set vowels = Set.of('A', 'E', 'I', 'O', 'U'); - if (vowels.contains(onsetWithSex.charAt(0))) { - return String.format("as an %s", onsetWithSex); - } else { - return String.format("as a %s", onsetWithSex); - } - } - private String hpoOnsetIndividualDescription(PhenopacketSex psex, HpoOnsetAge hpoOnsetTermAge) { if (hpoOnsetTermAge.isFetus()) { return switch (psex) { @@ -275,178 +260,11 @@ private String hpoOnsetIndividualDescription(PhenopacketSex psex, HpoOnsetAge hp } } - /** - * A sentence such as The proband was a 39-year-old woman who presented at the age of 12 years with - * HPO1, HPO2, and HPO3. HPO4 and HPO5 were excluded. This method returns the phrase that ends with "with" - * - * @param psex - * @param lastExamAge - * @param onsetAge - * @return - - private String onsetAndLastEncounterAvailable(PhenopacketSex psex, - PhenopacketAge lastExamAge, - PhenopacketAge onsetAge) { - String individualDescription; - String onsetDescription; - if (lastExamAge.ageType().equals(PhenopacketAgeType.ISO8601_AGE_TYPE)) { - Iso8601Age isoAge = (Iso8601Age) lastExamAge; - individualDescription = iso8601individualDescription(psex, isoAge); - } else if (lastExamAge.ageType().equals(PhenopacketAgeType.HPO_ONSET_AGE_TYPE)) { - HpoOnsetAge hpoOnsetTermAge = (HpoOnsetAge) lastExamAge; - individualDescription = hpoOnsetAsA(psex, hpoOnsetTermAge); - } else { - // should never happen - throw new PhenolRuntimeException("Did not recognize last exam age type " + lastExamAge.ageType()); - } - if (onsetAge.ageType().equals(PhenopacketAgeType.ISO8601_AGE_TYPE)) { - Iso8601Age isoAge = (Iso8601Age) onsetAge; - onsetDescription = iso8601AtAgeOf(isoAge); - } else if (onsetAge.ageType().equals(PhenopacketAgeType.HPO_ONSET_AGE_TYPE)) { - HpoOnsetAge hpoOnsetTermAge = (HpoOnsetAge) onsetAge; - onsetDescription = onsetTermAtAgeOf(hpoOnsetTermAge); - } else { - // should never happen - throw new PhenolRuntimeException("Did not recognize onset age type " + onsetAge.ageType()); - } - return String.format("%s %s %s %s:", - buildBlocks.probandWasA(), - individualDescription, - buildBlocks.inWhomManifestationsWereExcluded(), - onsetDescription); - - } - */ - - /** - * Age at last examination available but age of onset not available - * The proband was a 39-year-old woman who presented with HPO1, HPO2, and HPO3. HPO4 and HPO5 were excluded. - * - * @param psex - * @param lastExamAge - - private String lastEncounterAvailable(PhenopacketSex psex, - PhenopacketAge lastExamAge) { - String individualDescription; - if (lastExamAge.ageType().equals(PhenopacketAgeType.ISO8601_AGE_TYPE)) { - Iso8601Age isoAge = (Iso8601Age) lastExamAge; - individualDescription = iso8601individualDescription(psex, isoAge); - } else if (lastExamAge.ageType().equals(PhenopacketAgeType.HPO_ONSET_AGE_TYPE)) { - HpoOnsetAge hpoOnsetTermAge = (HpoOnsetAge) lastExamAge; - individualDescription = hpoOnsetIndividualDescription(psex, hpoOnsetTermAge); - } else { - // should never happen - throw new PhenolRuntimeException("Did not recognize last exam age type " + lastExamAge.ageType()); - } - - return String.format("%s %s %s", - buildBlocks.probandWasA(), - individualDescription, - buildBlocks.inWhomManifestationsWereExcluded()); - - }*/ - - /** - * Age at last examination not available but age of onset available - * The proband presented at the age of 12 years with HPO1, HPO2, and HPO3. HPO4 and HPO5 were excluded. - * - * @param psex sex of the proband - * @param onsetAge age at onset of disease - * @return - - private String onsetAvailable(PhenopacketSex psex, - PhenopacketAge onsetAge) { - String onsetDescription; - String individualDescription; - if (onsetAge.ageType().equals(PhenopacketAgeType.ISO8601_AGE_TYPE)) { - Iso8601Age isoAge = (Iso8601Age) onsetAge; - individualDescription = iso8601individualDescriptionAsA(psex, isoAge); - } else if (onsetAge.ageType().equals(PhenopacketAgeType.HPO_ONSET_AGE_TYPE)) { - HpoOnsetAge hpoOnsetTermAge = (HpoOnsetAge) onsetAge; - individualDescription = hpoOnsetAsA(psex, hpoOnsetTermAge); - } else { - // should never happen - throw new PhenolRuntimeException("Did not recognize onset age type " + onsetAge.ageType()); - } - - return String.format("%s %s %s", - buildBlocks.probandNoAgePresented(), - individualDescription, - buildBlocks.inWhomManifestationsWereExcluded()); - - - }*/ - - /** - * This method is called if we have no information at all about the age of the proband - * - * @param psex Sex of the proband - * @return A string such as "The proband was a female who presented with"; - */ - private String ageNotAvailable(PhenopacketSex psex) { - - return switch (psex) { - case FEMALE -> buildBlocks.probandWasAFemale(); - case MALE -> buildBlocks.probandWasAMale(); - default -> buildBlocks.probandWasAnIndividual(); - }; - - } - - /* - private String individualName(PpktIndividual individual) { - PhenopacketSex psex = individual.getSex(); - Optional ageOpt = individual.getAgeAtLastExamination(); - if (ageOpt.isEmpty()) { - ageOpt = individual.getAgeAtOnset(); - } - if (ageOpt.isEmpty()) { - return switch (psex) { - case FEMALE -> "female"; - case MALE -> "male"; - default -> "individual"; - }; - } - PhenopacketAge age = ageOpt.get();; - if (age.isChild()) { - return switch (psex) { - case FEMALE -> buildBlocks.girl(); - case MALE -> buildBlocks.boy(); - default -> buildBlocks.child(); - }; - } else if (age.isCongenital()) { - return switch (psex) { - case FEMALE -> "female newborn"; - case MALE -> "male newborn"; - default -> "newborn"; - }; - } else if (age.isFetus()) { - return switch (psex) { - case FEMALE -> "female fetus"; - case MALE -> "male fetus"; - default -> "fetus"; - }; - } else if (age.isInfant()) { - return switch (psex) { - case FEMALE -> "female infant"; - case MALE -> "male infant"; - default -> "infant"; - }; - } else { - return switch (psex) { - case FEMALE -> buildBlocks.woman(); - case MALE -> buildBlocks.man(); - default -> buildBlocks.inAdulthoold(); - }; - } - } -*/ - @Override public String atAgeForVignette(PhenopacketAge ppktAge) { if (ppktAge.ageType().equals(PhenopacketAgeType.ISO8601_AGE_TYPE)) { - return "At an age of " + ppktAge.age(); + return "At an age of " + buildBlocks.fromIso((Iso8601Age)ppktAge); } else if (ppktAge.ageType().equals(PhenopacketAgeType.HPO_ONSET_AGE_TYPE)) { if (ppktAge.isFetus()) { return buildBlocks.duringFetal(); diff --git a/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktPhenotypicFeatureEnglish.java b/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktPhenotypicFeatureEnglish.java index 74f30d7..f94464b 100644 --- a/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktPhenotypicFeatureEnglish.java +++ b/src/main/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktPhenotypicFeatureEnglish.java @@ -110,7 +110,7 @@ public String featuresAtOnset(String personString, List ontologyTe List excluded = getExcludedFeaturesAsStr(ontologyTerms); var observedStr = getOxfordCommaList(observed); var excludedStr = getOxfordCommaList(excluded); - if (!observed.isEmpty() && excluded.isEmpty()) { + if (!observed.isEmpty() && ! excluded.isEmpty()) { return String.format("%s presented with %s. However, the following features were excluded: %s.", personString, observedStr, excludedStr); } else if (!observed.isEmpty()) { diff --git a/src/test/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PPKtEnglishBuildingBlocksTest.java b/src/test/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PPKtEnglishBuildingBlocksTest.java new file mode 100644 index 0000000..6fcc3df --- /dev/null +++ b/src/test/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PPKtEnglishBuildingBlocksTest.java @@ -0,0 +1,22 @@ +package org.monarchinitiative.phenopacket2prompt.output.impl.english; + +import org.junit.jupiter.api.Test; +import org.monarchinitiative.phenopacket2prompt.model.Iso8601Age; +import org.monarchinitiative.phenopacket2prompt.output.PPKtBuildingBlockGenerator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PPKtEnglishBuildingBlocksTest { + + public final static PPKtBuildingBlockGenerator generator = new PPKtEnglishBuildingBlocks(); + + @Test + public void oneMonth() { + String expected = "1 month"; + Iso8601Age iso = new Iso8601Age("P1M"); + String result = generator.fromIso(iso); + assertEquals(expected, result); + } + + +} diff --git a/src/test/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktIndividualEnglishTest.java b/src/test/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktIndividualEnglishTest.java index 0de26fd..b9f1696 100644 --- a/src/test/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktIndividualEnglishTest.java +++ b/src/test/java/org/monarchinitiative/phenopacket2prompt/output/impl/english/PpktIndividualEnglishTest.java @@ -100,9 +100,9 @@ private static Stream testIndlAtAge() { new TestIdvlAtAge("congenital", congenital, new TestOutcome.Ok("At birth")), new TestIdvlAtAge("infantile", - infantile, new TestOutcome.Ok("During the infantile period")), + infantile, new TestOutcome.Ok("As an infant")), new TestIdvlAtAge("childhood age", - childhood, new TestOutcome.Ok("During childhood")), + childhood, new TestOutcome.Ok("As a child")), new TestIdvlAtAge("46 years old", p46y, new TestOutcome.Ok("At an age of 46 years")) ); @@ -121,8 +121,6 @@ void testPPKtSex(TestIdvlAtAge testCase) { () -> generator.atAgeForVignette(testCase.ppktAge()), "Incorrect error handling for: " + testCase.description()); } - - }