55import io
66import logging
77import pathlib
8- from collections import namedtuple , OrderedDict
8+ from collections import ChainMap , namedtuple , OrderedDict
99import re
1010
1111import jinja2
2424RangeIExpr = namedtuple ('RangeIExpr' , 'name, value, scale' )
2525
2626
27- # Define Neuron to Arbor parameter conversions (conv defaults to identity)
2827class ArbVar :
28+ """Definition of a Neuron to Arbor parameter conversion"""
29+
2930 def __init__ (self , name , conv = None ):
31+ """Constructor
32+
33+ Args:
34+ name (str): Arbor parameter name
35+ conv (): Conversion of parameter value from Neuron units
36+ to Arbor (defaults to identity)
37+ """
3038 self .name = name
3139 self .conv = conv
3240
41+ def __repr__ (self ):
42+ return 'ArbVar(%s, %s)' % (self .name , self .conv )
43+
3344
3445class Nrn2ArbParamAdapter :
3546 """Converts a Neuron parameter to Arbor format (name and value)"""
@@ -220,9 +231,9 @@ def process_global(cls, params):
220231 params (): List of global parameters in Neuron format
221232
222233 Returns:
223- A mapping of mechanism to parameters. The mechanism parameters are
224- in Arbor format ( mechanism name is None for non-mechanism
225- parameters).
234+ A mapping of mechanism to parameters representing Arbor global
235+ properties. The mechanism parameters are in Arbor format
236+ (mechanism name is None for non-mechanism parameters).
226237 """
227238 return cls ._format_params_and_group_by_mech (
228239 [Location (name = name , value = value )
@@ -240,10 +251,11 @@ def process_local(cls, params, channels):
240251 channels (): Mapping of Arbor label to co-located NMODL mechanisms
241252
242253 Returns:
243- In the first component, a two-level mapping of Arbor label to
244- mechanism to parameters. The mechanism parameters are in Arbor
245- format (mechanism name is None for non-mechanism parameters).
246- In the second component, the global properties found are returned.
254+ The return value is a tuple. In the first component, a two-level
255+ mapping of Arbor label to mechanism to parameters. The mechanism
256+ parameters are in Arbor format (mechanism name is None for
257+ non-mechanism parameters). In the second component, the
258+ Arbor global properties found are returned.
247259 """
248260 local_mechs = dict ()
249261 global_properties = dict ()
@@ -253,9 +265,12 @@ def process_local(cls, params, channels):
253265
254266 # move Arbor global properties to global_params
255267 mechs , global_props = cls ._separate_global_properties (loc , mechs )
256- for mech , props in global_props .items ():
257- global_properties [mech ] = \
258- global_properties .get (mech , []) + props
268+ if global_props .keys () != {None }:
269+ raise CreateAccException (
270+ 'Support for Arbor default mechanisms not implemented.' )
271+ # iterate over global_props items if above exception triggers
272+ global_properties [None ] = \
273+ global_properties .get (None , []) + global_props [None ]
259274 local_mechs [loc ] = mechs
260275 return local_mechs , global_properties
261276
@@ -509,19 +524,18 @@ def _arb_populate_label_dict(local_mechs, local_scaled_mechs, pprocess_mechs):
509524
510525 label_dict = dict ()
511526
512- for acc_labels in [local_mechs .keys (),
513- local_scaled_mechs .keys (),
514- pprocess_mechs .keys ()]:
515- for acc_label in acc_labels :
516- if acc_label .name in label_dict and \
517- acc_label != label_dict [acc_label .name ]:
518- raise CreateAccException (
519- 'Label %s already exists in' % acc_label .name +
520- ' label_dict with different s-expression: '
521- ' %s != %s.' % (label_dict [acc_label .name ].loc ,
522- acc_label .loc ))
523- elif acc_label .name not in label_dict :
524- label_dict [acc_label .name ] = acc_label
527+ acc_labels = ChainMap (local_mechs , local_scaled_mechs , pprocess_mechs )
528+
529+ for acc_label in acc_labels :
530+ if acc_label .name in label_dict and \
531+ acc_label != label_dict [acc_label .name ]:
532+ raise CreateAccException (
533+ 'Label %s already exists in' % acc_label .name +
534+ ' label_dict with different s-expression: '
535+ ' %s != %s.' % (label_dict [acc_label .name ].loc ,
536+ acc_label .loc ))
537+ elif acc_label .name not in label_dict :
538+ label_dict [acc_label .name ] = acc_label
525539
526540 return label_dict
527541
@@ -592,6 +606,9 @@ def create_acc(mechs,
592606 of a custom template
593607 '''
594608
609+ if custom_jinja_params is None :
610+ custom_jinja_params = {}
611+
595612 if pathlib .Path (morphology ).suffix .lower () not in ['.swc' , '.asc' ]:
596613 raise CreateAccException ("Morphology file %s not supported in Arbor "
597614 " (only supported types are .swc and .asc)."
@@ -642,9 +659,6 @@ def create_acc(mechs,
642659 default_location_order ,
643660 _arb_loc_desc )
644661
645- if custom_jinja_params is None :
646- custom_jinja_params = {}
647-
648662 filenames = {
649663 name : template_name + (name if name .startswith ('.' ) else "_" + name )
650664 for name in templates .keys ()}
@@ -825,7 +839,7 @@ def read_acc(cell_json_filename):
825839
826840class CreateAccException (Exception ):
827841
828- """All exceptions generated by create_acc module"""
842+ """Exceptions generated by create_acc module"""
829843
830844 def __init__ (self , message ):
831845 """Constructor"""
0 commit comments