|
| 1 | +package owltools.gaf.lego; |
| 2 | + |
| 3 | +import java.util.Collection; |
| 4 | +import java.util.Collections; |
| 5 | +import java.util.HashSet; |
| 6 | +import java.util.List; |
| 7 | +import java.util.Map; |
| 8 | +import java.util.Set; |
| 9 | +import java.util.UUID; |
| 10 | + |
| 11 | +import org.apache.commons.lang3.StringUtils; |
| 12 | +import org.apache.log4j.Logger; |
| 13 | +import org.semanticweb.owlapi.model.AddImport; |
| 14 | +import org.semanticweb.owlapi.model.IRI; |
| 15 | +import org.semanticweb.owlapi.model.OWLAnnotation; |
| 16 | +import org.semanticweb.owlapi.model.OWLAnnotationProperty; |
| 17 | +import org.semanticweb.owlapi.model.OWLAxiom; |
| 18 | +import org.semanticweb.owlapi.model.OWLClass; |
| 19 | +import org.semanticweb.owlapi.model.OWLClassExpression; |
| 20 | +import org.semanticweb.owlapi.model.OWLDataFactory; |
| 21 | +import org.semanticweb.owlapi.model.OWLException; |
| 22 | +import org.semanticweb.owlapi.model.OWLImportsDeclaration; |
| 23 | +import org.semanticweb.owlapi.model.OWLNamedIndividual; |
| 24 | +import org.semanticweb.owlapi.model.OWLObject; |
| 25 | +import org.semanticweb.owlapi.model.OWLObjectProperty; |
| 26 | +import org.semanticweb.owlapi.model.OWLOntology; |
| 27 | +import org.semanticweb.owlapi.model.OWLOntologyID; |
| 28 | +import org.semanticweb.owlapi.model.OWLOntologyManager; |
| 29 | + |
| 30 | +import owltools.gaf.Bioentity; |
| 31 | +import owltools.gaf.ExtensionExpression; |
| 32 | +import owltools.gaf.GafDocument; |
| 33 | +import owltools.gaf.GeneAnnotation; |
| 34 | +import owltools.graph.OWLGraphWrapper; |
| 35 | +import owltools.vocab.OBOUpperVocabulary; |
| 36 | + |
| 37 | + |
| 38 | +/** |
| 39 | + * Simple translation of {@link GeneAnnotation} to the all individual lego annotation model. |
| 40 | + * |
| 41 | + */ |
| 42 | +public class GafToLegoIndividualTranslator { |
| 43 | + |
| 44 | + private static Logger logger = Logger.getLogger(GafToLegoIndividualTranslator.class); |
| 45 | + |
| 46 | + private final OWLGraphWrapper graph; |
| 47 | + private final OWLObjectProperty partOf; |
| 48 | + private final OWLObjectProperty occursIn; |
| 49 | + private final OWLObjectProperty inTaxon; |
| 50 | + private OWLClass mf; |
| 51 | + private OWLObjectProperty enabledBy; |
| 52 | + |
| 53 | + private Map<String, OWLObject> allOWLObjectsByAltId; |
| 54 | + |
| 55 | + private final boolean addLineNumber; |
| 56 | + |
| 57 | + public GafToLegoIndividualTranslator(OWLGraphWrapper graph, boolean addLineNumber) { |
| 58 | + this.graph = graph; |
| 59 | + this.addLineNumber = addLineNumber; |
| 60 | + allOWLObjectsByAltId = graph.getAllOWLObjectsByAltId(); |
| 61 | + OWLDataFactory df = graph.getDataFactory(); |
| 62 | + partOf = OBOUpperVocabulary.BFO_part_of.getObjectProperty(df); |
| 63 | + occursIn = OBOUpperVocabulary.BFO_occurs_in.getObjectProperty(df); |
| 64 | + |
| 65 | + mf = OBOUpperVocabulary.GO_molecular_function.getOWLClass(df); |
| 66 | + enabledBy = OBOUpperVocabulary.GOREL_enabled_by.getObjectProperty(df); |
| 67 | + inTaxon = graph.getOWLObjectPropertyByIdentifier("RO:0002162"); // in taxon |
| 68 | + } |
| 69 | + |
| 70 | + protected void reportError(String error, GeneAnnotation annotation) { |
| 71 | + logger.error(error+" \t Annotation: "+annotation.toString()); |
| 72 | + } |
| 73 | + |
| 74 | + protected void reportWarn(String warning, GeneAnnotation annotation) { |
| 75 | + logger.warn(warning+" \t Annotation: "+annotation.toString()); |
| 76 | + } |
| 77 | + |
| 78 | + /** |
| 79 | + * Translate the given {@link GafDocument} into an OWL representation of the LEGO model. |
| 80 | + * |
| 81 | + * @param gaf |
| 82 | + * @return lego ontology |
| 83 | + * @throws OWLException |
| 84 | + */ |
| 85 | + public OWLOntology translate(GafDocument gaf) throws OWLException { |
| 86 | + final OWLOntologyManager m = graph.getManager(); |
| 87 | + OWLOntology lego = m.createOntology(IRI.generateDocumentIRI()); |
| 88 | + OWLOntology sourceOntology = graph.getSourceOntology(); |
| 89 | + OWLOntologyID ontologyID = sourceOntology.getOntologyID(); |
| 90 | + if (ontologyID != null) { |
| 91 | + IRI ontologyIRI = ontologyID.getOntologyIRI(); |
| 92 | + if (ontologyIRI != null) { |
| 93 | + OWLDataFactory f = m.getOWLDataFactory(); |
| 94 | + OWLImportsDeclaration importDeclaration = f.getOWLImportsDeclaration(ontologyIRI); |
| 95 | + m.applyChange(new AddImport(lego, importDeclaration )); |
| 96 | + } |
| 97 | + } |
| 98 | + translate(gaf.getGeneAnnotations(), lego); |
| 99 | + return lego; |
| 100 | + } |
| 101 | + |
| 102 | + /** |
| 103 | + * Translate the given annotations ({@link GeneAnnotation}) into an OWL representation of the LEGO model. |
| 104 | + * |
| 105 | + * @param annotations |
| 106 | + * @param lego |
| 107 | + * @throws OWLException |
| 108 | + */ |
| 109 | + public void translate(Collection<GeneAnnotation> annotations, final OWLOntology lego) throws OWLException { |
| 110 | + final OWLOntologyManager m = graph.getManager(); |
| 111 | + |
| 112 | + Set<OWLAxiom> axioms = new HashSet<OWLAxiom>(); |
| 113 | + for(GeneAnnotation annotation : annotations) { |
| 114 | + translate(annotation, axioms); |
| 115 | + } |
| 116 | + m.addAxioms(lego, axioms); |
| 117 | + } |
| 118 | + |
| 119 | + /** |
| 120 | + * Translate theGeneAnnotation into an OWL representation of the LEGO model. |
| 121 | + * |
| 122 | + * @param annotation |
| 123 | + * @param axioms |
| 124 | + * @throws OWLException |
| 125 | + */ |
| 126 | + public void translate(GeneAnnotation annotation, Set<OWLAxiom> axioms) throws OWLException { |
| 127 | + // skip ND annotations |
| 128 | + if ("ND".equals(annotation.getShortEvidence())) { |
| 129 | + reportWarn("Skipping ND annotation", annotation); |
| 130 | + return; |
| 131 | + } |
| 132 | + // skip annotation using a qualifier |
| 133 | + String rel = StringUtils.trimToNull(annotation.getRelation()); |
| 134 | + if (rel != null) { |
| 135 | + if ("enables".equals(rel) == false && "part_of".equals(rel) == false && "involved_in".equals(rel) == false) { |
| 136 | + reportWarn("Skipping annotation with unsupported relation: "+annotation.getRelation(), annotation); |
| 137 | + return; |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + final OWLDataFactory f = graph.getDataFactory(); |
| 142 | + |
| 143 | + |
| 144 | + final String annotationClsString = annotation.getCls(); |
| 145 | + final OWLClass c = getOwlClass(annotationClsString); |
| 146 | + if (c == null) { |
| 147 | + reportError("Could not find a class for the given identifier: "+annotationClsString, annotation); |
| 148 | + return; |
| 149 | + } |
| 150 | + |
| 151 | + List<List<ExtensionExpression>> extensionExpressionGroups = annotation.getExtensionExpressions(); |
| 152 | + if (extensionExpressionGroups != null && !extensionExpressionGroups.isEmpty()) { |
| 153 | + Set<OWLClassExpression> parsedGroups = new HashSet<OWLClassExpression>(); |
| 154 | + for(List<ExtensionExpression> group : extensionExpressionGroups) { |
| 155 | + Set<OWLClassExpression> operands = new HashSet<OWLClassExpression>(); |
| 156 | + for(ExtensionExpression extension : group) { |
| 157 | + final String extensionClsString = extension.getCls(); |
| 158 | + final String extensionRelationString = extension.getRelation(); |
| 159 | + OWLClass extensionCls = getOwlClass(extensionClsString); |
| 160 | + if (extensionCls == null) { |
| 161 | + IRI extensionIRI = IdStringManager.getIRI(extensionClsString); |
| 162 | + extensionCls = f.getOWLClass(extensionIRI); |
| 163 | + } |
| 164 | + final OWLObjectProperty extensionRelation = graph.getOWLObjectPropertyByIdentifier(extensionRelationString); |
| 165 | + if (extensionRelation == null) { |
| 166 | + reportError("Could not find a class for the given extension relation identifier: "+extensionRelationString, annotation); |
| 167 | + continue; |
| 168 | + } |
| 169 | + operands.add(f.getOWLObjectSomeValuesFrom(extensionRelation, extensionCls)); |
| 170 | + } |
| 171 | + operands.add(c); |
| 172 | + parsedGroups.add(f.getOWLObjectIntersectionOf(operands)); |
| 173 | + } |
| 174 | + if (annotation.isNegated()) { |
| 175 | + OWLClassExpression union = f.getOWLObjectUnionOf(parsedGroups); |
| 176 | + translate(annotation, union, axioms); |
| 177 | + } |
| 178 | + else { |
| 179 | + for(OWLClassExpression ce : parsedGroups) { |
| 180 | + translate(annotation, ce, axioms); |
| 181 | + } |
| 182 | + } |
| 183 | + } |
| 184 | + else { |
| 185 | + translate(annotation, c, axioms); |
| 186 | + } |
| 187 | + } |
| 188 | + |
| 189 | + |
| 190 | + private void translate(GeneAnnotation annotation, OWLClassExpression ce, Set<OWLAxiom> axioms) throws OWLException { |
| 191 | + final OWLDataFactory f = graph.getDataFactory(); |
| 192 | + |
| 193 | + // # STEP 1 - Bioentity instance |
| 194 | + final Bioentity bioentity = annotation.getBioentityObject(); |
| 195 | + final String isoForm = StringUtils.trimToNull(annotation.getGeneProductForm()); |
| 196 | + |
| 197 | + final OWLClass bioentityClass; |
| 198 | + if (isoForm == null) { |
| 199 | + // option #1: default bioentity id |
| 200 | + bioentityClass = addBioentityCls(bioentity.getId(), bioentity.getSymbol(), bioentity.getNcbiTaxonId(), axioms, f); |
| 201 | + } |
| 202 | + else { |
| 203 | + // option #2: ISO-form as subclass of bioentity |
| 204 | + bioentityClass = addBioentityCls(isoForm, bioentity.getSymbol()+" ISO Form "+isoForm, bioentity.getNcbiTaxonId(), axioms, f); |
| 205 | + OWLClass bioentityClassSuper = addBioentityCls(bioentity.getId(), bioentity.getSymbol(), bioentity.getNcbiTaxonId(), axioms, f); |
| 206 | + axioms.add(f.getOWLDeclarationAxiom(bioentityClassSuper)); |
| 207 | + axioms.add(f.getOWLSubClassOfAxiom(bioentityClass, bioentityClassSuper)); |
| 208 | + } |
| 209 | + |
| 210 | + IRI bioentityInstanceIRI = generateNewIRI("bioentity", bioentityClass); |
| 211 | + OWLNamedIndividual bioentityInstance = f.getOWLNamedIndividual(bioentityInstanceIRI); |
| 212 | + axioms.add(f.getOWLDeclarationAxiom(bioentityInstance)); |
| 213 | + axioms.add(f.getOWLClassAssertionAxiom(bioentityClass, bioentityInstance)); |
| 214 | + |
| 215 | + // # STEP 2 - create instance: |
| 216 | + |
| 217 | + // use Aspect to switch between the three options: P == BP, C == CC, F = MF |
| 218 | + String aspect = annotation.getAspect(); |
| 219 | + if (aspect == null) { |
| 220 | + reportError("Error, no aspect defined.", annotation); |
| 221 | + return; |
| 222 | + } |
| 223 | + |
| 224 | + // TODO evidence |
| 225 | + Set<OWLAnnotation> annotations = Collections.emptySet(); |
| 226 | + if (addLineNumber) { |
| 227 | + int lineNumber = annotation.getSource().getLineNumber(); |
| 228 | + OWLAnnotation source = f.getOWLAnnotation(getLineNumberProperty(axioms, f), f.getOWLLiteral(lineNumber)); |
| 229 | + annotations = Collections.singleton(source); |
| 230 | + } |
| 231 | + boolean negated = annotation.isNegated(); |
| 232 | + if (negated) { |
| 233 | + handleNegated(bioentityClass, aspect, annotations, ce, axioms, f); |
| 234 | + return; |
| 235 | + } |
| 236 | + |
| 237 | + //List<String> sources = annotation.getReferenceIds(); |
| 238 | + if ("F".equals(aspect)) { |
| 239 | + // create individual |
| 240 | + OWLNamedIndividual individual = f.getOWLNamedIndividual(generateNewIRI("mf", ce)); |
| 241 | + axioms.add(f.getOWLDeclarationAxiom(individual)); |
| 242 | + |
| 243 | + // types |
| 244 | + axioms.add(f.getOWLClassAssertionAxiom(ce, individual)); |
| 245 | + |
| 246 | + // link instances |
| 247 | + |
| 248 | + axioms.add(f.getOWLObjectPropertyAssertionAxiom(enabledBy, individual, bioentityInstance, annotations)); |
| 249 | + } |
| 250 | + else if ("C".equals(aspect)) { |
| 251 | + // generic mf instance |
| 252 | + OWLNamedIndividual mfIndividual = f.getOWLNamedIndividual(generateNewIRI("mf", mf)); |
| 253 | + axioms.add(f.getOWLDeclarationAxiom(mfIndividual)); |
| 254 | + |
| 255 | + // generic mf type |
| 256 | + axioms.add(f.getOWLClassAssertionAxiom(mf, mfIndividual)); |
| 257 | + |
| 258 | + // link mf to bioentity |
| 259 | + axioms.add(f.getOWLObjectPropertyAssertionAxiom(enabledBy, mfIndividual, bioentityInstance)); |
| 260 | + |
| 261 | + // cc instance |
| 262 | + OWLNamedIndividual ccIndividual = f.getOWLNamedIndividual(generateNewIRI("cc", ce)); |
| 263 | + axioms.add(f.getOWLDeclarationAxiom(ccIndividual)); |
| 264 | + |
| 265 | + // cc type |
| 266 | + axioms.add(f.getOWLClassAssertionAxiom(ce, ccIndividual)); |
| 267 | + |
| 268 | + // link cc and mf |
| 269 | + axioms.add(f.getOWLObjectPropertyAssertionAxiom(occursIn, ccIndividual, mfIndividual, annotations)); |
| 270 | + |
| 271 | + |
| 272 | + } |
| 273 | + else if ("P".equals(aspect)) { |
| 274 | + // generic mf instance |
| 275 | + OWLNamedIndividual mfIndividual = f.getOWLNamedIndividual(generateNewIRI("mf", mf)); |
| 276 | + axioms.add(f.getOWLDeclarationAxiom(mfIndividual)); |
| 277 | + |
| 278 | + // generic mf type |
| 279 | + axioms.add(f.getOWLClassAssertionAxiom(mf, mfIndividual)); |
| 280 | + |
| 281 | + // link mf to bioentity |
| 282 | + axioms.add(f.getOWLObjectPropertyAssertionAxiom(enabledBy, mfIndividual, bioentityInstance)); |
| 283 | + |
| 284 | + // cc instance |
| 285 | + OWLNamedIndividual bpIndividual = f.getOWLNamedIndividual(generateNewIRI("bp", ce)); |
| 286 | + axioms.add(f.getOWLDeclarationAxiom(bpIndividual)); |
| 287 | + |
| 288 | + // cc type |
| 289 | + axioms.add(f.getOWLClassAssertionAxiom(ce, bpIndividual)); |
| 290 | + |
| 291 | + // link cc and mf |
| 292 | + axioms.add(f.getOWLObjectPropertyAssertionAxiom(partOf, bpIndividual, mfIndividual, annotations)); |
| 293 | + } |
| 294 | + } |
| 295 | + |
| 296 | + private void handleNegated(OWLClass bioentityClass, String aspect, Set<OWLAnnotation> annotations, |
| 297 | + OWLClassExpression ce, Set<OWLAxiom> axioms, OWLDataFactory f) { |
| 298 | + if ("F".equals(aspect)) { |
| 299 | + OWLClassExpression notCE = f.getOWLObjectComplementOf(f.getOWLObjectSomeValuesFrom(enabledBy, ce)); |
| 300 | + axioms.add(f.getOWLSubClassOfAxiom(bioentityClass, notCE, annotations)); |
| 301 | + } |
| 302 | + else if ("C".equals(aspect)) { |
| 303 | + OWLClassExpression notCE = f.getOWLObjectComplementOf(f.getOWLObjectSomeValuesFrom(occursIn, ce)); |
| 304 | + axioms.add(f.getOWLSubClassOfAxiom(bioentityClass, notCE, annotations)); |
| 305 | + } |
| 306 | + else if ("P".equals(aspect)) { |
| 307 | + OWLClassExpression notCE = f.getOWLObjectComplementOf(f.getOWLObjectSomeValuesFrom(partOf, ce)); |
| 308 | + axioms.add(f.getOWLSubClassOfAxiom(bioentityClass, notCE, annotations)); |
| 309 | + } |
| 310 | + } |
| 311 | + |
| 312 | + private OWLClass addBioentityCls(String id, String lbl, String taxon, Set<OWLAxiom> axioms, OWLDataFactory f) { |
| 313 | + IRI iri = IdStringManager.getIRI(id); |
| 314 | + OWLClass cls = f.getOWLClass(iri); |
| 315 | + boolean add = axioms.add(f.getOWLDeclarationAxiom(cls)); |
| 316 | + if (add) { |
| 317 | + OWLAnnotation annotation = f.getOWLAnnotation(f.getRDFSLabel(), f.getOWLLiteral(lbl)); |
| 318 | + axioms.add(f.getOWLAnnotationAssertionAxiom(iri, annotation)); |
| 319 | + if (taxon != null) { |
| 320 | + OWLClass taxonClass = f.getOWLClass(IdStringManager.getIRI(taxon)); |
| 321 | + axioms.add(f.getOWLDeclarationAxiom(taxonClass)); |
| 322 | + axioms.add(f.getOWLSubClassOfAxiom(cls, |
| 323 | + f.getOWLObjectSomeValuesFrom(inTaxon, taxonClass))); |
| 324 | + } |
| 325 | + } |
| 326 | + return cls; |
| 327 | + } |
| 328 | + |
| 329 | + /** |
| 330 | + * @param id |
| 331 | + * @return cls or null |
| 332 | + */ |
| 333 | + private OWLClass getOwlClass(String id) { |
| 334 | + OWLClass cls = graph.getOWLClassByIdentifier(id); |
| 335 | + if (cls == null) { |
| 336 | + // check alt ids |
| 337 | + OWLObject owlObject = allOWLObjectsByAltId.get(id); |
| 338 | + if (owlObject != null && owlObject instanceof OWLClass) { |
| 339 | + cls = (OWLClass) owlObject; |
| 340 | + } |
| 341 | + } |
| 342 | + return cls; |
| 343 | + } |
| 344 | + |
| 345 | + |
| 346 | + private static final IRI GAF_LINE_NUMBER = IRI.create("http://gaf/line_number"); |
| 347 | + |
| 348 | + private OWLAnnotationProperty getLineNumberProperty(Set<OWLAxiom> axioms, OWLDataFactory f) { |
| 349 | + OWLAnnotationProperty p = f.getOWLAnnotationProperty(GAF_LINE_NUMBER); |
| 350 | + axioms.add(f.getOWLDeclarationAxiom(p)); |
| 351 | + return p; |
| 352 | + } |
| 353 | + |
| 354 | + private IRI generateNewIRI(String type, OWLClassExpression ce) { |
| 355 | + if( ce.isAnonymous() == false) { |
| 356 | + OWLClass c = ce.asOWLClass(); |
| 357 | + String id = StringUtils.replaceOnce(IdStringManager.getId(c.getIRI()), ":", "_"); |
| 358 | + type = type + "-" + id; |
| 359 | + } |
| 360 | + return IRI.create("http://geneontology.org/lego/"+type+"-"+UUID.randomUUID().toString()); |
| 361 | + |
| 362 | + } |
| 363 | + |
| 364 | +} |
0 commit comments