Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Data Structures   File List   Namespace Members   Data Fields   Globals   Related Pages   Examples  

Continuous Class Reference
[Base]

Inherits Process, Observable< ContinuousObserver >, and TraceProducer.

Inherited by FreeFall, Oscillator, RealBounce, and RealFall.


Detailed Description

Time continuous process.

Author:
Ralf Gerstenberger

Note:
Continuous supports Observation.

Continuous supports Trace.

See also:
Process
Continuous is a base class for all user defined time continuous processes. It provides functionality of Process and introduces the possibility to define time continuous processes. A user has to implement the drivatives() function to define the time continuous state changes. The function integrate() computes the time continuous state changes.

Example:
//----------------------------------------------------------------------------
//      Copyright (C) 2002, 2003 Humboldt-Universitaet zu Berlin
//
//      This library is free software; you can redistribute it and/or
//      modify it under the terms of the GNU Lesser General Public
//      License as published by the Free Software Foundation; either
//      version 2.1 of the License, or (at your option) any later version.
//
//      This library is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//      Lesser General Public License for more details.
//
//      You should have received a copy of the GNU Lesser General Public
//      License along with this library; if not, write to the Free Software
//      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//----------------------------------------------------------------------------
#include <odemx/base/Continuous.h>
#include <cmath>

using namespace odemx;

//
// The first Continuous process is very simple. It only defines 
// a sinus/co-sinus oscillator.
//
class Oscillator : public Continuous {
public:
        //
        // The construction of a Continuous object is a little different to 
        // that of a Process object. You also have to provide the number
        // of state-variables used by your process. In case of Oscillator
        // we need two variables.
        //
        Oscillator() : Continuous(getDefaultSimulation(), "Oscillator", 2) {};

protected:
        //
        // The main-function of a continuous process is quite similar to that of
        // a discrete process. You can do everything that is possible in Process.
        // That's why a continuous can behave just like a discrete process. But
        // it can also go through phases of continuous state changes.
        //
        virtual int main() {
                //
                // Before you can start the solver, which is computing the continuous
                // state changes, you will have to initialise the state variables.
                //
                state[0]=1;
                state[1]=0;

                //
                // Than you should set some parameters for the internal solver. These
                // parameters include error sensitivity and the step length.
                //
                // The step length is set with 'setStepLength()'. The first parameter
                // sets the minimal step length, while the second defines the maximal
                // step length. The internal solver will compute new states in steps. 
                // Between every step the process holds. The actual length of the step
                // taken will depend on numerical errors, peer processes, state events,
                // and the parameters provided with 'setStepLength()'. The actual step 
                // length will not exceed your provided maximum. If the step length has
                // to be reduced because of numerical errors or state events it will not 
                // be reduced below your provided minimum.
                //
                setStepLength(0.01, 0.1);

                //
                // The error sensitivity is set with 'setErrorlimit()'. The first parameter
                // defines whether the errors should be considered relative to the value of
                // the state variables (0) or absolute (1). The second parameter
                // sets the maximum error acceptable (relative or absolute). If the actual
                // error exceeds this value the solver will try to reduce the step length.
                // If this fails, because the step length is already to small, you will get
                // a simulation error.
                //
                setErrorlimit(0, 0.1);

                //
                // Finally, the continuous phase is started with 'integrate()'. It is stopped
                // either by a time event, a state event or an interrupt from another process.
                // 
                // The time event is set by the first parameter. If it is 0 the solver will
                // run for ever. Otherwise it will run to the given absolute time. If the
                // provided time has already passed it will return at once. The return value of
                // integrate will be 0 if the time event was hit. If the process is interrupted
                // 'integrate()' returns 2.
                //
                integrate(20.0, 0);

                return 0;
        }

        //
        // Every Continuous process has to provide its specific 'derivatives()' function.
        // In this function you define how the state changes during the time. You do this
        // by setting the rate in which a state variable is changed. Although you don't have
        // to, you can include the time provided by t in your computation. But never use
        // 'getCurrentTime()' to get the time. 
        //
        virtual void derivatives (double t) {
                rate[0]=-state[1];
                rate[1]=state[0];
        }
};

//
// The FreeFall continuous process needs only one state variable. It demonstrates
// the use of parameter t in 'derivatives()'. The result is an idealistic free fall.
//
class FreeFall : public Continuous {
public:
        FreeFall() : Continuous(getDefaultSimulation(), "FreeFall", 1) {};

protected:
        virtual int main() {
                state[0]=0.0;

                setStepLength(.1,1);
                integrate(20.0, 0);

                return 0;
        }

