dendrotweaks 0.4.0__py3-none-any.whl → 0.4.2__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 CHANGED
@@ -1,7 +1,7 @@
1
- __version__ = "0.4.0"
1
+ __version__ = "0.4.2"
2
2
 
3
3
  from dendrotweaks.model import Model
4
- from dendrotweaks.simulators import NEURONSimulator
4
+ from dendrotweaks.simulators import NeuronSimulator
5
5
  from dendrotweaks.biophys.distributions import Distribution
6
6
  from dendrotweaks.path_manager import PathManager
7
7
  from dendrotweaks.stimuli import Synapse, Population, IClamp
@@ -1,10 +1,5 @@
1
1
  from typing import List, Callable, Dict
2
2
 
3
- from dendrotweaks.morphology.trees import Node
4
- from dendrotweaks.morphology.sec_trees import Section
5
- from dendrotweaks.morphology.seg_trees import Segment
6
- from dendrotweaks.biophys.mechanisms import Mechanism
7
- from dendrotweaks.biophys.distributions import Distribution
8
3
  from dendrotweaks.utils import timeit
9
4
  from dataclasses import dataclass, field, asdict
10
5
  from typing import List, Tuple, Dict, Optional
@@ -134,7 +134,8 @@ class PythonCodeGenerator(CodeGenerator):
134
134
  # Generate the signature
135
135
  signature_str = self._generate_signature(procedure.signature,
136
136
  is_method=True,
137
- extra_params=['celsius'])
137
+ extra_params=['celsius'],
138
+ default_params=True)
138
139
 
139
140
  # Generate the body
140
141
  body_str = self._generate_body(procedure.statements)
@@ -160,7 +161,7 @@ class PythonCodeGenerator(CodeGenerator):
160
161
 
161
162
  return procedures
162
163
 
163
- def _generate_signature(self, signature, is_method=True, extra_params=None):
164
+ def _generate_signature(self, signature, is_method=True, extra_params=None, default_params=False):
164
165
  """
165
166
  Generate the signature string for a function using a Jinja2 template.
166
167
  The function AST representation is used to retrieve the function name
@@ -180,6 +181,9 @@ class PythonCodeGenerator(CodeGenerator):
180
181
  template = Template(signature_template)
181
182
  name = signature['name']
182
183
  params = [param['name'] for param in signature.get('params', [])]
184
+ if params == [] and default_params:
185
+ print(f"Warning: Procedure {name} has no parameters! Expected 'v' or 'cai'. Defaulting to 'v'.")
186
+ params = ['v']
183
187
  if is_method:
184
188
  params = ['self'] + params
185
189
 
dendrotweaks/model.py CHANGED
@@ -6,9 +6,9 @@ import numpy as np
6
6
  import quantities as pq
7
7
 
8
8
  from dendrotweaks.morphology.point_trees import PointTree
9
- from dendrotweaks.morphology.sec_trees import Section, SectionTree, Domain
10
- from dendrotweaks.morphology.seg_trees import Segment, SegmentTree
11
- from dendrotweaks.simulators import NEURONSimulator
9
+ from dendrotweaks.morphology.sec_trees import NeuronSection, Section, SectionTree, Domain
10
+ from dendrotweaks.morphology.seg_trees import NeuronSegment, Segment, SegmentTree
11
+ from dendrotweaks.simulators import NeuronSimulator
12
12
  from dendrotweaks.biophys.groups import SegmentGroup
13
13
  from dendrotweaks.biophys.mechanisms import Mechanism, LeakChannel, CaDynamics
14
14
  from dendrotweaks.biophys.io import create_channel, standardize_channel, create_standard_channel
@@ -149,7 +149,7 @@ class Model():
149
149
 
150
150
  # Simulator
151
151
  if simulator_name == 'NEURON':
152
- self.simulator = NEURONSimulator()
152
+ self.simulator = NeuronSimulator()
153
153
  elif simulator_name == 'Jaxley':
154
154
  self.simulator = JaxleySimulator()
155
155
  else:
@@ -231,9 +231,9 @@ class Model():
231
231
  The dictionary mapping mechanisms to domains where they are inserted.
232
232
  """
233
233
  mechs_to_domains = defaultdict(set)
234
- for domain, mechs in self.domains_to_mechs.items():
235
- for mech in mechs:
236
- mechs_to_domains[mech].add(domain)
234
+ for domain_name, mech_names in self.domains_to_mechs.items():
235
+ for mech_name in mech_names:
236
+ mechs_to_domains[mech_name].add(domain_name)
237
237
  return dict(mechs_to_domains)
238
238
 
239
239
 
