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(); }
CellMLModelDefinition::CellMLModelDefinition(const char* url) : mURL(url) { //mCompileCommand = "gcc -fPIC -O3 -shared -x c -o"; mCompileCommand = "gcc -fPIC -g -shared -x c -o"; mTmpDirExists = false; mCodeFileExists = false; mDsoFileExists = false; mSaveTempFiles = false; mInstantiated = false; nBound = -1; nRates = -1; nAlgebraic = -1; nConstants = -1; mNumberOfWantedVariables = 0; mNumberOfKnownVariables = 0; mNumberOfIndependentVariables = 0; mStateCounter = 0; mIntermediateCounter = 0; mParameterCounter = 0; mModel = NULL; mCodeInformation = NULL; mAnnotations = NULL; std::cout << "Creating CellMLModelDefinition from the URL: " << url << std::endl; if (! mURL.empty()) { //std::cout << "Have a valid simulation description." << std::endl; //std::cout << " CellML model URI: " << mURL.c_str() << std::endl; RETURN_INTO_WSTRING(URL,string2wstring(mURL.c_str())); RETURN_INTO_OBJREF(cb,iface::cellml_api::CellMLBootstrap, CreateCellMLBootstrap()); RETURN_INTO_OBJREF(ml,iface::cellml_api::ModelLoader,cb->modelLoader()); iface::cellml_api::Model* model = (iface::cellml_api::Model*)NULL; try { model = ml->loadFromURL(URL.c_str()); model->fullyInstantiateImports(); mModel = static_cast<void*>(model); // create the annotation set RETURN_INTO_OBJREF(ats,iface::cellml_services::AnnotationToolService,CreateAnnotationToolService()); iface::cellml_services::AnnotationSet* as = ats->createAnnotationSet(); mAnnotations = static_cast<void*>(as); // make sure we can generate code and get the initial code information RETURN_INTO_OBJREF(cgb,iface::cellml_services::CodeGeneratorBootstrap, CreateCodeGeneratorBootstrap()); RETURN_INTO_OBJREF(cg,iface::cellml_services::CodeGenerator, cgb->createCodeGenerator()); try { RETURN_INTO_OBJREF(cci,iface::cellml_services::CodeInformation, cg->generateCode(model)); // need to keep a handle on the code information cci->add_ref(); mCodeInformation = static_cast<void*>(cci); // and add all state variables as wanted and the variable of integration as known RETURN_INTO_OBJREF(cti,iface::cellml_services::ComputationTargetIterator,cci->iterateTargets()); while(1) { RETURN_INTO_OBJREF(ct,iface::cellml_services::ComputationTarget,cti->nextComputationTarget()); if (ct == NULL) break; if (ct->type() == iface::cellml_services::STATE_VARIABLE) { as->setStringAnnotation(ct->variable(),L"flag",L"STATE"); as->setStringAnnotation(ct->variable(),L"array",L"OC_STATE"); as->setStringAnnotation(ct->variable(),L"array_index",formatNumber(mStateCounter).c_str()); mStateCounter++; } else if (ct->type() == iface::cellml_services::VARIABLE_OF_INTEGRATION) { as->setStringAnnotation(ct->variable(),L"flag",L"INDEPENDENT"); mNumberOfIndependentVariables++; } else if (ct->degree() > 0) { //as->setStringAnnotation(ct->variable(),L"flag-degree",L"WANTED"); //mNumberOfWantedVariables++; } } } catch (...) { std::wcerr << L"Error generating the code information for the model" << std::endl; mCodeInformation = static_cast<void*>(NULL); } } catch (...) { std::wcerr << L"Error loading model URL: " << URL.c_str() << std::endl; mModel = static_cast<void*>(NULL); } } }
std::wstring CellMLModelDefinition::getModelAsCCode(void* _model,void* _annotations) { iface::cellml_api::Model* model = static_cast<iface::cellml_api::Model*>(_model); iface::cellml_services::AnnotationSet* as = static_cast<iface::cellml_services::AnnotationSet*>(_annotations); std::wstring code; RETURN_INTO_OBJREF(cgb,iface::cellml_services::CodeGeneratorBootstrap, CreateCodeGeneratorBootstrap()); RETURN_INTO_OBJREF(cg,iface::cellml_services::CodeGenerator, cgb->createCodeGenerator()); #if defined (CUSTOM_CODE_GENERATION) RETURN_INTO_OBJREF(ccg, iface::cellml_services::CustomGenerator, cg->createCustomGenerator(model)); RETURN_INTO_OBJREF(cti, iface::cellml_services::ComputationTargetIterator, ccg->iterateTargets()); while (true) { RETURN_INTO_OBJREF(ct, iface::cellml_services::ComputationTarget, cti->nextComputationTarget()); if (ct == NULL) break; RETURN_INTO_WSTRING(flag,as->getStringAnnotation(ct->variable(),L"flag")); if ((flag == L"WANTED") || (ct->degree() > 0)) { ccg->requestComputation(ct); } else if (flag == L"KNOWN") { ccg->markAsKnown(ct); } } #endif /* The trunk MaLaES has been updated since the 1.5 release, so define a * "custom" MaLaES here */ RETURN_INTO_OBJREF(mbs,iface::cellml_services::MaLaESBootstrap, CreateMaLaESBootstrap()); RETURN_INTO_OBJREF(mt,iface::cellml_services::MaLaESTransform, mbs->compileTransformer( L"opengroup: (\r\n" L"closegroup: )\r\n" L"abs: #prec[H]fabs(#expr1)\r\n" L"and: #prec[20]#exprs[&&]\r\n" L"arccos: #prec[H]acos(#expr1)\r\n" L"arccosh: #prec[H]acosh(#expr1)\r\n" L"arccot: #prec[1000(900)]atan(1.0/#expr1)\r\n" L"arccoth: #prec[1000(900)]atanh(1.0/#expr1)\r\n" L"arccsc: #prec[1000(900)]asin(1/#expr1)\r\n" L"arccsch: #prec[1000(900)]asinh(1/#expr1)\r\n" L"arcsec: #prec[1000(900)]acos(1/#expr1)\r\n" L"arcsech: #prec[1000(900)]acosh(1/#expr1)\r\n" L"arcsin: #prec[H]asin(#expr1)\r\n" L"arcsinh: #prec[H]asinh(#expr1)\r\n" L"arctan: #prec[H]atan(#expr1)\r\n" L"arctanh: #prec[H]atanh(#expr1)\r\n" L"ceiling: #prec[H]ceil(#expr1)\r\n" L"cos: #prec[H]cos(#expr1)\r\n" L"cosh: #prec[H]cosh(#expr1)\r\n" L"cot: #prec[900(0)]1.0/tan(#expr1)\r\n" L"coth: #prec[900(0)]1.0/tanh(#expr1)\r\n" L"csc: #prec[900(0)]1.0/sin(#expr1)\r\n" L"csch: #prec[900(0)]1.0/sinh(#expr1)\r\n" L"diff: #lookupDiffVariable\r\n" L"divide: #prec[900]#expr1/#expr2\r\n" L"eq: #prec[30]#exprs[==]\r\n" L"exp: #prec[H]exp(#expr1)\r\n" L"factorial: #prec[H]factorial(#expr1)\r\n" L"factorof: #prec[30(900)]#expr1 % #expr2 == 0\r\n" L"floor: #prec[H]floor(#expr1)\r\n" L"gcd: #prec[H]gcd_multi(#count, #exprs[, ])\r\n" L"geq: #prec[30]#exprs[>=]\r\n" L"gt: #prec[30]#exprs[>]\r\n" L"implies: #prec[10(950)] !#expr1 || #expr2\r\n" L"int: #prec[H]defint(func#unique1, BOUND, CONSTANTS, RATES, VARIABLES, " L"#bvarIndex, pret)#supplement double func#unique1(double* BOUND, " L"double* CONSTANTS, double* RATES, double* VARIABLES, int* pret) { return #expr1; }\r\n" L"lcm: #prec[H]lcm_multi(#count, #exprs[, ])\r\n" L"leq: #prec[30]#exprs[<=]\r\n" L"ln: #prec[H]log(#expr1)\r\n" L"log: #prec[H]arbitrary_log(#expr1, #logbase)\r\n" L"lt: #prec[30]#exprs[<]\r\n" L"max: #prec[H]multi_max(#count, #exprs[, ])\r\n" L"min: #prec[H]multi_min(#count, #exprs[, ])\r\n" L"minus: #prec[500]#expr1 - #expr2\r\n" L"neq: #prec[30]#expr1 != #expr2\r\n" L"not: #prec[950]!#expr1\r\n" L"or: #prec[10]#exprs[||]\r\n" L"plus: #prec[500]#exprs[+]\r\n" L"power: #prec[H]pow(#expr1, #expr2)\r\n" L"quotient: #prec[1000(0)] (double)(((int)#expr2) == 0 ? #expr1 / 0.0 : (int)(#expr1) / (int)(#expr2))\r\n" L"rem: #prec[1000(0)] (double)(((int)#expr2) == 0 ? (#expr1) / 0.0 : (int)(#expr1) % (int)(#expr2))\r\n" L"root: #prec[1000(900)] pow(#expr1, 1.0 / #degree)\r\n" L"sec: #prec[900(0)]1.0 / cos(#expr1)\r\n" L"sech: #prec[900(0)]1.0 / cosh(#expr1)\r\n" L"sin: #prec[H] sin(#expr1)\r\n" L"sinh: #prec[H] sinh(#expr1)\r\n" L"tan: #prec[H] tan(#expr1)\r\n" L"tanh: #prec[H] tanh(#expr1)\r\n" L"times: #prec[900] #exprs[*]\r\n" L"unary_minus: #prec[950]- #expr1\r\n" L"units_conversion: #prec[500(900)]#expr1*#expr2 + #expr3\r\n" L"units_conversion_factor: #prec[900]#expr1*#expr2\r\n" L"units_conversion_offset: #prec[500]#expr1+#expr2\r\n" L"xor: #prec[25(30)] (#expr1 != 0) ^ (#expr2 != 0)\r\n" L"piecewise_first_case: #prec[1000(5)](#expr1 ? #expr2 : \r\n" L"piecewise_extra_case: #prec[1000(5)]#expr1 ? #expr2 : \r\n" L"piecewise_otherwise: #prec[1000(5)]#expr1)\r\n" L"piecewise_no_otherwise: #prec[1000(5)]0.0/0.0)\r\n" L"eulergamma: #prec[999]0.577215664901533\r\n" L"exponentiale: #prec[999]2.71828182845905\r\n" L"false: #prec[999]0.0\r\n" L"infinity: #prec[900]1.0/0.0\r\n" L"notanumber: #prec[999]0.0/0.0\r\n" L"pi: #prec[999] 3.14159265358979\r\n" L"true: #prec[999]1.0\r\n")); /* now can use the standard transformation? cg->transform(mt); */ try { #if defined (CUSTOM_CODE_GENERATION) RETURN_INTO_OBJREF(cci,iface::cellml_services::CustomCodeInformation,ccg->generateCode()); printf("Constraint level = "); switch (cci->constraintLevel()) { case iface::cellml_services::UNDERCONSTRAINED: printf("UNDERCONSTRAINED\n"); break; case iface::cellml_services::UNSUITABLY_CONSTRAINED: printf("UNSUITABLY_CONSTRAINED\n"); break; case iface::cellml_services::OVERCONSTRAINED: printf("OVERCONSTRAINED\n"); break; case iface::cellml_services::CORRECTLY_CONSTRAINED: printf("CORRECTLY_CONSTRAINED\n"); break; default: printf("Unkown value\n"); } printf("Index count: %u\n", cci->indexCount()); cti = already_AddRefd<iface::cellml_services::ComputationTargetIterator>(cci->iterateTargets()); while (true) { RETURN_INTO_OBJREF(ct, iface::cellml_services::ComputationTarget, cti->nextComputationTarget()); if (ct == NULL) break; RETURN_INTO_OBJREF(cv, iface::cellml_api::CellMLVariable, ct->variable()); RETURN_INTO_WSTRING(compname, cv->componentName()); RETURN_INTO_WSTRING(varname, cv->name()); printf("* Computation target %S/%S:%u:\n", compname.c_str(), varname.c_str(), ct->degree()); printf(" => Type = "); switch (ct->type()) { case iface::cellml_services::VARIABLE_OF_INTEGRATION: printf("VARIABLE_OF_INTEGRATION - was marked as independent.\n"); break; case iface::cellml_services::CONSTANT: printf("CONSTANT - this should not happen!\n"); break; case iface::cellml_services::STATE_VARIABLE: printf("STATE_VARIABLE - was requested, and is available.\n"); break; case iface::cellml_services::ALGEBRAIC: printf("ALGEBRAIC - is used as an intermediate.\n"); break; case iface::cellml_services::FLOATING: printf("FLOATING - unused and not requested.\n"); break; case iface::cellml_services::LOCALLY_BOUND: printf("LOCALLY_BOUND - locally bound in expressions only.\n"); break; case iface::cellml_services::PSEUDOSTATE_VARIABLE: printf("PSEUDOSTATE_VARIABLE - target was requested, but could " "not be computed from the independent variables and model.\n"); break; default: printf("Unknown type!\n"); } RETURN_INTO_WSTRING(targname, ct->name()); printf(" => Name = %S\n", targname.c_str()); printf(" => Index = %u\n", ct->assignedIndex()); } // To do: Print output from cci->iterateTargets(); RETURN_INTO_WSTRING(functionsString, cci->functionsString()); printf("Functions: %S\n", functionsString.c_str()); RETURN_INTO_WSTRING(codeS, cci->generatedCode()); printf("Code: %S\n", codeS.c_str()); #else // CUSTOM_CODE_GENERATION // annotate the source variables in the model with the code-names based on existing annotations RETURN_INTO_OBJREF(cvbs,iface::cellml_services::CeVASBootstrap,CreateCeVASBootstrap()); RETURN_INTO_OBJREF(cevas,iface::cellml_services::CeVAS,cvbs->createCeVASForModel(model)); for (unsigned int i=0;i<cevas->length();i++) { RETURN_INTO_OBJREF(cvs,iface::cellml_services::ConnectedVariableSet,cevas->getVariableSet(i)); RETURN_INTO_OBJREF(sv,iface::cellml_api::CellMLVariable,cvs->sourceVariable()); RETURN_INTO_WSTRING(array,as->getStringAnnotation(sv,L"array")); RETURN_INTO_WSTRING(index,as->getStringAnnotation(sv,L"array_index")); if (!array.empty() && !index.empty()) { std::wstring ename = array; ename += L"["; ename += index; ename += L"]"; as->setStringAnnotation(sv,L"expression",ename.c_str()); if (array == L"OC_STATE") { ename = std::wstring(L"OC_RATE"); ename += L"["; ename += index; ename += L"]"; as->setStringAnnotation(sv,L"expression_d1",ename.c_str()); } } } cg->useCeVAS(cevas); cg->useAnnoSet(as); RETURN_INTO_OBJREF(cci,iface::cellml_services::CodeInformation,cg->generateCode(model)); wchar_t* m = cci->errorMessage(); if (!wcscmp(m,L"")) { std::cout << "whoo hoo!" << std::endl; iface::cellml_services::ModelConstraintLevel mcl = cci->constraintLevel(); if (mcl == iface::cellml_services::UNDERCONSTRAINED) { std::cerr << "Model is underconstrained" << std::endl; } else if (mcl == iface::cellml_services::OVERCONSTRAINED) { std::cerr << "Model is overconstrained" << std::endl; } else if (mcl == iface::cellml_services::UNSUITABLY_CONSTRAINED) { std::cerr << "Model is unsuitably constrained" << std::endl; } else { std::cout << "Model is correctly constrained" << std::endl; // create the code in the format we know how to handle code += L"#include <math.h>\n"; code += L"#include <stdio.h>\n"; /* required functions */ code += L"extern double fabs(double x);\n"; code += L"extern double acos(double x);\n"; code += L"extern double acosh(double x);\n"; code += L"extern double atan(double x);\n"; code += L"extern double atanh(double x);\n"; code += L"extern double asin(double x);\n"; code += L"extern double asinh(double x);\n"; code += L"extern double acos(double x);\n"; code += L"extern double acosh(double x);\n"; code += L"extern double asin(double x);\n"; code += L"extern double asinh(double x);\n"; code += L"extern double atan(double x);\n"; code += L"extern double atanh(double x);\n"; code += L"extern double ceil(double x);\n"; code += L"extern double cos(double x);\n"; code += L"extern double cosh(double x);\n"; code += L"extern double tan(double x);\n"; code += L"extern double tanh(double x);\n"; code += L"extern double sin(double x);\n"; code += L"extern double sinh(double x);\n"; code += L"extern double exp(double x);\n"; code += L"extern double floor(double x);\n"; code += L"extern double pow(double x, double y);\n"; code += L"extern double factorial(double x);\n"; code += L"extern double log(double x);\n"; code += L"extern double arbitrary_log(double x, double base);\n"; code += L"extern double gcd_pair(double a, double b);\n"; code += L"extern double lcm_pair(double a, double b);\n"; code += L"extern double gcd_multi(unsigned int size, ...);\n"; code += L"extern double lcm_multi(unsigned int size, ...);\n"; code += L"extern double multi_min(unsigned int size, ...);\n"; code += L"extern double multi_max(unsigned int size, ...);\n"; code += L"extern void NR_MINIMISE(double(*func)" L"(double VOI, double *C, double *R, double *S, double *A)," L"double VOI, double *C, double *R, double *S, double *A, " L"double *V);\n"; wchar_t* frag = cci->functionsString(); code += frag; free(frag); nBound = 1; nRates = cci->rateIndexCount(); nAlgebraic = cci->algebraicIndexCount(); nConstants = cci->constantIndexCount(); code += L"\n\nvoid OC_CellML_RHS_routine(double VOI, double* OC_STATE, double* OC_RATE, double* OC_WANTED, double* OC_KNOWN)\n{\n\n"; code += L"double DUMMY_ASSIGNMENT;\n"; code += L"double CONSTANTS["; code += formatNumber(nConstants); code += L"], ALGEBRAIC["; code += formatNumber(nAlgebraic); code += L"];\n\n"; // start the model code... /* https://svn.physiomeproject.org/svn/physiome/CellML_DOM_API/trunk/interfaces/CCGS.idl for full description */ /* initConsts - all variables which aren't state variables but have * an initial_value attribute, and any variables & rates * which follow. */ frag = cci->initConstsString(); //code += L"void SetupFixedConstants(double* CONSTANTS,double* RATES," // L"double* STATES)\n{\n"; code += frag; //code += L"}\n"; free(frag); /* rates - All rates which are not static. */ frag = cci->ratesString(); //code += L"void ComputeRates(double VOI,double* STATES,double* RATES," // L"double* CONSTANTS,double* ALGEBRAIC)\n{\n"; code += frag; //code += L"}\n"; free(frag); /* variables - All variables not computed by initConsts or rates * (i.e., these are not required for the integration of the model and * thus only need to be called for output or presentation or similar * purposes) */ frag = cci->variablesString(); //code += L"void EvaluateVariables(double VOI,double* CONSTANTS," // L"double* RATES, double* STATES, double* ALGEBRAIC)\n{\n"; code += frag; //code += L"}\n"; free(frag); // and now clear out initialisation of state variables and known variables. clearCodeAssignments(code,L"OC_STATE",mStateCounter); clearCodeAssignments(code,L"OC_KNOWN",mParameterCounter); // close the subroutine code += L"\n\n}//OC_CellML_RHS_routine()\n\n;"; } } else { std::wcerr << "Error generating code: " << m << std::endl; } free(m); #endif // CUSTOM_CODE_GENERATION } catch (...) { std::wcerr << L"Error generating the code information for model" << std::endl; } return code; }
int main(int argc, char** argv) { // Get the URL from which to load the model... if (argc < 2) { printf("Usage: CellML2C modelURL\n"); return -1; } uint32_t usenames = 0, useida = 0; for (int32_t i = 2; i < argc; i++) { if (!strcmp(argv[i], "usenames")) usenames = 1; else if (!strcmp(argv[i], "useida")) useida = 1; } wchar_t* URL; size_t l = strlen(argv[1]); URL = new wchar_t[l + 1]; memset(URL, 0, (l + 1) * sizeof(wchar_t)); const char* mbrurl = argv[1]; mbsrtowcs(URL, &mbrurl, l, NULL); iface::cellml_api::CellMLBootstrap* cb = CreateCellMLBootstrap(); iface::cellml_api::ModelLoader* ml = cb->modelLoader(); cb->release_ref(); iface::cellml_api::Model* mod; try { mod = ml->loadFromURL(URL); } catch (...) { printf("Error loading model URL.\n"); // Well, a leak on exit wouldn't be so bad, but someone might reuse this // code, so... delete [] URL; ml->release_ref(); return -1; } ml->release_ref(); delete [] URL; mod->fullyInstantiateImports(); iface::cellml_services::CodeGeneratorBootstrap* cgb = CreateCodeGeneratorBootstrap(); iface::cellml_services::CodeGenerator* cg; iface::cellml_services::IDACodeGenerator* icg; if (useida) cg = icg = cgb->createIDACodeGenerator(); else cg = cgb->createCodeGenerator(); cgb->release_ref(); if (usenames) doNameAnnotations(mod, cg); iface::cellml_services::CodeInformation* cci = NULL; try { cci = cg->generateCode(mod); } catch (iface::cellml_api::CellMLException&) { printf("Caught a CellMLException while generating code.\n"); cg->release_ref(); mod->release_ref(); return -1; } catch (...) { printf("Unexpected exception calling generateCode!\n"); // this is a leak, but it should also never happen :) return -1; } mod->release_ref(); cg->release_ref(); std::wstring m = cci->errorMessage(); if (m != L"") { printf("Error generating code: %S\n", m.c_str()); cci->release_ref(); return -1; } // We now have the code information... WriteCode(cci, useida); cci->release_ref(); return 0; }
int main(int argc, char** argv) { if (argc < 5) { printf("Usage: CustomGen modelURL wanted known unwanted\n" "Each of wanted, known, and unwanted is a comma separated list.\n" "Use a single comma to specify an empty list.\n" "Each entry in the list should be in the form:\n" " component/variable:degreeOfDerivative\n"); return -1; } std::wstring URL(MakeWideString(argv[1])); std::set<std::pair<std::pair<std::wstring, std::wstring>, uint32_t> > wanted, known, unwanted; TargetDescriptionToSet(argv[2], wanted); TargetDescriptionToSet(argv[3], known); TargetDescriptionToSet(argv[4], unwanted); RETURN_INTO_OBJREF(cb, iface::cellml_api::CellMLBootstrap, CreateCellMLBootstrap()); RETURN_INTO_OBJREF(ml, iface::cellml_api::ModelLoader, cb->modelLoader()); // These assignments to NULL are only here in the test code to help look for // memory errors by freeing things early... in production code, they wouldn't // be necessary. cb = NULL; ObjRef<iface::cellml_api::Model> mod; try { mod = already_AddRefd<iface::cellml_api::Model>(ml->loadFromURL(URL.c_str())); } catch (...) { printf("Error loading model URL.\n"); return -1; } RETURN_INTO_OBJREF(cgb, iface::cellml_services::CodeGeneratorBootstrap, CreateCodeGeneratorBootstrap() ); RETURN_INTO_OBJREF(cg, iface::cellml_services::CodeGenerator, cgb->createCodeGenerator()); cgb = NULL; cg->stateVariableNamePattern(L"VARS[%]"); RETURN_INTO_OBJREF(ccg, iface::cellml_services::CustomGenerator, cg->createCustomGenerator(mod)); cg = NULL; mod = NULL; RETURN_INTO_OBJREF(cti, iface::cellml_services::ComputationTargetIterator, ccg->iterateTargets()); while (true) { RETURN_INTO_OBJREF(ct, iface::cellml_services::ComputationTarget, cti->nextComputationTarget()); if (ct == NULL) break; RETURN_INTO_OBJREF(cv, iface::cellml_api::CellMLVariable, ct->variable()); RETURN_INTO_WSTRING(compname, cv->componentName()); RETURN_INTO_WSTRING(varname, cv->name()); std::pair<std::pair<std::wstring, std::wstring>, uint32_t> p (std::pair<std::wstring, std::wstring>(compname, varname), ct->degree()); if (wanted.count(p)) ccg->requestComputation(ct); else if (known.count(p)) ccg->markAsKnown(ct); else if (unwanted.count(p)) ccg->markAsUnwanted(ct); } cti = NULL; RETURN_INTO_OBJREF(cci, iface::cellml_services::CustomCodeInformation, ccg->generateCode()); ccg = NULL; printf("Constraint level = "); switch (cci->constraintLevel()) { case iface::cellml_services::UNDERCONSTRAINED: printf("UNDERCONSTRAINED\n"); break; case iface::cellml_services::UNSUITABLY_CONSTRAINED: printf("UNSUITABLY_CONSTRAINED\n"); break; case iface::cellml_services::OVERCONSTRAINED: printf("OVERCONSTRAINED\n"); break; case iface::cellml_services::CORRECTLY_CONSTRAINED: printf("CORRECTLY_CONSTRAINED\n"); break; default: printf("Unkown value\n"); } printf("Index count: %u\n", cci->indexCount()); cti = already_AddRefd<iface::cellml_services::ComputationTargetIterator>(cci->iterateTargets()); while (true) { RETURN_INTO_OBJREF(ct, iface::cellml_services::ComputationTarget, cti->nextComputationTarget()); if (ct == NULL) break; RETURN_INTO_OBJREF(cv, iface::cellml_api::CellMLVariable, ct->variable()); RETURN_INTO_WSTRING(compname, cv->componentName()); RETURN_INTO_WSTRING(varname, cv->name()); printf("* Computation target %S/%S:%u:\n", compname.c_str(), varname.c_str(), ct->degree()); printf(" => Type = "); switch (ct->type()) { case iface::cellml_services::VARIABLE_OF_INTEGRATION: printf("VARIABLE_OF_INTEGRATION - was marked as independent.\n"); break; case iface::cellml_services::CONSTANT: printf("CONSTANT - this should not happen!\n"); break; case iface::cellml_services::STATE_VARIABLE: printf("STATE_VARIABLE - was requested, and is available.\n"); break; case iface::cellml_services::ALGEBRAIC: printf("ALGEBRAIC - is used as an intermediate.\n"); break; case iface::cellml_services::FLOATING: printf("FLOATING - unused and not requested.\n"); break; case iface::cellml_services::LOCALLY_BOUND: printf("LOCALLY_BOUND - locally bound in expressions only.\n"); break; case iface::cellml_services::PSEUDOSTATE_VARIABLE: printf("PSEUDOSTATE_VARIABLE - target was requested, but could " "not be computed from the independent variables and model.\n"); break; default: printf("Unknown type!\n"); } RETURN_INTO_WSTRING(targname, ct->name()); printf(" => Name = %S\n", targname.c_str()); printf(" => Index = %u\n", ct->assignedIndex()); } // To do: Print output from cci->iterateTargets(); RETURN_INTO_WSTRING(functionsString, cci->functionsString()); printf("Functions: %S\n", functionsString.c_str()); RETURN_INTO_WSTRING(code, cci->generatedCode()); printf("Code: %S\n", code.c_str()); }
std::string generateCodeForModel(CellmlApiObjects* capi, std::map<std::string, unsigned char>& variableTypes, std::map<std::string, std::map<unsigned char, int> >& variableIndices, int numberOfInputs, int numberOfStates) { std::stringstream code; std::string codeString; if (! (capi && capi->codeInformation)) { std::cerr << "CellML Model Definition::generateCodeForModel: missing model implementation?" << std::endl; return ""; } // We need to regenerate the code information to make use of the flagged variables. ObjRef<iface::cellml_services::CodeGeneratorBootstrap> cgb = CreateCodeGeneratorBootstrap(); ObjRef<iface::cellml_services::CodeGenerator> cg = cgb->createCodeGenerator(); // catch any exceptions from the CellML API try { // annotate the source variables in the model with the code-names based on existing annotations for (unsigned int i=0; i < capi->cevas->length(); i++) { ObjRef<iface::cellml_services::ConnectedVariableSet> cvs = capi->cevas->getVariableSet(i); ObjRef<iface::cellml_api::CellMLVariable> sv = cvs->sourceVariable(); std::string currentId = getVariableUniqueId(sv); std::map<std::string, unsigned char>::iterator typeit(variableTypes.find(currentId)); if (typeit != variableTypes.end()) { std::wstringstream ename; // here we assign an array and index based on the "primary" purpose of the variable. Later // we will add in secondary purposes. unsigned char vType = typeit->second; if (vType & csim::StateType) { ename << L"CSIM_STATE[" << variableIndices[currentId][csim::StateType] << L"]"; } else if (vType & csim::IndependentType) { // do nothing, but stop input and output annotations } else if (vType & csim::InputType) { ename << L"CSIM_INPUT[" << variableIndices[currentId][csim::InputType] << L"]"; } else if (vType & csim::OutputType) { ename << L"CSIM_OUTPUT[" << variableIndices[currentId][csim::OutputType] << L"]"; } capi->annotations->setStringAnnotation(sv, L"expression", ename.str()); if (vType & csim::StateType) { ename.str(L""); ename.clear(); ename << L"CSIM_RATE[" << variableIndices[currentId][csim::StateType] << L"]"; capi->annotations->setStringAnnotation(sv, L"expression_d1", ename.str()); } } } cg->useCeVAS(capi->cevas); cg->useAnnoSet(capi->annotations); ObjRef<iface::cellml_services::CodeInformation> cci = cg->generateCode(capi->model); std::wstring m = cci->errorMessage(); if (m != L"") { std::cerr << "CellML Model Definition::generateCodeForModel: error generating code?" << std::endl; return ""; } iface::cellml_services::ModelConstraintLevel mcl = cci->constraintLevel(); if (mcl == iface::cellml_services::UNDERCONSTRAINED) { std::cerr << "Model is underconstrained" << std::endl; return ""; } else if (mcl == iface::cellml_services::OVERCONSTRAINED) { std::cerr << "Model is overconstrained" << std::endl; return ""; } else if (mcl == iface::cellml_services::UNSUITABLY_CONSTRAINED) { std::cerr << "Model is unsuitably constrained" << std::endl; return ""; } std::cout << "Model is correctly constrained" << std::endl; // create the code in the format we know how to handle code << "//#include <math.h>\n" /* required functions */ << "double fabs(double x);\n" << "double acos(double x);\n" << "double acosh(double x);\n" << "double atan(double x);\n" << "double atanh(double x);\n" << "double asin(double x);\n" << "double asinh(double x);\n" << "double acos(double x);\n" << "double acosh(double x);\n" << "double asin(double x);\n" << "double asinh(double x);\n" << "double atan(double x);\n" << "double atanh(double x);\n" << "double ceil(double x);\n" << "double cos(double x);\n" << "double cosh(double x);\n" << "double tan(double x);\n" << "double tanh(double x);\n" << "double sin(double x);\n" << "double sinh(double x);\n" << "double exp(double x);\n" << "double floor(double x);\n" << "double pow(double x, double y);\n" << "double factorial(double x);\n" << "double log(double x);\n" << "double arbitrary_log(double x, double base);\n" << "double gcd_pair(double a, double b);\n" << "double lcm_pair(double a, double b);\n" << "double gcd_multi(unsigned int size, ...);\n" << "double lcm_multi(unsigned int size, ...);\n" << "double multi_min(unsigned int size, ...);\n" << "double multi_max(unsigned int size, ...);\n" << "void NR_MINIMISE(double(*func)" "(double VOI, double *C, double *R, double *S, double *A)," "double VOI, double *C, double *R, double *S, double *A, " "double *V);\n"; std::wstring frag = cci->functionsString(); code << ws2s(frag); int nAlgebraic = cci->algebraicIndexCount(); int nConstants = cci->constantIndexCount(); code << "\n\nvoid csim_rhs_routine(double VOI, double* CSIM_STATE, double* CSIM_RATE, double* CSIM_OUTPUT, " << "double* CSIM_INPUT)\n{\n\n" << "double DUMMY_ASSIGNMENT;\n" << "double CONSTANTS[" << nConstants << "], ALGEBRAIC[" << nAlgebraic << "];\n\n"; /* initConsts - all variables which aren't state variables but have * an initial_value attribute, and any variables & rates * which follow. */ code << ws2s(cci->initConstsString()); /* rates - All rates which are not static. */ code << ws2s(cci->ratesString()); /* variables - All variables not computed by initConsts or rates * (i.e., these are not required for the integration of the model and * thus only need to be called for output or presentation or similar * purposes) */ code << ws2s(cci->variablesString()); // add in the setting of any outputs that are not already defined for (unsigned int i=0; i < capi->cevas->length(); i++) { ObjRef<iface::cellml_services::ConnectedVariableSet> cvs = capi->cevas->getVariableSet(i); ObjRef<iface::cellml_api::CellMLVariable> sv = cvs->sourceVariable(); std::string currentId = getVariableUniqueId(sv); std::map<std::string, unsigned char>::iterator typeit(variableTypes.find(currentId)); if (typeit != variableTypes.end()) { unsigned char vType = typeit->second; if (vType & csim::OutputType) { if (vType & csim::StateType) code << "CSIM_OUTPUT[" << variableIndices[currentId][csim::OutputType] << "] = CSIM_STATE[" << variableIndices[currentId][csim::StateType] << "];\n"; else if (vType & csim::InputType) code << "CSIM_OUTPUT[" << variableIndices[currentId][csim::OutputType] << "] = CSIM_INPUT[" << variableIndices[currentId][csim::InputType] << "];\n"; else if (vType & csim::IndependentType) code << "CSIM_OUTPUT[" << variableIndices[currentId][csim::OutputType] << "] = VOI;\n"; } } } // close the subroutine code << "\n\n}//csim_rhs_routine()\n\n"; // and now clear out initialisation of state variables and known variables from // the RHS routine. codeString = clearCodeAssignments(code.str(), "CSIM_STATE", numberOfStates); codeString = clearCodeAssignments(codeString, "CSIM_INPUT", numberOfInputs); // and finally create the initialisation routine std::stringstream initRoutine; initRoutine << "\nvoid csim_initialise_routine(double* CSIM_STATE, double* CSIM_OUTPUT, double* CSIM_INPUT)\n{\n"; // FIXME: this doesn't need to be in the interface? initRoutine << "double CSIM_RATES[" << numberOfStates << "];\n"; initRoutine << "double CONSTANTS[" << nConstants << "];\n"; initRoutine << ws2s(cci->initConstsString()); initRoutine << "\n}\n"; codeString += initRoutine.str(); } catch (...) { std::cerr << "CellML Model Definition::generateCodeForModel: something went wrong generating code?" << std::endl; return ""; } return codeString; }
int CellmlModelDefinition::instantiateCellmlApiObjects() { try { // create an annotation set to manage our variable usages ObjRef<iface::cellml_services::AnnotationToolService> ats = CreateAnnotationToolService(); ObjRef<iface::cellml_services::AnnotationSet> as = ats->createAnnotationSet(); mCapi->annotations = as; // mapping the connections between variables is a very expensive operation, so we want to // only do it once and keep hold of the mapping (tracker item 3294) ObjRef<iface::cellml_services::CeVASBootstrap> cvbs = CreateCeVASBootstrap(); ObjRef<iface::cellml_services::CeVAS> cevas = cvbs->createCeVASForModel(mCapi->model); std::wstring msg = cevas->modelError(); if (msg != L"") { std::cerr << "loadModel: Error creating CellML Variable Association Service: " << ws2s(msg) << std::endl; return -2; } mCapi->cevas = cevas; // now check we can generate code and grab hold of the initial code information ObjRef<iface::cellml_services::CodeGeneratorBootstrap> cgb = CreateCodeGeneratorBootstrap(); ObjRef<iface::cellml_services::CodeGenerator> cg = cgb->createCodeGenerator(); try { cg->useCeVAS(cevas); ObjRef<iface::cellml_services::CodeInformation> cci = cg->generateCode(mCapi->model); msg = cci->errorMessage(); if (msg != L"") { std::cerr << "CellmlModelDefintion::loadModel: Error generating code: " << ws2s(msg) << std::endl; return -4; } // TODO: we are only interested in models we can work with? if (cci->constraintLevel() != iface::cellml_services::CORRECTLY_CONSTRAINED) { std::cerr << "CellmlModelDefintion::loadModel: Model is not correctly constrained: " << std::endl; return -5; } mCapi->codeInformation = cci; // always flag all state variables and the variable of integration ObjRef<iface::cellml_services::ComputationTargetIterator> cti = cci->iterateTargets(); while (true) { ObjRef<iface::cellml_services::ComputationTarget> ct = cti->nextComputationTarget(); if (ct == NULL) break; if (ct->degree() > 0) break; // only want to initialise the base variables not the differential ObjRef<iface::cellml_api::CellMLVariable> v(ct->variable()); if (ct->type() == iface::cellml_services::STATE_VARIABLE) { mVariableTypes[getVariableUniqueId(v)] = csim::StateType; mVariableIndices[getVariableUniqueId(v)][csim::StateType] = mStateCounter; mStateCounter++; } else if (ct->type() == iface::cellml_services::VARIABLE_OF_INTEGRATION) { mVariableTypes[getVariableUniqueId(v)] = csim::IndependentType; mNumberOfIndependentVariables++; } else { // need to initialise the variable type mVariableTypes[getVariableUniqueId(v)] = csim::UndefinedType; } } } catch (...) { std::cerr << "loadModel: Error generating the code information for the model" << std::endl; return -3; } // if we get to here, everything worked. mModelLoaded = true; } catch (...) { std::wcerr << L"Error instantiating CellML API objects." << std::endl; return -1; } return csim::CSIM_OK; }