From e72bace8c5fd3beaec18b7616207197f3d63eebd Mon Sep 17 00:00:00 2001 From: Jannik Luboeinski Date: Sat, 14 Oct 2023 17:01:18 +0200 Subject: [PATCH] split function 'get_morph_and_decor()' into special cases for 1,2,3 segments --- python/test/unit/test_diffusion.py | 310 +++++++++++++++++------------ 1 file changed, 178 insertions(+), 132 deletions(-) diff --git a/python/test/unit/test_diffusion.py b/python/test/unit/test_diffusion.py index 5dae55ef36..91584c1a2f 100644 --- a/python/test/unit/test_diffusion.py +++ b/python/test/unit/test_diffusion.py @@ -95,130 +95,166 @@ def __init__(self, args): self.dt = 0.01 # duration of one timestep in ms self.dev = 0.01 # accepted relative deviation for `assertAlmostEqual` - # get_morph_and_decor - # Method that sets up and returns a morphology and decoration for given parameters - # - num_segs: number of segments (1, 2, or 3; in the case of 1 or 2, there'll be one branch, in the case of 3, there'll be three branches) + # get_morph_and_decor_1_seg + # Method that sets up and returns a morphology and decoration for one segment with the given parameters + # (one segment => there'll be one branch) # - num_cvs_per_seg: number of CVs per segment - # - l_1: axial length of the first segment in µm - # - l_2: axial length of the second segment in µm - # - l_3: axial length of the third segment in µm + # - length_1: axial length of the first segment in µm + # - radius_1: radius of the first segment in µm + def get_morph_and_decor_1_seg(self, num_cvs_per_seg, length_1, radius_1): + # --------------------------------------------------------------------------------------- + # set up the morphology + tree = A.segment_tree() + _ = tree.append( + A.mnpos, + A.mpoint(-length_1, 0, 0, radius_1), + A.mpoint(0, 0, 0, radius_1), + tag=0, + ) + labels = A.label_dict( + { + "soma-region": "(tag 0)", + "soma-start": '(on-components 0.0 (region "soma-region"))', + "soma-center": '(on-components 0.5 (region "soma-region"))', + "soma-end": '(on-components 1.0 (region "soma-region"))', + } + ) + morph = A.morphology(tree) + + # --------------------------------------------------------------------------------------- + # decorate the morphology with mechanisms + dec = A.decor() + dec.discretization( + A.cv_policy(f"(fixed-per-branch {num_cvs_per_seg})") + ) # use 'fixed-per-branch' policy to obtain exact number of CVs; there's one branch here + dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_exc_A") + dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_exc_B") + dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_inh") + dec.paint("(all)", A.density("neuron_with_diffusion")) + + return morph, dec, labels + + # get_morph_and_decor_2_seg + # Method that sets up and returns a morphology and decoration for two segments with the given parameters + # (two segments => there'll be one branch) + # - num_cvs_per_seg: number of CVs per segment + # - length_1: axial length of the first segment in µm + # - length_2: axial length of the second segment in µm # - radius_1: radius of the first segment in µm # - radius_2: radius of the second segment in µm - # - radius_3: radius of the third segment in µm - def get_morph_and_decor( - self, num_segs, num_cvs_per_seg, l_1, l_2, l_3, radius_1, radius_2, radius_3 + def get_morph_and_decor_2_seg( + self, num_cvs_per_seg, length_1, length_2, radius_1, radius_2 ): # --------------------------------------------------------------------------------------- # set up the morphology tree = A.segment_tree() - if num_segs == 1: - _ = tree.append( - A.mnpos, - A.mpoint(-l_1, 0, 0, radius_1), - A.mpoint(0, 0, 0, radius_1), - tag=0, - ) + s = tree.append( + A.mnpos, + A.mpoint(-length_1, 0, 0, radius_1), + A.mpoint(0, 0, 0, radius_1), + tag=0, + ) + _ = tree.append( + s, + A.mpoint(0, 0, 0, radius_2), + A.mpoint(+length_2, 0, 0, radius_2), + tag=1, + ) + labels = A.label_dict( + { + "soma-region": "(tag 0)", + "dendriteA-region": "(tag 1)", + "soma-start": '(on-components 0.0 (region "soma-region"))', + "soma-center": '(on-components 0.5 (region "soma-region"))', + "soma-end": '(on-components 1.0 (region "soma-region"))', + "dendriteA-center": '(on-components 0.5 (region "dendriteA-region"))', + } + ) + morph = A.morphology(tree) - labels = A.label_dict( - { - "soma-region": "(tag 0)", - "soma-start": '(on-components 0.0 (region "soma-region"))', - "soma-center": '(on-components 0.5 (region "soma-region"))', - "soma-end": '(on-components 1.0 (region "soma-region"))', - } - ) - elif num_segs == 2: - s = tree.append( - A.mnpos, - A.mpoint(-l_1, 0, 0, radius_1), - A.mpoint(0, 0, 0, radius_1), - tag=0, - ) - _ = tree.append( - s, - A.mpoint(0, 0, 0, radius_2), - A.mpoint(+l_2, 0, 0, radius_2), - tag=1, - ) + # --------------------------------------------------------------------------------------- + # decorate the morphology with mechanisms + dec = A.decor() + dec.discretization( + A.cv_policy(f"(fixed-per-branch {2*num_cvs_per_seg})") + ) # use 'fixed-per-branch' policy to obtain exact number of CVs; there's one branch here + dec.place( + '"dendriteA-center"', A.synapse("synapse_with_diffusion"), "syn_exc_A" + ) + dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_exc_B") + dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_inh") + dec.paint("(all)", A.density("neuron_with_diffusion")) - labels = A.label_dict( - { - "soma-region": "(tag 0)", - "dendriteA-region": "(tag 1)", - "soma-start": '(on-components 0.0 (region "soma-region"))', - "soma-center": '(on-components 0.5 (region "soma-region"))', - "soma-end": '(on-components 1.0 (region "soma-region"))', - "dendriteA-center": '(on-components 0.5 (region "dendriteA-region"))', - } - ) - elif num_segs == 3: - s = tree.append( - A.mnpos, - A.mpoint(-l_1, 0, 0, radius_1), - A.mpoint(0, 0, 0, radius_1), - tag=0, - ) - _ = tree.append( - s, - A.mpoint(0, 0, 0, radius_2), - A.mpoint(+l_2, 0, 0, radius_2), - tag=1, - ) - _ = tree.append( - s, - A.mpoint(0, 0, 0, radius_3), - A.mpoint(+l_3, 0, 0, radius_3), - tag=2, - ) + return morph, dec, labels - labels = A.label_dict( - { - "soma-region": "(tag 0)", - "dendriteA-region": "(tag 1)", - "dendriteB-region": "(tag 2)", - "soma-start": '(on-components 0.0 (region "soma-region"))', - "soma-center": '(on-components 0.5 (region "soma-region"))', - "soma-end": '(on-components 1.0 (region "soma-region"))', - "dendriteA-center": '(on-components 0.5 (region "dendriteA-region"))', - "dendriteB-center": '(on-components 0.5 (region "dendriteB-region"))', - } - ) - else: - raise ValueError( - f"Specified number of segments ({num_segs}) not supported." - ) + # get_morph_and_decor_3_seg + # Method that sets up and returns a morphology and decoration for three segments with the given parameters + # (three segments => there'll be three branches) + # - num_cvs_per_seg: number of CVs per segment + # - length_1: axial length of the first segment in µm + # - length_2: axial length of the second segment in µm + # - length_3: axial length of the third segment in µm + # - radius_1: radius of the first segment in µm + # - radius_2: radius of the second segment in µm + # - radius_3: radius of the third segment in µm + def get_morph_and_decor_3_seg( + self, + num_cvs_per_seg, + length_1, + length_2, + length_3, + radius_1, + radius_2, + radius_3, + ): + # --------------------------------------------------------------------------------------- + # set up the morphology + tree = A.segment_tree() + s = tree.append( + A.mnpos, + A.mpoint(-length_1, 0, 0, radius_1), + A.mpoint(0, 0, 0, radius_1), + tag=0, + ) + _ = tree.append( + s, + A.mpoint(0, 0, 0, radius_2), + A.mpoint(+length_2, 0, 0, radius_2), + tag=1, + ) + _ = tree.append( + s, + A.mpoint(0, 0, 0, radius_3), + A.mpoint(+length_3, 0, 0, radius_3), + tag=2, + ) + labels = A.label_dict( + { + "soma-region": "(tag 0)", + "dendriteA-region": "(tag 1)", + "dendriteB-region": "(tag 2)", + "soma-start": '(on-components 0.0 (region "soma-region"))', + "soma-center": '(on-components 0.5 (region "soma-region"))', + "soma-end": '(on-components 1.0 (region "soma-region"))', + "dendriteA-center": '(on-components 0.5 (region "dendriteA-region"))', + "dendriteB-center": '(on-components 0.5 (region "dendriteB-region"))', + } + ) morph = A.morphology(tree) # --------------------------------------------------------------------------------------- # decorate the morphology with mechanisms dec = A.decor() - if num_segs == 1: - dec.discretization( - A.cv_policy(f"(fixed-per-branch {num_segs*num_cvs_per_seg})") - ) # there is only branch here, use 'fixed-per-branch' policy to obtain exact number of CVs - dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_exc_A") - dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_exc_B") - dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_inh") - elif num_segs == 2: - dec.discretization( - A.cv_policy(f"(fixed-per-branch {num_segs*num_cvs_per_seg})") - ) # there is only branch here, use 'fixed-per-branch' policy to obtain exact number of CVs - dec.place( - '"dendriteA-center"', A.synapse("synapse_with_diffusion"), "syn_exc_A" - ) - dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_exc_B") - dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_inh") - elif num_segs == 3: - dec.discretization( - A.cv_policy(f"(fixed-per-branch {num_cvs_per_seg})") - ) # there are three branches here, use 'fixed-per-branch' policy to obtain exact number of CVs - dec.place( - '"dendriteA-center"', A.synapse("synapse_with_diffusion"), "syn_exc_A" - ) - dec.place( - '"dendriteB-center"', A.synapse("synapse_with_diffusion"), "syn_exc_B" - ) - dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_inh") + dec.discretization( + A.cv_policy(f"(fixed-per-branch {num_cvs_per_seg})") + ) # use 'fixed-per-branch' policy to obtain exact number of CVs; there are three branches here + dec.place( + '"dendriteA-center"', A.synapse("synapse_with_diffusion"), "syn_exc_A" + ) + dec.place( + '"dendriteB-center"', A.synapse("synapse_with_diffusion"), "syn_exc_B" + ) + dec.place('"soma-end"', A.synapse("synapse_with_diffusion"), "syn_inh") dec.paint("(all)", A.density("neuron_with_diffusion")) return morph, dec, labels @@ -248,43 +284,53 @@ def simulate_and_test_diffusion( r_3=4.0, ): # --------------------------------------------------------------------------------------- - # set parameters and calculate geometrical measures + # set parameters + inject_remove = [ + {"time": 0.1, "synapse": "syn_exc_A", "change": 600}, + {"time": 0.5, "synapse": "syn_exc_B", "change": 1200}, + {"time": 1.5, "synapse": "syn_inh", "change": -1400}, + ] # changes in particle amount (in 1e-18 mol) + diffusivity = 1 # diffusivity (in m^2/s) + + # --------------------------------------------------------------------------------------- + # get morphology, decoration, and labels, and calculate geometrical measures if num_segs == 1: r_2 = l_2 = 0 # set radius and length of second segment to zero r_3 = l_3 = 0 # set radius and length of third segment to zero + morph, dec, labels = self.get_morph_and_decor_1_seg( + num_cvs_per_seg, l_1, r_1 + ) # get morphology, decoration, and labels length_soma_cv = ( l_1 / num_cvs_per_seg - ) # consider 'fixed-per-branch' policy for one segment that forms one branch + ) # consider 'fixed-per-branch' policy for one segment, which forms one branch elif num_segs == 2: r_3 = l_3 = 0 # set radius and length of third segment to zero + morph, dec, labels = self.get_morph_and_decor_2_seg( + num_cvs_per_seg, l_1, l_2, r_1, r_2 + ) # get morphology, decoration, and labels length_soma_cv = (l_1 + l_2) / ( 2 * num_cvs_per_seg - ) # consider 'fixed-per-branch' policy for two segments that still only form one branch - else: + ) # consider 'fixed-per-branch' policy for two segments, which only form one branch + elif num_segs == 3: + morph, dec, labels = self.get_morph_and_decor_3_seg( + num_cvs_per_seg, l_1, l_2, l_3, r_1, r_2, r_3 + ) # get morphology, decoration, and labels length_soma_cv = ( l_1 / num_cvs_per_seg - ) # consider 'fixed-per-branch' policy for three segments which form three branches - - volume_tot = np.pi * ( - r_1**2 * l_1 + r_2**2 * l_2 + r_3**2 * l_3 - ) # volume of the whole setup in µm^3 + ) # consider 'fixed-per-branch' policy for three segments, which form three branches + else: + raise ValueError( + f"Specified number of segments ({num_segs}) not supported." + ) volume_soma_cv = np.pi * ( r_1**2 * length_soma_cv ) # volume of one cylindrical CV of the first segment in µm^3 - - inject_remove = [ - {"time": 0.1, "synapse": "syn_exc_A", "change": 600}, - {"time": 0.5, "synapse": "syn_exc_B", "change": 1200}, - {"time": 1.5, "synapse": "syn_inh", "change": -1400}, - ] # changes in particle amount (in 1e-18 mol) - diffusivity = 1 # diffusivity (in m^2/s) - # print(f"Testing l_1={l_1}, l_2={l_2}, l_3={l_3}, r_1={r_1}, r_2={r_2}, r_3={r_3}") + volume_tot = np.pi * ( + r_1**2 * l_1 + r_2**2 * l_2 + r_3**2 * l_3 + ) # volume of the whole setup in µm^3 # --------------------------------------------------------------------------------------- - # get morphology, decoration, and labels, and add the diffusive particle species 's' - morph, dec, labels = self.get_morph_and_decor( - num_segs, num_cvs_per_seg, l_1, l_2, l_3, r_1, r_2, r_3 - ) + # add the diffusive particle species 's' dec.set_ion("s", int_con=0.0, diff=diffusivity) # --------------------------------------------------------------------------------------- @@ -392,8 +438,7 @@ def test_diffusion_equal_radii(self, diffusion_catalogue): diffusion_catalogue, 3, 50, l_1=5, l_2=5, l_3=5, r_1=4, r_2=4, r_3=4 ) # 3 segments with radius 4 µm - """ TODO: not succeeding as of Arbor v0.9.0: """ - + """ TODO: not succeeding as of Arbor v0.9.0: # test_diffusion_different_length # Test: simulations with segments of different length but equal radius # - diffusion_catalogue: catalogue of diffusion mechanisms @@ -420,3 +465,4 @@ def test_diffusion_different_radii(self, diffusion_catalogue): self.simulate_and_test_diffusion( diffusion_catalogue, 3, 50, l_1=5, l_2=5, l_3=5, r_1=4, r_2=6, r_3=6 ) # 3 segments with radius 4 µm and 6 µm + """