diff --git a/PySONIC.sublime-project b/PySONIC.sublime-project index 9f884ae..4c82066 100644 --- a/PySONIC.sublime-project +++ b/PySONIC.sublime-project @@ -1,53 +1,53 @@ { "build_systems": [ { "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", "name": "Anaconda Python Builder", "selector": "source.python", - "shell_cmd": "\"C:\\Users\\lemaire\\Anaconda3\\python.exe\" -u \"$file\"" + "shell_cmd": "\"python\" -u \"$file\"" } ], "folders": [ { "file_exclude_patterns": [ "*.sublime-workspace", "MANIFEST.in", "LICENSE", "conf.py", "index.rst", "*.gitignore", "__init__.py", "*.c", "*.sh", "*.bat", "Makefile", "*.pkl" ], "folder_exclude_patterns": [ "docs", "*.egg-info", ".ipynb_checkpoints", "_build", "_static", "_templates", "__pycache__" ], "path": "." } ], "settings": { "anaconda_linting": true, "anaconda_linting_behaviour": "always", "pep257": false, "python_interpreter": "C:\\Users\\lemaire\\Anaconda3\\python.exe", "test_command": "python -m unittest discover", "use_pylint": false, "validate_imports": true }, "translate_tabs_to_spaces": true } diff --git a/PySONIC/core/__init__.py b/PySONIC/core/__init__.py index c362f65..53c8f9a 100644 --- a/PySONIC/core/__init__.py +++ b/PySONIC/core/__init__.py @@ -1,40 +1,39 @@ # -*- coding: utf-8 -*- # @Author: Theo Lemaire # @Email: theo.lemaire@epfl.ch # @Date: 2017-06-06 13:36:00 # @Last Modified by: Theo Lemaire -# @Last Modified time: 2019-06-14 17:16:01 +# @Last Modified time: 2019-06-17 10:57:14 import inspect import sys from .simulators import PWSimulator, PeriodicSimulator from .batches import Batch, createQueue from .model import Model from .pneuron import PointNeuron from .bls import BilayerSonophore, PmCompMethod, LennardJones from .nbls import NeuronalBilayerSonophore -from .nmodl_generator import NmodlGenerator from ..neurons import getPointNeuron def getModelsDict(): ''' Construct a dictionary of all model classes, indexed by simulation key. ''' current_module = sys.modules[__name__] models_dict = {} for _, obj in inspect.getmembers(current_module): if inspect.isclass(obj) and hasattr(obj, 'simkey') and isinstance(obj.simkey, str): models_dict[obj.simkey] = obj return models_dict def getModel(meta): ''' Return appropriate model object based on a dictionary of meta-information. ''' if meta['simkey'] == 'MECH': model = BilayerSonophore(meta['a'], meta['Cm0'], meta['Qm0']) else: model = getPointNeuron(meta['neuron']) if meta['simkey'] == 'ASTIM': model = NeuronalBilayerSonophore(meta['a'], model, meta['Fdrive']) return model diff --git a/PySONIC/core/nmodl_generator.py b/PySONIC/core/nmodl_generator.py deleted file mode 100644 index dd989b9..0000000 --- a/PySONIC/core/nmodl_generator.py +++ /dev/null @@ -1,184 +0,0 @@ -# -*- coding: utf-8 -*- -# @Author: Theo Lemaire -# @Email: theo.lemaire@epfl.ch -# @Date: 2019-03-18 21:17:03 -# @Last Modified by: Theo Lemaire -# @Last Modified time: 2019-06-17 10:45:45 - -import inspect -import re -from time import gmtime, strftime - -from ..constants import FARADAY, Rg - - -def escaped_pow(x): - return ' * '.join([x.group(1)] * int(x.group(2))) - - -class NmodlGenerator: - - tabreturn = '\n ' - NEURON_protected_vars = ['O', 'C'] - - def __init__(self, pneuron): - self.pneuron = pneuron - self.translated_states = [self.translateState(s) for s in self.pneuron.states] - - def allBlocks(self): - return '\n\n'.join([ - self.title(), - self.description(), - self.constants(), - self.tscale(), - self.neuron_block(), - self.parameter_block(), - self.state_block(), - self.assigned_block(), - self.function_tables(), - self.initial_block(), - self.breakpoint_block(), - self.derivative_block() - ]) - - def print(self): - print(self.allBlocks()) - - def dump(self, outfile): - with open(outfile, "w") as fh: - fh.write(self.allBlocks()) - - def translateState(self, state): - return '{}{}'.format(state, '1' if state in self.NEURON_protected_vars else '') - - def title(self): - return 'TITLE {} membrane mechanism'.format(self.pneuron.name) - - def description(self): - return '\n'.join([ - 'COMMENT', - self.pneuron.getDesc(), - '', - '@Author: Theo Lemaire, EPFL', - '@Date: {}'.format(strftime("%Y-%m-%d", gmtime())), - '@Email: theo.lemaire@epfl.ch', - 'ENDCOMMENT' - ]) - - def constants(self): - block = [ - 'FARADAY = {:.5e} (coul) : moles do not appear in units'.format(FARADAY), - 'R = {:.5e} (J/mol/K) : Universal gas constant'.format(Rg) - ] - return 'CONSTANT {{{}{}\n}}'.format(self.tabreturn, self.tabreturn.join(block)) - - def tscale(self): - return 'INDEPENDENT {t FROM 0 TO 1 WITH 1 (ms)}' - - def neuron_block(self): - block = [ - 'SUFFIX {}'.format(self.pneuron.name), - '', - ': Constituting currents', - *['NONSPECIFIC_CURRENT {}'.format(i) for i in self.pneuron.getCurrentsNames()], - '', - ': RANGE variables', - 'RANGE Adrive, Vmeff : section specific', - 'RANGE stimon : common to all sections (but set as RANGE to be accessible from caller)' - ] - return 'NEURON {{{}{}\n}}'.format(self.tabreturn, self.tabreturn.join(block)) - - def parameter_block(self): - block = [ - ': Parameters set by python/hoc caller', - 'stimon : Stimulation state', - 'Adrive (kPa) : Stimulation amplitude', - '', - ': Membrane properties', - 'cm = {} (uF/cm2)'.format(self.pneuron.Cm0 * 1e2) - ] - - # Reversal potentials - possibles_E = list(set(['Na', 'K', 'Ca'] + [i[1:] for i in self.pneuron.getCurrentsNames()])) - for x in possibles_E: - nernst_pot = 'E{}'.format(x) - if hasattr(self.pneuron, nernst_pot): - block.append('{} = {} (mV)'.format( - nernst_pot, getattr(self.pneuron, nernst_pot))) - - # Conductances / permeabilities - for i in self.pneuron.getCurrentsNames(): - suffix = '{}{}'.format(i[1:], '' if 'Leak' in i else 'bar') - factors = {'g': 1e-4, 'p': 1e2} - units = {'g': 'S/cm2', 'p': 'cm/s'} - for prefix in ['g', 'p']: - attr = '{}{}'.format(prefix, suffix) - if hasattr(self.pneuron, attr): - val = getattr(self.pneuron, attr) * factors[prefix] - block.append('{} = {} ({})'.format(attr, val, units[prefix])) - - return 'PARAMETER {{{}{}\n}}'.format(self.tabreturn, self.tabreturn.join(block)) - - def state_block(self): - block = [': Standard gating states', *self.translated_states] - return 'STATE {{{}{}\n}}'.format(self.tabreturn, self.tabreturn.join(block)) - - def assigned_block(self): - block = [ - ': Variables computed during the simulation and whose value can be retrieved', - 'Vmeff (mV)', - 'v (mV)', - *['{} (mA/cm2)'.format(i) for i in self.pneuron.getCurrentsNames()] - ] - return 'ASSIGNED {{{}{}\n}}'.format(self.tabreturn, self.tabreturn.join(block)) - - def function_tables(self): - block = [ - ': Function tables to interpolate effective variables', - 'FUNCTION_TABLE V(A(kPa), Q(nC/cm2)) (mV)', - *['FUNCTION_TABLE {}(A(kPa), Q(nC/cm2)) (mV)'.format(r) for r in self.pneuron.rates] - ] - return '\n'.join(block) - - def initial_block(self): - block = [': Set initial states values'] - for s in self.pneuron.states: - if s in self.pneuron.getGates(): - block.append('{0} = alpha{1}(0, v) / (alpha{1}(0, v) + beta{1}(0, v))'.format( - self.translateState(s), s.lower())) - else: - block.append('{} = ???'.format(self.translateState(s))) - - return 'INITIAL {{{}{}\n}}'.format(self.tabreturn, self.tabreturn.join(block)) - - def breakpoint_block(self): - block = [ - ': Integrate states', - 'SOLVE states METHOD cnexp', - '', - ': Compute effective membrane potential', - 'Vmeff = V(Adrive * stimon, v)', - '', - ': Compute ionic currents' - ] - for i in self.pneuron.getCurrentsNames(): - func_exp = inspect.getsource(getattr(self.pneuron, i)).splitlines()[-1] - func_exp = func_exp[func_exp.find('return') + 7:] - func_exp = func_exp.replace('self.', '').replace('Vm', 'Vmeff') - func_exp = re.sub(r'([A-Za-z][A-Za-z0-9]*)\*\*([0-9])', escaped_pow, func_exp) - block.append('{} = {}'.format(i, func_exp)) - - return 'BREAKPOINT {{{}{}\n}}'.format(self.tabreturn, self.tabreturn.join(block)) - - def derivative_block(self): - block = [': Gating states derivatives'] - for s in self.pneuron.states: - if s in self.pneuron.getGates(): - block.append( - '{0}\' = alpha{1}{2} * (1 - {0}) - beta{1}{2} * {0}'.format( - self.translateState(s), s.lower(), '(Adrive * stimon, v)') - ) - else: - block.append('{}\' = ???'.format(self.translateState(s))) - - return 'DERIVATIVE states {{{}{}\n}}'.format(self.tabreturn, self.tabreturn.join(block)) diff --git a/scripts/generate_mod_file.py b/scripts/generate_mod_file.py deleted file mode 100644 index 05c8efb..0000000 --- a/scripts/generate_mod_file.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# @Author: Theo Lemaire -# @Email: theo.lemaire@epfl.ch -# @Date: 2019-03-18 18:06:20 -# @Last Modified by: Theo Lemaire -# @Last Modified time: 2019-06-17 10:50:40 - -import os - -from PySONIC.utils import logger -from PySONIC.core import NmodlGenerator -from PySONIC.parsers import Parser - - -def main(): - parser = Parser() - parser.addNeuron() - parser.addSave() - parser.addOutputDir(dep_key='save') - args = parser.parse() - logger.setLevel(args['loglevel']) - - for pneuron in args['neuron']: - logger.info('generating %s neuron MOD file', pneuron.name) - gen = NmodlGenerator(pneuron) - if args['save']: - outfile = '{}.mod'.format(pneuron.name) - outpath = os.path.join(args['outputdir'], outfile) - logger.info('dumping MOD file in "%s"', args['outputdir']) - gen.dump(outpath) - else: - gen.print() - - -if __name__ == '__main__': - main()