        //
        // Again, never use getCurrentTime() to include the current time in your 
        // computation. The reason for this is, that 'derivatives()' is called multiple 
        // times for each step and these calls are not synchronised to the 
        // 'official' time in the simulation.
        //
        virtual void derivatives (double t) {
                double g=9.81;

                rate[0]=t*g;
        }
};

//
// RealFall simulates a 'real fall' which is slowed down by friction.
//
class RealFall : public Continuous {
public:
        RealFall() : Continuous(getDefaultSimulation(), "RealFall", 2) {};

protected:
        //
        // As in FreeFall we don't set the error limits. We can do so because
        // ODEMx uses default settings for error limits and step length. The
        // default for the error limits is a relative (0) error limit of 0.1 .
        //
        virtual int main() {
                state[0]=2.0;
                state[1]=0.0;

                setStepLength(.1, 1);
                integrate(20.0, 0);

                return 0;
        }

    virtual void derivatives (double t) {               
                double k=0.5;
                double g=-9.81;

                rate[0]=state[1];
                rate[1]=g - k*state[1];
        }
};

//
// RealBounce finally demonstrates the use of state events.
//
class RealBounce : public Continuous {
public:
        RealBounce() : Continuous(getDefaultSimulation(), "RealBounce", 3) {};

        //
        // 'hitGround()' is used to check a state event. The signature
        // of functions that can be used as state-event-functions is:
        //     bool(Process::*)()
        // ODEMx uses pointer to member functions if it needs a call-back.
        // The advantage is, you can use member functions with full access
        // to internal data of your classes to check state events. The
        // costs of this design decision is that you will always have to
        // cast the address of your state-event-function to the type 'Condition'.
        // 
        // A state function has to return true if a state event has occurred.
        // Remember, the computation of state changes is done in steps. Because
        // of that it is unlikely to hit a state event exactly. This has to
        // be considered when programming a state-event-function. If a state
        // event has occurred (or passed) the internal solver starts a binary
        // search to get closer to the exact event time. Finally, if it gets close
        // enough (minimum step length) the computation is stopped and 'integrate()'
        // returns 1.
        //
        bool hitGround() {
                return state[0]<=0.0;
        }

protected:
        virtual int main() {
                double g=-9.81;

                state[0]=2.0;
                state[1]=0.0;
                state[2]=g;

                setStepLength(0.01, 0.1);
                //
                // RealBounce uses the return value of 'integrate()' to control
                // the computation. Remember 'integrate()' returns 0 if a
                // time event occurred, 2 if the process was interrupted and 1
                // if a state event was detected.
                // 'integrate()' is called with the time event 20.0 and the
                // state-event-function 'hitGround()'. If the state event
                // is hit we reflect the movement 'state[1]=-(0.8*state[1])'
                // and continue until the simulation time exceeds 20.0.
                //
                while (integrate(20.0, (Condition)&RealBounce::hitGround)==1) 
                {               
                        //
                        // The ball hit the ground and is reflected.
                        //
                        if (fabs(state[1])<0.01 && state[0]<0.01) {
                                //
                                // We must stop the ball if it has lost to much energy.
                                // Otherwise we would produce an annoying loop. The
                                // state event would be hit in every step.
                                //
                                state[1]=0.0;
                                state[2]=0.0;
                        }
                        state[1]=-(0.8*state[1]);
                }

                return 0;
        }

    virtual void derivatives (double t) {               
                double k=0.5;

                rate[0]=state[1];
                rate[1]=state[2] - k*fabs(state[1]);
                rate[2]=0.0;
        }
};

int main(int argc, char* argv[]) {
        Oscillator osci;
        FreeFall free;
        RealFall real;
        RealBounce bounce;

        //
        // To follow the state changes we use the class ContuTrace. 
        // ContuTrace observes a provided continuous process and logs all
        // state changes into a text file. The file is managed by ContuTrace.
        // The name is either set in the constructor or build from the
        // name of the observed continuous process. If you run the simulation
        // you will find the 4 text files:
        //     Oscillator_trace.txt
        //     FreeFall_trace.txt
        //     RealFall_trace.txt
        //     RealBounce_trace.txt
        //
        ContuTrace tracer[] = {ContuTrace(&osci), ContuTrace(&free),
                                                   ContuTrace(&real), ContuTrace(&bounce)};

        //
        // Continuous processes are activated just like discrete processes.
        //
        osci.activate();
        free.activate();
        real.activate();
        bounce.activate();

        //
        // We can run the simulation without a time limit because all
        // our continuous processes end at 20.0 .
        //
        getDefaultSimulation()->run();

        return 0;
}

