Events is one of the most complex sub-systems within avida, but because of this we have automated the process of implementing new events. Normally, when you want to add to a component of avida, you need to make changes in at least three places: the header file to declare new classes or methods, the code file to write the full definition of those methods, and a third location to activate whatever you just wrot
>process_list; } void SetTask(cTaskEntry * _task) { task = _task; } cReactionProcess * AddProcess(); cReactionRequisite * AddRequisite(); };
Each reaction must have a unique name and a unique numerical ID associated with them. In addition to those data, a reaction object also has a task that acts as its trigger, a list of other requisites that must be met for the trigger to work, and a list of processes that will occur if the reaction goes off. The cReaction object acts a a single place to store all of this information.
Resources are a little more complicated than task entries to manage and understand. An object of type cResource contains 18 pieces of data, and the associated accessors. Like all of the other individual units we have discussed, resources have a unique name and numerical id. For all resource we store the quantities associated with their inflow, outflow, and initial count (each stored as a double) as well as the geometry of that resource.
For spatial resources we need to be able to describe how a resource exists in space so we store data for:
This class describes the dynamics of a resource, not its current count (since, for example, we might want local resources where each cell would have its own count). However, every time a resource is needed, any changes in its quantity from the last time it was used can be calculated using these numbers.
The cEnvironment class is used to maintain the details of how the environments work using the classes described above and a few others. Below is an abbreviated version of this class:
class cEnvironment {
private:
// Keep libraries of resources, reactions, and tasks.
cResourceLib resource_lib;
cReactionLib reaction_lib;
cTaskLib task_lib;
cInstLib inst_lib;
cMutationRates mut_rates;
public:
cEnvironment();
cEnvironment(const cString & filename);
~cEnvironment() { ; }
bool Load(const cString & filename);
// Interaction with the organisms
bool TestOutput( cReactionResult & result,
const tBuffer<int> & inputs,
const tBuffer<int> & outputs,
const tArray<int> & task_count,
const tArray<int> & reaction_count,
const tArray<double> & resource_count ) const;
};
The private data members include all of the libraries needed to specify
the environment, plus its mutation rates. The
Load() method takes a filename (environment.cfg
by default) and will fill out all of the libraries in this environment. The
most important feature of this class is the
TestOutput() method, which takes in all sorts
of information about the current state of the organism that has just done
an output and fills out an object of type
cReactionResult with information about what
happened. It also directly returns a bool that will indicate if there have
been any changes at all. The specific information it uses to determine
the results are the inputs the organism has
taken in and the outputs it has produced --
both needed to determine what tasks have been done, and therefore what
reactions may have been triggered. That organism's previous
task_count and
resource_count are also needed to determine
if the reactions requisites have been met. And finally the
resource_count available to the organisms is
needed to determine how much of each resource can be used in the reactions.
Events is one of the most complex sub-systems within avida, but because of this we have automated the process of implementing new events. Normally, when you want to add to a component of avida, you need to make changes in at least three places: the header file to declare new classes or methods, the code file to write the full definition of those methods, and a third location to activate whatever you just wrot
>process_list; } void SetTask(cTaskEntry * _task) { task = _task; } cReactionProcess * AddProcess(); cReactionRequisite * AddRequisite(); };
Each reaction must have a unique name and a unique numerical ID associated with them. In addition to those data, a reaction object also has a task that acts as its trigger, a list of other requisites that must be met for the trigger to work, and a list of processes that will occur if the reaction goes off. The cReaction object acts a a single place to store all of this information.
Resources are a little more complicated than task entries to manage and understand. An object of type cResource contains 18 pieces of data, and the associated accessors. Like all of the other individual units we have discussed, resources have a unique name and numerical id. For all resource we store the quantities associated with their inflow, outflow, and initial count (each stored as a double) as well as the geometry of that resource.
For spatial resources we need to be able to describe how a resource exists in space so we store data for:
This class describes the dynamics of a resource, not its current count (since, for example, we might want local resources where each cell would have its own count). However, every time a resource is needed, any changes in its quantity from the last time it was used can be calculated using these numbers.
The cEnvironment class is used to maintain the details of how the environments work using the classes described above and a few others. Below is an abbreviated version of this class:
class cEnvironment {
private:
// Keep libraries of resources, reactions, and tasks.
cResourceLib resource_lib;
cReactionLib reaction_lib;
cTaskLib task_lib;
cInstLib inst_lib;
cMutationRates mut_rates;
public:
cEnvironment();
cEnvironment(const cString & filename);
~cEnvironment() { ; }
bool Load(const cString & filename);
// Interaction with the organisms
bool TestOutput( cReactionResult & result,
const tBuffer<int> & inputs,
const tBuffer<int> & outputs,
const tArray<int> & task_count,
const tArray<int> & reaction_count,
const tArray<double> & resource_count ) const;
};
The private data members include all of the libraries needed to specify
the environment, plus its mutation rates. The
Load() method takes a filename (environment.cfg
by default) and will fill out all of the libraries in this environment. The
most important feature of this class is the
TestOutput() method, which takes in all sorts
of information about the current state of the organism that has just done
an output and fills out an object of type
cReactionResult with information about what
happened. It also directly returns a bool that will indicate if there have
been any changes at all. The specific information it uses to determine
the results are the inputs the organism has
taken in and the outputs it has produced --
both needed to determine what tasks have been done, and therefore what
reactions may have been triggered. That organism's previous
task_count and
resource_count are also needed to determine
if the reactions requisites have been met. And finally the
resource_count available to the organisms is
needed to determine how much of each resource can be used in the reactions.
Events is one of the most complex sub-systems within avida, but because of this we have automated the process of implementing new events. Normally, when you want to add to a component of avida, you need to make changes in at least three places: the header file to declare new classes or methods, the code file to write the full definition of those methods, and a third location to activate whatever you just wrot
>process_list; } void SetTask(cTaskEntry * _task) { task = _task; }