@@ -418,7 +418,7 @@ class Model():
418
418
  """
419
419
  if self.verbose: print(f'Building sections in {self.simulator_name}...')
420
420
  for sec in self.sec_tree.sections:
421
- sec.create_and_reference(self.simulator_name)
421
+ sec.create_and_reference()
422
422
  n_sec = len([sec._ref for sec in self.sec_tree.sections
423
423
  if sec._ref is not None])
424
424
  if self.verbose: print(f'{n_sec} sections created.')
@@ -439,9 +439,10 @@ class Model():
439
439
  # TODO: Check that domains match
440
440
  if not domain_name in self.domains_to_mechs:
441
441
  self.domains_to_mechs[domain_name] = set()
442
- for domain_name, mechs in self.domains_to_mechs.items():
443
- for mech_name in mechs:
444
- self.insert_mechanism(mech_name, domain_name)
442
+ for domain_name, mech_names in self.domains_to_mechs.items():
443
+ for mech_name in mech_names:
444
+ mech = self.mechanisms[mech_name]
445
+ self.insert_mechanism(mech, domain_name)
445
446
 
446
447
 
447
448
  def get_sections(self, filter_function):
@@ -493,7 +494,8 @@ class Model():
493
494
  for sec in self.sec_tree.sections:
494
495
  lambda_f = calculate_lambda_f(sec.distances, sec.diameters, sec.Ra, sec.cm, f)
495
496
  nseg = int((sec.L / (d_lambda * lambda_f) + 0.9) / 2) * 2 + 1
496
- # TODO: Set sec._nseg instead
497
+ # TODO: Set sec.nseg instead
498
+ sec._nseg = nseg
497
499
  sec._ref.nseg = nseg
498
500
  # Rebuild the segment tree
499
501
  self.seg_tree = create_segment_tree(self.sec_tree)
@@ -631,8 +633,8 @@ class Model():
631
633
 
632
634
  # Get data to transfer
633
635
  channel = self.mechanisms[channel_name]
634
- channel_domain_names = [domain_name for domain_name, mechs
635
- in self.domains_to_mechs.items() if channel_name in mechs]
636
+ channel_domain_names = [domain_name for domain_name, mech_names
637
+ in self.domains_to_mechs.items() if channel_name in mech_names]
636
638
  gbar_name = f'gbar_{channel_name}'
637
639
  gbar_distributions = self.params[gbar_name]
638
640
  # Kinetic variables cannot be transferred
@@ -709,13 +711,15 @@ class Model():
709
711
  for mech_name in self.domains_to_mechs[old_domain.name]:
710
712
  # TODO: What if section is already in domain? Can't be as
711
713
  # we use a filtered list of sections.
712
- sec.uninsert_mechanism(mech_name)
714
+ mech = self.mechanisms[mech_name]
715
+ sec.uninsert_mechanism(mech)
713
716
 
714
717
 
715
718
  for sec in sections_to_move:
716
719
  domain.add_section(sec)
717
720
  for mech_name in self.domains_to_mechs.get(domain.name, set()):
718
- sec.insert_mechanism(mech_name, distribute=distribute)
721
+ mech = self.mechanisms[mech_name]
722
+ sec.insert_mechanism(mech, distribute=distribute)
719
723
 
720
724
  self._remove_empty()
721
725
 
@@ -797,7 +801,7 @@ class Model():
797
801
  # domain.insert_mechanism(mech)
798
802
  self.domains_to_mechs[domain_name].add(mech.name)
799
803
  for sec in domain.sections:
800
- sec.insert_mechanism(mech.name)
804
+ sec.insert_mechanism(mech)
801
805
  self._add_mechanism_params(mech)
802
806
 
803
807
  # TODO: Redistribute parameters if any group contains this domain
@@ -847,7 +851,7 @@ class Model():
847
851
 
848
852
  # domain.uninsert_mechanism(mech)
849
853
  for sec in domain.sections:
850
- sec.uninsert_mechanism(mech.name)
854
+ sec.uninsert_mechanism(mech)
851
855
  self.domains_to_mechs[domain_name].remove(mech.name)
852
856
 
853
857
  if not self.mechs_to_domains.get(mech.name):
@@ -1402,7 +1406,8 @@ class Model():
1402
1406
  if mech_name == 'Leak':
1403
1407
  continue
1404
1408
  for sec in root.subtree:
1405
- sec.uninsert_mechanism(mech_name)
1409
+ mech = self.mechanisms[mech_name]
1410
+ sec.uninsert_mechanism(mech)
1406
1411
 
1407
1412
  # Disconnect
1408
1413
  root.disconnect_from_parent()
@@ -1434,7 +1439,8 @@ class Model():
1434
1439
  if mech_name == 'Leak':
1435
1440
  continue
1436
1441
  for sec in root.subtree:
1437
- sec.insert_mechanism(mech_name)
1442
+ mech = self.mechanisms[mech_name]
1443
+ sec.insert_mechanism(mech)
1438
1444
 
1439
1445
  # Replace locs with corresponding segs
1440
1446
 
@@ -1466,7 +1472,8 @@ class Model():
1466
1472
 
1467
1473
  # Reinsert active mechanisms after creating the new domain
1468
1474
  for mech_name in inserted_mechs:
1469
- root.insert_mechanism(mech_name)
1475
+ mech = self.mechanisms[mech_name]
1476
+ root.insert_mechanism(mech)
1470
1477
  self.domains_to_mechs[new_reduced_domain_name] = set(inserted_mechs.keys())
1471
1478
 
1472
1479
 
@@ -1,5 +1,5 @@
1
1
  from dendrotweaks.morphology.trees import Node, Tree
2
2
  from dendrotweaks.morphology.point_trees import Point, PointTree
3
- from dendrotweaks.morphology.sec_trees import Section, SectionTree, Domain
4
- from dendrotweaks.morphology.seg_trees import Segment, SegmentTree
3
+ from dendrotweaks.morphology.sec_trees import NeuronSection, Section, SectionTree, Domain
4
+ from dendrotweaks.morphology.seg_trees import NeuronSegment, Segment, SegmentTree
5
5
  from dendrotweaks.morphology.io.validation import validate_tree
@@ -1,7 +1,7 @@
1
1
  from dendrotweaks.morphology.trees import Node, Tree
2
2
  from dendrotweaks.morphology.point_trees import Point, PointTree
3
- from dendrotweaks.morphology.sec_trees import Section, SectionTree
4
- from dendrotweaks.morphology.seg_trees import Segment, SegmentTree
3
+ from dendrotweaks.morphology.sec_trees import NeuronSection, Section, SectionTree
4
+ from dendrotweaks.morphology.seg_trees import NeuronSegment, Segment, SegmentTree
5
5
 
6
6
  from dendrotweaks.morphology.io.reader import SWCReader
7
7
 
@@ -86,7 +86,7 @@ def _split_to_sections(point_tree: PointTree) -> List[Section]:
86
86
 
87
87
  # Assign a section to each bifurcation child
88
88
  for i, child in enumerate(bifurcation_children):
89
- section = Section(idx=i, parent_idx=-1, points=[child])
89
+ section = NeuronSection(idx=i, parent_idx=-1, points=[child])
90
90
  sections.append(section)
91
91
  child._section = section
92
92
  # Propagate the section to the children until the next
@@ -181,8 +181,8 @@ def _create_segments(sec_tree) -> List[Segment]:
181
181
  segs = {seg: idx + idx_counter for idx, seg in enumerate(sec._ref)}
182
182
  sec.segments = []
183
183
  for seg, idx in segs.items():
184
- segment = Segment(
185
- idx=idx, parent_idx=parent_idx, neuron_seg=seg, section=sec)
184
+ segment = NeuronSegment(
185
+ idx=idx, parent_idx=parent_idx, sim_seg=seg, section=sec)
186
186
  segments.append(segment)
187
187
  sec.segments.append(segment)
188
188
 
@@ -54,7 +54,9 @@ class Section(Node):
54
54
  self.points = points
55
55
  self.segments = []
56
56
  self._ref = None
57
+ self._nseg = None
57
58
  self._domain = self.points[0].domain
59
+ self._cell = None
58
60
 
59
61
  if not all(pt.domain == self._domain for pt in points):
60
62
  raise ValueError('All points in a section must belong to the same domain.')
@@ -125,105 +127,6 @@ class Section(Node):
125
127
  'parent_idx': [self.parent_idx]})
126
128
 
127
129
 
128
- # TODO: Figure out why this is different from NEURON's diam
129
- # Update: In NEURON, sec.diam returns the diameter of the segment at the center of the section
130
- # In this implementation, sec.diam returns the average diameter of the section
131
- # @property
132
- # def diam(self):
133
- # """
134
- # Average diameter of the section calculated from
135
- # the radii and distances of the points.
136
- # """
137
- # distances = self.distances # Cumulative distances
138
- # radii = self.radii # Corresponding radii
139
- # total_length = distances[-1] # Total section length
140
-
141
- # if total_length == 0:
142
- # return 0 # Avoid division by zero for zero-length sections
143
-
144
- # segment_lengths = np.diff(distances) # Lengths of frusta segments
145
- # segment_diameters = 2 * (np.array(radii[:-1]) + np.array(radii[1:])) / 2 # Mean diameter per segment
146
-
147
- # # Length-weighted average
148
- # avg_diameter = np.sum(segment_diameters * segment_lengths) / total_length
149
-
150
- # return avg_diameter
151
-
152
- @property
153
- def diam(self):
154
- """
155
- Diameter of the central segment of the section (from NEURON).
156
- """
157
- return self._ref.diam
158
-
159
-
160
- @property
161
- def L(self):
162
- """
163
- Length of the section (from NEURON).
164
- """
165
- return self._ref.L
166
-
167
-
168
- @property
169
- def cm(self):
170
- """
171
- Specific membrane capacitance of the section (from NEURON).
172
- """
173
- return self._ref.cm
174
-
175
-
176
- @property
177
- def Ra(self):
178
- """
179
- Axial resistance of the section (from NEURON).
180
- """
181
- return self._ref.Ra
182
-
183
-
184
- @property
185
- def nseg(self):
186
- """
187
- Number of segments in the section (from NEURON).
188
- """
189
- return self._ref.nseg
190
-
191
- @nseg.setter
192
- def nseg(self, value):
193
- if value < 1:
194
- raise ValueError('Number of segments must be at least 1.')
195
- if value % 2 == 0:
196
- raise ValueError('Number of segments must be odd.')
197
- # Set the number in NEURON
198
- self._ref.nseg = value
199
- # Get the new NEURON segments
200
- nrnsegs = [seg for seg in self._ref]
201
-
202
- # Create new DendroTweaks segments
203
- from dendrotweaks.morphology.seg_trees import Segment
204
- old_segments = self.segments
205
- new_segments = [Segment(idx=0, parent_idx=0, neuron_seg=seg, section=self)
206
- for seg in nrnsegs]
207
-
208
- seg_tree = self._tree._seg_tree
209
- first_segment = self.segments[0]
210
- parent = first_segment.parent
211
-
212
- for i, seg in enumerate(new_segments[:]):
213
- if i == 0:
214
- seg_tree.insert_node_before(seg, first_segment)
215
- else:
216
- seg_tree.insert_node_before(seg, new_segments[i-1])
217
-
218
- for seg in old_segments:
219
- seg_tree.remove_node(seg)
220
-
221
- # Sort the tree
222
- self._tree._seg_tree.sort()
223
- # Update the section's segments
224
- self.segments = new_segments
225
-
226
-
227
130
  @property
