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

SimulationManager.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   SpikeStream Application                                               *
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 "SimulationManager.h"
00025 #include "SimulationWidget.h"
00026 #include "Debug.h"
00027 #include "PVMMessages.h"
00028 #include "ConnectionType.h"
00029 #include "Utilities.h"
00030 #include "SpikeStreamMainWindow.h"
00031 
00032 //Qt includes
00033 #include <qapplication.h>
00034 #include <qmessagebox.h>
00035 #include <qtimer.h>
00036 
00037 //Other includes
00038 #include <signal.h>
00039 #include <stdio.h>
00040 #include "pvm3.h"
00041 #include <mysql++.h>
00042 #include <iostream>
00043 using namespace std;
00044 using namespace mysqlpp;
00045 
00046 
00047 //Declare static variables
00048 bool SimulationManager::stop;
00049 
00050 
00051 /*! Constructor */
00052 SimulationManager::SimulationManager(DBInterface *netDBInter, DBInterface *archDBInter, DBInterface *pattDBInter, DBInterface *devDBInter, QWidget *simWidg){
00053         //Store a reference to the DBInterface
00054         networkDBInterface = netDBInter;
00055         archiveDBInterface = archDBInter;
00056         patternDBInterface = pattDBInter;
00057         deviceDBInterface = devDBInter;
00058 
00059         //Set up a short version of this reference
00060         spikeStrApp = SpikeStreamMainWindow::spikeStreamApplication;
00061 
00062         //Store reference to parent to display progress and busy dialog
00063         simulationWidget = simWidg;
00064 
00065         //Create busy dialog
00066         busyDialog = new BusyDialog(simulationWidget, QString("Simulation"));
00067 
00068         //Graphics are not loading at this point
00069         graphicsLoading = false;
00070 
00071         //Initialise stop to true
00072         stop = true;
00073 
00074         //Initialise simulationRunning to false
00075         simulationRunning = false;
00076 
00077         //Set default max load time - should be set in config file.
00078         maxNeurDataLoadTime_sec = 200;
00079 }
00080 
00081 
00082 /*! Destructor
00083         Simulation should have been stopped by SpikeStremMainWindow before
00084         any deleting is done. Otherwise the networkDBInterface becomes unavailable for 
00085         resetting the database.*/
00086 SimulationManager::~SimulationManager(){
00087         #ifdef MEMORY_DEBUG
00088                 cout<<"DELETING SIMULATION MANAGER"<<endl;
00089         #endif//MEMORY_DEBUG
00090 }
00091 
00092 
00093 //-------------------------------------------------------------------------
00094 //------------------------- PUBLIC METHODS --------------------------------
00095 //-------------------------------------------------------------------------
00096 
00097 /*! Clears the record of a simulation error and resets the error message. */
00098 void SimulationManager::clearSimulationError(){
00099         simError = false;
00100         simulationErrorMsg = "";
00101 }
00102 
00103 
00104 /*! Stops the simulation.*/
00105 bool SimulationManager::destroySimulation(){
00106         cout<<"Destroying simulation"<<endl;
00107         //Show busy dialog
00108         busyDialog->showDialog(QString("Cleaning up simulation, please wait"));
00109 
00110         // Set stop to true to exit from run method. When this exits the simulation is cleaned up
00111         stop = true;
00112         
00113         simulationRunning = false;
00114 
00115         return true;
00116 }
00117 
00118 
00119 /*! Fires a specified neuron by sending a message to the appropriate task. */
00120 void SimulationManager::fireNeuron(unsigned int neuronGrpID, unsigned int neuronID){
00121         unsigned int tempArray[1];
00122         tempArray[0] = neuronID;
00123         sendMessage(neuronGrpTaskMap[neuronGrpID], FIRE_SPECIFIED_NEURONS_MSG, tempArray, 1);
00124 }
00125 
00126 
00127 /*! Returns whether there was an error generated during clean up of 
00128         the simulation. */
00129 bool SimulationManager::getCleanUpError(){
00130         return cleanUpError;
00131 }
00132 
00133 
00134 /*! Returns a description of errors generated during clean up of the simulation.*/
00135 QString SimulationManager::getCleanUpErrorMsg(){
00136         return cleanUpErrorMsg;
00137 }
00138 
00139 
00140 /*! Returns error messages generated during initialisation of the simulation. */
00141 QString SimulationManager::getInitErrorMsg(){
00142         return initErrorMsg;
00143 }
00144 
00145 
00146 /*! Returns errors generated during the simulation run. */
00147 QString SimulationManager::getSimulationErrorMsg(){
00148         return simulationErrorMsg;
00149 }
00150 
00151 
00152 /*! Returns true if the view weights have been saved. */
00153 bool SimulationManager::getViewWeightsSaved(){
00154         return viewWeightsSaved;
00155 }
00156 
00157 
00158 /*! Returns true if the loading of weights is complete. */
00159 bool SimulationManager::getWeightsLoaded(){
00160         return synapseWeightsLoaded;
00161 }
00162 
00163 
00164 /*! Returns true if the weights have all been saved. */
00165 bool SimulationManager::getWeightsSaved(){
00166         return weightsSaved;
00167 }
00168 
00169 
00170 /*! Initialises the simulation */
00171 StartSimRes SimulationManager::initialiseSimulation(QString archiveName, map<unsigned int, unsigned int> patternInputMap, map<unsigned int, unsigned int> deviceInOutMap, map<unsigned int, double>deviceFiringModeMap, map<const char*, unsigned int> parameterMap){
00172         //Create StartSimRes to return result of initialisation
00173         StartSimRes startSimRes;
00174         startSimRes.canceled = false;
00175         startSimRes.started = false;
00176 
00177         //Reset the error messages
00178         initErrorMsg = "";
00179         simError = false;
00180         simulationErrorMsg = "";
00181 
00182         //Show message dialog with information about what is going on
00183         QProgressDialog *progressDialog = new QProgressDialog("Starting simulation", "Cancel", 6, simulationWidget, "Creating virtual connections", true);
00184         progressDialog->setMinimumDuration(0);
00185         //Process events and quit if cancelled
00186         spikeStrApp->processEvents();
00187         if(progressDialog->wasCancelled()){
00188                 cleanUpSimulation();
00189                 startSimRes.canceled = true;
00190                 return startSimRes;
00191         }
00192 
00193         //Initialise data that might have been left over from a previous simulation
00194         archiveTaskID = -1;
00195         neuronGrpTaskMap.clear();
00196         neuronGrpTaskVector.clear();
00197 
00198         //Set weights saved to true since they are being loaded up from the database
00199         weightsSaved = true;
00200 
00201         /* Create virtual connections for all neuron groups that are not reciprocally connected
00202                 This is needed in the present version to avoid synchronization errors */
00203         if(!createTempVirtualConnections()){
00204                 initErrorMsg += "Failed to create virtual connections.\n";
00205                 cleanUpSimulation();
00206                 progressDialog->cancel();
00207                 return startSimRes;     
00208         }
00209         progressDialog->setProgress(1);
00210         progressDialog->setLabelText("Starting PVM");
00211         spikeStrApp->processEvents();
00212         if(progressDialog->wasCancelled()){
00213                 cleanUpSimulation();
00214                 startSimRes.canceled = true;
00215                 return startSimRes;
00216         }
00217 
00218         //Start pvm daemon if it is not already running
00219         if(!startPvm()){
00220                 initErrorMsg += "PVM start failed.\n";
00221                 cleanUpSimulation();
00222                 progressDialog->cancel();
00223                 return startSimRes;
00224         }
00225         progressDialog->setProgress(2);
00226         progressDialog->setLabelText("Spawning tasks");
00227         spikeStrApp->processEvents();
00228         if(progressDialog->wasCancelled()){
00229                 cleanUpSimulation();
00230                 startSimRes.canceled = true;
00231                 return startSimRes;
00232         }
00233 
00234         cout<<"Starting neuron simulation. Parent task id = "<<thisTaskID<<endl;
00235 
00236         //Spawn tasks to simulate neuron groups
00237         if(!spawnNeuronGroupTasks()){
00238                 initErrorMsg += "Spawn tasks failed.\n";
00239                 cleanUpSimulation();
00240                 progressDialog->cancel();
00241                 return startSimRes;
00242         }
00243         progressDialog->setProgress(3);
00244         progressDialog->setLabelText("Checking tasks");
00245         spikeStrApp->processEvents();
00246         if(progressDialog->wasCancelled()){
00247                 cleanUpSimulation();
00248                 startSimRes.canceled = true;
00249                 return startSimRes;
00250         }
00251 
00252         //Check that tasks have written their task id to the database
00253         if(!checkNeuronGroupTasks()){
00254                 initErrorMsg += "Launch of tasks could not be checked.\n";
00255                 cleanUpSimulation();
00256                 progressDialog->cancel();
00257                 return startSimRes;
00258         }
00259         progressDialog->setProgress(4);
00260         progressDialog->setLabelText("Loading neuron data");
00261         spikeStrApp->processEvents();
00262         if(progressDialog->wasCancelled()){
00263                 cleanUpSimulation();
00264                 startSimRes.canceled = true;
00265                 return startSimRes;
00266         }
00267 
00268         //Instruct tasks to load up neuron data
00269         StartSimRes startNeurRes = loadNeuronData(patternInputMap, deviceInOutMap, deviceFiringModeMap, parameterMap, progressDialog);
00270         if(!startNeurRes.started && !startNeurRes.canceled){//Error loading up neuron data
00271                 initErrorMsg += "Neuron data could not be loaded.\n";
00272                 cleanUpSimulation();
00273                 progressDialog->cancel();
00274                 return startSimRes;     
00275         }
00276         else if(startNeurRes.canceled){
00277                 cleanUpSimulation();
00278                 startSimRes.canceled = true;
00279                 return startSimRes;
00280         }
00281         progressDialog->setProgress(5);
00282         progressDialog->setLabelText("Starting archive task");
00283         spikeStrApp->processEvents();
00284 
00285         //Spawn the archive task to record neuron data
00286         if(!spawnArchiveTask(archiveName, parameterMap)){
00287                 initErrorMsg += "Error spawning archive task.\n";
00288                 cleanUpSimulation();
00289                 progressDialog->cancel();
00290                 return startSimRes;
00291         }
00292         
00293         //If have reached this point, simulation should have started ok
00294         #ifdef SIMULATION_LOAD_DEBUG
00295                 cout<<"Finished initialisation of simulation"<<endl;
00296         #endif//SIMULATION_LOAD_DEBUG
00297 
00298         //Start this thread running
00299         stop = false;
00300         start();
00301 
00302         //Clear progress dialog and return successful start information
00303         progressDialog->setProgress(6);
00304         spikeStrApp->processEvents();
00305         delete progressDialog;
00306         startSimRes.started = true;
00307         return startSimRes;
00308 }
00309 
00310 
00311 /*! Injects an amount of noise into a neuron group. */
00312 void SimulationManager::injectNoise(unsigned int neuronGrpID, int amount){
00313         int neurGrpTaskID = neuronGrpTaskMap[neuronGrpID];
00314         sendMessage(neurGrpTaskID, INJECT_NOISE_MSG, amount);
00315 }
00316 
00317 
00318 /*! Static method used by other classes to query whether the simulation is 
00319         initialised or not. */
00320 bool SimulationManager::isInitialised(){
00321         if (stop)
00322                 return false;
00323         return true;
00324 }
00325 
00326 
00327 /*! Returns true if the simulation is running. */
00328 bool SimulationManager::isRunning(){
00329         return simulationRunning;
00330 }
00331 
00332 
00333 /*! Instructs the tasks running neuron groups to reload their weights from the database.
00334         This task sends the reload weights instructions and then the run method is used to receive
00335         the confirmation messages, which set synapseWeightsSaved to true when they have all been received. */
00336 bool SimulationManager::loadWeights(){
00337         //Check to see if there are any tasks before continuing
00338         if(neuronGrpTaskMap.empty()){
00339                 synapseWeightsLoaded = true;
00340                 return true;
00341         }
00342 
00343         //Instruct tasks to load weights
00344         synapseWeightsLoaded = false;
00345         weightsLoadedAcknowledgementMap.clear();
00346         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00347                 bool messageSent = sendMessage(iter->second, LOAD_WEIGHTS_MSG);
00348                 if(!messageSent){
00349                         return false;
00350                 }
00351                 //Store task ids in a map to check that they have all been received
00352                 weightsLoadedAcknowledgementMap[iter->second] = false;
00353         }
00354         return true;
00355 }
00356 
00357 
00358 /*! Instructs the simulation manager to start monitoring a neuron group.
00359         This involves sending a message to the appropriate task. When the spike
00360         lists   are received they are automatically passed to the appropriate 
00361         network monitor. */
00362 void SimulationManager::monitorNeuronGroup(unsigned int neuronGrpID, bool monitorNeurons){
00363         if(isInitialised() && !graphicsLoading){//Don't want to try to send stray messages when not initialised or when graphics are loading
00364                 int neurGrpTaskID = neuronGrpTaskMap[neuronGrpID];
00365                 if(monitorNeurons)
00366                         sendMessage(neurGrpTaskID, REQUEST_FIRING_NEURON_DATA_MSG);
00367                 else
00368                         sendMessage(neurGrpTaskID, REQUEST_SPIKE_DATA_MSG);
00369         }
00370 }
00371 
00372 
00373 /*! Sends a message to a neuron group requesting an XML file containing information about
00374         the variables that are to be monitored in the neuron. Different neuron implementations
00375         have different variables, so need to get this information each time.*/
00376 bool SimulationManager::startNeuronMonitoring(unsigned int neuronGrpID, unsigned int neuronID, bool restart){
00377         if(!restart){//Do not have the neuron info
00378                 //Send message to neuron group requesting the monitor neuron information.
00379                 return sendMessage_unsigned(neuronGrpTaskMap[neuronGrpID], REQUEST_MONITOR_NEURON_INFO_MSG, neuronID);
00380         }
00381         else{//Want to restart the monitoring
00382                 return sendMessage_unsigned(neuronGrpTaskMap[neuronGrpID], START_MONITORING_NEURON_MSG, neuronID);
00383         }
00384 }
00385 
00386 
00387 /*! Sends a message to a neuron group requesting an XML file containing information about
00388         the variables that are to be monitored in the neuron. Different neuron implementations
00389         have different variables, so need to get this information each time. */
00390 bool SimulationManager::startSynapseMonitoring(unsigned int neuronGrpID, unsigned int fromNeuronID, unsigned int toNeuronID, bool restart){
00391         if(!restart){//Do not have the neuron info
00392                 //Send message to neuron group requesting the monitor neuron information.
00393                 return sendMessage(neuronGrpTaskMap[neuronGrpID], REQUEST_MONITOR_SYNAPSE_INFO_MSG, fromNeuronID, toNeuronID);
00394         }
00395         else{//Want to restart the monitoring
00396                 return sendMessage(neuronGrpTaskMap[neuronGrpID], START_MONITORING_SYNAPSE_MSG, fromNeuronID, toNeuronID);
00397         }
00398 }
00399 
00400 
00401 /*! Sends a message to a neuron group instructing it to stop sending neuron data messages. */
00402 bool SimulationManager::stopNeuronMonitoring(unsigned int neuronGrpID, unsigned int neuronID){
00403         //Send message to neuron group requesting the monitor neuron information.
00404         return sendMessage_unsigned(neuronGrpTaskMap[neuronGrpID], STOP_MONITORING_NEURON_MSG, neuronID);       
00405 }
00406 
00407 
00408 /*! Sends a message to a neuron group instructing it to stop sending neuron data messages. */
00409 bool SimulationManager::stopSynapseMonitoring(unsigned int neuronGrpID, unsigned int fromNeuronID, unsigned int toNeuronID){
00410         //Send message to neuron group requesting the monitor neuron information.
00411         return sendMessage(neuronGrpTaskMap[neuronGrpID], STOP_MONITORING_SYNAPSE_MSG, fromNeuronID, toNeuronID);       
00412 }
00413 
00414 
00415 /*! Instructs the tasks to save a tempory copy of their weights to the database so that they
00416         can be easily viewed. This could also be done by requesting the weights from a neuron group, 
00417         which would save database space, but would be more messy to implement */
00418 bool SimulationManager::saveViewWeights(){
00419         //Check to see if there are any tasks before continuing
00420         if(neuronGrpTaskMap.empty()){
00421                 viewWeightsSaved = true;
00422                 return true;
00423         }
00424 
00425         //Instruct tasks to save the weights
00426         viewWeightsSaved = false;
00427         viewWeightsSavedAcknowledgementMap.clear();
00428         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00429                 bool messageSent = sendMessage(iter->second, SAVE_VIEW_WEIGHTS_MSG);
00430                 if(!messageSent){
00431                         return false;
00432                 }
00433                 //Store task ids in a map to check that they have all been received
00434                 viewWeightsSavedAcknowledgementMap[iter->second] = false;
00435         }
00436         return true;
00437 }
00438 
00439 
00440 /*! Instructs the tasks running neuron groups to write their weights to the database.
00441         This task sends the save weights instructions and then the run method is used to receive
00442         the confirmation methods which set synapseWeightsSaved to true when they have all been received. */
00443 bool SimulationManager::saveWeights(){
00444         //Check to see if there are any tasks before continuing
00445         if(neuronGrpTaskMap.empty()){
00446                 weightsSaved = true;
00447                 return true;
00448         }
00449 
00450         //Instruct tasks to save weights
00451         weightsSaved = false;
00452         weightsSavedAcknowledgementMap.clear();
00453         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00454                 bool messageSent = sendMessage(iter->second, SAVE_WEIGHTS_MSG);
00455                 if(!messageSent){
00456                         return false;
00457                 }
00458                 //Store task ids in a map to check that they have all been received
00459                 weightsSavedAcknowledgementMap[iter->second] = false;
00460         }
00461         return true;
00462 }
00463 
00464 
00465 /*! Controls whether the simulation runs at less than its maximum speed
00466         This is done by instructing the tasks to sleep for the appropriate
00467         duration every time step. */
00468 void SimulationManager::setFrameRate(int fr){
00469         if(isInitialised()){
00470                 //Maximum frame rate, set time step sleep interval to be zero
00471                 unsigned int minTimeStepDuration;
00472                 if(fr < 0)
00473                         minTimeStepDuration = 0;
00474                 else{//Need to divide 1000000 by the frame rate to get the mimimum time step duration in microseconds
00475                         minTimeStepDuration = 1000000 / fr;
00476                 }
00477                 for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00478                         bool messageSent = sendMessage(iter->second, SET_MIN_TIMESTEP_DURATION_US_MSG, minTimeStepDuration);
00479                         if(!messageSent){
00480                                 showErrorMessage("SimulationManager: PROBLEM SENDING SET_MIN_TIMESTEP_DURATION_US_MSG MESSAGE");
00481                         }
00482                 }
00483         }
00484 }
00485 
00486 
00487 /*! Sends a message to each task instructing it to load the global parameters. */
00488 bool SimulationManager::setGlobalParameters(){
00489         if(isInitialised()){
00490                 for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00491                         bool messageSent = sendMessage(iter->second, LOAD_GLOBAL_PARAMETERS_MSG);
00492                         if(!messageSent){
00493                                 return false;
00494                         }
00495                         //Could think about checking with acknowledgement message, but this would have to be done in the run method
00496                 }
00497         }
00498         return true;
00499 }
00500 
00501 
00502 /*! Called at the end of initialisation to instruct this class that all graphics loading
00503         is complete. */
00504 //      FIXME DESIGNED TO FILTER OUT STRAY MESSAGES, BUT NOT PROPERLY TESTED YET.
00505 void SimulationManager::setGraphicsLoading(bool gl){
00506         graphicsLoading = gl;
00507 }
00508 
00509 
00510 /*! Sets the maximum time that the simulation manager will wait for tasks to load their
00511         data. */
00512 void SimulationManager::setMaxNeurDataLoadTime_sec(int mNeurDataLoadTime){
00513         maxNeurDataLoadTime_sec = mNeurDataLoadTime;
00514 }
00515 
00516 
00517 /*! Passes a reference to the monitor area to enable the simulation manager 
00518         to send spike messages to the network monitor for display.
00519         The incoming map references the network monitors by neuron group id, but 
00520         need to store them by task id so that messages can be directly routed to        
00521         them. */
00522 void SimulationManager::setNetworkMonitors(map<unsigned int, NetworkMonitor*> nwMonMap){
00523         networkMonitorMap.clear();
00524         for(map<unsigned int, NetworkMonitor*>::iterator iter = nwMonMap.begin(); iter != nwMonMap.end(); ++iter){
00525                 networkMonitorMap[neuronGrpTaskMap[iter->first]] = iter->second;
00526         }
00527 }
00528 
00529 
00530 /*! Passes a reference to the neuron monitor map to enable the simulation manager
00531         to pass data to the neuron monitors. Only pass a reference because the 
00532         contents of the map are changed each time the simulation starts. */
00533 void SimulationManager::setNeuronMonitors(map<unsigned int, MonitorDataPlotter*> *neurMonMap){
00534         neuronMonitorMap = neurMonMap;
00535 }
00536 
00537 
00538 /*! Send message to each task instructing it to load its parameters. */
00539 bool SimulationManager::setNeuronParameters(){
00540         if(isInitialised()){
00541                 for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00542                         bool messageSent = sendMessage(iter->second, LOAD_NEURON_PARAMETERS_MSG);
00543                         if(!messageSent){
00544                                 return false;
00545                         }
00546                         //Could think about checking with acknowledgement message, but this would have to be done in the run method
00547                 }
00548         }
00549         return true;
00550 }
00551 
00552 
00553 /*! Instructs each task to load its noise parameters from the database. */
00554 bool SimulationManager::setNoiseParameters(){
00555         if(isInitialised()){
00556                 for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00557                         bool messageSent = sendMessage(iter->second, LOAD_NOISE_PARAMETERS_MSG);
00558                         if(!messageSent){
00559                                 return false;
00560                         }
00561                         //Could think about checking with acknowledgement message, but this would have to be done in the run method
00562                 }
00563         }
00564         return true;
00565 }
00566 
00567 
00568 /*! Passes a reference to the neuron monitor map to enable the simulation manager
00569         to pass data to the neuron monitors. Only pass a reference because the 
00570         contents of the map are changed each time the simulation starts. */
00571 void SimulationManager::setSynapseMonitors(map<unsigned int*, MonitorDataPlotter*, synapseKeyCompare> *synMonMap){
00572         synapseMonitorMap = synMonMap;
00573 }
00574 
00575 
00576 /*! Sends a message to each task instructing it to load its synapse parameters. */
00577 bool SimulationManager::setSynapseParameters(){
00578         if(isInitialised()){
00579                 for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00580                         bool messageSent = sendMessage(iter->second, LOAD_SYNAPSE_PARAMETERS_MSG);
00581                         if(!messageSent){
00582                                 return false;
00583                         }
00584                         //Could think about checking with acknowledgement message, but this would have to be done in the run method
00585                 }
00586         }
00587         return true;
00588 }
00589 
00590 
00591 /*! Sets the update mode for the simulation.
00592         Most efficient is event-driven, but may want to update the neuron or 
00593         synapse classes every time step to simulate spontaneous behaviour. */
00594 void SimulationManager::setUpdateMode(bool updateNeurons, bool updateSynapses){
00595         unsigned int updateInt = 0;
00596         if(!updateNeurons && !updateSynapses)
00597                 updateInt = 1;
00598         else if (updateNeurons && !updateSynapses)
00599                 updateInt = 2;
00600         else if (!updateNeurons && updateSynapses)
00601                 updateInt = 3;
00602         else
00603                 updateInt = 4;
00604 
00605         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00606                 bool messageSent = sendMessage(iter->second, SET_UPDATE_MODE_MSG, updateInt);
00607                 if(!messageSent){
00608                         showErrorMessage("SimulationManager: PROBLEM SENDING SET_UPDATE_MODE MESSAGE");
00609                 }
00610         }
00611 }
00612 
00613 
00614 /*! Returns true if there has been an error in the simulation. */
00615 bool SimulationManager::simulationError(){
00616         return simError;
00617 }
00618 
00619 
00620 /*! Sends a message to the archiver instructing it to start recording. */
00621 bool SimulationManager::startRecording(){
00622         bool messageSent = sendMessage(archiveTaskID, START_ARCHIVING_MSG);
00623         if(!messageSent)
00624                 return false;
00625         return true;
00626 }
00627 
00628 
00629 /*! Sends a message to all tasks instructing them to start sending spike messages. */
00630 bool SimulationManager::startSimulation(){
00631         #ifdef TRANSPORT_DEBUG
00632                 cout<<"Transport: Start simulation"<<endl;
00633         #endif//TRANSPORT_DEBUG
00634 
00635         //Work through running tasks and send a message instructing them to start
00636         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00637                 bool messageSent = sendMessage(iter->second, START_SIMULATION_MSG);
00638                 if(!messageSent){
00639                         simulationRunning = false;
00640                         return false;
00641                 }
00642         }
00643         weightsSaved = false;//Some of the tasks could be in learning mode so weights could be changing at this point
00644         simulationRunning = true;
00645         return true;
00646 }
00647 
00648 
00649 /*! Sends messages instructing simulation to advance one step and then stop. */
00650 bool SimulationManager::stepSimulation(){
00651         #ifdef TRANSPORT_DEBUG
00652                 cout<<"Transport: Step simulation"<<endl;
00653         #endif//TRANSPORT_DEBUG
00654 
00655         //Work through running tasks and send a message instructing them to advance one step and then pause
00656         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00657                 bool messageSent = sendMessage(iter->second, STEP_SIMULATION_MSG);
00658                 if(!messageSent){
00659                         return false;
00660                 }
00661         }
00662         weightsSaved = false;//Some of the tasks could be in learning mode so weights could be changing at this point
00663         simulationRunning = false; //Simulation should have successfully stopped after step FIXME NEED A CONFIRMATION MESSAGE TO BE SURE THAT THIS IS REALLY TRUE
00664         return true;
00665 }
00666 
00667 
00668 /*! Stops monitoring a neuron group. */
00669 void SimulationManager::stopMonitoringNeuronGroup(unsigned int neuronGrpID, bool monitorNeurons){
00670         if(isInitialised() && !graphicsLoading){//Don't want to try to send stray messages when not initialised or when graphics are loading
00671                 int neurGrpTaskID = neuronGrpTaskMap[neuronGrpID];
00672                 if(monitorNeurons)
00673                         sendMessage(neurGrpTaskID, CANCEL_FIRING_NEURON_DATA_MSG);
00674                 else
00675                         sendMessage(neurGrpTaskID, CANCEL_SPIKE_DATA_MSG);
00676         }
00677 }
00678 
00679 
00680 /*! Sends a message to the archiver instructing it to stop recording spike patterns. */
00681 bool SimulationManager::stopRecording(){
00682         bool messageSent = sendMessage(archiveTaskID, STOP_ARCHIVING_MSG);
00683         if(!messageSent)
00684                 return false;
00685         return true;
00686 }
00687 
00688 
00689 /*! Sends a message to all tasks instructing them to stop sending spike messages. */
00690 bool SimulationManager::stopSimulation(){
00691         #ifdef TRANSPORT_DEBUG
00692                 cout<<"Transport: Stop simulation"<<endl;
00693         #endif//TRANSPORT_DEBUG
00694 
00695         //Work through running tasks and send a message instructing them to start
00696         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00697                 bool messageSent = sendMessage(iter->second, STOP_SIMULATION_MSG);
00698                 if(!messageSent){
00699                         return false;
00700                 }
00701         }
00702         simulationRunning = false; //Simulation has been successfully stopped FIXME NEED A CONFIRMATION MESSAGE TO BE SURE THAT THIS IS REALLY TRUE
00703         return true;
00704 }
00705 
00706 
00707 //-----------------------------------------------------------------------
00708 //---------------- PROTECTED METHODS INHERITED FROM QTHREAD -------------
00709 //-----------------------------------------------------------------------
00710 
00711 /*! Main run method. */
00712 void SimulationManager::run(){
00713         struct timeval tmout;
00714         tmout.tv_sec = 5;
00715         tmout.tv_usec = 0;
00716 
00717         #ifdef TRANSPORT_DEBUG
00718                 cout<<"Transport: run"<<endl;
00719         #endif//TRANSPORT_DEBUG
00720 
00721         while(!stop){
00722                 //Timeout receive - waiting for message from other task.
00723                 int bufID = pvm_trecv(-1, -1, &tmout);
00724                 if(bufID < 0)
00725                         cerr<<"Receive error: "<<bufID<<endl;
00726                 else if (bufID > 0){
00727                         int numBytes, msgtag, senderTid;
00728                         int info = pvm_bufinfo(bufID, &numBytes, &msgtag, &senderTid);//Get info about message
00729                         if(info < 0)
00730                                 pvm_perror("SimulationManager.cpp: PROBLEM GETTING BUFFER INFO");
00731                         else{
00732                                 switch(msgtag){
00733                                         case(SPIKE_LIST_MSG):
00734                                                 #ifdef MESSAGE_DEBUG
00735                                                         cout<<"Task "<<thisTaskID<<": SPIKE_LIST_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00736                                                 #endif//MESSAGE_DEBUG
00737                                                 networkMonitorMap[senderTid]->processSpikeList();
00738                                         break;
00739                                         case(FIRING_NEURON_LIST_MSG):
00740                                                 #ifdef MESSAGE_DEBUG
00741                                                         cout<<"Task "<<thisTaskID<<": FIRING_NEURON_LIST_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00742                                                 #endif//MESSAGE_DEBUG
00743                                                 networkMonitorMap[senderTid]->processFiringNeuronList();
00744                                         break;
00745                                         case(MONITOR_NEURON_INFO_MSG):
00746                                                 #ifdef MESSAGE_DEBUG
00747                                                         cout<<"Task "<<thisTaskID<<": MONITOR_NEURON_INFO_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00748                                                 #endif//MESSAGE_DEBUG
00749                                                 unpackMonitorNeuronInfo();
00750                                         break;
00751                                         case(MONITOR_NEURON_DATA_MSG):
00752                                                 #ifdef MESSAGE_DEBUG
00753                                                         cout<<"Task "<<thisTaskID<<": MONITOR_NEURON_DATA_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00754                                                 #endif//MESSAGE_DEBUG
00755                                                 unpackMonitorNeuronData();
00756                                         break;
00757                                         case(MONITOR_SYNAPSE_INFO_MSG):
00758                                                 #ifdef MESSAGE_DEBUG
00759                                                         cout<<"Task "<<thisTaskID<<": MONITOR_SYNAPSE_INFO_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00760                                                 #endif//MESSAGE_DEBUG
00761                                                 unpackMonitorSynapseInfo();
00762                                         break;
00763                                         case(MONITOR_SYNAPSE_DATA_MSG):
00764                                                 #ifdef MESSAGE_DEBUG
00765                                                         cout<<"Task "<<thisTaskID<<": MONITOR_SYNAPSE_DATA_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00766                                                 #endif//MESSAGE_DEBUG
00767                                                 unpackMonitorSynapseData();
00768                                         break;
00769                                         case(TEST_MSG):
00770                                                 #ifdef MESSAGE_DEBUG
00771                                                         cout<<"Task "<<thisTaskID<<": TEST_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00772                                                 #endif//MESSAGE_DEBUG
00773                                         break;
00774                                         case(WEIGHT_SAVE_SUCCESS_MSG):
00775                                                 #ifdef MESSAGE_DEBUG
00776                                                         cout<<"Task "<<thisTaskID<<": WEIGHT_SAVE_SUCCESS_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00777                                                 #endif//MESSAGE_DEBUG
00778                                                 updateWeightsSavedState(senderTid);
00779                                         break;
00780                                         case(VIEW_WEIGHTS_SAVE_SUCCESS_MSG):
00781                                                 #ifdef MESSAGE_DEBUG
00782                                                         cout<<"Task "<<thisTaskID<<": VIEW_WEIGHTS_SAVE_SUCCESS_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00783                                                 #endif//MESSAGE_DEBUG
00784                                                 updateViewWeightsSavedState(senderTid);
00785                                         break;
00786                                         case(LOAD_WEIGHTS_SUCCESS_MSG):
00787                                                 #ifdef MESSAGE_DEBUG
00788                                                         cout<<"Task "<<thisTaskID<<": LOAD_WEIGHTS_SUCCESS_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00789                                                 #endif//MESSAGE_DEBUG
00790                                                 updateWeightsLoadedState(senderTid);
00791                                         break;
00792                                         case(ERROR_MSG):
00793                                                 #ifdef MESSAGE_DEBUG
00794                                                         cout<<"Task "<<thisTaskID<<": ERROR_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00795                                                 #endif//MESSAGE_DEBUG
00796                                                 showErrorMessage(senderTid);
00797                                         break;
00798                                         case(INFORMATION_MSG):
00799                                                 #ifdef MESSAGE_DEBUG
00800                                                         cout<<"Task "<<thisTaskID<<": INFORMATION_MSG "<<numBytes<<" bytes received from "<<senderTid<<endl;
00801                                                 #endif//MESSAGE_DEBUG
00802                                                 showInformationMessage();
00803                                         break;
00804                                         default:
00805                                                 cerr<<"Task "<<thisTaskID<<": *UNRECOGNIZED MESSAGE* msgtag = "<<msgtag<<" size "<<numBytes<<" bytes received from "<<senderTid<<endl;
00806                                 }
00807                         }
00808                 }
00809                 else if (bufID ==0)
00810                         cout<<"Checking for messages"<<endl;//Shows that it is alive
00811         }
00812         
00813         //When it has exited the while loop need to clean up the simulation before exiting the thread
00814         cleanUpSimulation();
00815 }
00816 
00817 
00818 //------------------------------------------------------------------------
00819 //-------------------------- PRIVATE METHODS -----------------------------
00820 //------------------------------------------------------------------------
00821 
00822 /*! When all tasks have been spawned this method check that each task has entered its 
00823         task id in the Neuron Group table. */
00824 bool SimulationManager::checkNeuronGroupTasks(){
00825         try{
00826                 Query query = networkDBInterface->getQuery();
00827                 query.reset();
00828                 query<<"SELECT NeuronGrpID, TaskID FROM NeuronGroups";
00829                 Result neuronGrpRes = query.store();
00830                 for(Result::iterator neuronGrpIter = neuronGrpRes.begin(); neuronGrpIter != neuronGrpRes.end(); ++neuronGrpIter){
00831                         Row neuronGrpRow(*neuronGrpIter);
00832                         unsigned int neuronGrpID = Utilities::getUInt((std::string)neuronGrpRow["NeuronGrpID"]);
00833                         int dbTaskID = Utilities::getInt((std::string)neuronGrpRow["TaskID"]);
00834                         if(neuronGrpTaskMap[neuronGrpID] != dbTaskID){//Error somewhere, possibly because task cannot connect to database
00835                                 cerr<<"SimulationManager: TASKID NOT CORRECT IN DATABASE. ABORTING SIMULATION"<<endl;
00836                                 return false;
00837                         }
00838                 }
00839         }
00840         catch (const BadQuery& er) {// Handle any query errors
00841                 cerr<<"SimulationManager: MYSQL QUERY EXCEPTION \""<<er.what()<<"\" checking neuron group tasks."<<endl;
00842                 return false;
00843         }
00844         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00845                 cerr<<"SimulationManager: MYSQL EXCEPTION \""<<er.what()<<"\" checking neuron group tasks."<<endl;
00846                 return false;
00847         }
00848         catch(std::exception& er){// Catch-all for any other exceptions
00849                 cerr<<"SimulationManager: STD EXCEPTION \""<<er.what()<<"\" checking neuron group tasks."<<endl;
00850                 return false;
00851         }
00852         return true;
00853 }
00854 
00855 
00856 /*! Unpacks an error message received during clean up, writes it to cerr
00857         and stores it for simulation widget to display. */
00858 void SimulationManager::cleanUpErrorMsgReceived(int senderTID){
00859         //Get the length of the message
00860         unsigned int messageLength;
00861         int info = pvm_upkuint(&messageLength, 1, 1);
00862         if(info < 0){
00863                 cerr<<"SimulationManager: ERROR EXTRACTING CHAR* LENGTH"<<endl;
00864                 return;
00865         }
00866 
00867         //Unpack the message
00868         char charArray[messageLength];
00869         pvm_upkstr(charArray);
00870 
00871         //Write error message to the console
00872         cerr<<"SimulationManager: CLEAN UP ERROR MESSAGE FROM "<<senderTID<<": "<<charArray<<endl;
00873 
00874         //Add to clean up error string for display
00875         cleanUpErrorMsg += "ERROR MESSAGE FROM ";
00876         cleanUpErrorMsg += QString::number(senderTID) += ": ";
00877         cleanUpErrorMsg += charArray;
00878         cleanUpErrorMsg += "\n";
00879         cleanUpError = true;
00880 }
00881 
00882 
00883 /*! Cleans up the simulation after it has exited from the run method. */
00884 void SimulationManager::cleanUpSimulation(){
00885         #ifdef SIMULATION_CLEAN_UP_DEBUG
00886                 cout<<"SimulationManager: Cleaning up simulation"<<endl;
00887         #endif//SIMULATION_CLEAN_UP_DEBUG
00888 
00889         //Create timeout for the archiver
00890         struct timeval archiveTimeout;
00891         archiveTimeout.tv_sec = 20;//Should not take more than 20 seconds for tasks to clean up
00892         archiveTimeout.tv_usec = 0;
00893 
00894         //Timeout for ordinary tasks - runs in a loop
00895         struct timeval taskTimeout;
00896         taskTimeout.tv_sec = 0;
00897         taskTimeout.tv_usec = 200000;
00898 
00899         /* Initialise variable to record errors. Want to keep cleaning up in the 
00900                 face of errors to reduce damage and maximise information to the user. */
00901         cleanUpError = false;   
00902         cleanUpErrorMsg = "";
00903 
00904         //Instruct any started simulation tasks to exit
00905         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
00906                 #ifdef SIMULATION_CLEAN_UP_DEBUG
00907                         cout<<"Sending exit message to task "<<iter->second<<endl;
00908                 #endif//SIMULATION_CLEAN_UP_DEBUG
00909 
00910                 if(!sendMessage(iter->second, EXIT_MSG)){
00911                         cerr<<"SimulationManager: ERROR KILLING SIMULATION TASK "<<iter->second<<endl;
00912                         cleanUpErrorMsg += "Error sending exit message to simulation task. TID=";
00913                         cleanUpErrorMsg += QString::number(iter->second) += ".\n";
00914                         cleanUpError = true;
00915                 }
00916         }
00917 
00918         /* Wait for tasks to send task exited messages */
00919         vector<int> tempTaskVector = neuronGrpTaskVector;// Temporary copy of vector of taskIDs processing neuron grps
00920         int timeoutCount = 0;
00921         while(!tempTaskVector.empty()){// Need to wait for all tasks to send exit message
00922                 int bufID = pvm_trecv(-1, -1, &taskTimeout);// Blocking receive waiting for message from any task
00923                 if(bufID < 0){
00924                         cleanUpError = true;    
00925                         cleanUpErrorMsg = "RECEIVE ERROR WAITING FOR TASK_EXITED_MSG.\n";
00926                         cerr<<"SimulationManager: RECEIVE ERROR WAITING FOR TASK_EXITED_MSG."<<endl;
00927                         break;//Quit waiting for messages
00928                 }
00929                 else if (bufID == 0){
00930                         ++timeoutCount;//Receive has timed out
00931                         if(timeoutCount > 30){//30 x 200000 = 6 second timeout
00932                                 cleanUpError = true;
00933                                 cleanUpErrorMsg += "TIMEOUT WHILST WAITING FOR TASK_EXITED_MSG.\n";
00934                                 cerr<<"SimulationManager: TIMEOUT WHILST WAITING FOR TASK_EXITED_MSG."<<endl;
00935                                 break;//Quit waiting
00936                         }
00937                 }
00938                 else if (bufID > 0){
00939                         timeoutCount = 0;//Reset timeout count
00940                         int bytes, msgtag, msgTaskID;
00941                         int info = pvm_bufinfo(bufID, &bytes, &msgtag, &msgTaskID);//Get info about message
00942                         if(info < 0){
00943                                 pvm_perror("SimulationManager: PROBLEM GETTING BUFFER INFO");
00944                                 cleanUpError = true;
00945                                 cleanUpErrorMsg += "PVM ERROR GETTING BUFFER INFORMATION";
00946                         }
00947                         else{
00948                                 if(msgtag == TASK_EXITED_MSG){
00949                                         /* Work through vector and remove entry if it can be found.
00950                                                 I have done it this way to avoid potential duplicate messages from the
00951                                                 same task, which a simple count would overlook. */
00952                                         for(vector<int>::iterator iter = tempTaskVector.begin(); iter != tempTaskVector.end(); ++iter){
00953                                                 if(*iter == msgTaskID){
00954                                                         #ifdef SIMULATION_CLEAN_UP_DEBUG
00955                                                                 cout<<"Task "<<msgTaskID<<" clean up complete."<<endl;
00956                                                         #endif//SIMULATION_CLEAN_UP_DEBUG
00957                                                         tempTaskVector.erase(iter);
00958                                                         break;
00959                                                 }
00960                                         }
00961                                 }
00962                                 else if(msgtag == ERROR_MSG){
00963                                         cleanUpErrorMsgReceived(msgTaskID);
00964                                         break;
00965                                 }
00966                                 else if(msgtag == INFORMATION_MSG){
00967                                         showInformationMessage();
00968                                 }
00969                                 else{
00970                                         pvm_perror("SimulationManager: UNEXPECTED MESSAGE");
00971                                         cleanUpErrorMsg += "PVM ERROR: UNEXPECTED MESSAGE";
00972                                         cleanUpError = true;
00973                                         break;
00974                                 }
00975                         }
00976                 }
00977         }
00978 
00979         //Delete all temporary virtual connections from the database
00980         #ifdef SIMULATION_CLEAN_UP_DEBUG
00981                 cout<<"Deleting temp virtual connections from database"<<endl;
00982         #endif//SIMULATION_CLEAN_UP_DEBUG
00983 
00984         deleteTempVirtualConnections();
00985 
00986         #ifdef SIMULATION_CLEAN_UP_DEBUG
00987                 cout<<"Temporary virtual connections deleted"<<endl;
00988         #endif//SIMULATION_CLEAN_UP_DEBUG
00989         
00990         //Reset all taskIDs in Neuron Group Table to -1
00991         #ifdef SIMULATION_CLEAN_UP_DEBUG
00992                 cout<<"Resetting task ids in database"<<endl;
00993         #endif//SIMULATION_CLEAN_UP_DEBUG
00994 
00995         try {
00996                 Query query = networkDBInterface->getQuery();
00997                 query.reset();
00998                 query<<"UPDATE NeuronGroups SET TaskID = -1";
00999                 query.execute();
01000         }
01001         catch (const BadQuery& er) {// Handle any query errors
01002                 cerr<<"SimulationManager: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
01003                 cleanUpErrorMsg += "Bad query resetting task IDs.";
01004                 cleanUpError = true;
01005         }
01006         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01007                 cerr<<"SimulationManager: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
01008                 cleanUpErrorMsg += "Exception thrown resetting task IDs.";
01009                 cleanUpError = true;
01010         }
01011         catch(std::exception& er){// Catch-all for any other exceptions
01012                 cerr<<"SimulationManager: STD EXCEPTION \""<<er.what()<<"\""<<endl;
01013                 cleanUpErrorMsg += "Exception thrown resetting task IDs";
01014                 cleanUpError = true;
01015         }
01016 
01017         #ifdef SIMULATION_CLEAN_UP_DEBUG
01018                 cout<<"Task ids in database reset"<<endl;
01019         #endif//SIMULATION_CLEAN_UP_DEBUG
01020 
01021         //Send message to archive task instructing it to exit
01022         if(archiveTaskID > 0){//Check archive task id is likely to be valid
01023                 #ifdef SIMULATION_CLEAN_UP_DEBUG
01024                         cout<<"Sending message to exit archive task "<<archiveTaskID<<endl;
01025                 #endif//SIMULATION_CLEAN_UP_DEBUG
01026 
01027                 if(!sendMessage(archiveTaskID, EXIT_MSG)){
01028                         cerr<<"SimulationManager: ERROR KILLING ARCHIVE TASK "<<archiveTaskID<<endl;
01029                         cleanUpErrorMsg += "Error sending exit message to archive task. TID=";
01030                         cleanUpErrorMsg += QString::number(archiveTaskID) += ".\n";
01031                         cleanUpError = true;
01032                 }
01033                 //Check that archive task is exiting ok
01034                 #ifdef SIMULATION_CLEAN_UP_DEBUG
01035                         cout<<"Checking that archive task has cleaned up using trecv"<<endl;
01036                 #endif//SIMULATION_CLEAN_UP_DEBUG
01037 
01038                 int bufferID = pvm_trecv(archiveTaskID, -1, &archiveTimeout);
01039                 if(bufferID < 0){
01040                         pvm_perror("SimulationManager: RECEIVE ERROR WHEN KILLING ARCHIVE TASK: ");
01041                         cleanUpErrorMsg += "Error receiving confirmation of exit message from archive task. TID=";
01042                         cleanUpErrorMsg += QString::number(archiveTaskID) += ".\n";
01043                         cleanUpError = true;
01044                 }
01045                 else if (bufferID == 0){
01046                         cerr<<"SimulationManager: TIMEOUT WHILE WAITING FOR ARCHIVER TO CLEAN UP."<<endl;
01047                         cleanUpErrorMsg += "Time out while waiting for archiver to clean up. TID=";
01048                         cleanUpErrorMsg += QString::number(archiveTaskID) += ".\n";
01049                         cleanUpError = true;
01050                 }
01051                 else{
01052                         int bytes, msgtag, msgTaskID;
01053                         int info = pvm_bufinfo(bufferID, &bytes, &msgtag, &msgTaskID);//Get info about message
01054                         if(info < 0){
01055                                 pvm_perror("SimulationManager: PROBLEM GETTING BUFFER INFO");
01056                                 cleanUpError = true;
01057                                 cleanUpErrorMsg += "PVM ERROR GETTING BUFFER INFORMATION";
01058                         }
01059                         else{
01060                                 if(msgtag == TASK_EXITED_MSG){
01061                                         #ifdef SIMULATION_CLEAN_UP_DEBUG
01062                                                 cout<<"Archive task cleaned up successfully."<<endl;
01063                                         #endif//SIMULATION_CLEAN_UP_DEBUG
01064                                 }
01065                                 else if(msgtag == ERROR_MSG){
01066                                         cleanUpErrorMsg += "Error message from Archiver during clean up. TID=";
01067                                         cleanUpErrorMsg += QString::number(archiveTaskID) += ".\nArchiver should be cleaned up automatically.\n";
01068                                         cleanUpError = true;
01069                                 }
01070                                 else{
01071                                         cleanUpErrorMsg += "Unrecognized message from Archiver. TID=";
01072                                         cleanUpErrorMsg += QString::number(archiveTaskID) += ".\nArchiver should be cleaned up automatically.\n";
01073                                         cleanUpError = true;
01074                                 }
01075                         }
01076                 }
01077         }
01078 
01079         //Delete all information about tasks
01080         archiveTaskID = -1;
01081         neuronGrpTaskMap.clear();
01082         neuronGrpTaskVector.clear();
01083 
01084         //Exit from Pvm without shutting it down
01085         #ifdef SIMULATION_CLEAN_UP_DEBUG
01086                 cout<<"Exiting from PVM"<<endl;
01087         #endif//SIMULATION_CLEAN_UP_DEBUG
01088 
01089         int info = pvm_exit();
01090         if(info < 0 ){
01091                 pvm_perror("SimulationManager: ERROR EXITING FROM PVM");
01092                 cleanUpErrorMsg += "Error exiting from PVM.\n";
01093                 cleanUpError = true;
01094         }
01095 
01096         #ifdef SIMULATION_CLEAN_UP_DEBUG
01097                 if(!cleanUpError) cout<<"Successfully exited from PVM"<<endl;
01098         #endif//SIMULATION_CLEAN_UP_DEBUG
01099 
01100         //Hide dialog indicating that clean up is in progress
01101         busyDialog->hide();
01102 
01103         #ifdef SIMULATION_CLEAN_UP_DEBUG
01104                 cout<<"SimulationManager: Simulation cleaned up"<<endl;
01105         #endif//SIMULATION_CLEAN_UP_DEBUG
01106 }
01107 
01108 
01109 /*! Looks through connection group table and creates a virtual connection
01110         in the opposite direction to every connection that is not reciprocal.
01111         This makes sure that all of the simulation groups send and receive
01112         a message at each simulation time step and thus keep in step. */
01113 bool SimulationManager::createTempVirtualConnections(){
01114         /* First delete any stray temporary virtual connections in case the previous
01115                 simulation crashed */
01116         if (!deleteTempVirtualConnections())
01117                 return false;
01118 
01119         //Query the database
01120         try{
01121                 Query query = networkDBInterface->getQuery();
01122                 query<<"SELECT FromNeuronGrpID, ToNeuronGrpID FROM ConnectionGroups";
01123                 Result result = query.store();
01124                 
01125                 //Create a map to hold the connections
01126                 vector< pair<unsigned int, unsigned int> > tempConnVector;
01127                 
01128                 //Load the connections into a vector
01129                 for(Result::iterator iter = result.begin(); iter != result.end(); ++iter){
01130                         Row row(*iter);
01131                         unsigned int fromGrpID = Utilities::getUInt((std::string)row["FromNeuronGrpID"]);
01132                         unsigned int toGrpID = Utilities::getUInt((std::string)row["ToNeuronGrpID"]);
01133                         pair<unsigned int, unsigned int> tempPair;
01134                         tempPair.first = fromGrpID;
01135                         tempPair.second = toGrpID;
01136                         tempConnVector.push_back(tempPair);
01137                 }
01138         
01139                 //Work through the 
01140                 for(vector< pair<unsigned int, unsigned int> >::iterator iter1 = tempConnVector.begin(); iter1 != tempConnVector.end(); ++iter1){
01141                         //Look for a connection in which the to group = the from group and vice versa
01142                         bool reciprocalConnectionFound = false;
01143                         for(vector< pair<unsigned int, unsigned int> >::iterator iter2 = tempConnVector.begin(); iter2 != tempConnVector.end(); ++iter2){
01144                                 if(iter1->first == iter2->second && iter2->first == iter1->second){
01145                                         reciprocalConnectionFound = true;
01146                                         break;
01147                                 }
01148                         }
01149                         if(!reciprocalConnectionFound){
01150                                 query.reset();
01151                                 query<<"INSERT INTO ConnectionGroups (FromNeuronGrpID, ToNeuronGrpID, ConnType) VALUES ("<<iter1->second<<", "<<iter1->first<<", "<<ConnectionType::TempVirtual<<")";
01152                                 try{
01153                                         query.execute();
01154                                 }
01155                                 catch (const Exception& er) {// Catch-all for MySQL++ exceptions
01156                                         cerr << "MySQL++ Error: " << er.what() << endl;
01157                                         return false;
01158                                 }
01159                         }
01160                 }
01161         }
01162         catch (const BadQuery& er) {// Handle any query errors
01163                 cerr<<"SimulationManager: MYSQL QUERY EXCEPTION \""<<er.what()<<"\" creating temporary virtual connections."<<endl;
01164                 return false;
01165         }
01166         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01167                 cerr<<"SimulationManager: MYSQL EXCEPTION \""<<er.what()<<"\" creating temporary virtual connections."<<endl;
01168                 return false;
01169         }
01170         catch(std::exception& er){// Catch-all for any other exceptions
01171                 cerr<<"SimulationManager: STD EXCEPTION \""<<er.what()<<"\" creating temporary virtual connections."<<endl;
01172                 return false;
01173         }
01174         return true;
01175 }
01176 
01177 
01178 /*! Deletes all the temporary virtual connections from the connection table. */
01179 bool SimulationManager::deleteTempVirtualConnections(){
01180         try{
01181                 Query query = networkDBInterface->getQuery();
01182                 query.reset();
01183                 query<<"DELETE FROM ConnectionGroups WHERE ConnType = "<<ConnectionType::TempVirtual;
01184                 query.execute();
01185         }
01186         catch (const BadQuery& er) {// Handle any query errors
01187                 cerr<<"SimulationManager: MYSQL QUERY EXCEPTION \""<<er.what()<<"\" deleting temporary virtual connections."<<endl;
01188                 return false;
01189         }
01190         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01191                 cerr<<"SimulationManager: MYSQL EXCEPTION \""<<er.what()<<"\" deleting temporary virtual connections."<<endl;
01192                 return false;
01193         }
01194         catch(std::exception& er){// Catch-all for any other exceptions
01195                 cerr<<"SimulationManager: STD EXCEPTION \""<<er.what()<<"\" deleting temporary virtual connections."<<endl;
01196                 return false;
01197         }
01198         return true;
01199 }
01200 
01201 
01202 /*! Diplays and records error messages received during initialisation of the
01203         simulation. */
01204 void SimulationManager::initErrorMsgReceived(int senderTID){
01205         //Get the length of the message
01206         unsigned int messageLength;
01207         int info = pvm_upkuint(&messageLength, 1, 1);
01208         if(info < 0){
01209                 cerr<<"SimulationManager: ERROR EXTRACTING CHAR* LENGTH."<<endl;
01210                 return;
01211         }
01212 
01213         //Unpack the message
01214         char charArray[messageLength];
01215         info = pvm_upkstr(charArray);
01216         if(info < 0){
01217                 cerr<<"SimulationManager: ERROR UNPACKING CHAR* MESSAGE."<<endl;
01218                 return;
01219         }
01220 
01221         //Write error message to the console
01222         cerr<<"SimulationManager: INIT ERROR MESSAGE FROM "<<senderTID<<": "<<charArray<<endl;
01223 
01224         //Add to initErrorMsg string for display
01225         initErrorMsg += "ERROR MESSAGE FROM ";
01226         initErrorMsg += QString::number(senderTID) += ": ";
01227         initErrorMsg += charArray;
01228         initErrorMsg += "\n";
01229 }
01230 
01231 
01232 /*! Instructs tasks to load up their data. */
01233 StartSimRes SimulationManager::loadNeuronData(map<unsigned int, unsigned int> patternInputMap, map<unsigned int, unsigned int> deviceInOutMap, map<unsigned int, double>deviceFiringModeMap, map<const char*, unsigned int> parameterMap, QProgressDialog* progressDialog){
01234         //Initialise result of this operation
01235         StartSimRes startSimRes;
01236         startSimRes.canceled = false;
01237         startSimRes.started = false;
01238 
01239         /* Create a timeout to detect if neuronsimulation task does not load neuron data within 
01240                 a specified time. */
01241         struct timeval timeout;
01242         timeout.tv_sec = 0;
01243         timeout.tv_usec = 200000;//Runs in a loop checking for messages every 0.2 seconds
01244 
01245         //Work through running tasks and send a message instructing them to load neuron data
01246         for(map<unsigned int, int>::iterator iter = neuronGrpTaskMap.begin(); iter != neuronGrpTaskMap.end(); ++iter){
01247                 /* See if this neuron group receives an input or is connected to an output.
01248                         Within a single simulation type some layers may be running with an input or 
01249                         pattern and others with no input */
01250                 if(patternInputMap.count(iter->first) > 0){//Determine what type of simulation it is and pack message appropriately
01251                         int numberOfPatternParameters = 3;
01252                         unsigned int parameterArray[numberOfPatternParameters];
01253                         parameterArray[0] = PATTERN_SIMULATION;
01254                         parameterArray[1] = patternInputMap[iter->first]; //Pattern ID
01255                         parameterArray[2] = parameterMap["TimeStepsPerPattern"];
01256                         bool messageSent = sendMessage(iter->second, LOAD_SIMULATION_DATA_MSG, parameterArray, numberOfPatternParameters);
01257                         if(!messageSent)
01258                                 return startSimRes;
01259                 }
01260                 else if(deviceInOutMap.count(iter->first) > 0){
01261                         int numberOfLiveParameters = 3;
01262                         unsigned int parameterArray[numberOfLiveParameters];
01263                         parameterArray[0] = LIVE_SIMULATION;
01264                         parameterArray[1] = deviceInOutMap[iter->first];//Device ID
01265                         /*Convert firing mode to unsigned int to save messing around with separate doubles etc.
01266                                 Need to reverse this procedure when unpacking the firing mode. */
01267                         double tmpDevFiringMode = deviceFiringModeMap[iter->first];//Number between -1 and OUTPUT_FIRING_MODE with 0.1 resolution
01268                         tmpDevFiringMode += 1.0;//Number between 0 and OUTPUT_FIRING_MODE with 0.1 resolution
01269                         tmpDevFiringMode *= 10.0;//Number between 0 and OUTPUT_FIRING_MODE with 1 resolution
01270                         parameterArray[2] = (unsigned int)rint(tmpDevFiringMode);
01271                         bool messageSent = sendMessage(iter->second, LOAD_SIMULATION_DATA_MSG, parameterArray, numberOfLiveParameters);
01272                         if(!messageSent)
01273                                 return startSimRes;
01274                 }
01275                 else{//Neuron group is not connected to anything so it is running in no input mode
01276                         int numberOfNoInputParameters = 1;
01277                         unsigned int parameterArray[numberOfNoInputParameters];
01278                         parameterArray[0] = NO_INPUT_SIMULATION;
01279                         bool messageSent = sendMessage(iter->second, LOAD_SIMULATION_DATA_MSG, parameterArray, numberOfNoInputParameters);
01280                         if(!messageSent)
01281                                 return startSimRes;
01282                 }
01283 
01284                 //Process events and quit if cancelled
01285                 spikeStrApp->processEvents();
01286                 if(progressDialog->wasCancelled()){
01287                         startSimRes.canceled = true;
01288                         return startSimRes;
01289                 }
01290         }
01291         
01292         /* Wait for tasks to send loading complete message */
01293         vector<int> tempTaskVector = neuronGrpTaskVector;// Temporary copy of vector of taskIDs processing neuron grps
01294 
01295         //Set up timer to check for messages every 0.2 seconds
01296         timeout.tv_sec = 0;
01297         timeout.tv_usec = 200000;
01298 
01299         //Count how many timeouts we have done - throw an error when timeoutCount / 5 > maxNeurDataLoadTime_sec
01300         int timeoutCount = 0;
01301         while(!tempTaskVector.empty()){// Need to wait for all tasks to load
01302                 int bufID = pvm_trecv(-1, -1, &timeout);// Blocking receive waiting for message from any task
01303                 if(bufID < 0){
01304                         cerr<<"SimulationManager: RECEIVE ERROR: "<<bufID<<endl;
01305                         return startSimRes;
01306                 }
01307                 else if (bufID == 0){
01308                         //Process events and quit if cancelled
01309                         spikeStrApp->processEvents();
01310                         if(progressDialog->wasCancelled()){
01311                                 startSimRes.canceled = true;
01312                                 return startSimRes;
01313                         }
01314                         ++timeoutCount;
01315                         if(( timeoutCount / 5) > maxNeurDataLoadTime_sec){
01316                                 initErrorMsg += "TIMEOUT WHILST LOADING NEURON DATA.\n";
01317                                 cerr<<"SimulationManager: TIMEOUT WHILST WAITING FOR LOADING COMPLETE MESSAGES"<<endl;
01318                                 return startSimRes;
01319                         }
01320                 }
01321                 else if (bufID > 0){
01322                         timeoutCount = 0;//Reset timeout count
01323                         int bytes, msgtag, msgTaskID;
01324                         int info = pvm_bufinfo(bufID, &bytes, &msgtag, &msgTaskID);//Get info about message
01325                         if(info < 0)
01326                                 pvm_perror("SimulationManager: PROBLEM GETTING BUFFER INFO");
01327                         else{
01328                                 if(msgtag == SIMULATION_LOADING_COMPLETE_MSG){
01329                                         /* Work through vector and remove entry if it can be found.
01330                                                 I have done it this way to avoid potential duplicate messages from the
01331                                                 same task, which a simple count would overlook. */
01332                                         for(vector<int>::iterator iter = tempTaskVector.begin(); iter != tempTaskVector.end(); ++iter){
01333                                                 if(*iter == msgTaskID){
01334                                                         #ifdef SIMULATION_LOAD_DEBUG
01335                                                                 cout<<"Task "<<msgTaskID<<" loading complete"<<endl;
01336                                                         #endif//SIMULATION_LOAD_DEBUG
01337                                                         tempTaskVector.erase(iter);
01338                                                         break;
01339                                                 }
01340                                         }
01341                                 }
01342                                 else if(msgtag == ERROR_MSG){
01343                                         initErrorMsgReceived(msgTaskID);
01344                                         return startSimRes;
01345                                 }
01346                                 else if(msgtag == INFORMATION_MSG){
01347                                         showInformationMessage();
01348                                 }
01349                                 else{
01350                                         pvm_perror("SimulationManager: UNEXPECTED MESSAGE");
01351                                         return startSimRes;
01352                                 }
01353                         }
01354                 }
01355         }
01356         startSimRes.started = true;
01357         return startSimRes;
01358 }
01359 
01360 
01361 /*! Sends a message that does not contain data. */
01362 bool SimulationManager::sendMessage(int taskID, int msgtag){
01363         int bufID = pvm_initsend(PvmDataDefault);
01364         if(bufID<0){
01365                 cerr<<"SimulationManager: Init send error: "<<endl;
01366                 return false;
01367         }
01368         int info = pvm_send(taskID, msgtag);
01369         if(info < 0){
01370                 cerr<<"SimulationManager: MESSAGE SENDING ERROR TO "<<taskID<<" WITH MSGTAG "<<msgtag<<endl;
01371                 return false;
01372         }
01373         return true;
01374 }
01375 
01376 
01377 /*! Sends a message containing a single integer. */
01378 bool SimulationManager::sendMessage(int taskID, int msgtag, int msgData){
01379         //Initialise buffer
01380         int bufID = pvm_initsend(PvmDataDefault);
01381         if(bufID<0){
01382                 cerr<<"SimulationManager: Init send error: "<<endl;
01383                 return false;
01384         }
01385 
01386         //Pack unsigned int data
01387         int info = pvm_pkint(&msgData, 1, 1);
01388         if(info < 0){
01389                 cerr<<"SimulationManager: ERROR PACKING UNSIGNED INT INTO MESSAGE"<<endl;
01390                 return false;
01391         }
01392 
01393         //Send message
01394         info = pvm_send(taskID, msgtag);
01395         if(info < 0){
01396                 cerr<<"SimulationManager: MESSAGE SENDING ERROR TO "<<taskID<<" WITH MSGTAG "<<msgtag<<endl;
01397                 return false;
01398         }
01399         return true;
01400 }
01401 
01402 
01403 /*! Sends a message containing a single unsigned integer. */
01404 bool SimulationManager::sendMessage_unsigned(int taskID, int msgtag, unsigned int msgData){
01405         //Initialise buffer
01406         int bufID = pvm_initsend(PvmDataDefault);
01407         if(bufID<0){
01408                 cerr<<"SimulationManager: Init send error: "<<endl;
01409                 return false;
01410         }
01411 
01412         //Pack unsigned int data
01413         int info = pvm_pkuint(&msgData, 1, 1);
01414         if(info < 0){
01415                 cerr<<"SimulationManager: ERROR PACKING UNSIGNED INT INTO MESSAGE"<<endl;
01416                 return false;
01417         }
01418 
01419         //Send message
01420         info = pvm_send(taskID, msgtag);
01421         if(info < 0){
01422                 cerr<<"SimulationManager: MESSAGE SENDING ERROR TO "<<taskID<<" WITH MSGTAG "<<msgtag<<endl;
01423                 return false;
01424         }
01425         return true;
01426 }
01427 
01428 
01429 /*! Sends a message containing two integers. */
01430 bool SimulationManager::sendMessage(int taskID, int msgtag, unsigned int msgData1, unsigned int msgData2){
01431         //Initialise buffer
01432         int bufID = pvm_initsend(PvmDataDefault);
01433         if(bufID<0){
01434                 cerr<<"SimulationManager: Init send error: "<<endl;
01435                 return false;
01436         }
01437 
01438         //Pack unsigned int data
01439         int info = pvm_pkuint(&msgData1, 1, 1);
01440         if(info < 0){
01441                 cerr<<"SimulationManager: ERROR PACKING UNSIGNED INT INTO MESSAGE"<<endl;
01442                 return false;
01443         }
01444         info = pvm_pkuint(&msgData2, 1, 1);
01445         if(info < 0){
01446                 cerr<<"SimulationManager: ERROR PACKING UNSIGNED INT INTO MESSAGE"<<endl;
01447                 return false;
01448         }
01449 
01450         //Send message
01451         info = pvm_send(taskID, msgtag);
01452         if(info < 0){
01453                 cerr<<"SimulationManager: MESSAGE SENDING ERROR TO "<<taskID<<" WITH MSGTAG "<<msgtag<<endl;
01454                 return false;
01455         }
01456         return true;
01457 }
01458 
01459 
01460 /*! Sends a message with an array of unsigned integers. */
01461 bool SimulationManager::sendMessage(int taskID, int msgtag, unsigned int *uIntArray, int arrayLength){
01462         //Initialise buffer
01463         int bufID = pvm_initsend(PvmDataDefault);
01464         if(bufID<0){
01465                 pvm_perror("SimulationManager: INIT SEND ERROR ");
01466                 return false;
01467         }
01468 
01469         //Pack length of the array
01470         int info = pvm_pkint(&arrayLength, 1, 1);
01471         if(info < 0){
01472                 pvm_perror("SimulationManager: ERROR PACKING ARRAY LENGTH INTO MESSAGE");
01473                 return false;
01474         }
01475 
01476         //Pack unsigned int array data
01477         info = pvm_pkuint(uIntArray, arrayLength, 1);
01478         if(info < 0){
01479                 pvm_perror("SimulationManager: ERROR PACKING UNSIGNED INT ARRAY INTO MESSAGE");
01480                 return false;
01481         }
01482 
01483         //Send message
01484         info = pvm_send(taskID, msgtag);
01485         if(info < 0){
01486                 cerr<<"SimulationManager: MESSAGE SENDING ERROR TO "<<taskID<<" WITH MSGTAG "<<msgtag<<endl;
01487                 return false;
01488         }
01489         return true;
01490 }
01491 
01492 
01493 /*! Sends a message with an array of doubles . */
01494 bool SimulationManager::sendMessage(int taskID, int msgtag, double doubleArray [], int arrayLength){
01495         //Initialise buffer
01496         int bufID = pvm_initsend(PvmDataDefault);
01497         if(bufID<0){
01498                 cerr<<"SimulationManager: Init send error: "<<endl;
01499                 return false;
01500         }
01501 
01502         //Pack double data
01503         int info = pvm_pkdouble(doubleArray, arrayLength, 1);
01504         if(info < 0){
01505                 cerr<<"SimulationManager: ERROR PACKING DOUBLES INTO MESSAGE"<<endl;
01506                 return false;
01507         }
01508 
01509         //Send message
01510         info = pvm_send(taskID, msgtag);
01511         if(info < 0){
01512                 cerr<<"SimulationManager: MESSAGE SENDING ERROR TO "<<taskID<<" WITH MSGTAG "<<msgtag<<endl;
01513                 return false;
01514         }
01515         return true;
01516 }
01517 
01518 
01519 /*! Unpacks an error message, writes it to cerr and records that an error message
01520         has been received. Only the first error message is recorded to prevent a large
01521         number of duplicates. */
01522 void SimulationManager::showErrorMessage(int senderTID){
01523         //Get the length of the message
01524         unsigned int messageLength;
01525         int info = pvm_upkuint(&messageLength, 1, 1);
01526         if(info < 0){
01527                 cerr<<"SimulationManager: ERROR EXTRACTING CHAR* LENGTH"<<endl;
01528                 return;
01529         }
01530         //Unpack the message
01531         char charArray[messageLength];
01532         pvm_upkstr(charArray);
01533 
01534         //Write error message to the console
01535         cerr<<"ERROR MESSAGE FROM "<<senderTID<<". MESSAGE: "<<charArray<<endl;
01536 
01537         /* Only add to string if it is the first message. 
01538                 Otherwise could get large number of errors arriving in between 
01539                 checks when the first one is the most important */
01540         if(!simError){
01541                 simulationErrorMsg += "ERROR MESSAGE FROM ";
01542                 simulationErrorMsg += QString::number(senderTID) += ": ";
01543                 simulationErrorMsg += charArray;
01544                 simulationErrorMsg += "\n";
01545         }
01546 
01547         //Flag the error
01548         simError = true;
01549 }
01550 
01551 
01552 /*! Called from within this class when an error has been generated.
01553         Only the first error message is recorded to prevent a large
01554         number of duplicates. */
01555 void SimulationManager::showErrorMessage(const char* msg){
01556         //Write error message to the console
01557         cerr<<msg<<endl;
01558 
01559         /* Add to error message for display if it is the first error message
01560                 Otherwise a large number of error messages could become unmanageable */
01561         if(!simError){
01562                 simulationErrorMsg += msg;
01563                 simulationErrorMsg += "\n";
01564         }
01565         
01566         //Flag the error
01567         simError = true;
01568 }
01569 
01570 
01571 /*! Unpacks an information message and writes it to system out. */
01572 void SimulationManager::showInformationMessage(){
01573         //Get the length of the message
01574         unsigned int messageLength;
01575         int info = pvm_upkuint(&messageLength, 1, 1);
01576         if(info < 0){
01577                 cerr<<"SimulationManager: ERROR EXTRACTING CHAR* LENGTH"<<endl;
01578                 return;
01579         }
01580 
01581         //Unpack the message
01582         char charArray[messageLength];
01583         pvm_upkstr(charArray);
01584 
01585         //Write the message to the console
01586         cout<<charArray<<endl;
01587 }
01588 
01589 
01590 /*! Spawns the archive task with the information it needs. */
01591 bool SimulationManager::spawnArchiveTask(const QString &archiveName, map<const char*, unsigned int> parameterMap){
01592         //Set up char array to hold command line arguments for tasks
01593         DBParameters neuralNetworkDBParameters = networkDBInterface->getDBParameters();
01594         char *commandLineArray[21];
01595         //Add parameters for nerual network database
01596         commandLineArray[0] = "-nnh";//neural network DB host
01597         commandLineArray[1] = neuralNetworkDBParameters.host;
01598         commandLineArray[2] = "-nnu";//neural network DB user
01599         commandLineArray[3] = neuralNetworkDBParameters.user;
01600         commandLineArray[4] = "-nnp";//neural network DB password
01601         commandLineArray[5] = neuralNetworkDBParameters.password;
01602         commandLineArray[6] = "-nnd";//neural network DB database
01603         commandLineArray[7] = neuralNetworkDBParameters.database;
01604 
01605         //Add parameters for archive database
01606         DBParameters archiveDBParameters = archiveDBInterface->getDBParameters();
01607         commandLineArray[8] = "-ah";//archive DB host
01608         commandLineArray[9] = archiveDBParameters.host;
01609         commandLineArray[10] = "-au";//archive DB user
01610         commandLineArray[11] = archiveDBParameters.user;
01611         commandLineArray[12] = "-ap";//archive DB password
01612         commandLineArray[13] = archiveDBParameters.password;
01613         commandLineArray[14] = "-ad";//archive DB database
01614         commandLineArray[15] = archiveDBParameters.database;
01615         
01616         //Add parameter to specify the archive name
01617         commandLineArray[16] = "-an";//archive name
01618         const char* archNameChar = archiveName.ascii(); 
01619         int archNameLength = strlen(archNameChar);
01620         commandLineArray[17] = new char[archNameLength + 1];//Allow space for terminating character which is not counted by strlen
01621         try{
01622                 Utilities::safeCStringCopy(commandLineArray[17], archNameChar, archNameLength);
01623         }
01624         catch(std::exception& er){
01625                 cerr<<"SimulationManager: Exception thrown copying archive name: \""<<er.what()<<"\""<<endl;
01626                 return false;
01627         }
01628 
01629         //Determine whether to monitor spikes or firing neurons
01630         commandLineArray[18] = "-at";//Type of monitoring
01631         if(parameterMap.find("ArchiveFiringNeurons") != parameterMap.end()){
01632                 commandLineArray[19] = "Neurons";
01633         }
01634         else if(parameterMap.find("ArchiveSpikes") != parameterMap.end()){
01635                 commandLineArray[19] = "Spikes";
01636         }
01637         else{
01638                 cerr<<"SimulationManager. CANNOT FIND ARCHIVE SPIKES/FIRING NEURONS PARAMETER"<<endl;
01639                 return false;
01640         }
01641 
01642         //Finish off
01643         commandLineArray[20] = '\0';
01644 
01645         //Spawn task to handle archive
01646         int newTaskID;
01647         int numTasksLaunched = pvm_spawn("spikestreamarchiver", commandLineArray, 0, "", 1, &newTaskID);
01648                 
01649         // Check that task has launched
01650         if (numTasksLaunched == 1) {
01651                 //Store task ID
01652                 archiveTaskID = newTaskID;
01653                 
01654                 //Wait for a confirmation message that task has launched
01655                 #ifdef LAUNCH_TASKS_DEBUG
01656                         cout<<"SimulationManager: Archive task "<<newTaskID<<" spawned, waiting for confirmation."<<endl;
01657                 #endif//LAUNCH_TASKS_DEBUG
01658 
01659                 //If archive task does not launch in 30 seconds, there is almost certainly an error
01660                 struct timeval timeout;
01661                 timeout.tv_sec = 60;
01662                 timeout.tv_usec = 0;
01663                 
01664                 //Blocking receive - waiting for message from other task
01665                 int bufID = pvm_trecv(newTaskID, -1, &timeout);
01666                 if(bufID < 0){
01667                         cerr<<"SimulationManager: RECEIVE ERROR STARTING ARCHIVE TASK: "<<bufID<<endl;
01668                         return false;
01669                 }
01670                 else if(bufID == 0){
01671                         cerr<<"SimulationManager: ATTEMPT TO START ARCHIVE TASK HAS TIMED OUT"<<endl;
01672                         return false;
01673                 }
01674                 else{//Check that task has started ok or unpack error message.
01675                         int bytes, msgtag, msgTaskID;
01676                         int info = pvm_bufinfo(bufID, &bytes, &msgtag, &msgTaskID);//Get info about message
01677                         if(info < 0){
01678                                 pvm_perror("SimulationManager: PROBLEM GETTING BUFFER INFO FOR ARCHIVE TASK");
01679                                 return false;
01680                         }
01681                         else{//Determine the type of message from the new task.
01682                                 if(msgtag == ARCHIVE_TASK_STARTED_MSG){
01683                                         /* Unpack the simulation start time from the message. 
01684                                                 This is used to prevent the current archive from being deleted by the archive widget */
01685                                         unsigned int simulationStartTime = 0;
01686                                         int info = pvm_upkuint(&simulationStartTime, 1, 1);
01687                                         if(info < 0){
01688                                                 cerr<<"SimulationManager: ERROR UNPACKING SIMULATION START TIME; TASK ID = "<<pvm_mytid()<<"; simulationStartTime =  "<<simulationStartTime<<endl;
01689                                                 return false;
01690                                         }
01691 
01692                                         /* Inform other classes that the simulation start time has changed.
01693                                                 This method should only be called within the main application thread so do not need to lock mutex.*/
01694                                         emit simulationStartTimeChanged(simulationStartTime);
01695                         
01696                                         //If this point is reached, everything should be ok.
01697                                         #ifdef LAUNCH_TASKS_DEBUG
01698                                                 cout<<"SimulationManager: Archive task "<<newTaskID<<" started."<<endl;
01699                                         #endif//LAUNCH_TASKS_DEBUG
01700                                 }
01701                                 else if(msgtag == ERROR_MSG){
01702                                         initErrorMsgReceived(msgTaskID);//Display error message
01703                                         #ifdef LAUNCH_TASKS_DEBUG
01704                                                 cout<<"SimulationManager: Archive task "<<newTaskID<<" started with errors."<<endl;
01705                                         #endif//LAUNCH_TASKS_DEBUG
01706                                         return false;
01707                                 }
01708                                 else{//Unrecognized message
01709                                         cerr<<"SimulationManager: UNEXPECTED MESSAGE FROM ARCHIVE TASK "<<newTaskID<<". MESSAGE TYPE: "<<msgtag<<endl;
01710                                         return false;
01711                                 }
01712                         }
01713                 }
01714         }
01715         else{
01716                 cerr<<"SimulationManager: CANNOT START ARCHIVE TASK"<<endl;
01717                 return false;
01718         }
01719 
01720         //Clean up memory
01721         delete commandLineArray[17];
01722 
01723         //Everything should be ok if we have reached this point.
01724         return true;
01725 }
01726 
01727 
01728 /*! Spawn task to simulate neuron group.
01729         Pass database information to tasks in the form of arguments, rather 
01730         than managing separate config files.
01731         Each spawned task writes its task id to the database, which acts as a check 
01732         that they have all successfully established database communication. */
01733 bool SimulationManager::spawnNeuronGroupTasks(){
01734         /* Create a timeout to detect if neuronsimulation task does not start within 
01735                 a specified time. */
01736         struct timeval timeout;
01737         timeout.tv_sec = 30;//Should not take more than 30 seconds to spawn a task
01738         timeout.tv_usec = 0;
01739 
01740         //Set up char array to hold command line arguments for tasks
01741         DBParameters networkDBParameters = networkDBInterface->getDBParameters();
01742         DBParameters patternDBParameters = patternDBInterface->getDBParameters();
01743         DBParameters deviceDBParameters = deviceDBInterface->getDBParameters();
01744         char *commandLineArray[27];
01745         commandLineArray[0] = "-ng";
01746         commandLineArray[1] = new char[20];//Has to be long enough to hold an integer as a string.
01747         commandLineArray[2] = "-nnh";
01748         commandLineArray[3] = networkDBParameters.host;
01749         commandLineArray[4] = "-nnu";
01750         commandLineArray[5] = networkDBParameters.user;
01751         commandLineArray[6] = "-nnp";
01752         commandLineArray[7] = networkDBParameters.password;
01753         commandLineArray[8] = "-nnd";
01754         commandLineArray[9] = networkDBParameters.database;
01755         commandLineArray[10] = "-ph";
01756         commandLineArray[11] = patternDBParameters.host;
01757         commandLineArray[12] = "-pu";
01758         commandLineArray[13] = patternDBParameters.user;
01759         commandLineArray[14] = "-pp";
01760         commandLineArray[15] = patternDBParameters.password;
01761         commandLineArray[16] = "-pd";
01762         commandLineArray[17] = patternDBParameters.database;    
01763         commandLineArray[18] = "-dh";
01764         commandLineArray[19] = deviceDBParameters.host;
01765         commandLineArray[20] = "-du";
01766         commandLineArray[21] = deviceDBParameters.user;
01767         commandLineArray[22] = "-dp";
01768         commandLineArray[23] = deviceDBParameters.password;
01769         commandLineArray[24] = "-dd";
01770         commandLineArray[25] = deviceDBParameters.database;     
01771         commandLineArray[26] = '\0';
01772 
01773 
01774         //Work through the neuron groups, spawning a new process for each group.
01775         try{
01776                 Query query = networkDBInterface->getQuery();
01777                 query.reset();
01778                 query<<"SELECT NeuronGrpID FROM NeuronGroups";
01779                 Result neuronGrpRes = query.store();
01780                 for(Result::iterator neuronGrpIter = neuronGrpRes.begin(); neuronGrpIter != neuronGrpRes.end(); ++neuronGrpIter){
01781                         int newTaskID;
01782                         Row neuronGrpRow(*neuronGrpIter);
01783                         string neuronGrpString = (std::string)neuronGrpRow["NeuronGrpID"];
01784                         Utilities::safeCStringCopy(commandLineArray[1], neuronGrpString.c_str(), 20);
01785                         
01786                         //Spawn the task
01787                         int numTasksLaunched = pvm_spawn("spikestreamsimulation", commandLineArray, 0, "", 1, &newTaskID);
01788                         
01789                         // Check that task has launched
01790                         if (numTasksLaunched == 1) {
01791                                 //Store neuronGrpIDs and task
01792                                 //These will need to be reset in the table at the end of the simulation
01793                                 unsigned int neuronGrpID = Utilities::getUInt(neuronGrpString);
01794                                 neuronGrpTaskMap[neuronGrpID] = newTaskID;
01795                                 neuronGrpTaskVector.push_back(newTaskID);
01796                         
01797                                 //Wait for a confirmation message that task has launched
01798                                 #ifdef LAUNCH_TASKS_DEBUG
01799                                         cout<<"Task "<<newTaskID<<" spawned, waiting for confirmation."<<endl;
01800                                 #endif//LAUNCH_TASKS_DEBUG
01801                         
01802                                 //Blocking receive with timeout waiting for message from other task
01803                                 //Better to check each task is up before running database check
01804                                 int bufID = pvm_trecv(newTaskID, -1, &timeout);
01805                                 if(bufID < 0){
01806                                         cerr<<"SimulationManager: RECEIVE ERROR WITH SIMULATION TASK: "<<bufID<<endl;
01807                                         return false;
01808                                 }
01809                                 else if(bufID == 0){
01810                                         cerr<<"SimulationManager: TIME OUT WHEN ATTEMPTING TO SPAWN SIMULATION TASK WITH ID: "<<neuronGrpID<<endl;
01811                                         return false;
01812                                 }
01813                                 else{
01814                                         int bytes, msgtag, msgTaskID;
01815                                         int info = pvm_bufinfo(bufID, &bytes, &msgtag, &msgTaskID);//Get info about message
01816                                         if(info < 0){
01817                                                 pvm_perror("SimulationManager: PROBLEM GETTING BUFFER INFO FOR SIMULATION TASK");
01818                                                 return false;
01819                                         }
01820                                         else{//Determine the type of message from the new task.
01821                                                 if(msgtag == SIMULATION_TASK_STARTED_MSG){
01822                                                         #ifdef LAUNCH_TASKS_DEBUG
01823                                                                 cout<<"Task "<<newTaskID<<" started for neuron group "<<neuronGrpID<<"."<<endl;
01824                                                         #endif//LAUNCH_TASKS_DEBUG
01825                                                 }
01826                                                 else if(msgtag == ERROR_MSG){
01827                                                         initErrorMsgReceived(msgTaskID);
01828                                                         #ifdef LAUNCH_TASKS_DEBUG
01829                                                                 cout<<"Task "<<newTaskID<<" started for neuron group "<<neuronGrpID<<" with errors."<<endl;
01830                                                         #endif//LAUNCH_TASKS_DEBUG
01831                                                         return false;
01832                                                 }
01833                                                 else{//Unrecognized message
01834                                                         cerr<<"SimulationManager: UNEXPECTED MESSAGE FROM SIMULATION TASK "<<newTaskID<<". MESSAGE TYPE: "<<msgtag<<endl;
01835                                                         return false;
01836                                                 }
01837                                         }
01838                                 }
01839                         }
01840                         else{
01841                                 cerr<<"SimulationManager.cpp: CANNOT START NEURON GROUP TASK"<<endl;
01842                                 return false;
01843                         }
01844                 }
01845         }
01846         catch (const BadQuery& er) {// Handle any query errors
01847                 cerr<<"SimulationManager: MYSQL QUERY EXCEPTION \""<<er.what()<<"\" spawning neuron group tasks."<<endl;
01848                 return false;
01849         }
01850         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01851                 cerr<<"SimulationManager: MYSQL EXCEPTION \""<<er.what()<<"\" spawning neuron group tasks."<<endl;
01852                 return false;
01853         }
01854         catch(std::exception& er){// Catch-all for any other exceptions
01855                 cerr<<"SimulationManager: STD EXCEPTION \""<<er.what()<<"\" spawning neuron group tasks."<<endl;
01856                 return false;
01857         }
01858 
01859         //Delete char array created to hold neuron group
01860         delete commandLineArray[1];
01861 
01862         return true;
01863 }
01864 
01865 
01866 /*! Starts pvm daemon if it is not already running. */
01867 bool SimulationManager::startPvm(){
01868         //First need to define PVM_ROOT environment variable if it is not alread defined
01869         char * pvmRoot = getenv("PVM_ROOT");
01870         if (!pvmRoot){
01871                 int putEnvRes = putenv("PVM_ROOT=/usr/lib/pvm3");
01872                 if (putEnvRes){//Returns 0 if successful
01873                         cerr<<"SimulationManager.cpp: Failed to define environment variable PVM_ROOT"<<endl;
01874                         return false;
01875                 }
01876         }
01877         
01878         //Now start pvm daemon
01879         int info = pvm_start_pvmd(0, (char **)0, 1);
01880         if(info == PvmDupHost)
01881         ;//Do nothing, pvmd3 is already running. FIXME COULD CHECK THIS BEFORE TRYING TO START UP
01882         else if(info == PvmSysErr){
01883                 cerr<<"Pvm system not responding"<<endl;
01884                 return false;
01885         }
01886 
01887         //Store the task id of this task
01888         thisTaskID = pvm_mytid();
01889         if(thisTaskID < 0){
01890                 pvm_perror("SimulationManager.cpp: TASK ID LESS THAN ZERO. STOPPING SIMULATION.");
01891                 return false;
01892         }
01893 
01894         /* Set up direct routing. This increases the available bandwidth, 
01895                 but is not scalable to more than 60 tasks */
01896         pvm_setopt( PvmRoute, PvmRouteDirect );
01897         return true;
01898 }
01899 
01900 
01901 /*! Unpacks monitoring data sent from a neuron class. */
01902 void SimulationManager::unpackMonitorNeuronData(){
01903         unsigned int tempNeuronID, numberOfVariables;
01904         double msgTime;
01905         //Get the neuron ID
01906         int info = pvm_upkuint(&tempNeuronID, 1, 1);
01907         #ifdef PVM_DEBUG
01908                 if(info < 0){
01909                         cerr<<"SimulationManager: ERROR EXTRACTING NEURON ID; TASK ID = "<<pvm_mytid()<<"; tempNeuronID: "<<tempNeuronID<<endl;
01910                         return;
01911                 }
01912         #endif//PVM_DEBUG       
01913 
01914         //Get the time of the message
01915         info = pvm_upkdouble(&msgTime, 1, 1);
01916         #ifdef PVM_DEBUG
01917                 if(info < 0){
01918                         cerr<<"SimulationManager: ERROR EXTRACTING MESSAGE TIME; TASK ID = "<<pvm_mytid()<<"; msgTime: "<<msgTime<<endl;
01919                         return;
01920                 }
01921         #endif//PVM_DEBUG
01922 
01923         // Extract the number of variables in the message
01924         info = pvm_upkuint(&numberOfVariables, 1, 1);
01925         #ifdef PVM_DEBUG
01926                 if(info < 0){
01927                         cerr<<"SimulationManager: ERROR NUMBER OF VARIABLES FROM MESSAGE; TASK ID = "<<pvm_mytid()<<"; numberOfVariables: "<<numberOfVariables<<endl;
01928                         return;
01929                 }
01930         #endif//PVM_DEBUG
01931 
01932         //Unpack the list of variables 
01933         double tempVarArray[numberOfVariables];
01934 
01935         //Unpack array of doubles
01936         info = pvm_upkdouble(tempVarArray, numberOfVariables, 1);
01937         #ifdef PVM_DEBUG
01938                 if(info < 0){
01939                         cerr<<"NetworkMonitor: ERROR UNPACKING DATA ID FROM MESSAGE. NeuronID = "<<tempNeuronID<<endl;
01940                         return;
01941                 }
01942         #endif//PVM_DEBUG
01943 
01944         //Add the data to the appropriate neuron Monitor
01945         if(neuronMonitorMap->count(tempNeuronID))
01946                 (*neuronMonitorMap)[tempNeuronID]->plotData(msgTime, tempVarArray, numberOfVariables);
01947         else{
01948                 showErrorMessage("SimulationManager: Neuron ID not found in Neuron Monitor Map when unpacking data.");
01949                 cerr<<"SimulationManager: Neuron ID not found in Neuron Monitor Map: "<<tempNeuronID<<endl;
01950         }
01951 }
01952 
01953 
01954 /*! Unpacks XML structured information about monitoring data sent from a neuron class. */
01955 void SimulationManager::unpackMonitorNeuronInfo(){
01956         unsigned int tempNeuronID, charLength;
01957 
01958         #ifdef MONITOR_NEURON_DATA_DEBUG
01959                 cout<<"SimulationManager: Monitor neuron info message received."<<endl;
01960         #endif//MONITOR_NEURON_DATA_DEBUG
01961 
01962         //Get the neuron ID
01963         int info = pvm_upkuint(&tempNeuronID, 1, 1);
01964         #ifdef PVM_DEBUG
01965                 if(info < 0){
01966                         cerr<<"SimulationManager: ERROR EXTRACTING NEURON ID; TASK ID = "<<pvm_mytid()<<"; tempNeuronID: "<<tempNeuronID<<endl;
01967                         return;
01968                 }
01969         #endif//PVM_DEBUG
01970 
01971         // Extract the length of the XML string
01972         info = pvm_upkuint(&charLength, 1, 1);
01973         #ifdef PVM_DEBUG
01974                 if(info < 0){
01975                         cerr<<"SimulationManager: ERROR EXTRACTING LENGTH OF XML STRING FROM MESSAGE; TASK ID = "<<pvm_mytid()<<"; charLength: "<<charLength<<endl;
01976                         return;
01977                 }
01978         #endif//PVM_DEBUG
01979 
01980         //Unpack the message
01981         char* charArray = new char[charLength];
01982         pvm_upkstr(charArray);
01983 
01984         //Add the data to the appropriate neuron Monitor
01985         if(neuronMonitorMap->count(tempNeuronID))
01986                 (*neuronMonitorMap)[tempNeuronID]->setUpGraphs(charArray);
01987         else{
01988                 showErrorMessage("SimulationManager: Neuron ID not found in Neuron Monitor Map when unpacking info.");
01989                 cerr<<"SimulationManager: Neuron ID not found in Neuron Monitor Map: "<<tempNeuronID<<endl;
01990         }
01991 }
01992 
01993 
01994 /*! Unpacks monitoring data sent from a synapse class. */
01995 void SimulationManager::unpackMonitorSynapseData(){
01996         unsigned int tmpFromNeurID, tmpToNeurID, numberOfVariables;
01997         double msgTime;
01998         //Get the from neuron ID
01999         int info = pvm_upkuint(&tmpFromNeurID, 1, 1);
02000         #ifdef PVM_DEBUG
02001                 if(info < 0){
02002                         cerr<<"SimulationManager: ERROR EXTRACTING FROM NEURON ID; TASK ID = "<<pvm_mytid()<<"; tmpFromNeurID: "<<tmpFromNeurID<<endl;
02003                         return;
02004                 }
02005         #endif//PVM_DEBUG       
02006 
02007         //Get the to neuron id
02008         info = pvm_upkuint(&tmpToNeurID, 1, 1);
02009         #ifdef PVM_DEBUG
02010                 if(info < 0){
02011                         cerr<<"SimulationManager: ERROR EXTRACTING TO NEURON ID; TASK ID = "<<pvm_mytid()<<"; tmpToNeurID: "<<tmpToNeurID<<endl;
02012                         return;
02013                 }
02014         #endif//PVM_DEBUG       
02015 
02016         //Get the time of the message
02017         info = pvm_upkdouble(&msgTime, 1, 1);
02018         #ifdef PVM_DEBUG
02019                 if(info < 0){
02020                         cerr<<"SimulationManager: ERROR EXTRACTING MESSAGE TIME; TASK ID = "<<pvm_mytid()<<"; msgTime: "<<msgTime<<endl;
02021                         return;
02022                 }
02023         #endif//PVM_DEBUG
02024 
02025         // Extract the number of variables in the message
02026         info = pvm_upkuint(&numberOfVariables, 1, 1);
02027         #ifdef PVM_DEBUG
02028                 if(info < 0){
02029                         cerr<<"SimulationManager: ERROR NUMBER OF VARIABLES FROM MESSAGE; TASK ID = "<<pvm_mytid()<<"; numberOfVariables: "<<numberOfVariables<<endl;
02030                         return;
02031                 }
02032         #endif//PVM_DEBUG
02033 
02034         //Unpack the list of variables 
02035         double tempVarArray[numberOfVariables];
02036 
02037         //Unpack array of doubles
02038         info = pvm_upkdouble(tempVarArray, numberOfVariables, 1);
02039         #ifdef PVM_DEBUG
02040                 if(info < 0){
02041                         cerr<<"NetworkMonitor: ERROR UNPACKING DATA ID FROM MESSAGE. tmpFromNeurID = "<<tmpFromNeurID<<" tmpToNeurID = "<<tmpToNeurID<<endl;
02042                         return;
02043                 }
02044         #endif//PVM_DEBUG
02045 
02046         //Create a key to access the synapse monitor map
02047         unsigned int tmpSynapseKey[2];
02048         tmpSynapseKey[0] = tmpFromNeurID;
02049         tmpSynapseKey[1] = tmpToNeurID;
02050 
02051         //Add the data to the appropriate neuron Monitor
02052         if(synapseMonitorMap->count(tmpSynapseKey))
02053                 (*synapseMonitorMap)[tmpSynapseKey]->plotData(msgTime, tempVarArray, numberOfVariables);
02054         else{
02055                 showErrorMessage("SimulationManager: Synapse not found in Synapse Monitor Map when unpacking data.");
02056                 cerr<<"SimulationManager: Synapse key not found in Synapse Monitor Map: "<<tmpSynapseKey[0]<<" "<<tmpSynapseKey[1]<<endl;
02057         }
02058 }
02059 
02060 
02061 /*! Unpacks XML structured information about monitoring data sent from a synapse class. */
02062 void SimulationManager::unpackMonitorSynapseInfo(){
02063         unsigned int tmpFromNeurID, tmpToNeurID, charLength;
02064 
02065         //Get the from neuron ID
02066         int info = pvm_upkuint(&tmpFromNeurID, 1, 1);
02067         #ifdef PVM_DEBUG
02068                 if(info < 0){
02069                         cerr<<"SimulationManager: ERROR EXTRACTING FROM NEURON ID; TASK ID = "<<pvm_mytid()<<"; tmpFromNeuronID: "<<tmpFromNeurID<<endl;
02070                         return;
02071                 }
02072         #endif//PVM_DEBUG
02073 
02074         //Get the to neuron ID
02075         info = pvm_upkuint(&tmpToNeurID, 1, 1);
02076         #ifdef PVM_DEBUG
02077                 if(info < 0){
02078                         cerr<<"SimulationManager: ERROR EXTRACTING TO NEURON ID; TASK ID = "<<pvm_mytid()<<"; tmpToNeuronID: "<<tmpToNeurID<<endl;
02079                         return;
02080                 }
02081         #endif//PVM_DEBUG
02082 
02083         // Extract the length of the XML string
02084         info = pvm_upkuint(&charLength, 1, 1);
02085         #ifdef PVM_DEBUG
02086                 if(info < 0){
02087                         cerr<<"SimulationManager: ERROR EXTRACTING LENGTH OF XML STRING FROM MESSAGE; TASK ID = "<<pvm_mytid()<<"; charLength: "<<charLength<<endl;
02088                         return;
02089                 }
02090         #endif//PVM_DEBUG
02091 
02092         //Unpack the message
02093         char* charArray = new char[charLength];
02094         pvm_upkstr(charArray);
02095 
02096         //Create a key to access the synapse monitor map
02097         unsigned int tmpSynapseKey[2];
02098         tmpSynapseKey[0] = tmpFromNeurID;
02099         tmpSynapseKey[1] = tmpToNeurID;
02100 
02101         //Add the data to the appropriate synapse Monitor
02102         if(synapseMonitorMap->count(tmpSynapseKey))
02103                 (*synapseMonitorMap)[tmpSynapseKey]->setUpGraphs(charArray);
02104         else{
02105                 showErrorMessage("SimulationManager: Synapse not found in Synapse Monitor Map when unpacking info.");
02106                 cerr<<"SimulationManager: Synapse key not found in Synapse Monitor Map: "<<tmpSynapseKey[0]<<" "<<tmpSynapseKey[1]<<endl;
02107         }
02108 }
02109 
02110 
02111 
02112 /*! Records a message from a task to indicate that its view weights have been saved. */
02113 void SimulationManager::updateViewWeightsSavedState(int taskID){
02114         viewWeightsSavedAcknowledgementMap.erase(taskID);
02115         if(viewWeightsSavedAcknowledgementMap.size() == 0)
02116                 viewWeightsSaved = true;
02117 }
02118 
02119 
02120 /*! Records a message from a task to indicate that its weights have been loaded. */
02121 void SimulationManager::updateWeightsLoadedState(int taskID){
02122         weightsLoadedAcknowledgementMap.erase(taskID);
02123         if(weightsLoadedAcknowledgementMap.size() == 0)
02124                 synapseWeightsLoaded = true;
02125 }
02126 
02127 
02128 /*! Records a message from a task to indicate that its weights have been saved.*/
02129 void SimulationManager::updateWeightsSavedState(int taskID){
02130         weightsSavedAcknowledgementMap.erase(taskID);
02131         if(weightsSavedAcknowledgementMap.size() == 0)
02132                 weightsSaved = true;
02133 }
02134 
02135 
02136 
02137 

Generated on Mon Sep 3 22:29:04 2007 for SpikeStream Application by  doxygen 1.4.4