diff --git a/build.sbt b/build.sbt index 045bc52..45c0b76 100644 --- a/build.sbt +++ b/build.sbt @@ -4,7 +4,7 @@ organization := "org.renci" name := "ncit-utils" -version := "0.3.1" +version := "0.4" licenses := Seq("BSD-3-Clause" -> url("https://opensource.org/licenses/BSD-3-Clause")) @@ -27,6 +27,7 @@ libraryDependencies ++= { "org.semanticweb.elk" % "elk-owlapi" % "0.4.3", "org.backuity.clist" %% "clist-core" % "3.2.2", "org.backuity.clist" %% "clist-macros" % "3.2.2" % "provided", + "com.github.pathikrit" %% "better-files" % "3.1.0", "com.typesafe.scala-logging" %% "scala-logging" % "3.7.1", "ch.qos.logback" % "logback-classic" % "1.2.3", "org.codehaus.groovy" % "groovy-all" % "2.4.6" diff --git a/src/main/scala/org/renci/ncit/Common.scala b/src/main/scala/org/renci/ncit/Common.scala new file mode 100644 index 0000000..9a952b1 --- /dev/null +++ b/src/main/scala/org/renci/ncit/Common.scala @@ -0,0 +1,7 @@ +package org.renci.ncit + +trait Common { + + def run(): Unit + +} \ No newline at end of file diff --git a/src/main/scala/org/renci/ncit/Main.scala b/src/main/scala/org/renci/ncit/Main.scala index 6ef0b8c..d99c98e 100644 --- a/src/main/scala/org/renci/ncit/Main.scala +++ b/src/main/scala/org/renci/ncit/Main.scala @@ -4,6 +4,6 @@ import org.backuity.clist._ object Main extends App { - Cli.parse(args).withProgramName("blazegraph-runner").withCommands(MaterializePropertyExpressions).foreach(_.run) + Cli.parse(args).withProgramName("blazegraph-runner").withCommands(MaterializePropertyExpressions, ReplaceMappedTerms).foreach(_.run) } \ No newline at end of file diff --git a/src/main/scala/org/renci/ncit/MaterializePropertyExpressions.scala b/src/main/scala/org/renci/ncit/MaterializePropertyExpressions.scala index 1073498..8b45127 100644 --- a/src/main/scala/org/renci/ncit/MaterializePropertyExpressions.scala +++ b/src/main/scala/org/renci/ncit/MaterializePropertyExpressions.scala @@ -24,7 +24,7 @@ import org.semanticweb.owlapi.reasoner.OWLReasoner import com.typesafe.scalalogging.LazyLogging -object MaterializePropertyExpressions extends Command(description = "Materialize property expressions") with LazyLogging { +object MaterializePropertyExpressions extends Command(description = "Materialize property expressions") with Common with LazyLogging { var ontologyFile = arg[File](name = "ontology") var nonRedundantOutputFile = arg[File](name = "nonredundant") @@ -32,7 +32,7 @@ object MaterializePropertyExpressions extends Command(description = "Materialize val prefix = "http://github.com/NCI-Thesaurus/thesaurus-obo-edition" - def run(): Unit = { + override def run(): Unit = { val manager = OWLManager.createOWLOntologyManager() val ontology = manager.loadOntologyFromOntologyDocument(ontologyFile) val properties = ontology.getObjectPropertiesInSignature(Imports.INCLUDED).asScala.toSet diff --git a/src/main/scala/org/renci/ncit/ReplaceMappedTerms.scala b/src/main/scala/org/renci/ncit/ReplaceMappedTerms.scala new file mode 100644 index 0000000..fe206d9 --- /dev/null +++ b/src/main/scala/org/renci/ncit/ReplaceMappedTerms.scala @@ -0,0 +1,66 @@ +package org.renci.ncit + +import java.nio.charset.StandardCharsets +import java.util.Collections + +import scala.collection.JavaConverters._ + +import org.backuity.clist._ +import org.phenoscape.scowl._ +import org.semanticweb.owlapi.apibinding.OWLManager +import org.semanticweb.owlapi.model.AddAxiom +import org.semanticweb.owlapi.model.IRI +import org.semanticweb.owlapi.model.OWLLiteral +import org.semanticweb.owlapi.model.RemoveAxiom +import org.semanticweb.owlapi.search.EntitySearcher +import org.semanticweb.owlapi.util.OWLEntityRenamer + +import com.typesafe.scalalogging.LazyLogging + +import better.files._ + +object ReplaceMappedTerms extends Command(description = "Replace mapped terms") with Common with LazyLogging { + + var mappingFile = arg[String](name = "mappings") + var ontology = arg[java.io.File](name = "ontology") + var keepColumn = arg[Int](name = "keep") + var dropColumn = arg[Int](name = "drop") + var outputFile = arg[java.io.File](name = "output") + + override def run(): Unit = { + val manager = OWLManager.createOWLOntologyManager() + val ont = manager.loadOntologyFromOntologyDocument(ontology) + val renamer = new OWLEntityRenamer(manager, Collections.singleton(ont)) + val newTerms = (for { + line <- File(mappingFile).lines(StandardCharsets.UTF_8).drop(1) + } yield { + val items = line.split("\t", -1) + val newTerm = IRI.create(items(keepColumn)) + val oldTerm = IRI.create(items(dropColumn)) + val changes = renamer.changeIRI(oldTerm, newTerm) + val logicalChanges = changes.asScala.filter(c => c.isAxiomChange && c.getAxiom.isLogicalAxiom) + manager.applyChanges(logicalChanges.asJava) + val labelChanges = EntitySearcher.getAnnotationAssertionAxioms(oldTerm, ont).asScala.filter(_.getProperty == RDFSLabel).flatMap { oldLabelAxiom => + val oldLabel = oldLabelAxiom.getValue.asInstanceOf[OWLLiteral].getLiteral + val newLabelAxiom = oldTerm Annotation (RDFSLabel, s"obsolete $oldLabel") + Set( + new AddAxiom(ont, manager.getOWLDataFactory.getDeprecatedOWLAnnotationAssertionAxiom(oldTerm)), + new RemoveAxiom(ont, oldLabelAxiom), + new AddAxiom(ont, newLabelAxiom)) + } + manager.applyChanges(labelChanges.toList.asJava) + Class(newTerm) + }).toSet + val hierarchyRemovals = for { + ax @ SubClassOf(_, subClass @ Class(_), _) <- ont.getAxioms().asScala + if newTerms(subClass) + } yield new RemoveAxiom(ont, ax) + val equivalenceRemovals = for { + ax @ EquivalentClasses(_, classes) <- ont.getAxioms().asScala + if classes.collectFirst { case c @ Class(_) => newTerms(c) }.nonEmpty + } yield new RemoveAxiom(ont, ax) + manager.applyChanges((hierarchyRemovals ++ equivalenceRemovals).toList.asJava) + manager.saveOntology(ont, IRI.create(outputFile)) + } + +} \ No newline at end of file