228
131
  def radii(self):
229
132
  """
@@ -271,8 +174,8 @@ class Section(Node):
271
174
  """
272
175
  if self._ref is None:
273
176
  raise ValueError('Section is not referenced in NEURON.')
274
- return (np.array([(2*i - 1) / (2 * self._ref.nseg)
275
- for i in range(1, self._ref.nseg + 1)]) * self._ref.L).tolist()
177
+ return (np.array([(2*i - 1) / (2 * self.nseg)
178
+ for i in range(1, self.nseg + 1)]) * self.L).tolist()
276
179
 
277
180
 
278
181
  @property
@@ -282,7 +185,7 @@ class Section(Node):
282
185
  """
283
186
  if self._ref is None:
284
187
  raise ValueError('Section is not referenced in NEURON.')
285
- nseg = int(self._ref.nseg)
188
+ nseg = int(self.nseg)
286
189
  return [i / nseg for i in range(nseg + 1)]
287
190
 
288
191
 
@@ -322,80 +225,27 @@ class Section(Node):
322
225
  areas = [np.pi * (r1 + r2) * np.sqrt((r1 - r2)**2 + h**2) for r1, r2, h in zip(self.radii[:-1], self.radii[1:], np.diff(self.distances))]
323
226
  return sum(areas)
324
227
 
325
- def has_mechanism(mech_name):
326
- """
327
- Check if the section has a mechanism inserted.
328
-
329
- Parameters
330
- ----------
331
- mech_name : str
332
- The name of the mechanism to check.
333
- """
334
- return self._ref.has_membrane(mech_name)
335
-
336
-
337
- # REFERENCING METHODS
338
-
339
- def create_and_reference(self, simulator_name='NEURON'):
340
- """
341
- Add a reference to the section in the simulator.
342
-
343
- Parameters
344
- ----------
345
- simulator_name : str
346
- The name of the simulator to create the section in.
347
- """
348
- if simulator_name == 'NEURON':
349
- self.create_NEURON_section()
350
- elif simulator_name == 'JAXLEY':
351
- self.create_JAXLEY_section()
352
-
353
-
354
- def create_NEURON_section(self):
355
- """
356
- Create a NEURON section.
357
- """
358
- self._ref = h.Section() # name=f'Sec_{self.idx}'
359
- if self.parent is not None:
360
- # TODO: Attaching basal to soma 0
361
- if self.parent.parent is None: # if parent is soma
362
- self._ref.connect(self.parent._ref(0.5))
363
- else:
364
- self._ref.connect(self.parent._ref(1))
365
- # Add 3D points to the section
366
- self._ref.pt3dclear()
367
- for pt in self.points:
368
- diam = 2*pt.r
369
- diam = round(diam, 16)
370
- self._ref.pt3dadd(pt.x, pt.y, pt.z, diam)
371
-
372
- def create_JAXLEY_section(self):
373
- """
374
- Create a JAXLEY section.
375
- """
376
- raise NotImplementedError
377
-
378
228
 
379
229
  # MECHANISM METHODS
380
230
 
381
- def insert_mechanism(self, name: str):
231
+ def insert_mechanism(self, mech):
382
232
  """
