dendrotweaks 0.4.0__py3-none-any.whl → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
- __version__ = "0.4.0"
1
+ __version__ = "0.4.1"
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):
@@ -631,8 +632,8 @@ class Model():
631
632
 
632
633
  # Get data to transfer
633
634
  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]
635
+ channel_domain_names = [domain_name for domain_name, mech_names
636
+ in self.domains_to_mechs.items() if channel_name in mech_names]
636
637
  gbar_name = f'gbar_{channel_name}'
637
638
  gbar_distributions = self.params[gbar_name]
638
639
  # Kinetic variables cannot be transferred
@@ -709,13 +710,15 @@ class Model():
709
710
  for mech_name in self.domains_to_mechs[old_domain.name]:
710
711
  # TODO: What if section is already in domain? Can't be as
711
712
  # we use a filtered list of sections.
712
- sec.uninsert_mechanism(mech_name)
713
+ mech = self.mechanisms[mech_name]
714
+ sec.uninsert_mechanism(mech)
713
715
 
714
716
 
715
717
  for sec in sections_to_move:
716
718
  domain.add_section(sec)
717
719
  for mech_name in self.domains_to_mechs.get(domain.name, set()):
718
- sec.insert_mechanism(mech_name, distribute=distribute)
720
+ mech = self.mechanisms[mech_name]
721
+ sec.insert_mechanism(mech, distribute=distribute)
719
722
 
720
723
  self._remove_empty()
721
724
 
@@ -797,7 +800,7 @@ class Model():
797
800
  # domain.insert_mechanism(mech)
798
801
  self.domains_to_mechs[domain_name].add(mech.name)
799
802
  for sec in domain.sections:
800
- sec.insert_mechanism(mech.name)
803
+ sec.insert_mechanism(mech)
801
804
  self._add_mechanism_params(mech)
802
805
 
803
806
  # TODO: Redistribute parameters if any group contains this domain
@@ -847,7 +850,7 @@ class Model():
847
850
 
848
851
  # domain.uninsert_mechanism(mech)
849
852
  for sec in domain.sections:
850
- sec.uninsert_mechanism(mech.name)
853
+ sec.uninsert_mechanism(mech)
851
854
  self.domains_to_mechs[domain_name].remove(mech.name)
852
855
 
853
856
  if not self.mechs_to_domains.get(mech.name):
@@ -1402,7 +1405,8 @@ class Model():
1402
1405
  if mech_name == 'Leak':
1403
1406
  continue
1404
1407
  for sec in root.subtree:
1405
- sec.uninsert_mechanism(mech_name)
1408
+ mech = self.mechanisms[mech_name]
1409
+ sec.uninsert_mechanism(mech)
1406
1410
 
1407
1411
  # Disconnect
1408
1412
  root.disconnect_from_parent()
@@ -1434,7 +1438,8 @@ class Model():
1434
1438
  if mech_name == 'Leak':
1435
1439
  continue
1436
1440
  for sec in root.subtree:
1437
- sec.insert_mechanism(mech_name)
1441
+ mech = self.mechanisms[mech_name]
1442
+ sec.insert_mechanism(mech)
1438
1443
 
1439
1444
  # Replace locs with corresponding segs
1440
1445
 
@@ -1466,7 +1471,8 @@ class Model():
1466
1471
 
1467
1472
  # Reinsert active mechanisms after creating the new domain
1468
1473
  for mech_name in inserted_mechs:
1469
- root.insert_mechanism(mech_name)
1474
+ mech = self.mechanisms[mech_name]
1475
+ root.insert_mechanism(mech)
1470
1476
  self.domains_to_mechs[new_reduced_domain_name] = set(inserted_mechs.keys())
1471
1477
 
1472
1478
 
@@ -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.1
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=t5t6BzFqY45ePdil4bFlkEaQZiKS-KKthacbRUkwDhc,384
2
+ dendrotweaks/model.py,sha256=Y6m9U0FOoMYG3qCLZczxYfl1-nXeL-4uZNuAqrDlwPQ,69113
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.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
53
+ dendrotweaks-0.4.1.dist-info/METADATA,sha256=zX87vndTAiJHfWJkywrmMiqa7lNxcg4Kwfbf6tQ0OKs,2740
54
+ dendrotweaks-0.4.1.dist-info/WHEEL,sha256=A8Eltl-h0W-qZDVezsLjjslosEH_pdYC2lQ0JcbgCzs,91
55
+ dendrotweaks-0.4.1.dist-info/top_level.txt,sha256=OzT_2BSI5j5zxC447K6Y-0W-GHbued7iX-_hFGAKMxY,13
56
+ dendrotweaks-0.4.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.1)
2
+ Generator: setuptools (80.7.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5