All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sbml.jsbml.ext.comp.util.CompFlatteningConverter Maven / Gradle / Ivy

The newest version!
/*
 * ----------------------------------------------------------------------------
 * This file is part of JSBML. Please visit 
 * for the latest version of JSBML and more information about SBML.
 *
 * Copyright (C) 2009-2022 jointly by the following organizations:
 * 1. The University of Tuebingen, Germany
 * 2. EMBL European Bioinformatics Institute (EBML-EBI), Hinxton, UK
 * 3. The California Institute of Technology, Pasadena, CA, USA
 * 4. The University of California, San Diego, La Jolla, CA, USA
 * 5. The Babraham Institute, Cambridge, UK
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation. A copy of the license agreement is provided
 * in the file named "LICENSE.txt" included with this software distribution
 * and also available online as .
 * ----------------------------------------------------------------------------
 */
package org.sbml.jsbml.ext.comp.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.xml.stream.XMLStreamException;

import org.sbml.jsbml.Compartment;
import org.sbml.jsbml.Constraint;
import org.sbml.jsbml.Event;
import org.sbml.jsbml.FunctionDefinition;
import org.sbml.jsbml.InitialAssignment;
import org.sbml.jsbml.ListOf;
import org.sbml.jsbml.Model;
import org.sbml.jsbml.Parameter;
import org.sbml.jsbml.Reaction;
import org.sbml.jsbml.Rule;
import org.sbml.jsbml.SBMLDocument;
import org.sbml.jsbml.SBMLReader;
import org.sbml.jsbml.SBase;
import org.sbml.jsbml.Species;
import org.sbml.jsbml.UnitDefinition;
import org.sbml.jsbml.ext.comp.CompConstants;
import org.sbml.jsbml.ext.comp.CompModelPlugin;
import org.sbml.jsbml.ext.comp.CompSBMLDocumentPlugin;
import org.sbml.jsbml.ext.comp.CompSBasePlugin;
import org.sbml.jsbml.ext.comp.Deletion;
import org.sbml.jsbml.ext.comp.ExternalModelDefinition;
import org.sbml.jsbml.ext.comp.ModelDefinition;
import org.sbml.jsbml.ext.comp.Port;
import org.sbml.jsbml.ext.comp.ReplacedElement;
import org.sbml.jsbml.ext.comp.Submodel;

/**
 * The {@link CompFlatteningConverter} object translates a hierarchical model defined with the SBML Level 3
 * Hierarchical Model Composition package into a 'flattened' version of the same model. This means the the hierarchical
 * structure is dissolved and all objects are built into a single model that does no longer require the comp package.
 *
 * @author Christoph Blessing
 * @since 1.0
 */
public class CompFlatteningConverter {

    private final static Logger LOGGER = Logger.getLogger(CompFlatteningConverter.class.getName());

    private List previousModelIDs;
    private List previousModelMetaIDs;
    private ListOf modelDefinitionListOf;
    private ListOf externalModelDefinitionListOf;

    private List listOfSubmodelsToFlatten;

    private Model flattenedModel;

    public CompFlatteningConverter() {
        this.listOfSubmodelsToFlatten = new ArrayList<>();

        this.previousModelIDs = new ArrayList<>();
        this.previousModelMetaIDs = new ArrayList<>();

        this.modelDefinitionListOf = new ListOf<>();
        this.externalModelDefinitionListOf = new ListOf<>();

        this.flattenedModel = new Model();

    }