383
233
  Inserts a mechanism in the section if
384
234
  it is not already inserted.
385
235
  """
386
- if self._ref.has_membrane(name):
236
+ if self._ref.has_membrane(mech.name):
387
237
  return
388
- self._ref.insert(name)
238
+ self._ref.insert(mech.name)
389
239
 
390
240
 
391
- def uninsert_mechanism(self, name: str):
241
+ def uninsert_mechanism(self, mech):
392
242
  """
393
243
  Uninserts a mechanism in the section if
394
244
  it was inserted.
395
245
  """
396
- if not self._ref.has_membrane(name):
246
+ if not self._ref.has_membrane(mech.name):
397
247
  return
398
- self._ref.uninsert(name)
248
+ self._ref.uninsert(mech.name)
399
249
 
400
250
 
401
251
  # PARAMETER METHODS
@@ -636,7 +486,7 @@ class Section(Node):
636
486
  seg_radii = np.array([seg.diam / 2 for seg in self._ref])
637
487
 
638
488
  # Use the specified bar width calculation from original code
639
- bar_width = [self._ref.L / self._ref.nseg] * self._ref.nseg
489
+ bar_width = [self.L / self._nseg] * self._nseg
640
490
 
641
491
  # Plot segment radii as bars
642
492
  ax.bar(normalized_seg_centers, seg_radii, width=bar_width,
@@ -666,7 +516,7 @@ class Section(Node):
666
516
  parent_seg_radii = np.array([seg.diam / 2 for seg in self.parent._ref])
667
517
 
668
518
  # Use the specified bar width calculation for parent
669
- parent_bar_width = [self.parent._ref.L / self.parent._ref.nseg] * self.parent._ref.nseg
519
+ parent_bar_width = [self.parent.L / self.parent._nseg] * self.parent._nseg
670
520
 
671
521
  # Plot parent segment radii as bars
672
522
  ax.bar(normalized_parent_seg_centers, parent_seg_radii,
@@ -738,6 +588,131 @@ class Section(Node):
738
588
  return ax
739
589
 
740
590
 
591
+
592
+ # --------------------------------------------------------------
593
+ # NEURON SECTION
594
+ # --------------------------------------------------------------
595
+
596
+ class NeuronSection(Section):
597
+
598
+ def __init__(self, idx, parent_idx, points) -> None:
599
+ super().__init__(idx, parent_idx, points)
600
+
601
+ @property
602
+ def diam(self):
603
+ """
604
+ Diameter of the central segment of the section (from NEURON).
605
+ """
606
+ return self._ref.diam
607
+
608
+
609
+ @property
610
+ def L(self):
611
+ """
612
+ Length of the section (from NEURON).
613
+ """
614
+ return self._ref.L
615
+
616
+
617
+ @property
618
+ def cm(self):
619
+ """
620
+ Specific membrane capacitance of the section (from NEURON).
621
+ """
622
+ return self._ref.cm
623
+
624
+
625
+ @property
626
+ def Ra(self):
627
+ """
628
+ Axial resistance of the section (from NEURON).
629
+ """
630
+ return self._ref.Ra
631
+
632
+
633
+ def has_mechanism(mech_name):
634
+ """
635
+ Check if the section has a mechanism inserted.
636
+
637
+ Parameters
638
+ ----------
639
+ mech_name : str
640
+ The name of the mechanism to check.
641
+ """
642
+ return self._ref.has_membrane(mech_name)
643
+
644
+
645
+ @property
646
+ def nseg(self):
647
+ """
648
+ Number of segments in the section (from NEURON).
649
+ """
650
+ return self._nseg
651
+
652
+
653
+ @nseg.setter
654
+ def nseg(self, value):
655
+ if value < 1:
656
+ raise ValueError('Number of segments must be at least 1.')
657
+ if value % 2 == 0:
658
+ raise ValueError('Number of segments must be odd.')
659
+ # Set the number in NEURON
660
+ self._nseg = self._ref.nseg = value
661
+ # Get the new NEURON segments
662
+ nrnsegs = [seg for seg in self._ref]
663
+
664
+ # Create new DendroTweaks segments
665
+ from dendrotweaks.morphology.seg_trees import NeuronSegment
666
+ old_segments = self.segments
667
+ new_segments = [NeuronSegment(idx=0, parent_idx=0, sim_seg=seg, section=self)
668
+ for seg in nrnsegs]
669
+
670
+ seg_tree = self._tree._seg_tree
671
+ first_segment = self.segments[0]
672
+ parent = first_segment.parent
673
+
674
+ for i, seg in enumerate(new_segments[:]):
675
+ if i == 0:
676
+ seg_tree.insert_node_before(seg, first_segment)
677
+ else:
678
+ seg_tree.insert_node_before(seg, new_segments[i-1])
679
+
680
+ for seg in old_segments:
681
+ seg_tree.remove_node(seg)
682
+
683
+ # Sort the tree
684
+ self._tree._seg_tree.sort()
685
+ # Update the section's segments
686
+ self.segments = new_segments
687
+
688
+
689
+ # REFERENCING METHODS
690
+
691
+ def create_and_reference(self):
692
+ """
693
+ Create a NEURON section.
694
+ """
695
+ self._ref = h.Section() # name=f'Sec_{self.idx}'
696
+ self._nseg = self._ref.nseg
697
+ if self.parent is not None:
698
+ # TODO: Attaching basal to soma 0
699
+ if self.parent.parent is None: # if parent is soma
700
+ self._ref.connect(self.parent._ref(0.5))
701
+ else:
702
+ self._ref.connect(self.parent._ref(1))
703
+ # Add 3D points to the section
704
+ self._ref.pt3dclear()
705
+ for pt in self.points:
706
+ diam = 2*pt.r
707
+ diam = round(diam, 16)
708
+ self._ref.pt3dadd(pt.x, pt.y, pt.z, diam)
709
+
710
+
711
+
712
+ # ========================================================================
713
+ # SECTION TREE
714
+ # ========================================================================
715
+
741
716
  class SectionTree(Tree):
742
717
  """
