Main Page | Namespace List | Alphabetical List | Class List | Directories | File List | Class Members | File Members

SpikeStreamSimulation.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   SpikeStream Simulation                                                *
00003  *   Copyright (C) 2007 by David Gamez                                     *
00004  *   david@davidgamez.eu                                                   *
00005  *   Version 0.1                                                           *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 
00023 //SpikeStream includes
00024 #include "SpikeStreamSimulation.h"
00025 #include "Debug.h"
00026 #include "PVMMessages.h"
00027 #include "Utilities.h"
00028 #include "SimulationTypes.h"
00029 #include "ConnectionType.h"
00030 #include "DeviceTypes.h"
00031 #include "GlobalVariables.h"
00032 
00033 //Other includes
00034 #include "mysql++.h"
00035 #include "pvm3.h"
00036 #include <cmath>
00037 #include <string>
00038 #include <iostream>
00039 using namespace std;
00040 using namespace mysqlpp;
00041 
00042 
00043 /*! Database Exception for errors connected with the database. */
00044 class DatabaseException : public exception{
00045   virtual const char* what() const throw(){
00046     return "Database error";
00047   }
00048 } databaseException;
00049 
00050 
00051 //Declare and initialize static variables
00052 int SpikeStreamSimulation::thisTaskID = 0;
00053 int SpikeStreamSimulation::parentTaskID = 0;
00054 SimulationClock* SpikeStreamSimulation::simulationClock;
00055 bool SpikeStreamSimulation::errorState = false;
00056 unsigned int SpikeStreamSimulation::neuronGrpID = 0;
00057 
00058 #ifdef RECORD_STATISTICS
00059         Statistics SpikeStreamSimulation::statistics;
00060 #endif//RECORD_STATISTICS
00061 
00062 
00063 /*! Default constructor - NOT USED. */
00064 SpikeStreamSimulation::SpikeStreamSimulation(){
00065 }
00066 
00067 
00068 /*! Main constructor.
00069         Do not return from construction during an error because we must reach
00070         the run() call so that simulation manager can cleanly shut the task down
00071         when there is an error. */
00072 SpikeStreamSimulation::SpikeStreamSimulation(int argc, char **argv){
00073         /* Initialize the random number generator using the current time in microseconds
00074                 Since each task starts at a slightly different time, this ensures that random
00075                 activity in the different layers is independent. */
00076         timeval randomTimeStruct;
00077         gettimeofday(&randomTimeStruct, NULL);
00078         srand(randomTimeStruct.tv_usec);
00079 
00080         //Create the simulation clock
00081         simulationClock = new SimulationClock();
00082 
00083         //Create the array that will be used to receive the spikes
00084         unpackArray = new unsigned int[MAX_NUMBER_OF_SPIKES];
00085 
00086         //Set up synapse hash map by setting empty and deleted keys
00087         synapseMap.set_empty_key(EMPTY_NEURON_ID_KEY);
00088         synapseMap.set_deleted_key(DELETED_NEURON_ID_KEY);
00089 
00090         //Set up neuron update map by satting empty and deleted keys
00091         neuronUpdateMap.set_empty_key(EMPTY_NEURON_ID_KEY);
00092         neuronUpdateMap.set_deleted_key(DELETED_NEURON_ID_KEY);
00093 
00094         //Set up neuron update map by satting empty and deleted keys
00095         neuronMonitorMap.set_empty_key(EMPTY_NEURON_ID_KEY);
00096         neuronMonitorMap.set_deleted_key(DELETED_NEURON_ID_KEY);
00097 
00098         //Initialise variables
00099         delayInLastTimeStep = false;
00100         calculateComputeTime = false;
00101         neuronMonitorMode = false;
00102         synapseMonitorMode = false;
00103         
00104         //Set simulationDataLoaded to false
00105         simulationDataLoaded = false;
00106 
00107         //Set simulation running to false
00108         simulationRunning = false;
00109         
00110         //Simulation started is set to true later, when initial messages are sent from all the neuron groups
00111         simulationStarted = false;
00112 
00113         //Initialise time structs used to calculate how long each time step lasts
00114         gettimeofday(&startComputeTimeStruct, NULL);
00115         gettimeofday(&endComputeTimeStruct, NULL);
00116         minTimeStepDuration_us = 0;//Runs at maximum speed by default
00117 
00118         //Initialise noise parameters
00119         noiseEnabled = false;
00120         percentNeurons_noise = 0;
00121         directFiring_noise = true;
00122         synapticWeight_noise = 0;
00123         randomPercentNoise = false;
00124 
00125         //Default update mode is event driven
00126         updateAllNeurons = false;
00127         updateAllSynapses = false;
00128 
00129         //Get task id and parent task id
00130         thisTaskID = pvm_mytid();
00131         parentTaskID = pvm_parent();
00132 
00133         /* Set up direct routing, which increases the available bandwidth.
00134                 NOTE This is not scalable to more than 60 tasks */
00135         pvm_setopt( PvmRoute, PvmRouteDirect );
00136 
00137         /* Read command line arguments. 
00138                 These include host, username and password for database and NeuronGrpID
00139                 Use options: -n [neuronGrpID] -h [hostname] -d [database] -u [username]  -p [password] 
00140                 with spaces in between to avoid strict ordering. argv[0] is the executable name, so start
00141                 from 1.*/
00142         char *neuralNetworkHost = NULL, *neuralNetworkUser = NULL, *neuralNetworkPassword = NULL, *neuralNetworkDatabase = NULL;
00143         char *patternHost = NULL, *patternUser = NULL, *patternPassword = NULL, *patternDatabase = NULL;
00144         char *deviceHost = NULL, *deviceUser = NULL, *devicePassword = NULL, *deviceDatabase = NULL;
00145         for(int i=1; i<argc; i += 2){
00146                 if(argv[i][0] == '-'){//This line contains an option
00147                         if(Utilities::cStringEquals(argv[i], "-ng", 4)){//Extract information about neuron group
00148                                 neuronGrpID = Utilities::getUInt(argv[i+1]);
00149                         }
00150                         else if(Utilities::cStringEquals(argv[i], "-nnh", 4)){//Extract neural network host information
00151                                 neuralNetworkHost = argv[i+1];
00152                         }
00153                         else if(Utilities::cStringEquals(argv[i], "-nnu", 4)) {//Extract neural network user information
00154                                 neuralNetworkUser = argv[i+1];
00155                         }
00156                         else if(Utilities::cStringEquals(argv[i], "-nnp", 4)){// Extract neural network password information
00157                                 neuralNetworkPassword = argv[i+1];
00158                         }
00159                         else if(Utilities::cStringEquals(argv[i], "-nnd", 4)){// Extract neural network database information
00160                                 neuralNetworkDatabase = argv[i+1];
00161                         }
00162                         else if(Utilities::cStringEquals(argv[i], "-ph", 4)){//Extract pattern host information
00163                                 patternHost = argv[i+1];
00164                         }
00165                         else if(Utilities::cStringEquals(argv[i], "-pu", 4)) {//Extract pattern user information
00166                                 patternUser = argv[i+1];
00167                         }
00168                         else if(Utilities::cStringEquals(argv[i], "-pp", 4)){// Extract pattern password information
00169                                 patternPassword = argv[i+1];
00170                         }
00171                         else if(Utilities::cStringEquals(argv[i], "-pd", 4)){// Extract pattern database information
00172                                 patternDatabase = argv[i+1];
00173                         }
00174                         else if(Utilities::cStringEquals(argv[i], "-dh", 4)){//Extract device host information
00175                                 deviceHost = argv[i+1];
00176                         }
00177                         else if(Utilities::cStringEquals(argv[i], "-du", 4)) {//Extract device user information
00178                                 deviceUser = argv[i+1];
00179                         }
00180                         else if(Utilities::cStringEquals(argv[i], "-dp", 4)){// Extract device password information
00181                                 devicePassword = argv[i+1];
00182                         }
00183                         else if(Utilities::cStringEquals(argv[i], "-dd", 4)){// Extract device database information
00184                                 deviceDatabase = argv[i+1];
00185                         }
00186                 }
00187                 else{
00188                         systemError("SpikeStreamSimulation: Invalid command line arguments!");
00189                 }
00190         }
00191 
00192         //Check that all parameters have been initialised
00193         if( neuralNetworkHost == NULL || neuralNetworkUser == NULL || neuralNetworkPassword == NULL || neuralNetworkDatabase == NULL || patternHost == NULL || patternUser == NULL || patternPassword == NULL || patternDatabase == NULL || deviceHost == NULL || deviceUser == NULL || devicePassword == NULL || deviceDatabase == NULL){
00194                 systemError("SpikeStreamSimulation: SOME OR ALL OF THE COMMAND LINE PARAMETERS ARE MISSING");
00195         }
00196 
00197         //Output database parameters in debug mode
00198         #ifdef COMMAND_LINE_PARAMETERS_DEBUG
00199                 cout<<"Neural network database parameters: "<<neuralNetworkHost<<", "<<neuralNetworkUser<<", "<<neuralNetworkPassword<<", "<<neuralNetworkDatabase<<endl;
00200                 cout<<"Pattern database parameters: "<<patternHost<<", "<<patternUser<<", "<<patternPassword<<", "<<patternDatabase<<endl;
00201                 cout<<"Device database parameters: "<<deviceHost<<", "<<deviceUser<<", "<<devicePassword<<", "<<deviceDatabase<<endl;
00202         #endif//COMMAND_LINE_PARAMETERS_DEBUG
00203 
00204         //Create a new neural network database interface and connect to database
00205         networkDBInterface = new DBInterface(neuralNetworkHost, neuralNetworkUser, neuralNetworkPassword, neuralNetworkDatabase);
00206         if(!networkDBInterface->connectToDatabase(true)){//Exceptions enabled
00207                 systemError("Failed to connect to the neural network database.");//This sets up the error state, so will only respond to exit message now
00208         }
00209 
00210         //Create a new pattern database interface and connect to database
00211         patternDBInterface = new DBInterface(patternHost, patternUser, patternPassword, patternDatabase);
00212         if(!patternDBInterface->connectToDatabase(true)){//Exceptions enabled
00213                 systemError("Failed to connect to the pattern database.");//This sets up the error state, so will only respond to exit message now
00214         }
00215 
00216         //Create a new device database interface and connect to database
00217         deviceDBInterface = new DBInterface(deviceHost, deviceUser, devicePassword, deviceDatabase);
00218         if(!deviceDBInterface->connectToDatabase(true)){//Exceptions enabled
00219                 systemError("Failed to connect to the device database.");//This sets up the error state, so will only respond to exit message now
00220         }
00221         
00222         //Add the task id of this task to the database to enable communication between tasks
00223         if(!errorState)
00224                 addTaskIDToDatabase();
00225 
00226         //Create new class loader to load neuron and synapse classes
00227         if(!errorState)
00228                 classLoader = new ClassLoader(networkDBInterface);
00229 
00230         /*Send confirmation message to parent, which will not check database messages until 
00231                 confirmation from all tasks has been received. */
00232         sendMessage(parentTaskID, SIMULATION_TASK_STARTED_MSG);
00233 
00234         //Give user feedback about initialization of task
00235         cout<<"Simulation task started for neuron group "<<neuronGrpID<<" with taskID "<<thisTaskID<<endl;
00236 
00237         //Start the run method for this class   
00238         stop = false;
00239         run();
00240 }
00241 
00242 
00243 /*! Destructor. */
00244 SpikeStreamSimulation::~SpikeStreamSimulation(){
00245         #ifdef MEMORY_DEBUG
00246                 cout<<"DELETING NEURON SIMULATION. TASK ID: "; printTID(thisTaskID); cout<<endl;
00247         #endif//MEMORY_DEBUG
00248 
00249         //Output statistics about the simulation run if required
00250         #ifdef RECORD_STATISTICS
00251                 cout<<"=========================== STATISTICS ==============================="<<endl;
00252                 cout<<"      Total number of neurons fired: "<<statistics.neuronFireTotal<<endl;
00253                 cout<<"      Total number of spikes: "<<statistics.spikeTotal<<endl;
00254                 cout<<"      Number of time steps: "<<(simulationClock->getTimeStep() - statistics.startTimeStep)<<endl;
00255                 cout<<"      "; statisticsTimer.printTime();
00256                 cout<<"=========================== /STATISTICS ==============================="<<endl;
00257         #endif//RECORD_STATISTICS
00258         
00259         //Delete simulation clock
00260         delete simulationClock;
00261 
00262         /* Delete device manager: in all simulation modes there will be a device manager 
00263                 to delete, which needs to be deleted before the databases are closed */
00264         delete deviceManager;
00265 
00266         //Delete pattern manager if it is a pattern simulation
00267         if(simulationType == PATTERN_SIMULATION)
00268                 delete patternManager;
00269 
00270         /* Delete database interfaces. Some of these may have been deleted
00271                 during load time to save resources, so need to check for this */
00272         if(networkDBInterface != NULL)
00273                 delete networkDBInterface;
00274         if(patternDBInterface != NULL)
00275                 delete patternDBInterface;
00276         if(deviceDBInterface != NULL)
00277                 delete deviceDBInterface;
00278 
00279         //Delete the class loader
00280         delete classLoader;
00281 
00282         //Delete neurons
00283         for(unsigned int i=0; i<numberOfNeurons; ++i)
00284                 delete neuronArray[i];
00285         delete [] neuronArray;
00286 
00287         //Delete task holders
00288         delete neuronTaskHolder;
00289         for(map<int, TaskHolder*>::iterator iter = spikeTaskHolderMap.begin(); iter != spikeTaskHolderMap.end(); ++iter)
00290                 delete iter->second;
00291 
00292         //Delete unpack array
00293         delete [] unpackArray;
00294 
00295         //Delete synapses and synapse keys
00296         for( dense_hash_map<unsigned int, dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >*, hash<unsigned int> >::iterator outerIter = synapseMap.begin(); outerIter != synapseMap.end(); ++outerIter){
00297                 for(dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >::iterator innerIter = outerIter->second->begin(); innerIter != outerIter->second->end(); ++innerIter){
00298                         //Delete Synapse
00299                         delete innerIter->second;
00300                 }
00301                 //Delete inner hash map
00302                 delete outerIter->second;
00303         }
00304         
00305         //Delete dynamically allocated maps for connection parameters
00306         for(map<unsigned int, map<string, double>* >::iterator iter = connParameterMap.begin(); iter != connParameterMap.end(); ++iter)
00307                 delete iter->second;
00308 
00309         //Inform SpikeStream Application that clean up is complete
00310         sendMessage(parentTaskID, TASK_EXITED_MSG);
00311 
00312         #ifdef MEMORY_DEBUG
00313                 cout<<">>>>>>>>>>>>>>>>>>>>>>>>>> NEURON SIMULATION FINISHED CLEANING UP <<<<<<<<<<<<<<<<<<<<<<<<<<<<<"<<endl;
00314         #endif//MEMORY_DEBUG
00315 
00316         //Flush any remaining messages before exiting
00317         cout.flush();
00318 
00319         //Exit from pvm
00320         pvm_exit();
00321 }
00322 
00323 
00324 /*! Main run method.
00325         This loops around receiving and processing messages until the simulation ends. */
00326 void SpikeStreamSimulation::run(){
00327         while(!stop){
00328                 //Blocking receive - waiting for messages from other tasks
00329                 int bufID = pvm_recv(-1, -1);
00330                 #ifdef PVM_BUFFER_DEBUG
00331                         if(bufID > 50){
00332                                 cout<<"Run method: BUFFER ID CHECK ON RECEIVE bufID = "<<bufID<<endl;
00333                         }
00334                 #endif//PVM_BUFFER_DEBUG
00335 
00336                 #ifdef PVM_DEBUG
00337                         if(bufID < 0){
00338                                 pvm_perror("SpikeStreamSimulation: MESSAGE RECEIVE ERROR");
00339                                 systemError("Message receive error");
00340                                 return;
00341                         }
00342                 #endif//PVM_DEBUG
00343 
00344                 int bytes, msgtag, senderTID, info;
00345                 info = pvm_bufinfo(bufID, &bytes, &msgtag, &senderTID);//Get info about message
00346                 #ifdef PVM_DEBUG
00347                         if(info < 0){
00348                                 pvm_perror("SpikeStreamSimulation: PROBLEM GETTING BUFFER INFO");
00349                                 systemError("Problem getting buffer info.");
00350                                 return;
00351                         }
00352                 #endif//PVM_DEBUG
00353 
00354                 if(errorState){//When there has been an error, task only responds to an exit msg
00355                         if(msgtag == EXIT_MSG){
00356                                 #ifdef MESSAGE_DEBUG
00357                                         cout<<"Task "<<thisTaskID<<": EXIT_MSG "<<bytes<<" bytes received from "<<senderTID<<endl;
00358                                 #endif//MESSAGE_DEBUG
00359                                 stop = true;//Exits the archiver from the run loop
00360                         }
00361                         else{
00362                                 systemError("Task is in error state and will no longer carry out any operations.\nTermination of the simulation is recommended.");
00363                         }
00364                 }
00365                 else{
00366                         switch(msgtag){
00367                                 case (SPIKE_LIST_MSG):
00368                                         #ifdef MESSAGE_DEBUG
00369                                                 cout<<"Task "<<thisTaskID<<": SPIKE_LIST_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00370                                         #endif//MESSAGE_DEBUG
00371                                         processSpikeList(senderTID, -1);
00372                                 break;
00373                                 case(LOAD_SIMULATION_DATA_MSG):
00374                                         #ifdef MESSAGE_DEBUG
00375                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": LOAD_NEURON_DATA_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00376                                         #endif//MESSAGE_DEBUG
00377                                         loadSimulationData();
00378                                 break;
00379                                 case(START_SIMULATION_MSG):
00380                                         #ifdef MESSAGE_DEBUG
00381                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": START_SIMULATION_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00382                                         #endif//MESSAGE_DEBUG
00383                                         startSimulation();
00384                                 break;
00385                                 case(STOP_SIMULATION_MSG):
00386                                         #ifdef MESSAGE_DEBUG
00387                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": STOP_SIMULATION_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00388                                         #endif//MESSAGE_DEBUG
00389                                         stopSimulation();
00390                                 break;
00391                                 case(STEP_SIMULATION_MSG):
00392                                         #ifdef MESSAGE_DEBUG
00393                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": STEP_SIMULATION_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00394                                         #endif//MESSAGE_DEBUG
00395                                         stepSimulation();
00396                                 break;
00397                                 case(REQUEST_SPIKE_DATA_MSG):
00398                                         #ifdef MESSAGE_DEBUG
00399                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": REQUEST_SPIKE_DATA_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00400                                         #endif//MESSAGE_DEBUG
00401                                         addReceivingTask_Spikes(senderTID);
00402                                 break;
00403                                 case(REQUEST_FIRING_NEURON_DATA_MSG):
00404                                         #ifdef MESSAGE_DEBUG
00405                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": REQUEST_FIRING_NEURON_DATA_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00406                                         #endif//MESSAGE_DEBUG
00407                                         addReceivingTask_Neurons(senderTID);
00408                                 break;
00409                                 case(CANCEL_SPIKE_DATA_MSG):
00410                                         #ifdef MESSAGE_DEBUG
00411                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": CANCEL_SPIKE_DATA_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00412                                         #endif//MESSAGE_DEBUG
00413                                         removeReceivingTask_Spikes(senderTID);
00414                                 break;
00415                                 case(CANCEL_FIRING_NEURON_DATA_MSG):
00416                                         #ifdef MESSAGE_DEBUG
00417                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": CANCEL_SPIKE_DATA_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00418                                         #endif//MESSAGE_DEBUG
00419                                         removeReceivingTask_Neurons(senderTID);
00420                                 break;
00421                                 case(INJECT_NOISE_MSG):
00422                                         #ifdef MESSAGE_DEBUG
00423                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": INJECT_NOISE_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00424                                         #endif//MESSAGE_DEBUG
00425                                         injectNoise();
00426                                 break;
00427                                 case(FIRE_SPECIFIED_NEURONS_MSG):
00428                                         #ifdef MESSAGE_DEBUG
00429                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": FIRE_SPECIFIED_NEURONS_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00430                                         #endif//MESSAGE_DEBUG
00431                                         fireSpecifiedNeurons();
00432                                 break;
00433                                 case(LOAD_NEURON_PARAMETERS_MSG):
00434                                         #ifdef MESSAGE_DEBUG
00435                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": LOAD_NEURON_PARAMETERS_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00436                                         #endif//MESSAGE_DEBUG
00437                                         loadNeuronParameters();
00438                                 break;
00439                                 case(LOAD_SYNAPSE_PARAMETERS_MSG):
00440                                         #ifdef MESSAGE_DEBUG
00441                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": LOAD_SYNAPSE_PARAMETERS_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00442                                         #endif//MESSAGE_DEBUG
00443                                         loadSynapseParameters();
00444                                 break;
00445                                 case(LOAD_GLOBAL_PARAMETERS_MSG):
00446                                         #ifdef MESSAGE_DEBUG
00447                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": LOAD_GLOBAL_PARAMETERS_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00448                                         #endif//MESSAGE_DEBUG
00449                                         loadGlobalParameters();
00450                                 break;
00451                                 case(LOAD_NOISE_PARAMETERS_MSG):
00452                                         #ifdef MESSAGE_DEBUG
00453                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": LOAD_NOISE_PARAMETERS_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00454                                         #endif//MESSAGE_DEBUG
00455                                         loadNoiseParameters();
00456                                 break;
00457                                 case (EXIT_MSG):
00458                                         #ifdef MESSAGE_DEBUG
00459                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": EXIT_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00460                                         #endif//MESSAGE_DEBUG
00461                                         stop = true;//Exit from run method and invoke the destructor
00462                                 break;
00463                                 case (SAVE_WEIGHTS_MSG):
00464                                         #ifdef MESSAGE_DEBUG
00465                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": SAVE_WEIGHTS_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00466                                         #endif//MESSAGE_DEBUG
00467                                         saveWeights();
00468                                 break;
00469                                 case (LOAD_WEIGHTS_MSG):
00470                                         #ifdef MESSAGE_DEBUG
00471                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": LOAD_WEIGHTS_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00472                                         #endif//MESSAGE_DEBUG
00473                                         reloadWeights();
00474                                 break;
00475                                 case (SAVE_VIEW_WEIGHTS_MSG):
00476                                         #ifdef MESSAGE_DEBUG
00477                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": SAVE_VIEW_WEIGHTS_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00478                                         #endif//MESSAGE_DEBUG
00479                                         saveViewWeights();
00480                                 break;
00481                                 case (SET_MIN_TIMESTEP_DURATION_US_MSG):
00482                                         #ifdef MESSAGE_DEBUG
00483                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": SET_MIN_TIMESTEP_DURATION_US_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00484                                         #endif//MESSAGE_DEBUG
00485                                         setMinTimeStepDuration(senderTID);
00486                                 break;
00487                                 case (SET_UPDATE_MODE_MSG):
00488                                         #ifdef MESSAGE_DEBUG
00489                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": SET_UPDATE_MODE_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00490                                         #endif//MESSAGE_DEBUG
00491                                         setUpdateMode(senderTID);
00492                                 break;
00493                                 case (REQUEST_MONITOR_NEURON_INFO_MSG):
00494                                         #ifdef MESSAGE_DEBUG
00495                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": REQUEST_MONITOR_NEURON_INFO_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00496                                         #endif//MESSAGE_DEBUG
00497                                         startNeuronMonitoring(senderTID, false);
00498                                 break;
00499                                 case (START_MONITORING_NEURON_MSG):
00500                                         #ifdef MESSAGE_DEBUG
00501                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": START_MONITORING_NEURON_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00502                                         #endif//MESSAGE_DEBUG
00503                                         startNeuronMonitoring(senderTID, true);
00504                                 break;
00505                                 case (STOP_MONITORING_NEURON_MSG):
00506                                         #ifdef MESSAGE_DEBUG
00507                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": STOP_MONITORING_NEURON_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00508                                         #endif//MESSAGE_DEBUG
00509                                         stopNeuronMonitoring(senderTID);
00510                                 break;
00511                                 case (REQUEST_MONITOR_SYNAPSE_INFO_MSG):
00512                                         #ifdef MESSAGE_DEBUG
00513                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": REQUEST_MONITOR_SYNAPSE_INFO_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00514                                         #endif//MESSAGE_DEBUG
00515                                         startSynapseMonitoring(senderTID, false);
00516                                 break;
00517                                 case (START_MONITORING_SYNAPSE_MSG):
00518                                         #ifdef MESSAGE_DEBUG
00519                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": START_MONITORING_SYNAPSE_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00520                                         #endif//MESSAGE_DEBUG
00521                                         startSynapseMonitoring(senderTID, true);
00522                                 break;
00523                                 case (STOP_MONITORING_SYNAPSE_MSG):
00524                                         #ifdef MESSAGE_DEBUG
00525                                                 cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": STOP_MONITORING_SYNAPSE_MSG "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00526                                         #endif//MESSAGE_DEBUG
00527                                         stopSynapseMonitoring(senderTID);
00528                                 break;
00529                                 default:
00530                                         cout<<"Task "; printTID(thisTaskID); cout<<"; NeuronGroup: "<<neuronGrpID<<": *UNRECOGNIZED MESSAGE* MSGTAG = "<<msgtag<<"; size "<<bytes<<" bytes received from "; printTID(senderTID); cout<<endl;
00531                                         systemError("UNRECOGNIZED MESSAGE RECEIVED FROM ", senderTID);
00532                                 break;
00533                         }
00534                 }
00535         }
00536         //End of run method, need to clean up and exit pvm
00537         cleanUpSimulation();
00538 }
00539 
00540 
00541 //----------------------------------------------------------------------------
00542 //--------------------------- PUBLIC METHODS ---------------------------------
00543 //----------------------------------------------------------------------------
00544 
00545 /*! Returns the ID of the neuron group that is being simulated by this task. */
00546 unsigned int SpikeStreamSimulation::getNeuronGrpID(){
00547         return neuronGrpID;
00548 }
00549 
00550 /*! Writes an error message to the standard output and sends a message 
00551         to the parent task with the error message. */
00552 void SpikeStreamSimulation::systemError(const char *message){
00553         errorState = true;//Put the program into error state when it stops operating and waits for exit message.
00554         cerr<<"SpikeStreamSimulation "; printTID(); cerr<<": "<<message<<endl;
00555         sendMessage(parentTaskID, ERROR_MSG, message);
00556 }
00557 
00558 
00559 /*! Writes an error message to the standard output and sends a message 
00560         to the parent task with the error message. */
00561 void SpikeStreamSimulation::systemError(const char *message, int messageData1){
00562         errorState = true;//Put the program into error state when it stops operating and waits for exit message.
00563         ostringstream tempStr;
00564         tempStr<<message<<messageData1;
00565         cerr<<"SpikeStreamSimulation "; printTID(); cerr<<": "<<message<<messageData1<<endl;
00566         sendMessage(parentTaskID, ERROR_MSG, tempStr.str().data());
00567 }
00568 
00569 
00570 /*! Writes an error message to the standard output and sends a message 
00571         to the parent task with the error message. */
00572 void SpikeStreamSimulation::systemError(const string &message){
00573         errorState = true;//Put the program into error state when it stops operating and waits for exit message.
00574         cerr<<"SpikeStreamSimulation "; printTID(); cerr<<": "<<message<<endl;
00575         sendMessage(parentTaskID, ERROR_MSG, message.data());
00576 }
00577 
00578 
00579 /*! Writes an error message to the standard output and sends a message 
00580         to the parent task with the error message. */
00581 void SpikeStreamSimulation::systemError_double(const string &message, double messageData1){
00582         errorState = true;//Put the program into error state when it stops operating and waits for exit message.
00583         cerr<<"SpikeStreamSimulation "; printTID(); cerr<<": "<<message<<" "<<messageData1<<endl;
00584         ostringstream tempStr;
00585         tempStr<<message<<" "<<messageData1;
00586         sendMessage(parentTaskID, ERROR_MSG, tempStr.str().data());
00587 }
00588 
00589 
00590 /*! Writes an error message to the standard output and sends a message 
00591         to the parent task with the error message. */
00592 void SpikeStreamSimulation::systemError_int(const string &message, int messageData1){
00593         errorState = true;//Put the program into error state when it stops operating and waits for exit message.
00594         cerr<<"SpikeStreamSimulation "; printTID(); cerr<<": "<<message<<" "<<messageData1<<endl;
00595         ostringstream tempStr;
00596         tempStr<<message<<" "<<messageData1;
00597         sendMessage(parentTaskID, ERROR_MSG, tempStr.str().data());
00598 }
00599 
00600 
00601 /*! Writes an information message to the standard output and sends a 
00602         message to the parent task with the message. */
00603 void SpikeStreamSimulation::systemInfo(const char *message){
00604         cout<<message<<endl;
00605         sendMessage(parentTaskID, INFORMATION_MSG, message);
00606 }
00607 
00608 
00609 /*! Writes an information message to the standard output and sends a 
00610         message to the parent task with the message. */
00611 void SpikeStreamSimulation::systemInfo(const char *message, bool messageData1){
00612         ostringstream tempStr;
00613         tempStr<<message<<messageData1;
00614         cout<<tempStr.str()<<endl;
00615         sendMessage(parentTaskID, INFORMATION_MSG, tempStr.str().data());
00616 }
00617 
00618 
00619 /*! Writes an information message to the standard output and sends a 
00620         message to the parent task with the message. */
00621 void SpikeStreamSimulation::systemInfo(const char *message, int messageData1){
00622         ostringstream tempStr;
00623         tempStr<<message<<messageData1;
00624         cout<<tempStr.str()<<endl;
00625         sendMessage(parentTaskID, INFORMATION_MSG, tempStr.str().data());
00626 }
00627 
00628 
00629 //--------------------------------------------------------------------------
00630 //------------------------- PRIVATE METHODS --------------------------------
00631 //--------------------------------------------------------------------------
00632 
00633 /*! Adds a task that will receive the firing neuron data from this task. */
00634 void SpikeStreamSimulation::addReceivingTask_Neurons(int newTask){
00635         neuronTaskHolder->addReceivingTask(newTask);
00636 }
00637 
00638 
00639 /*! Adding a task to receive spikes is easy because it is just treated as another neuron group
00640         and sent all the spikes from this neuron group at each time step. */
00641 void SpikeStreamSimulation::addReceivingTask_Spikes(int newTask){
00642         //Work through the task holders and add task to them
00643         for(map<int, TaskHolder*>::iterator iter = spikeTaskHolderMap.begin(); iter != spikeTaskHolderMap.end(); ++iter)
00644                 iter->second->addReceivingTask(newTask);
00645 }
00646 
00647 
00648 /*! Inserts this task id into database. */
00649 void SpikeStreamSimulation::addTaskIDToDatabase(){
00650         try{
00651                 Query query = networkDBInterface->getQuery();
00652                 query.reset();
00653                 query<<"UPDATE NeuronGroups SET TaskID = "<<thisTaskID<<" WHERE NeuronGrpID = "<<neuronGrpID;
00654                 ResNSel updateResult = query.execute();
00655 
00656                 //Check that a single row has been updated
00657                 if(!updateResult.success){
00658                         systemError("SpikeStreamSimulation: FAILURE TO UPDATE DATABASE WITH TASK ID FOR NEURON GROUP ", neuronGrpID);
00659                 }
00660         }
00661         catch (const BadQuery& er) {// Handle any query errors
00662                 ostringstream errorStrStream;
00663                 errorStrStream<<"Bad query when adding task ID to database: \""<<er.what()<<"\"";
00664                 systemError(errorStrStream.str());
00665         }
00666         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00667                 ostringstream errorStrStream;
00668                 errorStrStream<<"Exception thrown adding task ID to database: \""<<er.what()<<"\"";
00669                 systemError(errorStrStream.str());
00670         }
00671 }
00672 
00673 
00674 /*! Cleans up after the simulation. */
00675 void SpikeStreamSimulation::cleanUpSimulation(){
00676         cout<<"Cleaning up simulation"<<endl;
00677         deviceManager->closeDevice();//Close device
00678 }
00679 
00680 
00681 /*! Fires noiseAmount percentage of neurons directly by calling fireNeuron() on the neuron class. */
00682 void SpikeStreamSimulation::fireRandomNeurons(double noiseAmount){
00683         #ifdef NOISE_DEBUG
00684                 int numNeuronsFired = 0;
00685         #endif//NOISE_DEBUG
00686 
00687         //Calculate threshold to be applied to random number to decide if neuron fires or not
00688         int threshold = (int)rint(((double)RAND_MAX * (noiseAmount / 100.0)));
00689 
00690         //Work through neuron array firing neurons at random
00691         for(unsigned int i=0; i<numberOfNeurons; ++i){
00692                 if(rand() < threshold){
00693                         neuronArray[i]->fireNeuron();
00694                         #ifdef NOISE_DEBUG
00695                                 ++numNeuronsFired;
00696                         #endif//NOISE_DEBUG
00697                 }
00698         }
00699         #ifdef NOISE_DEBUG
00700                 cout<<"SpikeStreamSimulation: Inject noise: noiseAmount = "<<noiseAmount<<"; number of neurons fired = "<<numNeuronsFired<<endl;
00701         #endif//NOISE_DEBUG
00702 }
00703 
00704 
00705 /*! Calls changeMembranePotential on noiseAmount percentage of neurons in this
00706         layer. This simulates a noisy input to the neuron group. */
00707 void SpikeStreamSimulation::fireRandomNeurons_synaptic(double noiseAmount){
00708         #ifdef NOISE_DEBUG
00709                 int numNeuronsChanged = 0;
00710         #endif//NOISE_DEBUG
00711 
00712         //Get a threshold that will be used to subsample the percentage of neurons
00713         int threshold = (int)rint(((double)RAND_MAX * (noiseAmount / 100.0)));
00714 
00715         //Work through neuron array changing the membrane potential of neurons at random
00716         for(unsigned int i=0; i<numberOfNeurons; ++i){
00717                 if(rand() < threshold){
00718                         neuronArray[i]->changePostSynapticPotential(synapticWeight_noise, 0);
00719                         neuronUpdateMap[ i + startNeuronID ] = true;
00720 
00721                         #ifdef NOISE_DEBUG
00722                                 ++numNeuronsChanged;
00723                         #endif//NOISE_DEBUG
00724                 }
00725         }
00726         #ifdef NOISE_DEBUG
00727                 cout<<"SpikeStreamSimulation: Fire random neurons (synaptic): noiseAmount = "<<noiseAmount<<"; number of neurons with membrane potential adjustment = "<<numNeuronsChanged<<endl;
00728         #endif//NOISE_DEBUG
00729 }
00730 
00731 
00732 /*! Fires the specified neurons. Usually called in respose to a FIRE_NEURON_MSG for debugging
00733         purposes. */
00734 void SpikeStreamSimulation::fireSpecifiedNeurons(){
00735         int numberOfFiringNeurons;
00736         
00737         //Unpack number of neurons to be fired
00738         int info = pvm_upkint(&numberOfFiringNeurons, 1, 1);
00739         #ifdef PVM_DEBUG
00740                 if(info < 0){
00741                         systemError("ERROR UNPACKING NUMBER OF NEURONS FROM MESSAGE");
00742                         return;
00743                 }
00744         #endif//PVM_DEBUG
00745 
00746         //Unpack neuron IDs
00747         unsigned int fireNeuronArray[numberOfFiringNeurons];
00748         info = pvm_upkuint(fireNeuronArray, numberOfFiringNeurons, 1);
00749         #ifdef PVM_DEBUG
00750                 if(info < 0){
00751                         systemError("ERROR UNPACKING NEURON IDS FROM MESSAGE");
00752                         return;
00753                 }
00754         #endif//PVM_DEBUG
00755         
00756         for(int i=0; i<numberOfFiringNeurons; ++i){
00757                 #ifdef FIRING_NEURONS_EXTERNAL_DEBUG
00758                         if((fireNeuronArray[i] < startNeuronID) || (fireNeuronArray[i] > (startNeuronID + numberOfNeurons))){
00759                                 systemError("SpikeStreamSimulation: FIRING NEURONS, NEURON ID OUT OF RANGE", fireNeuronArray[i]);
00760                                 return;
00761                         }
00762                         else
00763                                 cout<<"SpikeStreamSimulation: Firing neuron neuronID = "<<(fireNeuronArray[i] - startNeuronID)<<endl;
00764                 #endif//FIRING_NEURONS_EXTERNAL_DEBUG
00765                 neuronArray[fireNeuronArray[i] - startNeuronID]->fireNeuron();
00766         }
00767 }
00768 
00769 
00770 /*! Returns a random number between range low and range high. */
00771 double SpikeStreamSimulation::getRandomPercentage(){
00772         return ( (double)rand() / (double)RAND_MAX ) * 100.0;
00773 }
00774 
00775 
00776 /*! Causes neurons to fire with random patterns in addition to any firing caused by their input 
00777         Message that calls this method contains a single integer specifying the noise. -1 means inject
00778         noise in a single neuron. Numbers above 0 give the percentage of neurons to be fired randomly. */
00779 void SpikeStreamSimulation::injectNoise(){
00780         int noiseAmount;
00781         info = pvm_upkint(&noiseAmount, 1, 1);
00782         #ifdef PVM_DEBUG
00783                 if(info < 0){
00784                         systemError("ERROR UNPACKING NOISE AMOUNT FROM MESSAGE");
00785                         return;
00786                 }
00787         #endif//PVM_DEBUG
00788         
00789         int ranNum_int = rand();
00790         int index_int;
00791         if(noiseAmount == -1){//Select 1 neuron at random
00792                 double index_doub = (double)ranNum_int *((double)numberOfNeurons / (double)RAND_MAX);
00793                 index_int = (int)rint(index_doub);
00794                 neuronArray[index_int]->fireNeuron();
00795                 #ifdef NOISE_DEBUG
00796                         cout<<"SpikeStreamSimulation: Inject noise, firing neuron "<<(index_int + startNeuronID)<<endl;
00797                 #endif//NOISE_DEBUG
00798         }
00799         else if(noiseAmount > 0 && noiseAmount <= 100){
00800                 fireRandomNeurons((double)noiseAmount);
00801         }
00802         else{
00803                 systemError("SpikeStreamSimulation: NOISE AMOUNT NOT RECOGNIZED");
00804         }
00805 }
00806 
00807 
00808 /*! Loads up the global parameters from the global parameters database. */
00809 bool SpikeStreamSimulation::loadGlobalParameters(){
00810         try{
00811                 //Query global parameters table
00812                 Query query = networkDBInterface->getQuery();
00813                 query.reset();
00814                 query<<"SELECT TimeStepDurationMS_val, RealTimeClock_val FROM GlobalParameters";
00815                 Result paramResult = query.store();
00816         
00817                 //Check the number of rows - should be 1. Quit if it is the wrong number
00818                 if(paramResult.rows() == 0){
00819                         systemError("Global Parameters table is empty and should have a single row");
00820                         return false;
00821                 }
00822                 else if (paramResult.rows() > 1){
00823                         systemError("Global Parameters table has more than one row and should only have a single row");
00824                         return false;
00825                 }
00826                 Row parameterRow (*paramResult.begin());//Have checked that there is only 1 row
00827         
00828                 //Real time clock and time step duration are mutually exclusive parameters
00829                 unsigned int realTimeClock = Utilities::getUInt((std::string)parameterRow["RealTimeClock_val"]);
00830                 if(realTimeClock == 0){
00831                         //Set the time step duration
00832                         double timeStepDurationMS = Utilities::getDouble((std::string)parameterRow["TimeStepDurationMS_val"]);
00833                 
00834                         //Set the synapse parameters for all basic synapses in this neuron group
00835                         simulationClock->setTimeStepDuration(timeStepDurationMS);
00836         
00837                         //Make sure live mode is false
00838                         simulationClock->setLiveMode(false);
00839                 }
00840                 else{//Run simulation in real time
00841                         simulationClock->setLiveMode(true);
00842                 }
00843         
00844                 //Print parameters for debug
00845                 #ifdef GLOBAL_PARAMETERS_DEBUG
00846                         cout<<"Time step duration (ms): "<<simulationClock->getTimeStepDuration_ms()<<"; Live mode = "<<realTimeClock<<endl;
00847                 #endif//GLOBAL_PARAMETERS_DEBUG
00848 
00849                 //Everything should be ok if we have reached this point
00850                 return true;
00851         }
00852         catch (const BadQuery& er) {// Handle any query errors
00853                 ostringstream errorStrStream;
00854                 errorStrStream<<"Bad query when loading global parameters: \""<<er.what()<<"\"";
00855                 systemError(errorStrStream.str());
00856                 return false;
00857         }
00858         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00859                 ostringstream errorStrStream;
00860                 errorStrStream<<"Exception thrown loading global parameters: \""<<er.what()<<"\"";
00861                 systemError(errorStrStream.str());
00862                 return false;
00863         }
00864         catch(std::exception& er){// Catch-all for any other exceptions
00865                 ostringstream errorStrStream;
00866                 errorStrStream<<"Exception thrown loading global parameters: \""<<er.what()<<"\"";
00867                 systemError(errorStrStream.str());
00868                 return false;
00869         }
00870 }
00871 
00872 
00873 /*! Loads the parameters for neurons from the database. */
00874 bool SpikeStreamSimulation::loadNeuronParameters(){
00875         try{
00876                 //Output debugging information
00877                 #ifdef NEURON_PARAMETERS_DEBUG
00878                         cout<<"Loading neuron parameters from table "<<classLoader->getNeuronParameterTableName(neuronType)<<endl;
00879                 #endif //NEURON_PARAMETERS_DEBUG
00880         
00881                 //Create a map to store all of the neuron parameters.
00882                 map<string, double> parameterMap;
00883         
00884                 //First need to get the names of all the parameters
00885                 Query query = networkDBInterface->getQuery();
00886                 query.reset();
00887                 query<<"SHOW COLUMNS FROM "<<classLoader->getNeuronParameterTableName(neuronType);
00888                 Result showResult = query.store();
00889                 for(Result::iterator iter = showResult.begin(); iter != showResult.end(); ++iter){
00890                         Row showRow(*iter);
00891         
00892                         //Get the column name
00893                         string tempFieldName((std::string)showRow["Field"]);
00894                 
00895                         //If it is a parameter name
00896                         if(tempFieldName.find("_val") != string::npos){
00897         
00898                                 //Create a key without the _val extension
00899                                 string finalFieldName(tempFieldName, 0, tempFieldName.find("_val"));
00900         
00901                                 //Store field name
00902                                 parameterMap[finalFieldName] = 0.0;
00903                         }
00904                 }
00905         
00906                 //Extract the values of the parameters from the database
00907                 bool firstParameter = true;
00908                 query.reset();
00909                 if(parameterMap.size() > 0){//There are parameters for this neuron type
00910                         query<<"SELECT ";
00911                         for(map<string, double>::iterator iter = parameterMap.begin(); iter != parameterMap.end(); ++iter){
00912                                 if(firstParameter){
00913                                         query<<iter->first<<"_val";
00914                                         firstParameter = false;
00915                                 }
00916                                 else{
00917                                         query<<", "<<iter->first<<"_val";
00918                                 }
00919                         }
00920                         query<<" FROM "<<classLoader->getNeuronParameterTableName(neuronType)<<" WHERE NeuronGrpID = "<<neuronGrpID;
00921                 }
00922                 else//No parameters for this neuron type
00923                         query<<"SELECT NeuronGrpID FROM "<<classLoader->getNeuronParameterTableName(neuronType)<<" WHERE NeuronGrpID = "<<neuronGrpID;
00924                 Result valueResult = query.store();
00925         
00926                 //Check that there is just one row for this neuron group
00927                 if(valueResult.size() != 1){
00928                         systemError_int("PARAMETER TABLE \"" + classLoader->getNeuronParameterTableName(neuronType) + "\" DOES NOT CONTAIN AN ENTRY FOR NEURON GROUP ", neuronGrpID);
00929                         return false;
00930                 }
00931                 Row parameterRow(*valueResult.begin());
00932                 for(map<string, double>::iterator iter = parameterMap.begin(); iter != parameterMap.end(); ++iter){
00933                         parameterMap[iter->first] = Utilities::getDouble((std::string)parameterRow[(iter->first + "_val").data()]);
00934                 }
00935 
00936                 /*Set the neuron parameters. Neuron parameters should all be static, but
00937                         does not appear to be possible to have a method that is both static 
00938                         and virtual so have made method virtual and not static, but which manipulates
00939                         the static variables for the neuron parameters. */
00940                 if(!neuronArray[0]->setParameters(parameterMap)){
00941                         systemError("FAILED TO SET NEURON PARAMETERS");
00942                         return false;
00943                 }
00944         
00945         
00946                 /* Inform neuron classes that their parameters have been changed. Needed in case they have
00947                         learning related variables, for example, that need to be updated to a final state
00948                         when learning is switched off. */
00949                 for(unsigned int i=0; i<numberOfNeurons; ++i){
00950                         neuronArray[i]->parametersChanged();    
00951                 }
00952         
00953                 #ifdef NEURON_PARAMETERS_DEBUG
00954                         cout<<"Setting neuron parameters: "<<endl;
00955                         for(map<string, double>::iterator iter = parameterMap.begin(); iter != parameterMap.end(); ++iter){
00956                                 cout<<iter->first<<" = "<<iter->second<<endl;
00957                         }
00958                 #endif //NEURON_PARAMETERS_DEBUG
00959 
00960                 //Everything is ok if we have reached this point
00961                 return true;
00962         }
00963         catch (const BadQuery& er) {// Handle any query errors
00964                 ostringstream errorStrStream;
00965                 errorStrStream<<"Bad query when loading neuron parameters: \""<<er.what()<<"\"";
00966                 systemError(errorStrStream.str());
00967                 return false;
00968         }
00969         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00970                 ostringstream errorStrStream;
00971                 errorStrStream<<"Exception thrown loading neuron parameters: \""<<er.what()<<"\"";
00972                 systemError(errorStrStream.str());
00973                 return false;
00974         }
00975         catch(std::exception& er){// Catch-all for any other exceptions
00976                 ostringstream errorStrStream;
00977                 errorStrStream<<"Exception thrown loading neuron parameters: \""<<er.what()<<"\"";
00978                 systemError(errorStrStream.str());
00979                 return false;
00980         }
00981 }
00982 
00983 
00984 /*! Loads up the neurons.
00985         NOTE Exception handling should be done by the calling method. */
00986 void SpikeStreamSimulation::loadNeurons(){
00987         Query generalQuery = networkDBInterface->getQuery();
00988         
00989         //Get information about neurons in neuron group
00990         generalQuery.reset();
00991         generalQuery<<"SELECT NeuronType, Width, Length FROM NeuronGroups WHERE NeuronGrpID = "<<neuronGrpID;
00992         Result result = generalQuery.store();
00993         Row neuronGrpInfoRow(*result.begin());//Should only be one row because neuronGrpID is unique
00994         neuronType = Utilities::getUShort(neuronGrpInfoRow["NeuronType"]);
00995         neuronGrpWidth = Utilities::getUInt(neuronGrpInfoRow["Width"]);
00996         neuronGrpLength = Utilities::getUInt(neuronGrpInfoRow["Length"]);
00997         
00998         /*Get the number of neurons in the group and the lowest neuronID in the group
00999                 By assuming that the neuron group is a continuous number of neuronIDs starting at 
01000                 neuronGrpStart it becomes easy to achieve random access to any neuron using the neuronID */
01001         generalQuery.reset();
01002         generalQuery<<"SELECT COUNT(NeuronID), MIN(NeuronID) FROM Neurons WHERE NeuronGrpID = "<<neuronGrpID;
01003         result = generalQuery.store();
01004         Row neurGrpPropRow(*result.begin());//Should only be one row
01005         numberOfNeurons = Utilities::getUInt(neurGrpPropRow["COUNT(NeuronID)"]);
01006         startNeuronID = Utilities::getUInt(neurGrpPropRow["MIN(NeuronID)"]);
01007         
01008         /* Create an array to hold the neurons. This contains neuron classes on the heap.
01009                 Create a different type of neuron depending on neuronType */
01010         neuronArray = new Neuron*[numberOfNeurons];
01011         for(unsigned int i=0; i<numberOfNeurons; ++i){
01012                 //Create the neuron
01013                 neuronArray[i] = classLoader->getNewNeuron(neuronType);
01014         
01015                 //Set up the necessary references.
01016                 //FIXME WOULD BE BETTER DONE STATICALLY, BUT HAD SOME STRANGE PROBLEMS WITH THIS
01017                 neuronArray[i]->setSimulationClock(simulationClock);
01018                 neuronArray[i]->setSynapseMapPtr(&synapseMap);
01019                 neuronArray[i]->setNeuronID(i + startNeuronID);
01020         }
01021 
01022         /* Work through the neurons that have been created and set up the connections for each one.*/
01023         Connection* tmpFastConnection = networkDBInterface->getNewConnection();
01024         if(!tmpFastConnection){
01025                 throw databaseException;
01026         }
01027         Query fastQuery = tmpFastConnection->query();
01028         int oldDelay = -1, tempTaskID = -1, oldTempTaskID = -1;
01029         vector<int> tempTaskIDVector;
01030         for(unsigned short neuronNum = 0; neuronNum < numberOfNeurons; ++neuronNum){
01031                 //Get number of connections from this neuron
01032                 generalQuery.reset();
01033                 generalQuery<<"SELECT COUNT(*) FROM Connections WHERE PreSynapticNeuronID = "<<(startNeuronID + neuronNum);
01034                 result = generalQuery.store();
01035                 Row connSizeRow(*result.begin());//Should only be one row
01036                 unsigned int numberOfConnections = Utilities::getUInt(connSizeRow["COUNT(*)"]);
01037                 
01038                 //Create an array to hold these connections
01039                 neuronArray[neuronNum]->connectionArray = new unsigned short[numberOfConnections * 2];//Deleted by Neuron class at end
01040                 neuronArray[neuronNum]->numberOfConnections = numberOfConnections * 2;
01041         
01042                 /* Work through connections and create connection holders pointing to different parts
01043                         of the array. This query orders by ConnGrpID and then by Delay, so can work through
01044                         each connection group and then through each list of delays */
01045                 fastQuery.reset();
01046                 fastQuery<<"SELECT PostSynapticNeuronID, Delay, ConnGrpID FROM Connections WHERE PreSynapticNeuronID = "<<(startNeuronID + neuronNum)<<" ORDER BY ConnGrpID, Delay";
01047                 ResUse neurConnRes = fastQuery.use();
01048                 Row neurConnRow;
01049                 if(neurConnRes){
01050                         //Create a counter to access array
01051                         int connectionCounter = 0;
01052                 
01053                         /* Work through all of the rows, adding entries to the connectionArray and 
01054                                 creating connection holders that point to parts of this array. These 
01055                                 connection holders are organised by task and delay */
01056                         try{
01057                                 while (neurConnRow = neurConnRes.fetch_row()){
01058                                         //Retrieve details about the row
01059                                         unsigned int postNeuronID = Utilities::getUInt(neurConnRow["PostSynapticNeuronID"]);
01060                                         int delay = Utilities::getInt(neurConnRow["Delay"]);
01061                                         unsigned int connGrpID = Utilities::getUInt(neurConnRow["ConnGrpID"]);
01062         
01063                                         #ifdef LOAD_NEURON_DEBUG
01064                                                 cout<<"Loading Connection into neuron: "<<startNeuronID + neuronNum<<"; postNeuronID = "<<postNeuronID<<"; delay = "<<delay<<"; connGrpID = "<<connGrpID<<endl;
01065                                         #endif//LOAD_NEURON_DEBUG
01066         
01067                                         // Get the task associated with the connection Grp ID
01068                                         tempTaskID = taskConnGrpMap[connGrpID];
01069                                         
01070                                         /* Add from entrie to connection array
01071                                                 To compress the data record the relative position in the array and then add 
01072                                                 the start neuron ID to this value when the message is received. 
01073                                                 The start neuron ID of this task is stored in the taskNeurGrpMap */
01074                                         neuronArray[neuronNum]->connectionArray[connectionCounter] = neuronNum;
01075                                         neuronArray[neuronNum]->connectionArray[connectionCounter + 1 ] = postNeuronID - startNeurIDTaskMap [ tempTaskID ];
01076                                         
01077                                         // Create connection holders organised by task and delay
01078                                         if(tempTaskID == oldTempTaskID){//Add connection to existing vector in connectionMap
01079                                                 #ifdef LOAD_NEURON_DEBUG
01080                                                         cout<<"Adding connection to existing task"<<endl;
01081                                                 #endif//LOAD_NEURON_DEBUG
01082         
01083                                                 if(delay == oldDelay){//Add to existing connection holder
01084                                                 
01085                                                         /* Increase number of connections in current connection holder by
01086                                                                 1. Have to increase it by 1 because this counts each pair of numbers in
01087                                                                 each connection. This controls how many numbers are read from 
01088                                                                 the connection array when a message is sent. back() returns an 
01089                                                                 iterator to the last connectionHolder in the vector so need to 
01090                                                                 dereference this`iterator to get the pointer to the connection 
01091                                                                 holder. */
01092                                                         (neuronArray[neuronNum]->connectionMap[tempTaskID].back()).numConnIDs++;
01093                                                 }
01094                                                 else{//Create a new connection holder to hold this new delay value
01095                                                         // New connection holder
01096                                                         ConnectionHolder tempConnHolder;
01097                                                 
01098                                                         /* Point the connection holder to the address of the current position 
01099                                                                 in the connection array. */
01100                                                         tempConnHolder.connIDArray = &(neuronArray[neuronNum]->connectionArray[connectionCounter]);
01101                                                 
01102                                                         //Set the number of connections in the connection holder
01103                                                         tempConnHolder.numConnIDs = 1;
01104                                                 
01105                                                         //Set the delay in the connection holder
01106                                                         tempConnHolder.delay = delay;
01107                                                 
01108                                                         //Add the connection holder to the vector in the connectionMap for this taskID
01109                                                         neuronArray[neuronNum]->connectionMap[tempTaskID].push_back(tempConnHolder);
01110                                                         
01111                                                         // Copy new delay value into old delay value
01112                                                         oldDelay = delay;
01113                                                 }
01114                                         }
01115                                         else{// New task
01116                                                 #ifdef LOAD_NEURON_DEBUG
01117                                                         cout<<"New task"<<endl;
01118                                                 #endif//LOAD_NEURON_DEBUG
01119         
01120                                                 /*Store this taskID. 
01121                                                         This gives me a list of tasks that this neuron needs to connect with. */
01122                                                 tempTaskIDVector.push_back(tempTaskID);
01123         
01124                                                 /*  Add a new vector to the connection map. 
01125                                                         This is done automatically with [] operator */
01126                                                 neuronArray[neuronNum]->connectionMap[tempTaskID];
01127         
01128                                                 // New connection holder
01129                                                 ConnectionHolder tempConnHolder;
01130         
01131                                                 /* Point the connection holder to the address of the current position 
01132                                                         in the connection array. */
01133                                                 tempConnHolder.connIDArray = &(neuronArray[neuronNum]->connectionArray[connectionCounter]);
01134         
01135                                                 //Set the number of connections in the connection holder
01136                                                 tempConnHolder.numConnIDs = 1;
01137         
01138                                                 //Set the delay in the connection holder
01139                                                 tempConnHolder.delay = delay;
01140         
01141                                                 //Add the connection holder to the vector in the connectionMap for this taskID
01142                                                 neuronArray[neuronNum]->connectionMap[tempTaskID].push_back(tempConnHolder);
01143         
01144                                                 //Store the old values of delay and task id
01145                                                 oldTempTaskID = tempTaskID;
01146                                                 oldDelay = delay;
01147                                         }
01148                                         /*Increase the counter that is keeping track of the connectionArray 
01149                                                 Needs to be increased by two since connection array stores both from and to 
01150                                                 neuron IDs */
01151                                         connectionCounter += 2;
01152                                 }
01153                         }
01154                         catch (const EndOfResults& er) {//EndOfResults exception thrown when fetch row no longer returns anything
01155                                 //No need to do anything here - this is normal behaviour
01156                         }
01157                         
01158                         /* All connections have been loaded into the neuron at neuronNum. Now need to create
01159                                 taskHolderArray for neuron. This holds references to all the task holder classes
01160                                 that will be used to send the neuron's spikes */
01161                         neuronArray[neuronNum]->numberOfSpikeTaskHolders = tempTaskIDVector.size();
01162                         neuronArray[neuronNum]->spikeTaskHolderArray = new TaskHolder*[tempTaskIDVector.size()];//Deleted by Neuron at clean up
01163                         int tHCounter = 0;
01164                         for(vector<int>::iterator iter = tempTaskIDVector.begin(); iter != tempTaskIDVector.end(); ++iter){
01165                                 neuronArray[neuronNum]->spikeTaskHolderArray[tHCounter] = spikeTaskHolderMap[*iter];
01166                                 ++tHCounter;
01167                         }
01168 
01169                         //Set the neuronTaskHolder for the neuron
01170                         neuronArray[neuronNum]->neuronTaskHolder = neuronTaskHolder;
01171                         
01172                         //Empty task ID vector so that it can be filled with task IDs for next neuron.
01173                         tempTaskIDVector.clear();
01174 
01175                         //Reset oldDelay and oldTempTaskID
01176                         oldDelay = -1; 
01177                         oldTempTaskID = -1;
01178                 }
01179                 else{
01180                         cerr<<fastQuery.error()<<endl;
01181                         systemError("CANNOT RETRIEVE NEURON GROUP DETAILS");
01182                 }
01183                 
01184                 //Print out details of neuron for debugging.
01185                 #ifdef LOAD_NEURON_DEBUG
01186                         cout<<"Loaded neuron number: "<<neuronNum<<endl;
01187                 #endif//LOAD_NEURON_DEBUG
01188         }
01189         //Close temporary connection
01190         tmpFastConnection->close();
01191 }
01192 
01193 
01194 /*! Loads the parameters controlling noise from the NoiseParameters database. */
01195 bool SpikeStreamSimulation::loadNoiseParameters(){
01196         try{
01197                 Query query = networkDBInterface->getQuery();
01198                 query.reset();
01199                 query<<"SELECT NeuronGrpID, NoiseEnabled, PercentNeurons, DirectFiring, SynapticWeight FROM NoiseParameters WHERE NeuronGrpID = "<<neuronGrpID;
01200                 Result noiseParamsRes = query.store();
01201                 Row noiseParamsRow(*noiseParamsRes.begin());//NeuronGrpID is unique
01202         
01203                 //Extract whether noise is enabled or not
01204                 unsigned int noiseEnabledVal = Utilities::getUInt((std::string)noiseParamsRow["NoiseEnabled"]);
01205                 if(noiseEnabledVal == 0)
01206                         noiseEnabled = false;
01207                 else 
01208                         noiseEnabled = true;
01209         
01210                 //Extract the percentage of neurons to be fired
01211                 percentNeurons_noise = Utilities::getDouble((std::string)noiseParamsRow["PercentNeurons"]);
01212                 if(percentNeurons_noise > 100 && percentNeurons_noise != RANDOM_PERCENT_NEURONS_NOISE){
01213                         systemError_double("NON RANDOM PERCENT OF NOISY NEURONS SHOULD NOT EXCEED 100: ", percentNeurons_noise);
01214                         return false;
01215                 }
01216 
01217                 //Are we selecting a random percentage of neurons for the noise
01218                 if(percentNeurons_noise == RANDOM_PERCENT_NEURONS_NOISE){
01219                         randomPercentNoise = true;
01220                 }
01221                 else{
01222                         randomPercentNoise = false;
01223                 }
01224         
01225                 //Extract whether neurons should be fired directly or via changeMembranePotential()
01226                 unsigned int directFiringVal = Utilities::getUInt((std::string)noiseParamsRow["DirectFiring"]);
01227                 if(directFiringVal == 0)
01228                         directFiring_noise = false;
01229                 else
01230                         directFiring_noise = true;
01231                 
01232                 //Extract the synaptic weight for synaptic firing of neurons
01233                 synapticWeight_noise = Utilities::getDouble((std::string)noiseParamsRow["SynapticWeight"]);
01234         
01235                 #ifdef NOISE_DEBUG
01236                         cout<<"NOISE PARAMETERS: percentNeurons_noise = "<<percentNeurons_noise<<"; directFiring_noise = "<<directFiring_noise<<"; synapticWeight_noise = "<<synapticWeight_noise<<endl;
01237                 #endif//NOISE_DEBUG
01238 
01239                 //Everything should be ok if we have reached this point
01240                 return true;
01241         }
01242         catch (const BadQuery& er) {// Handle any query errors
01243                 ostringstream errorStrStream;
01244                 errorStrStream<<"Bad query when loading noise parameters: \""<<er.what()<<"\"";
01245                 systemError(errorStrStream.str());
01246                 return false;
01247         }
01248         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01249                 ostringstream errorStrStream;
01250                 errorStrStream<<"Exception thrown loading noise parameters: \""<<er.what()<<"\"";
01251                 systemError(errorStrStream.str());
01252                 return false;
01253         }
01254         catch(std::exception& er){// Catch-all for any other exceptions
01255                 ostringstream errorStrStream;
01256                 errorStrStream<<"Exception thrown loading noise parameters: \""<<er.what()<<"\"";
01257                 systemError(errorStrStream.str());
01258                 return false;
01259         }
01260 }
01261 
01262 
01263 /*! Passes references to each neuron of the synapses
01264         that are connected to them. Used for some learning algorithms. */
01265 void SpikeStreamSimulation::loadPreSynapticNeuronMaps(){
01266         //Work through all the synapses
01267         for( dense_hash_map<unsigned int, dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >*, hash<unsigned int> >::iterator outerIter = synapseMap.begin(); outerIter != synapseMap.end(); ++outerIter){
01268                 for(dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >::iterator innerIter = outerIter->second->begin(); innerIter != outerIter->second->end(); ++innerIter){
01269                         //Get neuron that this synapse connects to and add a reference to this synapse to its vector
01270                         innerIter->second->postSynapticNeuron->preSynapseVector.push_back(innerIter->second);
01271                 }
01272         }
01273 }
01274 
01275 
01276 /*! Loads data into simulation. */
01277 void SpikeStreamSimulation::loadSimulationData(){
01278         /* First check to see if simulation data has already been loaded. This is to avoid the 
01279                 potential problem of duplicate messages. Could code reload neuron data as a separate
01280                 message if needed, although restart might be better. */
01281         if(simulationDataLoaded)
01282                 return;
01283 
01284         /* Unpack the number of simulation parameters */
01285         int numberOfSimulationParameters;
01286         int info = pvm_upkint(&numberOfSimulationParameters, 1, 1);
01287         if(info < 0){
01288                 systemError("ERROR UNPACKING NUMBER OF SIMULATION PARAMETERS FROM MESSAGE.");
01289                 return;
01290         }
01291 
01292         /* Unpack the rest of the message to determine what sort of simulation this
01293                 task should be carrying out. */
01294         info = pvm_upkuint(&simulationType, 1, 1);
01295         if(info < 0){
01296                 systemError("ERROR UNPACKING SIMULATION TYPE FROM MESSAGE");;
01297                 return;
01298         }
01299         
01300         //Unpack data relevant to a pattern simulation
01301         if(simulationType == PATTERN_SIMULATION){
01302                 //Need to unpack the patternGrpId and the timeStepsPerPattern
01303                 unsigned int patternGrpID;
01304                 info = pvm_upkuint(&patternGrpID, 1, 1);
01305                 if(info < 0){
01306                         systemError("ERROR UNPACKING patternGrpID FROM MESSAGE.");
01307                         return;
01308                 }
01309                 info = pvm_upkuint(&timeStepsPerPattern, 1, 1);
01310                 if(info < 0){
01311                         systemError("ERROR UNPACKING timeStepsPerPattern FROM MESSAGE.");
01312                         return;
01313                 }
01314 
01315                 //Create the pattern manager
01316                 patternManager = new PatternManager(networkDBInterface, patternDBInterface, neuronGrpID, patternGrpID);
01317 
01318                 /* Create an empty device manager that does nothing. This is needed at present because of intermittent
01319                         calls to the device manager during the simulation run, even when it is not being used. */
01320                 deviceManager = new DeviceManager();
01321 
01322                 //Free resources from device database
01323                 delete deviceDBInterface;
01324                 deviceDBInterface = NULL;
01325 
01326                 #ifdef SIMULATION_DEBUG
01327                         cout<<"Task: "; printTID(); cout<<": PATTERN_SIMULATION with pattern group "<<patternGrpID<<endl;
01328                 #endif//SIMULATION_DEBUG
01329         }
01330 
01331         //Unpack data relevant to a live simulation
01332         else if(simulationType == LIVE_SIMULATION){
01333                 //Unpack device id 
01334                 unsigned int deviceID;
01335                 info = pvm_upkuint(&deviceID, 1, 1);
01336                 if(info < 0){
01337                         systemError("ERROR UNPACKING deviceID FROM MESSAGE.");
01338                         return;
01339                 }
01340 
01341                 //Unpack device firing mode
01342                 unsigned int unpkDevFiringMode;
01343                 info = pvm_upkuint(&unpkDevFiringMode, 1, 1);
01344                 if(info < 0){
01345                         systemError("ERROR UNPACKING device firing mode FROM MESSAGE.");
01346                         return;
01347                 }
01348 
01349                 /* Convert back to a number between -1 and OUTPUT_FIRING_MODE with 0.1 resolution. */
01350                 double tmpDevFiringMode = (double)unpkDevFiringMode / 10.0;
01351                 tmpDevFiringMode -= 1.0;
01352 
01353                 #ifdef DEVICE_FIRING_MODE_DEBUG
01354                         cout<<"DEVICE FIRING MODE: unpacked value = "<<unpkDevFiringMode<<"; double value = "<<tmpDevFiringMode<<endl;
01355                 #endif//DEVICE_FIRING_MODE_DEBUG
01356 
01357                 //Create device manager
01358                 deviceManager = new DeviceManager(deviceID, neuronGrpID, tmpDevFiringMode, deviceDBInterface, networkDBInterface);
01359 
01360                 /* Set simulation to calculate compute time on each time step if we are receiving
01361                         data from an external device that needs to be sychronized to */
01362                 if(deviceManager->getDeviceType() == DeviceTypes::syncUDPNetworkInput)
01363                         calculateComputeTime = true;
01364 
01365                 //Free resources from pattern database
01366                 delete patternDBInterface;
01367                 patternDBInterface = NULL;
01368 
01369                 #ifdef SIMULATION_DEBUG
01370                         cout<<"Task: "<<thisTaskID<<": LIVE_SIMULATION with external device "<<deviceID<<endl;
01371                 #endif//SIMULATION_DEBUG
01372         }
01373 
01374         //The simulation is a NO_INPUT_SIMULATION - nothing to unpack at present
01375         else{
01376                 //Create an empty device manager
01377                 deviceManager = new DeviceManager();
01378 
01379                 //Free resources from unused databases
01380                 delete deviceDBInterface;
01381                 deviceDBInterface = NULL;
01382                 delete patternDBInterface;
01383                 patternDBInterface = NULL;
01384 
01385                 #ifdef SIMULATION_DEBUG
01386                         cout<<"Task: "; printTID(thisTaskID); cout<<": NO_INPUT_SIMULATION"<<endl;
01387                 #endif//SIMULATION_DEBUG
01388         }
01389 
01390         /* Load Tasks, Neurons and Synapses. This loading order must be preserved because some of 
01391                 the later items depend upon earlier ones. These are only called once, so do exception handling here.*/
01392         try{
01393                 loadTasks();
01394                 loadNeurons();
01395                 loadSynapses();
01396                 loadPreSynapticNeuronMaps();
01397         }
01398         catch (const BadQuery& er) {// Handle any query errors
01399                 ostringstream errorStrStream;
01400                 errorStrStream<<"Bad query when loading simulation data: \""<<er.what()<<"\"";
01401                 systemError(errorStrStream.str());
01402                 return;
01403         }
01404         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01405                 ostringstream errorStrStream;
01406                 errorStrStream<<"Exception thrown loading simulation data: \""<<er.what()<<"\"";
01407                 systemError(errorStrStream.str());
01408                 return;
01409         }
01410         catch(std::exception& er){// Catch-all for any other exceptions
01411                 ostringstream errorStrStream;
01412                 errorStrStream<<"Exception thrown loading simulation data: \""<<er.what()<<"\"";
01413                 systemError(errorStrStream.str());
01414                 return;
01415         }
01416 
01417         /* Load up parameters and set the maximum buffer size. 
01418                 Check that each has been performed successfully before moving on. */
01419         if(!loadNeuronParameters())
01420                 return;
01421         
01422         if(!loadSynapseParameters())
01423                 return;
01424 
01425         if(!loadGlobalParameters())
01426                 return;
01427 
01428         if(!loadNoiseParameters())
01429                 return;
01430 
01431         //Set the maximum buffer size.
01432         setMaxBufferSize();
01433 
01434         /* Set the neuron array in the pattern or device manager
01435                 and fire the neurons for the first time */
01436         if(simulationType == PATTERN_SIMULATION){
01437                 patternManager->setNeuronArray(neuronArray, numberOfNeurons);
01438                 patternManager->fireNeurons();
01439         }
01440         else if(simulationType == LIVE_SIMULATION && deviceManager->isInputDevice()){
01441                 deviceManager->setNeuronArray(neuronArray);
01442                 deviceManager->setNeuronUpdateMap(&neuronUpdateMap);
01443                 deviceManager->setNeuronVector(&neuronTaskHolder->firingNeuronVector, startNeuronID);//Use this to set the start neuron id
01444         }
01445         else if(simulationType == LIVE_SIMULATION && deviceManager->isOutputDevice()){
01446                 deviceManager->setNeuronVector(&neuronTaskHolder->firingNeuronVector, startNeuronID);
01447         }
01448 
01449         /* Send a message to the parent task to indicate that loading is complete */
01450         sendMessage(parentTaskID, SIMULATION_LOADING_COMPLETE_MSG);
01451         
01452         //Set simulation clock to zero
01453         simulationClock->reset();
01454         
01455         // Record the fact that the simulation data has been loaded
01456         simulationDataLoaded = true;
01457 }
01458 
01459 
01460 
01461 /*! Loads up the appropriate synapse parameters. */
01462 bool SpikeStreamSimulation::loadSynapseParameters(){
01463         try{
01464                 //Output debugging information
01465                 #ifdef SYNAPSE_PARAMETERS_DEBUG
01466                         cout<<"SpikeStreamSimulation: Loading synapse parameters"<<endl;
01467                 #endif //SYNAPSE_PARAMETERS_DEBUG
01468         
01469                 /*Work through all of the connection groups that connect to/from this neuron group. connParameterMap holds
01470                         a map of parameters for each connection group. */
01471                 for (map<unsigned int, map<string, double>* >::iterator connParamMapIter = connParameterMap.begin(); connParamMapIter != connParameterMap.end(); ++connParamMapIter){
01472                         //Clear the map if it holds parameters
01473                         connParamMapIter->second->clear();
01474         
01475                         //Get the names of all the parameters for this connection group
01476                         //First need to get the names of all the parameters
01477                         Query query = networkDBInterface->getQuery();
01478                         query.reset();
01479                         query<<"SHOW COLUMNS FROM "<<classLoader->getConnGrpParameterTableName(connParamMapIter->first);
01480         
01481                         #ifdef SYNAPSE_PARAMETERS_DEBUG
01482                                 cout<<query.preview()<<endl;
01483                         #endif //SYNAPSE_PARAMETERS_DEBUG
01484         
01485                         Result showResult = query.store();
01486                         for(Result::iterator iter = showResult.begin(); iter != showResult.end(); ++iter){
01487                                 Row showRow(*iter);
01488                 
01489                                 //Get the column name
01490                                 string tempFieldName((std::string)showRow["Field"]);
01491                         
01492                                 //If it is a parameter name
01493                                 if(tempFieldName.find("_val") != string::npos){
01494         
01495                                         //Create a key without the _val extension
01496                                         string finalFieldName(tempFieldName, 0, tempFieldName.find("_val"));
01497         
01498                                         //Store field name
01499                                         (*connParamMapIter->second)[finalFieldName] = 0.0;
01500                                 }
01501                         }
01502         
01503                         //Extract the values of the parameters from the database
01504                         bool firstParameter = true;
01505                         query.reset();
01506                         query<<"SELECT ";
01507                         for(map<string, double>::iterator iter = connParamMapIter->second->begin(); iter != connParamMapIter->second->end(); ++iter){
01508                                 if(firstParameter){
01509                                         query<<iter->first<<"_val";
01510                                         firstParameter = false;
01511                                 }
01512                                 else{
01513                                         query<<", "<<iter->first<<"_val";
01514                                 }
01515                         }
01516                         query<<" FROM "<<classLoader->getConnGrpParameterTableName(connParamMapIter->first)<<" WHERE ConnGrpID = "<<connParamMapIter->first;
01517         
01518                         #ifdef SYNAPSE_PARAMETERS_DEBUG
01519                                 cout<<query.preview()<<endl;
01520                         #endif //SYNAPSE_PARAMETERS_DEBUG
01521         
01522                         Result valueResult = query.store();
01523                 
01524                         //Check that there is just one row for this neuron group
01525                         if(valueResult.size() != 1){
01526                                 ostringstream tempStr;
01527                                 tempStr<<"SYNAPSE PARAMETER TABLE \""<<classLoader->getConnGrpParameterTableName(connParamMapIter->first)<<"\" CONTAINS "<<valueResult.size()<<" ENTRIES FOR CONNECTION GROUP "<<connParamMapIter->first<<endl;
01528                                 systemError(tempStr.str());
01529                                 return false;
01530                         }
01531                         Row parameterRow(*valueResult.begin());
01532                         for(map<string, double>::iterator iter = connParamMapIter->second->begin(); iter != connParamMapIter->second->end(); ++iter){
01533                                 (*connParamMapIter->second)[iter->first] = Utilities::getDouble((std::string)parameterRow[(iter->first + "_val").data()]);
01534                         }
01535                 }
01536         
01537                 #ifdef SYNAPSE_PARAMETERS_DEBUG
01538                         //Print out the parameters for each of the connection groups
01539                         for (map<unsigned int, map<string, double>* >::iterator connParamMapIter = connParameterMap.begin(); connParamMapIter != connParameterMap.end(); ++connParamMapIter){
01540                                 cout<<"--------------------- Neuron Group "<<neuronGrpID<<" Parameters for Connection Group "<<connParamMapIter->first<<" -------------------"<<endl;
01541                                 for(map<string, double>::iterator iter = connParamMapIter->second->begin(); iter != connParamMapIter->second->end(); ++iter){
01542                                         cout<<iter->first<<" = "<<iter->second<<endl;
01543                                 }
01544                         }
01545                 #endif //SYNAPSE_PARAMETERS_DEBUG
01546         
01547                 /* Synapse parameters have all been loaded up into the appropriate maps. Final thing needed is to inform
01548                         the synapse classes that the parameters have changed. If they want to monitor this change they will have
01549                         to create a local copy of the variable and compare it with the new value. */
01550                 for( dense_hash_map<unsigned int, dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >*, hash<unsigned int> >::iterator outerIter = synapseMap.begin(); outerIter != synapseMap.end(); ++outerIter){
01551                         for(dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >::iterator innerIter = outerIter->second->begin(); innerIter != outerIter->second->end(); ++innerIter){
01552                                 innerIter->second->parametersChanged();
01553                         }
01554                 }
01555 
01556                 //If we have reached this point everything should be ok.
01557                 return true;
01558         }
01559         catch (const BadQuery& er) {// Handle any query errors
01560                 ostringstream errorStrStream;
01561                 errorStrStream<<"Bad query when loading synapse parameters: \""<<er.what()<<"\"";
01562                 systemError(errorStrStream.str());
01563                 return false;
01564         }
01565         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01566                 ostringstream errorStrStream;
01567                 errorStrStream<<"Exception thrown loading synapse parameters: \""<<er.what()<<"\"";
01568                 systemError(errorStrStream.str());
01569                 return false;
01570         }
01571         catch(std::exception& er){// Catch-all for any other exceptions
01572                 ostringstream errorStrStream;
01573                 errorStrStream<<"Exception thrown loading synapse parameters: \""<<er.what()<<"\"";
01574                 systemError(errorStrStream.str());
01575                 return false;
01576         }
01577 }
01578 
01579 
01580 /*! Loads up the synapses data from the database and creates a new synapse for each neuron-neuron
01581         connection. A synapse is created for each connection where the postsynaptic neuron is in this
01582         neuron group. Synapses are stored in nested dense_hash_maps for speed of access. The key in the
01583         outer map is the fromNeuronID. The key in the inner maps is the toNeuronID. 
01584         NOTE Exception handling should be done by the calling method. */
01585 void SpikeStreamSimulation::loadSynapses(){
01586         /* Create a map to hold the link between connection group ids and synapse types.
01587                 All connections within a connection group use the same synapse type and so
01588                 this information is stored in the connection group table. */
01589         map<unsigned int, unsigned int> connSynapseTypeMap;
01590 
01591         // Create parameter map for each of the connection groups that this task is involved in
01592         Query query = networkDBInterface->getQuery();
01593         query.reset();
01594         query<<"SELECT ConnGrpID, ConnType, SynapseType FROM ConnectionGroups WHERE FromNeuronGrpID = "<<neuronGrpID<<" OR ToNeuronGrpID = "<<neuronGrpID;
01595         Result paramRes = query.store();
01596         for(Result::iterator iter = paramRes.begin(); iter != paramRes.end(); ++iter){
01597                 //Extract information about connection group
01598                 Row paramRow(*iter);
01599                 unsigned int connGrpID = Utilities::getUInt(paramRow["ConnGrpID"]);
01600                 unsigned int connType =  Utilities::getUInt(paramRow["ConnType"]);
01601                 unsigned short synapseType = Utilities::getShort(paramRow["SynapseType"]);
01602 
01603                 /*Create parameter maps on the heap */
01604                 if (connType == ConnectionType::Virtual || connType == ConnectionType::TempVirtual){
01605                         ;//Do nothing - don't need parameters for virtual connections which have no synapses
01606                 }
01607                 else{
01608                         //Create a new map to hold the parameters of the synapses in this connection group
01609                         connParameterMap[connGrpID] = new map<string, double>;
01610 
01611                         //Store the synapse type for the connection group
01612                         connSynapseTypeMap[connGrpID] = synapseType;
01613                 }
01614         }
01615         
01616         //Select all connections that have a connection to this neuron group
01617         Connection* tmpFastConnection = networkDBInterface->getNewConnection();
01618         if(!tmpFastConnection){
01619                 throw databaseException;
01620         }
01621         Query fastQuery = tmpFastConnection->query();
01622         fastQuery.reset();
01623         fastQuery<<"SELECT PreSynapticNeuronID, PostSynapticNeuronID, Weight, ConnGrpID FROM Connections WHERE PostSynapticNeuronID >= "<<startNeuronID<<" AND PostSynapticNeuronID < "<<(startNeuronID + numberOfNeurons);
01624         ResUse connRes = fastQuery.use();
01625         Row connRow;
01626         if(connRes){
01627                 try{
01628                         while (connRow = connRes.fetch_row()) {
01629                                 //Extract the pre and post neuron ids
01630                                 unsigned int tmpPreNeurID = Utilities::getUInt(connRow["PreSynapticNeuronID"]);
01631                                 unsigned int tmpPostNeurID = Utilities::getUInt(connRow["PostSynapticNeuronID"]);
01632         
01633                                 //Get weight and normalise to between -1.0 and 1.0
01634                                 double weight = (double)Utilities::getShort(connRow["Weight"]);
01635                                 weight /= 127.0;
01636         
01637                                 //Get connection group id
01638                                 unsigned int connGrpID = Utilities::getUInt(connRow["ConnGrpID"]);
01639         
01640                                 //Create second dense hash map if needed
01641                                 if(synapseMap.count(tmpPreNeurID) == 0){
01642                                         synapseMap[tmpPreNeurID] = new dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >();
01643                                         synapseMap[tmpPreNeurID]->set_empty_key(EMPTY_NEURON_ID_KEY);
01644                                 }
01645         
01646                                 //Create the synapse
01647                                 (*synapseMap[tmpPreNeurID])[tmpPostNeurID] = classLoader->getNewSynapse(connSynapseTypeMap[connGrpID]);
01648         
01649                                 //Set the necessary parameters.
01650                                 /* FIXME THESE WOULD BE MUCH BETTER HANDLED THROUGH STATIC REFERNECES IN THE Synapse
01651                                         CLASS. HOWEVER, I HAD STRANGE PROBLEMS WITH THIS.*/
01652                                 (*synapseMap[tmpPreNeurID])[tmpPostNeurID]->setSimulationClock(simulationClock);
01653                                 (*synapseMap[tmpPreNeurID])[tmpPostNeurID]->setPostSynapticNeuron(neuronArray[tmpPostNeurID - startNeuronID]);
01654                                 (*synapseMap[tmpPreNeurID])[tmpPostNeurID]->setPreSynapticNeuronID(tmpPreNeurID);
01655                                 (*synapseMap[tmpPreNeurID])[tmpPostNeurID]->setWeight(weight);
01656                                 (*synapseMap[tmpPreNeurID])[tmpPostNeurID]->setParameterMapReference(connParameterMap[connGrpID]);
01657                         }
01658                 }
01659                 catch (const EndOfResults& er) {//EndOfResults exception thrown when fetch row no longer returns anything
01660                         //No need to do anything here - this is normal behaviour
01661                 }
01662         }
01663         else{
01664                 cerr<<fastQuery.error()<<endl;
01665                 systemError("CANNOT RETRIEVE CONNECTION GROUP DETAILS");
01666         }
01667 
01668         //Close temporary connection
01669         tmpFastConnection->close();
01670 
01671         //Output debugging information if necessary
01672         #ifdef LOAD_SYNAPSE_DEBUG
01673                 printSynapseMap();
01674         #endif //LOAD_SYNAPSE_DEBUG
01675 }
01676 
01677 
01678 /*! Loads tasks and task holders
01679         Each connection group connects to a particular task and need to be able to 
01680         look up the task id using the connection group id in order to be able to make the
01681         neuron connections.
01682         NOTE Exception handling should be done by the calling method. */
01683 void SpikeStreamSimulation::loadTasks(){
01684         //Get query
01685         Query query= networkDBInterface->getQuery();
01686 
01687         //================== Create Neuron Task Holder ======================
01688         //Get size of this neuron group and create neuron task holder
01689         query.reset();
01690         query<<"SELECT COUNT(*) FROM Neurons WHERE NeuronGrpID = "<<neuronGrpID;
01691         Result sizeResult = query.store();
01692         Row sizeRow = (*sizeResult.begin());//Single row
01693         unsigned int neuronGrpSize = Utilities::getUInt((std::string) sizeRow["COUNT(*)"]);
01694         neuronTaskHolder = new NeuronTaskHolder(thisTaskID, neuronGrpSize);
01695         
01696 
01697         //================= Load Spike Task Holders =========================
01698         //Get a list of NeuronGrpIDs and TaskIDs
01699         query.reset();
01700         query<<"SELECT NeuronGrpID, TaskID FROM NeuronGroups";
01701         Result taskResult = query.store();
01702         for(Result::iterator iter = taskResult.begin(); iter != taskResult.end(); ++iter){
01703                 Row taskRow(*iter);
01704                 int tempTaskID = Utilities::getInt(taskRow["TaskID"]);
01705                 unsigned int tempNeuronGrpID = Utilities::getUInt(taskRow["NeuronGrpID"]);
01706                 
01707                 // Add entry storing the link between neuronGrpID and taskID
01708                 taskNeurGrpMap[tempNeuronGrpID] = tempTaskID;
01709         }
01710 
01711         /* When all the links between neuron group IDs and taskIDs have been stored, need to 
01712                 get the link between connection groups that this neuron group is involved in and the
01713                 task ids of these connection groups. */
01714                 
01715         // Select all connectionGrpIDs that this neuron group is connected to
01716         query.reset();
01717         query<<"SELECT ConnGrpID, ToNeuronGrpID FROM ConnectionGroups WHERE FromNeuronGrpID = "<<neuronGrpID;
01718         Result connGrpRes = query.store();
01719         for(Result::iterator connGrpIter = connGrpRes.begin(); connGrpIter != connGrpRes.end(); ++connGrpIter){
01720                 Row connGrpRow(*connGrpIter);
01721                 unsigned int connGrpID = Utilities::getUInt(connGrpRow["ConnGrpID"]);
01722                 unsigned int toNeuronGrpID = Utilities::getUInt(connGrpRow["ToNeuronGrpID"]);
01723                 
01724                 /* For regular connections, add entry to taskConnGrpMap storing 
01725                         link between connection group and taskID. This will be used later
01726                         when setting up the neurons.
01727                         The task ID of the toNeuronGrp needs to be looked up in the 
01728                         taskNeurGrpMap. */
01729                 taskConnGrpMap[connGrpID] = taskNeurGrpMap[toNeuronGrpID];
01730         }
01731                 
01732         /* Tasks that this neuron group communicates with are managed by a task holder class
01733                 This is loaded into a task holder map and references to task holders in this map
01734                 are passed to individual neurons. */
01735         for(map<unsigned int, int>::iterator iter = taskConnGrpMap.begin(); iter != taskConnGrpMap.end(); ++iter){
01736                 /* Check to see if task holder has already been created for this task id.
01737                         Several connection groups can connect to the same task */
01738                 if(spikeTaskHolderMap.find(iter->second) == spikeTaskHolderMap.end()){// Cannot find task: add new task holder
01739                         spikeTaskHolderMap[iter->second] = new TaskHolder(thisTaskID, iter->second);
01740                 }
01741         }
01742         
01743         /* Count how many spike messages should be received
01744                 To do this, select all the unique neuron groups that connect to this neuron 
01745                 group, including this neuron group */
01746         query.reset();
01747         query<<"SELECT DISTINCT FromNeuronGrpID FROM ConnectionGroups WHERE toNeuronGrpID = "<<neuronGrpID;//<<" AND FromNeuronGrpID != "<<neuronGrpID;
01748         Result distFromNeurIDRes = query.store();
01749 
01750         /* Work through these neuronGroupIDs and add the task id to the number of spike messages.
01751                 This will give a more reliable indication about whether all the messages have arrived
01752                 without a significant performance penalty */
01753         spikeMessageTotal = 0;
01754         for(Result::iterator iter = distFromNeurIDRes.begin(); iter != distFromNeurIDRes.end(); ++iter){
01755                 Row spikeListFromNeuronRow(*iter);
01756                 unsigned int spikeListFromNeuronID = Utilities::getUInt(spikeListFromNeuronRow["FromNeuronGrpID"]);
01757                 spikeMessageTotal += taskNeurGrpMap[spikeListFromNeuronID];
01758         }
01759 
01760         /* Work through the neuron groups and load up the start neuron ID for each task. 
01761                 This is used to compress the messages */
01762         for(map<unsigned int, int>::iterator iter = taskNeurGrpMap.begin(); iter != taskNeurGrpMap.end(); ++iter){
01763                 query.reset();
01764                 query<<"SELECT MIN(NeuronID) FROM Neurons WHERE NeuronGrpID = "<<iter->first;
01765                 Result minNeurIDRes = query.store();
01766                 Row minNeurIDRow(*minNeurIDRes.begin());//Should be only one row
01767                 startNeurIDTaskMap[iter->second] = Utilities::getUInt((std::string)minNeurIDRow["MIN(NeuronID)"]);
01768         }
01769 
01770         //Reset spike message count
01771         spikeMessageCount = 0;
01772 
01773         #ifdef TASK_DEBUG
01774                 cout<<"SpikeStreamSimulation: SpikeMessageTotal = "<<spikeMessageTotal<<endl;
01775         #endif//TASK_DEBUG
01776 }
01777 
01778 
01779 /*! Prints out the synapse map for debugging. */
01780 void SpikeStreamSimulation::printSynapseMap(){
01781         cout<<"----------------------- Start Synapse Map ---------------------------------"<<endl;
01782         for( dense_hash_map<unsigned int, dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >*, hash<unsigned int> >::iterator outerIter = synapseMap.begin(); outerIter != synapseMap.end(); ++outerIter){
01783                 for(dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >::iterator innerIter = outerIter->second->begin(); innerIter != outerIter->second->end(); ++innerIter){
01784                         cout<<"[ "<<outerIter->first<<", "<<innerIter->first<<" } ";
01785                         innerIter->second->print();
01786                         cout<<endl;
01787                 }
01788         }
01789         cout<<"------------------------- End Synapse Map ---------------------------------"<<endl;
01790 }
01791 
01792 
01793 /*! Prints out the task id for this task using either hexadecimal or decimal depending
01794         on the value of printTIDHex. */
01795 void SpikeStreamSimulation::printTID(){
01796         printTID(thisTaskID);
01797 }
01798 
01799 
01800 /*! Prints out a task id either as a hexadecimal or decimal value depending on the
01801         value of printTIDHex.
01802         Code adapted from http://mathforum.org/library/drmath/view/54347.html. */
01803 void SpikeStreamSimulation::printTID(int taskID_decimal){
01804         //Convert task id to hex and print it
01805         if(printTIDHex){
01806                 char hexCharArray[8];
01807                 unsigned long temp_value;
01808                 for(short index=7;index>=0;index--){
01809                         // temp_value=decimal_value/pow(16,index)
01810                         temp_value=taskID_decimal/(1<<(index<<2));
01811                         if(temp_value>9){
01812                                 hexCharArray[index]=(char)('A'-10+temp_value);
01813                                 // decimal_value=decimal_value%pow(16,index)
01814                                 taskID_decimal=taskID_decimal%(1<<(index<<2));
01815                         }
01816                         else if(temp_value>0){
01817                                 hexCharArray[index]=(char)('0'+temp_value);
01818                                 // decimal_value=decimal_value%pow(16,index)
01819                                 taskID_decimal=taskID_decimal%(1<<(index<<2));
01820                         }
01821                         else{
01822                                 hexCharArray[index]='0';
01823                         }
01824                 }
01825         
01826                 //Reverse and strip off significant digits
01827                 char finalHexCString [9];
01828                 bool firstDigitFound = false;
01829                 int counter = 0;
01830                 for(int i=7; i >=0; --i){
01831                         if(hexCharArray[i] == '0' && !firstDigitFound){
01832                                 ;//Do nothing want to ignore this
01833                         }
01834                         else if(hexCharArray[i] != '0' && !firstDigitFound){
01835                                 firstDigitFound = true;
01836                                 finalHexCString[counter] = hexCharArray[i];
01837                                 ++counter;
01838                         }
01839                         else{
01840                                 finalHexCString[counter] = hexCharArray[i];
01841                                 ++counter;
01842                         }
01843                 }
01844                 finalHexCString[counter] = '\0';
01845                 cout<<finalHexCString;
01846         }
01847         else
01848                 cout<<taskID_decimal;
01849 }
01850 
01851 
01852 /*! Called when a SPIKE_LIST_MSG is received containing spikes from another task.
01853         The spikes in this message are pairs of shorts with the from and to neuron ids, 
01854         but with the startNeuronID subtracted, so their value is relative to the neuron
01855         group they are from. Spike list is processed by reading these ids from the 
01856         message and using them to find the synapse in the map and call its update function. */
01857 void SpikeStreamSimulation::processSpikeList(unsigned int senderTID, int msgTimeStep){
01858 
01859         /* During step mode, exta spike messages can arrive before the message has been sent
01860                 so check to see if there are spike messages waiting to be sent and send them */
01861         int tempBufID = -1;
01862         if(spikeMessageCount == spikeMessageTotal){
01863                 tempBufID = pvm_setrbuf(0);//Store buffer before sending messages. Early messages may overwrite current buffer
01864                 #ifdef PVM_BUFFER_DEBUG
01865                         cout<<"ProcessSpikeList1: Saving buffer with ID = "<<tempBufID<<endl;
01866                 #endif//PVM_BUFFER_DEBUG
01867 
01868                 sendSpikeMessages();
01869 
01870                 #ifdef PVM_BUFFER_DEBUG
01871                         int oldBufID = pvm_setrbuf(tempBufID);
01872                         cout<<"ProcessSpikeList2: Saving buffer with ID = "<<oldBufID<<"; Loading buffer with ID = "<<tempBufID<<endl;
01873                 #else
01874                         pvm_setrbuf(tempBufID);
01875                 #endif//PVM_BUFFER_DEBUG
01876         }
01877 
01878         //Unpack message.
01879         unsigned int numberOfSpikes = 0;//Number of spikes in the message
01880         unsigned int messageTimeStep = 0;
01881         if(msgTimeStep == -1){//New incoming message received in the run method
01882                 //Extract the time step from the message. This should be one time step behind the current one or an error
01883                 info = pvm_upkuint(&messageTimeStep, 1, 1);
01884                 #ifdef PVM_DEBUG
01885                         if(info < 0){
01886                                 systemError("ERROR UNPACKING TIME STEP FROM MESSAGE; SENDER TASK ID");
01887                                 cerr<<"TIME STEP ERROR IN MESSAGE FROM TASK: "; printTID(senderTID); cout<<"; messageTimeStep: "<<messageTimeStep<<endl;
01888                                 return;
01889                         }
01890                 #endif//PVM_DEBUG
01891         }
01892         else{//A reloaded early message
01893                 messageTimeStep = msgTimeStep;
01894         }
01895 
01896         /* Check time step. Messages should always have a message time step 1 less than the 
01897                 current time step. However tasks can run at different rates, so it happens sometimes that a task
01898                 has processed the spikes from this task and sent a new spike list before other tasks have had a 
01899                 chance to send the current spike list. In this case (when messagetimestep == this time step), 
01900                 need to store the current receive buffer and process the message after sending the spike lists.
01901                 When simulation clock time step is 0 do not want to subtract 1 because with an unsigned int this 
01902                 leads to a very large number. */
01903 
01904         //Unexpected simulation error. Should not continue with simulation after this
01905         if((simulationClock->getTimeStep() > 0 && messageTimeStep < (simulationClock->getTimeStep() - 1)) || (messageTimeStep > simulationClock->getTimeStep())){
01906 
01907                 unsigned int tempInt = simulationClock->getTimeStep() - 1;
01908                 cout<<"SYNC PROBLEM: messageTimeStep = "<<messageTimeStep<<" simulationClock = "<<simulationClock->getTimeStep()<<" - 1= "<<tempInt<<endl;
01909 
01910                 ostringstream tempStr;
01911                 tempStr<<"SYNCHRONIZATION ERROR: Current time step: "<<simulationClock->getTimeStep()<<"; Message time step: "<<messageTimeStep<<" Message from: "; printTID(senderTID); cout<<endl;
01912                 systemError(tempStr.str());
01913                 spikeMessageCount += 10000;//Add an arbitrary number to prevent simulation from continuing
01914                 return;
01915         }
01916 
01917         /* Message has arrive early and needs to be stored until all messages have been dealt with 
01918                 from the previous timestep */
01919         else if(messageTimeStep == simulationClock->getTimeStep() ){
01920                 #ifdef MESSAGE_DEBUG
01921                         cout<<"SpikeStreamSimulation: Storing early message from "; printTID(senderTID); cout<<"; messageTimeStep = "<<messageTimeStep<<endl;
01922                 #endif//MESSAGE_DEBUG
01923 
01924                 EarlyMessage tmpEarlyMsg;
01925                 tmpEarlyMsg.bufferID = pvm_setrbuf(0);//Instruct PVM to store message and record the buffer id of stored message
01926                 #ifdef PVM_BUFFER_DEBUG
01927                         cout<<"ProcessSpikeList3: Saving buffer with ID = "<<tmpEarlyMsg.bufferID<<endl;
01928                 #endif//PVM_BUFFER_DEBUG
01929                 tmpEarlyMsg.senderTID = senderTID;
01930                 tmpEarlyMsg.timeStep = messageTimeStep;
01931                 earlyMessageStack.push(tmpEarlyMsg);
01932                 return;//Don't want to continue processing the now non existent buffer
01933         }
01934 
01935 
01936         /* Increase the count of the number of spike messages received. Will only increase the spikeMessageCount
01937                 on messages that are 1 time step behind. This applies to both regular and early messages. */
01938         spikeMessageCount += senderTID;
01939         
01940 
01941         /* Only want to unpack and process the spikes if running in no input mode or if updating
01942                 an external device. In these cases the spike message contains meaningful spikes that 
01943                 need to be processed. When updating the neurons from an external device or pattern
01944                 only fire the neurons when sending spike messages. */
01945         //NOTE HAVE KILLED THIS CONDITION SO THAT CAN INHIBIT INPUT LAYERS. DON'T KNOW IF THERE ARE UNPLEASANT REPERCUSSIONS
01946         //if(simulationType == NO_INPUT_SIMULATION || (simulationType == LIVE_SIMULATION && deviceManager->isOutputDevice())){
01947 
01948         // Extract the number of spikes in the message
01949         int info = pvm_upkuint(&numberOfSpikes, 1, 1);
01950         #ifdef PVM_DEBUG
01951                 if(info < 0){
01952                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING NUMBER OF SPIKES FROM MESSAGE; numberOfSpikes: "<<numberOfSpikes<<endl;
01953                         systemError("ERROR UNPACKING NUMBER OF SPIKES FROM MESSAGE");
01954                         return;
01955                 }
01956         #endif//PVM_DEBUG
01957 
01958         //Output debugging information if required
01959         #ifdef SPIKE_DEBUG
01960                 cout<<"Processing Spike list at time: "<<simulationClock->getTimeStep()<<"; Message time step = "<<messageTimeStep<<"; Number of spikes in message = "<<numberOfSpikes<<"; Spike message count = "<<spikeMessageCount<<endl;
01961         #endif //SPIKE_DEBUG
01962 
01963         //Unpack array of from and to neuron ids as two shorts compressed into an integer
01964         info = pvm_upkuint(unpackArray, numberOfSpikes, 1);
01965         #ifdef PVM_DEBUG
01966                 if(info < 0){
01967                         systemError("SpikeStreamSimulation: ERROR UNPACKING UNSIGNED INT FROM MESSAGE. NUMBER OF SPIKES = ", numberOfSpikes);
01968                         return;
01969                 }
01970         #endif//PVM_DEBUG
01971 
01972         /* Work through the unpackArray, extract information about the spikes
01973                 and request synapses to process the spikes. */
01974         for(unsigned int i=0; i<numberOfSpikes; ++i){
01975 
01976                 //Add the from neuron ID to the from key
01977                 unpkFromNeurID = (unsigned short) unpackArray[i];
01978                 unpkFromNeurID += startNeurIDTaskMap[senderTID];
01979 
01980                 //Add this from neuron ID to the from key 
01981                 unpkToNeurID = unpackArray[i] >> 16;
01982                 unpkToNeurID  += startNeuronID;
01983 
01984                 //Print the synapse key for debugging
01985                 //cout<<"Received Synapse Key: [ "<<unpkFromNeurID<<", "<<unpkToNeurID<<" ]"<<endl;
01986                                 
01987                 // Process the spike with full debug checks
01988                 #ifdef SPIKE_DEBUG
01989                         if(synapseMap.count(unpkFromNeurID)){//Check that from key is in map
01990                                 if(synapseMap[unpkFromNeurID]->count(unpkToNeurID)){//Check to key is in second map
01991                                         (*synapseMap[unpkFromNeurID])[unpkToNeurID]->processSpike();
01992                                         neuronUpdateMap[ unpkToNeurID ] = true;//The to neuron should be in this layer
01993                                 }
01994                                 else{
01995                                         ostringstream tempStr;
01996                                         tempStr<<"SpikeStreamSimulation: SYNAPSE TO KEY NOT FOUND IN INNER SYNAPSE MAP: [ "<<unpkFromNeurID<<", "<<unpkToNeurID<<" ]";
01997                                         systemError(tempStr.str().data());
01998                                 }
01999                         }
02000                         else{
02001                                 ostringstream tempStr;
02002                                 tempStr<<"SpikeStreamSimulation: SYNAPSE TO KEY NOT FOUND IN OUTER SYNAPSE MAP: [ "<<unpkFromNeurID<<", "<<unpkToNeurID<<" ]";
02003                                 systemError(tempStr.str().data());
02004                         }
02005 
02006                 //Process the spike with less checks
02007                 #else
02008                         (*synapseMap[unpkFromNeurID])[unpkToNeurID]->processSpike();
02009                         neuronUpdateMap[ unpkToNeurID ] = true;//The to neuron should be in the layer processed by this task
02010                 #endif//SPIKE_DEBUG
02011         }
02012         //}
02013 
02014         //Clean up buffer if necessary
02015         if(tempBufID != -1)
02016                 pvm_freebuf(tempBufID);
02017 
02018         
02019         /* If all spike messages have been received, send spike message to other tasks 
02020                 If simulationRunning is false, the method will exit here and the messages will be sent either
02021                 when step is pressed again or when a spike list is received. */
02022         if(spikeMessageCount == spikeMessageTotal && simulationRunning){
02023                 #ifdef TRANSPORT_DEBUG
02024                         cout<<"Process spike list: Sending spike messages"<<endl;
02025                 #endif//TRANSPORT_DEBUG
02026                 sendSpikeMessages();
02027         }
02028         else if(spikeMessageCount == spikeMessageTotal && !simulationRunning){
02029                 #ifdef TRANSPORT_DEBUG
02030                         cout<<"Process spike list: all spikes received but not sending messags because simulation not running"<<endl;
02031                 #endif//TRANSPORT_DEBUG
02032         }
02033         else{
02034                 #ifdef TRANSPORT_DEBUG
02035                         cout<<"Process spike list: not all spikes received; waiting for more spikes"<<endl;
02036                 #endif//TRANSPORT_DEBUG
02037         }
02038 }
02039 
02040 
02041 /*! Reloads the weights of the synapses from the database. */
02042 void SpikeStreamSimulation::reloadWeights(){
02043         try{
02044                 #ifdef RELOAD_WEIGHTS_DEBUG
02045                         cout<<"SpikeStreamSimulation: Reloading weights."<<endl;
02046                 #endif//RELOAD_WEIGHTS_DEBUG
02047         
02048                 //Select all connections that have a connection to this neuron group
02049                 Connection* tmpFastConnection = networkDBInterface->getNewConnection();
02050                 if(!tmpFastConnection){
02051                         throw databaseException;
02052                 }
02053                 Query fastQuery = tmpFastConnection->query();
02054                 fastQuery.reset();
02055                 fastQuery<<"SELECT PreSynapticNeuronID, PostSynapticNeuronID, Weight FROM Connections WHERE PostSynapticNeuronID >= "<<startNeuronID<<" AND PostSynapticNeuronID < "<<(startNeuronID + numberOfNeurons);
02056                 ResUse connRes = fastQuery.use();
02057                 Row connRow;
02058                 unsigned int tmpPreNeurID, tmpPostNeurID;
02059                 if(connRes){
02060                         try{
02061                                 while (connRow = connRes.fetch_row()) {
02062                 
02063                                         //Extract pre and post neuron ids
02064                                         tmpPreNeurID = Utilities::getUInt(connRow["PreSynapticNeuronID"]);
02065                                         tmpPostNeurID = Utilities::getUInt(connRow["PostSynapticNeuronID"]);
02066                                         
02067                                         //Extract the weight
02068                                         double weight = (double)Utilities::getShort(connRow["Weight"]);
02069                                         weight /= 127.0;//Normalise to between -1.0 and 1.0
02070                 
02071                                         /* Check that key is in map in debug mode. */
02072                                         #ifdef RELOAD_WEIGHTS_DEBUG
02073                                                 if(synapseMap.count(tmpPreNeurID)){//Check that from key is in map
02074                                                         if(!synapseMap[tmpPreNeurID]->count(tmpPostNeurID)){//Check to key is in second map
02075                                                                 cerr<<"SpikeStreamSimulation: CANNOT FIND SYNAPSE KEY: "<<tmpPreNeurID<<" " <<tmpPostNeurID<<endl;
02076                                                                 systemError("Cannot find key in synapse map when reloading weights.");
02077                                                                 return;
02078                                                         }
02079                                                 }
02080                                                 else{
02081                                                         cerr<<"SpikeStreamSimulation: CANNOT FIND SYNAPSE KEY: "<<tmpPreNeurID<<" " <<tmpPostNeurID<<endl;
02082                                                         systemError("Cannot find key in synapse map when reloading weights.");
02083                                                         return;
02084                                                 }
02085                                         #endif//RELOAD_WEIGHTS_DEBUG
02086                 
02087                                         //Set weight in synapse map
02088                                         (*synapseMap[tmpPreNeurID])[tmpPostNeurID]->setWeight(weight);
02089                                 }
02090                         }
02091                         catch (const EndOfResults& er) {//EndOfResults exception thrown when fetch row no longer returns anything
02092                                 //No need to do anything here - this is normal behaviour
02093                         }
02094                 }
02095                 else{
02096                         cerr<<fastQuery.error()<<endl;
02097                         systemError("CANNOT RETRIEVE CONNECTION GROUP DETAILS WHILST LOADING WEIGHTS");
02098                 }
02099 
02100                 #ifdef RELOAD_WEIGHTS_DEBUG
02101                         cout<<"SpikeStreamSimulation: Weights reloaded"<<endl;
02102                 #endif//RELOAD_WEIGHTS_DEBUG
02103         
02104                 //Close temporary connection
02105                 tmpFastConnection->close();
02106 
02107                 //Send acknowledgement message
02108                 sendMessage(parentTaskID, LOAD_WEIGHTS_SUCCESS_MSG);
02109         }
02110         catch (const BadQuery& er) {// Handle any query errors
02111                 ostringstream errorStrStream;
02112                 errorStrStream<<"Bad query when reloading weights: \""<<er.what()<<"\"";
02113                 systemError(errorStrStream.str());
02114         }
02115         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
02116                 ostringstream errorStrStream;
02117                 errorStrStream<<"Exception thrown reloading weights: \""<<er.what()<<"\"";
02118                 systemError(errorStrStream.str());
02119         }
02120         catch(std::exception& er){// Catch-all for any other exceptions
02121                 ostringstream errorStrStream;
02122                 errorStrStream<<"Exception thrown reloading weights: \""<<er.what()<<"\"";
02123                 systemError(errorStrStream.str());
02124         }
02125 }
02126 
02127 
02128 /*! Removes the specified task from the list of tasks that receive firing
02129         neuron data. */
02130 void SpikeStreamSimulation::removeReceivingTask_Neurons(int removeTaskID){
02131         neuronTaskHolder->removeReceivingTask(removeTaskID);
02132 }
02133 
02134 
02135 /*! Removes the specified task from the list of tasks that receive the spike messages
02136         from this task. */
02137 void SpikeStreamSimulation::removeReceivingTask_Spikes(int removeTaskID){
02138         //Work through the task holders and remove task from them
02139         for(map<int, TaskHolder*>::iterator iter = spikeTaskHolderMap.begin(); iter != spikeTaskHolderMap.end(); ++iter)
02140                 iter->second->removeReceivingTask(removeTaskID);
02141 }
02142 
02143 
02144 /*! Writes the weights of this neuron group into TempWeight field of the database
02145         so that they can be viewed by the user during a simulation run. */
02146 void SpikeStreamSimulation::saveViewWeights(){
02147         try{
02148                 #ifdef SAVE_WEIGHTS_DEBUG
02149                         cout<<"SpikeStreamSimulation: Saving view weights."<<endl;
02150                 #endif //SAVE_WEIGHTS_DEBUG
02151         
02152                 //Sort out the database stuff
02153                 Query query = networkDBInterface->getQuery();
02154         
02155                 //Work through the synapses in this layer and save the weights in a temporary location
02156                 for( dense_hash_map<unsigned int, dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >*, hash<unsigned int> >::iterator outerIter = synapseMap.begin(); outerIter != synapseMap.end(); ++outerIter){
02157                         for(dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >::iterator innerIter = outerIter->second->begin(); innerIter != outerIter->second->end(); ++innerIter){
02158                                 query.reset();
02159                                 query<<"UPDATE Connections SET TempWeight = "<<innerIter->second->getShortWeight()<<" WHERE PreSynapticNeuronID = "<<outerIter->first<<" AND PostSynapticNeuronID = "<<innerIter->first;
02160                                 query.execute();
02161                         }
02162                 }
02163 
02164                 #ifdef SAVE_WEIGHTS_DEBUG
02165                         cout<<"SpikeStreamSimulation: View weights saved"<<endl;
02166                 #endif //SAVE_WEIGHTS_DEBUG
02167         
02168                 //Send acknowledgement message
02169                 sendMessage(parentTaskID, VIEW_WEIGHTS_SAVE_SUCCESS_MSG);
02170         }
02171         catch (const BadQuery& er) {// Handle any query errors
02172                 ostringstream errorStrStream;
02173                 errorStrStream<<"Bad query when saving view weights: \""<<er.what()<<"\"";
02174                 systemError(errorStrStream.str());
02175         }
02176         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
02177                 ostringstream errorStrStream;
02178                 errorStrStream<<"Exception thrown saving view weights: \""<<er.what()<<"\"";
02179                 systemError(errorStrStream.str());
02180         }
02181         catch(std::exception& er){// Catch-all for any other exceptions
02182                 ostringstream errorStrStream;
02183                 errorStrStream<<"Exception thrown saving view weights: \""<<er.what()<<"\"";
02184                 systemError(errorStrStream.str());
02185         }
02186 }
02187 
02188 
02189 /*! Writes the weights of this neuron group into the database, overwriting their current values. */
02190 void SpikeStreamSimulation::saveWeights(){
02191         try{
02192                 #ifdef SAVE_WEIGHTS_DEBUG
02193                         cout<<"SpikeStreamSimulation: Saving weights."<<endl;
02194                 #endif //SAVE_WEIGHTS_DEBUG
02195         
02196                 //Sort out the database stuff
02197                 Query query = networkDBInterface->getQuery();
02198         
02199                 //Save the weights
02200                 for( dense_hash_map<unsigned int, dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >*, hash<unsigned int> >::iterator outerIter = synapseMap.begin(); outerIter != synapseMap.end(); ++outerIter){
02201                         for(dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >::iterator innerIter = outerIter->second->begin(); innerIter != outerIter->second->end(); ++innerIter){
02202                                 query.reset();
02203                                 query<<"UPDATE Connections SET Weight = "<<innerIter->second->getShortWeight()<<" WHERE PreSynapticNeuronID = "<<outerIter->first<<" AND PostSynapticNeuronID = "<<innerIter->first;
02204                                 query.execute();
02205                         }
02206                 }
02207         
02208                 #ifdef SAVE_WEIGHTS_DEBUG
02209                         cout<<"SpikeStreamSimulation: Weights saved"<<endl;
02210                 #endif //SAVE_WEIGHTS_DEBUG
02211 
02212                 //Send acknowledgement message
02213                 sendMessage(parentTaskID, WEIGHT_SAVE_SUCCESS_MSG);
02214         }
02215         catch (const BadQuery& er) {// Handle any query errors
02216                 ostringstream errorStrStream;
02217                 errorStrStream<<"Bad query when saving weights: \""<<er.what()<<"\"";
02218                 systemError(errorStrStream.str());
02219         }
02220         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
02221                 ostringstream errorStrStream;
02222                 errorStrStream<<"Exception thrown saving weights: \""<<er.what()<<"\"";
02223                 systemError(errorStrStream.str());
02224         }
02225         catch(std::exception& er){// Catch-all for any other exceptions
02226                 ostringstream errorStrStream;
02227                 errorStrStream<<"Exception thrown saving weights: \""<<er.what()<<"\"";
02228                 systemError(errorStrStream.str());
02229         }
02230 }
02231 
02232 
02233 /*! Sends a message without any contents. */
02234 bool SpikeStreamSimulation::sendMessage(int taskID, int msgtag){
02235         //Initialise the buffer
02236         int info = pvm_initsend(PvmDataDefault);
02237         #ifdef PVM_DEBUG
02238                 if(info < 0){
02239                         cout<<"SpikeStreamSimulation: Init send error: "<<info<<" with task "<<taskID<<" and msgtag: "<<msgtag<<endl;
02240                         return false;
02241                 }
02242         #endif //PVM_DEBUG
02243 
02244         //Send the message
02245         info = pvm_send(taskID, msgtag);
02246         #ifdef PVM_DEBUG
02247                 if(info < 0){
02248                         cout<<"SpikeStreamSimulation: Send error: "<<info<<" with task "<<taskID<<" and msgtag: "<<msgtag<<endl;
02249                         return false;
02250                 }
02251         #endif //PVM_DEBUG
02252 
02253         return true;
02254 }
02255 
02256 
02257 /*! Sends a message containing a char string. */
02258 bool SpikeStreamSimulation::sendMessage(int taskID, int msgtag, const char* charArray){
02259         //First find the length of the char array (+1 so that other end does not have to add 1 for null character)
02260         unsigned int arrayLength = strlen(charArray) + 1;
02261 
02262         //Initialise the buffer
02263         int info = pvm_initsend(PvmDataDefault);
02264         #ifdef PVM_DEBUG
02265                 if(info<0){
02266                         cerr<<"SpikeStreamSimulation: Init send error: tag: "<<msgtag<<" to: "<<taskID<<" containing: "<<charArray<<endl;
02267                         systemError("Init send error");
02268                         return false;
02269                 }
02270         #endif //PVM_DEBUG
02271 
02272         //Pack the length of the char array
02273         info = pvm_pkuint(&arrayLength, 1, 1);
02274         #ifdef PVM_DEBUG
02275                 if(info < 0){
02276                         cerr<<"SpikeStreamSimulation: ERROR PACKING MESSAGE LENGTH INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02277                         systemError("ERROR PACKING MESSAGE LENGTH INTO MESSAGE");
02278                         return false;
02279                 }
02280         #endif //PVM_DEBUG
02281 
02282         //Pack the char array
02283         info = pvm_pkstr((char*)charArray);
02284         #ifdef PVM_DEBUG
02285                 if(info < 0){
02286                         systemError("ERROR PACKING  CHAR* INTO MESSAGE");
02287                         return false;
02288                 }
02289         #endif //PVM_DEBUG
02290 
02291         //Send the message
02292         info = pvm_send(taskID, msgtag);
02293         #ifdef PVM_DEBUG
02294                 if(info<0){
02295                         cerr<<"SpikeStreamSimulation: Message send error: tag: "<<msgtag<<" to: "<<taskID<<" containing: "<<charArray<<endl;
02296                         systemError("PVM message send error");
02297                         return false;
02298                 }
02299         #endif //PVM_DEBUG
02300         return true;
02301 }
02302 
02303 
02304 /*! Sends a message containing an unsigned int and a char string. */
02305 bool SpikeStreamSimulation::sendMessage(int taskID, int msgtag, unsigned int intData, const char* charArray){
02306         //Find the length of the char array (+1 so that other end does not have to add 1 for null character)
02307         unsigned int arrayLength = strlen(charArray) + 1;
02308 
02309         //Initialise the buffer
02310         int info = pvm_initsend(PvmDataDefault);
02311         #ifdef PVM_DEBUG
02312                 if(info<0){
02313                         cerr<<"SpikeStreamSimulation: Init send error: tag: "<<msgtag<<" to: "<<taskID<<" containing: "<<charArray<<endl;
02314                         systemError("PVM init send error.");
02315                         return false;
02316                 }
02317         #endif //PVM_DEBUG
02318 
02319         //Pack the unsigned int
02320         info = pvm_pkuint(&intData, 1, 1);
02321         #ifdef PVM_DEBUG
02322                 if(info < 0){
02323                         cerr<<"SpikeStreamSimulation: ERROR PACKING UNSIGNED INT INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02324                         systemError("ERROR PACKING UNSIGNED INT INTO MESSAGE");
02325                         return false;
02326                 }
02327         #endif //PVM_DEBUG
02328 
02329         //Pack the length of the char array
02330         info = pvm_pkuint(&arrayLength, 1, 1);
02331         #ifdef PVM_DEBUG
02332                 if(info < 0){
02333                         cerr<<"SpikeStreamSimulation: ERROR PACKING MESSAGE LENGTH INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02334                         systemError("ERROR PACKING MESSAGE LENGTH INTO MESSAGE");
02335                         return false;
02336                 }
02337         #endif //PVM_DEBUG
02338 
02339         //Pack the char array
02340         info = pvm_pkstr((char*)charArray);
02341         #ifdef PVM_DEBUG
02342                 if(info < 0){
02343                         cerr<<"SpikeStreamSimulation: ERROR PACKING  CHAR* INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02344                         systemError("ERROR PACKING  CHAR* INTO MESSAGE");
02345                         return false;
02346                 }
02347         #endif //PVM_DEBUG
02348 
02349         //Send the message
02350         info = pvm_send(taskID, msgtag);
02351         #ifdef PVM_DEBUG
02352                 if(info<0){
02353                         cerr<<"SpikeStreamSimulation: Message send error: tag: "<<msgtag<<" to: "<<taskID<<" containing: "<<charArray<<endl;
02354                         systemError("PVM message send error.");
02355                         return false;
02356                 }
02357         #endif //PVM_DEBUG
02358         return true;
02359 }
02360 
02361 
02362 /*! Sends a message containing two unsigned ints and a char string. */
02363 bool SpikeStreamSimulation::sendMessage(int taskID, int msgtag, unsigned int msgData1, unsigned int msgData2, const char* charArray){
02364         //Find the length of the char array (+1 so that other end does not have to add 1 for null character)
02365         unsigned int arrayLength = strlen(charArray) + 1;
02366 
02367         //Initialise the buffer
02368         int info = pvm_initsend(PvmDataDefault);
02369         #ifdef PVM_DEBUG
02370                 if(info<0){
02371                         cerr<<"SpikeStreamSimulation: Init send error: tag: "<<msgtag<<" to: "<<taskID<<" containing: "<<charArray<<endl;
02372                         systemError("PVM init send error.");
02373                         return false;
02374                 }
02375         #endif //PVM_DEBUG
02376 
02377         //Pack the unsigned int
02378         info = pvm_pkuint(&msgData1, 1, 1);
02379         #ifdef PVM_DEBUG
02380                 if(info < 0){
02381                         cerr<<"SpikeStreamSimulation: ERROR PACKING FIRST UNSIGNED INT INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02382                         systemError("ERROR PACKING FIRST UNSIGNED INT INTO MESSAGE.");
02383                         return false;
02384                 }
02385         #endif //PVM_DEBUG
02386 
02387         //Pack the unsigned int
02388         info = pvm_pkuint(&msgData2, 1, 1);
02389         #ifdef PVM_DEBUG
02390                 if(info < 0){
02391                         cerr<<"SpikeStreamSimulation: ERROR PACKING SECOND UNSIGNED INT INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02392                         systemError("ERROR PACKING SECOND UNSIGNED INT INTO MESSAGE.");
02393                         return false;
02394                 }
02395         #endif //PVM_DEBUG
02396 
02397         //Pack the length of the char array
02398         info = pvm_pkuint(&arrayLength, 1, 1);
02399         #ifdef PVM_DEBUG
02400                 if(info < 0){
02401                         cerr<<"SpikeStreamSimulation: ERROR PACKING MESSAGE LENGTH INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02402                         systemError("ERROR PACKING MESSAGE LENGTH INTO MESSAGE.");
02403                         return false;
02404                 }
02405         #endif //PVM_DEBUG
02406 
02407         //Pack the char array
02408         info = pvm_pkstr((char*)charArray);
02409         #ifdef PVM_DEBUG
02410                 if(info < 0){
02411                         cerr<<"SpikeStreamSimulation: ERROR PACKING  CHAR* INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02412                         systemError("ERROR PACKING  CHAR* INTO MESSAGE.");
02413                         return false;
02414                 }
02415         #endif //PVM_DEBUG
02416 
02417         //Send the message
02418         info = pvm_send(taskID, msgtag);
02419         #ifdef PVM_DEBUG
02420                 if(info<0){
02421                         cerr<<"SpikeStreamSimulation: Message send error: tag: "<<msgtag<<" to: "<<taskID<<" containing: "<<charArray<<endl;
02422                         systemError("PVM message send error.");
02423                         return false;
02424                 }
02425         #endif //PVM_DEBUG
02426         return true;
02427 }
02428 
02429 
02430 /*! Sends a message containing an unsigned integer followed by a float array. */
02431 bool SpikeStreamSimulation::sendNeuronData(int taskID, int msgtag, unsigned int neuronID, double* dataArray, int arrayLength){
02432         //Initialise the buffer
02433         int info = pvm_initsend(PvmDataDefault);
02434         #ifdef PVM_DEBUG
02435                 if(info<0){
02436                         cerr<<"SpikeStreamSimulation: Init send error: tag: "<<msgtag<<" to: "<<taskID<<endl;
02437                         systemError("PVM init send error.");
02438                         return false;
02439                 }
02440         #endif //PVM_DEBUG
02441 
02442         //Pack the neuron ID
02443         info = pvm_pkuint(&neuronID, 1, 1);
02444         #ifdef PVM_DEBUG
02445                 if(info < 0){
02446                         cerr<<"SpikeStreamSimulation: ERROR PACKING UNSIGNED INT INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02447                         systemError("ERROR PACKING UNSIGNED INT INTO MESSAGE.");
02448                         return false;
02449                 }
02450         #endif //PVM_DEBUG
02451 
02452         //Pack the time
02453         double currTim = simulationClock->getSimulationTime();
02454         info = pvm_pkdouble(&currTim, 1, 1);
02455         #ifdef PVM_DEBUG
02456                 if(info < 0){
02457                         cerr<<"SpikeStreamSimulation: ERROR PACKING DOUBLE INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02458                         systemError("ERROR PACKING DOUBLE INTO MESSAGE.");
02459                         return false;
02460                 }
02461         #endif //PVM_DEBUG
02462 
02463         //Pack the length of the double array
02464         info = pvm_pkint(&arrayLength, 1, 1);
02465         #ifdef PVM_DEBUG
02466                 if(info < 0){
02467                         cerr<<"SpikeStreamSimulation: ERROR PACKING DOUBLE ARRAY LENGTH INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02468                         systemError("ERROR PACKING FLOAT ARRAY LENGTH INTO MESSAGE.");
02469                         return false;
02470                 }
02471         #endif //PVM_DEBUG
02472 
02473         //Pack the double array
02474         info = pvm_pkdouble(dataArray, arrayLength, 1);
02475         #ifdef PVM_DEBUG
02476                 if(info < 0){
02477                         cerr<<"SpikeStreamSimulation: ERROR PACKING DOUBLE ARRAY INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02478                         systemError("ERROR PACKING DOUBLE ARRAY INTO MESSAGE.");
02479                         return false;
02480                 }
02481         #endif //PVM_DEBUG
02482 
02483         //Send the message
02484         info = pvm_send(taskID, msgtag);
02485         #ifdef PVM_DEBUG
02486                 if(info<0){
02487                         cerr<<"SpikeStreamSimulation: Message send error: tag: "<<msgtag<<" to: "<<taskID<<endl;
02488                         systemError("PVM message send error.");
02489                         return false;
02490                 }
02491         #endif //PVM_DEBUG
02492         return true;
02493 }
02494 
02495 /*! Sends a message containing an unsigned integer followed by a float array. */
02496 bool SpikeStreamSimulation::sendSynapseData(int taskID, int msgtag, unsigned int fromNeurID, unsigned int toNeurID, double* dataArray, int arrayLength){
02497         //Initialise the buffer
02498         int info = pvm_initsend(PvmDataDefault);
02499         #ifdef PVM_DEBUG
02500                 if(info<0){
02501                         cerr<<"SpikeStreamSimulation: Init send error: tag: "<<msgtag<<" to: "<<taskID<<endl;
02502                         systemError("PVM init send error.");
02503                         return false;
02504                 }
02505         #endif //PVM_DEBUG
02506 
02507         //Pack the from neuron ID
02508         info = pvm_pkuint(&fromNeurID, 1, 1);
02509         #ifdef PVM_DEBUG
02510                 if(info < 0){
02511                         cerr<<"SpikeStreamSimulation: ERROR PACKING UNSIGNED INT INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02512                         systemError("ERROR PACKING UNSIGNED INT INTO MESSAGE.");
02513                         return false;
02514                 }
02515         #endif //PVM_DEBUG
02516 
02517         //Pack the to neuron ID
02518         info = pvm_pkuint(&toNeurID, 1, 1);
02519         #ifdef PVM_DEBUG
02520                 if(info < 0){
02521                         cerr<<"SpikeStreamSimulation: ERROR PACKING UNSIGNED INT INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02522                         systemError("ERROR PACKING UNSIGNED INT INTO MESSAGE");
02523                         return false;
02524                 }
02525         #endif //PVM_DEBUG
02526 
02527         //Pack the time
02528         double currTim = simulationClock->getSimulationTime();
02529         info = pvm_pkdouble(&currTim, 1, 1);
02530         #ifdef PVM_DEBUG
02531                 if(info < 0){
02532                         cerr<<"SpikeStreamSimulation: ERROR PACKING DOUBLE INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02533                         systemError("ERROR PACKING DOUBLE INTO MESSAGE.");
02534                         return false;
02535                 }
02536         #endif //PVM_DEBUG
02537 
02538         //Pack the length of the double array
02539         info = pvm_pkint(&arrayLength, 1, 1);
02540         #ifdef PVM_DEBUG
02541                 if(info < 0){
02542                         cerr<<"SpikeStreamSimulation: ERROR PACKING DOUBLE ARRAY LENGTH INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02543                         systemError("ERROR PACKING DOUBLE ARRAY LENGTH INTO MESSAGE");
02544                         return false;
02545                 }
02546         #endif //PVM_DEBUG
02547 
02548         //Pack the double array
02549         info = pvm_pkdouble(dataArray, arrayLength, 1);
02550         #ifdef PVM_DEBUG
02551                 if(info < 0){
02552                         cerr<<"SpikeStreamSimulation: ERROR PACKING DOUBLE ARRAY INTO MESSAGE; TASK ID = "<<thisTaskID<<endl;
02553                         systemError("ERROR PACKING DOUBLE ARRAY INTO MESSAGE");
02554                         return false;
02555                 }
02556         #endif //PVM_DEBUG
02557 
02558         //Send the message
02559         info = pvm_send(taskID, msgtag);
02560         #ifdef PVM_DEBUG
02561                 if(info<0){
02562                         cerr<<"SpikeStreamSimulation: Message send error: tag: "<<msgtag<<" to: "<<taskID<<endl;
02563                         systemError("PVM message send error.");
02564                         return false;
02565                 }
02566         #endif //PVM_DEBUG
02567         return true;
02568 }
02569 
02570 
02571 
02572 /*! Instructs the task holders to send the spike messages to the other tasks.
02573         At this point messages should have been received from all the tasks connecting
02574         to this task and all of the spikes should have been processed. However, the final
02575         state of the neurons still needs to be calculated. */
02576 void SpikeStreamSimulation::sendSpikeMessages(){
02577         /* When recording statistics, want to bring simulation to a halt after STATS_MONITORING_PERIOD
02578                 This is done by creating an error which will stop the simulation until the simulation is 
02579                 destroyed, which will print out the statistics. */
02580         #ifdef RECORD_STATISTICS
02581                 if(statisticsTimer.getTime_usec() > STATS_MONITORING_PERIOD){
02582                         statisticsTimer.stop();
02583                         systemError("Statistical monitoring period has expired");
02584                         return;
02585                 }
02586         #endif//RECORD_STATISTICS
02587 
02588         /*In noise mode, add noise to the layer either by firing neurons directly
02589                 or by changing the membrane potential using the supplied synapse weight */
02590         if(noiseEnabled){
02591                 if(directFiring_noise){//Fire a percentage of the neurons at random
02592                         if(randomPercentNoise)
02593                                 fireRandomNeurons(getRandomPercentage());
02594                         else
02595                                 fireRandomNeurons(percentNeurons_noise);
02596                 }
02597                 else{//Call changePostSynapticPotential on a random percentage of neurons
02598                         if(randomPercentNoise)
02599                                 fireRandomNeurons_synaptic(getRandomPercentage());
02600                         else
02601                                 fireRandomNeurons_synaptic(percentNeurons_noise);
02602                 }
02603         }
02604 
02605 
02606         /* In full synapse update mode, need to work through all the synapses and update them at 
02607                 each time step. Otherwise synapses should update themselves when they process a spike. 
02608                 Also need to update all neurons that these synapses are connected to.*/
02609         if(updateAllSynapses){
02610                 for( dense_hash_map<unsigned int, dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >*, hash<unsigned int> >::iterator outerIter = synapseMap.begin(); outerIter != synapseMap.end(); ++outerIter){
02611                         for(dense_hash_map<unsigned int, Synapse*, hash<unsigned int> >::iterator innerIter = outerIter->second->begin(); innerIter != outerIter->second->end(); ++innerIter){
02612                                 innerIter->second->calculateFinalState();
02613                                 neuronUpdateMap[innerIter->first] = true;
02614                         }
02615                 }
02616         }
02617 
02618         /* In event driven update mode need to work through the neurons that have received a spike to 
02619                 calculate whether they should fire or not. This can't be done as messages are received 
02620                 because the neuron could receive a lot of excitatory messages from one layer, which would 
02621                 fire it, before receiving other inhibitory messages from another layer, which would prevent 
02622                 it from firing. The only way around this  is to wait for all messages and then calculate the 
02623                 final membrane potential. */
02624 
02625         if(!updateAllNeurons){//Only update neurons that have received a spike
02626                 for(dense_hash_map<unsigned int, bool, hash<unsigned int> >::iterator iter = neuronUpdateMap.begin(); iter != neuronUpdateMap.end(); ++iter ){
02627                         neuronArray[ iter->first - startNeuronID ]->calculateFinalState();
02628                 }
02629         }
02630         /* In full neuron update mode, need to work through all the neurons and update them at 
02631                 each time step.*/
02632         else{
02633                 for(unsigned int i=0; i< numberOfNeurons; ++i)
02634                         neuronArray[i]->calculateFinalState();
02635         }
02636         //Empty the update map in all modes
02637         neuronUpdateMap.clear();
02638 
02639         
02640         /* Send monitoring data - draws graphs of data sent by neuron and synapse classes. 
02641                 In neuron monitor mode, need to extract parameters from the neuron and send them to the main application. */
02642         if(neuronMonitorMode){
02643                 for(dense_hash_map<unsigned int, bool, hash<unsigned int> >::iterator iter = neuronMonitorMap.begin(); iter != neuronMonitorMap.end(); ++iter){
02644                         //Send array of floats containing the monitoring data to the parent application
02645                         sendNeuronData(parentTaskID, MONITOR_NEURON_DATA_MSG, iter->first, neuronArray[iter->first - startNeuronID]->getMonitoringData()->dataArray, neuronArray[iter->first - startNeuronID]->getMonitoringData()->length);
02646                 }
02647         }
02648         /* In synapse monitor mode, need to extract parameters from the neuron and send them to the main application. */
02649         if(synapseMonitorMode){
02650                 for(map<unsigned int*, Synapse*, synapseKeyCompare>::iterator iter = synapseMonitorMap.begin(); iter != synapseMonitorMap.end(); ++iter){
02651                         //Send array of floats containing the monitoring data to the parent application
02652                         sendSynapseData(parentTaskID, MONITOR_SYNAPSE_DATA_MSG, iter->first[0], iter->first[1], iter->second->getMonitoringData()->dataArray, iter->second->getMonitoringData()->length);
02653                 }
02654         }
02655 
02656 
02657         /* To slow down the simulation for easy visualisation and to synchronize with external
02658                 devices, it may be necessary to sleep for a bit. */
02659         if(calculateComputeTime){
02660                 //Calculate how long this time step has taken. End time is larger than start time
02661                 gettimeofday(&endComputeTimeStruct, NULL);
02662                 timeStepComputeTime_us = 1000000 * (endComputeTimeStruct.tv_sec - startComputeTimeStruct.tv_sec) + endComputeTimeStruct.tv_usec - startComputeTimeStruct.tv_usec;
02663 
02664                 /* When using synchronized UDP, sleep behaviour depends on the interval between messages
02665                         received from the other class and whether a delay flag has been set in messages
02666                         received from the other class. */       
02667                 if( (simulationType == LIVE_SIMULATION) && (deviceManager->getDeviceType() == DeviceTypes::syncUDPNetworkInput) ){
02668                         if(deviceManager->getExternalSyncDelay() == false){//Will sleep if the other process is not sleeping
02669                                 
02670                                 //Sleep for the difference between my compute time and the external compute time
02671                                 if(deviceManager->getExternalComputeTime_us() > timeStepComputeTime_us){
02672                                         unsigned int delayAmount = (unsigned int) rint((double)(deviceManager->getExternalComputeTime_us() - timeStepComputeTime_us) / 1.0);//Could reduce sleep time by small amount to reduce overshoot
02673                                         setDelayInLastTimeStep(true);
02674                                         usleep( delayAmount );
02675                                 }
02676                                 /* Simulation is running slower than external device, so no need to sleep.*/
02677                                 else{
02678                                         setDelayInLastTimeStep(false);
02679                                 }
02680                         }
02681                         else{//Other process is sleeping, so do not want to sleep or indicate that we are sleeping
02682                                 setDelayInLastTimeStep(false);
02683                         }
02684                 }
02685 
02686                 /* Non UDP sync LIVE_SIMULATION, NO_INPUT_SIMULATION or PATTERN_SIMULATION modes.
02687                         Just have simple sleep without informing        other tasks that we are delaying.*/
02688                 else if (minTimeStepDuration_us > timeStepComputeTime_us){
02689                         //Sleep for the time difference between current time step duration and min time step duration
02690                         usleep(minTimeStepDuration_us - timeStepComputeTime_us);
02691                 }
02692 
02693                 //Get time at start of computation loop
02694                 gettimeofday(&startComputeTimeStruct, NULL);
02695         }
02696 
02697 
02698         /* Communicate with external devices. Simulation will be stopped if there
02699                 is an error with an external device. */
02700         if(simulationType == LIVE_SIMULATION){
02701                 if(deviceManager->isOutputDevice()){
02702                         if(!deviceManager->updateDevice()){//Update output device and check for errors
02703                                 simulationRunning = false;
02704                         }
02705                 }
02706                 else if(deviceManager->isInputDevice()){
02707                         if(!deviceManager->fetchData()){//Download data from input device and check for errors
02708                                 simulationRunning = false;
02709                         }
02710                 }
02711         }
02712 
02713 
02714         //Reset spike message count 
02715         spikeMessageCount = 0;
02716 
02717 
02718         /* Work through the spike task holders and send the current buffer to other tasks including
02719                 this task */
02720         for(map<int, TaskHolder*>::iterator iter = spikeTaskHolderMap.begin(); iter != spikeTaskHolderMap.end(); ++iter){
02721                 iter->second->sendSpikeMessages();
02722         }
02723 
02724 
02725         //Send firing neuron messages to external tasks
02726         neuronTaskHolder->sendFiringNeuronMessages();
02727 
02728 
02729         /* Have now sent all messages, so increase the simulation time step. */
02730         simulationClock->advance();
02731 
02732 
02733         //Deal with any messages that arrived early
02734         while(earlyMessageStack.size() > 0){
02735 
02736                 //Get early message
02737                 EarlyMessage earlyMsgPtr = earlyMessageStack.top();
02738 
02739                 //Extract the information about the early message
02740                 int msgTimeStep = earlyMsgPtr.timeStep;
02741                 int sender = earlyMsgPtr.senderTID;
02742                 int bufferID = earlyMsgPtr.bufferID;
02743 
02744                 /* Reload the receive buffer for this message. 
02745                         The set buffer method stores the current buffer. We need to store this 
02746                         buffer number so that we can delete it. */
02747                 int oldBufID = pvm_setrbuf(bufferID);
02748                 #ifdef PVM_BUFFER_DEBUG
02749                         cout<<"SendSpikeMessages1: Saving buffer with ID = "<<oldBufID<<"; Loading buffer with ID = "<<bufferID<<endl;
02750                 #endif//PVM_BUFFER_DEBUG
02751 
02752                 //Free memory from the old buffer, which we do not need.
02753                 pvm_freebuf(oldBufID);
02754                 #ifdef PVM_BUFFER_DEBUG
02755                         cout<<"SendSpikeMessages2: Deleting buffer with ID = "<<oldBufID<<endl;
02756                 #endif//PVM_BUFFER_DEBUG
02757 
02758                 /* Remove message from stack before caling processSpikeList. Otherwise in some situations, 
02759                         processSpikeList calls sendSpikeMessages, which in turn calls processSpikeList and so on */
02760                 earlyMessageStack.pop();
02761 
02762                 #ifdef MESSAGE_DEBUG
02763                         cout<<"SpikeStreamSimulation: Reloading earlier message with timestep = "<<msgTimeStep<<"; senderTID = "; printTID(sender); cout<<endl;
02764                 #endif//MESSAGE_DEBUG
02765 
02766                 //Call process spike list for this buffer
02767                 processSpikeList(sender, msgTimeStep);
02768 
02769                 //Free memory from saved buffer that we have restored to the memory
02770                 pvm_freebuf(bufferID);
02771                 #ifdef PVM_BUFFER_DEBUG
02772                         cout<<"SendSpikeMessages3: Deleting buffer with ID = "<<bufferID<<endl;
02773                 #endif//PVM_BUFFER_DEBUG
02774 
02775                 #ifdef MESSAGE_DEBUG
02776                         cout<<"SpikeStreamSimulation: Finished reloading earlier message with timestep = "<<msgTimeStep<<"; senderTID = "; printTID(sender); cout<<endl;
02777                 #endif//MESSAGE_DEBUG
02778         }
02779 
02780 
02781         //In PATTERN_SIMULATION mode, advance the pattern and fire neurons
02782         if(simulationType == PATTERN_SIMULATION){
02783                 //Change the pattern if it has been exposed for sufficient time
02784                 if(simulationClock->getTimeStep() % timeStepsPerPattern == 0)
02785                         patternManager->loadPatternData();
02786 
02787                 //Fire the neurons according to the pattern
02788                 patternManager->fireNeurons();
02789         }
02790 
02791         /*In LIVE_SIMULATION mode, update neurons from device data that was fetched
02792                 earlier. */
02793         else if(simulationType == LIVE_SIMULATION && deviceManager->isInputDevice()){
02794                 deviceManager->updateNeurons();
02795         }
02796 }
02797 
02798 
02799 /*! Used when synchronizing to an external device using UDP.
02800         Adds or deletes an entry in the SynchronizationDelay database to set whether the
02801         simulation is delaying itself for synchronization or not. Need to use a database
02802         for this to enable communiation between tasks on potentially separate machines. */
02803 void SpikeStreamSimulation::setDelayInLastTimeStep(bool dly){
02804         if(dly == delayInLastTimeStep)//Nothing has changed, so do nothing
02805                 return;
02806 
02807         try{
02808                 if(dly){//Delay has been switched on, so need to add this neuron group to Synchronization delay database
02809                         Query deviceQuery = deviceDBInterface->getQuery();
02810                         deviceQuery.reset();
02811                         deviceQuery<<"INSERT INTO SynchronizationDelay (NeuronGrpID) VALUES ( "<<neuronGrpID<<" )";
02812                         deviceQuery.execute();
02813                 }
02814                 else{
02815                         Query deviceQuery = deviceDBInterface->getQuery();
02816                         deviceQuery.reset();
02817                         deviceQuery<<"DELETE FROM SynchronizationDelay WHERE NeuronGrpID = "<<neuronGrpID;
02818                         deviceQuery.execute();
02819                 }
02820         }
02821         catch (const BadQuery& er) {// Handle any query errors
02822                 ostringstream errorStrStream;
02823                 errorStrStream<<"Bad query when setting delay in last timestep: \""<<er.what()<<"\"";
02824                 systemError(errorStrStream.str());
02825         }
02826         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
02827                 ostringstream errorStrStream;
02828                 errorStrStream<<"Exception thrown setting delay in last timestep: \""<<er.what()<<"\"";
02829                 systemError(errorStrStream.str());
02830         }
02831         catch(std::exception& er){// Catch-all for any other exceptions
02832                 ostringstream errorStrStream;
02833                 errorStrStream<<"Exception thrown setting delay in last timestep: \""<<er.what()<<"\"";
02834                 systemError(errorStrStream.str());
02835         }
02836 
02837         delayInLastTimeStep = dly;
02838 }       
02839 
02840 
02841 /*! Once neurons have been loaded, need to calculate the maximum size of the message 
02842         buffers in the task holders. This will be used to reserve space for the vectors
02843         to save increasing this at runtime. Another option would be to use arrays, but 
02844         this may not be significantly faster. */
02845 void SpikeStreamSimulation::setMaxBufferSize(){
02846         //Create map that will be used to count the number of potential messages in each buffer for each task
02847         map<int, int*> messageCountMap;
02848         
02849         //Create arrays to count number of messages in each buffer
02850         for(map<int, TaskHolder*>::iterator iter = spikeTaskHolderMap.begin(); iter != spikeTaskHolderMap.end(); ++iter){
02851                 //Create integer array to count the number of potential messages in the message buffer
02852                 messageCountMap[iter->first] = new int[NUMBER_OF_DELAY_VALUES];
02853                 //Initialise the array
02854                 for(int i=0; i<NUMBER_OF_DELAY_VALUES; ++i)
02855                         messageCountMap[iter->first][i] = 0;
02856         }
02857         
02858         //Work through neurons and calculate how many messages they could add to each buffer
02859         for(unsigned int i=0; i<numberOfNeurons; i++){
02860                 /* Iterate through each of the neuron's connection maps, counting the number of 
02861                         potential messages for each task. */
02862                 for(map<int, vector<ConnectionHolder> >::iterator taskIter = neuronArray[i]->connectionMap.begin(); taskIter != neuronArray[i]->connectionMap.end(); ++taskIter){
02863                         //Work through vector at this location in map
02864                         for(vector<ConnectionHolder>::iterator connHoldIter =  taskIter->second.begin(); connHoldIter != taskIter->second.end(); ++connHoldIter){
02865                                 messageCountMap[taskIter->first][connHoldIter->delay]++;
02866                         }
02867                 }
02868         }
02869         
02870         /* Find the largest potential message buffer size for each task holder, reserve space
02871                 in the vectors in the message buffers and delete the arrays that were created.*/
02872         for(map<int, int*>::iterator iter = messageCountMap.begin(); iter != messageCountMap.end(); ++iter){
02873                 int maxBufferSize = 0;
02874                 for(int i=0; i<NUMBER_OF_DELAY_VALUES; ++i){
02875                         if(iter->second[i] > maxBufferSize)
02876                                 maxBufferSize = iter->second[i];
02877                 }
02878                 spikeTaskHolderMap[iter->first]->setMaxBufferSize(maxBufferSize);
02879                 delete [] iter->second;
02880         }
02881 }
02882 
02883 
02884 /*! Sets the minimum duration of a time step in microseconds.
02885         Used to slow the simulation down. */
02886 void SpikeStreamSimulation::setMinTimeStepDuration(int senderTID){
02887 
02888         //Unpack the new minimum time step duration from message
02889         unsigned int tmpMinTSDuration = 0;//Unpack to a temp in case the unpacking goes wrong.
02890         info = pvm_upkuint(&tmpMinTSDuration, 1, 1);
02891         #ifdef PVM_DEBUG
02892                 if(info < 0){
02893                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING MINIMUM TIME STEP DURATION FROM MESSAGE"; 
02894                         printTID(senderTID);
02895                         cerr<<". tmpMinTSDuration = "<<tmpMinTSDuration<<endl;
02896                         systemError("ERROR UNPACKING MINIMUM TIME STEP DURATION FROM MESSAGE.");
02897                         return;
02898                 }
02899         #endif//PVM_DEBUG
02900 
02901         //Store min timestep duration
02902         minTimeStepDuration_us = tmpMinTSDuration;
02903 
02904         //Set the boolean to calculate the compute time appropriately
02905         if( (simulationType == LIVE_SIMULATION) && (deviceManager->getDeviceType() == DeviceTypes::syncUDPNetworkInput) )
02906                 calculateComputeTime = true;//In this mode will always be calculating the compute time
02907         else if(minTimeStepDuration_us > 0)
02908                 calculateComputeTime = true;//Calculate compute time if min time step duration has been set greater than 0
02909         else
02910                 calculateComputeTime = false;//Zero minimum time step duration so no point in calculating compute time
02911 }
02912 
02913 
02914 /*! Sets whether the updates of the neuron and synapse classes are event driven, or whether
02915         all neuron and/or synapse classes are updated at each time step. */
02916 void SpikeStreamSimulation::setUpdateMode(int senderTID){
02917 
02918         //Unpack the new update mode from message
02919         unsigned int newUpdateMode = 0;//Unpack to a temp in case the unpacking goes wrong.
02920         info = pvm_upkuint(&newUpdateMode, 1, 1);
02921         #ifdef PVM_DEBUG
02922                 if(info < 0){
02923                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING UPDATE MODE FROM MESSAGE"; 
02924                         printTID(senderTID);
02925                         cerr<<". newUpdateMode = "<<newUpdateMode<<endl;
02926                         systemError("ERROR UNPACKING UPDATE MODE FROM MESSAGE.");
02927                         return;
02928                 }
02929         #endif//PVM_DEBUG
02930 
02931         //Set the update mode
02932         switch(newUpdateMode){
02933                 case 1: updateAllNeurons = false; updateAllSynapses = false; break;
02934                 case 2: updateAllNeurons = true; updateAllSynapses = false; break;
02935                 case 3: updateAllNeurons = false; updateAllSynapses = true; break;
02936                 case 4: updateAllNeurons = true; updateAllSynapses = true; break;
02937                 default: systemError("Update mode not recognized: ", newUpdateMode);
02938         }
02939 }
02940 
02941 
02942 /*! Adds the neuron to the neuron monitoring map and sends back XML file that is used to 
02943         create the graphical plot of the neuron's data. */
02944 void SpikeStreamSimulation::startNeuronMonitoring(int senderTID, bool restart){
02945         //We are now in neuron monitoring mode
02946         neuronMonitorMode = true;
02947 
02948         //Unpack the id of the neuron that is to be monitored from message
02949         unsigned int neurID = 0;//Unpack to a temp in case the unpacking goes wrong.
02950         info = pvm_upkuint(&neurID, 1, 1);
02951         #ifdef PVM_DEBUG
02952                 if(info < 0){
02953                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING NEURON ID FROM MESSAGE"; 
02954                         printTID(senderTID);
02955                         cerr<<". neurID = "<<neurID<<endl;
02956                         systemError("ERROR UNPACKING NEURON ID FROM MESSAGE.");
02957                         return;
02958                 }
02959         #endif//PVM_DEBUG
02960 
02961         //Check that this is a valid key must be greater than the start neuron ID and l
02962         if( (neurID < startNeuronID) || neurID >= (startNeuronID + numberOfNeurons) ){
02963                 cerr<<"SpikeStreamSimulation: Neuron ID supplied for neuron monitoring is invalid. neurID = "<<neurID<<endl;
02964                 systemError("Neuron ID supplied for neuron monitoring is invalid.");
02965                 return;
02966         }
02967         
02968         //Add neuron id to map. If it is already monitoring this statement will have no effect.
02969         neuronMonitorMap[neurID] = true;
02970 
02971         if(!restart){
02972                 //Send XML data about the variables back to the main application
02973                 sendMessage(parentTaskID, MONITOR_NEURON_INFO_MSG, neurID, neuronArray[neurID - startNeuronID]->getMonitoringInfo().data());
02974         }
02975         //Otherwise, data will be sent at every update step
02976 }
02977 
02978 
02979 /*! Adds the synapse to the synapse monitoring map and sends back XML file that is used to 
02980         create the graphical plot of the synapse's data. */
02981 void SpikeStreamSimulation::startSynapseMonitoring(int senderTID, bool restart){
02982 
02983         //Unpack the id of the synapse that is to be monitored from message
02984         unsigned int fromNeurID = 0, toNeurID = 0;
02985         info = pvm_upkuint(&fromNeurID, 1, 1);
02986         #ifdef PVM_DEBUG
02987                 if(info < 0){
02988                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING FROM NEURON ID FROM MESSAGE"; 
02989                         printTID(senderTID);
02990                         cerr<<". neurID = "<<fromNeurID<<endl;
02991                         systemError("ERROR UNPACKING FROM NEURON ID FROM MESSAGE.");
02992                         return;
02993                 }
02994         #endif//PVM_DEBUG       
02995 
02996         info = pvm_upkuint(&toNeurID, 1, 1);
02997         #ifdef PVM_DEBUG
02998                 if(info < 0){
02999                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING FROM NEURON ID FROM MESSAGE"; 
03000                         printTID(senderTID);
03001                         cerr<<". neurID = "<<toNeurID<<endl;
03002                         systemError("ERROR UNPACKING FROM NEURON ID FROM MESSAGE.");
03003                         return;
03004                 }
03005         #endif//PVM_DEBUG
03006 
03007         //Check that this is a valid key
03008         if(synapseMap.count(fromNeurID)){
03009                 if(!synapseMap[fromNeurID]->count(toNeurID)){
03010                         cerr<<"SpikeStreamSimulation: To neuron key supplied for synapse monitoring is invalid. fromNeurID = "<<fromNeurID<<"; toNeurID = "<<toNeurID<<endl;
03011                         systemError("Key supplied for synapse monitoring is invalid.");
03012                         return;
03013                 }
03014         }
03015         else{
03016                 cerr<<"SpikeStreamSimulation: From neuron key supplied for synapse monitoring is invalid. fromNeurID = "<<fromNeurID<<"; toNeurID = "<<toNeurID<<endl;
03017                 systemError("Key supplied for synapse monitoring is invalid.");
03018                 return;
03019         }
03020 
03021         //Create array to act as key
03022         unsigned int* keyArray = new unsigned int[2];
03023         keyArray[0] = fromNeurID;
03024         keyArray[1] = toNeurID;
03025         
03026         //Add reference to synapse class to map. If it is already monitoring this statement will have no effect.
03027         synapseMonitorMap[keyArray] = (*synapseMap[fromNeurID])[toNeurID];
03028 
03029         if(!restart){
03030                 //Send XML data about the variables back to the main application
03031                 sendMessage(parentTaskID, MONITOR_SYNAPSE_INFO_MSG, fromNeurID, toNeurID, synapseMonitorMap[keyArray]->getMonitoringInfo().data());
03032         }
03033         //Otherwise, data will be sent at every update step
03034 
03035         //We are now in synapse monitoring mode
03036         synapseMonitorMode = true;
03037 }
03038 
03039 
03040 /*! In order to send a spike list, each task must have received a spike list and so unless they start
03041         sending spike lists to each other the whole thing will never begin. This method sends the current spike
03042         list to all recipients to initialise simulation. */
03043 void SpikeStreamSimulation::startSimulation(){
03044         /* When monitoring statistics, need to start a timer to monitor for a particular period.*/
03045         #ifdef RECORD_STATISTICS
03046                 if(simulationClock->getTimeStep() > 500){//Need to get neural network in stable state before doing stats
03047                         //Start timer of statistical monitoring period
03048                         statisticsTimer.start("Record statistics");
03049 
03050                         //Initialise statistics structure
03051                         statistics.neuronFireTotal = 0;
03052                         statistics.startTimeStep = simulationClock->getTimeStep();
03053                         statistics.spikeTotal = 0;
03054                 }
03055         #endif//RECORD_STATISTICS
03056 
03057         simulationRunning = true;//Simulation is now running
03058 
03059         //Only want to send initial messages once. Simulation should run continuously after that.
03060         if(!simulationStarted){
03061                 #ifdef TRANSPORT_DEBUG
03062                         cout<<"Play simulation - starting: Sending spike messages"<<endl;
03063                 #endif//TRANSPORT_DEBUG
03064 
03065                 //Send spikes
03066                 sendSpikeMessages();
03067                 
03068                 //Set simulation started to true. This information is needed in case step simulation is pressed before play
03069                 simulationStarted = true;
03070         }
03071 
03072         // Simulation has started and there should be messages ready to be sent
03073         else{
03074                 /* If all spike messages have been received, update neurons and send spike message to other tasks */
03075                 if(spikeMessageCount == spikeMessageTotal){
03076                         #ifdef TRANSPORT_DEBUG
03077                                 cout<<"Play simulation - already running: Sending spike messages"<<endl;
03078                         #endif//TRANSPORT_DEBUG
03079 
03080                         //Send spikes
03081                         sendSpikeMessages();
03082                 }
03083                 else{
03084                         #ifdef TRANSPORT_DEBUG
03085                                 cout<<"Play simulation: spikeMessageCount != spikeMessageTotal; spikeMessageCount = "<<spikeMessageCount<<"; spikeMessageTotal = "<<spikeMessageTotal<<endl;
03086                         #endif//TRANSPORT_DEBUG
03087                 }
03088         }
03089 }
03090 
03091 
03092 /*! Advances the simulation one step and then pauses it. */
03093 void SpikeStreamSimulation::stepSimulation(){
03094         //This prevents simulation from sending message when it has processed a message
03095         simulationRunning = false;
03096 
03097         //Simulation cannot be stepped unless it has started
03098         if(!simulationStarted){
03099                 #ifdef TRANSPORT_DEBUG
03100                         cout<<"Step simulation - starting up: sending spike messages"<<endl;
03101                 #endif//TRANSPORT_DEBUG
03102 
03103                 //Send spikes
03104                 sendSpikeMessages();
03105                 
03106                 //Set simulation started to true. This information is needed in case step simulation is pressed before play
03107                 simulationStarted = true;
03108         }
03109 
03110         // Simulation has started and there should be messages ready to be sent
03111         else{
03112                 /* If all spike messages have been received, update neurons and send spike message to other tasks */
03113                 if(spikeMessageCount == spikeMessageTotal){
03114                         #ifdef TRANSPORT_DEBUG
03115                                 cout<<"Step simulation - already running: sending spike messages"<<endl;
03116                         #endif//TRANSPORT_DEBUG
03117 
03118                         //Send spikes
03119                         sendSpikeMessages();
03120                 }
03121                 else{
03122                         #ifdef TRANSPORT_DEBUG
03123                                 cout<<"Step simulation - already running: not sending spike messages because spike message count less than number of Spike Messages"<<endl;
03124                         #endif//TRANSPORT_DEBUG
03125                 }
03126         }
03127 }
03128 
03129 
03130 /*! Stops the sending of monitor data for the specified neuron. */
03131 void SpikeStreamSimulation::stopNeuronMonitoring(int senderTID){
03132         //Unpack the id of the neuron that is no longer to be monitored
03133         unsigned int neurID = 0;
03134         info = pvm_upkuint(&neurID, 1, 1);
03135         #ifdef PVM_DEBUG
03136                 if(info < 0){
03137                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING NEURON ID FROM MESSAGE"; 
03138                         printTID(senderTID);
03139                         cerr<<". neurID = "<<neurID<<endl;
03140                         systemError("ERROR UNPACKING NEURON ID FROM MESSAGE.");
03141                         return;
03142                 }
03143         #endif//PVM_DEBUG
03144 
03145         //Remove neuron id from map
03146         neuronMonitorMap.erase(neurID);
03147 
03148         //Switch off neuron monitor mode if no neurons are being monitored
03149         if(neuronMonitorMap.empty())
03150                 neuronMonitorMode = false;
03151 }
03152 
03153 
03154 /*! Stops the simulation running without destroying it. When it has processed all of its 
03155         incoming spike lists it waits before sending spike messages until it receives the start simulation 
03156         message again. */
03157 void SpikeStreamSimulation::stopSimulation(){
03158         #ifdef TRANSPORT_DEBUG
03159                 cout<<"Stop simulation - setting simulationRunning to false"<<endl;
03160         #endif//TRANSPORT_DEBUG
03161 
03162         simulationRunning = false;//Prevent spike messages from being sent
03163 }
03164 
03165 
03166 /*! Stops the sending of monitoring data for the specified synapse. */
03167 void SpikeStreamSimulation::stopSynapseMonitoring(int senderTID){
03168         //Unpack the id of the synapse that is no longer to be monitored
03169         unsigned int fromNeurID = 0, toNeurID = 0;
03170         int info = pvm_upkuint(&fromNeurID, 1, 1);
03171         #ifdef PVM_DEBUG
03172                 if(info < 0){
03173                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING FROM NEURON ID FROM MESSAGE"; 
03174                         printTID(senderTID);
03175                         cerr<<". neurID = "<<fromNeurID<<endl;
03176                         systemError("ERROR UNPACKING FROM NEURON ID FROM MESSAGE.");
03177                         return;
03178                 }
03179         #endif//PVM_DEBUG
03180 
03181         info = pvm_upkuint(&toNeurID, 1, 1);
03182         #ifdef PVM_DEBUG
03183                 if(info < 0){
03184                         cerr<<"SpikeStreamSimulation: ERROR UNPACKING TO NEURON ID FROM MESSAGE"; 
03185                         printTID(senderTID);
03186                         cerr<<". neurID = "<<toNeurID<<endl;
03187                         systemError("ERROR UNPACKING TO NEURON ID FROM MESSAGE.");
03188                         return;
03189                 }
03190         #endif//PVM_DEBUG
03191 
03192         //Create an array to act as the key
03193         unsigned int tempArray[2];
03194         tempArray[0] = fromNeurID;
03195         tempArray[1] = toNeurID;
03196 
03197 //      for(map<unsigned int*, Synapse*, synapseKeyCompare>::iterator iter = synapseMonitorMap.begin()
03198 
03199 
03200         //Check key is in map
03201         if(synapseMonitorMap.count(tempArray)){
03202                 //Store the address of the key
03203                 unsigned int* tmpKey = synapseMonitorMap.find(tempArray)->first;
03204 
03205                 //Remove the address of the key array from the map
03206                 synapseMonitorMap.erase(tempArray);
03207 
03208                 //Deletes the array that is used as a key to this location in the map
03209                 delete [] tmpKey;
03210         }
03211         else{
03212                 systemError("SpikeStreamSimulation: Cannot find synapse key in map when stopping monitoring.");
03213                 cerr<<"Cannot find synapse key in map when stopping monitoring:"<<tempArray[0]<<" "<<tempArray[1]<<endl;
03214         }
03215 
03216         //Switch off synapse monitor mode if no synapses are being monitored
03217         if(synapseMonitorMap.empty())
03218                 synapseMonitorMode = false;
03219 }
03220 
03221 

Generated on Mon Sep 3 22:24:34 2007 for SpikeStream Simulation by  doxygen 1.4.4