@@ -200,7 +200,6 @@ def create_empty_template(
200200 ''' % dict (template_name = template_name , objref_str = objref_str ,
201201 newseclist_str = newseclist_str ,
202202 create_str = create_str )
203-
204203 return template
205204
206205 @staticmethod
@@ -246,7 +245,8 @@ def instantiate(self, sim=None):
246245
247246 if self .params is not None :
248247 for param in self .params .values ():
249- param .instantiate (sim = sim , icell = self .icell )
248+ param .instantiate (sim = sim , icell = self .icell ,
249+ params = self .params )
250250
251251 def destroy (self , sim = None ): # pylint: disable=W0613
252252 """Destroy instantiated model in simulator"""
@@ -479,3 +479,315 @@ def load_hoc_template(sim, hoc_string):
479479 'NEURON does not have template: ' + template_name
480480
481481 return template_name
482+
483+
484+ class LFPyCellModel (Model ):
485+
486+ """LFPy.Cell model class"""
487+
488+ def __init__ (
489+ self ,
490+ name ,
491+ electrode = None ,
492+ morph = None ,
493+ mechs = None ,
494+ params = None ,
495+ dt = 0.025 ,
496+ v_init = - 65.0 ,
497+ gid = 0 ,
498+ seclist_names = None ,
499+ secarray_names = None ,
500+ ):
501+ """Constructor
502+
503+ Args:
504+ name (str): name of this object
505+ should be alphanumeric string, underscores are allowed,
506+ first char should be a letter
507+ morph (Morphology):
508+ underlying Morphology of the cell
509+ mechs (list of Mechanisms):
510+ Mechanisms associated with the cell
511+ params (list of Parameters):
512+ Parameters of the cell model
513+ seclist_names (list of strings):
514+ Names of the lists of sections
515+ secarray_names (list of strings):
516+ Names of the sections
517+ """
518+ super (LFPyCellModel , self ).__init__ (name )
519+ self .check_name ()
520+ self .morphology = morph
521+ self .mechanisms = mechs
522+ self .params = collections .OrderedDict ()
523+ if params is not None :
524+ for param in params :
525+ self .params [param .name ] = param
526+
527+ # Cell instantiation in simulator
528+ self .icell = None
529+ self .lfpy_cell = None
530+ self .electrode = electrode
531+ self .lfpy_electrode = None
532+
533+ self .dt = dt
534+ self .v_init = v_init
535+
536+ self .param_values = None
537+ self .gid = gid
538+
539+ if seclist_names is None :
540+ self .seclist_names = [
541+ "all" ,
542+ "somatic" ,
543+ "basal" ,
544+ "apical" ,
545+ "axonal" ,
546+ "myelinated" ,
547+ ]
548+ else :
549+ self .seclist_names = seclist_names
550+
551+ if secarray_names is None :
552+ self .secarray_names = ["soma" , "dend" , "apic" , "axon" , "myelin" ]
553+ else :
554+ self .secarray_names = secarray_names
555+
556+ def check_name (self ):
557+ """Check if name complies with requirements"""
558+
559+ allowed_chars = string .ascii_letters + string .digits + "_"
560+
561+ if sys .version_info [0 ] < 3 :
562+ translate_args = [None , allowed_chars ]
563+ else :
564+ translate_args = [str .maketrans ("" , "" , allowed_chars )]
565+
566+ if (
567+ self .name == ""
568+ or self .name [0 ] not in string .ascii_letters
569+ or not str (self .name ).translate (* translate_args ) == ""
570+ ):
571+ raise TypeError (
572+ 'CellModel: name "%s" provided to constructor does not comply '
573+ "with the rules for Neuron template name: name should be "
574+ "alphanumeric "
575+ "non-empty string, underscores are allowed, "
576+ "first char should be letter" % self .name
577+ )
578+
579+ def params_by_names (self , param_names ):
580+ """Get parameter objects by name"""
581+
582+ return [self .params [param_name ] for param_name in param_names ]
583+
584+ def freeze (self , param_dict ):
585+ """Set params"""
586+
587+ for param_name , param_value in param_dict .items ():
588+ self .params [param_name ].freeze (param_dict [param_name ])
589+
590+ def unfreeze (self , param_names ):
591+ """Unset params"""
592+
593+ for param_name in param_names :
594+ self .params [param_name ].unfreeze ()
595+
596+ @staticmethod
597+ def create_empty_template (
598+ template_name , seclist_names = None , secarray_names = None
599+ ):
600+ """create an hoc template named template_name for an empty cell"""
601+
602+ objref_str = "objref this, CellRef"
603+ newseclist_str = ""
604+
605+ if seclist_names :
606+ for seclist_name in seclist_names :
607+ objref_str += ", %s" % seclist_name
608+ newseclist_str += (
609+ " %s = new SectionList()\n " % seclist_name
610+ )
611+
612+ create_str = ""
613+ if secarray_names :
614+ create_str = "create "
615+ create_str += ", " .join (
616+ "%s[1]" % secarray_name for secarray_name in secarray_names
617+ )
618+ create_str += "\n "
619+
620+ template = """\
621+ begintemplate %(template_name)s
622+ %(objref_str)s
623+ proc init() {\n %(newseclist_str)s
624+ forall delete_section()
625+ CellRef = this
626+ }
627+
628+ gid = 0
629+
630+ proc destroy() {localobj nil
631+ CellRef = nil
632+ }
633+
634+ %(create_str)s
635+ endtemplate %(template_name)s
636+ """ % dict (
637+ template_name = template_name ,
638+ objref_str = objref_str ,
639+ newseclist_str = newseclist_str ,
640+ create_str = create_str ,
641+ )
642+
643+ return template
644+
645+ @staticmethod
646+ def create_empty_cell (name , sim , seclist_names = None , secarray_names = None ):
647+ """Create an empty cell in Neuron"""
648+
649+ # TODO minize hardcoded definition
650+ # E.g. sectionlist can be procedurally generated
651+ hoc_template = CellModel .create_empty_template (
652+ name , seclist_names , secarray_names
653+ )
654+ sim .neuron .h (hoc_template )
655+
656+ template_function = getattr (sim .neuron .h , name )
657+
658+ return template_function ()
659+
660+ def instantiate (self , sim = None ):
661+ """Instantiate model in simulator"""
662+ from LFPy import Cell
663+ from lfpykit import RecExtElectrode
664+
665+ # TODO replace this with the real template name
666+ if not hasattr (sim .neuron .h , self .name ):
667+ self .icell = self .create_empty_cell (
668+ self .name ,
669+ sim = sim ,
670+ seclist_names = self .seclist_names ,
671+ secarray_names = self .secarray_names ,
672+ )
673+ else :
674+ self .icell = getattr (sim .neuron .h , self .name )()
675+
676+ self .icell .gid = self .gid
677+
678+ self .morphology .instantiate (sim = sim , icell = self .icell )
679+
680+ self .lfpy_cell = Cell (
681+ morphology = sim .neuron .h .allsec (),
682+ dt = self .dt ,
683+ v_init = self .v_init ,
684+ pt3d = True ,
685+ delete_sections = False ,
686+ nsegs_method = None ,
687+ )
688+
689+ self .lfpy_electrode = RecExtElectrode (
690+ self .lfpy_cell , probe = self .electrode
691+ )
692+
693+ if self .mechanisms is not None :
694+ for mechanism in self .mechanisms :
695+ mechanism .instantiate (sim = sim , icell = self .icell )
696+
697+ if self .params is not None :
698+ for param in self .params .values ():
699+ param .instantiate (sim = sim , icell = self .icell ,
700+ params = self .params )
701+
702+ def destroy (self , sim = None ): # pylint: disable=W0613
703+ """Destroy instantiated model in simulator"""
704+
705+ # Make sure the icell's destroy() method is called
706+ # without it a circular reference exists between CellRef and the object
707+ # this prevents the icells from being garbage collected, and
708+ # cell objects pile up in the simulator
709+ self .icell .destroy ()
710+
711+ # The line below is some M. Hines magic
712+ # DON'T remove it, because it will make sure garbage collection
713+ # is called on the icell object
714+ sim .neuron .h .Vector ().size ()
715+
716+ self .icell = None
717+
718+ self .morphology .destroy (sim = sim )
719+ for mechanism in self .mechanisms :
720+ mechanism .destroy (sim = sim )
721+ for param in self .params .values ():
722+ param .destroy (sim = sim )
723+
724+ def check_nonfrozen_params (self , param_names ): # pylint: disable=W0613
725+ """Check if all nonfrozen params are set"""
726+
727+ for param_name , param in self .params .items ():
728+ if not param .frozen :
729+ raise Exception (
730+ "CellModel: Nonfrozen param %s needs to be "
731+ "set before simulation" % param_name
732+ )
733+
734+ def create_hoc (
735+ self ,
736+ param_values ,
737+ ignored_globals = (),
738+ template = "cell_template.jinja2" ,
739+ disable_banner = False ,
740+ template_dir = None ,
741+ ):
742+ """Create hoc code for this model"""
743+
744+ to_unfreeze = []
745+ for param in self .params .values ():
746+ if not param .frozen :
747+ param .freeze (param_values [param .name ])
748+ to_unfreeze .append (param .name )
749+
750+ template_name = self .name
751+ morphology = os .path .basename (self .morphology .morphology_path )
752+ if self .morphology .do_replace_axon :
753+ replace_axon = self .morphology .replace_axon_hoc
754+ else :
755+ replace_axon = None
756+
757+ ret = create_hoc .create_hoc (
758+ mechs = self .mechanisms ,
759+ parameters = self .params .values (),
760+ morphology = morphology ,
761+ ignored_globals = ignored_globals ,
762+ replace_axon = replace_axon ,
763+ template_name = template_name ,
764+ template_filename = template ,
765+ template_dir = template_dir ,
766+ disable_banner = disable_banner ,
767+ )
768+
769+ self .unfreeze (to_unfreeze )
770+
771+ return ret
772+
773+ def __str__ (self ):
774+ """Return string representation"""
775+
776+ content = "%s:\n " % self .name
777+
778+ content += " morphology:\n "
779+
780+ if self .morphology is not None :
781+ content += " %s\n " % str (self .morphology )
782+
783+ content += " mechanisms:\n "
784+ if self .mechanisms is not None :
785+ for mechanism in self .mechanisms :
786+ content += " %s\n " % mechanism
787+
788+ content += " params:\n "
789+ if self .params is not None :
790+ for param in self .params .values ():
791+ content += " %s\n " % param
792+
793+ return content
0 commit comments