743
718
  A class representing a tree graph of sections in a neuron morphology.
@@ -14,8 +14,8 @@ class Segment(Node):
14
14
  The index of the segment.
15
15
  parent_idx : int
16
16
  The index of the parent segment.
17
- neuron_seg : h.Segment
18
- The NEURON segment.
17
+ sim_seg : h.Segment
18
+ The segment object from a simulator (e.g. NEURON).
19
19
  section : Section
20
20
  The section to which the segment belongs.
21
21
 
@@ -24,13 +24,13 @@ class Segment(Node):
24
24
  _section : Section
25
25
  The section to which the segment belongs.
26
26
  _ref : h.Segment
27
- The NEURON segment.
27
+ The segment object from a simulator (e.g. NEURON).
28
28
  """
29
29
 
30
- def __init__(self, idx, parent_idx, neuron_seg, section) -> None:
30
+ def __init__(self, idx, parent_idx, sim_seg, section) -> None:
31
31
  super().__init__(idx, parent_idx)
32
32
  self._section = section
33
- self._ref = neuron_seg
33
+ self._ref = sim_seg
34
34
 
35
35
 
36
36
  # PROPERTIES
@@ -43,30 +43,6 @@ class Segment(Node):
43
43
  return self._section.domain
44
44
 
45
45
 
46
- @property
47
- def x(self):
48
- """
49
- The position of the segment along the normalized section length (from NEURON).
50
- """
51
- return self._ref.x
52
-
53
-
54
- @property
55
- def area(self):
56
- """
57
- The area of the segment (from NEURON).
58
- """
59
- return self._ref.area()
60
-
61
-
62
- @property
63
- def diam(self):
64
- """
65
- The diameter of the segment (from NEURON).
66
- """
67
- return self._ref.diam
68
-
69
-
70
46
  @property
71
47
  def subtree_size(self):
72
48
  """
