예제 #1
0
def numberVars(diffvars):
    ret = {}
    count = 1
    for var in order(diffvars):
        ret[var] = count
        count += 1
    return ret
예제 #2
0
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)
예제 #3
0
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)
예제 #4
0
    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("}")
예제 #5
0
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)
예제 #6
0
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)
예제 #7
0
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)
예제 #8
0
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)
예제 #9
0
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)
예제 #10
0
def printParamConst(out, thesevars):
    out.inc()
    for var in order(thesevars):
        out("GlobalData_t %s = p->%s;", var, var)
    out.dec()
예제 #11
0
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)