Skip to content

Commit 2ad812f

Browse files
author
Dilawar Singh
committed
Rdesigeur by sarthak,
1 parent e62ec09 commit 2ad812f

File tree

4 files changed

+255
-15
lines changed

4 files changed

+255
-15
lines changed

builtins/Streamer.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,35 @@ void Streamer::cleanUp( void )
175175
*/
176176
void Streamer::reinit(const Eref& e, ProcPtr p)
177177
{
178-
Clock* clk = reinterpret_cast<Clock*>( Id(1).eref().data() );
178+
179179
if( tables_.size() == 0 )
180180
{
181181
moose::showWarn( "Zero tables in streamer. Disabling Streamer" );
182182
e.element()->setTick( -2 ); /* Disable process */
183183
return;
184184
}
185185

186+
Clock* clk = reinterpret_cast<Clock*>( Id(1).eref().data() );
187+
for (size_t i = 0; i < tableIds_.size(); i++)
188+
{
189+
int tickNum = tableIds_[i].element()->getTick();
190+
double tick = clk->getTickDt( tickNum );
191+
tableDt_.push_back( tick );
192+
// Make sure that all tables have the same tick.
193+
if( i > 0 )
194+
{
195+
if( tick != tableDt_[0] )
196+
{
197+
moose::showWarn( "Table " + tableIds_[i].path() + " has "
198+
" different clock dt. "
199+
" Make sure all tables added to Streamer have the same "
200+
" dt value."
201+
);
202+
}
203+
}
204+
}
205+
206+
186207
// Push each table dt_ into vector of dt
187208
for( size_t i = 0; i < tables_.size(); i++)
188209
{
@@ -252,15 +273,6 @@ void Streamer::process(const Eref& e, ProcPtr p)
252273
*/
253274
void Streamer::addTable( Id table )
254275
{
255-
Clock* clk = reinterpret_cast<Clock*>( Id(1).eref().data() );
256-
int tickNum = table.element()->getTick();
257-
double tick = clk->getTickDt( tickNum );
258-
tableDt_.push_back( tick );
259-
260-
// Set tick of stramer to 100 times of table tick or 10 seconds whichever is
261-
// higher.
262-
clk->setTickDt( 19, max( 10.0, 100 * tick ) );
263-
264276
// If this table is not already in the vector, add it.
265277
for( size_t i = 0; i < tableIds_.size(); i++)
266278
if( table.path() == tableIds_[i].path() )

python/rdesigneur/rdesigneur.py

Lines changed: 222 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#########################################################################
2-
## rdesigneur0_4.py ---
2+
## rdesigneur0_5.py ---
33
## This program is part of 'MOOSE', the
44
## Messaging Object Oriented Simulation Environment.
55
## Copyright (C) 2014 Upinder S. Bhalla. and NCBS
@@ -27,6 +27,10 @@
2727
from rdesigneurProtos import *
2828
from moose.neuroml.NeuroML import NeuroML
2929
from moose.neuroml.ChannelML import ChannelML
30+
import lxml
31+
from lxml import etree
32+
import h5py as h5
33+
import csv
3034

3135
#EREST_ACT = -70e-3
3236

@@ -76,7 +80,8 @@ def __init__(self,
7680
adaptorList= [],
7781
stimList = [],
7882
plotList = [],
79-
moogList = []
83+
moogList = [],
84+
params = None
8085
):
8186
""" Constructor of the rdesigner. This just sets up internal fields
8287
for the model building, it doesn't actually create any objects.
@@ -108,14 +113,20 @@ def __init__(self,
108113
self.chanDistrib = chanDistrib
109114
self.chemDistrib = chemDistrib
110115

116+
self.params = params
117+
111118
self.adaptorList = adaptorList
112119
self.stimList = stimList
113120
self.plotList = plotList
121+
self.saveList = plotList #ADDED BY Sarthak
122+
self.saveAs = []
114123
self.moogList = moogList
115124
self.plotNames = []
125+
self.saveNames = []
116126
self.moogNames = []
117127
self.cellPortionElist = []
118128
self.spineComptElist = []
129+
self.tabForXML = []
119130

120131
if not moose.exists( '/library' ):
121132
library = moose.Neutral( '/library' )
@@ -172,6 +183,7 @@ def buildModel( self, modelPath = '/model' ):
172183
self._buildStims()
173184
self._configureClocks()
174185
self._printModelStats()
186+
self._savePlots()
175187

176188
except BuildError as msg:
177189
print("Error: rdesigneur: model build failed:", msg)
@@ -485,6 +497,7 @@ def _parseComptField( self, comptList, plotSpec, knownFields ):
485497
kf = knownFields[field] # Find the field to decide type.
486498
if ( kf[0] == 'CaConcBase' or kf[0] == 'ChanBase' ):
487499
objList = self._collapseElistToPathAndClass( comptList, plotSpec[2], kf[0] )
500+
# print ("objList: ", len(objList), kf[1])
488501
return objList, kf[1]
489502
elif (field == 'n' or field == 'conc' ):
490503
path = plotSpec[2]
@@ -538,8 +551,6 @@ def _buildPlots( self ):
538551
pair = i[0] + " " + i[1]
539552
dendCompts = self.elecid.compartmentsFromExpression[ pair ]
540553
spineCompts = self.elecid.spinesFromExpression[ pair ]
541-
#print( "DENDENDENDNEDN = ", len(dendCompts), pair )
542-
#print( "SPINESPINESPINE = ", len(spineCompts), pair )
543554
plotObj, plotField = self._parseComptField( dendCompts, i, knownFields )
544555
plotObj2, plotField2 = self._parseComptField( spineCompts, i, knownFields )
545556
assert( plotField == plotField2 )
@@ -613,7 +624,212 @@ def display( self ):
613624
pylab.plot( t, j.vector * i[3] )
614625
if len( self.moogList ) > 0:
615626
pylab.ion()
616-
pylab.show()
627+
pylab.show(block=True)
628+
self._save() #This calls the _save function which saves only if the filenames have been specified
629+
630+
################################################################
631+
# Here we get the time-series data and write to various formats
632+
################################################################
633+
#[TO DO] Add NSDF output function
634+
'''
635+
The author of the functions -- [_savePlots(), _getTimeSeriesTable(), _writeXML(), _writeCSV(), _saveFormats(), _save()] is
636+
Sarthak Sharma.
637+
Email address: [email protected]
638+
'''
639+
640+
def _savePlots( self ):
641+
642+
knownFields = {
643+
'Vm':('CompartmentBase', 'getVm', 1000, 'Memb. Potential (mV)' ),
644+
'Im':('CompartmentBase', 'getIm', 1e9, 'Memb. current (nA)' ),
645+
'inject':('CompartmentBase', 'getInject', 1e9, 'inject current (nA)' ),
646+
'Gbar':('ChanBase', 'getGbar', 1e9, 'chan max conductance (nS)' ),
647+
'Gk':('ChanBase', 'getGk', 1e9, 'chan conductance (nS)' ),
648+
'Ik':('ChanBase', 'getIk', 1e9, 'chan current (nA)' ),
649+
'Ca':('CaConcBase', 'getCa', 1e3, 'Ca conc (uM)' ),
650+
'n':('PoolBase', 'getN', 1, '# of molecules'),
651+
'conc':('PoolBase', 'getConc', 1000, 'Concentration (uM)' )
652+
}
653+
654+
save_graphs = moose.Neutral( self.modelPath + '/save_graphs' )
655+
dummy = moose.element( '/' )
656+
k = 0
657+
658+
for i in self.saveList:
659+
pair = i[0] + " " + i[1]
660+
dendCompts = self.elecid.compartmentsFromExpression[ pair ]
661+
spineCompts = self.elecid.spinesFromExpression[ pair ]
662+
plotObj, plotField = self._parseComptField( dendCompts, i, knownFields )
663+
plotObj2, plotField2 = self._parseComptField( spineCompts, i, knownFields )
664+
assert( plotField == plotField2 )
665+
plotObj3 = plotObj + plotObj2
666+
numPlots = sum( i != dummy for i in plotObj3 )
667+
if numPlots > 0:
668+
save_tabname = save_graphs.path + '/save_plot' + str(k)
669+
scale = knownFields[i[3]][2]
670+
units = knownFields[i[3]][3]
671+
self.saveNames.append( ( save_tabname, i[4], k, scale, units ) )
672+
k += 1
673+
if i[3] == 'n' or i[3] == 'conc':
674+
save_tabs = moose.Table2( save_tabname, numPlots )
675+
else:
676+
save_tabs = moose.Table( save_tabname, numPlots )
677+
save_vtabs = moose.vec( save_tabs )
678+
q = 0
679+
for p in [ x for x in plotObj3 if x != dummy ]:
680+
moose.connect( save_vtabs[q], 'requestOut', p, plotField )
681+
q += 1
682+
683+
def _getTimeSeriesTable( self ):
684+
685+
'''
686+
This function gets the list with all the details of the simulation
687+
required for plotting.
688+
This function adds flexibility in terms of the details
689+
we wish to store.
690+
'''
691+
692+
knownFields = {
693+
'Vm':('CompartmentBase', 'getVm', 1000, 'Memb. Potential (mV)' ),
694+
'Im':('CompartmentBase', 'getIm', 1e9, 'Memb. current (nA)' ),
695+
'inject':('CompartmentBase', 'getInject', 1e9, 'inject current (nA)' ),
696+
'Gbar':('ChanBase', 'getGbar', 1e9, 'chan max conductance (nS)' ),
697+
'Gk':('ChanBase', 'getGk', 1e9, 'chan conductance (nS)' ),
698+
'Ik':('ChanBase', 'getIk', 1e9, 'chan current (nA)' ),
699+
'Ca':('CaConcBase', 'getCa', 1e3, 'Ca conc (uM)' ),
700+
'n':('PoolBase', 'getN', 1, '# of molecules'),
701+
'conc':('PoolBase', 'getConc', 1000, 'Concentration (uM)' )
702+
}
703+
704+
'''
705+
This takes data from plotList
706+
saveList is exactly like plotList but with a few additional arguments:
707+
->It will have a resolution option, i.e., the number of decimal figures to which the value should be rounded
708+
->There is a list of "saveAs" formats
709+
With saveList, the user will able to set what all details he wishes to be saved.
710+
'''
711+
712+
for i,ind in enumerate(self.saveNames):
713+
pair = self.saveList[i][0] + " " + self.saveList[i][1]
714+
dendCompts = self.elecid.compartmentsFromExpression[ pair ]
715+
spineCompts = self.elecid.spinesFromExpression[ pair ]
716+
# Here we get the object details from plotList
717+
savePlotObj, plotField = self._parseComptField( dendCompts, self.saveList[i], knownFields )
718+
savePlotObj2, plotField2 = self._parseComptField( spineCompts, self.saveList[i], knownFields )
719+
savePlotObj3 = savePlotObj + savePlotObj2
720+
721+
rowList = list(ind)
722+
save_vtab = moose.vec( ind[0] )
723+
t = np.arange( 0, save_vtab[0].vector.size, 1 ) * save_vtab[0].dt
724+
725+
rowList.append(save_vtab[0].dt)
726+
rowList.append(t)
727+
rowList.append([jvec.vector * ind[3] for jvec in save_vtab]) #get values
728+
rowList.append(self.saveList[i][3])
729+
rowList.append(filter(lambda obj: obj.path != '/', savePlotObj3)) #this filters out dummy elements
730+
731+
if (type(self.saveList[i][-1])==int):
732+
rowList.append(self.saveList[i][-1])
733+
else:
734+
rowList.append(12)
735+
736+
self.tabForXML.append(rowList)
737+
rowList = []
738+
739+
timeSeriesTable = self.tabForXML # the list with all the details of plot
740+
return timeSeriesTable
741+
742+
def _writeXML( self, filename, timeSeriesData ): #to write to XML file
743+
744+
plotData = timeSeriesData
745+
print("[CAUTION] The '%s' file might be very large if all the compartments are to be saved." % filename)
746+
root = etree.Element("TimeSeriesPlot")
747+
parameters = etree.SubElement( root, "parameters" )
748+
if self.params == None:
749+
parameters.text = "None"
750+
else:
751+
assert(isinstance(self.params, dict)), "'params' should be a dictionary."
752+
for pkey, pvalue in self.params.items():
753+
parameter = etree.SubElement( parameters, str(pkey) )
754+
parameter.text = str(pvalue)
755+
756+
#plotData contains all the details of a single plot
757+
title = etree.SubElement( root, "timeSeries" )
758+
title.set( 'title', str(plotData[1]))
759+
title.set( 'field', str(plotData[8]))
760+
title.set( 'scale', str(plotData[3]))
761+
title.set( 'units', str(plotData[4]))
762+
title.set( 'dt', str(plotData[5]))
763+
p = []
764+
assert(len(plotData[7]) == len(plotData[9]))
765+
766+
res = plotData[10]
767+
for ind, jvec in enumerate(plotData[7]):
768+
p.append( etree.SubElement( title, "data"))
769+
p[-1].set( 'path', str(plotData[9][ind].path))
770+
p[-1].text = ''.join( str(round(value,res)) + ' ' for value in jvec )
771+
772+
tree = etree.ElementTree(root)
773+
tree.write(filename)
774+
775+
def _writeCSV(self, filename, timeSeriesData):
776+
777+
plotData = timeSeriesData
778+
dataList = []
779+
header = []
780+
time = plotData[6]
781+
res = plotData[10]
782+
783+
for ind, jvec in enumerate(plotData[7]):
784+
header.append(plotData[9][ind].path)
785+
dataList.append([round(value,res) for value in jvec.tolist()])
786+
dl = [tuple(lst) for lst in dataList]
787+
rows = zip(tuple(time), *dl)
788+
header.insert(0, "time")
789+
790+
with open(filename, 'wb') as f:
791+
writer = csv.writer(f, quoting=csv.QUOTE_MINIMAL)
792+
writer.writerow(header)
793+
for row in rows:
794+
writer.writerow(row)
795+
796+
##########****SAVING*****###############
797+
def _saveFormats(self, timeSeriesData, k, *filenames):
798+
"This takes in the filenames and writes to corresponding format."
799+
if filenames:
800+
for filename in filenames:
801+
for name in filename:
802+
print (name)
803+
if name[-4:] == '.xml':
804+
self._writeXML(name, timeSeriesData)
805+
print(name, " written")
806+
elif name[-4:] == '.csv':
807+
self._writeCSV(name, timeSeriesData)
808+
print(name, " written")
809+
else:
810+
print("not possible")
811+
pass
812+
else:
813+
pass
814+
815+
816+
def _save( self ):
817+
timeSeriesTable = self._getTimeSeriesTable()
818+
for i,sList in enumerate(self.saveList):
819+
820+
if (len(sList) >= 6) and (type(sList[5]) != int):
821+
self.saveAs.extend(filter(lambda fmt: type(fmt)!=int, sList[5:]))
822+
try:
823+
timeSeriesData = timeSeriesTable[i]
824+
except IndexError:
825+
print("The object to be plotted has all dummy elements.")
826+
pass
827+
self._saveFormats(timeSeriesData, i, self.saveAs)
828+
self.saveAs=[]
829+
else:
830+
pass
831+
else:
832+
pass
617833

618834
################################################################
619835
# Here we set up the stims
@@ -1053,3 +1269,4 @@ def _buildAdaptor( self, meshName, elecRelPath, elecField, \
10531269
for j in range( i[1], i[2] ):
10541270
moose.connect( i[3], 'requestOut', chemVec[j], chemFieldSrc)
10551271
msg = moose.connect( i[3], 'output', elObj, elecFieldDest )
1272+

scheduling/Clock.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ void Clock::setTickDt( unsigned int i, double v )
591591
}
592592
for ( unsigned int j = 0; j < numTicks; ++j )
593593
numUsed += ( ticks_[j] != 0 );
594+
594595
if ( numUsed == 0 )
595596
{
596597
dt_ = v;

shell/Shell.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
**********************************************************************/
99

1010
#include <string>
11+
#include <algorithm>
12+
1113
using namespace std;
1214

1315

@@ -396,6 +398,14 @@ void Shell::doStop( )
396398
void Shell::doSetClock( unsigned int tickNum, double dt )
397399
{
398400
LookupField< unsigned int, double >::set( ObjId( 1 ), "tickDt", tickNum, dt );
401+
402+
// FIXME:
403+
// HACK: If clock 18 is being updated, make sure that clock 19 (streamer is also
404+
// updated with correct dt (10 or 100*dt). This is bit hacky.
405+
if( tickNum == 18 )
406+
LookupField< unsigned int, double >::set( ObjId( 1 ), "tickDt"
407+
, tickNum + 1, max( 100 * dt, 10.0 )
408+
);
399409
}
400410

401411
void Shell::doUseClock( string path, string field, unsigned int tick )

0 commit comments

Comments
 (0)