@@ -137,6 +113,42 @@ class Segment(Node):
137
113
  return np.nan
138
114
 
139
115
 
116
+
117
+ # -------------------------------------------------------------------
118
+ # NEURON SEGMENT
119
+ # -------------------------------------------------------------------
120
+
121
+ class NeuronSegment(Segment):
122
+ """
123
+ A class representing a segment for the Jaxley simulator.
124
+ """
125
+
126
+ def __init__(self, idx, parent_idx, sim_seg, section) -> None:
127
+ super().__init__(idx, parent_idx, sim_seg, section)
128
+
129
+ @property
130
+ def x(self):
131
+ """
132
+ The position of the segment along the normalized section length (from NEURON).
133
+ """
134
+ return self._ref.x
135
+
136
+
137
+ @property
138
+ def area(self):
139
+ """
140
+ The area of the segment (from NEURON).
141
+ """
142
+ return self._ref.area()
143
+
144
+
145
+ @property
146
+ def diam(self):
147
+ """
148
+ The diameter of the segment (from NEURON).
149
+ """
150
+ return self._ref.diam
151
+
140
152
  class SegmentTree(Tree):
141
153
  """
142
154
  A class representing a tree graph of segments.
@@ -10,6 +10,7 @@ h.load_file('stdrun.hoc')
10
10
  # h.load_file('import3d.hoc')
11
11
  # h.load_file('nrngui.hoc')
12
12
  # h.load_file('import3d')
13
+ import numpy as np
13
14
 
14
15
  import contextlib
15
16
 
@@ -31,6 +32,10 @@ def reset_neuron():
31
32
 
32
33
  reset_neuron()
33
34
 
35
+ # -------------------------------------------------------
36
+ # SIMULATOR
37
+ # -------------------------------------------------------
38
+
34
39
  class Simulator:
35
40
  """
36
41
  A generic simulator class.
@@ -79,7 +84,7 @@ class Simulator:
79
84
 
80
85
 
81
86
 
82
- class NEURONSimulator(Simulator):
87
+ class NeuronSimulator(Simulator):
83
88
  """
84
89
  A class to represent the NEURON simulator.
85
90
 
@@ -193,18 +198,25 @@ class NEURONSimulator(Simulator):
193
198
 
194
199
 
195
200
  def _init_simulation(self):
196
- h.CVode().active(self._cvode)
201
+
197
202
  h.celsius = self.temperature
198
- h.dt = self.dt
199
- h.stdinit()
200
- h.init()
203
+
204
+ if self._cvode:
205
+ h.cvode.active(1)
206
+ else:
207
+ h.cvode.active(0)
208
+ h.dt = self.dt
209
+
201
210
  h.finitialize(self.v_init)
202
- if h.cvode.active():
211
+
212
+ if self._cvode:
203
213
  h.cvode.re_init()
204
214
  else:
205
215
  h.fcurrent()
216
+
206
217
  h.frecord_init()
207
218
 
219
+
208
220
  def run(self, duration=300):
209
221
  """
210
222
  Run a simulation.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dendrotweaks
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: A toolbox for exploring dendritic dynamics
5
5
  Home-page: https://dendrotweaks.dendrites.gr
6
6
  Author: Roman Makarov
