Source code for bmtk.simulator.core.sonata_reader.node_adaptor
import os
import json
import types
import numpy as np
[docs]class SonataBaseNode(object):
def __init__(self, node, prop_adaptor):
self._node = node
self._prop_adaptor = prop_adaptor
@property
def node_id(self):
return self._prop_adaptor.node_id(self._node)
@property
def population_name(self):
return self._node.population_name
@property
def gid(self):
return self._prop_adaptor.gid(self._node)
@property
def dynamics_params(self):
return self._prop_adaptor.dynamics_params(self._node)
@property
def model_type(self):
return self._prop_adaptor.model_type(self._node)
@property
def model_template(self):
return self._prop_adaptor.model_template(self._node)
@property
def model_processing(self):
return self._prop_adaptor.model_processing(self._node)
@property
def network(self):
return self._prop_adaptor.network
@property
def population(self):
return self._prop_adaptor.network
def __getitem__(self, prop_key):
return self._node[prop_key]
def __contains__(self, item):
return item in self._node
[docs]class NodeAdaptor(object):
COL_MODEL_TYPE = 'model_type'
COL_GID = 'gid'
COL_DYNAMICS_PARAM = 'dynamics_params'
COL_MODEL_TEMPLATE = 'model_template'
COL_MODEL_PROCESSING = 'model_processing'
def __init__(self, network):
self._network = network
self._model_template_cache = {}
self._model_processing_cache = {}
@property
def batch_process(self):
return False
@batch_process.setter
def batch_process(self, flag):
pass
[docs] def node_id(self, node):
return node.node_id
[docs] def model_type(self, node):
return node[self.COL_MODEL_TYPE]
[docs] def model_template(self, node):
# TODO: If model-template comes from the types table we should split it in _preprocess_types
model_template_str = node[self.COL_MODEL_TEMPLATE]
if model_template_str is None:
return None
elif model_template_str in self._model_template_cache:
return self._model_template_cache[model_template_str]
else:
template_parts = model_template_str.split(':')
directive, template = template_parts[0], template_parts[1]
self._model_template_cache[model_template_str] = (directive, template)
return directive, template
[docs] def model_processing(self, node):
model_processing_str = node[self.COL_MODEL_PROCESSING]
if model_processing_str is None:
return []
else:
# TODO: Split in the node_types_table when possible
return model_processing_str.split(',')
[docs] @staticmethod
def preprocess_node_types(network, node_population):
# TODO: The following figures out the actually used node-type-ids. For mem and speed may be better to just
# process them all
#node_type_ids = node_population.type_ids
node_type_ids = np.unique(node_population.type_ids)
# TODO: Verify all the node_type_ids are in the table
node_types_table = node_population.types_table
# TODO: Convert model_type to a enum
if network.has_component('morphologies_dir'):
morph_dir = network.get_component('morphologies_dir')
if morph_dir is not None and 'morphology' in node_types_table.columns:
for nt_id in node_type_ids:
node_type = node_types_table[nt_id]
if node_type['morphology'] is None:
continue
# TODO: See if absolute path is stored in csv
swc_path = os.path.join(morph_dir, node_type['morphology'])
# According to Sonata format, the .swc extension is not needed. Thus we need to add it if req.
if not os.path.exists(swc_path) and not swc_path.endswith('.swc'):
swc_path += '.swc'
if not os.path.exists(swc_path):
network.io.log_exception('Could not find node morphology file {}.'.format(swc_path))
node_type['morphology'] = swc_path
if 'dynamics_params' in node_types_table.columns and 'model_type' in node_types_table.columns:
for nt_id in node_type_ids:
node_type = node_types_table[nt_id]
dynamics_params = node_type['dynamics_params']
if isinstance(dynamics_params, dict):
continue
if dynamics_params is None:
continue
model_type = node_type['model_type']
if model_type == 'biophysical':
params_dir = network.get_component('biophysical_neuron_models_dir')
elif model_type in ['point_process', 'point_neuron']:
params_dir = network.get_component('point_neuron_models_dir')
elif model_type == 'point_soma':
params_dir = network.get_component('point_neuron_models_dir')
elif model_type == 'population':
params_dir = network.get_component('population_models_dir')
elif model_type == 'lgnmodel' or model_type == 'virtual':
params_dir = network.get_component('filter_models_dir')
else:
# Not sure what to do in this case, throw Exception?
params_dir = network.get_component('custom_neuron_models')
params_path = os.path.join(params_dir, dynamics_params)
# see if we can load the dynamics_params as a dictionary. Otherwise just save the file path and let the
# cell_model loader function handle the extension.
try:
params_val = json.load(open(params_path, 'r'))
node_type['dynamics_params'] = params_val
except Exception:
# TODO: Check dynamics_params before
network.io.log_exception('Could not find node dynamics_params file {}.'.format(params_path))
# TODO: Use adaptor to validate model_type and model_template values
[docs] @classmethod
def create_adaptor(cls, node_group, network):
prop_map = cls(network)
return cls.patch_adaptor(prop_map, node_group, network)
[docs] @classmethod
def patch_adaptor(cls, adaptor, node_group, network):
adaptor.network = network
# Use node_id if the user hasn't specified a gid table
if not node_group.has_gids:
adaptor.gid = types.MethodType(NodeAdaptor.node_id, adaptor)
# dynamics_params
if node_group.has_dynamics_params:
adaptor.dynamics_params = types.MethodType(group_dynamics_params, adaptor)
elif 'dynamics_params' in node_group.all_columns:
adaptor.dynamics_params = types.MethodType(types_dynamics_params, adaptor)
else:
adaptor.dynamics_params = types.MethodType(none_function, adaptor)
if 'model_template' not in node_group.all_columns:
adaptor.model_template = types.MethodType(none_function, adaptor)
if 'model_processing' not in node_group.all_columns:
adaptor.model_processing = types.MethodType(empty_list, adaptor)
return adaptor
[docs] def get_node(self, sonata_node):
return SonataBaseNode(sonata_node, self)
[docs]def none_function(self, node):
return None
[docs]def empty_list(self, node):
return []
[docs]def types_dynamics_params(self, node):
return node['dynamics_params']
[docs]def group_dynamics_params(self, node):
return node.dynamics_params