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,155 @@
1
+ """
2
+ This module contains functions for reducing dendritic subtrees into single cylinders.
3
+ The module incorporates code from neuron_reduce, which implements the algorithm described in:
4
+ Amsalem, O., Eyal, G., Rogozinski, N. et al. An efficient analytical reduction of detailed nonlinear neuron models. Nat Commun 11, 288 (2020). https://doi.org/10.1038/s41467-019-13932-6
5
+ The original code can be found at: https://github.com/orena1/neuron_reduce. Licensed under MIT License.
6
+ """
7
+
8
+ import neuron
9
+ from neuron import h
10
+
11
+ import math
12
+ import cmath
13
+ import collections
14
+ import numpy as np
15
+
16
+ from neuron_reduce.reducing_methods import push_section
17
+ from neuron_reduce.reducing_methods import measure_input_impedance_of_subtree
18
+ from neuron_reduce.reducing_methods import find_best_real_X
19
+
20
+ EXCLUDE_MECHANISMS = ['Leak', 'na_ion', 'k_ion', 'ca_ion', 'h_ion']
21
+
22
+
23
+ def map_segs_to_params(root, mechanisms):
24
+ segs_to_params = {}
25
+ for sec in root.subtree:
26
+ for seg in sec:
27
+ segs_to_params[seg] = {}
28
+ for mech_name, mech in mechanisms.items():
29
+ if mech_name in EXCLUDE_MECHANISMS:
30
+ continue
31
+ segs_to_params[seg][mech_name] = {}
32
+ for param_name in mech.range_params_with_suffix:
33
+ segs_to_params[seg][mech_name][param_name] = seg.get_param_value(param_name)
34
+ return segs_to_params
35
+
36
+
37
+ def map_segs_to_locs(root, reduction_frequency, new_cable_properties):
38
+ """Maps segment names of the original subtree
39
+ to their new locations in the reduced cylinder.
40
+
41
+ This dictionary is used later to restore
42
+ the active conductances in the reduced cylinder.
43
+ """
44
+ segs_to_locs = {}
45
+
46
+ imp_obj, subtree_input_impedance = measure_input_impedance_of_subtree(root._ref,
47
+ reduction_frequency)
48
+ subtree_q = calculate_subtree_q(root._ref, reduction_frequency)
49
+
50
+ for sec in root.subtree:
51
+ for seg in sec:
52
+
53
+ mid_of_segment_loc = reduce_segment(seg._ref,
54
+ imp_obj,
55
+ subtree_input_impedance,
56
+ new_cable_properties.electrotonic_length,
57
+ subtree_q)
58
+
59
+ segs_to_locs[seg] = mid_of_segment_loc
60
+
61
+ return segs_to_locs
62
+
63
+
64
+ def calculate_subtree_q(root, reduction_frequency):
65
+ rm = 1.0 / root.gbar_Leak
66
+ rc = rm * (float(root.cm) / 1000000)
67
+ angular_freq = 2 * math.pi * reduction_frequency
68
+ q_imaginary = angular_freq * rc
69
+ q_subtree = complex(1, q_imaginary) # q=1+iwRC
70
+ q_subtree = cmath.sqrt(q_subtree)
71
+ return q_subtree
72
+
73
+
74
+ def reduce_segment(seg,
75
+ imp_obj,
76
+ root_input_impedance,
77
+ new_cable_electrotonic_length,
78
+ subtree_q):
79
+
80
+ sec = seg.sec
81
+
82
+ with push_section(sec):
83
+ orig_transfer_imp = imp_obj.transfer(seg.x) * 1000000 # ohms
84
+ orig_transfer_phase = imp_obj.transfer_phase(seg.x)
85
+ # creates a complex Impedance value with the given polar coordinates
86
+ orig_transfer_impedance = cmath.rect(
87
+ orig_transfer_imp, orig_transfer_phase)
88
+
89
+ new_electrotonic_location = find_best_real_X(root_input_impedance,
90
+ orig_transfer_impedance,
91
+ subtree_q,
92
+ new_cable_electrotonic_length)
93
+ new_relative_loc_in_section = (float(new_electrotonic_location) /
94
+ new_cable_electrotonic_length)
95
+
96
+ if new_relative_loc_in_section > 1: # PATCH
97
+ new_relative_loc_in_section = 0.999999
98
+
99
+ return new_relative_loc_in_section
100
+
101
+
102
+ def map_segs_to_reduced_segs(seg_to_locs, root):
103
+ """Replaces the locations (x values)
104
+ with the corresponding segments of the reduced cylinder i.e. sec(x).
105
+ """
106
+ locs_to_reduced_segs = {loc: root(loc)
107
+ for loc in seg_to_locs.values()}
108
+ segs_to_reduced_segs = {seg: locs_to_reduced_segs[loc]
109
+ for seg, loc in seg_to_locs.items()}
110
+ return segs_to_reduced_segs
111
+
112
+
113
+ def map_reduced_segs_to_params(segs_to_reduced_segs, segs_to_params):
114
+ reduced_segs_to_params = {}
115
+ for seg, reduced_seg in segs_to_reduced_segs.items():
116
+ if reduced_seg not in reduced_segs_to_params:
117
+ reduced_segs_to_params[reduced_seg] = collections.defaultdict(list)
118
+ for mech_name, mech_params in segs_to_params[seg].items():
119
+ for param_name, param_value in mech_params.items():
120
+ reduced_segs_to_params[reduced_seg][param_name].append(param_value)
121
+ return reduced_segs_to_params
122
+
123
+
124
+ def set_avg_params_to_reduced_segs(reduced_segs_to_params):
125
+ for reduced_seg, params in reduced_segs_to_params.items():
126
+ for param_name, param_values in params.items():
127
+ value = np.mean(param_values)
128
+ reduced_seg.set_param_value(param_name, value)
129
+
130
+
131
+ def interpolate_missing_values(reduced_segs_to_params, root):
132
+
133
+ non_mapped_segs = [seg for seg in root.segments
134
+ if seg not in reduced_segs_to_params]
135
+
136
+ xs = np.array([seg.x for seg in root.segments])
137
+
138
+ non_mapped_indices = np.where([seg in non_mapped_segs for seg in root.segments])[0]
139
+ mapped_indices = np.where([seg not in non_mapped_segs for seg in root.segments])[0]
140
+
141
+ print(f'Interpolated for ids {non_mapped_indices}')
142
+
143
+ for param in list(set([k for val in reduced_segs_to_params.values() for k in val.keys()])):
144
+ values = np.array([seg.get_param_value(param) for seg in root.segments])
145
+ if np.any(values != 0.) and np.any(values == 0.):
146
+ # Find the indices where param value is zero
147
+ # zero_indices = np.where(values == 0)[0]
148
+ # Interpolate the values for these indices
149
+ # values[zero_indices] = np.interp(xs[zero_indices], xs[values != 0], values[values != 0], left=0, right=0)
150
+ values[non_mapped_indices] = np.interp(xs[non_mapped_indices], xs[mapped_indices], values[mapped_indices], left=0, right=0)
151
+ print(f' {param} values: {values}')
152
+ # Set the values
153
+ for x, value in zip(xs, values):
154
+ seg = root(x)
155
+ seg.set_param_value(param, value)
@@ -0,0 +1,129 @@
1
+ """
2
+ This module contains functions for reducing dendritic subtrees into single cylinders.
3
+ The module incorporates code from neuron_reduce, which implements the algorithm described in:
4
+ Amsalem, O., Eyal, G., Rogozinski, N. et al. An efficient analytical reduction of detailed nonlinear neuron models. Nat Commun 11, 288 (2020). https://doi.org/10.1038/s41467-019-13932-6
5
+ The original code can be found at: https://github.com/orena1/neuron_reduce. Licensed under MIT License.
6
+ """
7
+
8
+
9
+ import math
10
+ import cmath
11
+
12
+ from neuron_reduce.subtree_reductor_func import calculate_nsegs_from_lambda, calculate_nsegs_from_manual_arg
13
+
14
+ def apply_params_to_section(section: "Section", cable_params: "CableParams", nseg: int):
15
+ '''Apply new cable parameters to the given section in the model'''
16
+ # Geometry
17
+ section._ref.L = cable_params.length
18
+ section._ref.diam = cable_params.diam
19
+ # Segmentation
20
+ section.nseg = nseg
21
+ # Passive properties
22
+ section._ref.cm = cable_params.cm
23
+ section._ref.Ra = cable_params.ra
24
+ section._ref.gbar_Leak = 1.0 / cable_params.rm
25
+ section._ref.e_Leak = cable_params.e_pas
26
+ remove_intermediate_points(section)
27
+ update_section_geometry(section)
28
+
29
+
30
+ def remove_intermediate_points(sec: "Section") -> None:
31
+ '''Removes all intermediate points in the section, keeping only start and end points'''
32
+ point_tree = sec._tree._point_tree
33
+
34
+ first_point, *intermediate_points, last_point = sec.points
35
+
36
+ for point in intermediate_points:
37
+ point_tree.remove_node(point)
38
+
39
+ point_tree.sort()
40
+ sec.points = [first_point, last_point]
41
+
42
+
43
+ def update_section_geometry(sec: "Section"):
44
+ '''Updates section geometry by adjusting the end point to maintain section length and direction'''
45
+ length = sec.L
46
+
47
+ if len(sec.points) != 2:
48
+ raise ValueError("Section must have only two points (the start and end points)")
49
+
50
+ first_point, last_point = sec.points
51
+
52
+ # Calculate the vector from first to last point
53
+ vector = (
54
+ last_point.x - first_point.x,
55
+ last_point.y - first_point.y,
56
+ last_point.z - first_point.z
57
+ )
58
+
59
+ # Calculate the current distance
60
+ distance = math.sqrt(sum(component**2 for component in vector))
61
+
62
+ # Scale the vector to match the desired length
63
+ scale = length / distance
64
+
65
+ # Update last point coordinates
66
+ last_point.x = first_point.x + vector[0] * scale
67
+ last_point.y = first_point.y + vector[1] * scale
68
+ last_point.z = first_point.z + vector[2] * scale
69
+
70
+ # Set radius for all points
71
+ radius = round(sec.diam / 2, 3)
72
+ for point in sec.points:
73
+ point.r = radius
74
+
75
+
76
+ def _get_subtree_biophysical_properties(subtree_root_ref, frequency):
77
+ ''' gets the biophysical cable properties (Rm, Ra, Rc) and q
78
+ for the subtree to be reduced according to the properties of the root section of the subtree
79
+ '''
80
+ section = subtree_root_ref.sec
81
+
82
+ rm = 1.0 / section.gbar_Leak # in ohm * cm^2
83
+ # in secs, with conversion of the capacitance from uF/cm2 to F/cm2
84
+ RC = rm * (float(section.cm) / 1000000)
85
+
86
+ # defining q=sqrt(1+iwRC))
87
+ angular_freq = 2 * math.pi * frequency # = w
88
+ q_imaginary = angular_freq * RC
89
+ q = complex(1, q_imaginary) # q=1+iwRC
90
+ q = cmath.sqrt(q) # q = sqrt(1+iwRC)
91
+
92
+ return (section.cm,
93
+ rm,
94
+ section.Ra, # in ohm * cm
95
+ section.e_Leak,
96
+ q)
97
+
98
+
99
+ def calculate_nsegs(new_cable_properties, total_segments_manual):
100
+
101
+ new_cable_properties = [new_cable_properties]
102
+
103
+ if total_segments_manual > 1:
104
+ print('the number of segments in the reduced model will be set to `total_segments_manual`')
105
+ new_cables_nsegs = calculate_nsegs_from_manual_arg(new_cable_properties,
106
+ total_segments_manual)
107
+ else:
108
+ new_cables_nsegs = calculate_nsegs_from_lambda(new_cable_properties)
109
+ if total_segments_manual > 0:
110
+ print('from lambda')
111
+ original_cell_seg_n = (sum(i.nseg for i in list(original_cell.basal)) +
112
+ sum(i.nseg for i in list(
113
+ original_cell.apical))
114
+ )
115
+ min_reduced_seg_n = int(
116
+ round((total_segments_manual * original_cell_seg_n)))
117
+ if sum(new_cables_nsegs) < min_reduced_seg_n:
118
+ logger.debug(f"number of segments calculated using lambda is {sum(new_cables_nsegs)}, "
119
+ "the original cell had {original_cell_seg_n} segments. "
120
+ "The min reduced segments is set to {total_segments_manual * 100}% of reduced cell segments")
121
+ logger.debug("the reduced cell nseg is set to %s" %
122
+ min_reduced_seg_n)
123
+ new_cables_nsegs = calculate_nsegs_from_manual_arg(new_cable_properties,
124
+ min_reduced_seg_n)
125
+ else:
126
+ # print('Automatic segmentation')
127
+ pass
128
+
129
+ return new_cables_nsegs[0]