@@ -1,15 +1,15 @@
1
- dendrotweaks/__init__.py,sha256=qmlQDMHQGSD70naZme_cEMgale9T5OH6VqjdxhznouM,384
2
- dendrotweaks/model.py,sha256=XX4WPaHPYUzm9CF4S6lUCDc_a1mORJaEbwtLexqEKCQ,68796
1
+ dendrotweaks/__init__.py,sha256=9L85_UrXGRtxCoSzemZUlzdq_FWZPX0Hjz7HUtyqepg,384
2
+ dendrotweaks/model.py,sha256=rMvS0BnqQ4ozIbM65t1jgydm5IeFo1QH0FAXEQNM-bs,69141
3
3
  dendrotweaks/model_io.py,sha256=xwXKMcUle-Y0HoWFYVZu3G8v4pdQXmeaDfl2Xi65eHw,2137
4
4
  dendrotweaks/path_manager.py,sha256=dai5o6UA0nk-ubwKWRu4LFdDBO77zW_SsMf6k0MLBiI,8703
5
- dendrotweaks/simulators.py,sha256=ADiXPqcWZ7oLQfMMnhgQNpgCW-NE6lBb5hZCQACSIkM,7237
5
+ dendrotweaks/simulators.py,sha256=Vg6ToTkDZ4OGcANYwYtamGnasyLNbyP8pfPHl9PnMnM,7413
6
6
  dendrotweaks/utils.py,sha256=jaUJNb39Bsevg3WJByP56bO7CLj1wzlh-uGZl-lxi1I,7131
7
7
  dendrotweaks/analysis/__init__.py,sha256=SEYpoQ5iXiQXyHB20-IAdDHYI-7CR5GYFXIwr-O05Ug,858
8
8
  dendrotweaks/analysis/ephys_analysis.py,sha256=Caiww27p9dnL5_27OmZ95AZ_OmefvImAPyItsJMSdmA,14320
9
9
  dendrotweaks/analysis/morphometric_analysis.py,sha256=5zohjGssyx-wezI-yY3Q-kYM_wzAQLLFBJ9Xk950_JY,3571
10
10
  dendrotweaks/biophys/__init__.py,sha256=k0o2xwyoaJUb1lfO9OHtqxheNP6R-Ya5o0g-bJOdCZg,360
11
11
  dendrotweaks/biophys/distributions.py,sha256=ADPFPA-CN7AbRJj0Ry4TxFZJhdYXJm87iIGWZSDr5vI,10299
12
- dendrotweaks/biophys/groups.py,sha256=Kze8ft8EYFXWW6zJhhbpWQUUt82L47g2IbB-5WpsWrY,3481
12
+ dendrotweaks/biophys/groups.py,sha256=Q4kBIqL1-piIgrpsVq6ojinAWHiEJ1GzMjSAQ7Ni_E8,3212
13
13
  dendrotweaks/biophys/mechanisms.py,sha256=j9uygcwkK6Z_08hpTHax40Wn-eV4V_k_on_KyPDnO90,18520
14
14
  dendrotweaks/biophys/default_mod/AMPA.mod,sha256=HY_pWzYvaSDV-w7qruenG2mnll8v79s40HFHjUCIi4U,980
15
15
  dendrotweaks/biophys/default_mod/AMPA_NMDA.mod,sha256=ztv2ePUiEQZ93-23FTkGO2DC91rehQuqo0NUIbHZ368,2318
@@ -25,21 +25,21 @@ dendrotweaks/biophys/default_templates/template_jaxley.py,sha256=t-GsCSUyQ7rDoaL
25
25
  dendrotweaks/biophys/default_templates/template_jaxley_new.py,sha256=I62KhnOYNV1bT-nPsDTxjIISYmDcso2X8rnsos28nYs,3631
26
26
  dendrotweaks/biophys/io/__init__.py,sha256=kkmQ4L0SatI3lWd3qE8KqOIKd7x3G2OnqAAW93sWWCU,575
27
27
  dendrotweaks/biophys/io/ast.py,sha256=7x_Kxz1qoQHZeIjovUNyVuKgUo4vAFKm-bd4hn9n1CI,6078
28
- dendrotweaks/biophys/io/code_generators.py,sha256=yg0Do1XLM_rIXk4i_FibJGfkWOt-GN0lq5dOCD4D3pk,11702
28
+ dendrotweaks/biophys/io/code_generators.py,sha256=RX0nw5-0CyWR3KOrTZUabKuPAQg2ysQ_nQi2iu9TxiE,11978
29
29
  dendrotweaks/biophys/io/converter.py,sha256=5yrPJhyZbuwV7tTGoacnNOvmRdVgXPIyGfiR0PyOVzg,3371
30
30
  dendrotweaks/biophys/io/factories.py,sha256=j1Hi2u-NTFFL8ElRYlgGVNHRcfKWH6o5GfKvraMTlwM,5020
31
31
  dendrotweaks/biophys/io/grammar.py,sha256=TJLTDlr8Ajp3J9DJ4IvulOCcpUkYr7HnoI0TGnNuEPc,11677