    /**
     * Public method to call on a CompflatteningConverter object.
     * Takes a SBML Document and flattens the models of the comp plugin.
     * Returns the SBML Document with a flattend model.
     *
     * @param document SBML Document to flatten
     * @return SBML Document with flattened model
     */
    public SBMLDocument flatten(SBMLDocument document) {

        if (document.isPackageEnabled(CompConstants.shortLabel)) {

            CompSBMLDocumentPlugin compSBMLDocumentPlugin = (CompSBMLDocumentPlugin) document.getExtension(CompConstants.shortLabel);

            this.modelDefinitionListOf = compSBMLDocumentPlugin.getListOfModelDefinitions();
            this.externalModelDefinitionListOf = compSBMLDocumentPlugin.getListOfExternalModelDefinitions();

            if (document.isSetModel() && document.getModel().getExtension(CompConstants.shortLabel) != null) {

                // TODO: the model itself has to be flattened (can hold a list of replacements etc.)
                CompModelPlugin compModelPlugin = (CompModelPlugin) document.getModel().getExtension(CompConstants.shortLabel);
                handlePorts(compModelPlugin, compModelPlugin.getListOfPorts());
                replaceElementsInModelDefinition(compModelPlugin, null); //TODO: why is null given here?

                this.flattenedModel = instantiateSubModels(compModelPlugin);
            } else {
                LOGGER.warning("No comp package found in Model. Can not flatten.");
            }

        } else {
            LOGGER.warning("No comp package found in Document. Cannot flatten.");
        }

        this.flattenedModel.unsetExtension(CompConstants.shortLabel);
        this.flattenedModel.unsetPlugin(CompConstants.shortLabel);

        document.setModel(this.flattenedModel);
        document.unsetExtension(CompConstants.shortLabel);
        document.disablePackage(CompConstants.shortLabel);

        return document;

    }


    /**
     * Initiates every Submodel in the CompModelPlugin recursively
     *
     * @param compModelPlugin
     */
    private Model instantiateSubModels(CompModelPlugin compModelPlugin) {

        // TODO: the first model is not always flat.

        Model model = compModelPlugin.getExtendedSBase().getModel();

        handlePorts(compModelPlugin, compModelPlugin.getListOfPorts());
        replaceElementsInModelDefinition(compModelPlugin, null);
        this.flattenedModel = mergeModels(flattenModel(model), this.flattenedModel);

        if (compModelPlugin.getSubmodelCount() > 0) {
            // check if submodel has submodel
            this.flattenedModel = initSubModels(compModelPlugin);
        } else {
            LOGGER.info("No more submodels");
        }

        return this.flattenedModel;
    }

    /**
     * Actualizes replacement provided by comp extension: The "replaced elements" referenced by {@link ReplacedElement} 
     * instances are here actually removed, along with their respective {@link Port}, and thus replaced by the holder 
     * of the {@link ReplacedElement} 
     * @param compModelPlugin plugin holding the {@link ReplacedElement}s, may be null -- not used in that case
     * @param compSBasePlugin plugin holding {@link ReplacedElement}s, may be null - not used in that case
     */
    private void replaceElementsInModelDefinition(CompModelPlugin compModelPlugin, CompSBasePlugin compSBasePlugin) {

        if (compModelPlugin != null || compSBasePlugin != null) {

            ListOf listOfReplacedElements = new ListOf<>();

            if (compModelPlugin != null) {
                listOfReplacedElements = compModelPlugin.getListOfReplacedElements();
            } else if (compSBasePlugin != null) {
                listOfReplacedElements = compSBasePlugin.getListOfReplacedElements();
            }

            for (ReplacedElement replacedElement : listOfReplacedElements) {

                for (ModelDefinition modelDefinition : this.modelDefinitionListOf) {
                    SBase sBase = modelDefinition.findNamedSBase(replacedElement.getIdRef());
                    if (sBase != null) {
                        sBase.removeFromParent();
                    }
                }

                if (compModelPlugin != null) {
                    for(Port port : compModelPlugin.getListOfPorts()){
                        if(port.getId().equals(replacedElement.getPortRef())){
                            port.removeFromParent();
                        }

                    }
                }
            }

        }
    }

