Skip to content
This repository has been archived by the owner on Sep 25, 2018. It is now read-only.

Commit

Permalink
Initial implementation of Noctua model reader for disease-phenotype m…
Browse files Browse the repository at this point in the history
…odels.
  • Loading branch information
balhoff committed Jul 28, 2016
1 parent c364b12 commit 6c81ead
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package org.phenopackets.pxftools.util

import java.io.InputStream

import scala.collection.JavaConverters._

import org.phenopackets.api.PhenoPacket
import org.phenopackets.api.model.association.PhenotypeAssociation
import org.phenopackets.api.model.condition.Phenotype
import org.phenopackets.api.model.entity.Disease
import org.phenopackets.api.model.evidence.Evidence
import org.phenopackets.api.model.evidence.Publication
import org.phenopackets.api.model.ontology.OntologyClass
import org.phenopackets.pxftools.util.NoctuaModelVocabulary._
import org.phenoscape.scowl._
import org.semanticweb.owlapi.apibinding.OWLManager
import org.semanticweb.owlapi.model.AxiomType
import org.semanticweb.owlapi.model.IRI
import org.semanticweb.owlapi.model.OWLClass
import org.semanticweb.owlapi.model.OWLEntity
import org.semanticweb.owlapi.model.OWLNamedIndividual
import org.semanticweb.owlapi.model.OWLOntology

import com.google.common.base.Optional
import com.typesafe.scalalogging.LazyLogging

import scalaz._
import scalaz.Scalaz._
import org.phenopackets.api.model.condition.ConditionFrequency
import org.phenopackets.api.model.ontology.ClassInstance
import org.phenopackets.api.model.condition.ConditionSeverity
import org.phenopackets.api.model.condition.TemporalRegion

