43
43
"********************************************************************" )
44
44
45
45
46
+ # these gates are available in moose. These are prefixed by 'gate'
47
+ _validMooseHHGateIds = ['X' , 'Y' , 'Z' ]
48
+
46
49
def _unique (ls ):
47
- res = [ ]
50
+ res = []
48
51
for l in ls :
49
52
if l not in res :
50
53
res .append (l )
51
54
return res
52
55
56
+
53
57
def _whichGate (chan ):
54
- return chan .name [- 1 ]
58
+ global _validMooseHHGateIds
59
+ c = chan .name [- 1 ]
60
+ assert c in _validMooseHHGateIds
61
+ return c
62
+
63
+ def _pairNmlGateWithMooseGates (mGates , nmlGates ):
64
+ """Return moose gate id from nml.HHGate
65
+ """
66
+ global _validMooseHHGateIds
67
+ # deep copy
68
+ mooseGatesMap = {_whichGate (x ) : x for x in mGates }
69
+ availableMooseGates = _validMooseHHGateIds [:]
70
+ mapping = {}
71
+ for nmlGate in nmlGates :
72
+ if nmlGate is None :
73
+ continue
74
+ if hasattr (nmlGate , 'id' ) and nmlGate .id :
75
+ mapping [nmlGate .id .upper ()] = nmlGate
76
+ availableMooseGates .remove (nmlGate .id .upper ())
77
+ else :
78
+ mapping [availableMooseGates .pop (0 )] = nmlGate
79
+
80
+ # Now replace 'X', 'Y', 'Z' with moose gates.
81
+ return [(mooseGatesMap [x ], mapping [x ]) for x in mapping ]
55
82
56
83
def _isConcDep (ct ):
57
84
"""_isConcDep
@@ -75,9 +102,10 @@ def _findCaConc():
75
102
Find a suitable CaConc for computing HHGate tables.
76
103
This is a hack, though it is likely to work in most cases.
77
104
"""
78
- caConcs = moose .wildcardFind ( '/library/##[TYPE=CaConc]' )
105
+ caConcs = moose .wildcardFind ('/library/##[TYPE=CaConc]' )
79
106
assert len (caConcs ) == 1 , "No moose.CaConc found. Currently moose \
80
107
supports HHChannel which depends only on moose.CaConc ."
108
+
81
109
return caConcs [0 ]
82
110
83
111
@@ -200,7 +228,6 @@ def __init__(self, verbose=False):
200
228
# Just in case.
201
229
self ._variables = {}
202
230
203
-
204
231
def read (self , filename , symmetric = True ):
205
232
self .doc = loaders .read_neuroml2_file (filename ,
206
233
include_includes = True ,
@@ -464,8 +491,9 @@ def isPassiveChan(self, chan):
464
491
'HHExpLinearRate' : linoid2
465
492
}
466
493
467
- def calculateRateFn (self , ratefn , vmin , vmax , tablen = 3000 , vShift = '0mV' ):
494
+ def calculateRateFn (self , ratefn , mgate , vmin , vmax , tablen = 3000 , vShift = '0mV' ):
468
495
"""Returns A / B table from ngate."""
496
+
469
497
tab = np .linspace (vmin , vmax , tablen )
470
498
if self ._is_standard_nml_rate (ratefn ):
471
499
midpoint , rate , scale = map (
@@ -476,24 +504,62 @@ def calculateRateFn(self, ratefn, vmin, vmax, tablen=3000, vShift='0mV'):
476
504
if ratefn .type != ct .name :
477
505
continue
478
506
logger_ .info ("Using %s to evaluate rate" % ct .name )
479
- rate = []
480
- for v in tab :
481
- req_vars = {'v' :'%sV' % v ,'vShift' :vShift ,'temperature' :self ._getTemperature ()}
482
- req_vars .update (self ._variables )
483
- vals = pynml .evaluate_component (ct , req_variables = req_vars )
484
- '''print(vals)'''
485
- if 'x' in vals :
486
- rate .append (vals ['x' ])
487
- if 't' in vals :
488
- rate .append (vals ['t' ])
489
- if 'r' in vals :
490
- rate .append (vals ['r' ])
491
- return np .array (rate )
492
-
493
- def calculateRateFnCaDep (self , ratefn , ca , camin , camax , tablen = 3000 , vShift = '0mV' ):
507
+ if not _isConcDep (ct ):
508
+ return self ._computeRateFn (ct , tab )
509
+ else :
510
+ ca = _findCaConc ()
511
+ assert _whichGate (mgate ) == 'Z' , mgate
512
+ return self ._computeRateFnCa (ca , ct , tab , vShift = vShift )
513
+
514
+ def _computeRateFnCa (self , ca , ct , tab , vShift ):
515
+ rate = []
516
+ for v in tab :
517
+ req_vars = {
518
+ ca .name : '%sV' % v ,
519
+ 'vShift' : vShift ,
520
+ 'temperature' : self ._getTemperature ()
521
+ }
522
+ req_vars .update (self ._variables )
523
+ vals = pynml .evaluate_component (ct , req_variables = req_vars )
524
+ '''print(vals)'''
525
+ if 'x' in vals :
526
+ rate .append (vals ['x' ])
527
+ if 't' in vals :
528
+ rate .append (vals ['t' ])
529
+ if 'r' in vals :
530
+ rate .append (vals ['r' ])
531
+ return np .array (rate )
532
+
533
+ def _computeRateFn (self , ct , tab , vShift ):
534
+ rate = []
535
+ for v in tab :
536
+ req_vars = {
537
+ 'v' : '%sV' % v ,
538
+ 'vShift' : vShift ,
539
+ 'temperature' : self ._getTemperature ()
540
+ }
541
+ req_vars .update (self ._variables )
542
+ vals = pynml .evaluate_component (ct , req_variables = req_vars )
543
+ '''print(vals)'''
544
+ if 'x' in vals :
545
+ rate .append (vals ['x' ])
546
+ if 't' in vals :
547
+ rate .append (vals ['t' ])
548
+ if 'r' in vals :
549
+ rate .append (vals ['r' ])
550
+ return np .array (rate )
551
+
552
+ def calculateRateFnCaDep (self ,
553
+ ratefn ,
554
+ ca ,
555
+ camin ,
556
+ camax ,
557
+ tablen = 3000 ,
558
+ vShift = '0mV' ):
494
559
"""Returns A / B table from ngate.
495
560
496
- FIXME: Merge with calculateRateFn
561
+ This function compute rate which depends on ca.
562
+ This must go into Z gate.
497
563
"""
498
564
tab = np .linspace (camin , camax , tablen )
499
565
if self ._is_standard_nml_rate (ratefn ):
@@ -504,10 +570,15 @@ def calculateRateFnCaDep(self, ratefn, ca, camin, camax, tablen=3000, vShift='0m
504
570
for ct in self .doc .ComponentType :
505
571
if ratefn .type != ct .name :
506
572
continue
507
- logger_ .info ("Using %s to evaluate rate (caConc dependant)" % ct .name )
573
+ logger_ .info ("Using %s to evaluate rate (caConc dependant)" %
574
+ ct .name )
508
575
rate = []
509
576
for v in tab :
510
- req_vars = {ca .name :'%sV' % v ,'vShift' :vShift ,'temperature' :self ._getTemperature ()}
577
+ req_vars = {
578
+ ca .name : '%sV' % v ,
579
+ 'vShift' : vShift ,
580
+ 'temperature' : self ._getTemperature ()
581
+ }
511
582
vals = pynml .evaluate_component (ct , req_variables = req_vars )
512
583
'''print(vals)'''
513
584
if 'x' in vals :
@@ -615,107 +686,109 @@ def _is_standard_nml_rate(self, rate):
615
686
rate .type == 'HHSigmoidVariable'
616
687
617
688
def createHHChannel (self , chan , vmin = - 150e-3 , vmax = 100e-3 , vdivs = 5000 ):
618
- mchan = moose .HHChannel ('%s/%s' % (self .lib .path , chan .id ))
619
- mgates = map (moose .element , (mchan .gateX , mchan .gateY , mchan .gateZ ))
689
+ path = '%s/%s' % (self .lib .path , chan .id )
690
+ if moose .exists (path ):
691
+ mchan = moose .element (path )
692
+ else :
693
+ mchan = moose .HHChannel (path )
694
+ mgates = [
695
+ moose .element (g ) for g in [mchan .gateX , mchan .gateY , mchan .gateZ ]
696
+ ]
620
697
621
698
# We handle only up to 3 gates in HHCHannel
622
- assert ( len (chan .gate_hh_rates ) <= 3 )
699
+ assert len (chan .gate_hh_rates ) <= 3 , "No more than 3 gates"
623
700
624
701
if self .verbose :
625
702
print ('== Creating channel: %s (%s) -> %s (%s)' %
626
703
(chan .id , chan .gate_hh_rates , mchan , mgates ))
704
+
627
705
all_gates = chan .gates + chan .gate_hh_rates
628
- for ngate , mgate in zip (all_gates , mgates ):
629
- if ngate is None :
630
- continue
631
- logger_ .info ('whichGate(mgate) %s %s' % (mgate , _whichGate (mgate )))
632
- if _whichGate (mgate ) == 'X' :
633
- mchan .Xpower = ngate .instances
634
- elif _whichGate (mgate ) == 'Y' :
635
- mchan .Ypower = ngate .instances
636
- elif _whichGate (mgate ) == 'Z' :
637
- mchan .Zpower = ngate .instance
638
- mgate .min = vmin
639
- mgate .max = vmax
640
- mgate .divs = vdivs
641
-
642
- # I saw only examples of GateHHRates in
643
- # HH-channels, the meaning of forwardRate and
644
- # reverseRate and steadyState are not clear in the
645
- # classes GateHHRatesInf, GateHHRatesTau and in
646
- # FateHHTauInf the meaning of timeCourse and
647
- # steady state is not obvious. Is the last one
648
- # refering to tau_inf and m_inf??
649
- fwd = ngate .forward_rate
650
- rev = ngate .reverse_rate
651
-
652
- self .paths_to_chan_elements [
653
- '%s/%s' %
654
- (chan .id , ngate .id )] = '%s/%s' % (chan .id , mgate .name )
655
-
656
- q10_scale = 1
657
- if ngate .q10_settings :
658
- if ngate .q10_settings .type == 'q10Fixed' :
659
- q10_scale = float (ngate .q10_settings .fixed_q10 )
660
- elif ngate .q10_settings .type == 'q10ExpTemp' :
661
- q10_scale = math .pow (
662
- float (ngate .q10_settings .q10_factor ),
663
- (self ._getTemperature () -
664
- SI (ngate .q10_settings .experimental_temp )) / 10 )
665
- #print('Q10: %s; %s; %s; %s'%(ngate.q10_settings.q10_factor, self._getTemperature(),SI(ngate.q10_settings.experimental_temp),q10_scale))
666
- else :
667
- raise Exception (
668
- 'Unknown Q10 scaling type %s: %s' %
669
- (ngate .q10_settings .type , ngate .q10_settings ))
670
706
671
- logger_ .info (' === Gate: %s; %s; %s; %s; %s; scale=%s' %
672
- (ngate .id , mgate .path , mchan .Xpower , fwd , rev , q10_scale ))
707
+ # If user set bnml channels' id to 'x', 'y' or 'z' then pair this gate
708
+ # with moose.HHChannel's gateX, gateY, gateZ respectively. Else pair
709
+ # them with gateX, gateY, gateZ acording to list order.
710
+ for mgate , ngate in _pairNmlGateWithMooseGates (mgates , all_gates ):
711
+ self ._addGateToHHChannel (chan , mchan , mgate , ngate , vmin , vmax ,
712
+ vdivs )
713
+ logger_ .debug ('== Created' , mchan .path , 'for' , chan .id )
714
+ return mchan
673
715
674
- print (fwd , rev )
675
- quit ()
716
+ def _addGateToHHChannel (self , chan , mchan , mgate , ngate , vmin , vmax ,
717
+ vdivs ):
718
+ """Add gateX, gateY, gateZ etc to moose.HHChannel (mchan).
676
719
677
- if (fwd is not None ) and (rev is not None ):
678
- # Note: MOOSE HHGate are either voltage of concentration
679
- # dependant. Here we figure out if nml description of gate is
680
- # concentration dependant or not.
681
- if not _isConcDep (fwd ):
682
- alpha = self .calculateRateFn (fwd , vmin , vmax , vdivs )
683
- else :
684
- ca = _findCaConc ()
685
- alpha = self .calculateRateFnCaDep (fwd , ca , vmin , vmax , vdivs )
720
+ Each gate can be voltage dependant and/or concentration dependant.
721
+ Only caConc dependant channels are supported.
722
+ """
686
723
687
- if not _isConcDep (rev ):
688
- beta = self .calculateRateFnCaDep (rev , vmin , vmax , vdivs )
689
- else :
690
- ca = _findCaConc ()
691
- beta = self .calculateRateFn (rev , ca , vmin , vmax , vdivs )
692
-
693
- mgate .tableA = q10_scale * (alpha )
694
- mgate .tableB = q10_scale * (alpha + beta )
695
-
696
- # Assuming the meaning of the elements in GateHHTauInf ...
697
- if hasattr (ngate ,'time_course' ) and hasattr (ngate ,'steady_state' ) \
698
- and (ngate .time_course is not None ) and (ngate .steady_state is not None ):
699
- tau = ngate .time_course
700
- inf = ngate .steady_state
701
- tau = self .calculateRateFn (tau , vmin , vmax , vdivs )
724
+ # set mgate.Xpower, .Ypower etc.
725
+ setattr (mchan , _whichGate (mgate ) + 'power' , ngate .instances )
726
+
727
+ mgate .min = vmin
728
+ mgate .max = vmax
729
+ mgate .divs = vdivs
730
+
731
+ # Note by Padraig:
732
+ # ---------------
733
+ # I saw only examples of GateHHRates in HH-channels, the meaning of
734
+ # forwardRate and reverseRate and steadyState are not clear in the
735
+ # classes GateHHRatesInf, GateHHRatesTau and in FateHHTauInf the
736
+ # meaning of timeCourse and steady state is not obvious. Is the last
737
+ # one # refering to tau_inf and m_inf??
738
+ fwd = ngate .forward_rate
739
+ rev = ngate .reverse_rate
740
+
741
+ self .paths_to_chan_elements ['%s/%s' % (chan .id , ngate .id )] = \
742
+ '%s/%s' % (chan .id , mgate .name )
743
+
744
+ q10_scale = 1
745
+ if ngate .q10_settings :
746
+ if ngate .q10_settings .type == 'q10Fixed' :
747
+ q10_scale = float (ngate .q10_settings .fixed_q10 )
748
+ elif ngate .q10_settings .type == 'q10ExpTemp' :
749
+ q10_scale = math .pow (
750
+ float (ngate .q10_settings .q10_factor ),
751
+ (self ._getTemperature () -
752
+ SI (ngate .q10_settings .experimental_temp )) / 10 )
753
+ logger_ .debug (
754
+ 'Q10: %s; %s; %s; %s' %
755
+ (ngate .q10_settings .q10_factor , self ._getTemperature (),
756
+ SI (ngate .q10_settings .experimental_temp ), q10_scale ))
757
+ else :
758
+ raise Exception ('Unknown Q10 scaling type %s: %s' %
759
+ (ngate .q10_settings .type , ngate .q10_settings ))
760
+ logger_ .info (' === Gate: %s; %s; %s; %s; %s; scale=%s' %
761
+ (ngate .id , mgate .path , mchan .Xpower , fwd , rev , q10_scale ))
762
+
763
+ if (fwd is not None ) and (rev is not None ):
764
+ # Note: MOOSE HHGate are either voltage of concentration
765
+ # dependant. Here we figure out if nml description of gate is
766
+ # concentration dependant or not.
767
+ alpha = self .calculateRateFn (fwd , mgate , vmin , vmax , vdivs )
768
+ beta = self .calculateRateFn (rev , mgate , vmin , vmax , vdivs )
769
+
770
+ mgate .tableA = q10_scale * (alpha )
771
+ mgate .tableB = q10_scale * (alpha + beta )
772
+
773
+ # Assuming the meaning of the elements in GateHHTauInf ...
774
+ if hasattr (ngate ,'time_course' ) and hasattr (ngate ,'steady_state' ) \
775
+ and (ngate .time_course is not None ) and (ngate .steady_state is not None ):
776
+ tau = ngate .time_course
777
+ inf = ngate .steady_state
778
+ tau = self .calculateRateFn (tau , mgate , vmin , vmax , vdivs )
779
+ inf = self .calculateRateFn (inf , mgate , vmin , vmax , vdivs )
780
+ mgate .tableA = q10_scale * (inf / tau )
781
+ mgate .tableB = q10_scale * (1 / tau )
782
+
783
+ if hasattr (ngate , 'steady_state' ) and (ngate .time_course is None ) \
784
+ and (ngate .steady_state is not None ):
785
+ inf = ngate .steady_state
786
+ tau = 1 / (alpha + beta )
787
+ if (inf is not None ):
702
788
inf = self .calculateRateFn (inf , vmin , vmax , vdivs )
703
789
mgate .tableA = q10_scale * (inf / tau )
704
790
mgate .tableB = q10_scale * (1 / tau )
705
791
706
- if hasattr (ngate , 'steady_state' ) and (ngate .time_course is None ) \
707
- and (ngate .steady_state is not None ):
708
- inf = ngate .steady_state
709
- tau = 1 / (alpha + beta )
710
- if (inf is not None ):
711
- inf = self .calculateRateFn (inf , vmin , vmax , vdivs )
712
- mgate .tableA = q10_scale * (inf / tau )
713
- mgate .tableB = q10_scale * (1 / tau )
714
-
715
- if self .verbose :
716
- print (self .filename , '== Created' , mchan .path , 'for' , chan .id )
717
- return mchan
718
-
719
792
def createPassiveChannel (self , chan ):
720
793
mchan = moose .Leakage ('%s/%s' % (self .lib .path , chan .id ))
721
794
if self .verbose :
0 commit comments