/** @cond doxygenLibsbmlInternal */ int Replacing::performConversions(SBase* replacement, ASTNode** conversionFactor) { SBMLDocument* doc = getSBMLDocument(); int ret = convertConversionFactor(conversionFactor); if (ret != LIBSBML_OPERATION_SUCCESS) { //convertConversionFactor sets its own error messages. return ret; } if (*conversionFactor==NULL) { return ret; } if (replacement==NULL) { if (doc) { string error = "Internal error in Replacing::performConversions: cannot perform a conversion of NULL."; doc->getErrorLog()->logPackageError("comp", CompModelFlatteningFailed, getPackageVersion(), getLevel(), getVersion(), error, getLine(), getColumn()); } return LIBSBML_OPERATION_FAILED; } SBase* replaced = getReferencedElement(); if (replaced==NULL) { //getReferencedElement sets its own error messages. return LIBSBML_INVALID_OBJECT; } Model* replacedmod = const_cast<Model*>(CompBase::getParentModel(replaced)); if (replacedmod==NULL) { if (doc) { string error = "Unable to perform conversion of replacement in Replacing::performConversions: No model parent could be found for replacement"; if (replacement->isSetId()) { error += replacement->getId() + "."; } doc->getErrorLog()->logPackageError("comp", CompModelFlatteningFailed, getPackageVersion(), getLevel(), getVersion(), error, getLine(), getColumn()); } return LIBSBML_INVALID_OBJECT; } if (!replacement->isSetId()) { //If the replacement has no ID, it won't need to be converted anywhere. Only theoretically possible for non-core SBase elements. return LIBSBML_OPERATION_SUCCESS; } string id = replacement->getId(); ASTNode replacementAST(AST_NAME); replacementAST.setName(id.c_str()); ASTNode divide(AST_DIVIDE); divide.addChild(replacementAST.deepCopy()); divide.addChild((*conversionFactor)->deepCopy()); List* allElements = replacedmod->getAllElements(); for (unsigned int e=0; e<allElements->getSize(); e++) { SBase* element = static_cast<SBase*>(allElements->get(e)); element->replaceSIDWithFunction(id, ÷); element->multiplyAssignmentsToSIdByFunction(id, *conversionFactor); } delete allElements; return ret; }
int Submodel::convertTimeAndExtentWith(const ASTNode* tcf, const ASTNode* xcf, const ASTNode* klmod) { if (tcf==NULL && xcf==NULL) return LIBSBML_OPERATION_SUCCESS; Model* model = getInstantiation(); if (model==NULL) { //getInstantiation sets its own error messages. return LIBSBML_OPERATION_FAILED; } ASTNode tcftimes(AST_TIMES); ASTNode tcfdiv(AST_DIVIDE); if (tcf != NULL) { tcftimes.addChild(tcf->deepCopy()); tcfdiv.addChild(tcf->deepCopy()); } ASTNode rxndivide(AST_DIVIDE); if (klmod != NULL) { ASTNode rxnref(AST_NAME); rxndivide.addChild(rxnref.deepCopy()); rxndivide.addChild(klmod->deepCopy()); } List* allElements = model->getAllElements(); for (ListIterator iter = allElements->begin(); iter != allElements->end(); ++iter) { SBase* element = static_cast<SBase*>(*iter); assert(element != NULL); ASTNode* ast1 = NULL; ASTNode* ast2 = NULL; Constraint* constraint = NULL; Delay* delay = NULL; EventAssignment* ea = NULL; InitialAssignment* ia = NULL; KineticLaw* kl = NULL; Priority* priority = NULL; RateRule* rrule = NULL; Rule* rule = NULL; Submodel* submodel = NULL; Trigger* trigger = NULL; string cf = ""; //Reaction math will be converted below, in the bits with the kinetic law. But because of that, we need to handle references *to* the reaction: even if it has no kinetic law, the units have changed, and this needs to be reflected by the flattening routine. if (rxndivide.getNumChildren() != 0 && element->getTypeCode()==SBML_REACTION && element->isSetId()) { rxndivide.getChild(0)->setName(element->getId().c_str()); for (ListIterator iter = allElements->begin(); iter != allElements->end(); ++iter) { SBase* subelement = static_cast<SBase*>(*iter); subelement->replaceSIDWithFunction(element->getId(), &rxndivide); } } //Submodels need their timeConversionFactor and extentConversionFactor attributes converted. We're moving top-down, so all we need to do here is fix the conversion factor attributes themselves, pointing them to new parameters if need be. if ((tcf !=NULL || xcf != NULL) && element->getTypeCode()==SBML_COMP_SUBMODEL) { submodel = static_cast<Submodel*>(element); if (tcf != NULL) { if (submodel->isSetTimeConversionFactor()) { createNewConversionFactor(cf, tcf, submodel->getTimeConversionFactor(), model); submodel->setTimeConversionFactor(cf); } else { submodel->setTimeConversionFactor(tcf->getName()); } } if (xcf != NULL) { if (submodel->isSetExtentConversionFactor()) { createNewConversionFactor(cf, xcf, submodel->getExtentConversionFactor(), model); submodel->setExtentConversionFactor(cf); } else { submodel->setExtentConversionFactor(xcf->getName()); } } } if (tcf==NULL) { if (klmod !=NULL && element->getTypeCode()==SBML_KINETIC_LAW) { kl = static_cast<KineticLaw*>(element); if (kl->isSetMath()) { ast1 = new ASTNode(AST_TIMES); ast1->addChild(klmod->deepCopy()); ast1->addChild(kl->getMath()->deepCopy()); kl->setMath(ast1); delete ast1; } } } else { // All math 'time' and 'delay' csymbols must still be converted. // Also, several constructs are modified directly. switch(element->getTypeCode()) { //This would be a WHOLE LOT SIMPLER if there was a 'hasMath' class in libsbml. But even so, it would have to // handle the kinetic laws, rate rules, and delays separately. case SBML_KINETIC_LAW: //Kinetic laws are multiplied by 'klmod'. kl = static_cast<KineticLaw*>(element); ast1 = kl->getMath()->deepCopy(); convertCSymbols(ast1, &tcfdiv, &tcftimes); if (klmod !=NULL) { kl = static_cast<KineticLaw*>(element); if (kl->isSetMath()) { ast2 = new ASTNode(AST_TIMES); ast2->addChild(klmod->deepCopy()); ast2->addChild(ast1); kl->setMath(ast2); delete ast2; } } else { kl->setMath(ast1); delete ast1; } break; case SBML_DELAY: //Delays are multiplied by the time conversion factor. delay = static_cast<Delay*>(element); if (delay->isSetMath()) { ast1 = delay->getMath()->deepCopy(); convertCSymbols(ast1, &tcfdiv, &tcftimes); tcftimes.addChild(ast1); delay->setMath(&tcftimes); tcftimes.removeChild(1); delete ast1; } break; case SBML_RATE_RULE: //Rate rules are divided by the time conversion factor. rrule = static_cast<RateRule*>(element); if (rrule->isSetMath()) { ast1 = rrule->getMath()->deepCopy(); tcfdiv.insertChild(0, ast1); rrule->setMath(&tcfdiv); tcfdiv.removeChild(0); delete ast1; } //Fall through to: case SBML_ASSIGNMENT_RULE: case SBML_ALGEBRAIC_RULE: //Rules in general need csymbols converted. rule = static_cast<Rule*>(element); if (rule->isSetMath()) { ast1 = rule->getMath()->deepCopy(); convertCSymbols(ast1, &tcfdiv, &tcftimes); rule->setMath(ast1); delete ast1; } break; case SBML_EVENT_ASSIGNMENT: //Event assignments need csymbols converted. ea = static_cast<EventAssignment*>(element); if (ea->isSetMath()) { ast1 = ea->getMath()->deepCopy(); convertCSymbols(ast1, &tcfdiv, &tcftimes); ea->setMath(ast1); delete ast1; } break; case SBML_INITIAL_ASSIGNMENT: //Initial assignments need csymbols converted. ia = static_cast<InitialAssignment*>(element); if (ia->isSetMath()) { ast1 = ia->getMath()->deepCopy(); convertCSymbols(ast1, &tcfdiv, &tcftimes); ia->setMath(ast1); delete ast1; } break; case SBML_CONSTRAINT: //Constraints need csymbols converted. constraint = static_cast<Constraint*>(element); if (constraint->isSetMath()) { ast1 = constraint->getMath()->deepCopy(); convertCSymbols(ast1, &tcfdiv, &tcftimes); constraint->setMath(ast1); delete ast1; } break; case SBML_PRIORITY: //Priorities need csymbols converted. priority = static_cast<Priority*>(element); if (priority->isSetMath()) { ast1 = priority->getMath()->deepCopy(); convertCSymbols(ast1, &tcfdiv, &tcftimes); priority->setMath(ast1); delete ast1; } break; case SBML_TRIGGER: //Triggers need csymbols converted. trigger = static_cast<Trigger*>(element); if (trigger->isSetMath()) { ast1 = trigger->getMath()->deepCopy(); convertCSymbols(ast1, &tcfdiv, &tcftimes); trigger->setMath(ast1); delete ast1; } break; default: //Do nothing! If we wanted to call a plugin routine, this would be the place. The only other alternative is to #ifdef some code in here that deals with the math-containing package objects explicitly. Which might be the best option, all told. break; } } } delete allElements; return LIBSBML_OPERATION_SUCCESS; }