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.
Files changed (56) hide show
  1. dendrotweaks/__init__.py +10 -0
  2. dendrotweaks/analysis/__init__.py +11 -0
  3. dendrotweaks/analysis/ephys_analysis.py +482 -0
  4. dendrotweaks/analysis/morphometric_analysis.py +106 -0
  5. dendrotweaks/membrane/__init__.py +6 -0
  6. dendrotweaks/membrane/default_mod/AMPA.mod +65 -0
  7. dendrotweaks/membrane/default_mod/AMPA_NMDA.mod +100 -0
  8. dendrotweaks/membrane/default_mod/CaDyn.mod +54 -0
  9. dendrotweaks/membrane/default_mod/GABAa.mod +65 -0
  10. dendrotweaks/membrane/default_mod/Leak.mod +27 -0
  11. dendrotweaks/membrane/default_mod/NMDA.mod +72 -0
  12. dendrotweaks/membrane/default_mod/vecstim.mod +76 -0
  13. dendrotweaks/membrane/default_templates/NEURON_template.py +354 -0
  14. dendrotweaks/membrane/default_templates/default.py +73 -0
  15. dendrotweaks/membrane/default_templates/standard_channel.mod +87 -0
  16. dendrotweaks/membrane/default_templates/template_jaxley.py +108 -0
  17. dendrotweaks/membrane/default_templates/template_jaxley_new.py +108 -0
  18. dendrotweaks/membrane/distributions.py +324 -0
  19. dendrotweaks/membrane/groups.py +103 -0
  20. dendrotweaks/membrane/io/__init__.py +11 -0
  21. dendrotweaks/membrane/io/ast.py +201 -0
  22. dendrotweaks/membrane/io/code_generators.py +312 -0
  23. dendrotweaks/membrane/io/converter.py +108 -0
  24. dendrotweaks/membrane/io/factories.py +144 -0
  25. dendrotweaks/membrane/io/grammar.py +417 -0
  26. dendrotweaks/membrane/io/loader.py +90 -0
  27. dendrotweaks/membrane/io/parser.py +499 -0
  28. dendrotweaks/membrane/io/reader.py +212 -0
  29. dendrotweaks/membrane/mechanisms.py +574 -0
  30. dendrotweaks/model.py +1916 -0
  31. dendrotweaks/model_io.py +75 -0
  32. dendrotweaks/morphology/__init__.py +5 -0
  33. dendrotweaks/morphology/domains.py +100 -0
  34. dendrotweaks/morphology/io/__init__.py +5 -0
  35. dendrotweaks/morphology/io/factories.py +212 -0
  36. dendrotweaks/morphology/io/reader.py +66 -0
  37. dendrotweaks/morphology/io/validation.py +212 -0
  38. dendrotweaks/morphology/point_trees.py +681 -0
  39. dendrotweaks/morphology/reduce/__init__.py +16 -0
  40. dendrotweaks/morphology/reduce/reduce.py +155 -0
  41. dendrotweaks/morphology/reduce/reduced_cylinder.py +129 -0
  42. dendrotweaks/morphology/sec_trees.py +1112 -0
  43. dendrotweaks/morphology/seg_trees.py +157 -0
  44. dendrotweaks/morphology/trees.py +567 -0
  45. dendrotweaks/path_manager.py +261 -0
  46. dendrotweaks/simulators.py +235 -0
  47. dendrotweaks/stimuli/__init__.py +3 -0
  48. dendrotweaks/stimuli/iclamps.py +73 -0
  49. dendrotweaks/stimuli/populations.py +265 -0
  50. dendrotweaks/stimuli/synapses.py +203 -0
  51. dendrotweaks/utils.py +239 -0
  52. dendrotweaks-0.3.1.dist-info/METADATA +70 -0
  53. dendrotweaks-0.3.1.dist-info/RECORD +56 -0
  54. dendrotweaks-0.3.1.dist-info/WHEEL +5 -0
  55. dendrotweaks-0.3.1.dist-info/licenses/LICENSE +674 -0
  56. 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