void CellmlFile::retrieveCmetaIdsFromCellmlElement(iface::cellml_api::CellMLElement *pElement) { // Keep track of the given CellML element's cmeta:id QString cmetaId = QString::fromStdWString(pElement->cmetaId()); if (!cmetaId.isEmpty()) mUsedCmetaIds << cmetaId; // Do the same for all the child elements of the given CellML element ObjRef<iface::cellml_api::CellMLElementSet> childElements = pElement->childElements(); ObjRef<iface::cellml_api::CellMLElementIterator> childElementsIter = childElements->iterate(); try { for (ObjRef<iface::cellml_api::CellMLElement> childElement = childElementsIter->next(); childElement; childElement = childElementsIter->next()) { retrieveCmetaIdsFromCellmlElement(childElement); } } catch (...) { // Note: we should never reach this point, but it may still happen if a // CellML file contains a child element that is not known to the // CellML API. We are taking the view that this is a limitation of // the CellML API and shouldn't therefore generate an error for // something that should have been working fine in the first // place... } }
void CellmlFileRuntime::retrieveDaeCodeInformation(iface::cellml_api::Model *pModel) { // Get a code generator bootstrap and create a DAE code generator ObjRef<iface::cellml_services::CodeGeneratorBootstrap> codeGeneratorBootstrap = CreateCodeGeneratorBootstrap(); ObjRef<iface::cellml_services::IDACodeGenerator> codeGenerator = codeGeneratorBootstrap->createIDACodeGenerator(); // Generate some code for the model try { mDaeCodeInformation = codeGenerator->generateIDACode(pModel); // Check that the code generation went fine checkCodeInformation(mDaeCodeInformation); } catch (iface::cellml_api::CellMLException &exception) { couldNotGenerateModelCodeIssue(Core::formatMessage(QString::fromStdWString(exception.explanation))); } catch (...) { unknownProblemDuringModelCodeGenerationIssue(); } // Check the outcome of the DAE code generation if (mIssues.count()) resetDaeCodeInformation(); }
double SingleCellViewSimulation::requiredMemory() { // Determine and return the amount of required memory to run our simulation // Note #1: we return the amount as a double rather than a qulonglong (as we // do when retrieving the total/free amount of memory available; // see [OpenCOR]/src/plugins/misc/Core/src/coreutils.cpp) in case a // simulation requires an insane amount of memory... // Note #2: the 1 is for mPoints in SingleCellViewSimulationResults... iface::cellml_services::CellMLCompiledModel* compModel(mData->isDAETypeSolver() ? static_cast<iface::cellml_services::CellMLCompiledModel*> (mRuntime->daeCompiledModel()) : static_cast<iface::cellml_services::CellMLCompiledModel*> (mRuntime->odeCompiledModel())); ObjRef<iface::cellml_services::CodeInformation> codeInfo (compModel->codeInformation()); // This is not very accurate at all, because the solver caches a lot more // information about the problem being solved, some of it bigger than any // of the below (e.g. Jacobian matricies. Given the solver dependence of // this size, I'm not sure this function is that useful. return size() * (1 + codeInfo->constantIndexCount() + codeInfo->rateIndexCount() * 3 + codeInfo->algebraicIndexCount()) * sizeof(double); }
QStringList CellmlFileRuntime::componentHierarchy(iface::cellml_api::CellMLElement *pElement) { // Make sure that we have a given element if (!pElement) return QStringList(); // Try to retrieve the component that owns the given element, unless the // given element is a component itself (which will be the case when we come // here through recursion) ObjRef<iface::cellml_api::CellMLComponent> component = QueryInterface(pElement); ObjRef<iface::cellml_api::CellMLElement> parent = pElement->parentElement(); ObjRef<iface::cellml_api::CellMLComponent> parentComponent = QueryInterface(parent); if (!component && !parentComponent) { // The element isn't a component and neither is its parent, so it // doesn't have a hierarchy return QStringList(); } // Recursively retrieve the component hierarchy of the given element's // encapsulation parent, if any ObjRef<iface::cellml_api::CellMLComponent> componentEncapsulationParent = component?component->encapsulationParent():parentComponent->encapsulationParent(); return componentHierarchy(componentEncapsulationParent) << QString::fromStdWString(component?component->name():parentComponent->name()); }
//! (static) std::pair<bool, ObjRef> loadAndExecute(Runtime & runtime, const std::string & filename) { ObjRef script; try { script = loadScriptFile(filename); } catch (Exception * error) { std::cerr << "\nError occurred while loading file '" << filename << "':\n" << error->toString() << std::endl; return std::make_pair(false, error); } bool success = true; ObjRef result; try { runtime.executeObj(script.get()); result = runtime.getResult(); if(runtime.getState() == Runtime::STATE_EXCEPTION) { std::cout << "\nException caught (1):\n" << result.toString() << std::endl; success = false; } } catch (Object * o) { result = o; std::cout << "\nException caught (2):\n" << result.toString() << std::endl; success = false; } catch (...) { std::cout << "\nCaught unknown C++ exception." << std::endl; success = false; } return std::make_pair(success, result); }
QString CellmlFile::xmlBase() { // Return the CellML file's base URI if (load()) { ObjRef<iface::cellml_api::URI> baseUri = mModel->xmlBase(); return QString::fromStdWString(baseUri->asText()); } else { return QString(); } }
bool CellmlFile::load() { // Check whether the file is already loaded and without any issues if (!mLoadingNeeded) return mIssues.isEmpty(); // Consider the file loaded // Note: even when we can't load the file, we still consider it 'loaded' // since we at least tried to load it, so unless the file gets // modified (and we are to reload it), we are 'fine'... mLoadingNeeded = false; // Try to load the model if (!doLoad(mFileName, QString(), &mModel, mIssues)) return false; // Retrieve all the RDF triples associated with the model and initialise our // list of original RDF triples ObjRef<iface::cellml_api::RDFRepresentation> rdfRepresentation = mModel->getRDFRepresentation(L"http://www.cellml.org/RDF/API"); if (rdfRepresentation) { mRdfApiRepresentation = QueryInterface(rdfRepresentation); if (mRdfApiRepresentation) { mRdfDataSource = mRdfApiRepresentation->source(); ObjRef<iface::rdf_api::TripleSet> rdfTriples = mRdfDataSource->getAllTriples(); ObjRef<iface::rdf_api::TripleEnumerator> rdfTriplesEnumerator = rdfTriples->enumerateTriples(); for (ObjRef<iface::rdf_api::Triple> rdfTriple = rdfTriplesEnumerator->getNextTriple(); rdfTriple; rdfTriple = rdfTriplesEnumerator->getNextTriple()) { mRdfTriples << new CellmlFileRdfTriple(this, rdfTriple); } mRdfTriples.updateOriginalRdfTriples(); } } // Determine which cmeta:ids are currently in use, be they in the various // CellML elements or RDF triples retrieveCmetaIdsFromCellmlElement(mModel); foreach (CellmlFileRdfTriple *rdfTriple, mRdfTriples) mUsedCmetaIds << rdfTriple->metadataId(); mUsedCmetaIds.removeDuplicates(); return true; }
void SingleCellViewSimulationData::startNextRepeat() { mCurrentRepeat++; if (mCurrentRepeat >= solverProperties()["nrepeats"].toInt()) { emit simulationComplete(); return; } if (mCurrentRepeat == 0) mStatesWhenRun = mStates; else mStates = mStatesWhenRun; newIntegrationRun(); if (!mIntegrationRun) return; mState = SingleCellViewSimulationData::SIMSTATE_WAITING_RESULTS; iface::cellml_services::CellMLCompiledModel* compModel(isDAETypeSolver() ? static_cast<iface::cellml_services::CellMLCompiledModel*> (mRuntime->daeCompiledModel()) : static_cast<iface::cellml_services::CellMLCompiledModel*> (mRuntime->odeCompiledModel())); ObjRef<iface::cellml_services::CodeInformation> codeInfo (compModel->codeInformation()); mResultReceiver = new ResultListener(mIntegrationRun, codeInfo->rateIndexCount(), codeInfo->algebraicIndexCount()); mResultReceiver->delay(mDelay); mIntegrationRun->setStepSizeControl(mSolverProperties["absTol"].toDouble(), mSolverProperties["relTol"].toDouble(), 1.0, // Scaling factor: states 1.0, // Scaling factor: rates mSolverProperties["maxStep"].toDouble()); mIntegrationRun->setResultRange(mStartingPoint, mEndingPoint, 10000.0 // Maximum density of points in bvar, as an upper bound on the number // of points returned. ); mIntegrationRun->setProgressObserver(mResultReceiver); QObject::connect(mResultReceiver, SIGNAL(constantsAvailable(const QList<double>)), this, SIGNAL(constantsAvailable(const QList<double>))); QObject::connect(mResultReceiver, SIGNAL(solveDone()), this, SLOT(startNextRepeat())); QObject::connect(mResultReceiver, SIGNAL(solveFailure(QString)), this, SIGNAL(simulationFailed(QString))); QObject::connect(mResultReceiver, SIGNAL(solvePointAvailable(double,QList<double>,QList<double>,QList<double>)), this, SIGNAL(simulationDataAvailable(double,QList<double>,QList<double>,QList<double>))); setupOverrides(); mIntegrationRun->start(); }
//! (static) std::pair<bool, ObjRef> loadAndExecute(Runtime & runtime, const std::string & filename) { try { ObjRef result = _loadAndExecute(runtime,filename); ObjRef exitResult = runtime.fetchAndClearExitResult(); return std::make_pair(true,exitResult.isNotNull() ? exitResult : result); } catch (Object * error) { std::ostringstream os; os << "Error occurred while loading file '" << filename << "':\n" << error->toString() << std::endl; runtime.log(Logger::LOG_ERROR,os.str()); return std::make_pair(false, error); } // }catch(...){ // std::cout << "\nCaught unknown C++ exception." << std::endl; // return std::make_pair(false, result.detachAndDecrease()); }
bool CellmlFileManager::canLoadFileContents(const QString &pFileContents) const { // Try to load the CellML file contents ObjRef<iface::cellml_api::CellMLBootstrap> cellmlBootstrap = CreateCellMLBootstrap(); ObjRef<iface::cellml_api::DOMModelLoader> modelLoader = cellmlBootstrap->modelLoader(); ObjRef<iface::cellml_api::Model> model; try { model = modelLoader->createFromText(pFileContents.toStdWString()); return true; } catch (iface::cellml_api::CellMLException &) { return false; } }
void CDA_CellMLElement::addEventListener ( const std::wstring& aType, iface::events::EventListener* aListener, bool aUseCapture ) throw(std::exception&) { // Only bubbling is supported, as these events can't be cancelled. if (aUseCapture) throw iface::cellml_api::CellMLException(L"Only bubbling events are supported."); int32_t event = FindEventByName(aType); // Unknown events are silently ignored, as per the DOM Events specification. if (event == -1) return; // Find the adaptor, if there is one... ListenerToAdaptor_t::iterator i = mListenerToAdaptor.find(aListener); ObjRef<CDA_CellMLElementEventAdaptor> adaptor; if (i == mListenerToAdaptor.end()) { // We add a refcount, putting the total to 2... adaptor = new CDA_CellMLElementEventAdaptor(this, aListener); // One refcount is used for the map, the other belongs to the ObjRef and // will be automatically dropped. mListenerToAdaptor.insert(std::pair<iface::events::EventListener*, CDA_CellMLElementEventAdaptor*> (aListener, adaptor) ); } else adaptor = (*i).second; try { adaptor->newEventType(event); } catch (std::exception& e) { adaptor->considerDestruction(); throw e; } }
std::wstring CompactorReport::getReport() const { std::wstringstream report; report << L"Model Compaction Report\n" << L"=======================\n\n"; if (! mErrorMessage.empty()) report << L"Error message: " << mErrorMessage << L"\n\n"; std::wstring indent = L""; if (mVariableForCompaction.size() > 0) { report << L"Some variables have not been compacted.\n" << L"Uncompacted variables are given below.\n\n"; for (size_t i=0; i<mVariableForCompaction.size(); ++i) { ObjRef<iface::cellml_api::CellMLVariable> variable = mVariableForCompaction[i].first; ObjRef<iface::cellml_api::CellMLVariable> srcVariable = mVariableForCompaction[i].second; std::wstring modelUri = variable->modelElement()->base_uri()->asText(); std::wstring srcModelUri = srcVariable->modelElement()->base_uri()->asText(); for (size_t j=0;j<i;++j) indent += L"\t"; report << indent << L"Compaction requested for variable: " << modelUri << L" # " << variable->componentName() << L" / " << variable->name() << L";\n" << indent << L"with the actual source variable being: " << srcModelUri << L" # " << srcVariable->componentName() << L" / " << srcVariable->name() << L"\n"; } } report.flush(); return report.str(); }
/*! Tries to locate the given __filename__ with the current searchPath set in the runtime. @return the path to the file or the original __filename__ if the file could not be found. */ static std::string findFile(Runtime & runtime, const std::string & filename){ static const StringId seachPathsId("__searchPaths"); std::string file(IO::condensePath(filename)); if( IO::getEntryType(file)!=IO::TYPE_FILE ){ if(Array * searchPaths = dynamic_cast<Array*>(runtime.getAttribute(seachPathsId).getValue())){ for(ERef<Iterator> itRef=searchPaths->getIterator();!itRef->end();itRef->next()){ ObjRef valueRef = itRef->value(); std::string s(IO::condensePath(valueRef.toString()+'/'+filename)); if( IO::getEntryType(s)==IO::TYPE_FILE ){ file = s; break; } } } } return file; }
/*! Tries to locate the given __filename__ with the current searchPath set in the runtime. @return the path to the file or the original __filename__ if the file could not be found. */ static std::string findFile(Runtime & runtime, const std::string & filename){ static const identifierId seachPathsId=stringToIdentifierId("__searchPaths"); std::string file(FileUtils::condensePath(filename)); if( FileUtils::isFile(file)!=1 ){ if(Array * searchPaths = dynamic_cast<Array*>(runtime.getAttribute(seachPathsId))){ for(ERef<Iterator> itRef=searchPaths->getIterator();!itRef->end();itRef->next()){ ObjRef valueRef = itRef->value(); std::string s(FileUtils::condensePath(valueRef.toString()+"/"+filename)); if( FileUtils::isFile(s)==1 ){ file = s; break; } } } } return file; }
bool CellmlFile::doLoad(const QString &pFileName, const QString &pFileContents, ObjRef<iface::cellml_api::Model> *pModel, CellmlFileIssues &pIssues) { // Make sure that pIssues is empty pIssues.clear(); // Get a bootstrap object and its model loader ObjRef<iface::cellml_api::CellMLBootstrap> cellmlBootstrap = CreateCellMLBootstrap(); ObjRef<iface::cellml_api::DOMModelLoader> modelLoader = cellmlBootstrap->modelLoader(); // Try to create the model try { if (pFileContents.isEmpty()) *pModel = modelLoader->loadFromURL(QUrl::fromPercentEncoding(QUrl::fromLocalFile(pFileName).toEncoded()).toStdWString()); else *pModel = modelLoader->createFromText(pFileContents.toStdWString()); } catch (iface::cellml_api::CellMLException &exception) { // Something went wrong with the loading of the model if (pFileContents.isEmpty()) { pIssues << CellmlFileIssue(CellmlFileIssue::Error, QObject::tr("the model could not be loaded (%1)").arg(Core::formatMessage(QString::fromStdWString(exception.explanation)))); } else { pIssues << CellmlFileIssue(CellmlFileIssue::Error, QObject::tr("the model could not be created (%1)").arg(Core::formatMessage(QString::fromStdWString(exception.explanation)))); } return false; } // Update the base URI, should the CellML file be a remote one or its // contents be directly passed onto us Core::FileManager *fileManagerInstance = Core::FileManager::instance(); ObjRef<iface::cellml_api::URI> baseUri = (*pModel)->xmlBase(); if (fileManagerInstance->isRemote(pFileName)) { // We are dealing with a remote file, so its XML base value should point // to its remote location baseUri->asText(fileManagerInstance->url(pFileName).toStdWString()); } else if (!pFileContents.isEmpty()) { // We are dealing with a file which contents was directly passed onto // us, so its XML base value should point to its actual location baseUri->asText(pFileName.toStdWString()); } return true; }
bool isCellmlFile(const QString &pFileName) { // If the given file is already managed by our CellML file manager, then we // consider that it's still a CellML file (even though it may not be a // CellML file anymore after having been edited and saved, but in this case // it's good to keep considering the file as a CellML file, so that the user // can continue editing it for example) QString nativeFileName = Core::nativeCanonicalFileName(pFileName); if (CellMLSupport::CellmlFileManager::instance()->cellmlFile(nativeFileName)) return true; // The given file is not managed by our CellML file manager, so check // whether it's a new file and, if so, consider it as a CellML file if (Core::FileManager::instance()->isNew(nativeFileName)) return true; // Check whether we are dealing with an empty file or a file that contains // spaces of sorts and, if not, whether we can load it using the CellML API QString fileContents; if (Core::readTextFromFile(nativeFileName, fileContents)) { if (fileContents.trimmed().isEmpty()) return true; ObjRef<iface::cellml_api::CellMLBootstrap> cellmlBootstrap = CreateCellMLBootstrap(); ObjRef<iface::cellml_api::DOMModelLoader> modelLoader = cellmlBootstrap->modelLoader(); ObjRef<iface::cellml_api::Model> model; try { model = modelLoader->createFromText(fileContents.toStdWString()); return true; } catch (iface::cellml_api::CellMLException &) { return false; } } else { return false; } }
Util::GenericAttribute * convertFromEScript(const EScript::ObjPtr & object) override { // is a Number? EScript::Number * n = dynamic_cast<EScript::Number *> (object.get()); if (n != nullptr) { return GenericAttribute::createNumber(n->getValue()); } // is a Bool? EScript::Bool * b = dynamic_cast<EScript::Bool *> (object.get()); if (b != nullptr) { return GenericAttribute::createBool(b->toBool()); } // is a String? EScript::String * s = dynamic_cast<EScript::String *> (object.get()); if (s != nullptr) { return GenericAttribute::createString(s->getString()); } // is an Array? EScript::Array * a = dynamic_cast<EScript::Array *> (object.get()); if (a != nullptr) { auto gl = new Util::GenericAttributeList; for (ERef<EScript::Iterator> i = a->getIterator(); !i->end(); i->next()) { ObjRef value = i->value(); gl->push_back(convertEScriptObjectToGenericAttribute(value)); } return gl; } // is a Map? EScript::Map * m = dynamic_cast<EScript::Map *> (object.get()); if (m != nullptr) { auto gm = new Util::GenericAttributeMap; for (ERef<EScript::Iterator> i = m->getIterator(); !i->end(); i->next()) { ObjRef key = i->key(); ObjRef value = i->value(); gm->setValue(key->toString(), convertEScriptObjectToGenericAttribute(value)); } return gm; } return nullptr; }
void operator= (const ObjRef<U>& newAssign) { T* nap = newAssign.getPointer(); if (mPtr == nap) return; if (mPtr) mPtr->release_ref(); mPtr = nap; if (mPtr != NULL) mPtr->add_ref(); }
void SingleCellViewSimulationData::setupOverrides() { iface::cellml_services::CellMLCompiledModel* compModel(isDAETypeSolver() ? static_cast<iface::cellml_services::CellMLCompiledModel*> (mRuntime->daeCompiledModel()) : static_cast<iface::cellml_services::CellMLCompiledModel*> (mRuntime->odeCompiledModel())); ObjRef<iface::cellml_services::CodeInformation> codeInfo (compModel->codeInformation()); for (unsigned int i = 0; i < codeInfo->constantIndexCount(); i++) if (mInitialConstants[i] != mConstants[i]) mIntegrationRun->setOverride(iface::cellml_services::CONSTANT, i, mConstants[i]); for (unsigned int i = 0; i < codeInfo->rateIndexCount(); i++) if (mInitialStates[i] != mStates[i]) mIntegrationRun->setOverride(iface::cellml_services::STATE_VARIABLE, i, mStates[i]); }
int CellmlModelDefinition::loadModelFromString(const std::string &ms) { std::cout << "Creating CellML Model Definition from the given model string" << std::endl; mUrl = ""; std::wstring msW = s2ws(ms); ObjRef<iface::cellml_api::CellMLBootstrap> cb = CreateCellMLBootstrap(); ObjRef<iface::cellml_api::DOMModelLoader> ml = cb->modelLoader(); int code; try { ObjRef<iface::cellml_api::Model> model = ml->createFromText(msW); model->fullyInstantiateImports(); // we have a model, so we can start grabbing hold of the CellML API objects mCapi = new CellmlApiObjects(); mCapi->model = model; code = instantiateCellmlApiObjects(); } catch (...) { std::wcerr << L"Error loading model from string." << std::endl; return -1; } return code; }
int CellmlModelDefinition::loadModel(const std::string &url) { std::cout << "Creating CellML Model Definition from the URL: " << url << std::endl; mUrl = url; if (mUrl.empty()) return -1; std::wstring urlW = s2ws(url); ObjRef<iface::cellml_api::CellMLBootstrap> cb = CreateCellMLBootstrap(); ObjRef<iface::cellml_api::DOMModelLoader> ml = cb->modelLoader(); int code; try { ObjRef<iface::cellml_api::Model> model = ml->loadFromURL(urlW); model->fullyInstantiateImports(); // we have a model, so we can start grabbing hold of the CellML API objects mCapi = new CellmlApiObjects(); mCapi->model = model; code = instantiateCellmlApiObjects(); } catch (...) { std::wcerr << L"Error loading model: " << urlW << std::endl; return -1; } return code; }
//! ---|> [Object] Object * ForeachControl::execute(Runtime & rt) { ERef<Iterator> itRef=dynamic_cast<Iterator *>(rt.executeObj(arrayExpressionRef.get())); if(!rt.assertNormalState(this) || itRef.isNull()) return NULL; ObjRef resultRef; while (!itRef->end()) { if (keyVar) rt.assignToVariable(keyVar,itRef->key()); if (valueVar) rt.assignToVariable(valueVar,itRef->value()); if(!actionRef.isNull()){ try { resultRef=rt.executeObj(actionRef.get()); } catch (Object * e) { std::cout << "###"<<e<<itRef->key(); throw(e); } if(!rt.checkNormalState()){ if(rt.getState()==Runtime::STATE_BREAKING){ rt.resetState(); break; }else if(rt.getState()==Runtime::STATE_CONTINUE){ rt.resetState(); }else{ return NULL; } } } itRef->next(); } return resultRef.detachAndDecrease(); }
ObjRef<iface::cellml_api::CellMLVariable> findLocalVariable(CellmlApiObjects* capi, const std::string& variableId) { if (!(capi->cevas)) { std::cerr << "CellMLModelDefinition::findLocalVariable -- missing CeVAS object?" << std::endl; return NULL; } // find named variable - in local components only! CVpair cv = splitName(variableId); if ((cv.first.length() == 0) || (cv.second.length() == 0)) return NULL; //std::cout << "Component name: " << cv.first << "; variable name: " << cv.second << std::endl; ObjRef<iface::cellml_api::CellMLComponentSet> components = capi->model->localComponents(); ObjRef<iface::cellml_api::CellMLComponent> component = components->getComponent(s2ws(cv.first)); if (!component) { std::cerr << "CellMLModelDefinition::findLocalVariable -- unable to find local component: " << cv.first << std::endl; return NULL; } ObjRef<iface::cellml_api::CellMLVariableSet> variables = component->variables(); ObjRef<iface::cellml_api::CellMLVariable> variable = variables->getVariable(s2ws(cv.second)); if (!variable) { std::cerr << "CellMLModelDefinition::findLocalVariable -- unable to find variable: " << cv.first << " / " << cv.second << std::endl; return NULL; } // get source variable ObjRef<iface::cellml_services::ConnectedVariableSet> cvs = capi->cevas->findVariableSet(variable); ObjRef<iface::cellml_api::CellMLVariable> v = cvs->sourceVariable(); if (!v) { std::cerr << "CellMLModelDefinition::findLocalVariable -- unable get source variable for variable: " << cv.first << " / " << cv.second << std::endl; return NULL; } return v; }
CellmlFileRdfTripleElement::CellmlFileRdfTripleElement(iface::rdf_api::Node *pRdfNode) : mId(QString()), mUriReference(QString()), mLexicalForm(QString()), mLanguage(QString()), mDataTypeUri(QString()) { // Check which interface is supported by the node and initialise it in case // it supports the rdf_api::URIReference, rdf_api::PlainLiteral or // rdf_api::TypedLiteral interface ObjRef<iface::rdf_api::URIReference> uriReference = QueryInterface(pRdfNode); if (uriReference) { // The rdf_api::URIReference interface is supported, so initialise the // triple element using that interface mType = UriReference; mUriReference = QString::fromStdWString(uriReference->URI()).trimmed(); } else { ObjRef<iface::rdf_api::PlainLiteral> plainLiteral = QueryInterface(pRdfNode); if (plainLiteral) { // The rdf_api::PlainLiteral interface is supported, so initialise // the triple element using that interface mType = PlainLiteral; mLexicalForm = QString::fromStdWString(plainLiteral->lexicalForm()).trimmed(); mLanguage = QString::fromStdWString(plainLiteral->language()).trimmed(); } else { ObjRef<iface::rdf_api::TypedLiteral> typedLiteral = QueryInterface(pRdfNode); if (typedLiteral) { // The rdf_api::TypedLiteral interface is supported, so // initialise the triple element using that interface mType = TypedLiteral; mLexicalForm = QString::fromStdWString(typedLiteral->lexicalForm()).trimmed(); mDataTypeUri = QString::fromStdWString(typedLiteral->datatypeURI()).trimmed(); } else { // The node doesn't support any interface, so initialise the // triple element using its id // Note: the id returned by the CellML API will look something // like // // 7EQ?;?Y?A?w???A // // This is clearly not user-friendly, so we generate and // use our own id instead... static QMap<QString, QString> ids; static int counter = 0; QString id = QString::fromStdString(pRdfNode->objid()).trimmed(); mType = Id; mId = ids.value(id); if (mId == QString()) { // There is no id value for the current id, so generate one // and keep track of it mId = QString("id_%1").arg(++counter, 9, 10, QChar('0')); ids.insert(id, mId); } } } } // Keep track of the RDF triple element's value as a string, which is based // on its type switch (mType) { case UriReference: mAsString = mUriReference; break; case PlainLiteral: mAsString = mLexicalForm+" ["+mLanguage+"]"; break; case TypedLiteral: mAsString = mLexicalForm+" ["+mDataTypeUri+"]"; break; default: // Id mAsString = mId; } }
void WriteCode(iface::cellml_services::CodeInformation* cci, uint32_t useida) { iface::cellml_services::ModelConstraintLevel mcl = cci->constraintLevel(); if (mcl == iface::cellml_services::UNDERCONSTRAINED) { ObjRef<iface::cellml_services::ComputationTarget> ctMissingIV(cci->missingInitial()); if (ctMissingIV != NULL) { ObjRef<iface::cellml_api::CellMLVariable> v = ctMissingIV->variable(); std::wstring n = v->name(); std::wstring c = v->componentName(); std::wstring str; uint32_t deg = ctMissingIV->degree(); if (deg != 0) { str += L"d^"; wchar_t buf[20]; any_swprintf(buf, 20, L"%u", deg); str += buf; str += L"/dt^"; str += buf; str += L" "; } str += n; str += L" (in "; str += c; str += L")\n"; printf("/* Model is underconstrained due to missing initial_value on %S\n", str.c_str()); } else { printf("/* Model is underconstrained.\n" " * List of undefined targets follows...\n"); iface::cellml_services::ComputationTargetIterator* cti = cci->iterateTargets(); iface::cellml_services::ComputationTarget* ct; std::vector<std::wstring> messages; while (true) { ct = cti->nextComputationTarget(); if (ct == NULL) break; if (ct->type() != iface::cellml_services::FLOATING) { ct->release_ref(); continue; } iface::cellml_api::CellMLVariable* v = ct->variable(); std::wstring n = v->name(); std::wstring c = v->componentName(); std::wstring str = L" * * "; uint32_t deg = ct->degree(); if (deg != 0) { str += L"d^"; wchar_t buf[20]; any_swprintf(buf, 20, L"%u", deg); str += buf; str += L"/dt^"; str += buf; str += L" "; } str += n; str += L" (in "; str += c; str += L")\n"; messages.push_back(str); v->release_ref(); ct->release_ref(); } cti->release_ref(); // Sort the messages... std::sort(messages.begin(), messages.end()); std::vector<std::wstring>::iterator msgi; for (msgi = messages.begin(); msgi != messages.end(); msgi++) printf("%S", (*msgi).c_str()); printf(" */\n"); } return; } else if (mcl == iface::cellml_services::OVERCONSTRAINED) { printf("/* Model is overconstrained.\n" " * List variables defined at time of error follows...\n"); iface::cellml_services::ComputationTargetIterator* cti = cci->iterateTargets(); iface::cellml_services::ComputationTarget* ct; std::vector<std::wstring> messages; while (true) { ct = cti->nextComputationTarget(); if (ct == NULL) break; if (ct->type() == iface::cellml_services::FLOATING) { ct->release_ref(); continue; } iface::cellml_api::CellMLVariable* v = ct->variable(); std::wstring n = v->name(); std::wstring str = L" * * "; uint32_t deg = ct->degree(); if (deg != 0) { str += L"d^"; wchar_t buf[20]; any_swprintf(buf, 20, L"%u", deg); str += buf; str += L"/dt^"; str += buf; str += L" "; } str += n; str += L"\n"; messages.push_back(str); v->release_ref(); ct->release_ref(); } cti->release_ref(); // Sort the messages... std::sort(messages.begin(), messages.end()); std::vector<std::wstring>::iterator msgi; for (msgi = messages.begin(); msgi != messages.end(); msgi++) printf("%S", (*msgi).c_str()); // Get flagged equations... iface::mathml_dom::MathMLNodeList* mnl = cci->flaggedEquations(); printf(" * Extraneous equation was:\n"); iface::dom::Node* n = mnl->item(0); mnl->release_ref(); iface::dom::Element* el = reinterpret_cast<iface::dom::Element*>(n->query_interface("dom::Element")); n->release_ref(); std::wstring cmeta = el->getAttribute(L"id"); if (cmeta == L"") printf(" * <equation with no cmeta ID>\n"); else printf(" * %S\n", cmeta.c_str()); n = el->parentNode(); el->release_ref(); if (n != NULL) { el = reinterpret_cast<iface::dom::Element*> (n->query_interface("dom::Element")); n->release_ref(); cmeta = el->getAttribute(L"id"); if (cmeta == L"") printf(" * in <math with no cmeta ID>\n"); else printf(" * in math with cmeta:id %S\n", cmeta.c_str()); el->release_ref(); } printf(" */\n"); return; } else if (mcl == iface::cellml_services::UNSUITABLY_CONSTRAINED) { printf("/* Model is unsuitably constrained (i.e. would need capabilities" " beyond those of the CCGS to solve).\n" " * The status of variables at time of error follows...\n"); iface::cellml_services::ComputationTargetIterator* cti = cci->iterateTargets(); iface::cellml_services::ComputationTarget* ct; std::vector<std::wstring> messages; while (true) { ct = cti->nextComputationTarget(); if (ct == NULL) break; std::wstring str = L" * * "; if (ct->type() == iface::cellml_services::FLOATING) str += L" Undefined: "; else str += L" Defined: "; uint32_t deg = ct->degree(); if (deg != 0) { str += L"d^"; wchar_t buf[20]; any_swprintf(buf, 20, L"%u", deg); str += buf; str += L"/dt^"; str += buf; str += L" "; } iface::cellml_api::CellMLVariable* v = ct->variable(); std::wstring n = v->name(); str += n; str += L"\n"; messages.push_back(str); v->release_ref(); ct->release_ref(); } cti->release_ref(); // Sort the messages... std::sort(messages.begin(), messages.end()); std::vector<std::wstring>::iterator msgi; for (msgi = messages.begin(); msgi != messages.end(); msgi++) printf("%S", (*msgi).c_str()); printf(" */\n"); return; } printf("/* Model is correctly constrained.\n"); iface::mathml_dom::MathMLNodeList* mnl = cci->flaggedEquations(); uint32_t i, l = mnl->length(); if (l == 0) printf(" * No equations needed Newton-Raphson evaluation.\n"); else printf(" * The following equations needed Newton-Raphson evaluation:\n"); std::vector<std::wstring> messages; for (i = 0; i < l; i++) { iface::dom::Node* n = mnl->item(i); iface::dom::Element* el = reinterpret_cast<iface::dom::Element*>(n->query_interface("dom::Element")); n->release_ref(); std::wstring cmeta = el->getAttribute(L"id"); std::wstring str; if (cmeta == L"") str += L" * <equation with no cmeta ID>\n"; else { str += L" * "; str += cmeta; str += L"\n"; } n = el->parentNode(); el->release_ref(); el = reinterpret_cast<iface::dom::Element*> (n->query_interface("dom::Element")); n->release_ref(); cmeta = el->getAttribute(L"id"); if (cmeta == L"") str += L" * in <math with no cmeta ID>\n"; else { str += L" * in math with cmeta:id "; str += cmeta; str += L"\n"; } el->release_ref(); messages.push_back(str); } mnl->release_ref(); // Sort the messages... std::sort(messages.begin(), messages.end()); std::vector<std::wstring>::iterator msgi; for (msgi = messages.begin(); msgi != messages.end(); msgi++) printf("%S", (*msgi).c_str()); printf(" * The rate and state arrays need %u entries.\n", cci->rateIndexCount()); printf(" * The algebraic variables array needs %u entries.\n", cci->algebraicIndexCount()); printf(" * The constant array needs %u entries.\n", cci->constantIndexCount()); printf(" * Variable storage is as follows:\n"); messages.clear(); iface::cellml_services::ComputationTargetIterator* cti = cci->iterateTargets(); while (true) { iface::cellml_services::ComputationTarget* ct = cti->nextComputationTarget(); if (ct == NULL) break; iface::cellml_api::CellMLVariable* v = ct->variable(); iface::cellml_api::CellMLElement* el = v->parentElement(); iface::cellml_api::CellMLComponent* c = reinterpret_cast<iface::cellml_api::CellMLComponent*> (el->query_interface("cellml_api::CellMLComponent")); el->release_ref(); std::wstring str; std::wstring vn = v->name(), cn = c->name(); str += L" * * Target "; uint32_t deg = ct->degree(); if (deg != 0) { str += L"d^"; wchar_t buf[20]; any_swprintf(buf, 20, L"%u", deg); str += buf; str += L"/dt^"; str += buf; str += L" "; } str += vn; str += L" in component "; str += cn; str += L"\n"; c->release_ref(); v->release_ref(); str += L" * * * Variable type: "; str += TypeToString(ct->type()); str += L"\n * * * Variable index: "; wchar_t buf[40]; any_swprintf(buf, 40, L"%u\n", ct->assignedIndex()); str += buf; str += L" * * * Variable storage: "; std::wstring vsn = ct->name(); str += vsn; str += '\n'; ct->release_ref(); messages.push_back(str); } cti->release_ref(); // Sort the messages... std::sort(messages.begin(), messages.end()); for (msgi = messages.begin(); msgi != messages.end(); msgi++) printf("%S", (*msgi).c_str()); printf(" */\n"); std::wstring frag = cci->functionsString(); printf("%S", frag.c_str()); // Now start the code... frag = cci->initConstsString(); printf("void SetupFixedConstants(double* CONSTANTS, double* RATES, double* STATES)\n{\n%S}\n", frag.c_str()); frag = cci->variablesString(); printf("void EvaluateVariables(double VOI, double* CONSTANTS, double* RATES, double* STATES, double* ALGEBRAIC)\n" "{\n%S}\n", frag.c_str()); if (useida) { iface::cellml_services::IDACodeInformation* icci = reinterpret_cast<iface::cellml_services::IDACodeInformation*>(cci->query_interface("cellml_services::IDACodeInformation")); frag = icci->essentialVariablesString(); printf("void EvaluateEssentialVariables(double VOI, double* CONSTANTS, double* RATES, double* STATES, double* ALGEBRAIC)\n" "{\n%S}\n", frag.c_str()); frag = cci->ratesString(); printf("void ComputeResiduals(double VOI, double* STATES, double* RATES, double* CONSTANTS, " "double* ALGEBRAIC)\n" "{\n%S}\n", frag.c_str()); frag = icci->stateInformationString(); printf("void SetupStateInfo(double * SI)\n{\n%S}\n", frag.c_str()); frag = icci->rootInformationString(); printf("void RootInformation()\n{\n%S}\n", frag.c_str()); icci->release_ref(); } else { frag = cci->ratesString(); printf("void ComputeRates(double VOI, double* STATES, double* RATES, double* CONSTANTS, " "double* ALGEBRAIC)\n" "{\n%S}\n", frag.c_str()); } }
int main(int argc, char** argv) { try { std::wstring modelURL (L"http://models.cellml.org/workspace/hodgkin_huxley_1952/@@rawfile/949cd4d3/hodgkin_huxley_1952.cellml"); // Create a CellML Bootstrap and a model loader. ObjRef<iface::cellml_api::CellMLBootstrap> bootstrap(CreateCellMLBootstrap()); ObjRef<iface::cellml_api::DOMModelLoader> loader(bootstrap->modelLoader()); // Load a CellML model. ObjRef<iface::cellml_api::Model> hhModel (loader->loadFromURL(modelURL)); // Request a RDF/API capable RDF representation... ObjRef<iface::cellml_api::RDFRepresentation> rr(hhModel->getRDFRepresentation(L"http://www.cellml.org/RDF/API")); ObjRef<iface::rdf_api::RDFAPIRepresentation> rrHH(QueryInterface(rr)); // Retrieve the DataSource. Note: Changes to the data source are not pushed back // to the model until the source attribute is set on the rrHH again. ObjRef<iface::rdf_api::DataSource> dsHH(rrHH->source()); // Get the resource corresponding to the cmeta:id on the model. Note that // cmetaId can return the empty string, which you should check for in // production code, if there is no cmeta:id ObjRef<iface::rdf_api::URIReference> hhModelRef (dsHH->getURIReference(bootstrap->makeURLAbsolute(modelURL, L"#" + hhModel->cmetaId()))); #ifdef DUMP_ALL_TRIPLES_FIRST { ObjRef<iface::rdf_api::TripleSet> ts(dsHH->getAllTriples()); ObjRef<iface::rdf_api::TripleEnumerator> te(ts->enumerateTriples()); while (true) { ObjRef<iface::rdf_api::Triple> t(te->getNextTriple()); if (t == NULL) break; displayTriple(t); } } #endif ObjRef<iface::rdf_api::URIReference> pmid(dsHH->getURIReference(L"http://www.cellml.org/bqs/1.0#Pubmed_id")); // Note: Calls like this could fail with an exception if there was no pubmed ID - production code should check. ObjRef<iface::rdf_api::Triple> t(hhModelRef->getTripleOutOfByPredicate(pmid)); ObjRef<iface::rdf_api::Node> n(t->object()); ObjRef<iface::rdf_api::Literal> lPMID(QueryInterface(n)); if (lPMID != NULL) // It will be null if for some reason it isn't a literal... std::wcout << L"Model pubmed ID: " << lPMID->lexicalForm() << std::endl; ObjRef<iface::rdf_api::URIReference> bqsReference(dsHH->getURIReference(L"http://www.cellml.org/bqs/1.0#reference")); ObjRef<iface::rdf_api::TripleSet> ts(hhModelRef->getTriplesOutOfByPredicate(bqsReference)); ObjRef<iface::rdf_api::TripleEnumerator> te(ts->enumerateTriples()); while (true) { t = te->getNextTriple(); if (t == NULL) break; ObjRef<iface::rdf_api::Resource> r(QueryInterface(t->object())); if (r == NULL) continue; std::wcout << L"Found a resource description:" << std::endl; try { t = r->getTripleOutOfByPredicate(pmid); n = t->object(); lPMID = QueryInterface(n); if (lPMID != NULL) std::wcout << L" Reference pubmed ID: " << lPMID->lexicalForm() << std::endl; } catch(...) {} // Look up the subject... ObjRef<iface::rdf_api::URIReference> subject(dsHH->getURIReference(L"http://purl.org/dc/elements/1.1/subject")); ts = r->getTriplesOutOfByPredicate(subject); ObjRef<iface::rdf_api::TripleEnumerator> te2 = ts->enumerateTriples(); while (true) { t = te2->getNextTriple(); if (t == NULL) break; n = t->object(); r = QueryInterface(n); if (r == NULL) continue; std::wcout << " Subject:" << std::endl; ObjRef<iface::rdf_api::URIReference> subjectType(dsHH->getURIReference(L"http://www.cellml.org/bqs/1.0#subject_type")); ts = r->getTriplesOutOfByPredicate(subjectType); ObjRef<iface::rdf_api::TripleEnumerator> te3 = ts->enumerateTriples(); t = te3->getNextTriple(); if (t) { n = t->object(); ObjRef<iface::rdf_api::Literal> l(QueryInterface(n)); std::wcout << " Subject Type=" << l->lexicalForm() << std::endl; } ObjRef<iface::rdf_api::URIReference> value(dsHH->getURIReference(L"http://www.w3.org/1999/02/22-rdf-syntax-ns#value")); ts = r->getTriplesOutOfByPredicate(value); te3 = ts->enumerateTriples(); t = te3->getNextTriple(); if (t == NULL) continue; n = t->object(); r = QueryInterface(n); if (r == NULL) continue; ObjRef<iface::rdf_api::Container> cont(r->correspondingContainer()); // Add a new entry to the container first... ObjRef<iface::rdf_api::PlainLiteral> newPL(dsHH->getPlainLiteral(L"Newly created label", L"en")); cont->appendChild(newPL); // Delete any labels that match 'giant axon'... ObjRef<iface::rdf_api::NodeIterator> ni(cont->iterateChildren()); while (true) { ObjRef<iface::rdf_api::Node> n(ni->getNextNode()); if (n == NULL) break; ObjRef<iface::rdf_api::Literal> l(QueryInterface(n)); if (l == NULL) continue; if (l->lexicalForm() == L"giant axon") // The false means don't renumber immediately. This leaves the // container with gaps... cont->removeChild(l, false); } cont->renumberContainer(); // Remove the gaps. displayContainer(cont, L" "); } } } catch (iface::cellml_api::CellMLException&) { std::wcout << L"A CellMLException was raised. In production code, you would normally have more " << L"exception handlers to work out exactly where the problem occurred. This program " << L"avoids that for simplicity, to make the normal control flow easier to understand. " << L"The most likely cause is a network problem retrieving the hardcoded model URL." << std::endl; return 1; } catch (iface::rdf_api::RDFProcessingError&) { std::wcout << L"An RDFProcessingError was raised. In production code, you would normally have more " << L"exception handlers to work out exactly where the problem occurred. This program " << L"avoids that for simplicity, to make the normal control flow easier to understand." << std::endl; return 2; } return 0; }
void CellmlFileRuntime::update() { // Reset the runtime's properties reset(true, true); // Check that the model is either a 'simple' ODE model or a DAE model // Note #1: we don't check whether a model is valid, since all we want is to // update its runtime (which has nothing to do with editing or even // validating a model), so if it can be done then great otherwise // tough luck (so to speak)... // Note #2: in order to do so, we need to get a 'normal' code generator (as // opposed to an IDA, i.e. DAE, code generator) since if the model // is correctly constrained, then we can check whether some of its // equations were flagged as needing a Newton-Raphson evaluation, // in which case we would be dealing with a DAE model... // Note #3: ideally, there would be a more convenient way to determine the // type of a model, but there isn't... iface::cellml_api::Model *model = mCellmlFile->model(); if (!model) return; // Retrieve the model's type // Note: this can be done by checking whether some equations were flagged // as needing a Newton-Raphson evaluation... retrieveOdeCodeInformation(model); if (!mOdeCodeInformation) return; ObjRef<iface::mathml_dom::MathMLNodeList> flaggedEquations = mOdeCodeInformation->flaggedEquations(); mModelType = flaggedEquations->length()?CellmlFileRuntime::Dae:CellmlFileRuntime::Ode; // If the model is of DAE type, then we don't want the ODE-specific code // information, but the DAE-specific code one ObjRef<iface::cellml_services::CodeInformation> genericCodeInformation; if (mModelType == CellmlFileRuntime::Ode) { genericCodeInformation = mOdeCodeInformation; } else { retrieveDaeCodeInformation(model); if (!mDaeCodeInformation) return; genericCodeInformation = mDaeCodeInformation; } // Retrieve the number of constants, states/rates, algebraic and conditional // variables in the model // Note: this is to avoid having to go through the ODE/DAE code information // an unnecessary number of times when we want to retrieve either of // those numbers (e.g. see // SingleCellViewSimulationResults::addPoint())... if (mModelType == CellmlFileRuntime::Ode) { mConstantsCount = mOdeCodeInformation->constantIndexCount(); mStatesRatesCount = mOdeCodeInformation->rateIndexCount(); mAlgebraicCount = mOdeCodeInformation->algebraicIndexCount(); mCondVarCount = 0; } else { mConstantsCount = mDaeCodeInformation->constantIndexCount(); mStatesRatesCount = mDaeCodeInformation->rateIndexCount(); mAlgebraicCount = mDaeCodeInformation->algebraicIndexCount(); mCondVarCount = mDaeCodeInformation->conditionVariableCount(); } // Determine whether the model imports some components // Note #1: a model that only imports units will clearly not affect our // model's variables, hence such a model won't be relevant for our // mapping below... // Note #2: a model cannot be fully instantiated if it imports an empty // component or a component with unmapped variables, so we don't // need to worry about this type of model... ObjRef<iface::cellml_api::CellMLImportSet> imports = model->imports(); ObjRef<iface::cellml_api::CellMLImportIterator> importsIter = imports->iterateImports(); bool hasComponentImports = false; for (ObjRef<iface::cellml_api::CellMLImport> import = importsIter->nextImport(); import; import = importsIter->nextImport()) { ObjRef<iface::cellml_api::ImportComponentSet> importComponents = import->components(); if (importComponents->length()) { hasComponentImports = true; break; } } // If the model contains some imports then we want to to go through the // variables defined or referenced in our main CellML file and do a mapping // between the source of a variable and a variable in the main CellML file // Note: indeed, when it comes to CellML 1.1 files, we only want to list the // parameters that are either defined or referenced in our main CellML // file. Not only does it make sense, but also only the parameters // listed in a main CellML file can be referenced in SED-ML... QMap<iface::cellml_api::CellMLVariable *, iface::cellml_api::CellMLVariable *> mainVariables = QMap<iface::cellml_api::CellMLVariable *, iface::cellml_api::CellMLVariable *>(); ObjRef<iface::cellml_api::CellMLComponentSet> localComponents = model->localComponents(); ObjRef<iface::cellml_api::CellMLComponentIterator> localComponentsIter = localComponents->iterateComponents(); if (hasComponentImports) { for (ObjRef<iface::cellml_api::CellMLComponent> component = localComponentsIter->nextComponent(); component; component = localComponentsIter->nextComponent()) { ObjRef<iface::cellml_api::CellMLVariableSet> variables = component->variables(); ObjRef<iface::cellml_api::CellMLVariableIterator> variablesIter = variables->iterateVariables(); for (ObjRef<iface::cellml_api::CellMLVariable> variable = variablesIter->nextVariable(); variable; variable = variablesIter->nextVariable()) { ObjRef<iface::cellml_api::CellMLVariable> sourceVariable = variable->sourceVariable(); mainVariables.insert(sourceVariable, variable); } } } // Go through all our computation targets and determine which ones are // referenced in our main CellML file, and sort them by component and // variable name ObjRef<iface::cellml_services::ComputationTargetIterator> computationTargetIter = genericCodeInformation->iterateTargets(); for (ObjRef<iface::cellml_services::ComputationTarget> computationTarget = computationTargetIter->nextComputationTarget(); computationTarget; computationTarget = computationTargetIter->nextComputationTarget()) { // Make sure that our computation target is defined or referenced in our // main CellML file, if it has imports ObjRef<iface::cellml_api::CellMLVariable> variable = computationTarget->variable(); iface::cellml_api::CellMLVariable *mainVariable = mainVariables.value(variable); iface::cellml_api::CellMLVariable *realVariable = mainVariable?mainVariable:variable.getPointer(); if ( hasComponentImports && !mainVariable && (computationTarget->type() != iface::cellml_services::VARIABLE_OF_INTEGRATION)) { continue; } // Determine the type of our computation target CellmlFileRuntimeParameter::ParameterType parameterType; switch (computationTarget->type()) { case iface::cellml_services::VARIABLE_OF_INTEGRATION: parameterType = CellmlFileRuntimeParameter::Voi; break; case iface::cellml_services::CONSTANT: // We are dealing with a constant, but the question is whether that // constant is a 'proper' constant, a 'computed' constant or even a // rate, and this can be determined by checking whether the computed // target has an initial value or even a degree // Note: a state variable that is initialised using the initial // value of another variable will have its rate considered as // a constant. However, when it comes to the GUI, we really // want it to be seen as a rate hence we check for the degree // of the computed target... if (QString::fromStdWString(variable->initialValue()).isEmpty()) { // The computed target doesn't have an initial value, so it must // be a 'computed' constant parameterType = CellmlFileRuntimeParameter::ComputedConstant; } else if (computationTarget->degree()) { // The computed target has a degree, so it is effectively a rate parameterType = CellmlFileRuntimeParameter::Rate; } else { // The computed target has an initial value, so it must be a // 'proper' constant parameterType = CellmlFileRuntimeParameter::Constant; } break; case iface::cellml_services::STATE_VARIABLE: case iface::cellml_services::PSEUDOSTATE_VARIABLE: parameterType = CellmlFileRuntimeParameter::State; break; case iface::cellml_services::ALGEBRAIC: // We are dealing with either a 'proper' algebraic variable or a // rate variable // Note: if the variable's degree is equal to zero, then we are // dealing with a 'proper' algebraic variable otherwise we // are dealing with a rate variable... if (computationTarget->degree()) parameterType = CellmlFileRuntimeParameter::Rate; else parameterType = CellmlFileRuntimeParameter::Algebraic; break; case iface::cellml_services::FLOATING: parameterType = CellmlFileRuntimeParameter::Floating; break; case iface::cellml_services::LOCALLY_BOUND: parameterType = CellmlFileRuntimeParameter::LocallyBound; break; } // Keep track of our computation target, should its type be of interest if ( (parameterType != CellmlFileRuntimeParameter::Floating) && (parameterType != CellmlFileRuntimeParameter::LocallyBound)) { CellmlFileRuntimeParameter *parameter = new CellmlFileRuntimeParameter(QString::fromStdWString(realVariable->name()), computationTarget->degree(), QString::fromStdWString(realVariable->unitsName()), componentHierarchy(realVariable), parameterType, computationTarget->assignedIndex()); if (parameterType == CellmlFileRuntimeParameter::Voi) mVariableOfIntegration = parameter; if (!hasComponentImports || (realVariable == mainVariable)) mParameters << parameter; } } std::sort(mParameters.begin(), mParameters.end(), sortParameters); // Generate the model code QString modelCode = QString(); QString functionsString = QString::fromStdWString(genericCodeInformation->functionsString()); if (!functionsString.isEmpty()) { // We will need to solve at least one NLA system mAtLeastOneNlaSystem = true; modelCode += "struct rootfind_info\n" "{\n" " double aVOI;\n" "\n" " double *aCONSTANTS;\n" " double *aRATES;\n" " double *aSTATES;\n" " double *aALGEBRAIC;\n" "\n" " int *aPRET;\n" "};\n" "\n" "extern void doNonLinearSolve(char *, void (*)(double *, double *, void*), double *, int *, int, void *);\n" "\n" +functionsString.replace("do_nonlinearsolve(", QString("doNonLinearSolve(\"%1\", ").arg(address())) +"\n"; // Note: we rename do_nonlinearsolve() to doNonLinearSolve() because // CellML's CIS service already defines do_nonlinearsolve(), yet // we want to use our own non-linear solve routine defined in our // Compiler plugin. Also, we add a new parameter to all our calls // to doNonLinearSolve() so that doNonLinearSolve() can retrieve // the correct instance of our NLA solver... } // Retrieve the body of the function that initialises constants and extract // the statements that are related to computed variables (since we want to // be able to recompute those whenever the user modifies a parameter) // Note: ideally, we wouldn't have to do that, but the CellML API doesn't // distinguish between 'proper' and 'computed' constants... // (See https://tracker.physiomeproject.org/show_bug.cgi?id=3499) static const QRegularExpression InitializationStatementRegEx = QRegularExpression("^(CONSTANTS|RATES|STATES)\\[\\d*\\] = [+-]?\\d*\\.?\\d+([eE][+-]?\\d+)?;$"); QStringList initConstsList = cleanCode(genericCodeInformation->initConstsString()).split("\n"); QString initConsts = QString(); QString compCompConsts = QString(); foreach (const QString &initConst, initConstsList) { // Add the statement either to our list of 'proper' constants or // 'computed' constants if (InitializationStatementRegEx.match(initConst).hasMatch()) initConsts += (initConsts.isEmpty()?QString():"\n")+initConst; else compCompConsts += (compCompConsts.isEmpty()?QString():"\n")+initConst; } modelCode += functionCode("int initializeConstants(double *CONSTANTS, double *RATES, double *STATES)", initConsts, true); modelCode += "\n"; modelCode += functionCode("int computeComputedConstants(double *CONSTANTS, double *RATES, double *STATES)", compCompConsts, true); modelCode += "\n"; // Retrieve the body of the remaining functions if (mModelType == CellmlFileRuntime::Ode) { modelCode += functionCode("int computeOdeRates(double VOI, double *CONSTANTS, double *RATES, double *STATES, double *ALGEBRAIC)", cleanCode(mOdeCodeInformation->ratesString())); modelCode += "\n"; modelCode += functionCode("int computeOdeVariables(double VOI, double *CONSTANTS, double *RATES, double *STATES, double *ALGEBRAIC)", cleanCode(genericCodeInformation->variablesString())); } else { modelCode += functionCode("int computeDaeEssentialVariables(double VOI, double *CONSTANTS, double *RATES, double *OLDRATES, double *STATES, double *OLDSTATES, double *ALGEBRAIC, double *CONDVAR)", cleanCode(mDaeCodeInformation->essentialVariablesString())); modelCode += "\n"; modelCode += functionCode("int computeDaeResiduals(double VOI, double *CONSTANTS, double *RATES, double *OLDRATES, double *STATES, double *OLDSTATES, double *ALGEBRAIC, double *CONDVAR, double *resid)", cleanCode(mDaeCodeInformation->ratesString())); modelCode += "\n"; modelCode += functionCode("int computeDaeRootInformation(double VOI, double *CONSTANTS, double *RATES, double *OLDRATES, double *STATES, double *OLDSTATES, double *ALGEBRAIC, double *CONDVAR)", cleanCode(mDaeCodeInformation->rootInformationString())); modelCode += functionCode("int computeDaeStateInformation(double *SI)", cleanCode(mDaeCodeInformation->stateInformationString())); modelCode += "\n"; modelCode += functionCode("int computeDaeVariables(double VOI, double *CONSTANTS, double *RATES, double *STATES, double *ALGEBRAIC, double *CONDVAR)", cleanCode(genericCodeInformation->variablesString())); } // Check whether the model code contains a definite integral, otherwise // compute it and check that everything went fine if (modelCode.contains("defint(func")) { mIssues << CellmlFileIssue(CellmlFileIssue::Error, QObject::tr("definite integrals are not yet supported")); } else if (!mCompilerEngine->compileCode(modelCode)) { mIssues << CellmlFileIssue(CellmlFileIssue::Error, mCompilerEngine->error()); } // Keep track of the ODE/DAE functions, but only if no issues were reported if (mIssues.count()) { reset(true, false); } else { // Add the symbol of any required external function, if any if (mAtLeastOneNlaSystem) llvm::sys::DynamicLibrary::AddSymbol("doNonLinearSolve", (void *) (intptr_t) doNonLinearSolve); // Retrieve the ODE/DAE functions mInitializeConstants = (InitializeConstantsFunction) (intptr_t) mCompilerEngine->getFunction("initializeConstants"); mComputeComputedConstants = (ComputeComputedConstantsFunction) (intptr_t) mCompilerEngine->getFunction("computeComputedConstants"); if (mModelType == CellmlFileRuntime::Ode) { mComputeOdeRates = (ComputeOdeRatesFunction) (intptr_t) mCompilerEngine->getFunction("computeOdeRates"); mComputeOdeVariables = (ComputeOdeVariablesFunction) (intptr_t) mCompilerEngine->getFunction("computeOdeVariables"); } else { mComputeDaeEssentialVariables = (ComputeDaeEssentialVariablesFunction) (intptr_t) mCompilerEngine->getFunction("computeDaeEssentialVariables"); mComputeDaeResiduals = (ComputeDaeResidualsFunction) (intptr_t) mCompilerEngine->getFunction("computeDaeResiduals"); mComputeDaeRootInformation = (ComputeDaeRootInformationFunction) (intptr_t) mCompilerEngine->getFunction("computeDaeRootInformation"); mComputeDaeStateInformation = (ComputeDaeStateInformationFunction) (intptr_t) mCompilerEngine->getFunction("computeDaeStateInformation"); mComputeDaeVariables = (ComputeDaeVariablesFunction) (intptr_t) mCompilerEngine->getFunction("computeDaeVariables"); } // Make sure that we managed to retrieve all the ODE/DAE functions bool functionsOk = mInitializeConstants && mComputeComputedConstants; if (mModelType == CellmlFileRuntime::Ode) { functionsOk = functionsOk && mComputeOdeRates && mComputeOdeVariables; } else { functionsOk = functionsOk && mComputeDaeEssentialVariables && mComputeDaeResiduals && mComputeDaeRootInformation && mComputeDaeStateInformation && mComputeDaeVariables; } if (!functionsOk) { mIssues << CellmlFileIssue(CellmlFileIssue::Error, QObject::tr("an unexpected problem occurred while trying to retrieve the model functions")); reset(true, false); } } }
ObjRef(const ObjRef<T>& aPtr) { mPtr = aPtr.getPointer(); if (mPtr != NULL) mPtr->add_ref(); }
template<class T, class U> bool operator!=(const ObjRef<T>& lhs, const ObjRef<U>& rhs) { return (lhs.getPointer() != rhs.getPointer()); }
QStringList CellmlFileRuntime::componentHierarchy(iface::cellml_api::CellMLElement *pElement) { // Make sure that we have a given element if (!pElement) return QStringList(); // Try to retrieve the component that owns the given element, unless the // given element is a component itself (which will be the case when we come // here through recursion) ObjRef<iface::cellml_api::CellMLComponent> component = QueryInterface(pElement); ObjRef<iface::cellml_api::CellMLElement> parent = pElement->parentElement(); ObjRef<iface::cellml_api::CellMLComponent> parentComponent = QueryInterface(parent); if (!component && !parentComponent) { // The element isn't a component and neither is its parent, so it // doesn't have a hierarchy return QStringList(); } // Check whether this is an imported component and, if so, retrieve its // imported name QString componentName = QString::fromStdWString(component?component->name():parentComponent->name()); ObjRef<iface::cellml_api::CellMLElement> componentParent = component?component->parentElement():parentComponent->parentElement(); ObjRef<iface::cellml_api::CellMLElement> componentParentParent = componentParent->parentElement(); if (componentParentParent) { // The given element comes from or is an imported component, so go // through our different imported components and look for the one we are // after ObjRef<iface::cellml_api::CellMLImport> import = QueryInterface(componentParentParent); ObjRef<iface::cellml_api::ImportComponentSet> importComponents = import->components(); ObjRef<iface::cellml_api::ImportComponentIterator> importComponentsIter = importComponents->iterateImportComponents(); for (ObjRef<iface::cellml_api::ImportComponent> importComponent = importComponentsIter->nextImportComponent(); importComponent; importComponent = importComponentsIter->nextImportComponent()) { if (!componentName.compare(QString::fromStdWString(importComponent->componentRef()))) { // This is the imported component we are after, so retrieve its // imported name componentName = QString::fromStdWString(importComponent->name()); break; } } } // Recursively retrieve the component hierarchy of the given element's // encapsulation parent, if any ObjRef<iface::cellml_api::CellMLComponent> componentEncapsulationParent = component?component->encapsulationParent():parentComponent->encapsulationParent(); return componentHierarchy(componentEncapsulationParent) << componentName; }