From 29c25fc9bc62d70271199feee34d671951076dce Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Wed, 2 Jan 2019 09:55:41 +0100
Subject: [PATCH] export/import of position to compartment implemented

---
 .../converter/model/sbml/SbmlExporter.java    | 62 ++++++++++++++-----
 .../sbml/species/SbmlSpeciesExporter.java     | 33 ++++++++++
 .../model/sbml/species/SbmlSpeciesParser.java | 19 ++++++
 .../model/sbml/SbmlExporterTest.java          | 17 +++++
 4 files changed, 115 insertions(+), 16 deletions(-)

diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java
index d9ec1fc0ca..99a4a95a00 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java
@@ -37,6 +37,7 @@ import lcsb.mapviewer.model.map.species.Complex;
 import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.map.species.Protein;
 import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.PositionToCompartment;
 import lcsb.mapviewer.modelutils.map.ElementUtils;
 
 public class SbmlExporter {
@@ -97,7 +98,7 @@ public class SbmlExporter {
     MultiModelPlugin multiPlugin = null;
     if (usedExtensions.contains(SbmlExtension.MULTI)) {
       multiPlugin = createSbmlMultiPlugin(result);
-      assignStructuralStatesToTypes(multiPlugin, model);
+      assignModelDataToTypes(multiPlugin, model);
     }
 
     SbmlCompartmentExporter compartmentExporter = new SbmlCompartmentExporter(result, model, usedExtensions);
@@ -119,18 +120,21 @@ public class SbmlExporter {
     return doc;
   }
 
-  private void assignStructuralStatesToTypes(MultiModelPlugin multiPlugin, lcsb.mapviewer.model.map.model.Model model) {
+  private void assignModelDataToTypes(MultiModelPlugin multiPlugin, lcsb.mapviewer.model.map.model.Model model) {
     for (Element element : model.getElements()) {
       String structuralState = null;
+      MultiSpeciesType speciesType = speciesTypeByClass.get(element.getClass());
       if (element instanceof Protein) {
         structuralState = ((Protein) element).getStructuralState();
       } else if (element instanceof Complex) {
         structuralState = ((Complex) element).getStructuralState();
       }
       if (structuralState != null) {
-        MultiSpeciesType speciesType = speciesTypeByClass.get(element.getClass());
         addStructuralStateToPossibleValues(speciesType, structuralState);
       }
+      if (element instanceof Species) {
+        addPositionToCompartmentToPossibleValues(speciesType, ((Species) element).getPositionToCompartment());
+      }
     }
 
   }
@@ -141,6 +145,14 @@ public class SbmlExporter {
     addPosibleValueToFeature(feature, structuralState);
   }
 
+  private void addPositionToCompartmentToPossibleValues(MultiSpeciesType speciesType, PositionToCompartment position) {
+    SpeciesFeatureType feature = speciesType.getListOfSpeciesFeatureTypes()
+        .get("minerva_position_to_compartment_" + speciesType.getName());
+    if (position != null) {
+      addPosibleValueToFeature(feature, position.name());
+    }
+  }
+
   /**
    * Create SBML layout for the given model.
    * 
@@ -183,24 +195,42 @@ public class SbmlExporter {
     result.addExtension("multi", multiPlugin);
     for (Class<? extends Element> clazz : new ElementUtils().getAvailableElementSubclasses()) {
       if (Species.class.isAssignableFrom(clazz)) {
-        MultiSpeciesType speciesType = new MultiSpeciesType();
-        speciesType.setName(clazz.getSimpleName());
-        speciesType.setId("minerva_species_type_" + clazz.getSimpleName());
-        if (Protein.class.isAssignableFrom(clazz) || Complex.class.isAssignableFrom(clazz)) {
-          SpeciesFeatureType feature = new SpeciesFeatureType();
-          feature.setName("Structural state");
-          feature.setId("minerva_structural_state_" + clazz.getSimpleName());
-          addPosibleValueToFeature(feature, "");
-          speciesType.getListOfSpeciesFeatureTypes().add(feature);
-        }
-        multiPlugin.getListOfSpeciesTypes().add(speciesType);
-        speciesTypeByClass.put(clazz, speciesType);
-        speciesType.setSBOTerm(SBOTermSpeciesType.getTermByType((Class<? extends Species>) clazz));
+        createSpeciesTypeForClass(multiPlugin, clazz);
       }
     }
     return multiPlugin;
   }
 
+  @SuppressWarnings("unchecked")
+  private void createSpeciesTypeForClass(MultiModelPlugin multiPlugin, Class<? extends Element> clazz) {
+    MultiSpeciesType speciesType = new MultiSpeciesType();
+    speciesType.setName(clazz.getSimpleName());
+    speciesType.setId("minerva_species_type_" + clazz.getSimpleName());
+    if (Protein.class.isAssignableFrom(clazz) || Complex.class.isAssignableFrom(clazz)) {
+      createStructuralStateFeature(clazz, speciesType);
+    }
+    createPositionToCompartmentFeature(clazz, speciesType);
+    multiPlugin.getListOfSpeciesTypes().add(speciesType);
+    speciesTypeByClass.put(clazz, speciesType);
+    speciesType.setSBOTerm(SBOTermSpeciesType.getTermByType((Class<? extends Species>) clazz));
+  }
+
+  private void createStructuralStateFeature(Class<? extends Element> clazz, MultiSpeciesType speciesType) {
+    SpeciesFeatureType feature = new SpeciesFeatureType();
+    feature.setName("Structural state");
+    feature.setId("minerva_structural_state_" + clazz.getSimpleName());
+    addPosibleValueToFeature(feature, "");
+    speciesType.getListOfSpeciesFeatureTypes().add(feature);
+  }
+
+  private void createPositionToCompartmentFeature(Class<? extends Element> clazz, MultiSpeciesType speciesType) {
+    SpeciesFeatureType feature = new SpeciesFeatureType();
+    feature.setName("Position to compartment");
+    feature.setId("minerva_position_to_compartment_" + clazz.getSimpleName());
+    addPosibleValueToFeature(feature, "undefined");
+    speciesType.getListOfSpeciesFeatureTypes().add(feature);
+  }
+
   private void addPosibleValueToFeature(SpeciesFeatureType feature, String value) {
     boolean alreadyExists = false;
     for (PossibleSpeciesFeatureValue existingValue : feature.getListOfPossibleSpeciesFeatureValues()) {
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java
index b636d3937c..313f3cdf73 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java
@@ -70,6 +70,12 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j
     MultiSpeciesType speciesType = getMultiSpeciesType(element);
     multiExtension.setSpeciesType(speciesType.getId());
     result.addExtension("multi", multiExtension);
+    assignStructuralStateToMulti(element, multiExtension, speciesType);
+    assignPostionToCompartmentToMulti(element, multiExtension, speciesType);
+  }
+
+  private void assignStructuralStateToMulti(Species element, MultiSpeciesPlugin multiExtension,
+      MultiSpeciesType speciesType) {
     String structuralState = null;
     if (element instanceof Protein) {
       structuralState = ((Protein) element).getStructuralState();
@@ -98,6 +104,33 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j
     }
   }
 
+  private void assignPostionToCompartmentToMulti(Species element, MultiSpeciesPlugin multiExtension,
+      MultiSpeciesType speciesType) {
+    String positionToCompartmentName = "undefined";
+    if (element.getPositionToCompartment() != null) {
+      positionToCompartmentName = element.getPositionToCompartment().name();
+    }
+    SpeciesFeatureType structuralStateFeature = speciesType
+        .getSpeciesFeatureType("minerva_position_to_compartment_" + element.getClass().getSimpleName());
+    PossibleSpeciesFeatureValue structuralStateFeatureValue = null;
+    for (PossibleSpeciesFeatureValue value : structuralStateFeature.getListOfPossibleSpeciesFeatureValues()) {
+      if (value.getName().equals(positionToCompartmentName)) {
+        structuralStateFeatureValue = value;
+      }
+    }
+    if (structuralStateFeatureValue == null) {
+      throw new InvalidStateException(
+          new ElementUtils().getElementTag(element) + "Cannot find position to compartment value for: "
+              + positionToCompartmentName);
+    }
+
+    SpeciesFeature feature = multiExtension.createSpeciesFeature();
+    feature.setSpeciesFeatureType(structuralStateFeature.getId());
+    SpeciesFeatureValue value = new SpeciesFeatureValue();
+    value.setValue(structuralStateFeatureValue.getId());
+    feature.addSpeciesFeatureValue(value);
+  }
+
   private MultiSpeciesType getMultiSpeciesType(Species element) {
     MultiSpeciesType speciesType = getMultiPlugin()
         .getSpeciesType("minerva_species_type_" + element.getClass().getSimpleName());
diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java
index 9308131a7f..aeff43bca2 100644
--- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java
+++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java
@@ -32,6 +32,7 @@ import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.map.species.Protein;
 import lcsb.mapviewer.model.map.species.Species;
 import lcsb.mapviewer.model.map.species.Unknown;
+import lcsb.mapviewer.model.map.species.field.PositionToCompartment;
 import lcsb.mapviewer.modelutils.map.ElementUtils;
 
 public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> {
@@ -124,6 +125,24 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species>
       } else {
         logger.warn(warnPrefix + "Invalid structural state for class " + featureTypeString);
       }
+    } else if (featureTypeString.startsWith("minerva_position_to_compartment_")) {
+      if (featureTypeString.equals("minerva_position_to_compartment_" + minervaElement.getClass().getSimpleName())) {
+        SpeciesFeatureType featureType = speciesType.getListOfSpeciesFeatureTypes().get(featureTypeString);
+
+        List<String> positionToCompartments = new ArrayList<>();
+        for (SpeciesFeatureValue featureValue : feature.getListOfSpeciesFeatureValues()) {
+          PossibleSpeciesFeatureValue possibleSpeciesFeatureValue = featureType.getListOfPossibleSpeciesFeatureValues()
+              .get(featureValue.getValue());
+          positionToCompartments.add(possibleSpeciesFeatureValue.getName());
+        }
+        if (positionToCompartments.size() != 1) {
+          logger.warn(warnPrefix + "Position to compartment must exactly one value");
+        } else {
+          minervaElement.setPositionToCompartment(PositionToCompartment.getByString(positionToCompartments.get(0)));
+        }
+      } else {
+        logger.warn(warnPrefix + "Invalid structural state for class " + featureTypeString);
+      }
     } else {
       logger.warn(warnPrefix + "Feature not supported: " + featureTypeString);
     }
diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
index aff6bc9be3..23bcd786c0 100644
--- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
+++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java
@@ -50,6 +50,7 @@ import lcsb.mapviewer.model.map.species.IonChannelProtein;
 import lcsb.mapviewer.model.map.species.ReceptorProtein;
 import lcsb.mapviewer.model.map.species.Species;
 import lcsb.mapviewer.model.map.species.TruncatedProtein;
+import lcsb.mapviewer.model.map.species.field.PositionToCompartment;
 
 public class SbmlExporterTest {
   Logger logger = Logger.getLogger(SbmlExporterTest.class);
@@ -479,6 +480,22 @@ public class SbmlExporterTest {
     assertEquals("Structural state not exported/imported properly", 0, comparator.compare(model, deserializedModel));
   }
 
+  @Test
+  public void testExportPositionToCompartment() throws Exception {
+    Model model = createEmptyModel();
+    GenericProtein element = new GenericProtein("id");
+    element.setName("test name");
+    element.setX(10);
+    element.setWidth(10);
+    element.setY(10);
+    element.setHeight(10);
+    element.setPositionToCompartment(PositionToCompartment.INSIDE);
+    model.addElement(element);
+    Model deserializedModel = getModelAfterSerializing(model);
+
+    assertEquals("Postion to compartment not exported/imported properly", 0, comparator.compare(model, deserializedModel));
+  }
+
   @Test
   public void testMultiExtensionProteinStateInTypes() throws Exception {
     String structuralState = "xxx";
-- 
GitLab