    private void handlePorts(CompModelPlugin compModelPlugin, ListOf listOfPorts){

        for (Port port : listOfPorts){

            // Port object instance defines a port for a component in a model.

            // A port could be created by using the metaIdRef attribute
            // to identify the object for which a given Port instance is the port;
            // The question 'what does this port correspond to?' would be answered by the value of the metaIdRef attribute.

            String idRef = port.getIdRef();
            String metaIDRef = port.getMetaIdRef();

            if(metaIDRef != null && !metaIDRef.isEmpty()){

                SBase parentOfPort = compModelPlugin.getParent();

                SBase sBase = compModelPlugin.getSBMLDocument().findSBase(idRef);
                addSBaseToModel(parentOfPort.getModel(), sBase);

            } else if(idRef != null && !idRef.isEmpty()){
                SBase parentOfPort = compModelPlugin.getParent();

                for (ModelDefinition modelDefinition : this.modelDefinitionListOf) {
                    SBase sBase = modelDefinition.findNamedSBase(idRef);

                    if(sBase != null){
                        addSBaseToModel(parentOfPort.getModel(), sBase);
                        break;
                    }
                }


            }

            // If a port references an object from a namespace that is not understood by the interpreter,
            // the interpreter must consider the port to be not understood as well.
            // If an interpreter cannot tell whether the referenced object does not
            // exist or if exists in an unparsed XML or SBML namespace, it may choose to display a warning to the user.

        }

        listOfPorts.removeFromParent();
    }

    private Model initSubModels(CompModelPlugin compModelPlugin) {

        ListOf subModelListOf = compModelPlugin.getListOfSubmodels().clone();

        // TODO: replace elements
        replaceElementsInModelDefinition(compModelPlugin, null);

        // TODO: ports
        ListOf listOfPorts = compModelPlugin.getListOfPorts();
        handlePorts(compModelPlugin, listOfPorts);

        for (Submodel submodel : subModelListOf) {

            this.listOfSubmodelsToFlatten.add(submodel);

            ModelDefinition modelDefinition = this.modelDefinitionListOf.get(submodel.getModelRef());

            // TODO: how to initialize external model definitions?
            if (modelDefinition == null) {
                ExternalModelDefinition externalModelDefinition = this.externalModelDefinitionListOf.get(submodel.getModelRef());
                try {
                    SBMLDocument externalDocument = SBMLReader.read(new File(externalModelDefinition.getSource()));
                    Model flattendExternalModel = flatten(externalDocument).getModel(); //external model can also contain submodels etc.
                    this.flattenedModel = mergeModels(this.flattenedModel, flattendExternalModel);
                } catch (XMLStreamException | IOException e) {
                    e.printStackTrace();
                }
            }

            if (modelDefinition != null && modelDefinition.getExtension(CompConstants.shortLabel) != null) {
                initSubModels((CompModelPlugin) modelDefinition.getExtension(CompConstants.shortLabel));
            } else {
                LOGGER.info("No model definition found in " + submodel.getId() + ".") ;
            }

        }

        return flattenAndMergeModels(this.listOfSubmodelsToFlatten);
    }

    private Model flattenAndMergeModels(List listOfSubmodelsToFlatten) {

        int sizeOfList = listOfSubmodelsToFlatten.size();

        if (sizeOfList >= 2) {
            Submodel last = listOfSubmodelsToFlatten.get(sizeOfList - 1);
            Submodel secondLast = listOfSubmodelsToFlatten.get(sizeOfList - 2);

            this.flattenedModel = mergeModels(this.flattenedModel, mergeModels(flattenSubModel(secondLast), flattenSubModel(last)));
            listOfSubmodelsToFlatten.remove(secondLast);
            listOfSubmodelsToFlatten.remove(last);

            flattenAndMergeModels(listOfSubmodelsToFlatten);

        } else if (sizeOfList == 1) {
            Submodel last = listOfSubmodelsToFlatten.get(sizeOfList - 1);

            this.flattenedModel = mergeModels(this.flattenedModel, flattenSubModel(last));
        }

        return this.flattenedModel;

    }

