dendrotweaks 0.3.1__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 +10 -0
- dendrotweaks/analysis/__init__.py +11 -0
- dendrotweaks/analysis/ephys_analysis.py +482 -0
- dendrotweaks/analysis/morphometric_analysis.py +106 -0
- dendrotweaks/membrane/__init__.py +6 -0
- dendrotweaks/membrane/default_mod/AMPA.mod +65 -0
- dendrotweaks/membrane/default_mod/AMPA_NMDA.mod +100 -0
- dendrotweaks/membrane/default_mod/CaDyn.mod +54 -0
- dendrotweaks/membrane/default_mod/GABAa.mod +65 -0
- dendrotweaks/membrane/default_mod/Leak.mod +27 -0
- dendrotweaks/membrane/default_mod/NMDA.mod +72 -0
- dendrotweaks/membrane/default_mod/vecstim.mod +76 -0
- dendrotweaks/membrane/default_templates/NEURON_template.py +354 -0
- dendrotweaks/membrane/default_templates/default.py +73 -0
- dendrotweaks/membrane/default_templates/standard_channel.mod +87 -0
- dendrotweaks/membrane/default_templates/template_jaxley.py +108 -0
- dendrotweaks/membrane/default_templates/template_jaxley_new.py +108 -0
- dendrotweaks/membrane/distributions.py +324 -0
- dendrotweaks/membrane/groups.py +103 -0
- dendrotweaks/membrane/io/__init__.py +11 -0
- dendrotweaks/membrane/io/ast.py +201 -0
- dendrotweaks/membrane/io/code_generators.py +312 -0
- dendrotweaks/membrane/io/converter.py +108 -0
- dendrotweaks/membrane/io/factories.py +144 -0
- dendrotweaks/membrane/io/grammar.py +417 -0
- dendrotweaks/membrane/io/loader.py +90 -0
- dendrotweaks/membrane/io/parser.py +499 -0
- dendrotweaks/membrane/io/reader.py +212 -0
- dendrotweaks/membrane/mechanisms.py +574 -0
- dendrotweaks/model.py +1916 -0
- dendrotweaks/model_io.py +75 -0
- dendrotweaks/morphology/__init__.py +5 -0
- dendrotweaks/morphology/domains.py +100 -0
- dendrotweaks/morphology/io/__init__.py +5 -0
- dendrotweaks/morphology/io/factories.py +212 -0
- dendrotweaks/morphology/io/reader.py +66 -0
- dendrotweaks/morphology/io/validation.py +212 -0
- dendrotweaks/morphology/point_trees.py +681 -0
- dendrotweaks/morphology/reduce/__init__.py +16 -0
- dendrotweaks/morphology/reduce/reduce.py +155 -0
- dendrotweaks/morphology/reduce/reduced_cylinder.py +129 -0
- dendrotweaks/morphology/sec_trees.py +1112 -0
- dendrotweaks/morphology/seg_trees.py +157 -0
- dendrotweaks/morphology/trees.py +567 -0
- dendrotweaks/path_manager.py +261 -0
- dendrotweaks/simulators.py +235 -0
- dendrotweaks/stimuli/__init__.py +3 -0
- dendrotweaks/stimuli/iclamps.py +73 -0
- dendrotweaks/stimuli/populations.py +265 -0
- dendrotweaks/stimuli/synapses.py +203 -0
- dendrotweaks/utils.py +239 -0
- dendrotweaks-0.3.1.dist-info/METADATA +70 -0
- dendrotweaks-0.3.1.dist-info/RECORD +56 -0
- dendrotweaks-0.3.1.dist-info/WHEEL +5 -0
- dendrotweaks-0.3.1.dist-info/licenses/LICENSE +674 -0
- dendrotweaks-0.3.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
import re
|
2
|
+
from typing import List, Dict
|
3
|
+
import os
|
4
|
+
|
5
|
+
class MODFileReader():
|
6
|
+
"""
|
7
|
+
Reader class for .mod files.
|
8
|
+
|
9
|
+
Provides methods to read and preprocess .mod files.
|
10
|
+
Splits the content of the file into blocks for further parsing.
|
11
|
+
|
12
|
+
Attributes
|
13
|
+
----------
|
14
|
+
content : str
|
15
|
+
The content of the MOD file.
|
16
|
+
blocks : Dict[str, List[str]]
|
17
|
+
The blocks of the MOD file corresponding to the
|
18
|
+
NMODL blocks e.g. NEURON, PARAMETER, ASSIGNED, etc.
|
19
|
+
unmatched : str
|
20
|
+
The unmatched content in the MOD file after splitting into blocks.
|
21
|
+
"""
|
22
|
+
|
23
|
+
BLOCK_TYPES = ['TITLE',
|
24
|
+
'COMMENT',
|
25
|
+
'NEURON',
|
26
|
+
'UNITS',
|
27
|
+
'PARAMETER',
|
28
|
+
'ASSIGNED',
|
29
|
+
'STATE',
|
30
|
+
'BREAKPOINT',
|
31
|
+
'DERIVATIVE',
|
32
|
+
'INITIAL',
|
33
|
+
'FUNCTION',
|
34
|
+
'PROCEDURE',
|
35
|
+
'KINETIC']
|
36
|
+
|
37
|
+
def __init__(self):
|
38
|
+
|
39
|
+
self._original_content = None
|
40
|
+
self.content = None
|
41
|
+
self.blocks = {}
|
42
|
+
self.unmatched = None
|
43
|
+
|
44
|
+
# READ
|
45
|
+
|
46
|
+
def read_file(self, path_to_file: str) -> str:
|
47
|
+
"""
|
48
|
+
Read the content of the file.
|
49
|
+
|
50
|
+
Parameters
|
51
|
+
----------
|
52
|
+
path_to_file : str
|
53
|
+
The path to the file.
|
54
|
+
"""
|
55
|
+
with open(path_to_file, 'r') as f:
|
56
|
+
content = f.read()
|
57
|
+
|
58
|
+
self._file_name = os.path.basename(path_to_file).replace('.mod', '')
|
59
|
+
self._path_to_file = path_to_file
|
60
|
+
self._original_content = content
|
61
|
+
self.content = content
|
62
|
+
|
63
|
+
# PREPROCESS
|
64
|
+
|
65
|
+
def preprocess(self, remove_inline_comments=True,
|
66
|
+
remove_unitsoff=True, remove_verbatim=True) -> None:
|
67
|
+
"""
|
68
|
+
Preprocess the content of the file.
|
69
|
+
"""
|
70
|
+
self.replace_suffix_with_name(overwirte=True)
|
71
|
+
if remove_inline_comments:
|
72
|
+
self.remove_inline_comments()
|
73
|
+
if remove_unitsoff:
|
74
|
+
self.remove_unitsoff()
|
75
|
+
if remove_verbatim:
|
76
|
+
self.remove_verbatim()
|
77
|
+
|
78
|
+
def replace_suffix_with_name(self, overwirte=False) -> None:
|
79
|
+
"""
|
80
|
+
Replace the suffix in the content of the file with the file name.
|
81
|
+
|
82
|
+
Notes
|
83
|
+
-----
|
84
|
+
Suffix is a string of the form SUFFIX suffix
|
85
|
+
|
86
|
+
Parameters
|
87
|
+
----------
|
88
|
+
overwirte : bool, optional
|
89
|
+
Whether to overwrite the content of the file with the modified content.
|
90
|
+
"""
|
91
|
+
suffix_pattern = r'SUFFIX\s+\w+'
|
92
|
+
match = re.search(suffix_pattern, self.content)
|
93
|
+
# print(f"Replacing {match.group()} with SUFFIX {self._file_name}")
|
94
|
+
self.content = re.sub(suffix_pattern, f'SUFFIX {self._file_name}', self.content)
|
95
|
+
if overwirte:
|
96
|
+
self._overwrite()
|
97
|
+
|
98
|
+
def _overwrite(self) -> None:
|
99
|
+
"""
|
100
|
+
Overwrite the content of the file with the modified content.
|
101
|
+
"""
|
102
|
+
with open(self._path_to_file, 'w') as f:
|
103
|
+
f.write(self.content)
|
104
|
+
# print(f"Overwritten {self._path_to_file}")
|
105
|
+
|
106
|
+
def remove_inline_comments(self) -> None:
|
107
|
+
"""
|
108
|
+
Remove the rest of the line after ":" from the content of the file.
|
109
|
+
"""
|
110
|
+
self.content = re.sub(r':.*', '', self.content)
|
111
|
+
|
112
|
+
|
113
|
+
def remove_unitsoff(self) -> None:
|
114
|
+
"""
|
115
|
+
Remove 'UNITSOFF' and 'UNITSON' from the content of the file.
|
116
|
+
"""
|
117
|
+
self.content = re.sub(r'UNITSOFF|UNITSON', '', self.content)
|
118
|
+
|
119
|
+
|
120
|
+
def remove_verbatim(self) -> None:
|
121
|
+
"""
|
122
|
+
Remove 'VERBATIM' and 'ENDVERBATIM' and everything in between from the content of the file.
|
123
|
+
"""
|
124
|
+
self.content = re.sub(r'VERBATIM.*?ENDVERBATIM', '', self.content, flags=re.DOTALL)
|
125
|
+
|
126
|
+
|
127
|
+
def remove_suffix_from_gbar(self) -> None:
|
128
|
+
"""
|
129
|
+
Remove the suffix from 'gbar' in the content of the file.
|
130
|
+
|
131
|
+
Example
|
132
|
+
-------
|
133
|
+
gnabar -> gbar
|
134
|
+
"""
|
135
|
+
self._content = re.sub(r'\b\w*g\w*bar\w*\b', 'gbar', self._content)
|
136
|
+
logger.info("Removed suffix from 'gbar' (e.g. gnabar -> gbar)")
|
137
|
+
|
138
|
+
# SPLIT TO BLOCKS
|
139
|
+
|
140
|
+
def get_blocks(self, verbose=True) -> Dict[str, List[str]]:
|
141
|
+
"""
|
142
|
+
Split the content of the file into blocks and return them.
|
143
|
+
|
144
|
+
Parameters
|
145
|
+
----------
|
146
|
+
verbose : bool, optional
|
147
|
+
Whether to print the
|
148
|
+
blocks of the file.
|
149
|
+
|
150
|
+
Returns
|
151
|
+
-------
|
152
|
+
Dict[str, List[str]]
|
153
|
+
A dictionary of blocks where the key is the block name
|
154
|
+
"""
|
155
|
+
for block_type in self.BLOCK_TYPES:
|
156
|
+
matches = self._get_block_regex(block_type)
|
157
|
+
self.blocks[block_type] = matches
|
158
|
+
if verbose:
|
159
|
+
message = f"Split content into blocks:\n"
|
160
|
+
message += '\n'.join([f" {len(block_content)} - {block_name}"
|
161
|
+
for block_name, block_content in self.blocks.items()])
|
162
|
+
print(message)
|
163
|
+
self.find_unmatched_content()
|
164
|
+
return self.blocks
|
165
|
+
|
166
|
+
def _get_block_regex(self, block_name: str) -> List[str]:
|
167
|
+
"""
|
168
|
+
Get the regex pattern for a specific block.
|
169
|
+
|
170
|
+
Example
|
171
|
+
-------
|
172
|
+
NEURON {
|
173
|
+
...
|
174
|
+
}
|
175
|
+
|
176
|
+
Parameters:
|
177
|
+
------------
|
178
|
+
block_name : str
|
179
|
+
The name of the block e.g. 'NEURON', 'PARAMETER', etc.
|
180
|
+
|
181
|
+
Returns
|
182
|
+
-------
|
183
|
+
List[str]
|
184
|
+
A list of matches for the block.
|
185
|
+
"""
|
186
|
+
if block_name == 'TITLE':
|
187
|
+
pattern = r"(" + re.escape(block_name) + r"[\s\S]*?\n)"
|
188
|
+
elif block_name == 'COMMENT':
|
189
|
+
pattern = r"(" + re.escape(block_name) + r"[\s\S]*?ENDCOMMENT)"
|
190
|
+
else:
|
191
|
+
pattern = r"(\b" + re.escape(block_name) + r"\b[\s\S]*?\{(?:[^{}]*\{[^{}]*\})*[^{}]*?\})"
|
192
|
+
matches = re.findall(pattern, self.content, re.DOTALL)
|
193
|
+
return matches
|
194
|
+
|
195
|
+
def find_unmatched_content(self, verbose:bool=False) -> None:
|
196
|
+
"""
|
197
|
+
Find unmatched content in the content of the file.
|
198
|
+
|
199
|
+
Parameters
|
200
|
+
----------
|
201
|
+
verbose : bool, optional
|
202
|
+
Whether to print the unmatched content.
|
203
|
+
"""
|
204
|
+
unmatched = self.content
|
205
|
+
for block_name, block in self.blocks.items():
|
206
|
+
for block_content in block:
|
207
|
+
unmatched = unmatched.replace(block_content, '')
|
208
|
+
unmatched = unmatched.strip()
|
209
|
+
if verbose:
|
210
|
+
if unmatched: print(f"Unmatched content:\n{unmatched}")
|
211
|
+
else: print("No unmatched content.")
|
212
|
+
self._unmatched = unmatched
|