def numberVars(diffvars): ret = {} count = 1 for var in order(diffvars): ret[var] = count count += 1 return ret
def generateMatlab(model, targetName): template = {} template["target"] = targetName inputs = model.inputs() if inputs: template["arglower"] = 1 else: template["arglower"] = 0 good = set() if model.time != None: good.add(model.time) timename = str(model.time) else: timename = "U_current_time" template["timename"] = timename out = utility.Indenter(open(targetName + "_init.m", "w")) params = model.varsWithAttribute("param") printer = MatlabPrintVisitor(out, model.ssa, params) out(""" function [U_y_init, U_ordering, U_params] = %(target)s_init(%(timename)s,varargin) narginchk(1+%(arglower)d,2); if (nargin >= 1) U_params = varargin{1}; else U_params = struct(); end """ % template) out.inc() if inputs: out("%define the inputs") good |= inputs for symbol in order(inputs): out("%s = U_params.%s(%s);", pretty(symbol), pretty(symbol), timename) out("\n\n") out("%define the initial conditions") diffvars = model.diffvars() model.printTarget(good, params | diffvars, printer) diffvarNumbering = numberVars(diffvars) out("U_y_init = zeros(%d, 1);", len(diffvarNumbering)) for var in order(diffvars): out("U_y_init(%d) = %s;", diffvarNumbering[var], pretty(var)) out("U_ordering = struct();") for var in order(diffvars): out("U_ordering.%s = %d;", pretty(var), diffvarNumbering[var]) out.dec() out(""" end """ % template) out = utility.Indenter(open(targetName + ".m", "w")) printer = MatlabPrintVisitor(out, model.ssa, params) out(""" function U_dydt = %(target)s(%(timename)s,U_diffvars,varargin) """ % template) out.inc() out("U_dydt = zeros(%d,1);" % len(diffvarNumbering)) good = set() if model.time != None: good.add(model.time) out("% make copies of the differential vars") for var in order(diffvars): out("%s = U_diffvars(%d);", pretty(var), diffvarNumbering[var]) good |= diffvars out(""" narginchk(2+%(arglower)d,3); if (nargin >= 3) U_params = varargin{1}; else U_params = struct(); end """ % template) if inputs: out("% define all inputs") good |= inputs for symbol in order(inputs): out("%s = U_params.%s(%s);", pretty(symbol), pretty(symbol), timename) out("% define the differential update") diffvarUpdate = {var: model.diffvarUpdate(var) for var in diffvars} model.printTarget(good, set(diffvarUpdate.values()), printer) out("% stuff the differential update into an array") for var in order(diffvars): out("U_dydt(%d) = %s;", diffvarNumbering[var], pretty(diffvarUpdate[var])) out.dec() out(""" end""" % template) out = utility.Indenter(open(targetName + "_trace.m", "w")) printer = MatlabPrintVisitor(out, model.ssa, params) out(""" function U_trace = %(target)s_trace(%(timename)s,U_diffvars,varargin) """ % template) out.inc() out("% make copies of the differential vars") for var in order(diffvars): out("%s = U_diffvars(:,%d);", pretty(var), diffvarNumbering[var]) out(""" narginchk(2+%(arglower)d,3); if (nargin >= 3) U_params = varargin{1}; else U_params = struct(); end """ % template) if inputs: out("% define all inputs") good |= inputs for symbol in order(inputs): out("%s = U_params.%s(%s);", pretty(symbol), pretty(symbol), timename) tracevars = model.varsWithAttribute("trace") out("%calculate the tracing vars we need") model.printTarget(good, tracevars - good, printer) out("%save the tracing vars") out("U_trace = struct();") for var in order(tracevars): out('U_trace.%s = %s;', var, var) out.dec() out(""" end""" % template)
def generateContinuity(model, targetName): template = {} template["target"] = targetName diffvars = model.diffvars() diffvarUpdate = {var: model.diffvarUpdate(var) for var in diffvars} gates = model.varsWithAttribute("gate") & diffvars params = model.varsWithAttribute("param") coupled = model.varsWithAttribute("coupled") & diffvars inputs = model.inputs() differ = Differentiator(model, diffvars | params | inputs) gateJacobians = {} for gate in diffvars: (gateJacobians[gate], dontcare) = differ.diff(diffvarUpdate[gate], gate) differ.augmentInstructions() dt = model.addSymbol("_dt") approxvars = set([dt]) if model.time != None: approxvars.add(model.time) expensiveVars = model.extractExpensiveFunctions() model.makeNamesUnique() computeTargets = set() computeTargets |= set([diffvarUpdate[var] for var in diffvars]) computeTargets |= set([gateJacobians[var] for var in diffvars]) statevars = model.inputs() | diffvars computeAllDepend = model.allDependencies(approxvars | statevars, computeTargets) constants = model.allExcluding(approxvars, statevars) & computeAllDepend varCount = {} ii = 0 for var in order(coupled): varCount[var] = ii ii += 1 for var in order(diffvars - coupled): varCount[var] = ii ii += 1 ii = 0 for var in order(inputs): varCount[var] = ii ii += 1 for var in order(params): varCount[var] = ii ii += 1 fieldNumbers = {} ii = 1 for var in order(inputs): fieldNumbers[var] = ii ii += 1 for var in order(coupled): fieldNumbers[var] = ii ii += 1 out = utility.Indenter(open(targetName + ".txt", "w")) out(" component %(target)s StateVar", template) for var in order(coupled): out( "voltage spatially coupled [['Field %d', '']] d%s_dt = 0 StateVar %s", fieldNumbers[var], pretty(var), pretty(var)) for var in order(diffvars - coupled): out("voltage state [['Value', '1']] d%s_dt = 0 StateVar %s", pretty(var), pretty(var)) out("param root component __root__ Parameters") out.inc() for var in order(inputs): out("parameter [['Field %s', '']] Parameters %s", fieldNumbers[var], pretty(var)) for var in order(params): out("parameter [['Value', '%s']] Parameters %s", str(model.ssa[var].sympy), pretty(var)) out.dec() out = utility.Indenter(open(targetName + ".continuity.c", "w")) out(''' void cpu_advance_be1(REAL _t, REAL _t_end, REAL *_y_global, REAL *_y_global_temp, REAL *_rpar_global, int num_gauss_pts, int num_gpus, int gp_offset) { //REAL bi; REAL _dt = _t_end-_t; ''' % template) out.inc() if model.time: out("REAL %s = _t;", pretty(model.time)) good = set() good |= approxvars for var in order(diffvars): out("REAL %s=_y_global[%d];", pretty(var), varCount[var]) good |= statevars for var in order(params | inputs): out("REAL %s=_rpar_global[%d];", pretty(var), varCount[var]) good |= params cprinter = CPrintVisitor(out, model.ssa, good, "REAL") model.printTarget(good, computeTargets, cprinter) for var in order(diffvars): out("_y_global_temp[%d] = _y_global[%d] + %s*_dt/(1-_dt*%s);", varCount[var], varCount[var], diffvarUpdate[var], gateJacobians[var]) out.dec() out(''' //assigned_vars: 10 } ''' % template)
def toCode(self, out, declared=set()): declared = declared.copy() out("subsystem %s {", self.name) out.inc() #find all the variables I need to specify for me. allDecl = set() for component in self.subComponents.values(): allDecl |= component.outputs allDecl |= component.inputs allDecl |= self.localDiffvars() allDecl |= self.inputs allDecl |= self.outputs allDiffvars = set() for componentName in order(self.subComponents.keys()): subComponent = self.subComponents[componentName] allDiffvars |= subComponent.outputDiffvars() allDiffvars |= self.localDiffvars() allConstants = set() for componentName in order(self.subComponents.keys()): subComponent = self.subComponents[componentName] allConstants |= subComponent.outputConstants() allConstants |= self.localConstants() #separate those declared variables into computed and state if True: allDecl -= declared localDiffvars = self.localDiffvars() - self.outputs for var in order(self.outputs & allDiffvars): out("provides diffvar %s {%s};", var, self.lookupUnit(var)) for var in order(self.outputs & allConstants): out("provides %s {%s};", var, self.lookupUnit(var)) for var in order(self.outputs - allDiffvars - allConstants): out("provides %s {%s};", var, self.lookupUnit(var)) for var in order((allDecl - allConstants) - self.outputs - self.inputs - localDiffvars): out("shared %s {%s};", var, self.lookupUnit(var)) for var in order((allDecl & allConstants) - self.outputs - self.inputs - localDiffvars): out("shared %s {%s};", var, self.lookupUnit(var)) for var in order(localDiffvars): out("diffvar %s {%s};", var, self.lookupUnit(var)) declared |= allDecl #find all the differential variables invoked = set() good = self.inputs.copy() | allDiffvars | (allConstants - self.localConstants()) defined = set() while True: newFront = set() #go through all the invocations and see if they are good to go for componentName in order( set(self.subComponents.keys()) - invoked): subComponent = self.subComponents[componentName] if subComponent.inputs <= good: subComponent.toCode(out, declared) newFront |= subComponent.outputs invoked.add(componentName) #go through all the equations looking for things with met dependencies. for var in order((set(self.eqns.keys()) - defined)): eqn = self.eqns[var] #print var #print eqn.dependencies #print good #print defined if eqn.dependencies <= good: newFront.add(var) eqn.toCode(out) if eqn.isDiff: newFront.add(var + ".diff") if not newFront: break else: good |= newFront defined |= newFront if not self.outputs <= defined or invoked < set( self.subComponents.keys()): #out("//WARNING, circular dependency detected, dumping the rest. You'll have to fix this manually.") for var in order((set(self.eqns.keys()) - defined)): self.eqns[var].toCode(out) for componentName in order( set(self.subComponents.keys()) - invoked): subComponent = self.subComponents[componentName] subComponent.toCode(out, declared) debug = False if debug: print(list(self.eqns.keys())) print(self.outputs) print(self.outputs - defined) print(good) print("-----") print(invoked) print(set(self.subComponents.keys()) - invoked) for componentName in set(self.subComponents.keys()) - invoked: print("=====") component = self.subComponents[componentName] print(component.name) print(component.inputs - good) print(component.outputs - good) assert (False) out.dec() out("}")
def generateChaste(model, targetName): template = {} template["target"] = targetName diffvars = model.diffvars() diffvarUpdate = {var: model.diffvarUpdate(var) for var in diffvars} params = model.varsWithAttribute("param") gates = model.varsWithAttribute("gate") & diffvars tracevars = model.varsWithAttribute("trace") markovs = model.varsWithAttribute("markov") & diffvars lbLookup = {} ubLookup = {} for var in gates | markovs: lbLookup[var] = 0 ubLookup[var] = 1 for var in model.varsWithAttribute("lb"): lbLookup[var] = model.info("lb", var) ubLookup[var] = model.info("ub", var) V = model.input("V") V_init = model.output("V_init") Iion = model.output("Iion") hasCai = False if "Cai" in model.outputs(): Cai = model.output("Cai") hasCai = True out = utility.Indenter(open(targetName + ".hpp", "w")) out( ''' #ifndef %(target)s_HPP_ #define %(target)s_HPP_ #include "ChasteSerialization.hpp" #include <boost/serialization/base_object.hpp> #include "AbstractCardiacCell.hpp" #include "AbstractStimulusFunction.hpp" #include "AbstractDynamicallyLoadableEntity.hpp" #include <vector> /** * This class represents the Luo-Rudy 1991 system of equations, * with support for being compiled into a .so and loaded at run-time. */ class %(target)s : public AbstractCardiacCell, public AbstractDynamicallyLoadableEntity { private: /** Needed for serialization. */ friend class boost::serialization::access; /** * Archive the member variables. * * @param archive * @param version */ template<class Archive> void serialize(Archive & archive, const unsigned int version) { archive & boost::serialization::base_object<AbstractCardiacCell>(*this); archive & boost::serialization::base_object<AbstractDynamicallyLoadableEntity>(*this); } /** * Range-checking on the current values of the state variables. Make sure * all gating variables have are within zero and one, and all concentrations * are positive */ void VerifyStateVariables(); public: /** * Constructor * * @param pSolver is a pointer to the ODE solver * @param pIntracellularStimulus is a pointer to the intracellular stimulus */ %(target)s(boost::shared_ptr<AbstractIvpOdeSolver> pSolver, boost::shared_ptr<AbstractStimulusFunction> pIntracellularStimulus); /** * Destructor */ ~%(target)s(); /** * Fill in a vector representing the RHS of the Luo-Rudy 1991 system * of Odes at each time step, y' = [y1' ... yn']. * Some ODE solver will call this function repeatedly to solve for y = [y1 ... yn]. * * @param time the current time, in milliseconds * @param rY current values of the state variables * @param rDY to be filled in with derivatives */ void EvaluateYDerivatives(double time, const std::vector<double> &rY, std::vector<double> &rDY); /** * Returns the ionic current * * @param pStateVariables optional state at which to evaluate the current * @return the total ionic current */ double GetIIonic(const std::vector<double>* pStateVariables=NULL);''', template) if hasCai: out(''' /** * Get the intracellular calcium concentration * * @return the intracellular calcium concentration */ double GetIntracellularCalciumConcentration(); ''') out( r''' }; #include "SerializationExportWrapper.hpp" CHASTE_CLASS_EXPORT(%(target)s) namespace boost { namespace serialization { /** * Allow us to not need a default constructor, by specifying how Boost should * instantiate a %(target)s instance. */ template<class Archive> inline void save_construct_data( Archive & ar, const %(target)s * t, const unsigned int file_version) { const boost::shared_ptr<AbstractIvpOdeSolver> p_solver = t->GetSolver(); const boost::shared_ptr<AbstractStimulusFunction> p_stimulus = t->GetStimulusFunction(); ar << p_solver; ar << p_stimulus; } /** * Allow us to not need a default constructor, by specifying how Boost should * instantiate a %(target)s instance (using existing constructor). * * NB this constructor allocates memory for the other member variables too. */ template<class Archive> inline void load_construct_data( Archive & ar, %(target)s * t, const unsigned int file_version) { boost::shared_ptr<AbstractIvpOdeSolver> p_solver; boost::shared_ptr<AbstractStimulusFunction> p_stimulus; ar >> p_solver; ar >> p_stimulus; ::new(t)%(target)s(p_solver, p_stimulus); } } } // namespace ... #endif // %(target)s_ ''', template) out = utility.Indenter(open(targetName + ".cpp", "w")) out( r''' #include "%(target)s.hpp" #include "OdeSystemInformation.hpp" #include <cmath> //#include <iostream> #include "Exception.hpp" enum StateVarEnum { ''', template) for var in order(diffvars): out("_enum_%s,", var) out( r''' NUMSTATES }; /** * Constructor */ %(target)s::%(target)s( boost::shared_ptr<AbstractIvpOdeSolver> pSolver, boost::shared_ptr<AbstractStimulusFunction> pIntracellularStimulus) : AbstractCardiacCell(pSolver, NUMSTATES+1, 0, pIntracellularStimulus) { mpSystemInfo = OdeSystemInformation<%(target)s>::Instance(); Init(); } /** * Destructor */ %(target)s::~%(target)s(void) { } ''', template) if hasCai: out( ''' double %s::GetIntracellularCalciumConcentration() { return mStateVariables[_enum_%s+1]; } ''', targetName, Cai) out( r''' /** * Fill in a vector representing the RHS of the %(target)s system * of Odes at each time step, y' = [y1' ... yn']. * Some ODE solver will call this function repeatedly to solve for y = [y1 ... yn]. * * @param time the current time, in milliseconds * @param rY current values of the state variables * @param rDY to be filled in with derivatives */ void %(target)s::EvaluateYDerivatives(double time, const std::vector<double> &_rY, std::vector<double> &_rDY) { ''', template) out.inc() out("double %s = _rY[0];", V) for var in order(diffvars): out("double %s = _rY[_enum_%s+1];", var, var) ii = 0 for var in order(params): out("double %s = GetParameter(%d);", var, ii) ii += 1 cprinter = CPrintVisitor(out, model.ssa, params) good = diffvars | set([V]) | params model.printTarget(good, set(diffvarUpdate.values()) | set([Iion]), cprinter) out("_rDY[0] = -%s;", Iion) for var in order(diffvars): out("_rDY[_enum_%s+1] = %s;", var, diffvarUpdate[var]) out.dec() out( ''' } double %(target)s::GetIIonic(const std::vector<double>* pStateVariables) { ''', template) out.inc() out("double %s = _rY[0];", V) for var in order(diffvars): out("double %s = _rY[_enum_%s+1];", var, var) ii = 0 for var in order(params): out("double %s = GetParameter(%d);", var, ii) ii += 1 cprinter = CPrintVisitor(out, model.ssa, params) model.printTarget(good, set([Iion]), cprinter) out("assert(!std::isnan(%s));", Iion) out("return %s;", Iion) out.dec() out( ''' } void %(target)s::VerifyStateVariables() { const std::vector<double>& _rY = rGetStateVariables(); ''', template) out.inc() for var in order(diffvars): out("double %s = _rY[_enum_%s+1];", var, var) if var in lbLookup: out("if (%s < %s)", var, lbLookup[var]) out("{") out.inc() out( 'EXCEPTION(DumpState("%s has gone under its lower bound. Check model parameters, for example spatial stepsize"));', var) out.dec() out("}") if var in ubLookup: out("if (%s > %s)", var, ubLookup[var]) out("{") out.inc() out( 'EXCEPTION(DumpState("%s has gone over its upper bound. Check model parameters, for example spatial stepsize"));', var) out.dec() out("}") out.dec() out( ''' } template<> void OdeSystemInformation<%(target)s>::Initialise(void) { ''', template) out.inc() cprinter = CPrintVisitor(out, model.ssa, params) model.printTarget(set(), diffvars | set([V_init]) | params, cprinter) out('this->mVariableNames.push_back("%s");', V) out('this->mVariableUnits.push_back("mV");') # FIXME, make generic out('this-mInitialConditions.push_back(%s);', V_init) for var in order(diffvars): out('this->mVariableNames.push_back("%s");', var) out('this->mVariableUnits.push_back("%s");', model.ssa[var].astUnit.rawUnit) out('this-mInitialConditions.push_back(%s);', var) for var in order(params): out('this->mParameterNames.push_back("%s");', var) out('this->mParameterUnits.push_back("");' ) #FIXME, put in a unit if we have one. out('this->mParameters.push_back(%s);', var) out.dec() out( ''' this->mInitialised = true; } #include "SerializationExportWrapperForCpp.hpp" CHASTE_CLASS_EXPORT(%(target)s) extern "C" { /** * C-style constructor with a standard name, so the main program can create instances * of this cell model when it is loaded from a .so. * * @param pSolver ODE solver used to simulate the cell * @param pIntracellularStimulus intracellular stimulus */ AbstractCardiacCellInterface* MakeCardiacCell(boost::shared_ptr<AbstractIvpOdeSolver> pSolver, boost::shared_ptr<AbstractStimulusFunction> pStimulus){ return new %(target)s(pSolver, pStimulus); } } ''', template)
def generateCardioidMech(model, targetName): template = {} template["target"] = targetName diffvars = model.diffvars() diffvarUpdate = {var: model.diffvarUpdate(var) for var in diffvars} flagvars = model.varsWithAttribute("flag") paramvars = model.varsWithAttribute("param") tracevars = model.varsWithAttribute("trace") simvars = set() stretch = model.input("stretch") tension = model.output("tension") if "stretchVel" not in model._inputs: stretchVel = model.addSymbol("stretchVel") else: stretchVel = model.input("stretchVel") inputvars = set([stretch, stretchVel]) | model.inputs() partialFromDiff = {} diffPartialFromDiff = {} differ = Differentiator(model, inputvars - set([stretch])) partialvars = set() for diffvar in diffvars: partial = model.addSymbol("_partial_" + str(diffvar)) partialvars.add(partial) differ.cacheResult(diffvar, stretchVel, partial, None) partialFromDiff[diffvar] = partial partialStretch = model.addSymbol("_partial_stretch") differ.cacheResult(stretch, stretchVel, partialStretch, None) for diffvar in diffvars: (diffvarUpdate[partialFromDiff[diffvar]], dontcare) = differ.diff(diffvarUpdate[diffvar], stretchVel) (dtension_temp, dontcare) = differ.diff(tension, stretchVel) differ.augmentInstructions() dtension_dstretchVel = model.addInstruction("dtension_dstretchVel", dtension_temp) outputvars = set([tension, dtension_dstretchVel]) out = utility.Indenter(open(targetName + ".hh", "w")) out( r''' #include "ExcitationContraction.hh" #include <vector> #include <string> namespace %(target)s { struct State {''', template) out.inc() for var in order(diffvars | partialvars): out("double %s;", var) out.dec() out( ''' }; class ThisModel : public ExcitationContraction { public: ThisModel(const int numPoints); virtual std::string name() const; virtual int getHandle(const std::string& varName) const; virtual std::string getUnit(const int varHandle) const; virtual std::vector<std::string> getVarGroup(const std::string type) const; virtual double get(const int varHandle) const; virtual void set(const int varHandle, const double value); virtual double get(const int varHandle, const int iCell) const; virtual void set(const int varHandle, const int iCell, const double value); virtual double get(const int varHandle, const int iCell, const double* inputs[]) const; virtual void resetDefaultParameters(); virtual void initialize(const double *const inputs[]); virtual void tryTimestep(const double dt, const double *const inputs[]); virtual void outputForNextTimestep(const double dt, const double* const inputs[], double* const outputs[]); virtual void commitTimestep(); private: int _numPoints; //double _dt; //FLAGS ''', template) out.inc() for var in order(flagvars): out("double %s;", var) out.dec() out(r''' //PARAMETERS ''', template) out.inc() for var in order(paramvars): out("double %s;", var) out.dec() out( r''' //STATE std::vector<State> _state[2]; std::vector<State> _partial; int _oldIdx; inline int _old() const { return _oldIdx; } inline int _new() const { return 1 ^ _oldIdx; } inline void swapOldAndNew() { _oldIdx = _new(); } }; } ''', template) out = utility.Indenter(open(targetName + ".cpp", "w")) out( r''' #include "%(target)s.hh" #include <cassert> #include <cmath> using namespace std; namespace %(target)s { string ThisModel::name() const { return "%(target)s"; } enum varHandles { ''', template) handlevars = diffvars | inputvars | outputvars | flagvars | paramvars out.inc() for var in order(handlevars): out('_handle_%s,', var) out.dec() out(r''' NUM_HANDLES }; const string varNames[] = { ''', template) out.inc() for var in order(handlevars): out('"%s",', var) out.dec() out(r''' "" }; const string varUnits[] = { ''', template) out.inc() for var in order(handlevars): out('"not_implemented",') out.dec() out(r''' "" }; enum inputOrder { ''', template) out.inc() for var in order(inputvars): out('_inIdx_%s,', var) out.dec() out(r''' NUM_INPUTS }; enum outputOrder { ''', template) out.inc() for var in order(outputvars): out('_outIdx_%s,', var) out.dec() out( r''' NUM_OUTPUTS }; int ThisModel::getHandle(const string& varName) const { for (int ii=0; ii<NUM_HANDLES; ii++) { if (varName == varNames[ii]) { return ii; } } return -1; } string ThisModel::getUnit(const int varHandle) const { assert(varHandle > 0 && varHandle < NUM_HANDLES); return varUnits[varHandle]; } vector<string> ThisModel::getVarGroup(const std::string type) const { vector<string> names; if (0) {} ''', template) out.inc() varGroups = { "input": inputvars, "output": outputvars, "checkpoint": diffvars, "flag": flagvars, "param": paramvars, } for (group, groupvars) in itemsOrderedByKey(varGroups): out(r'else if (type == "%s")' % group) out(r'{') out.inc() out(r'names.reserve(%d);', len(groupvars)) for var in order(groupvars): out(r'names.push_back("%s");', var) out.dec() out(r'}') out.dec() out( r''' return names; } double ThisModel::get(const int varHandle) const { if (0) {} ''', template) out.inc() for var in order(flagvars | paramvars): out('else if (varHandle == _handle_%s)', var) out('{') out(' return %s;', var) out('}') out.dec() out( r''' return NAN; } void ThisModel::set(const int varHandle, const double value) { if (0) {} ''', template) out.inc() for var in order(flagvars | paramvars): out('else if (varHandle == _handle_%s)', var) out('{') out(' %s = value;', var) out('}') out.dec() out( r''' assert(0 && "Can't set a value for parameter that doesn't exist"); } double ThisModel::get(const int varHandle, const int iCell) const { if (0) {} ''', template) out.inc() for var in order(diffvars): out('else if (varHandle == _handle_%s)', var) out('{') out(' return _state[_old()][iCell].%s;', var) out('}') out.dec() out( r''' return get(varHandle); } void ThisModel::set(const int varHandle, const int iCell, const double value) { if (0) {} ''', template) out.inc() for var in order(diffvars): out('else if (varHandle == _handle_%s)', var) out('{') out(' _state[_old()][iCell].%s = value;', var) out('}') out.dec() out( r''' set(varHandle, value); } double ThisModel::get(const int varHandle, const int iCell, const double* inputs[]) const { ''', template) out.inc() out('if (0) {}') for var in order(tracevars): out('else if (varHandle == _handle_%s)', var) out('{') out('}') out.dec() out( r''' return get(varHandle, iCell); } ThisModel::ThisModel(const int numPoints) { _numPoints = numPoints; _oldIdx = 0; _state[0].resize(numPoints); _state[1].resize(numPoints); //set the flags ''', template) out.inc() good = set(simvars) cprinter = CPrintVisitor(out, model.ssa, paramvars | flagvars | simvars) model.printTarget(good, flagvars, cprinter) good |= flagvars out.dec() out( r''' //set the default parameters resetDefaultParameters(); } void ThisModel::resetDefaultParameters() { ''', template) out.inc() cprinter = CPrintVisitor(out, model.ssa, paramvars | flagvars | simvars) model.printTarget(flagvars | simvars, paramvars, cprinter) good |= paramvars out.dec() out( r''' } void ThisModel::initialize(const double* const _inputs[]) { for (int _icell=0; _icell < _numPoints; _icell++) {''', template) out.inc(2) for var in order(inputvars): out("const double %s = _inputs[_inIdx_%s][_icell];", var, var) good |= inputvars cprinter = CPrintVisitor(out, model.ssa, paramvars | flagvars) model.printTarget(flagvars, diffvars, cprinter) for var in order(diffvars): out("_state[_old()][_icell].%s = %s;", var, var) good |= diffvars out.dec(2) out( r''' } } const int internalTimestep = 20; void ThisModel::tryTimestep(const double dt, const double* const _inputs[]) { for (int _icell=0; _icell < _numPoints; _icell++) {''', template) out.inc(2) for var in order(inputvars - set([stretch])): out("const double %s = _inputs[_inIdx_%s][_icell];", var, var) out("double %s = _inputs[_inIdx_%s][_icell];", stretch, stretch) good |= inputvars for var in order(partialvars): out("double %s = 0;", var) good |= partialvars for var in order(diffvars): out("double %s = _state[_old()][_icell].%s;", var, var) out("for (int itime=0; itime<internalTimestep; itime++)") out("{") out.inc() out("double %s = itime*(dt/internalTimestep);", partialStretch) good |= set([partialStretch]) cprinter = CPrintVisitor(out, model.ssa, paramvars | flagvars) model.printTarget(good, set(diffvarUpdate.values()), cprinter) for var in order(diffvars | partialvars): out("%s += %s*(dt/internalTimestep);", var, diffvarUpdate[var]) out("%s += %s*(dt/internalTimestep);", stretch, stretchVel) out.dec() out("}") for var in order(diffvars | partialvars): out("_state[_new()][_icell].%s = %s;", var, var) good |= diffvars out.dec(2) out( r''' } } void ThisModel::outputForNextTimestep(const double dt, const double* const _inputs[], double* const outputs[]) { for (int _icell=0; _icell < _numPoints; _icell++) {''', template) out.inc(2) for var in order(inputvars - set([stretch])): out("const double %s = _inputs[_inIdx_%s][_icell];", var, var) for var in order(diffvars | partialvars): out("const double %s = _state[_new()][_icell].%s;", var, var) out("const double %s = _inputs[_inIdx_%s][_icell]+dt*%s;", stretch, stretch, stretchVel) out("const double %s = dt;", partialStretch) cprinter = CPrintVisitor(out, model.ssa, paramvars | flagvars) model.printTarget(good, outputvars, cprinter) for var in order(outputvars): out("outputs[_outIdx_%s][_icell] = %s;", var, var) out.dec(2) out( r''' } } void ThisModel::commitTimestep() { swapOldAndNew(); } } ''', template)
def generateCardioid(model, targetName, arch="cpu", interp=True): template = {} template["target"] = targetName diffvars = model.diffvars() diffvarUpdate = {var: model.diffvarUpdate(var) for var in diffvars} params = model.varsWithAttribute("param") | model.varsWithAttribute("flag") markovs = model.varsWithAttribute("markov") & diffvars gates = model.varsWithAttribute("gate") & diffvars if interp: polyfits = model.varsWithAttribute("interp") else: polyfits = set() tracevars = model.varsWithAttribute("trace") nointerps = model.varsWithAttribute("nointerp") V = model.input("V") V_init = model.output("V_init") Iion = model.output("Iion") differ = Differentiator(model, diffvars | params | set([V])) gateJacobians = {} for gate in order(gates): (gateJacobians[gate], dontcare) = differ.diff(diffvarUpdate[gate], gate) markovJacobians = {var: {} for var in markovs} for imarkov in order(markovs): for jmarkov in order(markovs): (dontcare, markovJacobians[imarkov][jmarkov]) = differ.diff( diffvarUpdate[imarkov], jmarkov) differ.augmentInstructions() dt = model.addSymbol("_dt") gateTargets = {} for gate in order(gates): F = model.ssa[diffvarUpdate[gate]].sympy L = model.ssa[gateJacobians[gate]].sympy M = (F - L * gate).simplify() RLA = model.addInstruction("_%s_RLA" % gate, sympy.exp(dt * L) - 1) RLB = model.addInstruction("_%s_RLB" % gate, M / L) gateTargets[gate] = (RLA, RLB) gateInf = set() for gate in gates: RLA, RLB = gateTargets[gate] gateInf.add(RLB) markovOld = {} for markov in order(markovs): markovOld[markov] = model.addSymbol("_mi_old_%s" % markov) markovTargets = {} for imarkov in order(markovs): summation = 0 for jmarkov in order(markovs): if imarkov == jmarkov: continue if jmarkov in markovTargets: thisSym = markovTargets[jmarkov] else: thisSym = markovOld[jmarkov] summation += markovJacobians[imarkov][jmarkov].sympy * thisSym sss = (diffvarUpdate[imarkov] + dt * summation) / ( 1 - dt * markovJacobians[imarkov][imarkov].sympy) markovTargets[imarkov] = model.addInstruction("_mi_new_%s" % imarkov, sss) expensiveVars = model.extractExpensiveFunctions() model.makeNamesUnique() computeTargets = set() computeTargets.add(Iion) computeTargets |= set( [diffvarUpdate[var] for var in diffvars - gates - markovs]) for gate in gates: (RLA, RLB) = gateTargets[gate] computeTargets.add(RLA) computeTargets.add(RLB) for markov in markovs: computeTargets.add(markovTargets[markov]) approxvars = set([dt]) statevars = model.inputs() | diffvars | set(markovOld.values()) computeAllDepend = model.allDependencies(approxvars | statevars | params, computeTargets) constants = model.allExcluding(approxvars, statevars) & computeAllDepend polyfitTargets = {} allfits = set() for fit in polyfits: good = approxvars | params | set([fit]) dependsOnlyOnFit = model.allExcluding(good, (statevars - good) | nointerps) polyfitCandidates = (dependsOnlyOnFit & computeAllDepend) - constants expensiveFit = expensiveVars & polyfitCandidates inexpensiveFit = model.allExcluding(good, (statevars - good) | expensiveFit) polyfitCandidates -= inexpensiveFit externallyUsedFits = (model.allDependencies( approxvars | statevars | params | polyfitCandidates, computeTargets) & polyfitCandidates) polyfitTargets[fit] = externallyUsedFits allfits |= externallyUsedFits fitCount = 0 interps = {} def interpParams(inputString): naive_rtol = 1e-4 params = inputString.split(",") default_lb = params.pop(0) default_ub = params.pop(0) default_inc = params.pop(0) if params: default_rtol = params.pop(0) else: default_rtol = naive_rtol return (default_lb, default_ub, default_inc, default_rtol) for fit in order(polyfits): (default_lb, default_ub, default_inc, default_rtol) = interpParams(model.info("interp", fit)) for target in order(polyfitTargets[fit]): (lb, ub, inc, rtol) = (default_lb, default_ub, default_inc, default_rtol) interps[target] = (fit, fitCount, lb, ub, inc, rtol) fitCount += 1 computeAllDepend = model.allDependencies( approxvars | statevars | params | allfits, computeTargets) constants = model.allExcluding(approxvars, statevars) & computeAllDepend #FIXME! This is a kludge until I get masking working properly for simd stuff. #for now, just disable any simdops for vectorized code. vecVars = computeAllDepend - constants #Are any of these variables booleans? ifVars = set() for var in vecVars - approxvars - statevars - params: rhs = model.ssa[var] if isinstance(rhs, Choice): ifVars.add(rhs.ifVar) canUseVecops = not bool(vecVars & ifVars) out = utility.Indenter(open(targetName + ".hh", "w")) out( ''' #include "Reaction.hh" #include "Interpolation.hh" #include "object.h" #include "reactionFactory.hh" #include <vector> #include <sstream> #ifdef USE_CUDA # include "lazy_array.hh" # include <nvrtc.h> # include <cuda.h> #else //USE_CUDA''', template) out('# if %d', not canUseVecops) out( ''' # include <simdops/resetArch.hpp> # endif # include <simdops/simdops.hpp> # include "VectorDouble32.hh" #endif //USE_CUDA REACTION_FACTORY(%(target)s)(OBJECT* obj, const double dt, const int numPoints, const ThreadTeam& group); namespace %(target)s { #ifndef USE_CUDA struct State { ''', template) out.inc(2) for var in order(diffvars): out("double %s[SIMDOPS_FLOAT64V_WIDTH];", var) out.dec(2) out( r''' }; #endif //USE_CUDA class ThisReaction : public Reaction { public: ThisReaction(const int numPoints, const double __dt); std::string methodName() const; void createInterpolants(const double _dt); //void updateNonGate(double dt, const VectorDouble32&Vm, VectorDouble32&dVR); //void updateGate (double dt, const VectorDouble32&Vm) ; virtual void getCheckpointInfo(std::vector<std::string>& fieldNames, std::vector<std::string>& fieldUnits) const; virtual int getVarHandle(const std::string& varName) const; virtual void setValue(int iCell, int varHandle, double value); virtual double getValue(int iCell, int varHandle) const; virtual double getValue(int iCell, int varHandle, double V) const; virtual const std::string getUnit(const std::string& varName) const; private: unsigned nCells_; double __cachedDt; public: //PARAMETERS''', template) out.inc(2) for var in order(params): out("double %s;", var) out.dec(2) out( ''' public: void calc(double dt, ro_mgarray_ptr<int> indexArray, ro_mgarray_ptr<double> Vm_m, ro_mgarray_ptr<double> iStim_m, wo_mgarray_ptr<double> dVm_m); void initializeMembraneVoltage(ro_mgarray_ptr<int> indexArray, wo_mgarray_ptr<double> Vm); virtual ~ThisReaction(); #ifdef USE_CUDA void constructKernel(); lazy_array<double> stateTransport_; std::string _program_code; nvrtcProgram _program; std::vector<char> _ptx; CUmodule _module; CUfunction _kernel; int blockSize_; #else //USE_CUDA std::vector<State, AlignedAllocator<State> > state_; #endif ''', template) out.inc(2) out("//BGQ_HACKFIX, compiler bug with zero length arrays") out("Interpolation _interpolant[%d+1];" % fitCount) out.dec(2) out( ''' FRIEND_FACTORY(%(target)s)(OBJECT* obj, const double dt, const int numPoints, const ThreadTeam& group); }; } ''', template) out = utility.Indenter(open(targetName + ".cc", "w")) out( ''' /** How to convert this code to work for any other model: - Search/Replace the model name with your own specific string in the header and source files - Add your own code to EDIT_FLAGS and EDIT_PARAMETERS - Add your own code to EDIT_PERCELL_FLAGS and EDIT_PERCELL_PARAMETERS - Add your own states to EDIT_STATE - Add your computation code to the main calc routine, copy pasting frmo matlab. */ #include "%(target)s.hh" #include "object_cc.hh" #include "mpiUtils.h" #include <cmath> #include <cassert> #include <fstream> #include <iostream> using namespace std; #define setDefault(name, value) objectGet(obj, #name, name, TO_STRING(value)) template<typename TTT> static inline string TO_STRING(const TTT x) { stringstream ss; ss << x; return ss.str(); } static const char* interpName[] = {''', template) out.inc() fitMap = [] for fit in range(0, len(interps)): fitMap.append(0) for target in order(interps.keys()): fit, fitCount, lb, ub, inc, rtol = interps[target] fitMap[fitCount] = (target, fit, lb, ub, inc, rtol) for fitCount in range(0, len(fitMap)): (target, fit, lb, ub, inc, rtol) = fitMap[fitCount] out('"%s",', target) out.dec() out( r''' NULL }; REACTION_FACTORY(%(target)s)(OBJECT* obj, const double _dt, const int numPoints, const ThreadTeam&) { %(target)s::ThisReaction* reaction = new %(target)s::ThisReaction(numPoints, _dt); //override the defaults //EDIT_PARAMETERS''', template) out.inc(2) for var in order(params): out("double %s;", var) good = set([dt]) paramPrinter = ParamPrintVisitor(out, model.ssa, params, params) model.printTarget(good, params, paramPrinter) good |= params for var in order(params): out("reaction->%s = %s;", var, var) out.dec(2) fitDependencies = model.allDependencies(good | polyfits, allfits) & good out(r''' bool reusingInterpolants = false; string fitName; objectGet(obj, "fit", fitName, ""); int funcCount = sizeof(reaction->_interpolant)/sizeof(reaction->_interpolant[0])-1; //BGQ_HACKFIX, compiler bug with zero length arrays if (fitName != "") { OBJECT* fitObj = objectFind(fitName, "FIT");''' % template) out.inc(3) if dt in fitDependencies: out('double _fit_dt; objectGet(fitObj, "dt", _fit_dt, "nan");') for var in order(fitDependencies - set([dt])): out('double _fit_%s; objectGet(fitObj, "%s", _fit_%s, "nan");' '', var, var, var) out.dec(3) out(r''' if (1''' % template) out.inc(4) if dt in fitDependencies: out("&& _fit_dt == _dt") for var in order(fitDependencies - set([dt])): out("&& _fit_%s == reaction->%s", var, var) out.dec(4) out(r''' ) { vector<string> functions; objectGet(fitObj, "functions", functions); OBJECT* funcObj; if (functions.size() == funcCount) { for (int _ii=0; _ii<functions.size(); _ii++) { OBJECT* funcObj = objectFind(functions[_ii], "FUNCTION"); objectGet(funcObj, "numer", reaction->_interpolant[_ii].numNumer_, "-1"); objectGet(funcObj, "denom", reaction->_interpolant[_ii].numDenom_, "-1"); objectGet(funcObj, "coeff", reaction->_interpolant[_ii].coeff_); } reusingInterpolants = true; } } } if (!reusingInterpolants) { reaction->createInterpolants(_dt); //save the interpolants if (funcCount > 0 && getRank(0) == 0) { ofstream outfile((string(obj->name) +".fit.data").c_str()); outfile.precision(16); fitName = string(obj->name) + "_fit"; outfile << obj->name << " REACTION { fit=" << fitName << "; }\n"; outfile << fitName << " FIT {\n";''' % template) out.inc(4) if dt in fitDependencies: out(r'outfile << " dt = " << _dt << ";\n";') for var in order(fitDependencies - set([dt])): out(r'outfile << " %s = " << reaction->%s << ";\n";', var, var) out.dec(4) out( r''' outfile << " functions = "; for (int _ii=0; _ii<funcCount; _ii++) { outfile << obj->name << "_interpFunc" << _ii << "_" << interpName[_ii] << " "; } outfile << ";\n"; outfile << "}\n"; for (int _ii=0; _ii<funcCount; _ii++) { outfile << obj->name << "_interpFunc" << _ii << "_" << interpName[_ii] << " FUNCTION { " << "numer=" << reaction->_interpolant[_ii].numNumer_ << "; " << "denom=" << reaction->_interpolant[_ii].numDenom_ << "; " << "coeff="; for (int _jj=0; _jj<reaction->_interpolant[_ii].coeff_.size(); _jj++) { outfile << reaction->_interpolant[_ii].coeff_[_jj] << " "; } outfile << "; }\n"; } outfile.close(); } } #ifdef USE_CUDA reaction->constructKernel(); #endif return reaction; } #undef setDefault namespace %(target)s { void ThisReaction::createInterpolants(const double _dt) { ''', template) out.inc() for fitCount in range(0, len(interps)): target, fit, lb, ub, inc, rtol = fitMap[fitCount] lookup = { "target": target, "ub": ub, "lb": lb, "inc": inc, "fit": fit, "fitCount": fitCount, "rtol": rtol, "window": 0.1, } if target in gateInf: lookup["window"] = 1 out("{") out.inc() out("int _numPoints = (%(ub)s - %(lb)s)/%(inc)s;", lookup) out("vector<double> _inputs(_numPoints);") out("vector<double> _outputs(_numPoints);") out("for (int _ii=0; _ii<_numPoints; _ii++)", lookup) out("{") out.inc() out( "double %(fit)s = %(lb)s + (%(ub)s - %(lb)s)*(_ii+0.5)/_numPoints;", lookup) out("_inputs[_ii] = %(fit)s;", lookup) cprinter = CPrintVisitor(out, model.ssa, params) model.printTarget(good | set([fit]), set([target]), cprinter) out("_outputs[_ii] = %(target)s;", lookup) out.dec() out("}") out( r''' double relError = %(rtol)s; double actualTolerance = _interpolant[%(fitCount)d].create(_inputs,_outputs, relError,%(window)s); if (actualTolerance > relError && getRank(0) == 0) { cerr << "Warning: Could not meet tolerance for %(target)s: " << actualTolerance << " > " << relError << " target" << endl; }''', lookup) out.dec() out("}") out.dec() beforeCalcGood = good.copy() out( r''' } #ifdef USE_CUDA void generateInterpString(stringstream& ss, const Interpolation& interp, const char* interpVar) { ss << "{\n" " const double _numerCoeff[]={"; for (int _ii=interp.numNumer_-1; _ii>=0; _ii--) { if (_ii != interp.numNumer_-1) { ss << ", "; } ss << interp.coeff_[_ii]; } ss<< "};\n" " const double _denomCoeff[]={"; for (int _ii=interp.numDenom_+interp.numNumer_-2; _ii>=interp.numNumer_; _ii--) { ss << interp.coeff_[_ii] << ", "; } ss<< "1};\n" " double _inVal = " << interpVar << ";\n" " double _numerator=_numerCoeff[0];\n" " for (int _jj=1; _jj<sizeof(_numerCoeff)/sizeof(_numerCoeff[0]); _jj++)\n" " {\n" " _numerator = _numerCoeff[_jj] + _inVal*_numerator;\n" " }\n" " if (sizeof(_denomCoeff)/sizeof(_denomCoeff[0]) == 1)\n" " {\n" " _ratPoly = _numerator;\n" " }\n" " else\n" " {\n" " double _denominator=_denomCoeff[0];\n" " for (int _jj=1; _jj<sizeof(_denomCoeff)/sizeof(_denomCoeff[0]); _jj++)\n" " {\n" " _denominator = _denomCoeff[_jj] + _inVal*_denominator;\n" " }\n" " _ratPoly = _numerator/_denominator;\n" " }\n" "}" ; } void ThisReaction::constructKernel() { stringstream ss; ss.precision(16); ss << "enum StateOffset {\n" ''', template) out.inc() for var in order(diffvars): out(r'" %s_off,\n"', var) out.dec() out( r''' " NUMSTATES\n" "};\n" "extern \"C\"\n" "__global__ void %(target)s_kernel(const int* _indexArray, const double* _Vm, const double* _iStim, double* _dVm, double* _state) {\n" "const double _dt = " << __cachedDt << ";\n" "const int _nCells = " << nCells_ << ";\n" ''', template) out.inc(1) for var in order(params): out(r'"const double %s = " << %s << ";\n"', var, var) out.dec(1) out( r''' "const int _ii = threadIdx.x + blockIdx.x*blockDim.x;\n" "if (_ii >= _nCells) { return; }\n" "const double V = _Vm[_indexArray[_ii]];\n" "double _ratPoly;\n" ''', template) out.inc(1) for var in order(diffvars): out(r'"const double %s = _state[_ii+%s_off*_nCells];\n"', var, var) good |= diffvars good.add(V) calcCodeBuf = io.StringIO() calcOut = utility.Indenter(calcCodeBuf) iprinter = InterpolatePrintNvidiaVisitor(calcOut, model.ssa, params, interps) calcOut("//get the gate updates (diagonalized exponential integrator)") gateGoals = set() for RLA, RLB in gateTargets.values(): gateGoals.add(RLA) gateGoals.add(RLB) good.add(dt) gateSet = model.allDependencies(good | allfits, gateGoals) - good model.printSet(gateSet, iprinter) good |= gateSet calcOut("//get the other differential updates") diffGoals = set([diffvarUpdate[var] for var in diffvars - gates]) diffSet = model.allDependencies(good | allfits, diffGoals) - good model.printSet(diffSet, iprinter) good |= diffSet calcOut("//get Iion") IionSet = model.allDependencies(good | allfits, set([Iion])) - good model.printSet(IionSet, iprinter) good |= IionSet calcOut("//Do the markov update (1 step rosenbrock with gauss siedel)") for var in order(markovs): calcOut("double %s = %s;", markovTargets[var], diffvarUpdate[var]) calcOut("int _count=0;") calcOut("do") calcOut("{") calcOut.inc() iprinter.pushStack() for var in order(markovs): calcOut("double %s = %s;", markovOld[var], markovTargets[var]) markovGoals = set(markovOld.values()) good |= markovGoals iprinter.declaredStack[-1] |= set( ["%s" % var for var in markovTargets.values()]) markovSet = model.allDependencies(good | allfits, set(markovTargets.values())) - good model.printSet(markovSet, iprinter) calcOut("_count++;") iprinter.popStack() calcOut.dec() calcOut("} while (_count<50);") calcOut("//EDIT_STATE") for var in order(diffvars - gates - markovs): calcOut('_state[_ii+%s_off*_nCells] += _dt*%s;', var, diffvarUpdate[var]) for var in order(gates): (RLA, RLB) = gateTargets[var] calcOut( '_state[_ii+%(v)s_off*_nCells] += %(a)s*(%(v)s+%(b)s);', v=var, a=RLA, b=RLB, ) for var in order(markovs): calcOut("_state[_ii+%s_off*_nCells] += _dt*%s;", var, markovTargets[var]) for line in calcCodeBuf.getvalue().splitlines(): out('"' + line + r'\n"') out(r'"_dVm[_indexArray[_ii]] = -%s;\n"', Iion) out.dec() out( r''' "}\n"; _program_code = ss.str(); //cout << ss.str(); nvrtcCreateProgram(&_program, _program_code.c_str(), "%(target)s_program", 0, NULL, NULL); nvrtcCompileProgram(_program, 0, NULL); std::size_t size; nvrtcGetPTXSize(_program, &size); _ptx.resize(size); nvrtcGetPTX(_program, &_ptx[0]); cuModuleLoadDataEx(&_module, &_ptx[0], 0, 0, 0); cuModuleGetFunction(&_kernel, _module, "%(target)s_kernel"); } void ThisReaction::calc(double dt, ro_mgarray_ptr<int> indexArray_m, ro_mgarray_ptr<double> Vm_m, ro_mgarray_ptr<double> iStim_m, wo_mgarray_ptr<double> dVm_m) { if (nCells_ == 0) { return; } { int errorCode=-1; if (blockSize_ == -1) { blockSize_ = 1024; } while(1) { const int* indexArrayRaw = indexArray_m.useOn(GPU).raw(); const double* VmRaw = Vm_m.useOn(GPU).raw(); const double* iStimRaw = iStim_m.useOn(GPU).raw(); double* dVmRaw = dVm_m.useOn(GPU).raw(); double* stateRaw= stateTransport_.readwrite(GPU).raw(); void* args[] = { &indexArrayRaw, &VmRaw, &iStimRaw, &dVmRaw, &stateRaw}; int errorCode = cuLaunchKernel(_kernel, (nCells_+blockSize_-1)/blockSize_, 1, 1, blockSize_,1,1, 0, NULL, args, 0); if (errorCode == CUDA_ERROR_LAUNCH_OUT_OF_RESOURCES && blockSize_ > 0) { blockSize_ /= 2; continue; } else if (errorCode != CUDA_SUCCESS) { printf("Cuda return %%d;\n", errorCode); assert(0 && "Launch failed"); } else { break; } //cuCtxSynchronize(); } } } enum StateOffset {''', template) out.inc() for var in order(diffvars): out("_%s_off,", var) out.dec() out( ''' NUMSTATES }; ThisReaction::ThisReaction(const int numPoints, const double __dt) : nCells_(numPoints) { stateTransport_.resize(nCells_*NUMSTATES); __cachedDt = __dt; blockSize_ = -1; _program = NULL; _module = NULL; } ThisReaction::~ThisReaction() { if (_program) { nvrtcDestroyProgram(&_program); _program = NULL; } if (_module) { cuModuleUnload(_module); _module = NULL; } } #else //USE_CUDA #define width SIMDOPS_FLOAT64V_WIDTH #define real simdops::float64v #define load simdops::load ThisReaction::ThisReaction(const int numPoints, const double __dt) : nCells_(numPoints) { state_.resize((nCells_+width-1)/width); __cachedDt = __dt; } ThisReaction::~ThisReaction() {} void ThisReaction::calc(double _dt, ro_mgarray_ptr<int> ___indexArray, ro_mgarray_ptr<double> ___Vm, ro_mgarray_ptr<double> , wo_mgarray_ptr<double> ___dVm) { ro_array_ptr<int> __indexArray = ___indexArray.useOn(CPU); ro_array_ptr<double> __Vm = ___Vm.useOn(CPU); wo_array_ptr<double> __dVm = ___dVm.useOn(CPU); //define the constants''', template) out.inc() good = beforeCalcGood.copy() iprinter = InterpolatePrintCPUVisitor(out, model.ssa, params, interps, decltype="double") model.printTarget(good, computeAllDepend & constants, iprinter) good |= constants out.dec() out( ''' for (unsigned __jj=0; __jj<(nCells_+width-1)/width; __jj++) { const int __ii = __jj*width; //set Vm double __Vm_local[width]; { int cursor = 0; for (int __kk=0; __kk<width; __kk++) { __Vm_local[__kk] = __Vm[__indexArray[__ii+cursor]]; if (__ii+__kk < nCells_) { cursor++; } } } const real V = load(&__Vm_local[0]); //set all state variables''', template) out.inc(2) for var in order(diffvars): out('real %s=load(state_[__jj].%s);', var, var) good |= diffvars good.add(V) iprinter = InterpolatePrintCPUVisitor(out, model.ssa, good, interps, decltype="real") out("//get the gate updates (diagonalized exponential integrator)") gateGoals = set() for RLA, RLB in gateTargets.values(): gateGoals.add(RLA) gateGoals.add(RLB) good.add(dt) gateSet = model.allDependencies(good | allfits, gateGoals) - good model.printSet(gateSet, iprinter) good |= gateSet out("//get the other differential updates") diffGoals = set([diffvarUpdate[var] for var in diffvars - gates]) diffSet = model.allDependencies(good | allfits, diffGoals) - good model.printSet(diffSet, iprinter) good |= diffSet out("//get Iion") IionSet = model.allDependencies(good | allfits, set([Iion])) - good model.printSet(IionSet, iprinter) good |= IionSet out("//Do the markov update (1 step rosenbrock with gauss siedel)") if markovs: for var in order(markovs): out("real %s = %s;", markovTargets[var], diffvarUpdate[var]) out("int _count=0;") out("do") out("{") out.inc() iprinter.pushStack() for var in order(markovs): out("real %s = %s;", markovOld[var], markovTargets[var]) markovGoals = set(markovOld.values()) good |= markovGoals iprinter.declaredStack[-1] |= set( ["%s" % var for var in markovTargets.values()]) markovSet = model.allDependencies(good | allfits, set(markovTargets.values())) - good model.printSet(markovSet, iprinter) out("_count++;") iprinter.popStack() out.dec() out("} while (_count<50);") out("//EDIT_STATE") for var in order(diffvars - gates - markovs): out('%s += _dt*%s;', var, diffvarUpdate[var]) for var in order(gates): (RLA, RLB) = gateTargets[var] out( '%(v)s += %(a)s*(%(v)s+%(b)s);', v=var, a=RLA, b=RLB, ) for var in order(markovs): out("%s += _dt*%s;", var, markovTargets[var]) for var in order(diffvars): out("store(state_[__jj].%s, %s);", var, var) out("double __dVm_local[width];") out("simdops::store(&__dVm_local[0],-%s);", Iion) out.dec(2) out( ''' { int cursor = 0; for (int __kk=0; __kk<width && __ii+__kk<nCells_; __kk++) { __dVm[__indexArray[__ii+__kk]] = __dVm_local[__kk]; } } } } #endif //USE_CUDA string ThisReaction::methodName() const { return "%(target)s"; } void ThisReaction::initializeMembraneVoltage(ro_mgarray_ptr<int> __indexArray_m, wo_mgarray_ptr<double> __Vm_m) { assert(__Vm_m.size() >= nCells_); wo_array_ptr<double> __Vm = __Vm_m.useOn(CPU); ro_array_ptr<int> __indexArray = __indexArray_m.useOn(CPU); #ifdef USE_CUDA #define READ_STATE(state,index) (stateData[_##state##_off*nCells_+index]) wo_array_ptr<double> stateData = stateTransport_.useOn(CPU); #else //USE_CUDA #define READ_STATE(state,index) (state_[index/width].state[index %% width]) state_.resize((nCells_+width-1)/width); #endif //USE_CUDA ''', template) out.inc() cprinter = CPrintVisitor(out, model.ssa, params) good = set() good |= params target = set([V_init]) model.printTarget(good, target, cprinter) good.add(V) out("double V = V_init;") #FIXME, possibly make more general? model.printTarget(good, diffvars, cprinter) def readState(var, index): return "READ_STATE(%s,%s)" % (var, index) def writeState(statevar, value, index): return "%s = %s;" % (readState(statevar, index), value) out(r'for (int iCell=0; iCell<nCells_; iCell++)') out('{') out.inc() for var in order(diffvars): out(writeState(var, var, "iCell")) out.dec(2) out( ''' __Vm[__indexArray[iCell]] = V_init; } } enum varHandles {''', template) out.inc() for var in order(diffvars) + order(tracevars - diffvars): out('%s_handle,', var) out.dec() out( ''' NUMHANDLES }; const string ThisReaction::getUnit(const std::string& varName) const { if(0) {}''', template) out.inc() for var in order(diffvars | tracevars): varUnit = model.ssa[var].astUnit if varUnit.isNull(): unitText = "INVALID" else: unitText = str(varUnit.rawUnit) out('else if (varName == "%s") { return "%s"; }', var, unitText) out.dec() out( ''' return "INVALID"; } int ThisReaction::getVarHandle(const std::string& varName) const { if (0) {}''', template) out.inc() for var in order(diffvars | tracevars): out('else if (varName == "%s") { return %s_handle; }', var, var) out.dec() out( ''' return -1; } void ThisReaction::setValue(int iCell, int varHandle, double value) { #ifdef USE_CUDA auto stateData = stateTransport_.readwrite(CPU); #endif //USE_CUDA ''', template) out.inc() out("if (0) {}") for var in order(diffvars): out('else if (varHandle == %s_handle) { %s }', var, writeState(var, "value", "iCell")) out.dec() out( ''' } double ThisReaction::getValue(int iCell, int varHandle) const { #ifdef USE_CUDA auto stateData = stateTransport_.readonly(CPU); #endif //USE_CUDA ''', template) out.inc() out("if (0) {}") for var in order(diffvars): out('else if (varHandle == %s_handle) { return %s; }', var, readState(var, "iCell")) out.dec() out( ''' return NAN; } double ThisReaction::getValue(int iCell, int varHandle, double V) const { #ifdef USE_CUDA auto stateData = stateTransport_.readonly(CPU); #endif //USE_CUDA ''', template) out.inc() for var in order(diffvars): out('const double %s=%s;', var, readState(var, "iCell")) out('if (0) {}') for var in order(diffvars | tracevars): out('else if (varHandle == %s_handle)', var) out('{') out.inc() good = diffvars | set([V]) | params cprinter = CPrintVisitor(out, model.ssa, good) model.printTarget(good, set([var]) - params, cprinter) out('return %s;', var) out.dec() out('}') out.dec() out( ''' return NAN; } void ThisReaction::getCheckpointInfo(vector<string>& fieldNames, vector<string>& fieldUnits) const { fieldNames.clear(); fieldUnits.clear();''', template) out.inc() for var in order(diffvars): out('fieldNames.push_back("%s");', var) out('fieldUnits.push_back(getUnit("%s"));', var) out.dec() out(''' } }''', template)
def generateCoin(model, targetName): template = {'target': targetName} givenvars = model.inputs() targetvars = model.varsWithAttribute("target") diffvars = model.diffvars() unknownvars = model.varsWithAttribute("unknown") constraintvars = model.varsWithAttribute("constraint") markovs = model.varsWithAttribute("markov") & diffvars gates = model.varsWithAttribute("gate") & diffvars diffvarUpdate = {var: model.diffvarUpdate(var) for var in diffvars} lowerVals = { var: model.info("lb", var) for var in model.varsWithAttribute("lb") } upperVals = { var: model.info("ub", var) for var in model.varsWithAttribute("ub") } good = set() if model.time: good.add(time) differ = Differentiator(model, good | givenvars) gateJacobians = {} for gate in order(gates): (dontcare, gateJacobians[gate]) = differ.diff(diffvarUpdate[gate], gate) markovJacobians = {var: {} for var in markovs} for imarkov in order(markovs): for jmarkov in order(markovs): (dontcare, markovJacobians[imarkov][jmarkov]) = differ.diff( diffvarUpdate[imarkov], jmarkov) differ.augmentInstructions() dt = model.addSymbol("_dt") gateTargets = {} for gate in order(gates): F = model.ssa[diffvarUpdate[gate]].sympy L = gateJacobians[gate].sympy M = (F - L * gate).simplify() RLA = model.addInstruction("_%s_RLA" % gate, sympy.exp(dt * L)) RLB = model.addInstruction("_%s_RLB" % gate, M / L * (RLA - 1)) gateTargets[gate] = (RLA, RLB) markovOld = {} for markov in order(markovs): markovOld[markov] = model.addSymbol("_mi_old_%s" % markov) markovTargets = {} for imarkov in order(markovs): summation = 0 for jmarkov in order(markovs): if imarkov == jmarkov: continue if jmarkov in markovTargets: thisSym = markovTargets[jmarkov] else: thisSym = markovOld[jmarkov] summation += markovJacobians[imarkov][jmarkov].sympy * thisSym sss = (diffvarUpdate[imarkov] + dt * summation) / ( 1 - dt * markovJacobians[imarkov][imarkov].sympy) markovTargets[imarkov] = model.addInstruction("_mi_new_%s" % imarkov, sss) out = utility.Indenter(open(targetName + ".hpp", "w")) cprinter = CPrintVisitor(out, model.ssa, set()) out( ''' #ifndef __%(target)s_HPP__ #define __%(target)s_HPP__ #include <vector> #include <functional> #include "IpTNLP.hpp" namespace %(target)s { class ThisTNLP : public Ipopt::TNLP { public: double _dtRequested; double _time_lb; double _time_ub;''', template) out.inc() for var in order(givenvars) + order(targetvars): out('std::function<double(const double)> _func_%s;', var) out.dec() out( r''' /** default constructor */ ThisTNLP(){} /** default destructor */ virtual ~ThisTNLP(){} virtual bool get_nlp_info(Ipopt::Index& n, Ipopt::Index& m, Ipopt::Index& nnz_jac_g, Ipopt::Index& nnz_h_lag, Ipopt::TNLP::IndexStyleEnum& index_style); virtual bool get_bounds_info(Ipopt::Index n, Ipopt::Number* x_l, Ipopt::Number* x_u, Ipopt::Index m, Ipopt::Number* g_l, Ipopt::Number* g_u); virtual bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number* x, bool init_z, Ipopt::Number* z_L, Ipopt::Number* z_U, Ipopt::Index m, bool init_lambda, Ipopt::Number* lambda); virtual bool eval_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Number& obj_value); virtual bool eval_grad_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Number* grad_f){return false;} virtual bool eval_g(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Index m, Ipopt::Number* g){return false;} /** Method to return: * 1) The structure of the jacobian (if "values" is NULL) * 2) The values of the jacobian (if "values" is not NULL) */ virtual bool eval_jac_g(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index* iRow, Ipopt::Index *jCol, Ipopt::Number* values){return false;} /** Method to return: * 1) The structure of the hessian of the lagrangian (if "values" is NULL) * 2) The values of the hessian of the lagrangian (if "values" is not NULL) */ virtual bool eval_h(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Number obj_factor, Ipopt::Index m, const Ipopt::Number* lambda, bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index* iRow, Ipopt::Index* jCol, Ipopt::Number* values){return false;} virtual void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n, const Ipopt::Number* x, const Ipopt::Number* z_L, const Ipopt::Number* z_U, Ipopt::Index m, const Ipopt::Number* g, const Ipopt::Number* lambda, Ipopt::Number obj_value, const Ipopt::IpoptData* ip_data, Ipopt::IpoptCalculatedQuantities* ip_cq){} }; void getRequirements(std::vector<std::string>&); int getHandle(const std::string&); Ipopt::TNLP* factory(const std::vector<std::function<double(const double)> >& functions, const double time_lb, const double time_ub, const double dt); } #endif''', template) out = utility.Indenter(open(targetName + ".cpp", "w")) cprinter = CPrintVisitor(out, model.ssa, set()) out( r''' #include "%(target)s.hpp" #include <cassert> #include <cmath> using namespace Ipopt; using namespace std; namespace %(target)s { enum ReqEnum { ''', template) out.inc() for var in order(givenvars) + order(targetvars): out('_req_%s,', var) out.dec() out( r''' NUMREQS }; void getRequirements(vector<string>& reqs) { reqs.clear();''', template) out.inc() for var in order(givenvars) + order(targetvars): out('reqs.push_back("%s");', var) out.dec() out(r''' } int getHandle(const string& inname) { if (0) {}''', template) out.inc() for var in order(givenvars) + order(targetvars): out('else if (inname == "%s") { return _req_%s; }', var, var) out.dec() out( r''' return -1; } Ipopt::TNLP* factory(const vector<function<double(const double)> >& functions, const double time_lb, const double time_ub, const double dt) { assert(functions.size() == NUMREQS); ThisTNLP* thisTNLP = new ThisTNLP();''', template) out.inc() for var in order(givenvars) + order(targetvars): out('thisTNLP->_func_%s = functions[_req_%s];', var, var) out.dec() out( r''' thisTNLP->_dtRequested = dt; thisTNLP->_time_lb = time_lb; thisTNLP->_time_ub = time_ub; return thisTNLP; } enum UnkEnum {''', template) out.inc() for var in order(unknownvars): out('_unknown_%s,', var) out.dec() out(r''' NUMUNKNOWN }; enum ConstraintEnum {''', template) out.inc() for var in order(constraintvars): out('_constraint_%s,', var) out.dec() out( r''' NUMCONSTRAINT }; bool ThisTNLP::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g, Index& nnz_h_lag, IndexStyleEnum& index_style) { n = NUMUNKNOWN; m = NUMCONSTRAINT; nnz_jac_g = n*m; nnz_h_lag = n*n; index_style = FORTRAN_STYLE; return true; } bool ThisTNLP::get_bounds_info(Index n, Number* x_l, Number* x_u, Index m, Number* g_l, Number* g_u) {''', template) out.inc() for var in order(unknownvars): #lb = lowerVals.get(var,'-nlp_lower_bound_inf') #ub = upperVals.get(var,'nlp_upper_bound_inf') lb = lowerVals.get(var, '-1e35') ub = upperVals.get(var, '1e35') out("x_l[_unknown_%s] = %s;", var, lb) out("x_u[_unknown_%s] = %s;", var, ub) for var in order(constraintvars): lb = lowerVals.get(var, '-1e35') ub = upperVals.get(var, '1e35') out("g_l[_constraint_%s] = %s;", var, lb) out("g_u[_constraint_%s] = %s;", var, ub) out.dec() out( r''' return true; } bool ThisTNLP::get_starting_point(Index , bool _init_x, Number* _x, bool _init_z, Number* _z_L, Number* _z_U, Index , bool _init_lambda, Number* _lambda) { double _time = _time_lb; if (_init_x) { ''', template) out.inc(2) for var in order(givenvars): out('double %s = _func_%s(_time);', var, var) model.printTarget(givenvars, unknownvars, cprinter) for var in order(unknownvars): out('_x[_unknown_%s ] = %s;', var, var) out.dec(2) out( r''' } if (_init_z) { assert(0 && "No idea what to put for z bounds."); } if (_init_lambda) { assert(0 && "No idea how to initialize lambda."); } return true; } bool ThisTNLP::eval_f(Index, const Number* _x, bool _new_x, Number& _obj_value) { int _tsCount = round((_time_ub-_time_lb)/_dtRequested); double _dt = (_time_ub-_time_lb)/_tsCount; _obj_value = 0; ''', template) out.inc() for var in order(unknownvars): out('double %s = _x[_unknown_%s];', var, var) model.printTarget(unknownvars, diffvars, cprinter) out.dec() out( r''' for (int _ii=0; _ii<_tsCount; _ii++) { double _time = _time_lb+_ii*_dt;''', template) out.inc(2) for var in order(givenvars): out('double %s = _func_%s(_time);', var, var) out("//get the targets") good |= unknownvars | givenvars | diffvars targetSet = model.allDependencies(good, targetvars) - good model.printSet(targetSet, cprinter) good |= targetSet out("//get the gate updates (diagonalized exponential integrator)") gateGoals = set() for RLA, RLB in gateTargets.values(): gateGoals.add(RLA) gateGoals.add(RLB) good.add(dt) gateSet = model.allDependencies(good, gateGoals) - good model.printSet(gateSet, cprinter) good |= gateSet out("//get the other differential updates") diffGoals = set([diffvarUpdate[var] for var in diffvars - gates]) diffSet = model.allDependencies(good, diffGoals) - good model.printSet(diffSet, cprinter) good |= diffSet out("//Do the markov update (1 step rosenbrock with gauss siedel)") for var in order(markovs): out("double %s = %s;", markovTargets[var], diffvarUpdate[var]) out("int _count=0;") out("double _error;") out("do") out("{") out.inc() cprinter.pushStack() for var in order(markovs): out("double %s = %s;", markovOld[var], markovTargets[var]) markovGoals = set(markovOld.values()) good |= markovGoals cprinter.declaredStack[-1] |= set( ["%s" % var for var in markovTargets.values()]) markovSet = model.allDependencies(good, set(markovTargets.values())) model.printSet(markovSet, cprinter) out("_error = 0;") for var in order(markovs): old = markovOld[var] new = markovTargets[var] out("_error += (%s-%s)*(%s-%s);", old, new, old, new) out("_count++;") cprinter.popStack() out.dec() out("} while (_error > 1e-100 && _count<50);") for var in order(diffvars - gates - markovs): out("%s += _dt*%s;", var, diffvarUpdate[var]) for var in order(gates): RLA, RLB = gateTargets(var) out("%s = %s*%s + %s;", var, RLA, var, RLB) for var in order(markovs): out("%s += _dt*%s;", var, markovTargets[var]) for var in order(targetvars): out("double _residual_%s = %s - _func_%s(_time);", var, var, var) out("_obj_value += _dt*_residual_%s*_residual_%s;", var, var) out.dec(2) out(r''' } return true; } } // namespace HergCoinStandalone ''' % template)
def generateCarp(model, targetName): si = model.si unitFromExternalName = { "Vm": si.get("mV"), "Lambda": si.get("1"), "delLambda": si.get("1") / si.get("ms"), "Tension": si.get("kPa"), "K_e": si.get("mM"), "Na_e": si.get("mM"), "Ca_e": si.get("uM"), "Iion": si.get("uA") / si.get("uF"), "tension_component": si.get("1"), "K_i": si.get("mM"), "Na_i": si.get("mM"), "Ca_i": si.get("uM"), "Ca_b": si.get("uM"), "CaRel": si.get("uM"), "CaUp": si.get("uM"), "ATP": si.get("mM"), "ADP": si.get("uM"), } publicNames = set([ "Vm", "Lambda", "delLambda", "Tension", "K_e", "Na_e", "Ca_e", "Iion", "tension_component", ]) privateNames = set([ "K_i", "Na_i", "Ca_i", "Ca_b", "CaRel", "CaUp", "ATP", "ADP", ]) template = {} template["target"] = targetName template["uppercaseModel"] = targetName.upper() template["timeFactor"] = "1" #FIXME reqvars = None # anything with a req modvars = None # anything with a mod statevars = None # anything with a s-> paramvars = None # anything with a p-> flagvars = None # anything that can be used as a flag nodevars = None diffvars = None simvars = None interpvars = None # interp vars. interpTargets = None fevars = None tracevars = None ## Vars for printing externalNameFromVar = {} for var in model.varsWithAttribute("external"): externalName = model.info("external", var) if not externalName: externalName = str(var) externalNameFromVar[var] = externalName diffvars = model.diffvars() exvars = set(externalNameFromVar.keys()) reqvars = exvars & set(model.inputs()) modvars = exvars & set(model.ssa.keys()) paramvars = model.varsWithAttribute("param") flagvars = model.varsWithAttribute("flag") nodevars = model.varsWithAttribute("nodal") tracevars = model.varsWithAttribute("trace") statevars = (diffvars | nodevars) - exvars fevars = set(diffvars) simvars = set() dt = model.addSymbol("_dt") if model.time: simvars.add(model.time) simvars.add(dt) diffvarUpdate = {var: model.diffvarUpdate(var) for var in diffvars} V = model.input("V") V_init = model.output("V_init") Iion = model.output("Iion") modvars.add(Iion) externalNameFromVar.setdefault(Iion, "Iion") reqvars.add(V) externalNameFromVar.setdefault(V, "Vm") rushvars = model.varsWithAttribute("gate") & diffvars differ = Differentiator(model, diffvars | paramvars | reqvars | modvars) rushJacobians = {} for rush in order(rushvars): (rushJacobians[rush], dontcare) = differ.diff(diffvarUpdate[rush], rush) differ.augmentInstructions() rushTargets = {} for rush in order(rushvars): F = model.ssa[diffvarUpdate[rush]].sympy L = model.ssa[rushJacobians[rush]].sympy M = (F - L * rush).simplify() RLA = model.addInstruction("_%s_RLA" % rush, sympy.exp(dt * L)) RLB = model.addInstruction("_%s_RLB" % rush, M / L * (RLA - 1)) rushTargets[rush] = model.addInstruction("_%s_update" % rush, rush * RLA + RLB) fevars -= rushvars expensiveVars = model.extractExpensiveFunctions() model.makeNamesUnique() computeTargets = set() computeTargets.add(Iion) computeTargets |= set([diffvarUpdate[var] for var in diffvars - rushvars]) for gate in rushvars: computeTargets.add(rushTargets[gate]) approxvars = set([dt]) computeAllDepend = model.allDependencies(approxvars | statevars | reqvars, computeTargets) constants = model.allExcluding(approxvars, statevars | reqvars) & computeAllDepend interpvars = model.varsWithAttribute("interp") interpTargets = {} allinterps = set() for fit in interpvars: good = approxvars | set([fit]) dependsOnlyOnFitvar = model.allExcluding(good, (statevars | reqvars) - good) interpCandidates = (dependsOnlyOnFitvar & computeAllDepend) - constants expensiveInterps = expensiveVars & interpCandidates inexpensiveInterps = model.allExcluding( good, ((statevars | reqvars) - good) | expensiveInterps) interpCandidates -= inexpensiveInterps externallyUsedInterps = (model.allDependencies( approxvars | statevars | reqvars | interpCandidates, computeTargets) & interpCandidates) interpTargets[fit] = externallyUsedInterps allinterps |= externallyUsedInterps computeAllDepend = model.allDependencies( approxvars | statevars | reqvars | allinterps, computeTargets) constants = model.allExcluding(approxvars, statevars | reqvars) & computeAllDepend out = utility.Indenter(open(targetName + ".h", "w"), " ") cprinter = CPrintVisitor(out, model.ssa, set()) out( ''' //// HEADER GUARD /////////////////////////// // If automatically generated, keep above // comment as first line in file. #ifndef __%(uppercaseModel)s_H__ #define __%(uppercaseModel)s_H__ //// HEADER GUARD /////////////////////////// // DO NOT EDIT THIS SOURCE CODE FILE // ANY CHANGES TO THIS FILE WILL BE OVERWRITTEN!!!! // If you need to make a change, do what you have to do and send Rob // an email with what you had to change and why. He'll fix the translator // so your fix will be recorded the next time the translator runs. ''', template) out('#define %(target)s_REQDAT 0|%(req)s', target=targetName, req="|".join( ["%s_DATA_FLAG" % externalNameFromVar[var] for var in reqvars])) out('#define %(target)s_MODDAT 0|%(mod)s', target=targetName, mod="|".join( ["%s_DATA_FLAG" % externalNameFromVar[var] for var in modvars])) out(''' typedef struct %(target)s_params { ''', template) out.inc() for var in order(paramvars): out("GlobalData_t %s;", var) out.dec() out(''' char* flags; } %(target)s_Params;''', template) out('static char* %(target)s_flags = "%(flags)s";', target=targetName, flags="|".join([str(var) for var in flagvars])) out(''' typedef struct %(target)s_state {''', template) out.inc() for var in order(statevars): out("GlobalData_t %s;", var) out.dec() out( ''' } %(target)s_state; #ifdef __CUDACC__ extern "C" { #endif void initialize_params_%(target)s(ION_IF *); void construct_tables_%(target)s(ION_IF *); void destroy_%(target)s(ION_IF *); void initialize_sv_%(target)s(ION_IF *, GlobalData_t**); GLOBAL void compute_%(target)s(int, int, ION_IF *, GlobalData_t**); #ifdef __CUDACC__ }; #endif //// HEADER GUARD /////////////////////////// #endif //// HEADER GUARD /////////////////////////// ''', template) out = utility.Indenter(open(targetName + ".c", "w"), " ") out( ''' // DO NOT EDIT THIS SOURCE CODE FILE // ANY CHANGES TO THIS FILE WILL BE OVERWRITTEN!!!! // If you need to make a change, do what you have to do and send Rob // an email with what you had to change and why. He'll fix the translator // so your fix will be recorded the next time the translator runs. #include "ION_IF.h" #include "NumComp.h" #include "%(target)s.h" #ifdef __CUDACC__ #define pow powf #define log logf #endif void trace_%(target)s(ION_IF* IF, int node, FILE* file, GlobalData_t** impdata); void destroy_%(target)s( ION_IF *IF ) { destroy_luts( IF ); SV_free( &IF->sv_tab ); // rarely need to do anything else } void initialize_params_%(target)s( ION_IF *IF ) { cell_geom *region = &IF->cgeom; %(target)s_Params *p = (%(target)s_Params *)IF->params; ''', template) out.inc() good = set() out("//Compute the paramaters") cprinter = CPrintVisitor(out, model.ssa, set()) model.printTarget(good, paramvars, cprinter) for var in order(paramvars): out("p->%s = %s;", var, var) out.dec() out( ''' //p->Bufc = 0.2; //p->cell_type = EPI; //if (0) ; //else if (flag_set(p->flags, "EPI")) p->cell_type = EPI; //else if (flag_set(p->flags, "MCELL")) p->cell_type = MCELL; //else if (flag_set(p->flags, "ENDO")) p->cell_type = ENDO; IF->type->trace = trace_%(target)s; } // Define the parameters for the lookup tables enum Tables { ''', template) out.inc() for var in order(interpvars): out("_%s_TAB,", var) out.dec() out(''' N_TABS }; // Define the indices into the lookup tables. ''', template) for var in order(interpvars): out("enum %s_TableIndex {" % var) out.inc() for target in order(interpTargets[var]): out("%s_idx,", target) out("NROWS_%s", var) out.dec() out("};") out( ''' void construct_tables_%(target)s( ION_IF *IF ) { GlobalData_t _dt = IF->dt*%(timeFactor)s; cell_geom *region = &IF->cgeom; %(target)s_Params *p = (%(target)s_Params *)IF->params; IF->numLUT = N_TABS; IF->tables = (LUT *)IMP_malloc( N_TABS, sizeof(LUT) );''', template) printParamConst(out, paramvars - nodevars) good = set() good |= paramvars - nodevars good.add(dt) out(''' ''', template) for var in order(interpvars): (lb, ub, inc) = model.info("interp", var).split(",") out( ''' // Create the %(var)s lookup table LUT* %(var)s_tab = &IF->tables[_%(var)s_TAB]; { double epsilon=fabs(%(lb)s)*1e-7; LUT_alloc(%(var)s_tab, NROWS_%(var)s, %(lb)s+epsilon, %(ub)s+epsilon, %(inc)s, "%(target)s %(var)s"); } for (int __i=%(var)s_tab->mn_ind; __i<=%(var)s_tab->mx_ind; __i++) { double %(var)s = %(var)s_tab->res*__i; LUT_data_t* %(var)s_row = %(var)s_tab->tab[__i]; ''', target=targetName, var=var, lb=lb, ub=ub, inc=inc, ) out.inc(2) cprinter = CPrintVisitor(out, model.ssa, set()) model.printTarget(good | set([var]), interpTargets[var], cprinter) for target in order(interpTargets[var]): out('%(var)s_row[%(target)s_idx] = %(target)s;', var=var, target=target) out.dec() out('}') out('check_LUT(%(var)s_tab);', var=var) out.dec() out( ''' } void initialize_sv_%(target)s( ION_IF *IF, GlobalData_t **impdata ) { GlobalData_t _dt = IF->dt*%(timeFactor)s; cell_geom *region = &IF->cgeom; %(target)s_Params *p = (%(target)s_Params *)IF->params; SV_alloc( &IF->sv_tab, IF->numNode, sizeof(%(target)s_state) ); %(target)s_state *sv_base = (%(target)s_state *)IF->sv_tab.y; GlobalData_t t = 0;''', template) printParamConst(out, paramvars - nodevars) good = set() good |= paramvars - nodevars good.add(dt) out(''' //Prepare all the public arrays.''', template) out.inc() for var in order(reqvars | modvars): out("GlobalData_t* %s_ext = impdata[%s];", var, externalNameFromVar[var]) out.dec() out( ''' //Prepare all the private functions. //set the initial values for(int __i=0; __i<IF->sv_tab.numSeg; __i++ ){ %(target)s_state *sv = sv_base+__i;''', template) out.inc(2) out("//Get the definition of nodal vars") for var in order(paramvars & nodevars): out("GlobalData_t %s = p->%s;", var, var) good |= paramvars & nodevars out("//Read in the input vars") for var in order(reqvars - set([V])): out("GlobalData_t %s = %s_ext[__i];", var, var) good |= reqvars - set([V]) out("//Define voltage") valid = paramvars | (reqvars - set([V])) cprinter = CPrintVisitor(out, model.ssa, set()) model.printTarget(valid, set([V_init]), cprinter) out("double %s = %s;", V, V_init) good |= set([V]) out("//Define statevars and modvars") valid |= set([V]) model.printTarget(valid, (statevars | modvars) - valid, cprinter) out("//Save all the state variables") for var in order(statevars): out("sv->%s = %s;", var, var) out("//Save all external vars") for var in order(modvars): out("%s_ext[__i] = %s;", var, var) out("//Save voltage") out("%s_ext[__i] = %s;", V, V) out.dec(2) out( ''' //Change the units of external variables as appropriate. //sv->Ca_i *= 1e-3; } } /** compute the current * * param start index of first node * param end index of last node * param IF IMP * param plgdata external data needed by IMP */ GLOBAL void compute_%(target)s(int start, int end, ION_IF *IF, GlobalData_t **impdata ) { GlobalData_t _dt = IF->dt*%(timeFactor)s; cell_geom *region = &IF->cgeom; %(target)s_Params *p = (%(target)s_Params *)IF->params; %(target)s_state *sv_base = (%(target)s_state *)IF->sv_tab.y; GlobalData_t t = IF->tstp.cnt*_dt; ''', template) printParamConst(out, paramvars - nodevars) good = set() good |= paramvars - nodevars good.add(dt) out(''' //Prepare all the public arrays.''', template) out.inc() for var in order(reqvars | modvars): out("GlobalData_t* %s_ext = impdata[%s];", var, externalNameFromVar[var]) out.dec() out( ''' #ifdef __CUDACC__ int __i = blockDim.x * blockIdx.x + threadIdx.x; if ( __i>=end ) { return; } { #else #pragma omp parallel for schedule(static) for (int __i=start; __i<end; __i++) { #endif %(target)s_state *sv = sv_base+__i; ''', template) out.inc(2) out("//Read in the input vars") for var in order(reqvars): out("GlobalData_t %s = %s_ext[__i];", var, var) good |= reqvars out("//Get the definition of statevars") for var in order(statevars): out("GlobalData_t %s = sv->%s;", var, var) good |= statevars out('//Change the units of external variables as appropriate.') out('//sv->Ca_i *= 1e-3;') cprinter = LookupPrintVisitor(out, model.ssa, set(), interpTargets) out('//Compute lookup tables for things that have already been defined.') for var in order(good & set(interpTargets.keys())): cprinter.printLookup(var) out('//Compute external modvars') justDefined = model.allDependencies(good | allinterps, modvars - diffvars) - good model.printSet(justDefined, cprinter) good |= justDefined out('//Complete Forward Euler Update', template) justDefined = model.allDependencies( good | allinterps, set([diffvarUpdate[var] for var in fevars])) - good model.printSet(justDefined, cprinter) good |= justDefined out('//Complete Rush Larsen Update', template) justDefined = model.allDependencies(good | allinterps, set(rushTargets.values())) - good model.printSet(justDefined, cprinter) good |= justDefined out('//Finish the update', template) for var in order(fevars): out("%s += %s*_dt;", stateName(var, statevars), diffvarUpdate[var]) for var in order(rushvars): out("%s = %s;", stateName(var, statevars), rushTargets[var]) out('//Change the units of external variables as appropriate.', template) out('//sv->Ca_i *= 1e3;', template) for var in order(modvars): out("%s_ext[__i] = %s;", var, var) out.dec(2) out( ''' } } void trace_%(target)s(ION_IF* IF, int node, FILE* file, GlobalData_t** impdata) { static bool first = true; if (first) { first = false; FILE_SPEC theader = f_open("%(target)s_trace_header.txt","wt"); f_printf( theader, ''', template) out.inc(2) for var in order(tracevars): out('"%s\\n"', var) out.dec(2) out( ''' ); f_close(theader); } CUDA_TRACE( %(target)s, IF, node, file ) #ifdef HAVE_CUDA_LIMPET #define fprintf(A,F, ...) printf( F, __VA_ARGS__ ) #endif GlobalData_t _dt = IF->dt*%(timeFactor)s; cell_geom *region = &IF->cgeom; %(target)s_Params *p = (%(target)s_Params *)IF->params; %(target)s_state *sv_base = (%(target)s_state *)IF->sv_tab.y; %(target)s_state *sv = sv_base+node; int __i = node; GlobalData_t t = IF->tstp.cnt*_dt; ''', template) out.inc() printParamConst(out, paramvars - nodevars) good = set() good |= paramvars - nodevars good.add(dt) out('//Prepare all the public arrays.', template) for var in order(reqvars | modvars): out("GlobalData_t* %s_ext = impdata[%s];", var, externalNameFromVar[var]) out("//Read in the input vars") for var in order(reqvars): out("GlobalData_t %s = %s_ext[__i];", var, var) good |= reqvars out("//Get the definition of statevars") for var in order(statevars): out("GlobalData_t %s = sv->%s;", var, var) good |= statevars out('//Change the units of external variables as appropriate.') out('//sv->Ca_i *= 1e-3;') cprinter = CPrintVisitor(out, model.ssa, set()) model.printTarget(good, tracevars - good, cprinter) out('//Output the desired variables') for var in order(tracevars): out('fprintf(file, "%%4.12f\\t", %s);', var) out.dec() out( ''' //Change the units of external variables as appropriate. //sv->Ca_i *= 1e3; #ifdef HAVE_CUDA_LIMPET #undef fprintf #endif }''', template)
def printParamConst(out, thesevars): out.inc() for var in order(thesevars): out("GlobalData_t %s = p->%s;", var, var) out.dec()
def generateCeleris(model, targetName): template = {} template["target"] = targetName diffvars = model.diffvars() diffvarUpdate = {var: model.diffvarUpdate(var) for var in diffvars} llambda = model.input("lambda") actTime = model.input("actTime") if "stretchVel" not in model._inputs: stretchVel = model.addSymbol("_stretchVel") else: stretchVel = model.input("stretchVel") tension = model.output("tension") inputs = set([llambda, actTime, stretchVel]) ############ partialFromDiff = {} diffPartialFromDiff = {} differ = Differentiator(model, set([actTime, stretchVel])) partialvars = set() for diffvar in diffvars: partial = model.addSymbol("_partial_" + str(diffvar)) differ.cacheResult(diffvar, stretchVel, partial, None) partialFromDiff[diffvar] = partial partialLambda = model.addSymbol("_partial_lambda") differ.cacheResult(llambda, stretchVel, partialLambda, None) for diffvar in diffvars: (diffvarUpdate[partialFromDiff[diffvar]], dontcare) = differ.diff(diffvarUpdate[diffvar], stretchVel) (dtension_dstretchVel, dontcare) = differ.diff(tension, stretchVel) differ.augmentInstructions() ############### partialvars = set(partialFromDiff.values() + [partialLambda]) good = inputs | diffvars | partialvars indexFromVar = {} numRhsVars = 0 for var in order(diffvars): numRhsVars += 1 indexFromVar[var] = numRhsVars for var in order(good - diffvars): numRhsVars += 1 indexFromVar[var] = numRhsVars diffTargets = set() diffTargets |= set(diffvarUpdate.values()) tensionTargets = set() tensionTargets |= set([tension]) tensionTargets |= set([dtension_dstretchVel]) fprinter = FPrintVisitor(model.ssa) out = utility.Indenter(open(targetName + ".f", "w")) out( ''' SUBROUTINE %(target)sRHS (M_NEQ, M_T, M_SV, M_DSV) ! Declare inputs and outputs REAL (KRSIM) :: M_T, M_SV(*), M_DSV(*) ''', template) out(''' ! Declare the local variables ''', template) good = inputs | diffvars | partialvars diffDepend = model.allDependencies(good, diffTargets) | good varnames = set([pretty(var) for var in diffDepend]) code = "" for name in order(varnames): code += "REAL (KRSIM) :: %s\n" % name out(fprinter.fortranifyCode(code)) out(''' ! Set up the initial conditions from SV ''', template) code = "" for var in order(good): code += "%s = M_SV[%d];\n" % (pretty(var), indexFromVar[var]) out(fprinter.fortranifyCode(code)) out(''' ! Compute the derivatives ''', template) model.printTarget(diffvars | partialvars | inputs, diffTargets, fprinter) out(fprinter.finalize()) out(''' ! Store the derivatives ''', template) code = "" for diffvar in order(diffvars): code += "M_DSV[%d] = %s;\n" % (indexFromVar[diffvar], pretty(diffvarUpdate[diffvar])) partial = partialFromDiff[diffvar] code += "M_DSV[%d] = %s;\n" % (indexFromVar[partial], pretty(diffvarUpdate[partial])) code += "M_DSV[%d] = 1;\n" % indexFromVar[actTime] code += "M_DSV[%d] = %s;\n" % (indexFromVar[llambda], pretty(stretchVel)) code += "M_DSV[%d] = 1;\n" % indexFromVar[partialLambda] code += "M_DSV[%d] = 0;\n" % indexFromVar[stretchVel] out(fprinter.fortranifyCode(code)) template["numRhsVars"] = numRhsVars template["numDiffVars"] = len(diffvars) out( ''' RETURN END SUBROUTINE %(target)sRHS SUBROUTINE %(target)s (SV_0, PREV_LAMBDA, NEXT_LAMBDA, DT, @ PREV_ACTTIME, SV_1, TENSION, DTENSION) REAL (KRSIM), INTENT (IN) :: SV_0(%(numDiffVars)d), THIS_LAMBDA REAL (KRSIM), INTENT (OUT) :: SV_1(%(numDiffVars)d), TENSION, DTENSION REAL (KRSIM), INTENT (IN) :: PREV_LAMBDA, NEXT_LAMBDA, DT, @ PREV_ACTTIME REAL (KRSIM), INTENT (OUT) :: TENSION, DTENSION ! Declare the local variables REAL (KRSIM) :: ODEPACK_VARS(%(numRhsVars)d) ''', template) varnames = set([ pretty(var) for var in model.allDependencies(good, tensionTargets) | good ]) code = "" for name in order(varnames): code += "REAL (KRSIM) :: %s\n" % name out(fprinter.fortranifyCode(code)) out(''' ! Setup the local variables correctly ''', template) code = "" for diffvar in order(diffvars): code += "ODEPACK_VARS[%d] = SV_0[%d];\n" % (indexFromVar[diffvar], indexFromVar[diffvar]) partial = partialFromDiff[diffvar] code += "ODEPACK_VARS[%d] = 0;\n" % (indexFromVar[partial]) code += "ODEPACK_VARS[%d] = PREV_ACTIME;\n" % indexFromVar[actTime] code += "ODEPACK_VARS[%d] = PREV_LAMBDA;\n" % indexFromVar[llambda] code += "ODEPACK_VARS[%d] = 0;\n" % indexFromVar[partialLambda] code += "ODEPACK_VARS[%d] = (NEXT_LAMBDA-PREV_LAMBDA)/DT;\n" % indexFromVar[ stretchVel] out(fprinter.fortranifyCode(code)) out(''' ! Integrate the equations ''', template) out(''' ! Evaluate tension ''', template) code = "" for diffvar in order(diffvars): code += "%s = ODEPACK_VARS[%d];\n" % (pretty(diffvar), indexFromVar[diffvar]) partial = partialFromDiff[diffvar] code += "%s = ODEPACK_VARS[%d];\n" % (pretty(partial), indexFromVar[partial]) code += "%s = PREV_ACTTIME+DT;\n" % pretty(actTime) code += "%s = NEXT_LAMBDA;\n" % pretty(llambda) code += "%s = DT;\n" % pretty(partialLambda) code += "%s = (NEXT_LAMBDA-PREV_LAMBDA)/DT;\n" % pretty(stretchVel) out(fprinter.fortranifyCode(code)) model.printTarget(diffvars | partialvars | inputs, tensionTargets, fprinter) out(fprinter.finalize()) out(''' ! Set up the final outputs ''', template) code = "" for diffvar in order(diffvars): code += "SV_1[%d] = %s;\n" % (indexFromVar[diffvar], pretty(diffvar)) code += "TENSION = %s;\n" % pretty(tension) code += "DTENSION = %s/DT;\n" % pretty(dtension_dstretchVel) out(fprinter.fortranifyCode(code)) out(''' RETURN END SUBROUTINE %(target)s ''', template)