Since:
1.0


Public Member Functions

 Continuous (Simulation *s, Label l, int d, ContinuousObserver *o=0)
 Construction.

virtual ~Continuous ()
 Destruction.

virtual void interrupt ()
 Interrupt.

unsigned int getDimension () const
 Get number of state variables.

void setStepLength (double min, double max)
 Set minimum and maximum step length.

double getStepLength () const
 Get current step length.

void setErrorlimit (int n, double d)
 Set errorlimit.

void addPeer (Process *p)
 Add a partner process.

void delPeer (Process *p)
 Remove a peer.


Data Fields

std::vector< double > state
 State variables.

std::vector< double > rate
 Rate variables.

std::vector< double > error_vector
 Error vector.

double error_value
 Error.


Static Public Attributes

Trace MarkTypes
These MarkTypes are used to trace Continuous events. A TraceConsumer can use these constants to identify trace events send by Continuous.

const MarkTypeId baseMarkId = 1000
const MarkType markCreate
const MarkType markDestroy
const MarkType markAddPeer
const MarkType markRemovePeer
const MarkType markBeginIntegrate
const MarkType markEndIntegrate
const MarkType markNewValidState
const TagId baseTagId = 1000

Protected Member Functions

virtual int main ()=0
 User defined process behaviour.

virtual void derivatives (double t)=0
 User defined continuous behaviour.

int integrate (SimTime timeEvent, Condition stateEvent=0)
 Computation of time continuous state changes.

virtual double errorNorm ()
 Compute error.

int reduce ()
void binSearch ()
virtual void takeAStep (double h)
bool stopIntegrate ()

Protected Attributes

int dimension
double stepLength
double maxStepLength
double minStepLength
double time
int relative
double errorLimit
int stoped
std::vector< double > initial_state
std::vector< double > slope_1
std::vector< double > slope_2
std::vector< double > slope_3
SimTime stopTime
Condition stopCond
std::list< Process * > peers


Constructor & Destructor Documentation

Continuous Simulation s,
Label  l,
int  d,
ContinuousObserver o = 0
 

Construction.

Parameters:
s pointer to the Simulation object
l label of this object
d number of state variables used in derivatives()
o initial observer


Member Function Documentation

void interrupt  )  [virtual]
 

Interrupt.

If a Continuous process is interrupted inside integrate() the computation is not synchronised to the time of the interrupt. There might be an error depending on the step length. This can be prevented if the process that caused the interrupt is registered as a peer to the continuous process.

See also:
Process::interrupt

Reimplemented from Process.

unsigned int getDimension  )  const [inline]
 

Get number of state variables.

5getDimension() returns the number of state variables specified in the constructor. No more than the specified state variables may me used in derivatives(). The state variables are stored in the STL vector state.

void setStepLength double  min,
double  max
 

Set minimum and maximum step length.

Parameters:
min minimum step length
max maximum step length
The integrate() function computes state changes step by step. The step length used is variable depending on numerical errors, state events and registered peer processes. With setStepLength() the user can choose boundaries for the step length according to the needed accuracy.

See also:
integrate(), addPeer()

double getStepLength  )  const [inline]
 

Get current step length.

The integrate() function computes state changes step by step. The step length used is variable depending on numerical errors, state events and registered peer processes. getStepLength() returns the current step length.

See also:
integrate()

void setErrorlimit int  n,
double  d
[inline]
 

Set errorlimit.

Parameters:
n error type: 1 for relative error; 0 for absolute error
d limit
The integrate() function computes state changes step by step. The step length used does depend on the numerical error during computation. With setErrorlimit() the user can set the highest acceptable error. If the actual error is higher the step length is reduced.
The limit can be set absolute or relative. In the second case the limit is interpreted relative to the actual state values.

See also:
integrate()

void addPeer Process p  ) 
 

Add a partner process.

Parameters:
p pointer to Process object
The integrate() function computes state changes step by step. The next state value is computed in advance to the time consumption. If another process is accessing the state variables during the time consumption it receives wrong values. The step length however is variable and can be changed to synchronise computation with partner Processes. The function addPeer() is used to register partner Processes for synchronisation.