32
32
  dendrotweaks/biophys/io/loader.py,sha256=Wv9ZkEDyA3MkCdV0sMeRnBffg2WAI7yTV3r6C412GiY,6378
33
33
  dendrotweaks/biophys/io/parser.py,sha256=boT27lFrn5LYrJnkZFs0SwrZZrkSkwO8efqGPJ4Qj0I,17914
34
34
  dendrotweaks/biophys/io/reader.py,sha256=JWm5WM9illvSfDkhWEmWBcj8Y7PSi8zeZX9j1ARUHVU,6576
35
- dendrotweaks/morphology/__init__.py,sha256=aqJTQOpRVOYcbWqZ2q4e-Oy735r9_ubW-uE_5cFZVtI,323
35
+ dendrotweaks/morphology/__init__.py,sha256=JwXmSmdn9e_jqslITEdiU9kWvzxcxT9Aw_kUkXLbm5o,353
36
36
  dendrotweaks/morphology/domains.py,sha256=Y4txcGdBdl2aK1DfbTRziNtDyd6bChczwpCWE7lTFzg,2391
37
37
  dendrotweaks/morphology/point_trees.py,sha256=5dUPaQXYPdJbWoD3pFI2DV2XnuFRhB5d0wTBlfmmIeI,21600
38
- dendrotweaks/morphology/sec_trees.py,sha256=4EU8YbYsi1Pr_n7vkFuKQtIIWbJwP-8Q_epmioEXAIw,36902
39
- dendrotweaks/morphology/seg_trees.py,sha256=uwL1X9qeFNyJVHua1I3rhp0fLSRrS2TAVyb1Fnw4RwQ,3595
38
+ dendrotweaks/morphology/sec_trees.py,sha256=fj-1kBj7InkqB27Ux-jPidGQXts7FAPXa1m2LdzekNY,35816
39
+ dendrotweaks/morphology/seg_trees.py,sha256=-XeSJuD7ZixBJYQDzvmSEiNvOWbVmX_DanyAPkkR-NA,4042
40
40
  dendrotweaks/morphology/trees.py,sha256=NrNvPMR-U0clt63eqwVJqU0H8NJgY53QGA_BkdcwkQI,16033
41
41
  dendrotweaks/morphology/io/__init__.py,sha256=gAZqZdf5VKPb6ksK8Lwt7MbTAq8TDP8uq3Vs_ebNFEY,324
42
- dendrotweaks/morphology/io/factories.py,sha256=NngNINw73diGK7fud314JzWVhxv2aYLuA9wUuQA0Diw,6344
42
+ dendrotweaks/morphology/io/factories.py,sha256=DCE37QCloiYVro5HGihJbxPz91BB3y5NNf-oRaQ-M2g,6383
43
43
  dendrotweaks/morphology/io/reader.py,sha256=hW3c541WtG1rNag_YreEhvrLzm8-OTtw0fQREeHDthM,1913
44
44
  dendrotweaks/morphology/io/validation.py,sha256=lVkYw9y9yG5QpRh_N0YQ3FbZwuSUsQfSqJTMumMcDdc,7872
45
45
  dendrotweaks/morphology/reduce/__init__.py,sha256=p6Mg3KDHxTt8S4DtI0m7L7MqV6dS2pdIYAwB7B-toVw,921
@@ -49,8 +49,8 @@ dendrotweaks/stimuli/__init__.py,sha256=bFfSEZhCVpwOVEBgLe65iiY3SdpjKPhyLemC1z5O
49
49
  dendrotweaks/stimuli/iclamps.py,sha256=NjkhhwZKJR1f_g3N9BVxMVoO9ubBk5WkQ6h9Bnf9xgA,1681
50
50
  dendrotweaks/stimuli/populations.py,sha256=y85v8smiMifINIqXm1O3mOINAlDTz-SPGLS78alhX5A,8325
51
51
  dendrotweaks/stimuli/synapses.py,sha256=g4MgWTske2TZ2i9FIIOE8-KXNx_3dWa3zEhB2rcqYig,5470
52
- dendrotweaks-0.4.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
53
- dendrotweaks-0.4.0.dist-info/METADATA,sha256=9AAcxk2ZzIvqUOQg7hNf0Tw1an2EYJLl76gSI21WAKM,2740
54
- dendrotweaks-0.4.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
55
- dendrotweaks-0.4.0.dist-info/top_level.txt,sha256=OzT_2BSI5j5zxC447K6Y-0W-GHbued7iX-_hFGAKMxY,13
56
- dendrotweaks-0.4.0.dist-info/RECORD,,
52
+ dendrotweaks-0.4.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
53
+ dendrotweaks-0.4.2.dist-info/METADATA,sha256=RHDsvzirnDTlrF2wl4IqLgSLw-40UOJ8_VfNtoezyYw,2740
54
+ dendrotweaks-0.4.2.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
55
+ dendrotweaks-0.4.2.dist-info/top_level.txt,sha256=OzT_2BSI5j5zxC447K6Y-0W-GHbued7iX-_hFGAKMxY,13
56
+ dendrotweaks-0.4.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.1)
2
+ Generator: setuptools (80.7.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5