    /**
     * All remaining elements are placed in a single Model object
     * The original Model, ModelDefinition, and ExternalModelDefinition objects are all deleted
     *
     * @param previousModel
     * @param currentModel
     * @return mergedModel
     */
    private Model mergeModels(Model previousModel, Model currentModel) {

        Model mergedModel = new Model();

        // Merging of SBML models should be done in the order
        // Compartments -> Species -> Function Definitions -> Rules -> Events -> Units -> Reactions -> Parameters
        // If done in this order, potential conflicts are resolved incrementally along the way.

        if (previousModel != null) {

            // match versions and level
            mergedModel.setLevel(previousModel.getLevel());
            mergedModel.setVersion(previousModel.getVersion());

            mergeListsOfModels(previousModel.getListOfCompartments(), previousModel, mergedModel);
            mergeListsOfModels(previousModel.getListOfSpecies(), previousModel, mergedModel);
            mergeListsOfModels(previousModel.getListOfFunctionDefinitions(), previousModel, mergedModel);
            mergeListsOfModels(previousModel.getListOfRules(), previousModel, mergedModel);
            mergeListsOfModels(previousModel.getListOfEvents(), previousModel, mergedModel);
            mergeListsOfModels(previousModel.getListOfUnitDefinitions(), previousModel, mergedModel);
            mergeListsOfModels(previousModel.getListOfReactions(), previousModel, mergedModel);
            mergeListsOfModels(previousModel.getListOfParameters(), previousModel, mergedModel);
            mergeListsOfModels(previousModel.getListOfInitialAssignments(), previousModel, mergedModel);

        }

        if (currentModel != null) {

            mergeListsOfModels(currentModel.getListOfCompartments(), currentModel, mergedModel);
            mergeListsOfModels(currentModel.getListOfSpecies(), currentModel, mergedModel);
            mergeListsOfModels(currentModel.getListOfFunctionDefinitions(), currentModel, mergedModel);
            mergeListsOfModels(currentModel.getListOfRules(), currentModel, mergedModel);
            mergeListsOfModels(currentModel.getListOfEvents(), currentModel, mergedModel);
            mergeListsOfModels(currentModel.getListOfUnitDefinitions(), currentModel, mergedModel);
            mergeListsOfModels(currentModel.getListOfReactions(), currentModel, mergedModel);
            mergeListsOfModels(currentModel.getListOfParameters(), currentModel, mergedModel);
            mergeListsOfModels(currentModel.getListOfInitialAssignments(), currentModel, mergedModel);

        }

        // TODO: delete original model, ModelDefinition, and ExternalModelDefinition objects
        // QUESTION: can a model def be instantiated more than one time?
        return mergedModel;
    }