Note:
A peer must have a higher priority than its continuous partner to interact properly. To support this a continuous process reduces its priority by one inside integrate(). A peer has to ensure that its priority is at least as high as the priority of the continuous process.
See also:
integrate(), delPeer()

void delPeer Process p  ) 
 

Remove a peer.

Parameters:
p pointer to Process object
Removes a registered partner process.

See also:
addPeer()

virtual int main  )  [protected, pure virtual]
 

User defined process behaviour.

This function is implemented by the user to define the process behaviour.

See also:
Process::main()

Implements Process.

virtual void derivatives double  t  )  [protected, pure virtual]
 

User defined continuous behaviour.

Parameters:
t time
The user has to implement the function derivatives() to define the time continuous state changes. This is done indirectly by setting the rate by witch each state variable changes. The function is called by integrate() several times for each step.

Example Oscillator
The derivatives() function describes a simple sin/cos oscillator. The two rate variables depend only on the two state variables:
        virtual void derivatives (double t) {
                rate[0]=-state[1];
                rate[1]=state[0];
        }
Example FreeFall
This derivatives() function uses the provided parameter t to include the current time in the computation:
        virtual void derivatives (double t) {
                double g=9.81;

                rate[0]=t*g;
        }
Note:
If the time is required for the computation of the rates the prameter t has to be used instead of getCurrentTime().
See also:
integrate(), rate, state

int integrate SimTime  timeEvent,
Condition  stateEvent = 0
[protected]
 

Computation of time continuous state changes.

Parameters:
timeEvent time limit for integration (0 -> infinit)
stateEvent state event that stops integration (member call-back-function)
Returns:
0 if timeEvent hit; 1 if stateEvent hit; 2 if interrupted
The function integrate() computes time continuous state changes using the Runge-Kutta algorithm. The computation is stopped when the time timeEvent is reached, the state event occurred or the interrupt() function was called.
The computation is done step by step with a varying step length. The actual step length depends on computation errors, registered peers and the stop time (timeEvent). The user can set boundaries to the step length with the function setStepLength(). The default values used by integrate are 0.01 and 0.1 for minimum and maximum.
The step by step computation of time continuous processes introduces an inherent error. integrate() observes the computational errors for each state variable. The function errorNorm() is called to compute a single value from all error values. The user can use the function setErrorlimit() to specify the largest acceptable error. If the single value computed by errorNorm() exceeds the acceptable error integrate() tries to reduce the step length. This fails if the resulting step length would be smaller than the minimum step length set with setStepLength(). The default error limit is an absolute error of 0.1.
If during the computation a state event occurred, integrate() starts a binary search to find the exact time of the event. The minimum step length set by setStepLength() defines the accuracy of this search.
integrate() synchronises computation with partner processes. A process is registered as a partner with the function addPeer().

See also:
derivatives(), setStepLength(), setErrorlimit(), errorNorm(), addPeer() and state

double errorNorm  )  [protected, virtual]
 

Compute error.

Returns:
single error value
This function is called to compute a single error value from the error_vector. The default implementation returns the largest error(). A user can overwrite this function to use another error norm.

See also:
error, error_value and integrate()


Field Documentation

std::vector<double> state
 

State variables.

The state variables used during time continuous state changes are stored in this STL vector. A process which is accessing this variables directly should be registered with addPeer().

See also:
integrate(), derivatives(), addPeer()

std::vector<double> rate
 

Rate variables.

The STL vector rate is used for the computation of time continuous state changes. The state variables are not changed directly. In derivatives() the user sets the rate by witch each state variable is changed.

See also:
integrate(), derivatives()

std::vector<double> error_vector
 

Error vector.

The step by step computation of time continuous state changes introduces an inherent error. This error is computed for every state variable independently. error_vector is used to store the error values. The virtual function errorNorm() is called to compute a single error value from this vector which is stored in error_value.

See also:
integrate(), errorNorm(), error_value

double error_value
 

Error.

The step by step computation of time continuous state changes introduces an inherent error. This error is computed for every state variable independently. The function errorNorm() is used to compute a single error value from the vector of error values which is stored in error_value.

See also:
integrate(), errorNorm()


Generated on Mon Aug 11 10:36:06 2003 for ODEMx by doxygen1.3