Source code for bmtk.simulator.utils.simulation_inputs
[docs]class SimInput(object):
"""A helper class for parsing the "inputs" section of a SONATA config file. Separate the actual parameters needed
to instantiate a module from the metadata parameters (eg, name, module, input_type)
Use the build() method to parse the json/dictionary of a section of input, then **params** to get a dictionary
of the values used to instantiate::
input = SimInput.Build(
'spikes_inputs',
{'module': 'spikes', 'input_type': 'hdf5', input_file: 'my_spikes.h5', 'time_scale': 'ms'}
)
if input.module == 'spike':
SpikesInput(**params)
...
Attributes:
* **name** - str, name of module
* **input_type** - str
* **module** - str,
* **params** - dictionary, all parameters (not including name, input_type, module)
Custom Modules:
Sometimes certain input types may require extra steps in processing, like auto-conversion of filling in missing
parameters. In this case use the register module method::
class MyVClampInput(SimInput):
def avail_module():
return ['vclamp', 'voltage_clamp']
def build():
....
SimInput.registerModule(MyVClampInput)
Then when SimInput.build() is called and the 'module_name'=='vclamp' (or 'voltage_clamp') it will pass the parsing
to the MyVClampInput class.
"""
registry = {} # For factory function
def __init__(self, input_name, input_type, module, params):
self.name = input_name
self.input_type = input_type
self.module = module
self.params = params.copy()
# Remove the 'module' and 'input_type' from the params since user should access it through the variable
for param_key in ['module', 'input_type']:
if param_key in self.params:
del self.params[param_key]
# Special variable, not a part of standard but still want for ease of testing
if 'enabled' in params:
self.enabled = params['enabled']
del self.params['enabled']
else:
self.enabled = True
# Fill in missing values with default (as specified by the subclass)
for var_name, default_val in self._get_defaults():
if var_name not in self.params:
self.params[var_name] = default_val
# Check there are no missing parameters
@property
def node_set(self):
return self.params.get('node_set', None)
def _get_defaults(self):
return []
[docs] @classmethod
def build(cls, input_name, params):
"""Creates a SimInput object with parsed out parameters
:param input_name: name of specific input
:param params: dictionary of input parameters
:return: SimInput object, or subclass that matches the specified 'module' value
"""
params = params.copy()
if 'module' not in params:
raise Exception('inputs setting {} does not specify the "module".'.format(input_name))
if 'input_type' not in params:
raise Exception('inputs setting {} does not specify the "input_type".'.format(input_name))
module_name = params['module']
input_type = params['input_type']
module_cls = SimInput.registry.get(module_name, SimInput)
return module_cls(input_name, input_type, module_name, params)
[docs] @classmethod
def register_module(cls, subclass):
"""
:param subclass:
"""
# For factory, register subclass based on the module name(s)
assert(issubclass(subclass, cls))
mod_registry = cls.registry
mod_list = subclass.avail_modules()
modules = mod_list if isinstance(mod_list, list) else [mod_list]
for mod_name in modules:
if mod_name in mod_registry:
raise Exception('Multiple modules named {}'.format(mod_name))
mod_registry[mod_name] = subclass
return subclass
[docs]def from_config(cfg):
"""Takes in a bmtk.utils.Config instance and will automatically parse each "input" in the config sections,
returning a list of SimInput objects. If an input has "enabled" = False then it will automatically be excluded.
:param cfg: A SONATAConfig object
:return: A list of SimInput modules corresponding to the parsed inputs of a config.
"""
inputs_list = []
for input_name, input_params in cfg.inputs.items():
input_setting = SimInput.build(input_name, input_params)
if input_setting.enabled:
inputs_list.append(input_setting)
return inputs_list