diff --git a/docs/ga4gh-interoperability.rst b/docs/ga4gh-interoperability.rst new file mode 100644 index 00000000..5364ba3d --- /dev/null +++ b/docs/ga4gh-interoperability.rst @@ -0,0 +1,8 @@ +###################### +GA4GH Interoperability +###################### + +.. toctree:: + :maxdepth: 1 + + GA4GH Pedigree Standard diff --git a/docs/ga4gh-pedigree.rst b/docs/ga4gh-pedigree.rst new file mode 100644 index 00000000..71b0e531 --- /dev/null +++ b/docs/ga4gh-pedigree.rst @@ -0,0 +1,108 @@ +.. _rsga4ghpedigree: + +############## +GA4GH Pedigree +############## + + +The Phenopacket-schema includes an implementation of the `GA4GH Pedigree Standard `_. +GA4GH Pedigree defines a conceptual model of individuals and their relationships to allow other standards, such as +Phenopackets to be able to create an implementation of this model using native concepts. For example, the Phenopacket +schema representation of an individual in the GA4GH Pedigree is a :ref:`rstphenopacket`. + +The GA4GH Pedigree Standard enables much greater expressivity of the relationships between individuals compared to the +PED model used in the :ref:`rstfamily` message due to defining the relationships using the `Kinship ontology (KIN) `_ + + +Data model +########## + +The data model described here is transcribed from the `documentation `_ + +Pedigree +======== + +.. csv-table:: + :header: Field, Type, Multiplicity, Description + + id, string, 1..1, External identifier for the family being investigated + narrative, string, 0..1, Summary of the pedigree resource for human interpretation + date, string, 0..1, The date the pedigree was collected or last updated as ISO full or partial date i.e. YYYY or YYYY-MM or YYYY-MM-DD + status, string, 0..1, Status of the pedigree resource collection + index_patients, string, 0..*, Identified Individual(s) in the family of a health condition of focus being investigated. + individuals, :ref:`rstphenopacket`, 0..*, Collection of Individual who are the members of this pedigree + relationships, :ref:`rstga4ghrelationship`, 0..*, Collection of Relationship between the individuals who are the members of this pedigree + + +index_patients +~~~~~~~~~~~~~~ + +A list of identifiers for the individual(s) in the family affected with the health condition being investigated. These +individuals(s) are often termed the Proband, Consultand or First Person Tested Positive. + + +.. _rstga4ghrelationship: + +Relationship +============ + +.. csv-table:: + :header: Field, Type, Multiplicity, Description + + individual, string, 1..1, Identifier of the subject Individual; equivalent to the Biolink "subject" + relation, :ref:`rstontologyclass`, 1..1, The relationship the individual has to the relative. + relative, string, 1..1, Identifier of the relative Individual; equivalent to the Biolink "object" + + +individual and relative +~~~~~~~~~~~~~~~~~~~~~~~ + +The identifier values used in the ``individual`` and ``relative`` fields **must** match a value in the **id** element +used in the :ref:`rstindividual` ``subject`` of the phenopackets listed in the ``pedigree`` ``individuals`` field. + +relation +~~~~~~~~ + +An :ref:`rstontologyclass` from the `KIN Ontology `_ indicating the relationship the +``individual`` has to the ``relative`` e.g. if the individual is the relative's biological mother, then relation should +be isBiologicalMotherOf [KIN:027]. + + +Example +####### + +In this example we have simplified the phenopackets to include only the minimum required information to make a pedigree. +Ordinarily there should be more fields (e.g. the :ref:`rstmetadata`) within the phenopacket. + +.. code-block:: yaml + + --- + id: "FAM1" + narrative: "A Phenopacket GA4GH Pedigree of a trio with an affected child" + date: "2022-06-23" + indexPatients: + - "CHILD" + individuals: + - id: "1" + subject: + id: "MOTHER" + sex: "FEMALE" + - id: "2" + subject: + id: "FATHER" + sex: "MALE" + - id: "3" + subject: + id: "CHILD" + relationships: + - individualId: "MOTHER" + relation: + id: "KIN:027" + label: "isBiologicalMother" + relativeId: "CHILD" + - individualId: "FATHER" + relation: + id: "KIN:028" + label: "isBiologicalFather" + relativeId: "CHILD" + diff --git a/docs/index.rst b/docs/index.rst index 296860cb..6e7698a5 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,4 +29,4 @@ use `this link `_. recommended-ontologies working examples - + ga4gh-interoperability diff --git a/docs/pharmaceutical-treatment.rst b/docs/pharmaceutical-treatment.rst deleted file mode 100644 index 946e31fc..00000000 --- a/docs/pharmaceutical-treatment.rst +++ /dev/null @@ -1,82 +0,0 @@ -.. _rstpharmaceuticaltreatment: - -======================== -Pharmaceutical treatment -======================== - - -This represents treatment with a pharmaceutical agent, broadly defined -as prescription and over-the-counter -medicines, vaccines, and large-molecule biologic therapies. - - -**Data model** - - -.. list-table:: Definition of the ``PharmaceuticalTreatment`` element - :widths: 25 25 50 50 - :header-rows: 1 - - * - Field - - Type - - Status - - Description - * - drug - - OntologyClass - - required - - The drug. - * - route_of_administration - - OntologyClass - - recommended - - How was the drug administered? - * - dose_intervals - - DoseInterval (list) - - recommended - - dosages - * - drug_type - - DrugType - - optional - - Context of the drug administration - * - stop_reason_id - - StopReason - - optional - - reason to stop taking the drug - - -drug -~~~~ -An ontology term representing the pharmaceutical agent. This can be -a term from `DrugCentral `_, -`RxNorm `_, -`Drugbank `_, -`ChEBI `_, or other ontologies. - - -route_of_administration -~~~~~~~~~~~~~~~~~~~~~~~ -How the drug is administered, e.g., by mouth or intravenously. This can be -specified by ontology terms from the NCIT subhierarchy for -`Route of Administration `_. - - -dose_intervals -~~~~~~~~~~~~~~ -block of time in which the dosage of a medication was -constant, e.g., 30 mg/day for an interval of 10 days. -See :ref:`rstdoseinterval`. - - -drug_type -~~~~~~~~~ -The context in which a drug was administered. -See :ref:`rstdrugtype`. - - - -stop_reason_id -~~~~~~~~~~~~~~ -the reason for which a medication was discontinued. -See :ref:`rststopreason`. -Todo -- if the medication is still ongoing, we will need to represent this. - - diff --git a/docs/version2.rst b/docs/version2.rst deleted file mode 100644 index 9de7503b..00000000 --- a/docs/version2.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. _rstversion2: - -===================== -Phenopacket version 2 -===================== - -Version 1 of phenopackets was approved by GA4GH in `October, 2019 `_. -Based on initial experiences and feedback from multiple sources, we are planning to -extend version 1 to include better representation of the time course of disease, treatment, -and cancer-related data. Discussions are planned in the GA4GH -Clin/Pheno Full WS & Phenopackets Subgroups. Newcomers are welcome, please contact -the `GA4GH `_ to get involved! - -A number of new elements are now open for discussion by the community in the -`v1.1 branch `_ of -the phenopackets GitHub repository. - - -Version 2.0 -~~~~~~~~~~~ - -.. toctree:: - :maxdepth: 1 - - apiversion - dose-interval - drug-type - exposure - interval - medical-action - pharmaceutical-treatment - quantity - stop-reason - time-element - vital-status - - -We anticipate that version 2.0 will contain a very few breaking (backwards-incompatible) -changes affecting the representation of time and dates. These changes will be brought to the -GA4GH steering committee before release. \ No newline at end of file diff --git a/pom.xml b/pom.xml index a9a94d57..298235ec 100644 --- a/pom.xml +++ b/pom.xml @@ -212,8 +212,9 @@ org.apache.maven.plugins maven-surefire-plugin - 2.22.2 + 3.0.0-M7 + false **/FooTest.java diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 641712c1..49855f3f 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -9,4 +9,6 @@ exports org.ga4gh.vrs.v1; exports org.ga4gh.vrsatile.v1; + + exports org.ga4gh.pedigree.v1; } \ No newline at end of file diff --git a/src/main/proto/ga4gh/pedigree/v1/pedigree.proto b/src/main/proto/ga4gh/pedigree/v1/pedigree.proto new file mode 100644 index 00000000..7f61a292 --- /dev/null +++ b/src/main/proto/ga4gh/pedigree/v1/pedigree.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; + +package org.ga4gh.pedigree.v1; + +import "phenopackets/schema/v2/phenopackets.proto"; +import "phenopackets/schema/v2/core/base.proto"; + +option java_multiple_files = true; +option java_package = "org.ga4gh.pedigree.v1"; + +// A GA4GH Pedigree - equivalent to the Phenopacket::Family message +message Pedigree { + + // External identifier for the family being investigated + string id = 1; + + // Summary of the pedigree resource for human interpretation + string narrative = 2; + + // The date the pedigree was collected or last updated, as ISO full or partial date, i.e. YYYY, YYYY-MM, or YYYY-MM-DD + string date = 3; + + // Status of the pedigree resource collection + string status = 5; + + // Identified Individual in the family of a health condition of focus being investigated: Proband, Consultand, + // First Person Tested Positive + repeated string index_patients = 6; + + // Collection of Individual who are the members of this pedigree + repeated org.phenopackets.schema.v2.Phenopacket individuals = 7; + + // Collection of Relationship between the individuals who are the members of this pedigree + repeated Relationship relationships = 8; + +} + +message Relationship { + // Identifier of the subject Individual; equivalent to the Biolink "subject" + string individual_id = 1; + + // The relationship the individual has to the relative (e.g., if the individual is the relative's biological mother, + // then relation could be isBiologicalMotherOf [KIN:027]). + // Terms should come from the KIN Ontology (http://purl.org/ga4gh/kin.owl). + org.phenopackets.schema.v2.core.OntologyClass relation = 2; + + // Identifier of the relative Individual; equivalent to the Biolink "object" + string relative_id = 3; +} \ No newline at end of file diff --git a/src/test/java/org/ga4gh/pedigree/v1/Ga4ghPedigreeExamplesTest.java b/src/test/java/org/ga4gh/pedigree/v1/Ga4ghPedigreeExamplesTest.java new file mode 100644 index 00000000..9bff1d6f --- /dev/null +++ b/src/test/java/org/ga4gh/pedigree/v1/Ga4ghPedigreeExamplesTest.java @@ -0,0 +1,125 @@ +package org.ga4gh.pedigree.v1; + +import org.junit.jupiter.api.Test; +import org.phenopackets.schema.v2.Phenopacket; +import org.phenopackets.schema.v2.core.*; +import org.phenopackets.schema.v2.io.FormatMapper; + +import java.io.IOException; + +import static org.phenopackets.schema.v2.PhenoPacketTestUtil.ontologyClass; + +/** + * Test cases / examples for the Phenopackets implementation of the GA4GH-Pedigree conceptual model + */ +class Ga4ghPedigreeExamplesTest { + + private static final OntologyClass BIOLOGICAL_MOTHER_OF = ontologyClass("KIN:027", "isBiologicalMother"); + private static final OntologyClass BIOLOGICAL_FATHER_OF = ontologyClass("KIN:028", "isBiologicalFather"); + private static final OntologyClass MONOZYGOTIC_TWIN_OF = ontologyClass("KIN:010", "isMonozygoticMultipleBirthSiblingOf"); + private static final OntologyClass ADOPTIVE_PARENT_OF = ontologyClass("KIN:022", "isAdoptiveParentOf"); + private static final OntologyClass GESTATIONAL_CARRIER_OF = ontologyClass("KIN:005", "isGestationalCarrierOf"); + private static final OntologyClass OVUM_DONOR_OF = ontologyClass("KIN:038", "isOvumDonorOf"); + + private static Relationship.Builder relationship(Phenopacket subject, OntologyClass relationship, Phenopacket relative) { + return Relationship.newBuilder() + .setIndividualId(subject.getSubject().getId()) + .setRelation(relationship) + .setRelativeId(relative.getSubject().getId()); + } + + @Test + void simpleTrio() throws IOException { + Phenopacket mother = Phenopacket.newBuilder().setId("1").setSubject(Individual.newBuilder().setId("MOTHER").setSex(Sex.FEMALE)).build(); + Phenopacket father = Phenopacket.newBuilder().setId("2").setSubject(Individual.newBuilder().setId("FATHER").setSex(Sex.MALE)).build(); + Phenopacket proband = Phenopacket.newBuilder().setId("3").setSubject(Individual.newBuilder().setId("CHILD").setSex(Sex.UNKNOWN_SEX)).build(); + + Pedigree pedigree = Pedigree.newBuilder() + .setId("FAM1") + .setNarrative("A Phenopacket Schema GA4GH Pedigree of a trio with an affected child") + .setDate("2022-06-23") + .addIndexPatients(proband.getSubject().getId()) + .addIndividuals(mother) + .addIndividuals(father) + .addIndividuals(proband) + .addRelationships(relationship(mother, BIOLOGICAL_MOTHER_OF, proband)) + .addRelationships(relationship(father, BIOLOGICAL_FATHER_OF, proband)) + .build(); + + System.out.println(FormatMapper.messageToYaml(pedigree)); + } + + @Test + void twins() throws IOException { + Phenopacket mother = Phenopacket.newBuilder().setId("1").setSubject(Individual.newBuilder().setId("MOTHER").setSex(Sex.FEMALE)).build(); + Phenopacket father = Phenopacket.newBuilder().setId("2").setSubject(Individual.newBuilder().setId("FATHER").setSex(Sex.MALE)).build(); + Phenopacket twin1 = Phenopacket.newBuilder().setId("3").setSubject(Individual.newBuilder().setId("TWIN1").setSex(Sex.UNKNOWN_SEX)).build(); + Phenopacket twin2 = Phenopacket.newBuilder().setId("4").setSubject(Individual.newBuilder().setId("TWIN2").setSex(Sex.UNKNOWN_SEX)).build(); + + Pedigree pedigree = Pedigree.newBuilder() + .setId("FAM2") + .setNarrative("A Phenopacket Schema GA4GH Pedigree of a couple with identical twins") + .setDate("2022-06-23") + .addIndividuals(mother) + .addIndividuals(father) + .addIndividuals(twin1) + .addIndividuals(twin2) + .addRelationships(relationship(mother, BIOLOGICAL_MOTHER_OF, twin1)) + .addRelationships(relationship(mother, BIOLOGICAL_MOTHER_OF, twin2)) + .addRelationships(relationship(father, BIOLOGICAL_FATHER_OF, twin1)) + .addRelationships(relationship(father, BIOLOGICAL_FATHER_OF, twin2)) + .addRelationships(relationship(twin1, MONOZYGOTIC_TWIN_OF, twin2)) + .addRelationships(relationship(twin2, MONOZYGOTIC_TWIN_OF, twin1)) + .build(); + +// System.out.println(FormatMapper.messageToYaml(pedigree)); + } + + @Test + void adoption() throws IOException { + Phenopacket mother = Phenopacket.newBuilder().setId("1").setSubject(Individual.newBuilder().setId("MOTHER").setSex(Sex.FEMALE)).build(); + Phenopacket father = Phenopacket.newBuilder().setId("3").setSubject(Individual.newBuilder().setId("FATHER").setSex(Sex.MALE)).build(); + Phenopacket biologicalMother = Phenopacket.newBuilder().setId("2").setSubject(Individual.newBuilder().setId("BIOLOGICAL_MOTHER").setSex(Sex.FEMALE)).build(); + Phenopacket child = Phenopacket.newBuilder().setId("4").setSubject(Individual.newBuilder().setId("CHILD").setSex(Sex.UNKNOWN_SEX)).build(); + + Pedigree pedigree = Pedigree.newBuilder() + .setId("FAM3") + .setNarrative("A Phenopacket Schema GA4GH Pedigree of a child with an adoptive mother") + .setDate("2022-06-23") + .addIndividuals(mother) + .addIndividuals(biologicalMother) + .addIndividuals(father) + .addIndividuals(child) + .addRelationships(relationship(mother, ADOPTIVE_PARENT_OF, child)) + .addRelationships(relationship(biologicalMother, BIOLOGICAL_MOTHER_OF, child)) + .addRelationships(relationship(father, BIOLOGICAL_FATHER_OF, child)) + .build(); + +// System.out.println(FormatMapper.messageToYaml(pedigree)); + } + + @Test + void ivf() throws IOException { + Phenopacket mother = Phenopacket.newBuilder().setId("1").setSubject(Individual.newBuilder().setId("MOTHER").setSex(Sex.FEMALE)).build(); + Phenopacket father = Phenopacket.newBuilder().setId("3").setSubject(Individual.newBuilder().setId("FATHER").setSex(Sex.MALE)).build(); + Phenopacket surrogate = Phenopacket.newBuilder().setId("2").setSubject(Individual.newBuilder().setId("SURROGATE").setSex(Sex.FEMALE)).build(); + Phenopacket child = Phenopacket.newBuilder().setId("4").setSubject(Individual.newBuilder().setId("CHILD").setSex(Sex.UNKNOWN_SEX)).build(); + + Pedigree pedigree = Pedigree.newBuilder() + .setId("FAM4") + .setNarrative("A Phenopacket Schema GA4GH Pedigree of a child with an egg donor, gestational carrier, and biological father") + .setDate("2022-06-23") + .addIndividuals(mother) + .addIndividuals(surrogate) + .addIndividuals(father) + .addIndividuals(child) + .addRelationships(relationship(mother, OVUM_DONOR_OF, child)) + .addRelationships(relationship(surrogate, GESTATIONAL_CARRIER_OF, child)) + .addRelationships(relationship(father, BIOLOGICAL_FATHER_OF, child)) + .build(); + +// System.out.println(FormatMapper.messageToYaml(pedigree)); + } +} + +