dendrotweaks 0.3.1__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dendrotweaks/__init__.py +2 -2
- dendrotweaks/analysis/ephys_analysis.py +12 -8
- dendrotweaks/biophys/__init__.py +7 -0
- dendrotweaks/{membrane → biophys}/default_templates/NEURON_template.py +5 -3
- dendrotweaks/{membrane → biophys}/default_templates/default.py +2 -1
- dendrotweaks/{membrane → biophys}/default_templates/standard_channel.mod +5 -1
- dendrotweaks/{membrane → biophys}/groups.py +2 -2
- dendrotweaks/biophys/io/__init__.py +11 -0
- dendrotweaks/{membrane → biophys}/io/ast.py +6 -0
- dendrotweaks/{membrane → biophys}/io/code_generators.py +7 -1
- dendrotweaks/{membrane → biophys}/io/converter.py +3 -3
- dendrotweaks/{membrane → biophys}/io/factories.py +8 -6
- dendrotweaks/biophys/io/loader.py +190 -0
- dendrotweaks/{membrane → biophys}/io/parser.py +8 -8
- dendrotweaks/{membrane → biophys}/mechanisms.py +14 -10
- dendrotweaks/model.py +65 -32
- dendrotweaks/morphology/sec_trees.py +1 -1
- dendrotweaks/path_manager.py +9 -11
- dendrotweaks/simulators.py +82 -48
- dendrotweaks/stimuli/populations.py +11 -0
- {dendrotweaks-0.3.1.dist-info → dendrotweaks-0.4.0.dist-info}/METADATA +2 -2
- dendrotweaks-0.4.0.dist-info/RECORD +56 -0
- {dendrotweaks-0.3.1.dist-info → dendrotweaks-0.4.0.dist-info}/WHEEL +1 -1
- dendrotweaks/membrane/__init__.py +0 -6
- dendrotweaks/membrane/io/__init__.py +0 -11
- dendrotweaks/membrane/io/loader.py +0 -90
- dendrotweaks-0.3.1.dist-info/RECORD +0 -56
- /dendrotweaks/{membrane → biophys}/default_mod/AMPA.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/AMPA_NMDA.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/CaDyn.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/GABAa.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/Leak.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/NMDA.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/vecstim.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_templates/template_jaxley.py +0 -0
- /dendrotweaks/{membrane → biophys}/default_templates/template_jaxley_new.py +0 -0
- /dendrotweaks/{membrane → biophys}/distributions.py +0 -0
- /dendrotweaks/{membrane → biophys}/io/grammar.py +0 -0
- /dendrotweaks/{membrane → biophys}/io/reader.py +0 -0
- {dendrotweaks-0.3.1.dist-info → dendrotweaks-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {dendrotweaks-0.3.1.dist-info → dendrotweaks-0.4.0.dist-info}/top_level.txt +0 -0
dendrotweaks/__init__.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
__version__ = "0.
|
1
|
+
__version__ = "0.4.0"
|
2
2
|
|
3
3
|
from dendrotweaks.model import Model
|
4
4
|
from dendrotweaks.simulators import NEURONSimulator
|
5
|
-
from dendrotweaks.
|
5
|
+
from dendrotweaks.biophys.distributions import Distribution
|
6
6
|
from dendrotweaks.path_manager import PathManager
|
7
7
|
from dendrotweaks.stimuli import Synapse, Population, IClamp
|
8
8
|
|
@@ -27,7 +27,7 @@ def get_somatic_data(model):
|
|
27
27
|
seg = model.seg_tree.root
|
28
28
|
iclamp = model.iclamps[seg]
|
29
29
|
|
30
|
-
v = np.array(model.simulator.
|
30
|
+
v = np.array(model.simulator.recordings['v'][seg])
|
31
31
|
t = np.array(model.simulator.t)
|
32
32
|
dt = model.simulator.dt
|
33
33
|
|
@@ -165,7 +165,7 @@ def detect_somatic_spikes(model, **kwargs):
|
|
165
165
|
"""
|
166
166
|
seg = model.seg_tree.root
|
167
167
|
|
168
|
-
v = np.array(model.simulator.
|
168
|
+
v = np.array(model.simulator.recordings['v'][seg])
|
169
169
|
t = np.array(model.simulator.t)
|
170
170
|
dt = model.simulator.dt
|
171
171
|
|
@@ -271,7 +271,7 @@ def calculate_fI_curve(model, duration=1000, min_amp=0, max_amp=1, n=5, **kwargs
|
|
271
271
|
n_spikes = len(spike_data['spike_times'])
|
272
272
|
rate = n_spikes / iclamp.dur * 1000
|
273
273
|
rates.append(rate)
|
274
|
-
vs[amp] = model.simulator.
|
274
|
+
vs[amp] = model.simulator.recordings['v'][seg]
|
275
275
|
|
276
276
|
return {
|
277
277
|
'current_amplitudes': amps,
|
@@ -336,11 +336,14 @@ def calculate_voltage_attenuation(model):
|
|
336
336
|
if len(stimulated_segs) != 1:
|
337
337
|
print("Only one stimulation site is supported")
|
338
338
|
return None
|
339
|
-
recorded_segs = list(model.recordings.keys())
|
339
|
+
recorded_segs = list(model.recordings['v'].keys())
|
340
340
|
if len(recorded_segs) < 2:
|
341
341
|
print("At least two recording sites are required")
|
342
342
|
return None
|
343
343
|
|
344
|
+
print(f"Stimulating segment: {stimulated_segs[0]}")
|
345
|
+
print(f"Recording segments: {recorded_segs}")
|
346
|
+
|
344
347
|
stimulated_seg = stimulated_segs[0]
|
345
348
|
|
346
349
|
iclamp = model.iclamps[stimulated_seg]
|
@@ -355,8 +358,9 @@ def calculate_voltage_attenuation(model):
|
|
355
358
|
start_ts = int(iclamp.delay / model.simulator.dt)
|
356
359
|
stop_ts = int((iclamp.delay + iclamp.dur) / model.simulator.dt)
|
357
360
|
|
358
|
-
voltage_at_stimulated = np.array(model.simulator.
|
359
|
-
voltages = [np.array(model.simulator.
|
361
|
+
voltage_at_stimulated = np.array(model.simulator.recordings['v'][stimulated_seg])[start_ts:stop_ts]
|
362
|
+
voltages = [np.array(model.simulator.recordings['v'][seg])[start_ts:stop_ts] for seg in recorded_segs]
|
363
|
+
|
360
364
|
|
361
365
|
# Calculate voltage displacement from the resting potential
|
362
366
|
delta_v_at_stimulated = voltage_at_stimulated[0] - np.min(voltage_at_stimulated)
|
@@ -405,7 +409,7 @@ def calculate_dendritic_nonlinearity(model, duration=1000, max_weight=None, n=No
|
|
405
409
|
A dictionary containing the expected and observed voltage changes.
|
406
410
|
"""
|
407
411
|
|
408
|
-
recorded_segs = list(model.recordings.keys())
|
412
|
+
recorded_segs = list(model.recordings['v'].keys())
|
409
413
|
seg = recorded_segs[0]
|
410
414
|
|
411
415
|
populations = [pop for pops in model.populations.values() for pop in pops.values()]
|
@@ -432,7 +436,7 @@ def calculate_dendritic_nonlinearity(model, duration=1000, max_weight=None, n=No
|
|
432
436
|
for w in weights:
|
433
437
|
population.update_input_params(weight=w)
|
434
438
|
model.simulator.run(duration)
|
435
|
-
v = np.array(model.simulator.
|
439
|
+
v = np.array(model.simulator.recordings['v'][seg])
|
436
440
|
v_start = v[start_ts]
|
437
441
|
v_max = np.max(v[start_ts:])
|
438
442
|
delta_v = v_max - v_start
|
@@ -0,0 +1,7 @@
|
|
1
|
+
from dendrotweaks.biophys.mechanisms import Mechanism, IonChannel, StandardIonChannel
|
2
|
+
from dendrotweaks.biophys.mechanisms import CaDynamics, LeakChannel
|
3
|
+
from dendrotweaks.biophys.mechanisms import LeakChannel
|
4
|
+
from dendrotweaks.biophys.groups import SegmentGroup
|
5
|
+
from dendrotweaks.biophys.distributions import Distribution
|
6
|
+
|
7
|
+
import dendrotweaks.biophys.io as io
|
@@ -114,7 +114,7 @@ class Cell():
|
|
114
114
|
{% for domain, mechanisms in domains_to_mechs.items() %}
|
115
115
|
for sec in self.{{ domains_to_NEURON[domain] }}:
|
116
116
|
{% for mechanism in mechanisms %}
|
117
|
-
|
117
|
+
sec.insert('{{ mechanism }}')
|
118
118
|
{%- endfor %}
|
119
119
|
{% endfor %}
|
120
120
|
|
@@ -235,10 +235,12 @@ class Cell():
|
|
235
235
|
|
236
236
|
def add_recordings(self):
|
237
237
|
recordings = []
|
238
|
-
{% for
|
238
|
+
{% for var, recs in recordings.items() %}
|
239
|
+
{% for seg, rec in recs.items() %}
|
239
240
|
rec = h.Vector()
|
240
|
-
rec.record(self.{{seg._section.domain}}[{{seg._section.domain_idx}}]({{seg.x}}).
|
241
|
+
rec.record(self.{{seg._section.domain}}[{{seg._section.domain_idx}}]({{seg.x}})._ref_{{ var }})
|
241
242
|
recordings.append(rec)
|
243
|
+
{%- endfor -%}
|
242
244
|
{% endfor %}
|
243
245
|
return recordings
|
244
246
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
import sys
|
5
5
|
|
6
|
-
from dendrotweaks.
|
6
|
+
from dendrotweaks.biophys.mechanisms import IonChannel
|
7
7
|
import numpy as np
|
8
8
|
|
9
9
|
class {{ class_name }}(IonChannel):
|
@@ -43,6 +43,7 @@ class {{ class_name }}(IonChannel):
|
|
43
43
|
}
|
44
44
|
self.ion = "{{ ion }}"
|
45
45
|
self.current_name = "i_{{ ion }}"
|
46
|
+
self.current_available = {{ current_available }}
|
46
47
|
self.independent_var_name = "{{ independent_var_name }}"
|
47
48
|
self.temperature = 37
|
48
49
|
|
@@ -23,7 +23,7 @@ UNITS {
|
|
23
23
|
}
|
24
24
|
|
25
25
|
PARAMETER {
|
26
|
-
{% for key, value, unit in
|
26
|
+
{% for key, value, unit in params %}{{ "%-7s"|format(key) }} = {{ value }} ({{ unit }}){% if not loop.last %}
|
27
27
|
{% endif %}{% endfor %}
|
28
28
|
}
|
29
29
|
|
@@ -57,7 +57,11 @@ DERIVATIVE states {
|
|
57
57
|
}
|
58
58
|
|
59
59
|
INITIAL {
|
60
|
+
{%- if has_tadj%}
|
60
61
|
tadj = q10^((celsius - temp)/10(degC))
|
62
|
+
{%- else %}
|
63
|
+
tadj = 1
|
64
|
+
{%- endif %}
|
61
65
|
rates(v)
|
62
66
|
{% for state in state_vars %}{{ state }} = {{ state }}_inf
|
63
67
|
{% endfor %}
|
@@ -3,8 +3,8 @@ from typing import List, Callable, Dict
|
|
3
3
|
from dendrotweaks.morphology.trees import Node
|
4
4
|
from dendrotweaks.morphology.sec_trees import Section
|
5
5
|
from dendrotweaks.morphology.seg_trees import Segment
|
6
|
-
from dendrotweaks.
|
7
|
-
from dendrotweaks.
|
6
|
+
from dendrotweaks.biophys.mechanisms import Mechanism
|
7
|
+
from dendrotweaks.biophys.distributions import Distribution
|
8
8
|
from dendrotweaks.utils import timeit
|
9
9
|
from dataclasses import dataclass, field, asdict
|
10
10
|
from typing import List, Tuple, Dict, Optional
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from dendrotweaks.biophys.io.loader import MODFileLoader
|
2
|
+
from dendrotweaks.biophys.io.converter import MODFileConverter
|
3
|
+
|
4
|
+
from dendrotweaks.biophys.io.reader import MODFileReader
|
5
|
+
from dendrotweaks.biophys.io.parser import MODFileParser
|
6
|
+
from dendrotweaks.biophys.io.code_generators import PythonCodeGenerator
|
7
|
+
from dendrotweaks.biophys.io.code_generators import NMODLCodeGenerator
|
8
|
+
|
9
|
+
from dendrotweaks.biophys.io.factories import create_channel
|
10
|
+
from dendrotweaks.biophys.io.factories import create_standard_channel
|
11
|
+
from dendrotweaks.biophys.io.factories import standardize_channel
|
@@ -90,6 +90,12 @@ class AbstracSyntaxTree():
|
|
90
90
|
return {k:v for k, v in self.params.items()
|
91
91
|
if k in self['NEURON']['range']}
|
92
92
|
|
93
|
+
@property
|
94
|
+
def current_available(self):
|
95
|
+
"""
|
96
|
+
Returns True if the current is available in the mechanism.
|
97
|
+
"""
|
98
|
+
return 'i' in self['NEURON']['range']
|
93
99
|
|
94
100
|
# ASSIGNED block
|
95
101
|
@property
|
@@ -72,6 +72,7 @@ class PythonCodeGenerator(CodeGenerator):
|
|
72
72
|
'independent_var_name': ast.independent_var_name,
|
73
73
|
'channel_params': ast.params,
|
74
74
|
'range_params': ast.range_params,
|
75
|
+
'current_available': ast.current_available,
|
75
76
|
'state_vars': ast.state_vars,
|
76
77
|
'functions': self._generate_functions(ast),
|
77
78
|
'procedures': self._generate_procedures(ast),
|
@@ -296,10 +297,15 @@ class NMODLCodeGenerator(CodeGenerator):
|
|
296
297
|
variables = {
|
297
298
|
'suffix': channel.name,
|
298
299
|
'ion': channel.ion,
|
299
|
-
'
|
300
|
+
'params': [
|
300
301
|
(param, channel.params[param], get_unit(param))
|
301
302
|
for param in channel.params
|
302
303
|
],
|
304
|
+
'range_params': [
|
305
|
+
(param, channel.range_params[param], get_unit(param))
|
306
|
+
for param in channel.range_params
|
307
|
+
],
|
308
|
+
'has_tadj': ('q10' in channel.params and 'temp' in channel.params),
|
303
309
|
'state_vars': {
|
304
310
|
var: params['power'] for var, params in channel._state_powers.items()
|
305
311
|
},
|
@@ -1,6 +1,6 @@
|
|
1
|
-
from dendrotweaks.
|
2
|
-
from dendrotweaks.
|
3
|
-
from dendrotweaks.
|
1
|
+
from dendrotweaks.biophys.io.reader import MODFileReader
|
2
|
+
from dendrotweaks.biophys.io.parser import MODFileParser
|
3
|
+
from dendrotweaks.biophys.io.code_generators import PythonCodeGenerator
|
4
4
|
|
5
5
|
class MODFileConverter():
|
6
6
|
"""
|
@@ -3,9 +3,9 @@ import sys
|
|
3
3
|
from typing import List, Tuple
|
4
4
|
|
5
5
|
|
6
|
-
from dendrotweaks.
|
7
|
-
from dendrotweaks.
|
8
|
-
from dendrotweaks.
|
6
|
+
from dendrotweaks.biophys.io.converter import MODFileConverter
|
7
|
+
from dendrotweaks.biophys.io.code_generators import NMODLCodeGenerator
|
8
|
+
from dendrotweaks.biophys.mechanisms import Mechanism, IonChannel, StandardIonChannel
|
9
9
|
|
10
10
|
|
11
11
|
def create_channel(path_to_mod_file: str,
|
@@ -86,10 +86,12 @@ def standardize_channel(channel: IonChannel,
|
|
86
86
|
state_powers=channel._state_powers,
|
87
87
|
ion=channel.ion)
|
88
88
|
|
89
|
-
|
90
|
-
|
89
|
+
if 'q10' in channel.params:
|
90
|
+
standard_channel.params['q10'] = channel.params['q10']
|
91
|
+
if 'temp' in channel.params:
|
92
|
+
standard_channel.params['temp'] = channel.params['temp']
|
91
93
|
|
92
|
-
fit_temperature = channel.params.get('temp')
|
94
|
+
fit_temperature = channel.params.get('temp')
|
93
95
|
|
94
96
|
standard_channel.set_tadj(fit_temperature)
|
95
97
|
# Fit the standard channel to the data
|
@@ -0,0 +1,190 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import shutil
|
4
|
+
import subprocess
|
5
|
+
import neuron
|
6
|
+
from neuron import h
|
7
|
+
|
8
|
+
|
9
|
+
class MODFileLoader():
|
10
|
+
|
11
|
+
def __init__(self):
|
12
|
+
self._loaded_mechanisms = set()
|
13
|
+
self.verbose = False
|
14
|
+
|
15
|
+
def _log(self, message):
|
16
|
+
"""Print a message if verbose mode is enabled."""
|
17
|
+
if self.verbose:
|
18
|
+
print(message)
|
19
|
+
|
20
|
+
# LOADING METHODS
|
21
|
+
|
22
|
+
def _get_mechanism_dir(self, path_to_mod_file: str) -> str:
|
23
|
+
"""
|
24
|
+
Get the subdirectory for the given mod file.
|
25
|
+
|
26
|
+
Parameters
|
27
|
+
----------
|
28
|
+
path_to_mod_file : str
|
29
|
+
Path to the .mod file.
|
30
|
+
|
31
|
+
Returns
|
32
|
+
-------
|
33
|
+
str
|
34
|
+
Path to the subdirectory for the mechanism.
|
35
|
+
"""
|
36
|
+
mechanism_name = os.path.basename(path_to_mod_file).replace('.mod', '')
|
37
|
+
parent_dir = os.path.dirname(path_to_mod_file)
|
38
|
+
if sys.platform.startswith('win'):
|
39
|
+
return os.path.join(parent_dir, mechanism_name, mechanism_name)
|
40
|
+
else:
|
41
|
+
return os.path.join(parent_dir, mechanism_name)
|
42
|
+
|
43
|
+
def _clean_mechanism_dir(self, mechanism_dir: str) -> None:
|
44
|
+
|
45
|
+
if sys.platform.startswith('win'):
|
46
|
+
parent_dir = os.path.dirname(mechanism_dir)
|
47
|
+
shutil.rmtree(parent_dir)
|
48
|
+
else:
|
49
|
+
shutil.rmtree(mechanism_dir)
|
50
|
+
|
51
|
+
|
52
|
+
def load_mechanism(self, path_to_mod_file: str,
|
53
|
+
recompile: bool = False) -> None:
|
54
|
+
"""
|
55
|
+
Load a mechanism from the specified mod file.
|
56
|
+
Uses the NEURON neuron.load_mechanisms method to make
|
57
|
+
the mechanism available in the hoc interpreter.
|
58
|
+
Creates a temporary directory for the mechanism files
|
59
|
+
to be able to dynamically load mechanisms.
|
60
|
+
|
61
|
+
Parameters
|
62
|
+
----------
|
63
|
+
path_to_mod_file : str
|
64
|
+
Path to the .mod file.
|
65
|
+
recompile : bool
|
66
|
+
Force recompilation even if already compiled.
|
67
|
+
"""
|
68
|
+
mechanism_name = os.path.basename(path_to_mod_file).replace('.mod', '')
|
69
|
+
mechanism_dir = self._get_mechanism_dir(path_to_mod_file)
|
70
|
+
|
71
|
+
if self.verbose: print(f"{'=' * 60}\nLoading mechanism {mechanism_name} to NEURON...")
|
72
|
+
|
73
|
+
# Check if the mechanism is already loaded
|
74
|
+
if mechanism_name in self._loaded_mechanisms:
|
75
|
+
self._log(f'Mechanism "{mechanism_name}" already loaded')
|
76
|
+
return
|
77
|
+
|
78
|
+
if recompile and os.path.exists(mechanism_dir):
|
79
|
+
self._clean_mechanism_dir(mechanism_dir)
|
80
|
+
|
81
|
+
self._separate_and_compile(mechanism_name, mechanism_dir, path_to_mod_file)
|
82
|
+
|
83
|
+
# Load the mechanism
|
84
|
+
self._load_mechanism(mechanism_name, mechanism_dir)
|
85
|
+
|
86
|
+
|
87
|
+
# HELPER METHODS
|
88
|
+
|
89
|
+
def _separate_and_compile(self, mechanism_name, mechanism_dir, path_to_mod_file):
|
90
|
+
"""
|
91
|
+
Separate the mechanism files into their own directory and compile them.
|
92
|
+
Separation is done to enable dynamic loading of mechanisms.
|
93
|
+
Compilation is done using the appropriate command based on the platform.
|
94
|
+
|
95
|
+
Parameters
|
96
|
+
----------
|
97
|
+
mechanism_name : str
|
98
|
+
Name of the mechanism.
|
99
|
+
mechanism_dir : str
|
100
|
+
Directory to store the mechanism files.
|
101
|
+
path_to_mod_file : str
|
102
|
+
Path to the .mod file.
|
103
|
+
"""
|
104
|
+
|
105
|
+
if sys.platform.startswith('win'):
|
106
|
+
dll_file = os.path.join(os.path.dirname(mechanism_dir), 'nrnmech.dll')
|
107
|
+
if not os.path.exists(dll_file):
|
108
|
+
self._log(f'Compiling mechanism "{mechanism_name}"...')
|
109
|
+
os.makedirs(mechanism_dir, exist_ok=True)
|
110
|
+
shutil.copy(path_to_mod_file, mechanism_dir)
|
111
|
+
self._compile_files(mechanism_dir, ["mknrndll"], shell=True)
|
112
|
+
else:
|
113
|
+
x86_64_dir = os.path.join(mechanism_dir, 'x86_64')
|
114
|
+
if not os.path.exists(x86_64_dir):
|
115
|
+
self._log(f'Compiling mechanism "{mechanism_name}"...')
|
116
|
+
os.makedirs(mechanism_dir, exist_ok=True)
|
117
|
+
shutil.copy(path_to_mod_file, mechanism_dir)
|
118
|
+
self._compile_files(mechanism_dir, ["nrnivmodl"])
|
119
|
+
|
120
|
+
|
121
|
+
def _load_mechanism(self, mechanism_name: str, mechanism_dir: str) -> None:
|
122
|
+
"""
|
123
|
+
Load the mechanism into NEURON using neuron.load_mechanisms.
|
124
|
+
This method checks if the mechanism is already loaded
|
125
|
+
and only loads it if not.
|
126
|
+
Parameters
|
127
|
+
----------
|
128
|
+
mechanism_name : str
|
129
|
+
Name of the mechanism.
|
130
|
+
mechanism_dir : str
|
131
|
+
Directory containing the compiled mechanism files.
|
132
|
+
"""
|
133
|
+
|
134
|
+
if hasattr(h, mechanism_name):
|
135
|
+
self._log(f'Mechanism "{mechanism_name}" already exists in hoc')
|
136
|
+
else:
|
137
|
+
try:
|
138
|
+
neuron.load_mechanisms(mechanism_dir)
|
139
|
+
except Exception as e:
|
140
|
+
print(f"Failed to load mechanism {mechanism_name}: {e}")
|
141
|
+
return
|
142
|
+
self._loaded_mechanisms.add(mechanism_name)
|
143
|
+
self._log(f'Loaded mechanism "{mechanism_name}"')
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
def _compile_files(self, path, command, shell=False):
|
148
|
+
"""
|
149
|
+
Compile the MOD files in the specified directory.
|
150
|
+
|
151
|
+
Parameters
|
152
|
+
----------
|
153
|
+
path : str or Path
|
154
|
+
Directory containing MOD files to compile.
|
155
|
+
command : list
|
156
|
+
Compilation command to execute. Either "mknrndll" or "nrnivmodl".
|
157
|
+
shell : bool
|
158
|
+
Whether to use shell=True for subprocess.run
|
159
|
+
(Windows compatibility).
|
160
|
+
|
161
|
+
Returns
|
162
|
+
-------
|
163
|
+
bool
|
164
|
+
True if compilation succeeded, False otherwise.
|
165
|
+
"""
|
166
|
+
path_str = str(path)
|
167
|
+
|
168
|
+
try:
|
169
|
+
result = subprocess.run(
|
170
|
+
command,
|
171
|
+
cwd=path_str,
|
172
|
+
check=True,
|
173
|
+
capture_output=True,
|
174
|
+
text=True,
|
175
|
+
shell=shell
|
176
|
+
)
|
177
|
+
|
178
|
+
self._log("Compilation successful.")
|
179
|
+
if self.verbose and result.stdout:
|
180
|
+
print(result.stdout)
|
181
|
+
return
|
182
|
+
|
183
|
+
except subprocess.CalledProcessError as e:
|
184
|
+
print(f"Compilation failed with return code {e.returncode}")
|
185
|
+
if self.verbose:
|
186
|
+
if e.stdout:
|
187
|
+
print("Compiler output:\n", e.stdout)
|
188
|
+
if e.stderr:
|
189
|
+
print("Compiler errors:\n", e.stderr)
|
190
|
+
return
|
@@ -2,14 +2,14 @@ import re
|
|
2
2
|
import pprint
|
3
3
|
from typing import List, Dict, Union, Any
|
4
4
|
|
5
|
-
from dendrotweaks.
|
6
|
-
from dendrotweaks.
|
7
|
-
from dendrotweaks.
|
8
|
-
from dendrotweaks.
|
9
|
-
from dendrotweaks.
|
10
|
-
from dendrotweaks.
|
11
|
-
|
12
|
-
from dendrotweaks.
|
5
|
+
from dendrotweaks.biophys.io.grammar import title, comment_block
|
6
|
+
from dendrotweaks.biophys.io.grammar import neuron_block
|
7
|
+
from dendrotweaks.biophys.io.grammar import units_block, parameter_block, assigned_block
|
8
|
+
from dendrotweaks.biophys.io.grammar import state_block
|
9
|
+
from dendrotweaks.biophys.io.grammar import breakpoint_block, derivative_block, initial_block
|
10
|
+
from dendrotweaks.biophys.io.grammar import function_block, procedure_block
|
11
|
+
|
12
|
+
from dendrotweaks.biophys.io.ast import AbstracSyntaxTree
|
13
13
|
|
14
14
|
|
15
15
|
class MODFileParser():
|
@@ -32,6 +32,7 @@ class Mechanism():
|
|
32
32
|
self.name = name
|
33
33
|
self.params = {}
|
34
34
|
self.range_params = {}
|
35
|
+
self.current_available = False
|
35
36
|
|
36
37
|
@property
|
37
38
|
def params_with_suffix(self):
|
@@ -119,9 +120,12 @@ class IonChannel(Mechanism):
|
|
119
120
|
where q10 is the temperature coefficient and reference_temp is the
|
120
121
|
temperature at which the channel kinetics were measured.
|
121
122
|
"""
|
122
|
-
q10 = self.params.get("q10"
|
123
|
-
reference_temp = self.params.get("temp"
|
124
|
-
|
123
|
+
q10 = self.params.get("q10")
|
124
|
+
reference_temp = self.params.get("temp")
|
125
|
+
if q10 is None or reference_temp is None:
|
126
|
+
self.tadj = 1
|
127
|
+
else:
|
128
|
+
self.tadj = q10 ** ((temperature - reference_temp) / 10)
|
125
129
|
|
126
130
|
def get_data(self, x=None, temperature: float = 37, verbose=True) -> Dict[str, Dict[str, float]]:
|
127
131
|
"""
|
@@ -367,14 +371,14 @@ class StandardIonChannel(IonChannel):
|
|
367
371
|
# for param in self.STANDARD_PARAMS]
|
368
372
|
|
369
373
|
self.params = {
|
374
|
+
'gbar': 0.0,
|
375
|
+
**{
|
370
376
|
f'{param}_{state}': None
|
371
377
|
for state in state_powers
|
372
378
|
for param in self.STANDARD_PARAMS
|
379
|
+
}
|
373
380
|
}
|
374
|
-
self.params.
|
375
|
-
'gbar': 0.0,
|
376
|
-
})
|
377
|
-
self.range_params = self.params.copy()
|
381
|
+
self.range_params = {k:v for k, v in self.params.items()}
|
378
382
|
|
379
383
|
self.temperature = 37
|
380
384
|
|
@@ -474,9 +478,9 @@ class StandardIonChannel(IonChannel):
|
|
474
478
|
fit_result.params = {key: round(value, round_params) for key, value in fit_result.params.items()}
|
475
479
|
|
476
480
|
for param in ['k', 'delta', 'tau0', 'vhalf', 'sigma']:
|
477
|
-
|
478
|
-
|
479
|
-
|
481
|
+
value = fit_result.params[param]
|
482
|
+
self.params[f'{param}_{state}'] = value
|
483
|
+
self.range_params[f'{param}_{state}'] = value
|
480
484
|
|
481
485
|
|
482
486
|
def to_dict(self):
|