Example #1
0
void PyRun::trigger(const Eref& e, double input)
{
    if (!runcompiled_){
        return;
    }
    if (mode_ == 1){
        return;
    }
    
    PyObject * value = PyDict_GetItemString(locals_, inputvar_.c_str());
    if (value){
        Py_DECREF(value);
    }
    value = PyFloat_FromDouble(input);
    if (!value && PyErr_Occurred()){
        PyErr_Print();
    }
    if (PyDict_SetItemString(locals_, inputvar_.c_str(), value)){
        PyErr_Print();
    }
    PyEval_EvalCode(runcompiled_, globals_, locals_);
    if (PyErr_Occurred()){
        PyErr_Print ();
    }
    value = PyDict_GetItemString(locals_, outputvar_.c_str());
    if (value){
        double output = PyFloat_AsDouble(value);
        if (PyErr_Occurred()){
            PyErr_Print ();
        } else {
            outputOut()->send(e, output);
        }
    }
}
Example #2
0
void DiffAmp::reinit(const Eref& e, ProcPtr p)
{
    // What is the right thing to do?? Should we actually do a process step??
    output_ = 0.0;
    plus_ = 0.0;
    minus_ = 0.0;
    outputOut()->send(e, output_);
}
void PulseGen::reinit(const Eref& e, ProcPtr p)
{
    trigTime_ = -1;
    prevInput_ = 0;
    output_ = baseLevel_;
    input_ = 0;    
    outputOut()->send(e, output_);
}
Example #4
0
void RC::process(const Eref& e, const ProcPtr proc )
{
    double sum_inject_prev = inject_ + msg_inject_;
    double sum_inject = inject_ + msg_inject_;
    double dVin = (sum_inject - sum_inject_prev) * resistance_;
    double Vin = sum_inject * resistance_;
    state_ = Vin + dVin - dVin / dt_tau_ +
            (state_ - Vin + dVin / dt_tau_) * exp_;
    sum_inject_prev = sum_inject;
    msg_inject_ = 0.0;
    outputOut()->send(e, state_);
}
Example #5
0
void RC::reinit(const Eref& e, const ProcPtr proc)
{

    dt_tau_ = proc->dt / (resistance_ * capacitance_);
    state_ = v0_;
    if (dt_tau_ > 1e-15){ 
        exp_ = exp(-dt_tau_);
    } else {// use approximation
        exp_ = 1 - dt_tau_;
    }
    msg_inject_ = 0.0;
    outputOut()->send(e, state_);
}
Example #6
0
void PyRun::run(const Eref&e, string statement)
{
    PyRun_SimpleString(statement.c_str());
    PyObject * value = PyDict_GetItemString(locals_, outputvar_.c_str());
    if (value){
        double output = PyFloat_AsDouble(value);
        if (PyErr_Occurred()){
            PyErr_Print ();
        } else {
            outputOut()->send(e, output);
        }
    }
}
Example #7
0
void DiffAmp::process(const Eref& e, ProcPtr p)
{
    double output = gain_ * (plus_ - minus_);
    plus_ = 0.0;
    minus_ = 0.0;
    if ( output > saturation_ ) {
	output = saturation_;
    }
    if ( output < -saturation_ ) {
	output = -saturation_;
    }
    output_ = output;
    outputOut()->send(e, output_);
}
void PIDController::reinit(const Eref& e, ProcPtr proc )
{
    if ( tau_i_ <= 0.0 ){
        tau_i_ = proc->dt;
    }
    if ( tau_d_ < 0.0 ){
        tau_d_ = proc->dt / 4;
    }
    sensed_ = 0.0;
    output_ = 0;
    error_ = 0;
    e_previous_ = error_;
    e_integral_ = 0;
    e_derivative_ = 0;
    outputOut()->send(e, output_);
}
void PIDController::process(const Eref& e,  ProcPtr proc )
{
    double dt = proc->dt;
    e_previous_ = error_;
    error_ = command_ - sensed_;
    e_integral_ += 0.5 * (error_ + e_previous_) * dt;
    e_derivative_ = (error_ - e_previous_) / dt;
    output_ = gain_ * (error_ + e_integral_ / tau_i_ + e_derivative_ * tau_d_);
    if (output_ > saturation_){
        output_ = saturation_;
        e_integral_ -= 0.5 * (error_ + e_previous_) * dt;
    } else if (output_ < -saturation_){
        output_ = -saturation_;
        e_integral_ -= 0.5 * (error_ + e_previous_) * dt;
    }
    outputOut()->send(e, output_);
}
Example #10
0
void PyRun::process(const Eref & e, ProcPtr p)
{
    // PyRun_String(runstr_.c_str(), 0, globals_, locals_);
    // PyRun_SimpleString(runstr_.c_str());
    if (!runcompiled_ || mode_ == 2){
        return;
    }
    PyEval_EvalCode(runcompiled_, globals_, locals_);
    if (PyErr_Occurred()){
        PyErr_Print ();
    }
    PyObject * value = PyDict_GetItemString(locals_, outputvar_.c_str());
    if (value){
        double output = PyFloat_AsDouble(value);
        if (PyErr_Occurred()){
            PyErr_Print ();
        } else {
            outputOut()->send(e, output);
        }
    }
}
Example #11
0
const Cinfo* DiffAmp::initCinfo()
{
    static ValueFinfo<DiffAmp, double> gain( "gain",
                                             "Gain of the amplifier. The output of the amplifier is the difference"
                                             " between the totals in plus and minus inputs multiplied by the"
                                             " gain. Defaults to 1" ,
                                             &DiffAmp::setGain,
                                             &DiffAmp::getGain);
    static ValueFinfo<DiffAmp, double > saturation( "saturation",
                                                    "Saturation is the bound on the output. If output goes beyond the +/-"
                                                    "saturation range, it is truncated to the closer of +saturation and"
                                                    " -saturation. Defaults to the maximum double precision floating point"
                                                    " number representable on the system." ,
                                                    &DiffAmp::setSaturation,
                                                    &DiffAmp::getSaturation);

    static ReadOnlyValueFinfo<DiffAmp, double> output( "outputValue",
                                               "Output of the amplifier, i.e. gain * (plus - minus)." ,
                                               &DiffAmp::getOutput);
    ///////////////////////////////////////////////////////////////
    // Dest messages
    ///////////////////////////////////////////////////////////////

    static DestFinfo gainIn( "gainIn",
                             "Destination message to control gain dynamically.",
                             new OpFunc1<DiffAmp, double> (&DiffAmp::setGain));

    static DestFinfo plusIn( "plusIn",
                      "Positive input terminal of the amplifier. All the messages connected"
                      " here are summed up to get total positive input.",
                      new OpFunc1<DiffAmp, double> (&DiffAmp::plusFunc));

    static DestFinfo minusIn( "minusIn",
                      "Negative input terminal of the amplifier. All the messages connected"
                      " here are summed up to get total positive input.",
                      new OpFunc1<DiffAmp, double> (&DiffAmp::minusFunc));
    ///////////////////////////////////////////////////////////////////
    // Shared messages
    ///////////////////////////////////////////////////////////////////
    static DestFinfo process( "process",
                              "Handles process call, updates internal time stamp.",
                              new ProcOpFunc< DiffAmp >( &DiffAmp::process ) );
    static DestFinfo reinit( "reinit",
                             "Handles reinit call.",
                             new ProcOpFunc< DiffAmp >( &DiffAmp::reinit ) );
    static Finfo* processShared[] =
            {
		&process, &reinit
            };

    static SharedFinfo proc( "proc",
                             "This is a shared message to receive Process messages "
                             "from the scheduler objects."
                             "The first entry in the shared msg is a MsgDest "
                             "for the Process operation. It has a single argument, "
                             "ProcInfo, which holds lots of information about current "
                             "time, thread, dt and so on. The second entry is a MsgDest "
                             "for the Reinit operation. It also uses ProcInfo. ",
                             processShared, sizeof( processShared ) / sizeof( Finfo* )
                             );


    static Finfo * diffAmpFinfos[] = {
        &gain,
        &saturation,
        &output,
        &gainIn,
        &plusIn,
        &minusIn,
        outputOut(),
        &proc
    };
    static string doc[] = {
        "Name", "DiffAmp",
        "Author", "Subhasis Ray, 2008, NCBS",
        "Description", "A difference amplifier. "
        "Output is the difference between the total plus inputs and the total "
        "minus inputs multiplied by gain. Gain can be set statically as a field"
        " or can be a destination message and thus dynamically determined by the"
        " output of another object. Same as GENESIS diffamp object."
    };
    static Dinfo<DiffAmp> dinfo;
    static Cinfo diffAmpCinfo(
            "DiffAmp",
            Neutral::initCinfo(),
            diffAmpFinfos,
            sizeof(diffAmpFinfos)/sizeof(Finfo*),
            &dinfo,
            doc,
            sizeof(doc)/sizeof(string)
);

    return &diffAmpCinfo;
}
void PulseGen::process(const Eref& e, ProcPtr p )
{
    double currentTime = p->currTime;
    double period = width_[0] + delay_[0];
    double phase = 0.0;
    for (unsigned int ii = 1; ii < width_.size() && (width_[ii] > 0.0 || delay_[ii] > 0.0); ++ii){
        double incr = delay_[ii] + width_[ii] - width_[ii-1];
        if  (incr > 0){
            period += incr;
        }
    }
    switch (trigMode_){
        case PulseGen::FREE_RUN:
            phase = fmod(currentTime, period);
            break;
        case PulseGen::EXT_TRIG:
            if (input_ == 0){
                if (trigTime_ < 0){
                    phase = period;                
                }else{
                    phase = currentTime - trigTime_;
                }
            } else {
                if (prevInput_ == 0){
                    trigTime_ = currentTime;
                }
                phase = currentTime - trigTime_;
            }
            prevInput_ = input_;            
            break;
        case PulseGen::EXT_GATE:
            if(input_ == 0)
            {
                phase = period;		/* output = baselevel */
            }
            else
            {				/* gate high */ 
                if(prevInput_ == 0)
                {	/* low -> high */
                    trigTime_ = currentTime;
                }
                phase = fmod(currentTime - trigTime_, period);
            }
            prevInput_ = input_;
            break;
        default:
            cerr << "ERROR: PulseGen::newProcessFunc( const Conn* , ProcInfo ) - invalid triggerMode - " << trigMode_ << endl;
    }
    if (phase >= period){ // we have crossed all pulses 
        output_ = baseLevel_;
        return;
    }
    // go through all pulse positions to check which pulse/interpulse
    // are we are in and set the output level accordingly
    for (unsigned int ii = 0; ii < width_.size(); ++ii){
        if (phase < delay_[ii]){ // we are in the baseline area - before ii-th pulse
            output_ = baseLevel_;
            break;
        } else if (phase < delay_[ii] + width_[ii]){ // we are inside th ii-th pulse
            output_ = level_[ii];
            break;
        }
        phase -= delay_[ii];
    }
    outputOut()->send(e, output_);
}
Example #13
0
const Cinfo * PyRun::initCinfo()
{
    static ValueFinfo< PyRun, string > runstring(
        "runString",
        "String to be executed at each time step.",
        &PyRun::setRunString,
        &PyRun::getRunString);

    static ValueFinfo< PyRun, string > initstring(
        "initString",
        "String to be executed at initialization (reinit).",
        &PyRun::setInitString,
        &PyRun::getInitString);
    static ValueFinfo< PyRun, string > inputvar(
        "inputVar",
        "Name of local variable in which input balue is to be stored. Default"
        " is `input_` (to avoid conflict with Python's builtin function"
        " `input`).",
        &PyRun::setInputVar,
        &PyRun::getInputVar);

    static ValueFinfo< PyRun, string > outputvar(
        "outputVar",
        "Name of local variable for storing output. Default is `output`",
        &PyRun::setOutputVar,
        &PyRun::getOutputVar);

    static ValueFinfo< PyRun, int > mode(
        "mode",
        "Flag to indicate whether runString should be executed for both trigger and process, or one of them",
        &PyRun::setMode,
        &PyRun::getMode);

    // static ValueFinfo< PyRun, PyObject* > globals(
    //     "globals",
    //     "Global environment dict",
    //     &PyRun::setGlobals,
    //     &PyRun::getGlobals);

    // static ValueFinfo< PyRun, PyObject* > locals(
    //     "locals",
    //     "Local environment dict",
    //     &PyRun::setLocals,
    //     &PyRun::getLocals);

    static DestFinfo trigger(
        "trigger",
        "Executes the current runString whenever a message arrives. It stores"
        " the incoming value in local variable named"
        " `input_`, which can be used in the"
        " `runString` (the underscore is added to avoid conflict with Python's"
        " builtin function `input`). If debug is True, it prints the input"
        " value.",
        new EpFunc1< PyRun, double >(&PyRun::trigger));
    
    static DestFinfo run(
        "run",
        "Runs a specified string. Does not modify existing run or init strings.",
        new EpFunc1< PyRun, string >(&PyRun::run));

    static DestFinfo process(
        "process",
        "Handles process call. Runs the current runString.",
        new ProcOpFunc< PyRun >(&PyRun::process));

    static DestFinfo reinit(
        "reinit",
        "Handles reinit call. Runs the current initString.",
        new ProcOpFunc< PyRun >( &PyRun::reinit ));
    
    static Finfo * processShared[] = { &process, &reinit };
    static SharedFinfo proc(
        "proc",
        "This is a shared message to receive Process messages "
        "from the scheduler objects."
        "The first entry in the shared msg is a MsgDest "
        "for the Process operation. It has a single argument, "
        "ProcInfo, which holds lots of information about current "
        "time, thread, dt and so on. The second entry is a MsgDest "
        "for the Reinit operation. It also uses ProcInfo. ",
        processShared, sizeof( processShared ) / sizeof( Finfo* ));

    static Finfo * pyRunFinfos[] = {
        &runstring,
        &initstring,
        &mode,
        &inputvar,
        &outputvar,
        &trigger,
        outputOut(),
        // &locals,
        // &globals,
        &run,
        &proc,
    };

    static string doc[] = {
        "Name", "PyRun",
        "Author", "Subhasis Ray",
        "Description", "Runs Python statements from inside MOOSE."};
    static Dinfo< PyRun > dinfo;
    static Cinfo pyRunCinfo(
        "PyRun",
        Neutral::initCinfo(),
        pyRunFinfos,
        sizeof(pyRunFinfos) / sizeof(Finfo*),
        &dinfo,
        doc,
        sizeof(doc) / sizeof(string));
    return &pyRunCinfo;
}
Example #14
0
const Cinfo* RC::initCinfo()
{
        static DestFinfo process("process",
                      "Handles process call.",
                      new ProcOpFunc<RC>(&RC::process));
        static DestFinfo reinit( "reinit",
                       "Handle reinitialization",
                       new ProcOpFunc<RC>( &RC::reinit ));
    static Finfo* processShared[] = {
		&process, &reinit
    };
    static SharedFinfo proc("proc",
                                         "This is a shared message to receive Process messages "
                                         "from the scheduler objects."
                                         "The first entry in the shared msg is a MsgDest "
                                         "for the Process operation. It has a single argument, "
                                         "ProcInfo, which holds lots of information about current "
                                         "time, thread, dt and so on. The second entry is a MsgDest "
                                         "for the Reinit operation. It also uses ProcInfo. ",
                                         processShared,
                                         sizeof( processShared ) / sizeof( Finfo* ));
        static ValueFinfo<RC, double> V0( "V0", 
                                    "Initial value of 'state'",
                                    &RC::setV0,
                                    &RC::getV0 );
        static ValueFinfo<RC, double> R( "R", 
                                    "Series resistance of the RC circuit.",
                                    &RC::setResistance,
                                    &RC::getResistance);
        static ValueFinfo<RC, double> C( "C", 
                                    "Parallel capacitance of the RC circuit.",
                                    &RC::setCapacitance,
                                    &RC::getCapacitance);
        static ReadOnlyValueFinfo<RC, double> state("state", 
                               "Output value of the RC circuit. This is the voltage across the"
                               " capacitor.",
                               &RC::getState);
        static ValueFinfo<RC, double> inject( "inject",
                        "Input value to the RC circuit.This is handled as an input current to"
                        " the circuit.",
                        &RC::setInject,
                        &RC::getInject );
        static DestFinfo injectIn( "injectIn",
                       "Receives input to the RC circuit. All incoming messages are summed up"
                       " to give the total input current." ,
                       new OpFunc1<RC, double>(&RC::setInjectMsg));
    static Finfo* rcFinfos[] = {
        &V0,
        &R,
        &C,
        &state,
        &inject,
        outputOut(),
        &injectIn,
        &proc,
    };
    static string doc[] = {
        "Name", "RC",
        "Author", "Subhasis Ray, 2008, NCBS",
        "Description", "RC circuit: a series resistance R shunted by a capacitance C." };
    static Dinfo<RC> dinfo;
    static Cinfo rcCinfo("RC",
                         Neutral::initCinfo(),
                         rcFinfos,
                         sizeof( rcFinfos ) / sizeof( Finfo* ),
                         &dinfo,
                         doc,
                         sizeof(doc)/sizeof(string)
                         );
    return &rcCinfo;
}
const Cinfo* PIDController::initCinfo()
{
       static DestFinfo process( "process",
                       "Handle process calls.",
                       new ProcOpFunc<PIDController>( &PIDController::process));
	   static DestFinfo reinit( "reinit",
                       "Reinitialize the object.",
                       new ProcOpFunc<PIDController>( &PIDController::reinit ));
    static Finfo* processShared[] = {
		&process, &reinit
    };
    
        static ValueFinfo<PIDController, double> gain( "gain",
                                                "This is the proportional gain (Kp). This tuning parameter scales the"
                                                " proportional term. Larger gain usually results in faster response, but"
                                                " too much will lead to instability and oscillation.",
                                                &PIDController::setGain,
                                                &PIDController::getGain);
        static ValueFinfo<PIDController, double> saturation("saturation",
                                              "Bound on the permissible range of output. Defaults to maximum double"
                                              " value.",
                                              &PIDController::setSaturation,
                                              &PIDController::getSaturation);
        static ValueFinfo<PIDController, double> command("command",
                                              "The command (desired) value of the sensed parameter. In control theory"
                                              " this is commonly known as setpoint(SP).",                                               
                                              &PIDController::setCommand, 
                                              &PIDController::getCommand);
        static ReadOnlyValueFinfo<PIDController, double> sensed( "sensed",
                                                       "Sensed (measured) value. This is commonly known as process variable"
                                                       "(PV) in control theory.",
                                                       &PIDController::getSensed);
        static ValueFinfo<PIDController, double> tauI( "tauI", 
                                               "The integration time constant, typically = dt. This is actually"
                                               " proportional gain divided by integral gain (Kp/Ki)). Larger Ki"
                                               " (smaller tauI) usually leads to fast elimination of steady state"
                                               " errors at the cost of larger overshoot.",
                                               &PIDController::setTauI,
                                               &PIDController::getTauI);
        static ValueFinfo<PIDController, double> tauD( "tauD",
                                               "The differentiation time constant, typically = dt / 4. This is"
                                               " derivative gain (Kd) times proportional gain (Kp). Larger Kd (tauD)"
                                               " decreases overshoot at the cost of slowing down transient response"
                                               " and may lead to instability.",
                                               &PIDController::setTauD,
                                               &PIDController::getTauD);
        static ReadOnlyValueFinfo<PIDController, double> outputValue( "outputValue", 
                                                       "Output of the PIDController. This is given by:"
                                                       "      gain * ( error + INTEGRAL[ error dt ] / tau_i   + tau_d * d(error)/dt )\n"
                                                       "Where gain = proportional gain (Kp), tau_i = integral gain (Kp/Ki) and"
                                                       " tau_d = derivative gain (Kd/Kp). In control theory this is also known"
                                                       " as the manipulated variable (MV)",
                                                       &PIDController::getOutput);                                                  
        static ReadOnlyValueFinfo<PIDController, double> error( "error", 
                                                       "The error term, which is the difference between command and sensed"
                                                       " value.",
                                                       &PIDController::getError);
        static ReadOnlyValueFinfo<PIDController, double> integral( "integral",
                                                       "The integral term. It is calculated as INTEGRAL(error dt) ="
                                                       " previous_integral + dt * (error + e_previous)/2.",
                                                       &PIDController::getEIntegral );
        static ReadOnlyValueFinfo<PIDController, double> derivative( "derivative",
                                                       "The derivative term. This is (error - e_previous)/dt.",
                                                       &PIDController::getEDerivative );
        static ReadOnlyValueFinfo<PIDController, double> e_previous( "e_previous",
                                                       "The error term for previous step.",
                                                       &PIDController::getEPrevious);
        static DestFinfo commandIn( "commandIn",
                       "Command (desired value) input. This is known as setpoint (SP) in"
                       " control theory." ,
                       new OpFunc1<PIDController, double>( &PIDController::setCommand ));
        static DestFinfo sensedIn( "sensedIn",
                       "Sensed parameter - this is the one to be tuned. This is known as"
                       " process variable (PV) in control theory. This comes from the process"
                       " we are trying to control.",
                       new OpFunc1<PIDController, double>( &PIDController::setSensed ));
        static DestFinfo gainDest( "gainDest",
                       "Destination message to control the PIDController gain dynamically.",
                       new OpFunc1<PIDController, double>(&PIDController::setGain));
        static SharedFinfo proc( "proc",
                         "This is a shared message to receive Process messages "
                         "from the scheduler objects."
                         "The first entry in the shared msg is a MsgDest "
                         "for the Process operation. It has a single argument, "
                         "ProcInfo, which holds lots of information about current "
                         "time, thread, dt and so on. The second entry is a MsgDest "
                         "for the Reinit operation. It also uses ProcInfo. ",
                         processShared, sizeof( processShared ) / sizeof( Finfo* )
                         );


    static Finfo* pidFinfos[] = {
		&gain,
		&saturation,
		&command,
		&sensed,
		&tauI,
		&tauD,
		&outputValue,
		&error,
		&integral,
		&derivative,
		&e_previous,
		outputOut(),
		&commandIn,
		&sensedIn,
		&gainDest,
		&proc
    };
    static string doc[] = {
        "Name", "PIDController",
        "Author", "Subhasis Ray",
        "Description", "PID feedback controller."
        "PID stands for Proportional-Integral-Derivative. It is used to"
        " feedback control dynamical systems. It tries to create a feedback"
        " output such that the sensed (measured) parameter is held at command"
        " value. Refer to wikipedia (http://wikipedia.org) for details on PID"
        " Controller." };
    static Dinfo<PIDController> dinfo;
    static Cinfo pidCinfo(
            "PIDController",
            Neutral::initCinfo(),
            pidFinfos,
            sizeof( pidFinfos ) / sizeof( Finfo* ),
            &dinfo,
            doc,
            sizeof(doc)/sizeof(string));
    return &pidCinfo;
}
Example #16
0
const Cinfo* Ex::initCinfo()
{
	// Value field def
	static ValueFinfo< Ex, int > n(
		"n",
		"Integer element.",
		&Ex::setN,
		&Ex::getN
	);

	static ValueFinfo< Ex, double > x(
		"x",
		"Double element.",
		&Ex::setX,
		&Ex::getX
	);

	// Lookup field def
	static LookupValueFinfo< Ex, unsigned int, double > values(
		"value",
		"Vector of values",
		&Ex::setVal,
		&Ex::getVal
	);

	// Dest field def
	static DestFinfo handleX(
		"handleX",
		"Sets value of x_",
		new OpFunc1< Ex, double >(&Ex::handleX)
	);

	static DestFinfo handleN(
		"handleN",
		"Sets value of n_",
		new OpFunc1< Ex, int >(&Ex::handleN)
	);

	static DestFinfo handleValues(
		"handleValues",
		"Handle a vector of values",
		new OpFunc2< Ex, unsigned int, double >(&Ex::setVal)
	);

	// Shared field def
	static DestFinfo process(
		"process",
		"Handles process call",
		new ProcOpFunc< Ex >(&Ex::process)
	);

	static DestFinfo reinit(
		"reinit",
		"Handles reinit call",
		new ProcOpFunc< Ex >(&Ex::reinit)
	);

	static Finfo* processShared[] = {
		&process,
		&reinit
	};

	static SharedFinfo proc(
		"proc",
		"Handles 'reinit' and 'process' calls from a clock.",
		processShared,
		sizeof(processShared) / sizeof(Finfo*)
	);

	static Finfo* exFinfos[] = {
		&n,
		&x,
		&values,
		&handleX,
		&handleN,
		&handleValues,
		outputOut(),
		&proc
	};

	static Dinfo< Ex > exDinfo;

	static string doc[] =
    {
        "Name", "Ex",
        "Author", "Viktor Toth",
        "Description", "Example Moose class.",
    };

	static Cinfo exCinfo(
		"Ex",
		Neutral::initCinfo(),
		exFinfos,
		sizeof(exFinfos) / sizeof(Finfo*),
		&exDinfo,
		doc,
		sizeof(doc) / sizeof(string)
	);

	return &exCinfo;
}
const Cinfo* PulseGen::initCinfo()
{
    ///////////////////////////////////////////////////////
    // Field definitions
    ///////////////////////////////////////////////////////
    static ReadOnlyValueFinfo< PulseGen, double > output("outputValue",
                                                 "Output amplitude",
                                                 &PulseGen::getOutput);
    static ValueFinfo< PulseGen, double > baseLevel("baseLevel",
                                                     "Basal level of the stimulus",
                                                     &PulseGen::setBaseLevel,
                                                     &PulseGen::getBaseLevel);
    static ValueFinfo< PulseGen, double > firstLevel("firstLevel",
                                                     "Amplitude of the first pulse in a sequence",
                                                     &PulseGen::setFirstLevel,
                                                     &PulseGen::getFirstLevel);
    static ValueFinfo< PulseGen, double > firstWidth("firstWidth",
                                                     "Width of the first pulse in a sequence",
                                                     &PulseGen::setFirstWidth,
                                                     &PulseGen::getFirstWidth);
    static ValueFinfo< PulseGen, double > firstDelay("firstDelay",
                                                     "Delay to start of the first pulse in a sequence",
                                                     &PulseGen::setFirstDelay,
                                                     &PulseGen::getFirstDelay); 
    static ValueFinfo< PulseGen, double > secondLevel("secondLevel",
                                                     "Amplitude of the second pulse in a sequence",
                                                     &PulseGen::setSecondLevel,
                                                     &PulseGen::getSecondLevel);
    static ValueFinfo< PulseGen, double > secondWidth("secondWidth",
                                                     "Width of the second pulse in a sequence",
                                                     &PulseGen::setSecondWidth,
                                                     &PulseGen::getSecondWidth);
    static ValueFinfo< PulseGen, double > secondDelay("secondDelay",
                                                     "Delay to start of of the second pulse in a sequence",
                                                     &PulseGen::setSecondDelay,
                                                     &PulseGen::getSecondDelay);
    static ValueFinfo< PulseGen, unsigned int > count("count",
                                                     "Number of pulses in a sequence",
                                                     &PulseGen::setCount,
                                                     &PulseGen::getCount);
    static ValueFinfo< PulseGen, unsigned int > trigMode("trigMode",
                                                         "Trigger mode for pulses in the sequence.\n"
                                                         " 0 : free-running mode where it keeps looping its output\n"
                                                         " 1 : external trigger, where it is triggered by an external input (and"
                                                         " stops after creating the first train of pulses)\n"
                                                         " 2 : external gate mode, where it keeps generating the pulses in a"
                                                         " loop as long as the input is high.",
                                                     &PulseGen::setTrigMode,
                                                     &PulseGen::getTrigMode);
    static LookupValueFinfo < PulseGen, unsigned int, double > level("level",
                                                                     "Level of the pulse at specified index",
                                                                     &PulseGen::setLevel,
                                                                     &PulseGen::getLevel);
    static LookupValueFinfo < PulseGen, unsigned int, double > width("width",
                                                                     "Width of the pulse at specified index",
                                                                     &PulseGen::setWidth,
                                                                    &PulseGen::getWidth);
    static LookupValueFinfo < PulseGen, unsigned int, double > delay("delay",
                                                                    "Delay of the pulse at specified index",
                                                                    &PulseGen::setDelay,
                                                                    &PulseGen::getDelay);
    ///////////////////////////////////////////////////////////////
    // Dest messages
    ///////////////////////////////////////////////////////////////
    static DestFinfo levelIn("levelIn",
                             "Handle level value coming from other objects",
                             new OpFunc2< PulseGen, unsigned int, double >(&PulseGen::setLevel));
    static DestFinfo widthIn("widthIn",
                             "Handle width value coming from other objects",
                             new OpFunc2< PulseGen, unsigned int, double >(&PulseGen::setWidth));
    static DestFinfo delayIn("delayIn",
                             "Handle delay value coming from other objects",
                             new OpFunc2< PulseGen, unsigned int, double >(&PulseGen::setDelay));
    
    static DestFinfo input("input",
                           "Handle incoming input that determines gating/triggering onset. "
                           "Note that although this is a double field, the underlying field is"
                           " integer. So fractional part of input will be truncated",
                           new OpFunc1< PulseGen, double >(&PulseGen::input));
    ///////////////////////////////////////////////////////////////////
    // Shared messages
    ///////////////////////////////////////////////////////////////////
    static DestFinfo process( "process",
                              "Handles process call, updates internal time stamp.",
                              new ProcOpFunc< PulseGen >( &PulseGen::process ) );
    static DestFinfo reinit( "reinit",
                             "Handles reinit call.",
                             new ProcOpFunc< PulseGen >( &PulseGen::reinit ) );
    static Finfo* processShared[] =
            {
		&process, &reinit
            };
    
    static SharedFinfo proc( "proc",
                             "This is a shared message to receive Process messages "
                             "from the scheduler objects."
                             "The first entry in the shared msg is a MsgDest "
                             "for the Process operation. It has a single argument, "
                             "ProcInfo, which holds lots of information about current "
                             "time, thread, dt and so on. The second entry is a MsgDest "
                             "for the Reinit operation. It also uses ProcInfo. ",
                             processShared, sizeof( processShared ) / sizeof( Finfo* )
                             );

    static Finfo* pulseGenFinfos[] = {
        &output,
        &baseLevel,
        &firstLevel,
        &firstWidth,
        &firstDelay,
        &secondLevel,
        &secondWidth,
        &secondDelay,
        &count,
        &trigMode,
        &level,
        &width,
        &delay,
        &input,
        outputOut(),
        &levelIn,
        &widthIn,
        &delayIn,
        &proc,
    };
    static string doc[] =
    {
        "Name", "PulseGen",
        "Author", "Subhasis Ray",
        "Description", "PulseGen: general purpose pulse generator. This can generate any "
        "number of pulses with specified level and duration.",        
    };
    static Dinfo<PulseGen> dinfo;
    static Cinfo pulseGenCinfo("PulseGen",
                               Neutral::initCinfo(),
                               pulseGenFinfos,
                               sizeof(pulseGenFinfos)/sizeof(Finfo*),
                               &dinfo,
                               doc,
                               sizeof(doc)/sizeof(string));
    return & pulseGenCinfo;    
    
}