object NoctuaDiseasePhenotypeModelReader extends LazyLogging {

def read(stream: InputStream): PhenoPacket = {
val manager = OWLManager.createOWLOntologyManager()
val ont = manager.loadOntologyFromOntologyDocument(stream)
stream.close()
createPhenoPacket(ont)
}

def createPhenoPacket(ont: OWLOntology): PhenoPacket = {
val builder = PhenoPacket.newBuilder()
ont.getOntologyID.getOntologyIRI.asScala.foreach(iri => builder.id(iri.toString))
val associationsAndAnnotations = (for {
ObjectPropertyAssertion(annotations, HasPart, subj: OWLNamedIndividual, obj: OWLNamedIndividual) <- ont.getAxioms(AxiomType.OBJECT_PROPERTY_ASSERTION).asScala
} yield Map(Association(subj, obj) -> annotations)).reduce(_ |+| _)
var diseases = Set.empty[Disease]
for {
(Association(diseaseInd, phenotypeInd), annotations) <- associationsAndAnnotations
} {
val allDiseaseTypes = findOWLTypes(diseaseInd, ont)
if (allDiseaseTypes.size > 1) {
logger.warn(s"More than one type found for disease $diseaseInd; keeping only one to use as the entity ID.")
}
allDiseaseTypes.headOption.foreach { diseaseClass =>
val disease = new Disease()
disease.setId(diseaseClass.getIRI.toString)
findLabel(diseaseClass, ont).foreach(disease.setLabel)
findDescription(diseaseInd, ont).foreach(disease.setLabel)
diseases += disease
val phenotype = new Phenotype()
updateAsClassInstance(phenotype, phenotypeInd, ont)
findFrequency(phenotypeInd, ont).foreach(phenotype.setFrequency)
findSeverity(phenotypeInd, ont).foreach(phenotype.setSeverity)
findTimeOfOnset(phenotypeInd, ont).foreach(phenotype.setTimeOfOnset)
findTimeOfOffset(phenotypeInd, ont).foreach(phenotype.setTimeOfFinishing)
val associationBuilder = new PhenotypeAssociation.Builder(phenotype)
associationBuilder.setEntity(disease)
annotations.foreach {
case Annotation(AxiomHasEvidence, evidence: IRI) => associationBuilder.addEvidence(toEvidence(Individual(evidence), ont))
case Annotation(DCContributor, contributor ^^ _) => associationBuilder.setContributorId(contributor)
case Annotation(DCDate, date ^^ _) => associationBuilder.setDate(date)
case _ =>
}
builder.addPhenotypeAssociation(associationBuilder.build())
}
}
builder.setDiseases(diseases.toSeq.asJava)
builder.build()
}

private def toEvidence(ind: OWLNamedIndividual, ont: OWLOntology): Evidence = {
val evidence = new Evidence()
updateAsClassInstance(evidence, ind, ont)
val publications = for {
ObjectPropertyAssertion(_, HasSupportingReference, _, reference: IRI) <- ont.getObjectPropertyAssertionAxioms(ind).asScala
} yield {
val pubBuilder = new Publication.Builder()
pubBuilder.setId(reference.toString)
findLabel(Individual(reference), ont).foreach(pubBuilder.setTitle)
pubBuilder.build()
}
evidence.setSupportingPublications(publications.toSeq.asJava)
evidence
}

private def toOntologyClass(term: OWLClass, ont: OWLOntology): OntologyClass = {
val classBuilder = new OntologyClass.Builder(term.getIRI.toString)
findLabel(term, ont).foreach(classBuilder.setLabel)
classBuilder.build()
}

private def findLabel(item: OWLEntity, ont: OWLOntology): Option[String] = (for {
AnnotationAssertion(_, RDFSLabel, _, label ^^ _) <- ont.getAnnotationAssertionAxioms(item.getIRI).asScala
} yield label).headOption

private def findDescription(item: OWLEntity, ont: OWLOntology): Option[String] = (for {
AnnotationAssertion(_, DCDescription, _, desc ^^ _) <- ont.getAnnotationAssertionAxioms(item.getIRI).asScala
} yield desc).headOption

private def findFrequency(phenotypeInd: OWLNamedIndividual, ont: OWLOntology): Option[ConditionFrequency] = (for {
ObjectPropertyAssertion(_, ConditionToFrequency, _, frequencyInd: OWLNamedIndividual) <- ont.getObjectPropertyAssertionAxioms(phenotypeInd).asScala
} yield {
val frequency = new ConditionFrequency()
updateAsClassInstance(frequency, frequencyInd, ont)
frequency
}).headOption

private def findSeverity(phenotypeInd: OWLNamedIndividual, ont: OWLOntology): Option[ConditionSeverity] = (for {
ObjectPropertyAssertion(_, ConditionToSeverity, _, severityInd: OWLNamedIndividual) <- ont.getObjectPropertyAssertionAxioms(phenotypeInd).asScala
} yield {
val severity = new ConditionSeverity()
updateAsClassInstance(severity, severityInd, ont)
severity
}).headOption

private def findTimeOfOnset(phenotypeInd: OWLNamedIndividual, ont: OWLOntology): Option[TemporalRegion] = (for {
ObjectPropertyAssertion(_, ExistenceStartsDuring, _, onsetInd: OWLNamedIndividual) <- ont.getObjectPropertyAssertionAxioms(phenotypeInd).asScala
} yield {
toTemporalRegion(onsetInd, ont)
}).headOption

private def findTimeOfOffset(phenotypeInd: OWLNamedIndividual, ont: OWLOntology): Option[TemporalRegion] = (for {
ObjectPropertyAssertion(_, ExistenceEndsDuring, _, offsetInd: OWLNamedIndividual) <- ont.getObjectPropertyAssertionAxioms(phenotypeInd).asScala
} yield {
toTemporalRegion(offsetInd, ont)
}).headOption

private def toTemporalRegion(regionInd: OWLNamedIndividual, ont: OWLOntology): TemporalRegion = {
val region = new TemporalRegion()
updateAsClassInstance(region, regionInd, ont)
for {
ObjectPropertyAssertion(_, TemporalRegionToStart, _, start ^^ _) <- ont.getObjectPropertyAssertionAxioms(regionInd).asScala
} {
region.setStartTime(start)
}
for {
ObjectPropertyAssertion(_, TemporalRegionToEnd, _, end ^^ _) <- ont.getObjectPropertyAssertionAxioms(regionInd).asScala
} {
region.setEndTime(end)
}
region

}

private def updateAsClassInstance(instance: ClassInstance, ind: OWLNamedIndividual, ont: OWLOntology): Unit = {
findDescription(ind, ont).foreach(instance.setDescription)
instance.setTypes(findTypes(ind, ont).toSeq.asJava)
instance.setNegatedTypes(findNegatedTypes(ind, ont).toSeq.asJava)
}

private def findTypes(individual: OWLNamedIndividual, ont: OWLOntology): Set[OntologyClass] =
findOWLTypes(individual, ont).map(toOntologyClass(_, ont))

private def findOWLTypes(individual: OWLNamedIndividual, ont: OWLOntology): Set[OWLClass] = for {
ClassAssertion(_, owlClass: OWLClass, subj) <- ont.getClassAssertionAxioms(individual).asScala.toSet
} yield owlClass

private def findNegatedTypes(individual: OWLNamedIndividual, ont: OWLOntology): Set[OntologyClass] =
findNegatedOWLTypes(individual, ont).map(toOntologyClass(_, ont))

private def findNegatedOWLTypes(individual: OWLNamedIndividual, ont: OWLOntology): Set[OWLClass] = for {
ClassAssertion(_, ObjectComplementOf(owlClass: OWLClass), subj) <- ont.getClassAssertionAxioms(individual).asScala.toSet
} yield owlClass

private case class Association(subj: OWLNamedIndividual, obj: OWLNamedIndividual)

private implicit class OptionalOption[T](val self: Optional[T]) extends AnyVal {

def asScala: Option[T] = if (self.isPresent) Some(self.get) else None

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.phenopackets.pxftools.util

import org.phenoscape.scowl._
import org.semanticweb.owlapi.apibinding.OWLManager

import com.hp.hpl.jena.vocabulary.DC_11

object NoctuaModelVocabulary {

private val factory = OWLManager.getOWLDataFactory

val DCTitle = AnnotationProperty(DC_11.title.getURI)
val DCDescription = AnnotationProperty(DC_11.description.getURI)
val DCSource = AnnotationProperty(DC_11.source.getURI)
val DCDate = AnnotationProperty(DC_11.date.getURI)
val DCContributor = AnnotationProperty(DC_11.contributor.getURI)
val RDFSComment = factory.getRDFSComment
val HasPart = ObjectProperty("http://purl.obolibrary.org/obo/BFO_0000051")
val ConditionToFrequency = ObjectProperty("http://example.org/condition_to_frequency") //FIXME
val ConditionToSeverity = ObjectProperty("http://example.org/condition_to_severity") //FIXME
val TemporalRegionToStart = DataProperty("http://example.org/temporal_region_start_at") //FIXME
val TemporalRegionToEnd = DataProperty("http://example.org/temporal_region_end_at") //FIXME
val ExistenceStartsDuring = ObjectProperty("http://purl.obolibrary.org/obo/RO_0002488")
val ExistenceEndsDuring = ObjectProperty("http://purl.obolibrary.org/obo/RO_0002492")
val AxiomHasEvidence = AnnotationProperty("http://purl.obolibrary.org/obo/RO_0002612")
val HasSupportingReference = ObjectProperty("http://purl.obolibrary.org/obo/SEPIO_0000124")
val Publication = Class("http://purl.obolibrary.org/obo/IAO_0000311")

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.phenopackets.api.model.evidence.Evidence
import org.phenopackets.api.model.evidence.Publication
import org.phenopackets.api.model.ontology.ClassInstance
import org.phenopackets.api.util.ContextUtil
import org.phenopackets.pxftools.util.NoctuaModelVocabulary._
import org.phenoscape.scowl._
import org.semanticweb.owlapi.apibinding.OWLManager
import org.semanticweb.owlapi.formats.ManchesterSyntaxDocumentFormat
Expand All @@ -28,30 +29,10 @@ import org.semanticweb.owlapi.model.OWLNamedIndividual
import org.semanticweb.owlapi.model.OWLOntology

import com.github.jsonldjava.core.Context
import com.hp.hpl.jena.vocabulary.DC_11
import com.typesafe.scalalogging.LazyLogging

object NoctuaModelWriter extends LazyLogging {

private val factory = OWLManager.getOWLDataFactory
private val DCTitle = AnnotationProperty(DC_11.title.getURI)
private val DCDescription = AnnotationProperty(DC_11.description.getURI)
private val DCSource = AnnotationProperty(DC_11.source.getURI)
private val DCDate = AnnotationProperty(DC_11.date.getURI)
private val DCContributor = AnnotationProperty(DC_11.contributor.getURI)
private val RDFSComment = factory.getRDFSComment
private val RDFSLabel = factory.getRDFSLabel
private val HasPart = ObjectProperty("http://purl.obolibrary.org/obo/BFO_0000051")
private val ConditionToFrequency = ObjectProperty("http://example.org/condition_to_frequency") //FIXME
private val ConditionToSeverity = ObjectProperty("http://example.org/condition_to_severity") //FIXME
private val TemporalRegionToStart = DataProperty("http://example.org/temporal_region_start_at") //FIXME
private val TemporalRegionToEnd = DataProperty("http://example.org/temporal_region_end_at") //FIXME
private val ExistenceStartsDuring = ObjectProperty("http://purl.obolibrary.org/obo/RO_0002488")
private val ExistenceEndsDuring = ObjectProperty("http://purl.obolibrary.org/obo/RO_0002492")
private val AxiomHasEvidence = AnnotationProperty("http://purl.obolibrary.org/obo/RO_0002612")
private val HasSupportingReference = ObjectProperty("http://purl.obolibrary.org/obo/SEPIO_0000124")
private val Publication = Class("http://purl.obolibrary.org/obo/IAO_0000311")

def fromPhenoPacket(packet: PhenoPacket): OWLOntology = {
val manager = OWLManager.createOWLOntologyManager()
val context = ContextUtil.getJSONLDContext(packet)
Expand Down Expand Up @@ -214,7 +195,7 @@ object NoctuaModelWriter extends LazyLogging {
var axioms = Set.empty[OWLAxiom]
val pubIndividual = Individual(iri(publication.getId, context))
axioms += Declaration(pubIndividual)
axioms += pubIndividual Type Publication
axioms += pubIndividual Type org.phenopackets.pxftools.util.NoctuaModelVocabulary.Publication
axioms ++= Option(publication.getTitle).map(pubIndividual Annotation (DCTitle, _))
(pubIndividual, axioms)
}
Expand Down Expand Up @@ -244,7 +225,7 @@ object NoctuaModelWriter extends LazyLogging {
private def iri(id: String, context: Context): IRI = {
val expanded = ContextUtil.expandIdentifierAsValue(id, context)
val expandedID = if (expanded.contains(":")) {
if (!expanded.startsWith("http")) logger.warn(s"No HTTP URI found for identifer: $id")
if (!expanded.startsWith("http")) logger.warn(s"No HTTP URI found for identifier: $id")
expanded
} else {
logger.warn(s"No URI found for identifer: $id")
Expand Down

0 comments on commit 6c81ead

Please sign in to comment.