use of org.sbml.jsbml.SimpleSpeciesReference in project vcell by virtualcell.
the class SBMLExporter method addReactions.
/**
* addReactions comment.
* @throws SbmlException
* @throws XMLStreamException
*/
protected void addReactions() throws SbmlException, XMLStreamException {
// Check if any reaction has electrical mapping
boolean bCalculatePotential = false;
StructureMapping[] structureMappings = getSelectedSimContext().getGeometryContext().getStructureMappings();
for (int i = 0; i < structureMappings.length; i++) {
if (structureMappings[i] instanceof MembraneMapping) {
if (((MembraneMapping) structureMappings[i]).getCalculateVoltage()) {
bCalculatePotential = true;
}
}
}
// If it does, VCell doesn't export it to SBML (no representation).
if (bCalculatePotential) {
throw new RuntimeException("This VCell model has Electrical mapping; cannot be exported to SBML at this time");
}
l2gMap.clear();
ReactionSpec[] vcReactionSpecs = getSelectedSimContext().getReactionContext().getReactionSpecs();
for (int i = 0; i < vcReactionSpecs.length; i++) {
if (vcReactionSpecs[i].isExcluded()) {
continue;
}
ReactionStep vcReactionStep = vcReactionSpecs[i].getReactionStep();
// Create sbml reaction
String rxnName = vcReactionStep.getName();
org.sbml.jsbml.Reaction sbmlReaction = sbmlModel.createReaction();
sbmlReaction.setId(org.vcell.util.TokenMangler.mangleToSName(rxnName));
sbmlReaction.setName(rxnName);
String rxnSbmlName = vcReactionStep.getSbmlName();
if (rxnSbmlName != null && !rxnSbmlName.isEmpty()) {
sbmlReaction.setName(rxnSbmlName);
}
// If the reactionStep is a flux reaction, add the details to the annotation (structure, carrier valence, flux carrier, fluxOption, etc.)
// If reactionStep is a simple reaction, add annotation to indicate the structure of reaction.
// Useful when roundtripping ...
Element sbmlImportRelatedElement = null;
// try {
// sbmlImportRelatedElement = getAnnotationElement(vcReactionStep);
// } catch (XmlParseException e1) {
// e1.printStackTrace(System.out);
// // throw new RuntimeException("Error ");
// }
// Get annotation (RDF and non-RDF) for reactionStep from SBMLAnnotationUtils
sbmlAnnotationUtil.writeAnnotation(vcReactionStep, sbmlReaction, sbmlImportRelatedElement);
// Now set notes,
sbmlAnnotationUtil.writeNotes(vcReactionStep, sbmlReaction);
// Get reaction kineticLaw
Kinetics vcRxnKinetics = vcReactionStep.getKinetics();
org.sbml.jsbml.KineticLaw sbmlKLaw = sbmlReaction.createKineticLaw();
try {
// Convert expression from kinetics rate parameter into MathML and use libSBMl utilities to convert it to formula
// (instead of directly using rate parameter's expression infix) to maintain integrity of formula :
// for example logical and inequalities are not handled gracefully by libSBMl if expression.infix is used.
final Expression localRateExpr;
final Expression lumpedRateExpr;
if (vcRxnKinetics instanceof DistributedKinetics) {
localRateExpr = ((DistributedKinetics) vcRxnKinetics).getReactionRateParameter().getExpression();
lumpedRateExpr = null;
} else if (vcRxnKinetics instanceof LumpedKinetics) {
localRateExpr = null;
lumpedRateExpr = ((LumpedKinetics) vcRxnKinetics).getLumpedReactionRateParameter().getExpression();
} else {
throw new RuntimeException("unexpected Rate Law '" + vcRxnKinetics.getClass().getSimpleName() + "', not distributed or lumped type");
}
// if (vcRxnKinetics instanceof DistributedKinetics)
// Expression correctedRateExpr = kineticsAdapter.getExpression();
// Add parameters, if any, to the kineticLaw
Kinetics.KineticsParameter[] vcKineticsParams = vcRxnKinetics.getKineticsParameters();
// In the first pass thro' the kinetic params, store the non-numeric param names and expressions in arrays
String[] kinParamNames = new String[vcKineticsParams.length];
Expression[] kinParamExprs = new Expression[vcKineticsParams.length];
for (int j = 0; j < vcKineticsParams.length; j++) {
if (true) {
// Since local reaction parameters cannot be defined by a rule, such parameters (with rules) are exported as global parameters.
if ((vcKineticsParams[j].getRole() == Kinetics.ROLE_CurrentDensity && (!vcKineticsParams[j].getExpression().isZero())) || (vcKineticsParams[j].getRole() == Kinetics.ROLE_LumpedCurrent && (!vcKineticsParams[j].getExpression().isZero()))) {
throw new RuntimeException("Electric current not handled by SBML export; failed to export reaction \"" + vcReactionStep.getName() + "\" at this time");
}
if (!vcKineticsParams[j].getExpression().isNumeric()) {
// NON_NUMERIC KINETIC PARAM
// Create new name for kinetic parameter and store it in kinParamNames, store corresponding exprs in kinParamExprs
// Will be used later to add this param as global.
String newParamName = TokenMangler.mangleToSName(vcKineticsParams[j].getName() + "_" + vcReactionStep.getName());
kinParamNames[j] = newParamName;
kinParamExprs[j] = new Expression(vcKineticsParams[j].getExpression());
}
}
}
// If so, these need to be added as global param (else the SBML doc will not be valid)
for (int j = 0; j < vcKineticsParams.length; j++) {
final KineticsParameter vcKParam = vcKineticsParams[j];
if ((vcKParam.getRole() != Kinetics.ROLE_ReactionRate) && (vcKParam.getRole() != Kinetics.ROLE_LumpedReactionRate)) {
// if expression of kinetic param evaluates to a double, the parameter value is set
if ((vcKParam.getRole() == Kinetics.ROLE_CurrentDensity && (!vcKParam.getExpression().isZero())) || (vcKParam.getRole() == Kinetics.ROLE_LumpedCurrent && (!vcKParam.getExpression().isZero()))) {
throw new RuntimeException("Electric current not handled by SBML export; failed to export reaction \"" + vcReactionStep.getName() + "\" at this time");
}
if (vcKParam.getExpression().isNumeric()) {
// NUMERIC KINETIC PARAM
// check if it is used in other parameters that have expressions,
boolean bAddedParam = false;
String origParamName = vcKParam.getName();
String newParamName = TokenMangler.mangleToSName(origParamName + "_" + vcReactionStep.getName());
VCUnitDefinition vcUnit = vcKParam.getUnitDefinition();
for (int k = 0; k < vcKineticsParams.length; k++) {
if (kinParamExprs[k] != null) {
// The param could be in the expression for any other param
if (kinParamExprs[k].hasSymbol(origParamName)) {
// mangle its name to avoid conflict with other globals
if (globalParamNamesHash.get(newParamName) == null) {
globalParamNamesHash.put(newParamName, newParamName);
org.sbml.jsbml.Parameter sbmlKinParam = sbmlModel.createParameter();
sbmlKinParam.setId(newParamName);
sbmlKinParam.setValue(vcKParam.getConstantValue());
final boolean constValue = vcKParam.isConstant();
sbmlKinParam.setConstant(true);
// Set SBML units for sbmlParam using VC units from vcParam
if (!vcUnit.isTBD()) {
UnitDefinition unitDefn = getOrCreateSBMLUnit(vcUnit);
sbmlKinParam.setUnits(unitDefn);
}
Pair<String, String> origParam = new Pair<String, String>(rxnName, origParamName);
l2gMap.put(origParam, newParamName);
bAddedParam = true;
} else {
// need to get another name for param and need to change all its refereces in the other kinParam euqations.
}
// update the expression to contain new name, since the globalparam has new name
kinParamExprs[k].substituteInPlace(new Expression(origParamName), new Expression(newParamName));
}
}
}
// If the param hasn't been added yet, it is definitely a local param. add it to kineticLaw now.
if (!bAddedParam) {
org.sbml.jsbml.LocalParameter sbmlKinParam = sbmlKLaw.createLocalParameter();
sbmlKinParam.setId(origParamName);
sbmlKinParam.setValue(vcKParam.getConstantValue());
System.out.println("tis constant " + sbmlKinParam.isExplicitlySetConstant());
// Set SBML units for sbmlParam using VC units from vcParam
if (!vcUnit.isTBD()) {
UnitDefinition unitDefn = getOrCreateSBMLUnit(vcUnit);
sbmlKinParam.setUnits(unitDefn);
}
} else {
// hence change its occurance in rate expression if it contains that param name
if (localRateExpr != null && localRateExpr.hasSymbol(origParamName)) {
localRateExpr.substituteInPlace(new Expression(origParamName), new Expression(newParamName));
}
if (lumpedRateExpr != null && lumpedRateExpr.hasSymbol(origParamName)) {
lumpedRateExpr.substituteInPlace(new Expression(origParamName), new Expression(newParamName));
}
}
}
}
}
// (using the kinParamNames and kinParamExprs above) to ensure uniqueness in the global parameter names.
for (int j = 0; j < vcKineticsParams.length; j++) {
if (((vcKineticsParams[j].getRole() != Kinetics.ROLE_ReactionRate) && (vcKineticsParams[j].getRole() != Kinetics.ROLE_LumpedReactionRate)) && !(vcKineticsParams[j].getExpression().isNumeric())) {
String oldName = vcKineticsParams[j].getName();
String newName = kinParamNames[j];
// change the name of this parameter in the rate expression
if (localRateExpr != null && localRateExpr.hasSymbol(oldName)) {
localRateExpr.substituteInPlace(new Expression(oldName), new Expression(newName));
}
if (lumpedRateExpr != null && lumpedRateExpr.hasSymbol(oldName)) {
lumpedRateExpr.substituteInPlace(new Expression(oldName), new Expression(newName));
}
// Change the occurence of this param in other param expressions
for (int k = 0; k < vcKineticsParams.length; k++) {
if (((vcKineticsParams[k].getRole() != Kinetics.ROLE_ReactionRate) && (vcKineticsParams[j].getRole() != Kinetics.ROLE_LumpedReactionRate)) && !(vcKineticsParams[k].getExpression().isNumeric())) {
if (k != j && vcKineticsParams[k].getExpression().hasSymbol(oldName)) {
// for all params except the current param represented by index j (whose name was changed)
kinParamExprs[k].substituteInPlace(new Expression(oldName), new Expression(newName));
}
if (k == j && vcKineticsParams[k].getExpression().hasSymbol(oldName)) {
throw new RuntimeException("A parameter cannot refer to itself in its expression");
}
}
}
// end for - k
}
}
// In the fifth pass thro' the kinetic params, the non-numeric params are added to the global params of the model
for (int j = 0; j < vcKineticsParams.length; j++) {
if (((vcKineticsParams[j].getRole() != Kinetics.ROLE_ReactionRate) && (vcKineticsParams[j].getRole() != Kinetics.ROLE_LumpedReactionRate)) && !(vcKineticsParams[j].getExpression().isNumeric())) {
// Now, add this param to the globalParamNamesHash and add a global parameter to the sbmlModel
String paramName = kinParamNames[j];
if (globalParamNamesHash.get(paramName) == null) {
globalParamNamesHash.put(paramName, paramName);
} else {
// need to get another name for param and need to change all its refereces in the other kinParam euqations.
}
Pair<String, String> origParam = new Pair<String, String>(rxnName, paramName);
// keeps its name but becomes a global (?)
l2gMap.put(origParam, paramName);
ASTNode paramFormulaNode = getFormulaFromExpression(kinParamExprs[j]);
AssignmentRule sbmlParamAssignmentRule = sbmlModel.createAssignmentRule();
sbmlParamAssignmentRule.setVariable(paramName);
sbmlParamAssignmentRule.setMath(paramFormulaNode);
org.sbml.jsbml.Parameter sbmlKinParam = sbmlModel.createParameter();
sbmlKinParam.setId(paramName);
if (!vcKineticsParams[j].getUnitDefinition().isTBD()) {
sbmlKinParam.setUnits(getOrCreateSBMLUnit(vcKineticsParams[j].getUnitDefinition()));
}
// Since the parameter is being specified by a Rule, its 'constant' field shoud be set to 'false' (default - true).
sbmlKinParam.setConstant(false);
}
}
// end for (j) - fifth pass
// After making all necessary adjustments to the rate expression, now set the sbmlKLaw.
final ASTNode exprFormulaNode;
if (lumpedRateExpr != null) {
exprFormulaNode = getFormulaFromExpression(lumpedRateExpr);
} else {
if (bSpatial) {
exprFormulaNode = getFormulaFromExpression(localRateExpr);
} else {
exprFormulaNode = getFormulaFromExpression(Expression.mult(localRateExpr, new Expression(vcReactionStep.getStructure().getName())));
}
}
sbmlKLaw.setMath(exprFormulaNode);
} catch (cbit.vcell.parser.ExpressionException e) {
e.printStackTrace(System.out);
throw new RuntimeException("Error getting value of parameter : " + e.getMessage());
}
// Add kineticLaw to sbmlReaction - not needed now, since we use sbmlRxn.createKLaw() ??
// sbmlReaction.setKineticLaw(sbmlKLaw);
// Add reactants, products, modifiers
// Simple reactions have catalysts, fluxes have 'flux'
cbit.vcell.model.ReactionParticipant[] rxnParticipants = vcReactionStep.getReactionParticipants();
for (ReactionParticipant rxnParticpant : rxnParticipants) {
SimpleSpeciesReference ssr = null;
SpeciesReference sr = null;
// to get unique ID when the same species is both a reactant and a product
String rolePostfix = "";
if (rxnParticpant instanceof cbit.vcell.model.Reactant) {
rolePostfix = "r";
ssr = sr = sbmlReaction.createReactant();
} else if (rxnParticpant instanceof cbit.vcell.model.Product) {
rolePostfix = "p";
ssr = sr = sbmlReaction.createProduct();
}
if (rxnParticpant instanceof cbit.vcell.model.Catalyst) {
rolePostfix = "c";
ssr = sbmlReaction.createModifier();
}
if (ssr != null) {
ssr.setSpecies(rxnParticpant.getSpeciesContext().getName());
}
if (sr != null) {
sr.setStoichiometry(Double.parseDouble(Integer.toString(rxnParticpant.getStoichiometry())));
String modelUniqueName = vcReactionStep.getName() + '_' + rxnParticpant.getName() + rolePostfix;
sr.setId(TokenMangler.mangleToSName(modelUniqueName));
// SBML-REVIEW
sr.setConstant(true);
// int rcode = sr.appendNotes("<
// we know that in VCell we can't override stoichiometry anywhere, below is no longer questionable
// try {
// SBMLHelper.addNote(sr, "VCELL guess: how do we know if reaction is constant?");
// } catch (Exception e) {
// e.printStackTrace();
// }
}
}
sbmlReaction.setFast(vcReactionSpecs[i].isFast());
// this attribute is mandatory for L3, optional for L2. So explicitly setting value.
sbmlReaction.setReversible(true);
if (bSpatial) {
// set compartment for reaction if spatial
sbmlReaction.setCompartment(vcReactionStep.getStructure().getName());
// CORE HAS ALT MATH true
// set the "isLocal" attribute = true (in 'spatial' namespace) for each species
SpatialReactionPlugin srplugin = (SpatialReactionPlugin) sbmlReaction.getPlugin(SBMLUtils.SBML_SPATIAL_NS_PREFIX);
srplugin.setIsLocal(vcRxnKinetics instanceof DistributedKinetics);
}
}
}
Aggregations