    private void mergeListsOfModels(ListOf listOfObjects, Model sourceModel, Model targetModel) {

        // TODO: generify with listOf SBase ?

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfReactions) {

            ListOf reactionListOf = sourceModel.getListOfReactions().clone();
            sourceModel.getListOfReactions().removeFromParent();

            for (Reaction reaction : reactionListOf) {
                targetModel.addReaction(reaction.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfCompartments) {

            ListOf compartmentListOf = sourceModel.getListOfCompartments().clone();
            sourceModel.getListOfCompartments().removeFromParent();

            for (Compartment compartment : compartmentListOf) {
                targetModel.addCompartment(compartment.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfConstraints) {

            ListOf constraintListOf = sourceModel.getListOfConstraints().clone();
            sourceModel.getListOfConstraints().removeFromParent();

            for (Constraint constraint : constraintListOf) {
                targetModel.addConstraint(constraint.clone());
            }
        }


        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfSpecies) {

            ListOf speciesListOf = sourceModel.getListOfSpecies().clone();
            sourceModel.getListOfSpecies().removeFromParent();

            for (Species species : speciesListOf) {
                targetModel.addSpecies(species.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfEvents) {

            ListOf eventListOf = sourceModel.getListOfEvents().clone();
            sourceModel.getListOfEvents().removeFromParent();

            for (Event event : eventListOf) {
                targetModel.addEvent(event.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfFunctionDefinitions) {

            ListOf functionalDefinitionsListOf = sourceModel.getListOfFunctionDefinitions().clone();
            sourceModel.getListOfFunctionDefinitions().removeFromParent();

            for (FunctionDefinition functionalDefinition : functionalDefinitionsListOf) {
                targetModel.addFunctionDefinition(functionalDefinition.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfInitialAssignments) {

            ListOf initialAssignmentListOf = sourceModel.getListOfInitialAssignments().clone();
            sourceModel.getListOfInitialAssignments().removeFromParent();

            for (InitialAssignment initialAssignment : initialAssignmentListOf) {
                targetModel.addInitialAssignment(initialAssignment.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfParameters) {

            ListOf parameterListOf = sourceModel.getListOfParameters().clone();
            sourceModel.getListOfParameters().removeFromParent();

            for (Parameter parameter : parameterListOf) {

                if(parameter.isSetPlugin(CompConstants.shortLabel)){
                    replaceElementsInModelDefinition(null, (CompSBasePlugin) parameter.getExtension(CompConstants.shortLabel));
                    parameter.unsetPlugin(CompConstants.shortLabel);
                }
                targetModel.addParameter(parameter.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfRules) {

            ListOf ruleListOf = sourceModel.getListOfRules().clone();
            sourceModel.getListOfRules().removeFromParent();

            for (Rule rule : ruleListOf) {
                targetModel.addRule(rule.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfUnitDefinitions) {

            ListOf unitDefinitionListOf = sourceModel.getListOfUnitDefinitions().clone();
            sourceModel.getListOfUnitDefinitions().removeFromParent();

            for (UnitDefinition unit : unitDefinitionListOf) {
                targetModel.addUnitDefinition(unit.clone());
            }
        }

        if (listOfObjects.getSBaseListType() == ListOf.Type.listOfLocalParameters) {

            sourceModel.getLocalParameterCount();

        }



        //TODO:
        // no longer supported? there are no get methods for this
//        ListOf.Type.listOfCompartmentTypes
//        ListOf.Type.listOfEventAssignments
//        ListOf.Type.listOfLocalParameters: there is no getter method :(
//        ListOf.Type.listOfModifiers
//        ListOf.Type.listOfSpeciesTypes
//        ListOf.Type.listOfUnits

        // maybe they are already in listOfReactions?
//        ListOf.Type.listOfProducts
//        ListOf.Type.listOfReactants


    }

    /**
     * Performs the routine to flatten a submodel into a model
     *
     * @param subModel
     * @return
     */
    private Model flattenSubModel(Submodel subModel) {

        Model model = new Model();

        // 2
        // Let 'M' be the identifier of a given submodel.
        String subModelID = subModel.getId() + "_";
        String subModelMetaID = subModel.getMetaId() + "_";

        // Verify that no object identifier or meta identifier of objects in that submodel
        // (i.e., the id or metaid attribute values)
        // begin with the character sequence "M__";

        // if there is an existing identifier or meta identifier beginning with "M__",
        // add an underscore to "M__" (i.e., to produce "M___") and again check that the sequence is unique.
        // Continue adding underscores until you find a unique prefix. Let "P" stand for this final prefix.

        while (this.previousModelIDs.contains(subModelID)) {
            subModelID += "_";
        }

        while (this.previousModelMetaIDs.contains(subModelMetaID)) {
            subModelMetaID += "_";
        }

        if(!this.previousModelIDs.isEmpty()){ // because libSBML does it
            subModelID = this.previousModelIDs.get(this.previousModelIDs.size()-1) + subModelID;
        }

        this.previousModelIDs.add(subModelID);
        this.previousModelMetaIDs.add(subModelID);

        //subModel.setId(subModelID);
        //subModel.setMetaId(subModelMetaID);

        if (subModel.getModelRef() != null) {

            // initiate a clone of the referenced model
            Model modelOfSubmodel = this.modelDefinitionListOf.get(subModel.getModelRef()).clone();

            // 3
            // Remove all objects that have been replaced or deleted in the submodel.

            // TODO Delete Objects
            // each Deletion object identifies an object to "remove" from that Model instance
            for (Deletion deletion : subModel.getListOfDeletions()) {

                // TODO: search for element to remove in all model definitions?
                this.modelDefinitionListOf.remove(deletion.getMetaIdRef());
                subModel.removeDeletion(deletion);

                //deletion.removeFromParent();
                //for (ModelDefinition modelDefinition : this.modelDefinitionListOf){
                //    modelDefinition.remove(deletion.getMetaIdRef());
                //}
                // modelOfSubmodel.remove(deletion.getMetaIdRef());

            }
            subModel.getListOfDeletions().removeFromParent();

            // TODO: Replace Objects

            // 4
            // Transform the remaining objects in the submodel as follows:
            // a)
            // Change every identifier (id attribute)
            // to a new value obtained by prepending "P" to the original identifier.
            // b)
            // Change every meta identifier (metaid attribute)
            // to a new value obtained by prepending "P" to the original identifier.

            model = flattenModel(modelOfSubmodel);

            // 5
            // Transform every SIdRef and IDREF type value in the remaining objects of the submodel as follows:
            // a)
            // If the referenced object has been replaced by the application of a ReplacedBy or ReplacedElement construct,
            // change the SIdRef value (respectively, IDREF value) to the SId value (respectively, ID value)
            // of the object replacing it.
            // b)
            // If the referenced object has not been replaced, change the SIdRef and IDREF value by prepending "P"
            // to the original value.

            // 6
            // After performing the tasks above for all remaining objects, merge the objects of the remaining submodels
            // into a single model.
            // Merge the various lists (list of species, list of compartments, etc.)
            // in this step, and preserve notes and annotations as well as constructs from other SBML Level 3 packages.

            //model = modelOfSubmodel;
            //model = mergeModels(this.previousModel, modelOfSubmodel); // initiate model (?)

        }

        return model;
    }

    private void flattenSBaseList(Model modelOfSubmodel, ListOf listOfSBase){

        ListOf list = (ListOf) listOfSBase;

        for(SBase sBase : list){

            if (!sBase.getId().equals("")) {
                sBase.setId(modelOfSubmodel.getId() + sBase.getId());
            }

            if (!sBase.getMetaId().equals("")) {
                sBase.setMetaId(modelOfSubmodel.getId() + sBase.getMetaId());
            }

            if(sBase.isPackageEnabled(CompConstants.shortLabel)){
                CompSBasePlugin compSBasePlugin = (CompSBasePlugin) sBase.getExtension(CompConstants.shortLabel);
                CompModelPlugin compModelPlugin = (CompModelPlugin) modelOfSubmodel.getExtension(CompConstants.shortLabel);

                replaceElementsInModelDefinition(compModelPlugin,compSBasePlugin);

            }
            //sBase.unsetPlugin(CompConstants.shortLabel);
        }

    }

    private Model flattenModel(Model modelOfSubmodel) {

        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfReactions());
        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfCompartments());
        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfConstraints());
        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfEvents());

        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfFunctionDefinitions());
        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfParameters());
        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfRules());
        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfSpecies());
        flattenSBaseList(modelOfSubmodel, modelOfSubmodel.getListOfUnitDefinitions());

        return modelOfSubmodel;
    }

    private void addSBaseToModel(Model model, SBase sBase) {

        if (model != null && sBase != null) {

            sBase.removeFromParent();

            if (sBase.getClass() == Reaction.class) {
                model.addReaction((Reaction) sBase);
            } else if (sBase.getClass() == Compartment.class) {
                model.addCompartment((Compartment) sBase);
            } else if (sBase.getClass() == Constraint.class) {
                model.addConstraint((Constraint) sBase);
            } else if (sBase.getClass() == Event.class) {
                model.addEvent((Event) sBase);
            } else if (sBase.getClass() == FunctionDefinition.class) {
                model.addFunctionDefinition((FunctionDefinition) sBase);
            } else if (sBase.getClass() == Parameter.class) {
                model.addParameter((Parameter) sBase);
            } else if (sBase.getClass() == Rule.class) {
                model.addRule((Rule) sBase);
            } else if (sBase.getClass() == Species.class) {
                model.addSpecies((Species) sBase);
            } else if (sBase.getClass() == UnitDefinition.class) {
                model.addUnitDefinition((UnitDefinition) sBase);
            }

        }

    }
    
    
  /**
   * Collects any {@link ExternalModelDefinition}s that might be contained in
   * the given {@link SBMLDocument} and transfers them into local
   * {@link ModelDefinition}s (recursively, if the external models themselves
   * include external models; in that case, renaming may occur).
   * 
* The given {@link SBMLDocument} need have its locationURI set! *
* Opaque URIs (URNs) will not be dealt with in any defined way, resolve them * first (make sure all relevant externalModelDefinitions' source-attributes * are URLs or relative paths) * * @param document * an {@link SBMLDocument}, which might, but need not, contain * {@link ExternalModelDefinition}s to be transferred into its local * {@link ModelDefinition}s. The locationURI of the given document need * be set ({@link SBMLDocument#isSetLocationURI})! * @return a new {@link SBMLDocument} without {@link * ExternalModelDefinition}s, but containing the same information as * the given one * @throws Exception * if given document's locationURI is not set. Set it with * {@link SBMLDocument#setLocationURI} */ public static SBMLDocument internaliseExternalModelDefinitions( SBMLDocument document) throws Exception { if (!document.isSetLocationURI()) { LOGGER.warning("Location URI is not set: " + document); throw new Exception( "document's locationURI need be set. But it was not."); } SBMLDocument result = document.clone(); // no side-effects intended ArrayList usedIds = new ArrayList(); if (result.isSetModel()) { usedIds.add(result.getModel().getId()); } CompSBMLDocumentPlugin compSBMLDocumentPlugin = (CompSBMLDocumentPlugin) result.getExtension(CompConstants.shortLabel); // There is nothing to retrieve: if (compSBMLDocumentPlugin == null || !compSBMLDocumentPlugin.isSetListOfExternalModelDefinitions()) { return result; } else { /** For name-collision-avoidance */ for (ExternalModelDefinition emd : compSBMLDocumentPlugin.getListOfExternalModelDefinitions()) { usedIds.add(emd.getId()); } for (ExternalModelDefinition emd : compSBMLDocumentPlugin.getListOfExternalModelDefinitions()) { // general note: Be careful when using clone/cloning-constructors, they // do not preserve parent-child-relations Model referenced = emd.getReferencedModel(); SBMLDocument referencedDocument = referenced.getSBMLDocument(); SBMLDocument flattened = internaliseExternalModelDefinitions(referencedDocument); // Guarantee: flattened does not contain any externalModelDefinitions, only local MDs // (and main model) // use this, and migrate the MDs into the current compSBMLDocumentPlugin StringBuilder prefixBuilder = new StringBuilder(emd.getModelRef()); /** For name-collision-avoidance */ boolean contained = false; do { contained = false; prefixBuilder.append("_"); for (String id : usedIds) { contained |= id.startsWith(prefixBuilder.toString()); if(contained) { break; } } } while (contained); String newPrefix = prefixBuilder.toString(); CompSBMLDocumentPlugin referencedDocumentPlugin = (CompSBMLDocumentPlugin) flattened.getExtension( CompConstants.shortLabel); ListOf workingList; if(referencedDocumentPlugin == null) { // This may happen, if the main model of a non-comp-file is referenced workingList = new ListOf(); workingList.setLevel(referenced.getLevel()); workingList.setVersion(referenced.getVersion()); } else { workingList = referencedDocumentPlugin.getListOfModelDefinitions().clone(); } // Check whether the main model is needed; Do not internalise it, if not necessary boolean isMainReferenced = flattened.getModel().getId().equals(emd.getModelRef()); for ( ModelDefinition md : workingList) { if(isMainReferenced) { break; } CompModelPlugin cmp = (CompModelPlugin) md.getExtension(CompConstants.shortLabel); if (cmp != null) { for (Submodel sm : cmp.getListOfSubmodels()) { isMainReferenced |= flattened.getModel().getId().equals(sm.getModelRef()); } } } if(isMainReferenced) { ModelDefinition localisedMain = new ModelDefinition(flattened.getModel()); workingList.add(0, localisedMain); } for (ModelDefinition md : workingList) { ModelDefinition internalised = new ModelDefinition(md); // i.e. current one is the one directly referenced => take referent's place if(md.getId().equals(referenced.getId())) { internalised.setId(emd.getId()); } else { internalised.setId(newPrefix + internalised.getId()); } CompModelPlugin notYetInternalisedModelPlugin = (CompModelPlugin) internalised.getExtension(CompConstants.shortLabel); if(notYetInternalisedModelPlugin != null && notYetInternalisedModelPlugin.isSetListOfSubmodels()) { for (Submodel sm : notYetInternalisedModelPlugin.getListOfSubmodels()) { sm.setModelRef(newPrefix + sm.getModelRef()); } } compSBMLDocumentPlugin.addModelDefinition(internalised); } } compSBMLDocumentPlugin.unsetListOfExternalModelDefinitions(); return result; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy