Skip to content

Commit a15a538

Browse files
authored
Merge pull request #131 from dilawar/master
Fix bug related to Streamer, Changed it tick to 19 instead of 29, Header of csv does not have inverted commas Fails with clang.
2 parents 414a8d9 + 1800283 commit a15a538

File tree

6 files changed

+273
-19
lines changed

6 files changed

+273
-19
lines changed

builtins/Streamer.cpp

Lines changed: 28 additions & 3 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
{
@@ -191,6 +212,7 @@ void Streamer::reinit(const Eref& e, ProcPtr p)
191212
tableDt_.push_back( clk->getTickDt( tickNum ) );
192213
}
193214

215+
194216
// Make sure all tables have same dt_ else disable the streamer.
195217
vector<unsigned int> invalidTables;
196218
for (size_t i = 1; i < tableTick_.size(); i++)
@@ -238,10 +260,9 @@ void Streamer::process(const Eref& e, ProcPtr p)
238260
// Prepare data.
239261
zipWithTime( data_, currTime_ );
240262
StreamerBase::writeToOutFile( outfilePath_, format_, "a", data_, columns_ );
263+
241264
// clean the arrays
242265
data_.clear();
243-
for(size_t i = 0; i < tables_.size(); i++ )
244-
tables_[i]->clearVec();
245266
}
246267

247268

@@ -371,4 +392,8 @@ void Streamer::zipWithTime( vector<double>& data, double currTime)
371392
for( size_t i = 0; i < tables_.size(); i++)
372393
data.push_back( tables_[i]->getVec()[i] );
373394
}
395+
396+
// clear the data from tables now.
397+
for(size_t i = 0; i < tables_.size(); i++ )
398+
tables_[i]->clearVec();
374399
}

builtins/StreamerBase.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ void StreamerBase::writeToCSVFile( const string& filepath, const string& openmod
9898
string headerText = "";
9999
for( vector<string>::const_iterator it = columns.begin();
100100
it != columns.end(); it++ )
101-
headerText += "\"" + *it + "\"" + delimiter_;
101+
headerText += ( *it + delimiter_ );
102102
headerText += eol;
103103
fprintf( fp, "%s", headerText.c_str() );
104104
}

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+

0 commit comments

Comments
 (0)