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

SimulationWidget.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 "SimulationWidget.h"
00025 #include "Debug.h"
00026 #include "Utilities.h"
00027 #include "SimulationTypes.h"
00028 #include "DeviceTypes.h"
00029 #include "PatternTypes.h"
00030 #include "GlobalVariables.h"
00031 #include "SpikeStreamMainWindow.h"
00032 
00033 //Qt includes
00034 #include <qfile.h>
00035 #include <qpixmap.h>
00036 #include <qlabel.h>
00037 #include <qgroupbox.h>
00038 #include <qvalidator.h>
00039 #include <qregexp.h>
00040 #include <qmessagebox.h>
00041 #include <qbuttongroup.h>
00042 #include <qtimer.h>
00043 
00044 //Other includes
00045 #include <iostream>
00046 using namespace std;
00047 using namespace mysqlpp;
00048 
00049 
00050 //Declare and initialise static variables
00051 unsigned int SimulationWidget::simulationStartTime = 0;
00052 
00053 
00054 /*! Constructor. */
00055 SimulationWidget::SimulationWidget(QWidget *parent, DBInterface *netDBInter, DBInterface *archDBInter, DBInterface *pattDBInter, DBInterface *devDBInter) : QWidget(parent, "Simulation Widget"){
00056         
00057         //Store a reference to the database interfaces
00058         archiveDBInterface = archDBInter;
00059         networkDBInterface = netDBInter;
00060         patternDBInterface = pattDBInter;
00061         deviceDBInterface = devDBInter;
00062 
00063         //Set up a short version of spike stream application reference
00064         spikeStrApp = SpikeStreamMainWindow::spikeStreamApplication;
00065 
00066         //Set up variables
00067         ignoreInitialiseButton = false;
00068         ignoreRecordButton = false;
00069 
00070         //Create a validators
00071         QRegExp regExp( "([0-9]|[A-Z]|[a-z]|_|\\s){1,50}" );
00072         QValidator* archiveNameValidator = new QRegExpValidator(regExp, this);
00073         QValidator* paramIntValidator = new QIntValidator(0, 1000, this);
00074 
00075         //Set up pixmaps to control play and stop
00076         QPixmap playPixmap(SpikeStreamMainWindow::workingDirectory + "/images/play.xpm");
00077         QPixmap stepPixmap(SpikeStreamMainWindow::workingDirectory + "/images/step.xpm");
00078         QPixmap stopPixmap(SpikeStreamMainWindow::workingDirectory + "/images/stop.xpm");
00079         QPixmap recordPixmap(SpikeStreamMainWindow::workingDirectory + "/images/record.xpm");
00080         
00081         //Create a simulation manager to handle all the simulation work
00082         simulationManager = new SimulationManager(networkDBInterface, archiveDBInterface, patternDBInterface, deviceDBInterface, this);
00083         connect(simulationManager, SIGNAL(simulationStartTimeChanged(unsigned int)), this, SLOT(setSimulationStartTime(unsigned int)));
00084         
00085         //Pass references to simulation manager
00086         simulationManager->setNeuronMonitors(&neuronMonitorMap);
00087         simulationManager->setSynapseMonitors(&synapseMonitorMap);
00088 
00089         //Create dialogs to edit the simulation parameters.
00090         neuronParametersDialog = new NeuronParametersDialog(this, networkDBInterface, simulationManager);
00091         synapseParametersDialog = new SynapseParametersDialog(this, networkDBInterface, simulationManager);
00092         globalParametersDialog = new GlobalParametersDialog(this, networkDBInterface, simulationManager);
00093         noiseParametersDialog = new NoiseParametersDialog(this, networkDBInterface, simulationManager);
00094 
00095         //Create vertical layout to organise widget
00096         QVBoxLayout *mainVerticalBox = new QVBoxLayout(this, 5, 10, "vertical1");
00097 
00098 
00099         //=================== SIMULATION SETTINGS =====================
00100         //Create a group box for the simulation settings
00101         settingsGrpBox = new QGroupBox("Initialisation Settings", this);
00102 
00103         //Create a vertical box to organise layout in group box
00104         QVBoxLayout *settingsVerticalBox = new QVBoxLayout(settingsGrpBox, 5, 10, "vertical2");
00105         settingsVerticalBox->addSpacing(20);
00106 
00107         //Add box to take archive name
00108         QHBoxLayout *archiveNameBox = new QHBoxLayout();
00109         archiveNameBox->addSpacing(10);
00110         archiveNameBox->addWidget(new QLabel("Archive name", settingsGrpBox));
00111         archNameText = new QLineEdit("UNTITLED", settingsGrpBox);
00112         archNameText->setValidator(archiveNameValidator);
00113         archiveNameBox->addWidget(archNameText);
00114         archMonitorTypeCombo = new QComboBox(settingsGrpBox);
00115         archMonitorTypeCombo->insertItem("Archive firing neurons");
00116         archMonitorTypeCombo->insertItem("Archive spikes");
00117         archiveNameBox->addWidget(archMonitorTypeCombo);
00118         archiveNameBox->addStretch(5);
00119         settingsVerticalBox->addLayout(archiveNameBox);
00120 
00121         //Add a tabbed pane to let the user select between pattern and live input for the layers
00122         inputTabWidget = new QTabWidget(settingsGrpBox);
00123 
00124         //Set up the pattern input tab
00125         QWidget *patternWidgetTab = new QWidget(settingsGrpBox);
00126         QVBoxLayout *patternWidgetVerticalBox = new QVBoxLayout(patternWidgetTab, 5, 10, "vertical2");  
00127 
00128         //Set up table to hold pattern information
00129         patternTable = new QTable(0, 7, patternWidgetTab);
00130         patternTable->setShowGrid(false);
00131         patternTable->setSorting(false);
00132         patternTable->setSelectionMode(QTable::NoSelection);
00133         patternTable->verticalHeader()->hide();
00134         patternTable->setLeftMargin(0);
00135         QHeader * patternTableHeader = patternTable->horizontalHeader();
00136         patternIDCol = 0;//Remember to update this when changing the table
00137         patternTableHeader->setLabel(patternIDCol, "ID");
00138         patternTable->setColumnWidth(patternIDCol, 20);
00139         patternTableHeader->setLabel(1, "Description");
00140         patternTable->setColumnWidth(1, 130);
00141         patternTableHeader->setLabel(2, "Type");
00142         patternTable->setColumnWidth(2, 100);
00143         patternTableHeader->setLabel( 3, "Width" );
00144         patternTable->setColumnWidth( 3, 50);
00145         patternTableHeader->setLabel( 4, "Length" );
00146         patternTable->setColumnWidth( 4, 50);
00147         patternTableHeader->setLabel( 5, "Size" );
00148         patternTable->setColumnWidth( 5, 50);
00149         patternNeurGrpCol = 6;//Remember to update this when changing the table
00150         patternTableHeader->setLabel( patternNeurGrpCol, "Neuron Group" );
00151         patternTable->setColumnWidth( patternNeurGrpCol, 100);
00152         loadPatternTable();
00153         patternTable->setMinimumSize(700, 150);
00154         patternWidgetVerticalBox->addWidget(patternTable);
00155 
00156         //Set up option to choose the number of timesteps per pattern
00157         QHBoxLayout *timeStepsPatternBox = new QHBoxLayout();
00158         timeStepsPatternBox ->addWidget(new QLabel("Number of time steps per pattern", patternWidgetTab));
00159         timeStepsPatternText = new QLineEdit("1", patternWidgetTab);
00160         timeStepsPatternText->setValidator(paramIntValidator);
00161         timeStepsPatternBox->addWidget(timeStepsPatternText);
00162         timeStepsPatternBox->addStretch(5);
00163         patternWidgetVerticalBox->addLayout(timeStepsPatternBox);
00164 
00165         //Add the patternWidget tab to the input tab widget
00166         inputTabWidget->addTab(patternWidgetTab, "Pattern Input");
00167 
00168 
00169         //Set up tab to hold live input settings
00170         QWidget *liveWidgetTab = new QWidget(settingsGrpBox);
00171         QVBoxLayout *liveWidgetVerticalBox = new QVBoxLayout(liveWidgetTab, 5, 10);     
00172 
00173         //Add table to enable devices to be connected to neuron groups
00174         deviceTable = new QTable(0, 9, liveWidgetTab);
00175         deviceTable->setShowGrid(false);
00176         deviceTable->setSorting(false);
00177         deviceTable->setSelectionMode(QTable::NoSelection);
00178         deviceTable->verticalHeader()->hide();
00179         deviceTable->setLeftMargin(0);
00180         QHeader * deviceTableHeader = deviceTable->horizontalHeader();
00181         deviceIDCol = 0;//Remember to update this when changing the table
00182         deviceTableHeader->setLabel(deviceIDCol, "ID");
00183         deviceTable->setColumnWidth(deviceIDCol, 20);
00184         deviceTableHeader->setLabel(1, "Description");
00185         deviceTable->setColumnWidth(1, 180);
00186         deviceTableHeader->setLabel(2, "Type");
00187         deviceTable->setColumnWidth(2, 150);
00188         deviceTableHeader->setLabel( 3, "IP Address" );
00189         deviceTable->setColumnWidth( 3, 80);
00190         deviceTableHeader->setLabel( 4, "Port" );
00191         deviceTable->setColumnWidth( 4, 40);
00192         deviceTableHeader->setLabel( 5, "Width" );
00193         deviceTable->setColumnWidth( 5, 50);
00194         deviceTableHeader->setLabel( 6, "Length" );
00195         deviceTable->setColumnWidth( 6, 50);
00196         deviceNeurGrpCol = 7;//Remember to update this when changing the table
00197         deviceTableHeader->setLabel( deviceNeurGrpCol, "Neuron Group" );
00198         deviceTable->setColumnWidth( deviceNeurGrpCol, 150);
00199         deviceFiringModeCol = 8;
00200         deviceTableHeader->setLabel( deviceFiringModeCol, "Firing Mode" );
00201         deviceTable->setColumnWidth( deviceFiringModeCol, 150);
00202         loadDeviceTable();
00203         deviceTable->setMinimumSize(800, 150);
00204         liveWidgetVerticalBox->addWidget(deviceTable);
00205 
00206         inputTabWidget->addTab(liveWidgetTab, "Device Input/Output");
00207         settingsVerticalBox->addWidget(inputTabWidget);
00208 
00209 
00210         //Add settings box to layout. Need an extra box to make it fit nicely
00211         QHBoxLayout *settingsHBox = new QHBoxLayout();
00212         settingsHBox->addWidget(settingsGrpBox);
00213         settingsHBox->addStretch(5);
00214         mainVerticalBox->addLayout(settingsHBox);
00215 
00216 
00217         //====================   PARAMETERS   ==========================
00218         //Create a group box for the parameters
00219         QGroupBox *parameterGrpBox = new QGroupBox("Parameters", this);
00220         parameterGrpBox->setMinimumSize(725, 70);
00221 
00222         //Create a vertical box to organise layout in group box
00223         QHBoxLayout *parameterHBox = new QHBoxLayout();
00224         parameterHBox->addSpacing(10);
00225 
00226         //Add button to display neuron parameters
00227         QPushButton *neurParamButton = new QPushButton("Neuron Parameters", parameterGrpBox);
00228         connect (neurParamButton, SIGNAL(clicked()), this, SLOT(neuronParamButtonPressed()));
00229         parameterHBox->addWidget(neurParamButton);
00230 
00231         //Add button to display synapse parameters
00232         QPushButton *synapseParamButton = new QPushButton("Synapse Parameters", parameterGrpBox);
00233         connect (synapseParamButton, SIGNAL(clicked()), this, SLOT(synapseParamButtonPressed()));
00234         parameterHBox->addWidget(synapseParamButton);
00235 
00236         //Add button to display global parameters
00237         QPushButton *globalParamButton = new QPushButton("Global Parameters", parameterGrpBox);
00238         connect (globalParamButton, SIGNAL(clicked()), this, SLOT(globalParamButtonPressed()));
00239         parameterHBox->addWidget(globalParamButton);
00240 
00241         //Add button to display global parameters
00242         QPushButton *noiseParamButton = new QPushButton("Noise", parameterGrpBox);
00243         connect (noiseParamButton, SIGNAL(clicked()), this, SLOT(noiseParamButtonPressed()));
00244         parameterHBox->addWidget(noiseParamButton);
00245         parameterHBox->addSpacing(10);
00246 
00247         QVBoxLayout *parameterVBox = new QVBoxLayout(parameterGrpBox, 5, 10);
00248         parameterVBox->addSpacing(20);
00249         parameterVBox->addLayout(parameterHBox);
00250         parameterVBox->addSpacing(10);
00251 
00252         QHBoxLayout *paramHBox = new QHBoxLayout();
00253         paramHBox->addWidget(parameterGrpBox);
00254         paramHBox->addStretch(5);
00255         mainVerticalBox->addLayout(paramHBox);
00256 
00257 
00258         //=================== SIMULATION CONTROLS =========================
00259         //Create group box for the simulation controls
00260         QGroupBox *controlGrpBox = new QGroupBox("Simulation Controls", this);
00261 
00262         //Create a vertical box to organise layout in group box
00263         QVBoxLayout *controlVerticalBox = new QVBoxLayout(controlGrpBox, 5, 10, "vertical3");
00264         controlVerticalBox->addSpacing(20);
00265 
00266         //Set up initialise section
00267         QHBoxLayout *initialiseBox = new QHBoxLayout();
00268         initialiseBox->addSpacing(10);
00269         initialiseButton = new QPushButton("Initialise", controlGrpBox);
00270         initialiseButton->setToggleButton(true);
00271         connect (initialiseButton, SIGNAL(toggled(bool)), this, SLOT(initialiseButtonToggled(bool)));
00272         initialiseBox->addWidget(initialiseButton);
00273 
00274         reloadWeightsButton = new QPushButton("Reload weights", controlGrpBox);
00275         reloadWeightsButton->setEnabled(false);
00276         connect(reloadWeightsButton, SIGNAL(clicked()), this, SLOT(reloadWeightsButtonPressed()));
00277         initialiseBox->addWidget(reloadWeightsButton);
00278 
00279         saveWeightsButton = new QPushButton("Save weights", controlGrpBox);
00280         saveWeightsButton->setEnabled(false);
00281         connect(saveWeightsButton, SIGNAL(clicked()), this, SLOT(saveWeightsButtonPressed()));
00282         initialiseBox->addWidget(saveWeightsButton);
00283 
00284         viewWeightsButton = new QPushButton("View weights", controlGrpBox);
00285         viewWeightsButton->setEnabled(false);
00286         connect(viewWeightsButton, SIGNAL(clicked()), this, SLOT(viewWeightsButtonPressed()));
00287         initialiseBox->addWidget(viewWeightsButton);
00288         initialiseBox->addSpacing(10);
00289 
00290         controlVerticalBox->addLayout(initialiseBox);
00291         controlVerticalBox->addSpacing(5);
00292 
00293         //Set up transport buttons
00294         QHBoxLayout *simTransportButtonBox = new QHBoxLayout();
00295         simStartButton = new QPushButton(QIconSet(playPixmap), "", controlGrpBox);
00296         simStartButton->setToggleButton(true);
00297         simStartButton->setEnabled(false);
00298         simStartButton->setBaseSize(120, 30);
00299         simStartButton->setMaximumSize(120, 30);
00300         simStartButton->setMinimumSize(120, 30);
00301         connect (simStartButton, SIGNAL(toggled(bool)), this, SLOT(simStartButtonToggled(bool)));
00302         simTransportButtonBox->addSpacing(10);
00303         simTransportButtonBox->addWidget(simStartButton);
00304 
00305         simStepButton = new QPushButton(QIconSet(stepPixmap), "", controlGrpBox);
00306         simStepButton->setEnabled(false);
00307         simStepButton->setBaseSize(50, 30);
00308         simStepButton->setMaximumSize(50, 30);
00309         simStepButton->setMinimumSize(50, 30);
00310         connect (simStepButton, SIGNAL(clicked()), this, SLOT(simStepButtonPressed()));
00311         simTransportButtonBox->addWidget(simStepButton);
00312 
00313         recordButton = new QPushButton(QIconSet(recordPixmap), "", controlGrpBox);
00314         recordButton->setEnabled(false);
00315         recordButton->setToggleButton(true);
00316         recordButton->setBaseSize(50, 30);
00317         recordButton->setMaximumSize(50, 30);
00318         recordButton->setMinimumSize(50, 30);
00319         connect (recordButton, SIGNAL(toggled(bool)), this, SLOT(recordButtonToggled(bool)));
00320         simTransportButtonBox->addWidget(recordButton);
00321 
00322         simStopButton = new QPushButton(QIconSet(stopPixmap), "", controlGrpBox);
00323         simStopButton->setEnabled(false);
00324         simStopButton->setBaseSize(50, 30);
00325         simStopButton->setMaximumSize(50, 30);
00326         simStopButton->setMinimumSize(50, 30);
00327         connect (simStopButton, SIGNAL(clicked()), this, SLOT(simStopButtonPressed()));
00328         simTransportButtonBox->addWidget(simStopButton);
00329 
00330         frameRateCombo = new QComboBox(controlGrpBox);
00331         frameRateCombo->setEnabled(false);
00332         frameRateCombo->insertItem("Max speed");
00333         frameRateCombo->insertItem("1 fps");    
00334         frameRateCombo->insertItem("5 fps");
00335         frameRateCombo->insertItem("10 fps");
00336         frameRateCombo->insertItem("15 fps");
00337         frameRateCombo->insertItem("20 fps");
00338         frameRateCombo->insertItem("25 fps");
00339         frameRateCombo->setBaseSize(100, 30);
00340         frameRateCombo->setMaximumSize(100, 30);
00341         frameRateCombo->setMinimumSize(100, 30);
00342         frameRateCombo->setCurrentItem(0);
00343         connect(frameRateCombo, SIGNAL(activated(int)), this, SLOT(frameRateComboChanged(int)));
00344         simTransportButtonBox->addWidget(frameRateCombo);
00345 
00346         simModeCombo = new QComboBox(controlGrpBox);
00347         simModeCombo->setEnabled(false);
00348         simModeCombo->insertItem("Event driven");
00349         simModeCombo->insertItem("Update all neurons"); 
00350         simModeCombo->insertItem("Update all synapses");
00351         simModeCombo->insertItem("Update everything");
00352         simModeCombo->setBaseSize(130, 30);
00353         simModeCombo->setMaximumSize(130, 30);
00354         simModeCombo->setMinimumSize(130, 30);
00355         simModeCombo->setCurrentItem(0);
00356         connect(simModeCombo, SIGNAL(activated(int)), this, SLOT(simModeComboChanged(int)));
00357         simTransportButtonBox->addWidget(simModeCombo);
00358 
00359         simTransportButtonBox->addSpacing(10);
00360         simTransportButtonBox->addStretch(5);
00361 
00362         controlVerticalBox->addLayout(simTransportButtonBox);
00363         controlVerticalBox->addSpacing(10);
00364 
00365         //Set up option to monitor the activity in a neuron group
00366         QHBoxLayout *monitorBox = new QHBoxLayout();
00367         neuronGrpMonitorCombo = new QComboBox(controlGrpBox);
00368         neuronGrpMonitorCombo->setEnabled(false);
00369         neuronGrpMonitorCombo->setBaseSize(180, 20);
00370         neuronGrpMonitorCombo->setMaximumSize(180, 20);
00371         neuronGrpMonitorCombo->setMinimumSize(180, 20);
00372         monitorBox->addSpacing(10);
00373         monitorBox->addWidget(neuronGrpMonitorCombo);
00374         liveMonitorTypeCombo = new QComboBox(controlGrpBox);
00375         liveMonitorTypeCombo->insertItem("Neurons");
00376         liveMonitorTypeCombo->insertItem("Spikes");
00377         liveMonitorTypeCombo->setBaseSize(100, 20);
00378         liveMonitorTypeCombo->setMaximumSize(100, 20);
00379         liveMonitorTypeCombo->setMinimumSize(100, 20);
00380         liveMonitorTypeCombo->setEnabled(false);
00381         monitorBox->addWidget(liveMonitorTypeCombo);
00382         monitorButton = new QPushButton("Live Monitor", controlGrpBox);
00383         monitorButton->setMaximumSize(120, 20);
00384         monitorButton->setMinimumSize(120, 20);
00385         monitorButton->setEnabled(false);
00386         connect(monitorButton, SIGNAL(clicked()), this, SLOT(monitorButtonPressed()));
00387         monitorBox->addWidget(monitorButton);
00388         monitorBox->addStretch(5);
00389         controlVerticalBox->addLayout(monitorBox);
00390 
00391         //Controls to monitor the data of a single specified neuron
00392         QHBoxLayout *monitorNeuronBox = new QHBoxLayout();
00393         monitorNeuronCombo = new QComboBox(controlGrpBox);
00394         connect(monitorNeuronCombo, SIGNAL(activated(const QString &)), this, SLOT(monitorNeuronComboActivated(const QString &)));
00395         monitorNeuronCombo->setEnabled(false);
00396         monitorNeuronCombo->setBaseSize(180, 20);
00397         monitorNeuronCombo->setMaximumSize(180, 20);
00398         monitorNeuronCombo->setMinimumSize(180, 20);
00399         monitorNeuronBox->addSpacing(10);
00400         monitorNeuronBox->addWidget(monitorNeuronCombo);
00401         monitorNeuronText = new QLineEdit(controlGrpBox);
00402         monitorNeuronText->setBaseSize(100, 20);
00403         monitorNeuronText->setMaximumSize(100, 20);
00404         monitorNeuronText->setMinimumSize(100, 20);
00405         monitorNeuronValidator = new QIntValidator(this);
00406         monitorNeuronText->setValidator(monitorNeuronValidator);
00407         monitorNeuronText->setEnabled(false);
00408         monitorNeuronBox->addWidget(monitorNeuronText);
00409         monitorNeuronButton = new QPushButton("Monitor Neuron", controlGrpBox);
00410         monitorNeuronButton->setMaximumSize(120, 20);
00411         monitorNeuronButton->setMinimumSize(120, 20);
00412         connect(monitorNeuronButton, SIGNAL(clicked()), this, SLOT(monitorNeuronButtonPressed()));
00413         monitorNeuronButton->setEnabled(false);
00414         monitorNeuronBox->addWidget(monitorNeuronButton);
00415         monitorNeuronBox->addStretch(5);
00416         controlVerticalBox->addLayout(monitorNeuronBox);
00417 
00418         //Controls to monitor the data of a single specified synapse
00419         QHBoxLayout *monitorSynapseBox = new QHBoxLayout();
00420         monitorSynapseBox->addSpacing(10);
00421         monitorSynapseFromLabel = new QLabel("From: ", controlGrpBox);
00422         monitorSynapseFromLabel->setBaseSize(40, 20);
00423         monitorSynapseFromLabel->setMinimumSize(40, 20);
00424         monitorSynapseFromLabel->setMaximumSize(40, 20);
00425         monitorSynapseFromLabel->setEnabled(false);
00426         monitorSynapseBox->addWidget(monitorSynapseFromLabel);
00427         monitorSynapseFromNumLabel = new QLabel("0", controlGrpBox);
00428         monitorSynapseFromNumLabel->setAlignment(Qt::AlignHCenter | AlignVCenter);
00429         monitorSynapseFromNumLabel->setBaseSize(100, 20);
00430         monitorSynapseFromNumLabel->setMinimumSize(100, 20);
00431         monitorSynapseFromNumLabel->setMaximumSize(40, 20);
00432         monitorSynapseFromNumLabel->setEnabled(false);
00433         monitorSynapseBox->addWidget(monitorSynapseFromNumLabel);
00434         monitorSynapseToLabel = new QLabel("To: ", controlGrpBox);
00435         monitorSynapseToLabel->setBaseSize(30, 20);
00436         monitorSynapseToLabel->setMinimumSize(30, 20);
00437         monitorSynapseToLabel->setMaximumSize(30, 20);
00438         monitorSynapseToLabel->setEnabled(false);
00439         monitorSynapseBox->addWidget(monitorSynapseToLabel);
00440         monitorSynapseToNumLabel = new QLabel("0", controlGrpBox);
00441         monitorSynapseToNumLabel->setAlignment(Qt::AlignHCenter | AlignVCenter);
00442         monitorSynapseToNumLabel->setBaseSize(90, 20);
00443         monitorSynapseToNumLabel->setMinimumSize(90, 20);
00444         monitorSynapseToNumLabel->setEnabled(false);
00445         monitorSynapseBox->addWidget(monitorSynapseToNumLabel);
00446         monitorSynapseButton = new QPushButton("Monitor Synapse", controlGrpBox);
00447         monitorSynapseButton->setMaximumSize(120, 20);
00448         monitorSynapseButton->setMinimumSize(120, 20);
00449         connect(monitorSynapseButton, SIGNAL(clicked()), this, SLOT(monitorSynapseButtonPressed()));
00450         monitorSynapseButton->setEnabled(false);
00451         monitorSynapseBox->addWidget(monitorSynapseButton);
00452         monitorSynapseBox->addStretch(5);
00453         controlVerticalBox->addLayout(monitorSynapseBox);
00454         controlVerticalBox->addSpacing(10);
00455         
00456         //Set up option to inject random noise into the neuron group
00457         QHBoxLayout *injectNoiseBox = new QHBoxLayout();
00458 
00459         //Combo to choose neuron group
00460         injectNoiseNeurGrpCombo = new QComboBox(controlGrpBox);
00461         injectNoiseNeurGrpCombo->setEnabled(false);
00462         injectNoiseNeurGrpCombo->setBaseSize(180, 20);
00463         injectNoiseNeurGrpCombo->setMaximumSize(180, 20);
00464         injectNoiseNeurGrpCombo->setMinimumSize(180, 20);
00465         injectNoiseBox->addSpacing(10);
00466         injectNoiseBox->addWidget(injectNoiseNeurGrpCombo);
00467 
00468         //Combo to choose amount of noise
00469         injectNoiseAmntCombo = new QComboBox(controlGrpBox);
00470         injectNoiseAmntCombo->insertItem("1 Neuron");
00471         injectNoiseAmntCombo->insertItem("5%");
00472         injectNoiseAmntCombo->insertItem("25%");
00473         injectNoiseAmntCombo->insertItem("50%");
00474         injectNoiseAmntCombo->insertItem("75%");
00475         injectNoiseAmntCombo->insertItem("100%");
00476         injectNoiseAmntCombo->setBaseSize(100, 20);
00477         injectNoiseAmntCombo->setMaximumSize(100, 20);
00478         injectNoiseAmntCombo->setMinimumSize(100, 20);
00479         injectNoiseAmntCombo->setEnabled(false);
00480         injectNoiseBox->addWidget(injectNoiseAmntCombo);
00481 
00482         //Button to control noise
00483         injectNoiseButton = new QPushButton("Inject Noise", controlGrpBox);
00484         injectNoiseButton->setMaximumSize(120, 20);
00485         injectNoiseButton->setMinimumSize(120, 20);
00486         injectNoiseButton->setEnabled(false);
00487         connect(injectNoiseButton, SIGNAL(clicked()), this, SLOT(injectNoiseButtonPressed()));
00488         injectNoiseBox->addWidget(injectNoiseButton);
00489         injectNoiseBox->addStretch(5);
00490         
00491         controlVerticalBox->addLayout(injectNoiseBox);
00492 
00493         //Controls to fire a single specified neuron
00494         QHBoxLayout *fireNeuronBox = new QHBoxLayout();
00495         fireNeuronCombo = new QComboBox(controlGrpBox);
00496         connect(fireNeuronCombo, SIGNAL(activated(const QString &)), this, SLOT(fireNeuronComboActivated(const QString &)));
00497         fireNeuronCombo->setEnabled(false);
00498         fireNeuronCombo->setBaseSize(180, 20);
00499         fireNeuronCombo->setMaximumSize(180, 20);
00500         fireNeuronCombo->setMinimumSize(180, 20);
00501         fireNeuronBox->addSpacing(10);
00502         fireNeuronBox->addWidget(fireNeuronCombo);
00503         fireNeuronText = new QLineEdit(controlGrpBox);
00504         fireNeuronText->setBaseSize(100, 20);
00505         fireNeuronText->setMaximumSize(100, 20);
00506         fireNeuronText->setMinimumSize(100, 20);
00507         fireNeuronValidator = new QIntValidator(this);
00508         fireNeuronText->setValidator(fireNeuronValidator);
00509         fireNeuronText->setEnabled(false);
00510         fireNeuronBox->addWidget(fireNeuronText);
00511         fireNeuronButton = new QPushButton("Fire Neuron", controlGrpBox);
00512         fireNeuronButton->setMaximumSize(120, 20);
00513         fireNeuronButton->setMinimumSize(120, 20);
00514         connect(fireNeuronButton, SIGNAL(clicked()), this, SLOT(fireNeuronButtonPressed()));
00515         fireNeuronButton->setEnabled(false);
00516         fireNeuronBox->addWidget(fireNeuronButton);
00517         fireNeuronBox->addStretch(5);
00518 
00519         controlVerticalBox->addLayout(fireNeuronBox);
00520         controlVerticalBox->addSpacing(10);
00521 
00522         //Add controls box to layout. Need an extra box to make it fit nicely
00523         QHBoxLayout *conHBox = new QHBoxLayout();
00524         conHBox->addWidget(controlGrpBox);
00525         conHBox->addStretch(5);
00526         mainVerticalBox->addLayout(conHBox);
00527         mainVerticalBox->addSpacing(10);
00528 
00529 
00530         //========================== DOCKING AND GRAPH VISIBILITY CONTROLS ==============================
00531         QHBoxLayout *dockButtonBox = new QHBoxLayout();
00532         dockAllButton = new QPushButton("Dock All", this);
00533         dockAllButton->setEnabled(false);
00534         connect(dockAllButton, SIGNAL(clicked()), this, SLOT(dockAllButtonClicked()));
00535         dockButtonBox->addWidget(dockAllButton);
00536         undockAllButton = new QPushButton("Undock All", this);
00537         undockAllButton->setEnabled(false);
00538         connect(undockAllButton, SIGNAL(clicked()), this, SLOT(undockAllButtonClicked()));
00539         dockButtonBox->addWidget(undockAllButton);
00540         hideGraphsButton = new QPushButton("Hide Graphs", this);
00541         hideGraphsButton->setEnabled(false);
00542         connect (hideGraphsButton, SIGNAL(clicked()), this, SLOT(hideGraphsButtonClicked()));
00543         dockButtonBox->addWidget(hideGraphsButton);
00544         showGraphsButton = new QPushButton("Show Graphs", this);
00545         showGraphsButton->setEnabled(false);
00546         connect (showGraphsButton, SIGNAL(clicked()), this, SLOT(showGraphsButtonClicked()));
00547         dockButtonBox->addWidget(showGraphsButton);
00548         dockButtonBox->addStretch(5);
00549 
00550         mainVerticalBox->addLayout(dockButtonBox);
00551 
00552         simErrorCheckTimer = new QTimer(this);
00553         connect( simErrorCheckTimer, SIGNAL(timeout()), this, SLOT(checkSimManagerForErrors()));
00554 }
00555 
00556 
00557 /*! Destructor. */
00558 SimulationWidget::~SimulationWidget(){
00559         #ifdef MEMORY_DEBUG
00560                 cout<<"DELETING SIMULATION WIDGET"<<endl;
00561         #endif//MEMORY_DEBUG
00562 
00563         delete simulationManager;
00564 }
00565 
00566 
00567 //--------------------------------------------------------------------
00568 //------------------------- PUBLIC METHODS ---------------------------
00569 //--------------------------------------------------------------------
00570 
00571 /*! Returns a reference to the simulation manager.
00572         Used so that the neuron application can delete classes in the right order. */
00573 SimulationManager* SimulationWidget::getSimulationManager(){
00574         return simulationManager;
00575 }
00576 
00577 
00578 /*! Returns the simulation start time to prevent the deletion of live
00579         archives. */
00580 unsigned int SimulationWidget::getSimulationStartTime(){
00581         return simulationStartTime;
00582 }
00583 
00584 
00585 /*! Hides the windows that are currently visible.
00586 FIXME NEED TO KEEP A RECORD SO THAT THE SAME WINDOWS CAN BE SHOWN AGAIN. */
00587 void SimulationWidget::hideOpenWindows(){
00588         monitorArea->dockMonitorWindows();
00589         hideGraphsButtonClicked();
00590         neuronParametersDialog->hide();
00591         synapseParametersDialog->hide();
00592         globalParametersDialog->hide();
00593         noiseParametersDialog->hide();
00594 }
00595 
00596 
00597 /*! Reloads the connection groups. */
00598 void SimulationWidget::reloadConnectionGroups(){
00599         synapseParametersDialog->loadSynapseParameters();
00600 }
00601 
00602 
00603 /*! Reloads the devices. */
00604 void SimulationWidget::reloadDevices(){
00605         loadDeviceTable();
00606 }
00607 
00608 
00609 /*! vCalled whenver the list of neuron groups changes. */
00610 void SimulationWidget::reloadNeuronGroups(){
00611         loadPatternTable();
00612         loadDeviceTable();
00613         neuronParametersDialog->loadNeuronParameters();
00614 }
00615 
00616 
00617 /*! Called when changes are made to the patterns in the database. */
00618 void SimulationWidget::reloadPatterns(){
00619         loadPatternTable();
00620 }
00621 
00622 
00623 /*! Sets the currently active neuron so that the user can choose to fire it 
00624         for debugging etc. */
00625 void SimulationWidget::setFromNeuronID(unsigned int neurGrpID, unsigned int fromNeurID){
00626         //Work through fireNeuronCombo to find correct neuron group
00627         for(int i=0; i<fireNeuronCombo->count(); ++i){
00628                 QString neurGrpString = "[" + QString::number(neurGrpID) + "]";
00629                 if(fireNeuronCombo->text(i).contains(neurGrpString)){
00630                         fireNeuronCombo->setCurrentItem(i);
00631                         fireNeuronComboActivated(fireNeuronCombo->currentText());
00632                         break;
00633                 }
00634         }
00635         fireNeuronText->setText(QString::number(fromNeurID));
00636 
00637         //Work through monitorNeuronCombo to find correct neuron group
00638         //FIXME COULD GET RID OF THIS IF BOTH COMBOS ARE KEPT STRICTLY IN SYNC
00639         for(int i=0; i<monitorNeuronCombo->count(); ++i){
00640                 QString neurGrpString = "[" + QString::number(neurGrpID) + "]";
00641                 if(monitorNeuronCombo->text(i).contains(neurGrpString)){
00642                         monitorNeuronCombo->setCurrentItem(i);
00643                         monitorNeuronComboActivated(monitorNeuronCombo->currentText());
00644                         break;
00645                 }
00646         }
00647         monitorNeuronText->setText(QString::number(fromNeurID));
00648         monitorSynapseFromNumLabel->setText(QString::number(fromNeurID));
00649 }
00650 
00651 
00652 /*! Sets the reference to the monitor area that will be used to create monitor windows. */
00653 void SimulationWidget::setMonitorArea(MonitorArea *monAr){
00654         monitorArea = monAr;
00655 }
00656 
00657 
00658 /*! Sets the active to neuron. */
00659 void SimulationWidget::setToNeuronID(unsigned int toNeurID){
00660         monitorSynapseToNumLabel->setText(QString::number(toNeurID));
00661 }
00662 
00663 
00664 /*! Shows the windows that are currently visible.
00665 FIXME NEED TO TRACK WHICH ARE CURRENTLY OPEN. */
00666 void SimulationWidget::showOpenWindows(){
00667 
00668 }
00669 
00670 
00671 //------------------------------------------------------------------------
00672 //--------------------------------- SLOTS --------------------------------
00673 //------------------------------------------------------------------------
00674 
00675 /*! Checks the simulation manager to see if there have been any errors in 
00676         the simulation. */
00677 void SimulationWidget::checkSimManagerForErrors(){
00678         if(simulationManager->simulationError()){
00679                 //Stop the simulation if it is running
00680                 simStopButtonPressed();
00681 
00682                 //Show the error if we have not shown it already
00683                 QString* tempQStrErr = new QString(simulationManager->getSimulationErrorMsg());
00684                 if(!(simulationErrorMap.count(tempQStrErr))){
00685                         simulationErrorMap[tempQStrErr] = true;
00686                         QMessageBox::critical (this, "Simulation Error", *tempQStrErr);
00687                 }
00688                 else{
00689                         cout<<"SimulationWidget: Error filter working"<<endl;
00690                 }
00691 
00692                 //Clear the error
00693                 simulationManager->clearSimulationError();
00694         }
00695 }
00696 
00697 
00698 /*! Checks with the simulation manager to see if the weights have been saved for viewing 
00699         or if there has been an error. */
00700 void SimulationWidget::checkViewWeightsSaved(){
00701         if(simulationManager->getViewWeightsSaved()){
00702                 SpikeStreamMainWindow::spikeStrMainWin->reloadConnectionDetails();
00703                 delete busyDialog;
00704         }
00705         else if(simulationManager->simulationError()){
00706                 delete busyDialog;
00707                 QMessageBox::critical (this, "View Weight Save Error!", "An error occurred whilst saving synapse weights for viewing.");
00708         }
00709         else{
00710         QTimer *timer = new QTimer(this);
00711         connect( timer, SIGNAL(timeout()), this, SLOT(checkViewWeightsSaved()));
00712         timer->start( 500, TRUE ); // 1/2 second single-shot timer
00713         }
00714 }
00715 
00716 
00717 /*! Called by timer to check whether weights have been loaded or not. The timer is 
00718         restarted if they have not finished loading. */
00719 void SimulationWidget::checkWeightsLoadState(){
00720         if(simulationManager->getWeightsLoaded()){
00721                 delete busyDialog;
00722         }
00723         else if (simulationManager->simulationError()){
00724                 delete busyDialog;
00725                 QMessageBox::critical (this, "Weight Loading Error!", "An error occurred whilst reloading synapse weights.");
00726         }
00727         else{
00728         QTimer *timer = new QTimer(this);
00729         connect( timer, SIGNAL(timeout()), this, SLOT(checkWeightsLoadState()) );
00730         timer->start( 1000, TRUE ); // 1 second single-shot timer
00731         }
00732 }
00733 
00734 
00735 /*! Checks with the simulation manager to see if the weights have been saved or 
00736         if there has been an error. */
00737 void SimulationWidget::checkWeightsSaveState(){
00738         if(simulationManager->getWeightsSaved()){
00739                 SpikeStreamMainWindow::spikeStrMainWin->reloadConnectionDetails();
00740                 delete busyDialog;
00741         }
00742         else if(simulationManager->simulationError()){
00743                 delete busyDialog;
00744                 QMessageBox::critical (this, "Weight Save Error!", "An error occurred whilst saving synapse weights.");
00745         }
00746         else{
00747         QTimer *timer = new QTimer(this);
00748         connect( timer, SIGNAL(timeout()), this, SLOT(checkWeightsSaveState()) );
00749         timer->start( 500, TRUE ); // 1/2 second single-shot timer
00750         }
00751 }
00752 
00753 
00754 /*! Instructs monitor area to dock all monitor windows. */
00755 void SimulationWidget::dockAllButtonClicked(){
00756         monitorArea->dockMonitorWindows();
00757 }
00758 
00759 
00760 /*! Fires a single neuron. */
00761 void SimulationWidget::fireNeuronButtonPressed(){
00762         if(fireNeuronCombo->count() <=0)
00763                 return;
00764 
00765         unsigned int neuronID = 0, neuronGrpID = 0;
00766         try{
00767                 neuronID = Utilities::getUInt(fireNeuronText->text().ascii());
00768                 neuronGrpID = Utilities::getNeuronGrpID(fireNeuronCombo->currentText());
00769         }
00770         catch(std::exception& er){// Catch-all for any other exceptions
00771                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00772                 QString errorString = "Exception thrown firing neuron: \"";
00773                 errorString += er.what();
00774                 errorString += "\"";
00775                 QMessageBox::critical( 0, "Fire Neuron Error", errorString);
00776                 return;
00777         }
00778 
00779         if(neuronID < minFireNeuronID || neuronID > maxFireNeuronID){
00780                 QMessageBox::critical(this, "Fire Neuron Error", "The neuron ID is out of range for this neuron group");
00781                 return;
00782         }
00783         simulationManager->fireNeuron(neuronGrpID, neuronID);
00784 }
00785 
00786 
00787 /*! Gets the first neuron id in the neuron group when the selection
00788         is changed in the fire neuron combo. */
00789 void SimulationWidget::fireNeuronComboActivated(const QString &string){
00790         if(string == "")
00791                 return;
00792 
00793         try{
00794                 unsigned int neuronGrpID = Utilities::getNeuronGrpID(string);
00795                 Query query = networkDBInterface->getQuery();
00796                 query.reset();
00797                 query<<"SELECT MIN(NeuronID), MAX(NeuronID) FROM Neurons WHERE NeuronGrpID = "<<neuronGrpID;
00798                 Result result = query.store();
00799                 Row row(*result.begin());//Should only be 1 row
00800                 minFireNeuronID = Utilities::getUInt((std::string)row["MIN(NeuronID)"]);
00801                 maxFireNeuronID = Utilities::getUInt((std::string)row["MAX(NeuronID)"]);
00802                 fireNeuronValidator->setRange(minFireNeuronID, maxFireNeuronID);
00803                 fireNeuronText->setText(QString::number(minFireNeuronID));
00804         }
00805         catch (const BadQuery& er) {// Handle any query errors
00806                 cerr<<"SimulationWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00807                 QString errorString = "Bad query when finding neuron ID range: \"";
00808                 errorString += er.what();
00809                 errorString += "\"";
00810                 QMessageBox::critical( 0, "Neuron Range Error", errorString);
00811         }
00812         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00813                 cerr<<"SimulationWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00814                 QString errorString = "Exception thrown finding neuron ID range: \"";
00815                 errorString += er.what();
00816                 errorString += "\"";
00817                 QMessageBox::critical( 0, "Neuron Range Error", errorString);
00818         }
00819         catch(std::exception& er){// Catch-all for any other exceptions
00820                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00821                 QString errorString = "Exception thrown finding neuron ID range: \"";
00822                 errorString += er.what();
00823                 errorString += "\"";
00824                 QMessageBox::critical( 0, "Neuron Range Error", errorString);
00825         }
00826 }
00827 
00828 
00829 /*! Gets the first neuron id in the neuron group when the selection
00830         is changed in the monitor neuron combo. */
00831 void SimulationWidget::monitorNeuronComboActivated(const QString &string){
00832         if(string == "")
00833                 return;
00834 
00835         try{
00836                 unsigned int neuronGrpID = Utilities::getNeuronGrpID(string);
00837                 Query query = networkDBInterface->getQuery();
00838                 query.reset();
00839                 query<<"SELECT MIN(NeuronID), MAX(NeuronID) FROM Neurons WHERE NeuronGrpID = "<<neuronGrpID;
00840                 Result result = query.store();
00841                 Row row(*result.begin());//Should only be 1 row
00842                 minMonitorNeuronID = Utilities::getUInt((std::string)row["MIN(NeuronID)"]);
00843                 maxMonitorNeuronID = Utilities::getUInt((std::string)row["MAX(NeuronID)"]);
00844                 monitorNeuronValidator->setRange(minMonitorNeuronID, maxMonitorNeuronID);
00845                 monitorNeuronText->setText(QString::number(minMonitorNeuronID));
00846         }
00847         catch (const BadQuery& er) {// Handle any query errors
00848                 cerr<<"SimulationWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
00849                 QString errorString = "Bad query when finding neuron ID range: \"";
00850                 errorString += er.what();
00851                 errorString += "\"";
00852                 QMessageBox::critical( 0, "Neuron Range Error", errorString);
00853         }
00854         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
00855                 cerr<<"SimulationWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
00856                 QString errorString = "Exception thrown finding neuron ID range: \"";
00857                 errorString += er.what();
00858                 errorString += "\"";
00859                 QMessageBox::critical( 0, "Neuron Range Error", errorString);
00860         }
00861         catch(std::exception& er){// Catch-all for any other exceptions
00862                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00863                 QString errorString = "Exception thrown finding neuron ID range: \"";
00864                 errorString += er.what();
00865                 errorString += "\"";
00866                 QMessageBox::critical( 0, "Neuron Range Error", errorString);
00867         }
00868 }
00869 
00870 
00871 /*! Called when the frame rate is changed for live simulation. */
00872 void SimulationWidget::frameRateComboChanged(int){
00873         if(frameRateCombo->currentItem() == 0){
00874                 simulationManager->setFrameRate(-1);//Max frame rate
00875         }
00876         else{
00877                 try{
00878                         int frameRate = Utilities::getUInt(frameRateCombo->currentText().section(" ", 0, 0).ascii());
00879                         simulationManager->setFrameRate(frameRate);
00880                 }
00881                 catch(std::exception& er){// Catch-all for any other exceptions
00882                         cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
00883                         QString errorString = "Exception thrown converting frame rate from combo: \"";
00884                         errorString += er.what();
00885                         errorString += "\"";
00886                         QMessageBox::critical( 0, "Frame Rate Error", errorString);
00887                 }
00888         }
00889 }
00890 
00891 
00892 /*! Shows the global parameters dialog. */
00893 void SimulationWidget::globalParamButtonPressed(){
00894         if(globalParametersDialog->loadParameters())
00895                 globalParametersDialog->show();
00896 }
00897 
00898 
00899 /*! Hides the graphs plotting data from neurons or synapses. */
00900 void SimulationWidget::hideGraphsButtonClicked(){
00901         //Work through all of the neuron monitors and hide them
00902         for(map<unsigned int, MonitorDataPlotter*>::iterator iter = neuronMonitorMap.begin(); iter != neuronMonitorMap.end(); ++iter){
00903                 if(iter->second->isShown()){
00904                         iter->second->closeDialog(true);
00905                 }
00906         }
00907 
00908         //Work through all the synapse monitors and hide them
00909         for (map<unsigned int*, MonitorDataPlotter*, synapseKeyCompare>::iterator iter = synapseMonitorMap.begin(); iter != synapseMonitorMap.end(); ++iter){
00910                 if(iter->second->isShown()){
00911                         iter->second->closeDialog(true);
00912                 }
00913         }
00914 }
00915 
00916 
00917 /*! Launches or destroys the simulation and enables or disables
00918         the relevant components. */
00919 void SimulationWidget::initialiseButtonToggled(bool on){
00920         /* Used when we want to alter the button's state without
00921                 doing anything. */
00922         if(ignoreInitialiseButton){
00923                 ignoreInitialiseButton = false;
00924                 return;
00925         }
00926 
00927         if(on){
00928                 //Check for isolated neuron groups that are not connected to anything
00929                 if(neuronGroupsIsolated()){
00930                         int response = QMessageBox::warning(this, "Run Simulation", "Some of the neuron groups in your network model are not connected to another neuron group.\n These will not be updated and may prevent the simulation from running.\nDo you want to continue?",QMessageBox::Yes, QMessageBox::No, 0);
00931                         cout<<"RESPONSE IS "<<response<<endl;
00932                         if(response != QMessageBox::Yes){
00933                                 //Reset button
00934                                 ignoreInitialiseButton = true;
00935                                 initialiseButton->toggle();
00936                                 return;
00937                         }
00938                 }
00939 
00940                 //Reset simulation error map
00941                 simulationErrorMap.clear();
00942 
00943                 //Check that archive name is sensible and it is the right length
00944                 QString archiveName = archNameText->text();
00945                 if(archiveName.length() == 0)
00946                         archiveName = "Untitled";
00947                 else if(archiveName.length() > MAX_DATABASE_NAME_LENGTH)
00948                         archiveName.truncate(MAX_DATABASE_NAME_LENGTH);
00949                 archNameText->setText(archiveName);
00950 
00951                 //Sort out whether spikes or firing neurons are being archived
00952                 map<const char*, unsigned int> parameterMap;
00953                 if(archMonitorTypeCombo->currentText() == "Archive firing neurons")//Archive firing neurons
00954                         parameterMap["ArchiveFiringNeurons"] = 1;
00955                 else if(archMonitorTypeCombo->currentText() == "Archive spikes")//Archive spikes
00956                         parameterMap["ArchiveSpikes"] = 1;
00957                 else
00958                         cerr<<"SimulationWidget. CANNOT IDENTIFY WHETHER ARCHIVING FIRING NEURONS OR SPIKES"<<endl;
00959 
00960                 //Simulation can be a combination of patterns and live mode
00961                 map<unsigned int, unsigned int> patternInputMap;//Key is the neuron group ID; data is the pattern group id
00962                 map<unsigned int, unsigned int> deviceInOutMap;//Key is the neuron group ID; data is the device ID
00963                 map<unsigned int, double> deviceFiringModeMap;//Key is the neuron group ID; data is the firing mode of the device
00964 
00965                 //Fill pattern input map with links between neuron groups and pattern data
00966                 try{
00967                         for(int i=0; i<patternTable->numRows(); ++i){
00968                                 QString comboText = ((QComboTableItem*)patternTable->item(i, patternNeurGrpCol))->currentText();
00969                                 if(comboText != "None"){
00970                                         unsigned int patternGrpID = Utilities::getUInt(patternTable->text(i, patternIDCol).ascii());//Get patternID
00971                                         unsigned int neuronGrpID = Utilities::getNeuronGrpID(comboText);
00972                                         if(patternInputMap.count(neuronGrpID) > 0){//Check neuron group has not been entered twice
00973                                                 QMessageBox::critical (this, "Simulation Error", "Two patterns cannot be applied to a single neuron group", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
00974                                                 //Reset button
00975                                                 ignoreInitialiseButton = true;
00976                                                 initialiseButton->toggle();
00977                                                 return;
00978                                         }
00979                                         else
00980                                                 patternInputMap[neuronGrpID] = patternGrpID;
00981                                 }
00982                         }
00983                         //Fill parameter map with relevant simulation parameters
00984                         parameterMap["TimeStepsPerPattern"] = Utilities::getUInt(timeStepsPatternText->text().ascii());
00985         
00986                         //Fill device in out map with links between neuron groups and devices
00987                         for(int i=0; i<deviceTable->numRows(); ++i){
00988                                 QString comboText = ((QComboTableItem*)deviceTable->item(i, deviceNeurGrpCol))->currentText();
00989                                 if(comboText != "None"){//Device has been set
00990                                         unsigned int deviceID = Utilities::getUInt(deviceTable->text(i, deviceIDCol).ascii());//Get device ID
00991                                         unsigned int neuronGrpID = Utilities::getNeuronGrpID(comboText.ascii());
00992                                         if(deviceInOutMap.count(neuronGrpID) > 0){//Check neuron group has not been entered twice
00993                                                 QMessageBox::critical (this, "Simulation Error", "Two devices cannot be connected to a single neuron group", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
00994                                                 //Reset button
00995                                                 ignoreInitialiseButton = true;
00996                                                 initialiseButton->toggle();
00997                                                 return;
00998                                         }
00999                                         else{
01000                                                 //Store link between neuron group and device
01001                                                 deviceInOutMap[neuronGrpID] = deviceID;
01002 
01003                                                 //Extract information about the firing mode of the device
01004                                                 QString directFiringStr = deviceTable->item(i, deviceFiringModeCol)->text();
01005                                                 if(directFiringStr == "Direct"){
01006                                                         deviceFiringModeMap[neuronGrpID] = INPUT_DIRECT_FIRING_MODE;
01007                                                 }
01008                                                 else if(directFiringStr == "N/A"){
01009                                                         deviceFiringModeMap[neuronGrpID] = OUTPUT_FIRING_MODE;
01010                                                 }
01011                                                 else{//Need to extract the synaptic weight
01012                                                         QString synWeightStr = directFiringStr.section(" ", 2, 2);
01013                                                         deviceFiringModeMap[neuronGrpID] = Utilities::getDouble(synWeightStr.ascii());
01014                                                 }
01015                                         }
01016                                 }
01017                         }
01018                 }
01019                 catch(std::exception& er){// Catch-all for any other exceptions
01020                         cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
01021                         QString errorString = "Exception thrown initialising simulation: \"";
01022                         errorString += er.what();
01023                         errorString += "\"";
01024                         QMessageBox::critical( 0, "Initialise Simulation Error", errorString);
01025                         ignoreInitialiseButton = true;//Reset button
01026                         initialiseButton->toggle();
01027                         return;
01028                 }
01029 
01030                 //Run a quick check that user has not entered a neuron group in both tables
01031                 for(map<unsigned int, unsigned int>::iterator iter = patternInputMap.begin(); iter != patternInputMap.end(); ++iter){
01032                         if(deviceInOutMap.count(iter->first)){
01033                                 QMessageBox::critical (this, "Simulation Error", "A pattern and a device cannot be connected to a single neuron group", QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
01034                                 //Reset button
01035                                 ignoreInitialiseButton = true;
01036                                 initialiseButton->toggle();
01037                                 return;
01038                         }
01039                 }
01040 
01041                 /*Reset simulationStartTime. 
01042                         This should be set by the simulation manager if everything launches successfully */
01043                 simulationStartTime = 0;
01044 
01045                 //Start the simulation
01046                 StartSimRes startSimRes = simulationManager->initialiseSimulation(archiveName, patternInputMap, deviceInOutMap, deviceFiringModeMap, parameterMap);
01047 
01048                 if(startSimRes.started) {//If the simulation initialises successfully
01049                         /*Inform simulation manager that graphics loading is in progress
01050                                 This is to avoid visibility changes being sent to neuron simulation tasks whilst loading */
01051                         simulationManager->setGraphicsLoading(true);
01052 
01053                         //Set button text
01054                         initialiseButton->setText("Destroy");
01055 
01056                         //Load up dock windows ready for live monitoring of the simulation
01057                         monitorArea->loadSimulation();
01058 
01059                         //Pass references to the network monitors to the simulation manager
01060                         monitorArea->connectToManager();
01061                         
01062                         // Enable/disable relevant components
01063                         settingsGrpBox->setEnabled(false);
01064                         simStartButton->setEnabled(true);
01065                         simStepButton->setEnabled(true);
01066                         simStopButton->setEnabled(true);
01067                         recordButton->setEnabled(true);
01068                         liveMonitorTypeCombo->setEnabled(true);
01069                         monitorButton->setEnabled(true);
01070                         dockAllButton->setEnabled(true);
01071                         undockAllButton->setEnabled(true);
01072                         reloadWeightsButton->setEnabled(true);
01073                         saveWeightsButton->setEnabled(true);
01074                         viewWeightsButton->setEnabled(true);
01075                         frameRateCombo->setEnabled(true);
01076                         simModeCombo->setEnabled(true);
01077 
01078                         //Load up combos with appropriate names and initialise them
01079                         loadNeuronGrpNames(neuronGrpMonitorCombo);
01080                         neuronGrpMonitorCombo->insertItem("All layers");
01081                         neuronGrpMonitorCombo->setCurrentItem(neuronGrpMonitorCombo->count() - 1);
01082                         neuronGrpMonitorCombo->setEnabled(true);
01083                         loadNeuronGrpNames(injectNoiseNeurGrpCombo);
01084                         injectNoiseNeurGrpCombo->setEnabled(true);
01085                         injectNoiseAmntCombo->setEnabled(true);
01086                         injectNoiseButton->setEnabled(true);
01087                         loadNeuronGrpNames(fireNeuronCombo);
01088                         fireNeuronComboActivated(fireNeuronCombo->currentText());//Sets the ranges for the text field
01089                         fireNeuronCombo->setEnabled(true);
01090                         fireNeuronText->setEnabled(true);
01091                         fireNeuronButton->setEnabled(true);
01092                         loadNeuronGrpNames(monitorNeuronCombo);
01093                         monitorNeuronComboActivated(monitorNeuronCombo->currentText());//Sets the ranges for the text field
01094                         monitorNeuronCombo->setEnabled(true);
01095                         monitorNeuronText->setEnabled(true);
01096                         monitorNeuronButton->setEnabled(true);
01097                         monitorSynapseFromLabel->setEnabled(true);
01098                         monitorSynapseToLabel->setEnabled(true);
01099                         monitorSynapseFromNumLabel->setEnabled(true);
01100                         monitorSynapseToNumLabel->setEnabled(true);
01101                         monitorSynapseButton->setEnabled(true);
01102                         hideGraphsButton->setEnabled(true);
01103                         showGraphsButton->setEnabled(true);
01104 
01105                         /* Trigger event for frame rate combo. If this has been set during a previous
01106                                 simulation want to set the simulation to this previous value */
01107                         frameRateComboChanged(0);
01108 
01109                         /* Trigger event for simulatoin mode combo. If this has been set during a previous
01110                                 simulation run, want to set simulatin to this previous value. */
01111                         simModeComboChanged(simModeCombo->currentItem());
01112 
01113                         //Start timer to check for errors from the simulation manager
01114                 simErrorCheckTimer->start( 500, FALSE ); // 1/2 second repeating timer
01115 
01116                         /* Inform neuron application that simulation is running to enable/ disable
01117                                 any other components */
01118                         simulationManager->setGraphicsLoading(false);
01119                         SpikeStreamMainWindow::spikeStrMainWin->simulationInitialised();
01120                 }
01121                 
01122                 //Simulation failed to initialse
01123                 else{
01124                         //Inform user about error if simulation was not cancelled by user or if there was an error during clean up
01125                         if((!startSimRes.canceled) || simulationManager->getCleanUpError()){
01126                                 QString initErrorMessage("Error occurred whilst initialising simulation:\n");
01127                                 initErrorMessage += simulationManager->getInitErrorMsg();
01128                                 initErrorMessage += "Would you like to run the CleanPVM script?";
01129                                 if(QMessageBox::critical (this, "Simulation Error", initErrorMessage, QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel) == QMessageBox::Yes){
01130                                         ScriptRunner scriptRunner (this, "CleanPVM", SpikeStreamMainWindow::workingDirectory);
01131                                         scriptRunner.exec();
01132                                 }
01133                         }
01134 
01135                         //Reset button
01136                         ignoreInitialiseButton = true;
01137                         initialiseButton->toggle();
01138                         return;
01139                 }
01140         }
01141 
01142         //Simulation is to be destroyed
01143         else{
01144                 //Confirm that the user wants to end the simulation
01145                 int warningConfirmation = QMessageBox::warning (this, "Destroy Simulation?", "Are you sure that you want to terminate the simulation?", QMessageBox::Ok,  QMessageBox::Cancel, QMessageBox::NoButton);
01146                 if(warningConfirmation != QMessageBox::Ok){//1 is returned for cancel and closing message box
01147                         ignoreInitialiseButton = true;
01148                         initialiseButton->toggle();
01149                         return;
01150                 }
01151 
01152                 //User has confirmed, so destroy simulation
01153                 //Stop recording if it is recording
01154                 if(recordButton->isOn()){
01155                         simulationManager->stopRecording();
01156                         ignoreRecordButton = true;
01157                         recordButton->toggle();
01158                 }
01159 
01160                 //Destroy simulation
01161                 initialiseButton->setText("Initialise");
01162                 if(simulationManager->isInitialised()){
01163                         //Stop the timer checking for errors - clean up errors will be picked up at the end
01164                         simErrorCheckTimer->stop();     
01165 
01166                         //Destroy the simulation
01167                         simulationManager->destroySimulation();
01168 
01169                         //Reset simulation start time
01170                         simulationStartTime = 0;
01171                         
01172                         //Enable/disable relevant graphical componentes
01173                         settingsGrpBox->setEnabled(true);
01174                         simStartButton->setEnabled(false);
01175                         if(simStartButton->isOn())
01176                                 simStartButton->toggle();
01177                         simStepButton->setEnabled(false);
01178                         simStopButton->setEnabled(false);
01179                         recordButton->setEnabled(false);
01180                         liveMonitorTypeCombo->setEnabled(false);
01181                         monitorButton->setEnabled(false);
01182                         neuronGrpMonitorCombo->setEnabled(false);
01183                         injectNoiseNeurGrpCombo->setEnabled(false);
01184                         injectNoiseAmntCombo->setEnabled(false);
01185                         injectNoiseButton->setEnabled(false);
01186                         fireNeuronCombo->setEnabled(false);
01187                         fireNeuronText->setEnabled(false);
01188                         fireNeuronButton->setEnabled(false);
01189                         monitorNeuronCombo->setEnabled(false);
01190                         monitorNeuronText->setEnabled(false);
01191                         monitorNeuronButton->setEnabled(false);
01192                         monitorArea->resetMonitorWindows();
01193                         dockAllButton->setEnabled(false);
01194                         undockAllButton->setEnabled(false);
01195                         saveWeightsButton->setEnabled(false);
01196                         reloadWeightsButton->setEnabled(false);
01197                         viewWeightsButton->setEnabled(false);
01198                         frameRateCombo->setEnabled(false);
01199                         simModeCombo->setEnabled(false);
01200                         monitorSynapseFromLabel->setEnabled(false);
01201                         monitorSynapseToLabel->setEnabled(false);
01202                         monitorSynapseFromNumLabel->setEnabled(false);
01203                         monitorSynapseToNumLabel->setEnabled(false);
01204                         monitorSynapseButton->setEnabled(false);
01205                         hideGraphsButton->setEnabled(false);
01206                         showGraphsButton->setEnabled(false);
01207 
01208                         //Wait for simulation manager to stop
01209                         bool threadFinished = false;
01210                         int cycleCount = 0;
01211                         while(cycleCount < 300 && !threadFinished){
01212                                 threadFinished = simulationManager->wait(100);
01213                                 ++cycleCount;
01214                                 spikeStrApp->processEvents();
01215                         }
01216                         if(!threadFinished){//Problem shutting down simulation manager
01217                                 cerr<<"Simulation manager cannot be shut down cleanly within 30 seconds."<<endl;
01218                                 QMessageBox::critical(this, "Simulation Error", "Simulation manager cannot be shut down cleanly within 30 seconds.");
01219                         }
01220 
01221                         //Check for clean up error in simulation manager
01222                         if(simulationManager->getCleanUpError()){
01223                                 QString cleanUpErrorMessage("Error occurred whilst cleaning up simulation:\n");
01224                                 cleanUpErrorMessage += simulationManager->getCleanUpErrorMsg();
01225                                 cleanUpErrorMessage += "Would you like to run the CleanPVM script?";
01226                                 if(QMessageBox::critical (this, "Simulation Error", cleanUpErrorMessage, QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel) == QMessageBox::Yes){
01227                                         ScriptRunner scriptRunner (this, "CleanPVM", SpikeStreamMainWindow::workingDirectory);
01228                                         scriptRunner.exec();
01229                                 }
01230                         }
01231 
01232                         //Delete any remaining neuron monitor widgets
01233                         for(map<unsigned int, MonitorDataPlotter*>::iterator iter = neuronMonitorMap.begin(); iter != neuronMonitorMap.end(); ++iter){
01234                                 iter->second->closeDialog(false);
01235                                 delete iter->second;
01236                         }
01237                         neuronMonitorMap.clear();
01238 
01239                         //Delete any remaining synapse monitor widgets
01240                         for(map<unsigned int*, MonitorDataPlotter*, synapseKeyCompare>::iterator iter = synapseMonitorMap.begin(); iter != synapseMonitorMap.end(); ++iter){
01241                                 iter->second->closeDialog(false);//Close dialog window
01242                                 delete iter->second;//Delete monitor data plotter
01243                                 delete [] iter->first;//Delete key to map
01244                         }
01245                         synapseMonitorMap.clear();//Remove pointers from map
01246 
01247                         /* Inform neuron application that simulation has been destroyed to 
01248                                 enable or disable any other components */
01249                         SpikeStreamMainWindow::spikeStrMainWin->simulationDestroyed();
01250                 }
01251         }
01252 }
01253 
01254 
01255 /*! Injects the specified amount of noise into a neuron group. */
01256 void SimulationWidget::injectNoiseButtonPressed(){
01257         if(injectNoiseNeurGrpCombo->count() <=0)//Check for empty combo box
01258                 return;
01259 
01260         QString name = injectNoiseNeurGrpCombo->currentText();
01261         unsigned int neuronGrpID = Utilities::getNeuronGrpID(name);
01262         int noiseAmount;
01263         switch(injectNoiseAmntCombo->currentItem()){
01264                 case(0): noiseAmount = -1; break;//-1 means fire a single neuron
01265                 case(1): noiseAmount = 5; break;
01266                 case(2): noiseAmount = 25; break;
01267                 case(3): noiseAmount = 50; break;
01268                 case(4): noiseAmount = 75; break;
01269                 case(5): noiseAmount = 100; break;
01270                 default: cerr<<"Noise amount not recognised: "; return; 
01271         }
01272         simulationManager->injectNoise(neuronGrpID, noiseAmount);
01273 }
01274 
01275 
01276 /*! Make the associated network monitor visible in the dock area. */
01277 void SimulationWidget::monitorButtonPressed(){
01278         //Get the name of the neuron group to be monitored
01279         QString name = neuronGrpMonitorCombo->currentText();
01280 
01281         //Find out what type of monitoring
01282         bool monitorNeurons = true;
01283         if(liveMonitorTypeCombo->currentText() == "Neurons")
01284                 monitorNeurons = true;
01285         else if(liveMonitorTypeCombo->currentText() == "Spikes")
01286                 monitorNeurons = false;
01287         else{
01288                 cerr<<"SimulationWidget: CANNOT IDENTIFY MONITORING TYPE"<<endl;
01289                 return;
01290         }
01291 
01292         //Set the monitoring appropriately
01293         if(name == "All layers"){
01294                 monitorArea->showAllMonitorWindows(monitorNeurons);
01295         }
01296         else{
01297                 unsigned int neuronGrpID = Utilities::getNeuronGrpID(name);     
01298                 monitorArea->showMonitorWindow(neuronGrpID, monitorNeurons);
01299         }
01300 
01301         //Undock the monitoring windows
01302         monitorArea->undockMonitorWindows();
01303 }
01304 
01305 
01306 /*! Monitors a single neuron. */
01307 void SimulationWidget::monitorNeuronButtonPressed(){
01308         //Return if no layers are present
01309         if(monitorNeuronCombo->count() <=0)
01310                 return;
01311 
01312         //Get the details about the neuron group
01313         unsigned int neuronID = 0, neuronGrpID = 0;
01314         try{
01315                 neuronID = Utilities::getUInt(monitorNeuronText->text().ascii());
01316                 neuronGrpID = Utilities::getNeuronGrpID(monitorNeuronCombo->currentText());
01317         }
01318         catch(std::exception& er){// Catch-all for any other exceptions
01319                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
01320                 QString errorString = "Exception thrown getting neuron or neuron group ID: \"";
01321                 errorString += er.what();
01322                 errorString += "\"";
01323                 QMessageBox::critical( 0, "Monitor Neuron Error", errorString);
01324                 return;
01325         }
01326 
01327         if(neuronID < minMonitorNeuronID || neuronID > maxMonitorNeuronID){
01328                 QMessageBox::critical(this, "Monitor Neuron Error", "The neuron ID is out of range for this neuron group");
01329                 return;
01330         }
01331 
01332         //Are we already monitoring this neuron group?
01333         if(neuronMonitorMap.count(neuronID)){
01334                 #ifdef MONITOR_NEURON_DATA_DEBUG
01335                         cout<<"SimulationWidget: Neuron "<<neuronID<<" is already being monitored."<<endl;
01336                 #endif//MONITOR_NEURON_DATA_DEBUG
01337 
01338                 //Return if dialog is open and presumably active.
01339                 if(neuronMonitorMap[neuronID]->isShown()){
01340                         #ifdef MONITOR_NEURON_DATA_DEBUG
01341                                 cout<<"SimulationWidget: Neuron data graph is already being shown."<<endl;
01342                         #endif//MONITOR_NEURON_DATA_DEBUG
01343                         return;
01344                 }
01345 
01346                 //Neuron group is not being monitored
01347                 else{
01348                         #ifdef MONITOR_NEURON_DATA_DEBUG
01349                                 cout<<"SimulationWidget: Showing neuron data graph."<<endl;
01350                         #endif//MONITOR_NEURON_DATA_DEBUG
01351 
01352                         if(!neuronMonitorMap[neuronID]->showDialog()){
01353                                 QMessageBox::critical(this, "Monitor Neuron Error", "Error restarting neuron monitoring.");
01354                                 //Remove neuron monitor
01355                                 neuronMonitorMap[neuronID]->closeDialog(false);//Do not try to stop neuron monitoring - if we are here something is broken with this
01356                                 delete neuronMonitorMap[neuronID];
01357                                 neuronMonitorMap.erase(neuronID);
01358                         }
01359                         return;
01360                 }
01361         }
01362 
01363         #ifdef MONITOR_NEURON_DATA_DEBUG
01364                 cout<<"SimulationWidget: Constructing neuron data graph."<<endl;
01365         #endif//MONITOR_NEURON_DATA_DEBUG
01366 
01367         //Construct a window. When the data about the window is received, the window will be populated with the appropriate graphs
01368         neuronMonitorMap[neuronID] = new MonitorDataPlotter(this, monitorNeuronCombo->currentText(), neuronGrpID, neuronID);
01369 
01370         //Request meta data about which variables are being monitored and check for errors
01371         if(!simulationManager->startNeuronMonitoring(neuronGrpID, neuronID, false)){
01372                 QMessageBox::critical(this, "Monitor Neuron Error", "Error requesting monitor neuron information for this neuron group.");
01373                 
01374                 //Remove neuron monitor and return
01375                 neuronMonitorMap[neuronID]->closeDialog(false);//Do not try to stop monitoring because something is already broken.
01376                 delete neuronMonitorMap[neuronID];
01377                 neuronMonitorMap.erase(neuronID);
01378                 return;
01379         }
01380 }
01381 
01382 
01383 /*! Called when the button has been pressed to start synapse monitoring. */
01384 void SimulationWidget::monitorSynapseButtonPressed(){
01385         //Declare variables to use in the try-catch block.
01386         unsigned int fromNeuronID = 0, toNeuronID = 0, neuronGrpID = 0;
01387         unsigned int* synapseMonKey;
01388 
01389         try{
01390                 //First check that the from and to neurons are present and there is a connection between them.
01391                 fromNeuronID = Utilities::getUInt(monitorSynapseFromNumLabel->text().ascii());
01392                 toNeuronID = Utilities::getUInt(monitorSynapseToNumLabel->text().ascii());
01393                 Query query = networkDBInterface->getQuery();
01394                 query.reset();
01395                 query<<"SELECT COUNT(*) FROM Connections WHERE PreSynapticNeuronID="<<fromNeuronID<<" AND PostSynapticNeuronID="<<toNeuronID;
01396                 Result connRes = query.store();
01397                 Row connRow(*connRes.begin());//Should only be 1 row
01398                 unsigned int numberOfConns = Utilities::getUInt((std::string)connRow["COUNT(*)"]);
01399                 if(numberOfConns != 1){
01400                         QMessageBox::critical(this, "Monitor Synapse", "No synapse selected.\nUse the view tab to select a unique synapse for monitoring.\nCheck the direction of the connection if you are in between mode.");
01401                         return;
01402                 }
01403         
01404                 //Next find the neuron group that the synapse is in
01405                 query.reset();
01406                 query<<"SELECT NeuronGrpID FROM Neurons WHERE NeuronID="<<toNeuronID;
01407                 Result neurGrpRes = query.store();
01408                 Row neurGrpRow(*neurGrpRes.begin());//Should only be 1 row
01409                 neuronGrpID = Utilities::getUInt((std::string)neurGrpRow["NeuronGrpID"]);
01410         
01411                 //Turn neuron ids into a key to the map
01412                 synapseMonKey = new unsigned int[2];
01413                 synapseMonKey[0] = fromNeuronID;
01414                 synapseMonKey[1] = toNeuronID;
01415         
01416                 //Are we already monitoring this neuron group?
01417                 if(synapseMonitorMap.count(synapseMonKey)){
01418                         cout<<"SimulationWidget: Synapse from "<<fromNeuronID<<" to "<<toNeuronID<<" is already being monitored."<<endl;
01419                         //Return if dialog is open and presumably active.
01420                         if(synapseMonitorMap[synapseMonKey]->isShown()){
01421                                 //Get rid of the key, which is identical to the one already in the map
01422                                 delete [] synapseMonKey;
01423                                 return;
01424                         }
01425                         else{
01426                                 if(!synapseMonitorMap[synapseMonKey]->showDialog()){
01427                                         QMessageBox::critical(this, "Monitor Synapse Error", "Error restarting synapse monitoring.");
01428         
01429                                         //Remove synapse monitor
01430                                         synapseMonitorMap[synapseMonKey]->closeDialog(false);//Hide the dialog and do not try to stop monitoring because something is already broken
01431                                         delete synapseMonitorMap[synapseMonKey];//Delete the MonitorDataPlotter
01432                                         synapseMonitorMap.erase(synapseMonKey);//Delete the address of the key in the map
01433                                 }
01434                                 //Get rid of the key, which is identical to the one already in the map
01435                                 delete [] synapseMonKey;
01436                                 return;
01437                         }
01438                 }
01439         }
01440         catch (const BadQuery& er) {// Handle any query errors
01441                 cerr<<"SimulationWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
01442                 QString errorString = "Bad query when starting monitoring of synapse: \"";
01443                 errorString += er.what();
01444                 errorString += "\"";
01445                 QMessageBox::critical( 0, "MonitorSynapse Error", errorString);
01446                 return;
01447         }
01448         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01449                 cerr<<"SimulationWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
01450                 QString errorString = "Exception thrown starting monitoring of synapse: \"";
01451                 errorString += er.what();
01452                 errorString += "\"";
01453                 QMessageBox::critical( 0, "Monitor Synapse Error", errorString);
01454                 return;
01455         }
01456         catch(std::exception& er){// Catch-all for any other exceptions
01457                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
01458                 QString errorString = "Exception thrown starting monitoring of synapse: \"";
01459                 errorString += er.what();
01460                 errorString += "\"";
01461                 QMessageBox::critical( 0, "Monitor Synapse Error", errorString);
01462                 return;
01463         }
01464 
01465         /* Construct a window. When the data about the window is received, the window will be 
01466                 populated with the appropriate graphs. In this case leave synapseMonKey on the heap
01467                 so that it can be found by the map for comparison. */
01468         synapseMonitorMap[synapseMonKey] = new MonitorDataPlotter(this, neuronGrpID, fromNeuronID, toNeuronID);
01469 
01470         //Request meta data about which variables are being monitored and check for errors
01471         if(!simulationManager->startSynapseMonitoring(neuronGrpID, fromNeuronID, toNeuronID, false)){
01472                 QMessageBox::critical(this, "Monitor Synapse Error", "Error requesting monitor information for this synapse.");
01473                 
01474                 //Remove neuron monitor and return
01475                 synapseMonitorMap[synapseMonKey]->closeDialog(false);//Hide the dialog. Do not try to stop monitoring because something is already broken
01476                 delete synapseMonitorMap[synapseMonKey];//Delete the MonitorDataPlotter
01477                 synapseMonitorMap.erase(synapseMonKey);//Delete the address of the key in the map
01478                 delete [] synapseMonKey;//Delete the array of length two that is the key
01479                 return;
01480         }
01481 }
01482 
01483 
01484 /*! Shows the neuron parameter dialog. */
01485 void SimulationWidget::neuronParamButtonPressed(){
01486         if(neuronParametersDialog->loadNeuronParameters())
01487                 neuronParametersDialog->show();
01488 }
01489 
01490 
01491 /*! Shows the noise parameter dialog. */
01492 void SimulationWidget::noiseParamButtonPressed(){
01493         if(noiseParametersDialog->loadParameters())
01494                 noiseParametersDialog->show();
01495 }
01496 
01497 
01498 /*! Starts or stops the recording of neuron data to the archive. */
01499 void SimulationWidget::recordButtonToggled(bool on){
01500         //Ignore events generated by deliberately toggling button
01501         if(ignoreRecordButton){
01502                 ignoreRecordButton = false;
01503                 return;
01504         }
01505 
01506         if(on){//Start recording
01507                 if(!simulationManager->startRecording()){
01508                         ignoreRecordButton = true;//Recording has failed to start so ignore event generated by toggling button
01509                         recordButton->toggle();
01510                 }
01511         }
01512         else{//Stop recording
01513                 if(!simulationManager->stopRecording()){
01514                         ignoreRecordButton = true;//Recording has failed to stop so ignore event generated by toggling button
01515                         recordButton->toggle();
01516                 }
01517         }
01518 }
01519 
01520 
01521 /*! Reloads weights from the database into the neuron groups. This resets the weights
01522         in the simulation without restarting it. */
01523 void SimulationWidget::reloadWeightsButtonPressed(){
01524         int warningConfirmation = QMessageBox::warning (this, "Reload weights", "Are you sure that you want to reload the synapse weights?\nThis will overwrite any weights that have been learnt.", QMessageBox::Ok,  QMessageBox::Cancel, QMessageBox::NoButton);
01525         if(warningConfirmation == QMessageBox::Ok){//1 is returned for cancel and closing message box
01526                 /* Instruct simulation manager to send save weights message. 
01527                         This should be almost instantaneous */
01528                 if(!simulationManager->loadWeights())
01529                          QMessageBox::critical (this, "Weight Loading Error!", "An error occurred whilst reloading synapse weights.", QMessageBox::Ok,  QMessageBox::NoButton, QMessageBox::NoButton);
01530 
01531                 // Show busy dialog box
01532                 busyDialog = new BusyDialog(this, QString("Simulation"));
01533                 busyDialog->showDialog("Loading weights, please wait");
01534 
01535                 /* Start timer to check to see if weights have been loaded, if not refresh
01536                         busy dialog and restart timer */
01537         QTimer *timer = new QTimer(this);
01538         connect( timer, SIGNAL(timeout()), this, SLOT(checkWeightsLoadState()) );
01539         timer->start( 1000, TRUE ); // 1 second single-shot timer
01540         }
01541 }
01542 
01543 
01544 /*! Instructs the tasks to save their weights to the database. */
01545 void SimulationWidget::saveWeightsButtonPressed(){
01546         int warningConfirmation = QMessageBox::warning (this, "Save weights", "Are you sure that you want to save the current synapse weights?\nThis will overwrite all the weights in the database.", QMessageBox::Ok,  QMessageBox::Cancel, QMessageBox::NoButton);
01547         if(warningConfirmation == QMessageBox::Ok){//1 is returned for cancel and closing message box
01548                 /* Instruct simulation manager to send save weights message. 
01549                         This should be almost instantaneous */
01550                 if(!simulationManager->saveWeights())
01551                          QMessageBox::critical (this, "Weight Saving Error!", "An error occurred whilst saving the synapse weights.", QMessageBox::Ok,  QMessageBox::NoButton, QMessageBox::NoButton);
01552 
01553                 // Show busy dialog box
01554                 busyDialog = new BusyDialog(this, QString("Simulation"));
01555                 busyDialog->showDialog("Saving weights, please wait");
01556 
01557                 /* Start timer to check to see if weights have been saved, if not refresh
01558                         busy dialog and restart timer */
01559         QTimer *timer = new QTimer(this);
01560         connect( timer, SIGNAL(timeout()), this, SLOT(checkWeightsSaveState()) );
01561         timer->start( 500, TRUE ); // 1 second single-shot timer
01562         }
01563 }
01564 
01565 
01566 /*! Sets the simulation start time - used to prevent the deletion of
01567         active archives. */
01568 void SimulationWidget::setSimulationStartTime(unsigned int simStartTime){
01569         SimulationWidget::simulationStartTime = simStartTime;
01570 }
01571 
01572 
01573 /*! Shows all of the graphs monitoring data. */
01574 void SimulationWidget::showGraphsButtonClicked(){
01575         for(map<unsigned int, MonitorDataPlotter*>::iterator iter = neuronMonitorMap.begin(); iter != neuronMonitorMap.end(); ++iter){
01576                 if(!iter->second->isShown()){
01577                         if(!iter->second->showDialog()){
01578                                 QMessageBox::critical(this, "Monitor Error", "Error restarting monitoring.");
01579                         }
01580                 }
01581         }
01582         //Work through all the synapse monitors and show them
01583         for (map<unsigned int*, MonitorDataPlotter*, synapseKeyCompare>::iterator iter = synapseMonitorMap.begin(); iter != synapseMonitorMap.end(); ++iter){
01584                 if(!iter->second->isShown()){
01585                         if(!iter->second->showDialog()){
01586                                 QMessageBox::critical(this, "Monitor Error", "Error restarting monitoring.");
01587                         }
01588                 }
01589         }
01590 }
01591 
01592 
01593 /*! Called when the combo setting the simulation mode is changed.
01594         Instructs the simulation manager to set the simulation mode appropriately. */
01595 void SimulationWidget::simModeComboChanged(int currentIndex){
01596         switch(currentIndex){
01597                 case 0: simulationManager->setUpdateMode(false, false); break; //Event driven updates
01598                 case 1: simulationManager->setUpdateMode(true, false); break;//Update all neurons at each time step
01599                 case 2: simulationManager->setUpdateMode(false, true); break;//Update all synapses at each time step
01600                 case 3: simulationManager->setUpdateMode(true, true); break;//Update all neurons and symapses at each time step
01601                 default: cerr<<"SimulationWidget: SIMULATION MODE COMBO OPTION NOT RECOGNIZED: "<<currentIndex<<endl;
01602         }
01603 }
01604 
01605 
01606 /*! Starts or stops the simulation playing. */
01607 void SimulationWidget::simStartButtonToggled(bool on){
01608         if(on){
01609                 if(simulationManager->startSimulation()){//If the simulation start successfully
01610                         cout<<"Simulation started"<<endl;
01611                         reloadWeightsButton->setEnabled(false);
01612                         saveWeightsButton->setEnabled(false);
01613                         viewWeightsButton->setEnabled(false);
01614                         initialiseButton->setEnabled(false);
01615                 }
01616         }
01617         else{
01618                 simStopButtonPressed();
01619         }
01620 }
01621 
01622 
01623 /*! Steps through the simulation one time step at a time.
01624         NOTE this method is pretty slow, probably because of messaging
01625         lags in PVM. */
01626 void SimulationWidget::simStepButtonPressed(){
01627         if(simStartButton->isOn())
01628                 simStartButton->toggle();
01629         simulationManager->stepSimulation();
01630 }
01631 
01632 
01633 /*! Stops the simulation without destroying it. */
01634 void SimulationWidget::simStopButtonPressed(){
01635         if(simulationManager->isRunning()){
01636                 if(simulationManager->stopSimulation()){
01637                         initialiseButton->setEnabled(true);
01638                         if(simStartButton->isOn())
01639                                 simStartButton->toggle();
01640                         saveWeightsButton->setEnabled(true);
01641                         viewWeightsButton->setEnabled(true);
01642                         reloadWeightsButton->setEnabled(true);
01643                 }
01644         }
01645 }
01646 
01647 
01648 /*! Shows the synapse parameters dialog. */
01649 void SimulationWidget::synapseParamButtonPressed(){
01650         if(synapseParametersDialog->loadSynapseParameters())
01651                 synapseParametersDialog->show();
01652 }
01653 
01654 
01655 /*! Undocks all monitor windows. */
01656 void SimulationWidget::undockAllButtonClicked(){
01657         monitorArea->undockMonitorWindows();
01658 }
01659 
01660 
01661 /*! Instructs the tasks to save their weights to the database. */
01662 void SimulationWidget::viewWeightsButtonPressed(){
01663 /* Instruct simulation manager to send view weights message. 
01664         This should be almost instantaneous. */
01665         if(!simulationManager->saveViewWeights())
01666                         QMessageBox::critical (this, "View Weight Saving Error!", "An error occurred whilst saving the synapse weights for viewing.", QMessageBox::Ok,  QMessageBox::NoButton, QMessageBox::NoButton);
01667 
01668         // Show busy dialog box
01669         busyDialog = new BusyDialog(this, QString("Simulation"));
01670         busyDialog->showDialog("Saving weights for viewing, please wait");
01671 
01672         /* Start timer to check to see if weights have been saved, if not refresh
01673                 busy dialog and restart timer */
01674         QTimer *timer = new QTimer(this);
01675         connect( timer, SIGNAL(timeout()), this, SLOT(checkViewWeightsSaved()) );
01676         timer->start( 500, TRUE ); // 1/2 second single-shot timer
01677 }
01678 
01679 
01680 //----------------------------------------------------------------------
01681 //----------------------- PRIVATE METHODS ------------------------------
01682 //----------------------------------------------------------------------
01683 
01684 /*! Loads a list of layer names and IDs into a qstringlist
01685         Adapted from method in connection properties dialog. */
01686 void SimulationWidget::getNeuronGrpNames(QStringList &stringList, unsigned int patternWidth, unsigned int patternLength){
01687         try{
01688                 stringList.clear();
01689                 stringList += "None";
01690                 Query query = networkDBInterface->getQuery();
01691                 query.reset();
01692                 query<<"SELECT Name, NeuronGrpID, Width, Length FROM NeuronGroups";
01693                 Result neurGrpResult= query.store();
01694                 for(Result::iterator resIter = neurGrpResult.begin(); resIter < neurGrpResult.end(); resIter++){
01695                         Row row(*resIter);
01696                         /* Check to see if the width and length of the neuron group
01697                                 match that of the pattern */
01698                         unsigned int neurGrpWidth = Utilities::getUInt((std::string)row["Width"]);
01699                         unsigned int neurGrpLength = Utilities::getUInt((std::string)row["Length"]);
01700                         if((neurGrpWidth == patternWidth && neurGrpLength == patternLength) || (neurGrpWidth == patternLength && neurGrpLength == patternWidth)){
01701                                 QString neurGrpString((std::string)row["Name"] + " [" += (std::string)row["NeuronGrpID"] += "]");
01702                                 stringList += neurGrpString;
01703                         }
01704                 }
01705         }
01706         catch (const BadQuery& er) {// Handle any query errors
01707                 cerr<<"SimulationWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
01708                 QString errorString = "Bad query when getting neuron group names: \"";
01709                 errorString += er.what();
01710                 errorString += "\"";
01711                 QMessageBox::critical( 0, "Neuron Group Error", errorString);
01712         }
01713         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01714                 cerr<<"SimulationWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
01715                 QString errorString = "Exception thrown getting neuron group names: \"";
01716                 errorString += er.what();
01717                 errorString += "\"";
01718                 QMessageBox::critical( 0, "Neuron Group Error", errorString);
01719         }
01720         catch(std::exception& er){// Catch-all for any other exceptions
01721                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
01722                 QString errorString = "Exception thrown getting neuron group names: \"";
01723                 errorString += er.what();
01724                 errorString += "\"";
01725                 QMessageBox::critical( 0, "Neuron Group Error", errorString);
01726         }
01727 }
01728 
01729 
01730 /*! Loads a table with all the available patterns. 
01731         Enables a pattern to be assigned to a suitable neuron group before the simulation starts. */
01732 void SimulationWidget::loadDeviceTable(){
01733         //Empty device table
01734         deviceTable->setNumRows(0);
01735         
01736         //Load up a row for each pattern in the database
01737         try{
01738                 Query deviceQuery = deviceDBInterface->getQuery();
01739                 deviceQuery.reset();
01740                 deviceQuery<<"SELECT DeviceID, Description, IPAddress, Port, Type, TotalNumColumns, TotalNumRows FROM Devices";
01741                 Result result = deviceQuery.store();
01742                 for(Result::iterator iter = result.begin(); iter != result.end(); ++iter){
01743                         Row row(*iter);
01744                 
01745                         //Add new row to the table
01746                         int currentRow = deviceTable->numRows();
01747                         deviceTable->insertRows(currentRow, 1);
01748                 
01749                         //Populate row with pattern information
01750                         deviceTable->setItem(currentRow, 0,
01751                                 new QTableItem(deviceTable, QTableItem::Never, (std::string)row["DeviceID"]));//DeviceID
01752         
01753                         deviceTable->setItem(currentRow, 1,
01754                                 new QTableItem(deviceTable, QTableItem::Never, (std::string)row["Description"]));//Description
01755                 
01756                         unsigned int deviceType = Utilities::getUInt((std::string)row["Type"]);
01757                         deviceTable->setItem(currentRow, 2,
01758                                 new QTableItem(deviceTable, QTableItem::Never, DeviceTypes::getDescription(deviceType)));//Type
01759                 
01760                         deviceTable->setItem(currentRow, 3,
01761                                 new QTableItem(deviceTable, QTableItem::Never, (std::string)row["IPAddress"]));//IPAddress
01762         
01763                         deviceTable->setItem(currentRow, 4,
01764                                 new QTableItem(deviceTable, QTableItem::Never, (std::string)row["Port"]));//Port
01765         
01766                         deviceTable->setItem(currentRow, 5,
01767                                 new QTableItem(deviceTable, QTableItem::Never, (std::string)row["TotalNumColumns"]));//Width
01768         
01769                         deviceTable->setItem(currentRow, 6,
01770                                 new QTableItem(deviceTable, QTableItem::Never, (std::string)row["TotalNumRows"]));//Length
01771                 
01772                         /*Get a list of neuron group names that have the correct width and length
01773                                 for this device and add them to a combo box in the table */
01774                         QStringList neuronNamesList;
01775                         unsigned int deviceWidth = Utilities::getUInt((std::string)row["TotalNumColumns"]);
01776                         unsigned int deviceLength = Utilities::getUInt((std::string)row["TotalNumRows"]);
01777                         getNeuronGrpNames(neuronNamesList, deviceWidth, deviceLength);
01778                         deviceTable->setItem(currentRow, 7, new QComboTableItem(deviceTable, neuronNamesList));
01779 
01780                         //If the device is supplying input to the network, add combo with choices of type of input
01781                         if(DeviceTypes::isInputDevice(deviceType)){
01782                                 QStringList firingModeStrList;
01783                                 firingModeStrList += "Direct";
01784                                 for(double i=-1.0; i<=1.0; i += 0.2){
01785                                         if(rint(i * 10) == 0.0)//QString::number gives a strange very small value for zero
01786                                                 firingModeStrList += "Synaptic weight 0";
01787                                         else
01788                                                 firingModeStrList += "Synaptic weight " + QString::number(i);
01789                                 }
01790                                 QComboTableItem* tempFiringModeCombo = new QComboTableItem(deviceTable, firingModeStrList);
01791                                 deviceTable->setItem(currentRow, deviceFiringModeCol, tempFiringModeCombo);
01792                         }
01793                         //Otherwise just add a combo with n/a
01794                         else{
01795                                 QStringList firingModeStrList;
01796                                 firingModeStrList += "N/A";
01797                                 QComboTableItem* tempFiringModeCombo = new QComboTableItem(deviceTable, firingModeStrList);
01798                                 deviceTable->setItem(currentRow, deviceFiringModeCol, tempFiringModeCombo);
01799                         }
01800                 }
01801         }
01802         catch (const BadQuery& er) {// Handle any query errors
01803                 cerr<<"SimulationWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
01804                 QString errorString = "Bad query when filling device table: \"";
01805                 errorString += er.what();
01806                 errorString += "\"";
01807                 QMessageBox::critical( 0, "Device Error", errorString);
01808         }
01809         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01810                 cerr<<"SimulationWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
01811                 QString errorString = "Exception thrown filling device table: \"";
01812                 errorString += er.what();
01813                 errorString += "\"";
01814                 QMessageBox::critical( 0, "Device Error", errorString);
01815         }
01816         catch(std::exception& er){// Catch-all for any other exceptions
01817                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
01818                 QString errorString = "Exception thrown filling device table: \"";
01819                 errorString += er.what();
01820                 errorString += "\"";
01821                 QMessageBox::critical( 0, "Device Error", errorString);
01822         }
01823 }
01824 
01825 
01826 /*! Loads a list of layer names and IDs into a combo box 
01827         Adapted from method in connection properties dialog. */
01828 void SimulationWidget::loadNeuronGrpNames(QComboBox *comboBox){
01829         comboBox->clear();
01830         try{
01831                 Query query = networkDBInterface->getQuery();
01832                 query.reset();
01833                 query<<"SELECT Name, NeuronGrpID FROM NeuronGroups";
01834                 Result neurGrpResult= query.store();
01835                 for(Result::iterator resIter = neurGrpResult.begin(); resIter < neurGrpResult.end(); resIter++){
01836                         Row row(*resIter);
01837                         QString neurGrpString((std::string)row["Name"] + " [" += (std::string)row["NeuronGrpID"] += "]");
01838                         comboBox->insertItem(neurGrpString);
01839                 }
01840         }
01841         catch (const BadQuery& er) {// Handle any query errors
01842                 cerr<<"SimulationWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
01843                 QString errorString = "Bad query when loading neuron group names: \"";
01844                 errorString += er.what();
01845                 errorString += "\"";
01846                 QMessageBox::critical( 0, "Neuron Group Error", errorString);
01847         }
01848         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01849                 cerr<<"SimulationWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
01850                 QString errorString = "Exception thrown loading neuron group names: \"";
01851                 errorString += er.what();
01852                 errorString += "\"";
01853                 QMessageBox::critical( 0, "Neuron Group Error", errorString);
01854         }
01855 }
01856 
01857 
01858 /*! Loads a table with all the available patterns. 
01859         Enables a pattern to be assigned to a suitable neuron group before the simulation starts. */
01860 void SimulationWidget::loadPatternTable(){
01861         //Empty pattern table
01862         patternTable->setNumRows(0);
01863         
01864         //Load up a row for each pattern in the database
01865         try{
01866                 Query patternQuery = patternDBInterface->getQuery();
01867                 patternQuery.reset();
01868                 patternQuery<<"SELECT PatternGrpID, Description, PatternType, Width, Length, NumberOfPatterns FROM PatternDescriptions";
01869                 Result result = patternQuery.store();
01870                 for(Result::iterator iter = result.begin(); iter != result.end(); ++iter){
01871                         Row row(*iter);
01872                         //Add new row to the table
01873                         int currentRow = patternTable->numRows();
01874                         patternTable->insertRows(currentRow, 1);
01875                 
01876                         //Populate row with pattern information
01877                         patternTable->setItem(currentRow, 0,
01878                                 new QTableItem(patternTable, QTableItem::Never, (std::string)row["PatternGrpID"]));//PatternGrpID
01879         
01880                         patternTable->setItem(currentRow, 1,
01881                                 new QTableItem(patternTable, QTableItem::Never, (std::string)row["Description"]));//Description
01882                 
01883                         unsigned int patternType = Utilities::getUInt((std::string)row["PatternType"]);
01884                         patternTable->setItem(currentRow, 2,
01885                                 new QTableItem(patternTable, QTableItem::Never, PatternTypes::getDescription(patternType)));//Pattern Type
01886                 
01887                         patternTable->setItem(currentRow, 3,
01888                                 new QTableItem(patternTable, QTableItem::Never, (std::string)row["Width"]));//Width
01889                 
01890                         patternTable->setItem(currentRow, 4,
01891                                 new QTableItem(patternTable, QTableItem::Never, (std::string)row["Length"]));//Length
01892                 
01893                         patternTable->setItem(currentRow, 5,
01894                                 new QTableItem(patternTable, QTableItem::Never, (std::string)row["NumberOfPatterns"]));//Width
01895                 
01896                         //Get a list of neuron group names
01897                         QStringList neuronNamesList;
01898                         unsigned int patternWidth = Utilities::getUInt((std::string)row["Width"]);
01899                         unsigned int patternLength = Utilities::getUInt((std::string)row["Length"]);
01900                         getNeuronGrpNames(neuronNamesList, patternWidth, patternLength);
01901                         patternTable->setItem(currentRow, 6, new QComboTableItem(patternTable, neuronNamesList));
01902                 }
01903         }
01904         catch (const BadQuery& er) {// Handle any query errors
01905                 cerr<<"SimulationWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
01906                 QString errorString = "Bad query when filling pattern table: \"";
01907                 errorString += er.what();
01908                 errorString += "\"";
01909                 QMessageBox::critical( 0, "Pattern Error", errorString);
01910         }
01911         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01912                 cerr<<"SimulationWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
01913                 QString errorString = "Exception thrown filling pattern table: \"";
01914                 errorString += er.what();
01915                 errorString += "\"";
01916                 QMessageBox::critical( 0, "Pattern Error", errorString);
01917         }
01918         catch(std::exception& er){// Catch-all for any other exceptions
01919                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
01920                 QString errorString = "Exception thrown filling pattern table: \"";
01921                 errorString += er.what();
01922                 errorString += "\"";
01923                 QMessageBox::critical( 0, "Pattern Error", errorString);
01924         }
01925 }
01926 
01927 
01928 /*! Checks to see if any of the neuron groups are lacking connections with another
01929         neuron group. These will never receive spike messages and so will not be updated.
01930         Returns true if there are isolated neuron groups or if there has been an error. */
01931 bool SimulationWidget::neuronGroupsIsolated(){
01932         try{
01933                 Query query = networkDBInterface->getQuery();
01934                 query.reset();
01935         
01936                 //Get a complete list of neuron groups
01937                 query<<"SELECT NeuronGrpID FROM NeuronGroups";
01938                 Result neurGrpRes = query.store();
01939                 
01940                 //Work through the neuron groups and check that they are all in the ConnectionGroup database
01941                 for(Result::iterator iter = neurGrpRes.begin(); iter != neurGrpRes.end(); ++iter){
01942                         Row neurGrpRow (*iter);
01943                         query.reset();
01944                         query<<"SELECT ConnGrpID FROM ConnectionGroups WHERE FromNeuronGrpID = "<<neurGrpRow["NeuronGrpID"]<<" OR ToNeuronGrpID = "<<neurGrpRow["NeuronGrpID"];
01945                         Result connGrpRes = query.store();
01946                         if(connGrpRes.size() == 0)
01947                                 return true;
01948                 }
01949         }
01950         catch (const BadQuery& er) {// Handle any query errors
01951                 cerr<<"SimulationWidget: MYSQL QUERY EXCEPTION \""<<er.what()<<"\""<<endl;
01952                 QString errorString = "Bad query when checking for isolated neuron groups: \"";
01953                 errorString += er.what();
01954                 errorString += "\"";
01955                 QMessageBox::critical( 0, "Neuron Group Error", errorString);
01956                 return true;
01957         }
01958         catch (const Exception& er) {// Catch-all for any other MySQL++ exceptions
01959                 cerr<<"SimulationWidget: MYSQL EXCEPTION \""<<er.what()<<"\""<<endl;
01960                 QString errorString = "Exception thrown checking for isolated neuron groups: \"";
01961                 errorString += er.what();
01962                 errorString += "\"";
01963                 QMessageBox::critical( 0, "Neuron Group Error", errorString);
01964                 return true;
01965         }
01966         catch(std::exception& er){// Catch-all for any other exceptions
01967                 cerr<<"SimulationWidget: STD EXCEPTION \""<<er.what()<<"\""<<endl;
01968                 QString errorString = "Exception thrown checking for isolated neuron groups: \"";
01969                 errorString += er.what();
01970                 errorString += "\"";
01971                 QMessageBox::critical( 0, "Neuron Group Error", errorString);
01972                 return true;
01973         }
01974         return false;
01975 }
01976 

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