Ejemplo n.º 1
0
    def setup_network(self, neurons_path, num_replicas=10, neuron_types=None):

        # TODO: num_replicas should be set by a parameter, it affects how many duplicates of each neuron
        # and thus how many steps we have between n_min and n_max number of inputs specified.
        config_def = self.create_network_config(neurons_path=neurons_path,
                                                num_replicas=num_replicas,
                                                neuron_types=neuron_types)

        print(
            f"Writing network config file to {self.network_config_file_name}")
        with open(self.network_config_file_name, "w") as f:
            json.dump(config_def, f, indent=2, cls=NumpyEncoder)

        create_cube_mesh(os.path.join("data", "mesh", "InputTestMesh.obj"),
                         [0, 0, 0],
                         1e-3,
                         description="Mesh file used for Input Scaling")

        # Write the neurons path to file
        self.write_tuning_info()

        from snudda.place.place import SnuddaPlace
        from snudda.detect.detect import SnuddaDetect
        from snudda.detect.prune import SnuddaPrune

        sp = SnuddaPlace(network_path=self.network_path)
        sp.parse_config()
        sp.write_data()

        sd = SnuddaDetect(network_path=self.network_path)
        sd.detect()

        sp = SnuddaPrune(network_path=self.network_path)
        sp.prune()
Ejemplo n.º 2
0
    def setUp(self):

        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))

        network_path = os.path.join(os.path.dirname(__file__), "networks", "network_testing_detect")

        create_cube_mesh(file_name=os.path.join(network_path, "mesh", "simple_mesh.obj"),
                         centre_point=(0, 0, 0),
                         side_len=500e-6)

        config_file = os.path.join(network_path, "network-config.json")
        position_file = os.path.join(network_path, "network-neuron-positions.hdf5")
        save_file = os.path.join(network_path, "voxels", "network-putative-synapses.hdf5")

        #  TODO: If d_view is None code run sin serial, add test parallel
        sp = SnuddaPlace(config_file=config_file, d_view=None, verbose=True)

        sp.parse_config()
        sp.write_data(position_file)

        # We want to load in the ball and stick neuron that has 20 micrometer soma diameter, and axon (along y-axis),
        # and dendrite along (x-axis) out to 100 micrometer distance from centre of soma.

        self.sd = SnuddaDetect(config_file=config_file, position_file=position_file,
                               save_file=save_file, rc=None,
                               hyper_voxel_size=130, verbose=True)
Ejemplo n.º 3
0
    def setUp(self):

        os.chdir(os.path.dirname(__file__))

        self.network_path = os.path.join("networks", "network_testing_input")
        self.config_file = os.path.join(self.network_path,
                                        "network-config.json")
        self.position_file = os.path.join(self.network_path,
                                          "network-neuron-positions.hdf5")
        self.save_file = os.path.join(self.network_path, "voxels",
                                      "network-putative-synapses.hdf5")

        # Setup network so we can test input generation
        from snudda.init.init import SnuddaInit
        cell_spec = os.path.join(os.path.dirname(__file__), "validation")
        cnc = SnuddaInit(struct_def={},
                         config_file=self.config_file,
                         random_seed=1234)
        cnc.define_striatum(num_dSPN=5,
                            num_iSPN=0,
                            num_FS=5,
                            num_LTS=0,
                            num_ChIN=0,
                            volume_type="cube",
                            neurons_dir=cell_spec)
        cnc.write_json(self.config_file)

        # Place neurons
        from snudda.place.place import SnuddaPlace
        npn = SnuddaPlace(
            config_file=self.config_file,
            log_file=None,
            verbose=True,
            d_view=
            None,  # TODO: If d_view is None code run sin serial, add test parallel
            h5libver="latest")
        npn.parse_config()
        npn.write_data(self.position_file)

        # Detect
        self.sd = SnuddaDetect(config_file=self.config_file,
                               position_file=self.position_file,
                               save_file=self.save_file,
                               rc=None,
                               hyper_voxel_size=120,
                               verbose=True)

        self.sd.detect(restart_detection_flag=True)

        # Prune
        self.network_file = os.path.join(self.network_path,
                                         "network-synapses.hdf5")

        sp = SnuddaPrune(network_path=self.network_path,
                         config_file=None)  # Use default config file
        sp.prune(pre_merge_only=False)
Ejemplo n.º 4
0
    def write(self):

        # Before writing synapses, lets make sure they are sorted.
        # Sort order: columns 1 (dest), 0 (src), 6 (synapse type)
        sort_idx = np.lexsort(self.synapses[:self.synapse_ctr,
                                            [6, 0, 1]].transpose())
        self.synapses[:self.synapse_ctr, :] = self.synapses[sort_idx, :]

        # Write synapses to file
        with h5py.File(self.output_file_name, "w",
                       libver=self.h5libver) as out_file:

            out_file.create_dataset("config", data=json.dumps(self.config))

            network_group = out_file.create_group("network")
            network_group.create_dataset(
                "synapses",
                data=self.synapses[:self.synapse_ctr, :],
                dtype=np.int32,
                chunks=(self.synapse_chunk_size, 13),
                maxshape=(None, 13),
                compression=self.h5compression)

            network_group.create_dataset("nSynapses",
                                         data=self.synapse_ctr,
                                         dtype=int)
            network_group.create_dataset(
                "nNeurons", data=self.network_info.data["nNeurons"], dtype=int)

            # This is useful so the merge_helper knows if they need to search this file for synapses
            all_target_id = np.unique(self.synapses[:self.synapse_ctr, 1])
            network_group.create_dataset("allTargetId", data=all_target_id)

            # This creates a lookup that is used for merging later
            synapse_lookup = SnuddaDetect.create_lookup_table(
                data=self.synapses,
                n_rows=self.synapse_ctr,
                data_type="synapses",
                num_neurons=self.network_info.data["nNeurons"],
                max_synapse_type=self.next_channel_model_id)

            network_group.create_dataset("synapseLookup", data=synapse_lookup)
            network_group.create_dataset("maxChannelTypeID",
                                         data=self.next_channel_model_id,
                                         dtype=int)

        # We also need to update the work history file with how many synapses we created
        # for the projections between volumes

        with h5py.File(self.work_history_file, "a",
                       libver=self.h5libver) as hist_file:
            if "nProjectionSynapses" in hist_file:
                hist_file["nProjectionSynapses"][()] = self.synapse_ctr
            else:
                hist_file.create_dataset("nProjectionSynapses",
                                         data=self.synapse_ctr,
                                         dtype=int)
    def __init__(self):

        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))

        self.network_path = "touch_detection_illustration_network"
        self.config_file = os.path.join(self.network_path, "network-config.json")
        self.position_file = os.path.join(self.network_path, "network-neuron-positions.hdf5")
        self.save_file = os.path.join(self.network_path, "voxels", "network-putative-synapses.hdf5")

        create_cube_mesh(file_name=os.path.join(self.network_path, "mesh", "simple_mesh.obj"),
                         centre_point=(0, 0, 0),
                         side_len=500e-6)

        sp = SnuddaPlace(config_file=self.config_file, d_view=None)
        sp.parse_config()
        sp.write_data(self.position_file)

        self.sd = SnuddaDetect(config_file=self.config_file, position_file=self.position_file,
                               save_file=self.save_file, rc=None,
                               hyper_voxel_size=150)

        # Reposition the neurons so we know how many synapses and where they will be located before pruning
        neuron_positions = np.array([[0, 59, 0],  # Postsynaptiska
                                     [0, 89, 0],
                                     [0, 119, 0],
                                     [0, 149, 0],
                                     [0, 179, 0],
                                     [0, 209, 0],
                                     [0, 239, 0],
                                     [0, 269, 0],
                                     [0, 299, 0],
                                     [0, 329, 0],
                                     [59, 0, 0],  # Presynaptiska
                                     [89, 0, 0],
                                     [119, 0, 0],
                                     [149, 0, 0],
                                     [179, 0, 0],
                                     [209, 0, 0],
                                     [239, 0, 0],
                                     [269, 0, 0],
                                     [299, 0, 0],
                                     [329, 0, 0],
                                     ]) * 1e-6

        for idx, pos in enumerate(neuron_positions):
            self.sd.neurons[idx]["position"] = pos

        ang = -np.pi / 2
        R_x = np.array([[1, 0, 0],
                        [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        ang = np.pi / 2
        R_y = np.array([[np.cos(ang), 0, np.sin(ang)],
                        [0, 1, 0],
                        [-np.sin(ang), 0, np.cos(ang)]])

        for idx in range(0, 10):  # Post synaptic neurons
            self.sd.neurons[idx]["rotation"] = R_x

        for idx in range(10, 20):  # Presynaptic neurons
            self.sd.neurons[idx]["rotation"] = R_y

        self.sd.detect(restart_detection_flag=True)

        # Also update so that the new positions are saved in the place file
        rn = RepositionNeurons(self.position_file)
        for neuron_info in self.sd.neurons:
            rn.place(neuron_info["neuronID"], position=neuron_info["position"], rotation=neuron_info["rotation"],
                     verbose=False)
        rn.close()

        sp = SnuddaPrune(network_path=self.network_path)  # Use default config file
        sp.prune()
        sp = []
Ejemplo n.º 6
0
    def touch_detection(self, args):
        # self.networkPath = args.path
        print("Touch detection")
        print("Network path: " + str(self.network_path))

        if args.hvsize is not None:
            hyper_voxel_size = int(args.hvsize)
        else:
            hyper_voxel_size = 100

        if args.volumeID is not None:
            volume_id = args.volumeID
        else:
            volume_id = None

        log_dir = os.path.join(self.network_path, "log")
        if not os.path.exists(log_dir):
            print(f"Creating directory {log_dir}")
            os.makedirs(log_dir, exist_ok=True)

        config_file = os.path.join(self.network_path, "network-config.json")
        position_file = os.path.join(self.network_path,
                                     "network-neuron-positions.hdf5")
        log_filename = os.path.join(self.network_path, "log",
                                    "logFile-touch-detection.txt")
        save_file = os.path.join(self.network_path, "voxels",
                                 "network-putative-synapses.hdf5")

        random_seed = args.randomseed

        voxel_dir = os.path.join(self.network_path, "voxels")
        self.make_dir_if_needed(voxel_dir)

        self.setup_log_file(log_filename)  # sets self.logfile

        if args.parallel:
            self.setup_parallel()  # sets self.d_view and self.lb_view

        if args.h5legacy:
            h5libver = "earliest"
        else:
            h5libver = "latest"  # default

        from snudda.detect.detect import SnuddaDetect

        # You can now setup SnuddaDetect with only network_path and it will use default values
        # for config_file, position_file, logfile, save_file
        sd = SnuddaDetect(config_file=config_file,
                          position_file=position_file,
                          logfile=self.logfile,
                          save_file=save_file,
                          slurm_id=self.slurm_id,
                          volume_id=volume_id,
                          rc=self.rc,
                          hyper_voxel_size=hyper_voxel_size,
                          h5libver=h5libver,
                          random_seed=random_seed,
                          verbose=args.verbose)

        if args.cont:
            # Continue previous run
            print("Continuing previous touch detection")
            sd.detect(restart_detection_flag=False)
        else:
            sd.detect(restart_detection_flag=True)

        # Also run SnuddaProject to handle projections between volume

        from snudda.detect.project import SnuddaProject

        sp = SnuddaProject(network_path=self.network_path)
        sp.project()
        sp.write()

        self.stop_parallel()
        self.close_log_file()
Ejemplo n.º 7
0
    def setUp(self):
        from snudda.place.create_cube_mesh import create_cube_mesh

        # Create cube meshes
        self.network_path = os.path.join("networks", "network_testing_project")
        mesh_file_a = os.path.join(self.network_path, "mesh", "volume_A.obj")
        mesh_file_b = os.path.join(self.network_path, "mesh", "volume_B.obj")

        create_cube_mesh(mesh_file_a, [5e-3, 0, 0], 300e-6,
                         "Volume A - connect structures example")
        create_cube_mesh(mesh_file_b, [-5e-3, 0, 0], 300e-6,
                         "Volume B - connect structures example")

        # Define network

        from snudda.init.init import SnuddaInit

        cnc = SnuddaInit(network_path=self.network_path, random_seed=123)

        cnc.define_structure(struct_name="VolumeA",
                             struct_mesh=mesh_file_a,
                             d_min=15e-6,
                             mesh_bin_width=50e-6)
        cnc.define_structure(struct_name="VolumeB",
                             struct_mesh=mesh_file_b,
                             d_min=15e-6,
                             mesh_bin_width=50e-6)

        cnc.add_neurons(name="dSPN",
                        num_neurons=20,
                        volume_id="VolumeA",
                        neuron_dir=os.path.join("$DATA", "neurons", "striatum",
                                                "dspn"))
        cnc.add_neurons(name="iSPN",
                        num_neurons=20,
                        volume_id="VolumeB",
                        neuron_dir=os.path.join("$DATA", "neurons", "striatum",
                                                "ispn"))

        # Add the projection we want to test dSPN->iSPN
        proj_file = os.path.join("data", "ExampleProjection.json")

        cnc.neuron_projection(neuron_name="dSPN",
                              target_name="iSPN",
                              projection_name="ExampleProjection",
                              projection_file=proj_file,
                              source_volume="VolumeA",
                              dest_volume="VolumeB",
                              projection_radius=100e-6,
                              number_of_targets=[10, 5],
                              number_of_synapses=[10, 5],
                              dendrite_synapse_density="1",
                              connection_type="GABA",
                              dist_pruning=None,
                              f1=0.9,
                              soft_max=None,
                              mu2=None,
                              a3=None)

        # Also add dSPN-dSPN and iSPN-iSPN synapses
        # Note we do NOT add dSPN-iSPN again this way, as that would overwrite the above connections
        # (The above neuron_projection will also do normal touch detection)

        SPN2SPNdistDepPruning = "1-exp(-(0.4*d/60e-6)**2)"

        MSD1gGABA = [0.24e-9, 0.1e-9]
        MSD2gGABA = [0.24e-9, 0.1e-9]

        MSD1GABAfailRate = 0.7  # Taverna 2008, figure 2
        MSD2GABAfailRate = 0.4  # Taverna 2008, 2mM

        pfdSPNdSPN = os.path.join("$DATA", "synapses", "striatum",
                                  "PlanertFitting-DD-tmgaba-fit.json")
        pfdSPNiSPN = os.path.join("$DATA", "synapses", "striatum",
                                  "PlanertFitting-DI-tmgaba-fit.json")
        pfiSPNdSPN = os.path.join("$DATA", "synapses", "striatum",
                                  "PlanertFitting-ID-tmgaba-fit.json")
        pfiSPNiSPN = os.path.join("$DATA", "synapses", "striatum",
                                  "PlanertFitting-II-tmgaba-fit.json")

        cnc.add_neuron_target(neuron_name="dSPN",
                              target_name="dSPN",
                              connection_type="GABA",
                              dist_pruning=SPN2SPNdistDepPruning,
                              f1=0.38,
                              soft_max=3,
                              mu2=2.4,
                              a3=1.0,
                              conductance=MSD1gGABA,
                              parameter_file=pfdSPNdSPN,
                              mod_file="tmGabaA",
                              channel_param_dictionary={
                                  "tau1": (1.3e-3, 1e3),
                                  "tau2": (12.4e-3, 1e3),
                                  "failRate": MSD1GABAfailRate
                              })

        cnc.add_neuron_target(neuron_name="iSPN",
                              target_name="iSPN",
                              connection_type="GABA",
                              dist_pruning=SPN2SPNdistDepPruning,
                              f1=0.55,
                              soft_max=4,
                              mu2=2.4,
                              a3=1.0,
                              conductance=MSD2gGABA,
                              parameter_file=pfiSPNiSPN,
                              mod_file="tmGabaA",
                              channel_param_dictionary={
                                  "tau1": (1.3e-3, 1e3),
                                  "tau2": (12.4e-3, 1e3),
                                  "failRate": MSD2GABAfailRate
                              })

        cnc.write_json()

        # Place neurons, then detect, project and prune

        from snudda.place.place import SnuddaPlace
        sp = SnuddaPlace(network_path=self.network_path, verbose=True)
        sp.parse_config()
        sp.write_data()

        from snudda.detect.detect import SnuddaDetect
        sd = SnuddaDetect(network_path=self.network_path,
                          hyper_voxel_size=100,
                          verbose=True)
        sd.detect()

        from snudda.detect.project import SnuddaProject
        sp = SnuddaProject(network_path=self.network_path)
        sp.project()
        sp.write()

        from snudda.detect.prune import SnuddaPrune
        sp = SnuddaPrune(network_path=self.network_path, verbose=True)
        sp.prune()
Ejemplo n.º 8
0
    def test_project(self):

        # Are there connections dSPN->iSPN
        from snudda.utils.load import SnuddaLoad
        network_file = os.path.join(self.network_path, "network-synapses.hdf5")
        sl = SnuddaLoad(network_file)

        dspn_id_list = sl.get_cell_id_of_type("dSPN")
        ispn_id_list = sl.get_cell_id_of_type("iSPN")

        tot_proj_ctr = 0

        for dspn_id in dspn_id_list:
            for ispn_id in ispn_id_list:

                synapses, synapse_coords = sl.find_synapses(pre_id=dspn_id,
                                                            post_id=ispn_id)
                if synapses is not None:
                    tot_proj_ctr += synapses.shape[0]

        with self.subTest(stage="projection_exists"):
            # There should be projection synapses between dSPN and iSPN in this toy example
            self.assertTrue(tot_proj_ctr > 0)

        tot_dd_syn_ctr = 0
        for dspn_id in dspn_id_list:
            for dspn_id2 in dspn_id_list:

                synapses, synapse_coords = sl.find_synapses(pre_id=dspn_id,
                                                            post_id=dspn_id2)
                if synapses is not None:
                    tot_dd_syn_ctr += synapses.shape[0]

        tot_ii_syn_ctr = 0
        for ispn_id in ispn_id_list:
            for ispn_id2 in ispn_id_list:

                synapses, synapse_coords = sl.find_synapses(pre_id=ispn_id,
                                                            post_id=ispn_id2)
                if synapses is not None:
                    tot_ii_syn_ctr += synapses.shape[0]

        with self.subTest(stage="normal_synapses_exist"):
            # In this toy example neurons are quite sparsely placed, but we should have at least some
            # synapses
            self.assertTrue(tot_dd_syn_ctr > 0)
            self.assertTrue(tot_ii_syn_ctr > 0)

        # We need to run in parallel also to verify we get same result (same random seed)

        serial_synapses = sl.data["synapses"].copy()
        del sl  # Close old file so we can overwrite it

        os.environ["IPYTHONDIR"] = os.path.join(os.path.abspath(os.getcwd()),
                                                ".ipython")
        os.environ["IPYTHON_PROFILE"] = "default"
        os.system(
            "ipcluster start -n 4 --profile=$IPYTHON_PROFILE --ip=127.0.0.1&")
        time.sleep(10)

        # Run place, detect and prune in parallel by passing rc
        from ipyparallel import Client
        u_file = os.path.join(".ipython", "profile_default", "security",
                              "ipcontroller-client.json")
        rc = Client(url_file=u_file, timeout=120, debug=False)
        d_view = rc.direct_view(
            targets='all')  # rc[:] # Direct view into clients

        from snudda.detect.detect import SnuddaDetect
        sd = SnuddaDetect(network_path=self.network_path,
                          hyper_voxel_size=100,
                          rc=rc,
                          verbose=True)
        sd.detect()

        from snudda.detect.project import SnuddaProject
        # TODO: Currently SnuddaProject only runs in serial
        sp = SnuddaProject(network_path=self.network_path)
        sp.project()
        sp.write()

        from snudda.detect.prune import SnuddaPrune
        # Prune has different methods for serial and parallel execution, important to test it!
        sp = SnuddaPrune(network_path=self.network_path, rc=rc, verbose=True)
        sp.prune()

        with self.subTest(stage="check-parallel-identical"):
            sl2 = SnuddaLoad(network_file)
            parallel_synapses = sl2.data["synapses"].copy()

            # ParameterID, sec_X etc are randomised in hyper voxel, so you need to use same
            # hypervoxel size for reproducability between serial and parallel execution

            # All synapses should be identical regardless of serial or parallel execution path
            self.assertTrue((serial_synapses == parallel_synapses).all())

        os.system("ipcluster stop")
Ejemplo n.º 9
0
    def __init__(self):

        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))

        self.network_path = "pruning_illustration_network"
        self.config_file = os.path.join(self.network_path, "network-config.json")
        self.position_file = os.path.join(self.network_path, "network-neuron-positions.hdf5")
        self.save_file = os.path.join(self.network_path, "voxels", "network-synapses.hdf5")

        create_cube_mesh(file_name=os.path.join(self.network_path, "mesh", "simple_mesh.obj"),
                         centre_point=(0, 0, 0),
                         side_len=500e-6)

        sp = SnuddaPlace(config_file=self.config_file, d_view=None)

        print("Calling read_config")
        sp.parse_config()
        print("Read done")
        sp.write_data(self.position_file)

        # We want to load in the ball and stick neuron that has 20 micrometer soma diameter, and axon (along y-axis),
        # and dendrite along (x-axis) out to 200 micrometer distance from centre of soma.

        self.sd = SnuddaDetect(config_file=self.config_file, position_file=self.position_file,
                               save_file=self.save_file, rc=None,
                               hyper_voxel_size=150)

        # Reposition the neurons so we know how many synapses and where they will be located before pruning
        neuron_positions = np.array([[0, 59, 0],  # Postsynaptiska
                                     [0, 89, 0],
                                     [0, 119, 0],
                                     [0, 149, 0],
                                     [0, 179, 0],
                                     [0, 209, 0],
                                     [0, 239, 0],
                                     [0, 269, 0],
                                     [0, 299, 0],
                                     [0, 329, 0],
                                     [59, 0, 0],  # Presynaptiska
                                     [89, 0, 0],
                                     [119, 0, 0],
                                     [149, 0, 0],
                                     [179, 0, 0],
                                     [209, 0, 0],
                                     [239, 0, 0],
                                     [269, 0, 0],
                                     [299, 0, 0],
                                     [329, 0, 0],
                                     ]) * 1e-6

        # TODO: Add potential for gap junctions also by having 5 + 5 neurons in other grid

        for idx, pos in enumerate(neuron_positions):
            self.sd.neurons[idx]["position"] = pos

        ang = -np.pi / 2
        R_x = np.array([[1, 0, 0],
                        [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        ang = np.pi / 2
        R_y = np.array([[np.cos(ang), 0, np.sin(ang)],
                        [0, 1, 0],
                        [-np.sin(ang), 0, np.cos(ang)]])

        for idx in range(0, 10):  # Post synaptic neurons
            self.sd.neurons[idx]["rotation"] = R_x

        for idx in range(10, 20):  # Presynaptic neurons
            self.sd.neurons[idx]["rotation"] = R_y

        self.sd.detect(restart_detection_flag=True)

        # Also update so that the new positions are saved in the place file
        rn = RepositionNeurons(self.position_file)
        for neuron_info in self.sd.neurons:
            rn.place(neuron_info["neuronID"], position=neuron_info["position"], rotation=neuron_info["rotation"],
                     verbose=False)
        rn.close()

        if False:
            self.sd.process_hyper_voxel(1)
            plt, ax = self.sd.plot_hyper_voxel(plot_neurons=True, elev_azim=(90, 0),
                                               draw_axon_voxels=False, draw_dendrite_voxels=False,
                                               draw_axons=True, draw_dendrites=True,
                                               show_axis=False, title="No pruning",
                                               fig_file_name="Pruning-fig-1-no-pruning")
            import pdb
            pdb.set_trace()
Ejemplo n.º 10
0
    def setUp(self):

        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))

        self.network_path = os.path.join(os.path.dirname(__file__), "networks",
                                         "network_testing_prune3")

        create_cube_mesh(file_name=os.path.join(self.network_path, "mesh",
                                                "simple_mesh.obj"),
                         centre_point=(0, 0, 0),
                         side_len=500e-6)

        config_file = os.path.join(self.network_path, "network-config.json")
        position_file = os.path.join(self.network_path,
                                     "network-neuron-positions.hdf5")
        save_file = os.path.join(self.network_path, "voxels",
                                 "network-putative-synapses.hdf5")

        sp = SnuddaPlace(config_file=config_file, d_view=None, verbose=True)

        sp.parse_config()
        sp.write_data(position_file)

        # We want to load in the ball and stick neuron that has 20 micrometer soma diameter, and axon (along y-axis),
        # and dendrite along (x-axis) out to 100 micrometer distance from centre of soma.

        self.sd = SnuddaDetect(config_file=config_file,
                               position_file=position_file,
                               save_file=save_file,
                               rc=None,
                               hyper_voxel_size=120,
                               verbose=True)

        # Reposition the neurons so we know how many synapses and where they will be located before pruning
        neuron_positions = np.array([
            [0, 20, 0],  # Postsynaptiska
            [0, 40, 0],
            [0, 60, 0],
            [0, 80, 0],
            [0, 100, 0],
            [0, 120, 0],
            [0, 140, 0],
            [0, 160, 0],
            [0, 180, 0],
            [0, 200, 0],
            [20, 0, 0],  # Presynaptiska
            [40, 0, 0],
            [60, 0, 0],
            [80, 0, 0],
            [100, 0, 0],
            [120, 0, 0],
            [140, 0, 0],
            [160, 0, 0],
            [180, 0, 0],
            [200, 0, 0],
            [70, 0, 500],  # For gap junction check
            [110, 0, 500],
            [150, 0, 500],
            [190, 0, 500],
            [0, 70, 500],
            [0, 110, 500],
            [0, 150, 500],
            [0, 190, 500],
        ]) * 1e-6

        # TODO: Add potential for gap junctions also by having 5 + 5 neurons in other grid

        for idx, pos in enumerate(neuron_positions):
            self.sd.neurons[idx]["position"] = pos

        ang = -np.pi / 2
        R_x = np.array([[1, 0, 0], [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        ang = np.pi / 2
        R_y = np.array([[np.cos(ang), 0, np.sin(ang)], [0, 1, 0],
                        [-np.sin(ang), 0, np.cos(ang)]])

        for idx in range(0, 10):  # Post synaptic neurons
            self.sd.neurons[idx]["rotation"] = R_x

        for idx in range(10, 20):  # Presynaptic neurons
            self.sd.neurons[idx]["rotation"] = R_y

        for idx in range(24, 28):  # GJ neurons
            self.sd.neurons[idx]["rotation"] = R_x

        ang = np.pi / 2
        R_z = np.array([[np.cos(ang), -np.sin(ang), 0],
                        [np.sin(ang), np.cos(ang), 0], [0, 0, 1]])

        for idx in range(20, 24):  # GJ neurons
            self.sd.neurons[idx]["rotation"] = np.matmul(R_z, R_x)

        self.sd.detect(restart_detection_flag=True)

        if False:
            self.sd.process_hyper_voxel(1)
            self.sd.plot_hyper_voxel(plot_neurons=True)
Ejemplo n.º 11
0
class TestPrune(unittest.TestCase):
    def setUp(self):

        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))

        self.network_path = os.path.join(os.path.dirname(__file__), "networks",
                                         "network_testing_prune3")

        create_cube_mesh(file_name=os.path.join(self.network_path, "mesh",
                                                "simple_mesh.obj"),
                         centre_point=(0, 0, 0),
                         side_len=500e-6)

        config_file = os.path.join(self.network_path, "network-config.json")
        position_file = os.path.join(self.network_path,
                                     "network-neuron-positions.hdf5")
        save_file = os.path.join(self.network_path, "voxels",
                                 "network-putative-synapses.hdf5")

        sp = SnuddaPlace(config_file=config_file, d_view=None, verbose=True)

        sp.parse_config()
        sp.write_data(position_file)

        # We want to load in the ball and stick neuron that has 20 micrometer soma diameter, and axon (along y-axis),
        # and dendrite along (x-axis) out to 100 micrometer distance from centre of soma.

        self.sd = SnuddaDetect(config_file=config_file,
                               position_file=position_file,
                               save_file=save_file,
                               rc=None,
                               hyper_voxel_size=120,
                               verbose=True)

        # Reposition the neurons so we know how many synapses and where they will be located before pruning
        neuron_positions = np.array([
            [0, 20, 0],  # Postsynaptiska
            [0, 40, 0],
            [0, 60, 0],
            [0, 80, 0],
            [0, 100, 0],
            [0, 120, 0],
            [0, 140, 0],
            [0, 160, 0],
            [0, 180, 0],
            [0, 200, 0],
            [20, 0, 0],  # Presynaptiska
            [40, 0, 0],
            [60, 0, 0],
            [80, 0, 0],
            [100, 0, 0],
            [120, 0, 0],
            [140, 0, 0],
            [160, 0, 0],
            [180, 0, 0],
            [200, 0, 0],
            [70, 0, 500],  # For gap junction check
            [110, 0, 500],
            [150, 0, 500],
            [190, 0, 500],
            [0, 70, 500],
            [0, 110, 500],
            [0, 150, 500],
            [0, 190, 500],
        ]) * 1e-6

        # TODO: Add potential for gap junctions also by having 5 + 5 neurons in other grid

        for idx, pos in enumerate(neuron_positions):
            self.sd.neurons[idx]["position"] = pos

        ang = -np.pi / 2
        R_x = np.array([[1, 0, 0], [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        ang = np.pi / 2
        R_y = np.array([[np.cos(ang), 0, np.sin(ang)], [0, 1, 0],
                        [-np.sin(ang), 0, np.cos(ang)]])

        for idx in range(0, 10):  # Post synaptic neurons
            self.sd.neurons[idx]["rotation"] = R_x

        for idx in range(10, 20):  # Presynaptic neurons
            self.sd.neurons[idx]["rotation"] = R_y

        for idx in range(24, 28):  # GJ neurons
            self.sd.neurons[idx]["rotation"] = R_x

        ang = np.pi / 2
        R_z = np.array([[np.cos(ang), -np.sin(ang), 0],
                        [np.sin(ang), np.cos(ang), 0], [0, 0, 1]])

        for idx in range(20, 24):  # GJ neurons
            self.sd.neurons[idx]["rotation"] = np.matmul(R_z, R_x)

        self.sd.detect(restart_detection_flag=True)

        if False:
            self.sd.process_hyper_voxel(1)
            self.sd.plot_hyper_voxel(plot_neurons=True)

    def test_prune(self):

        pruned_output = os.path.join(self.network_path,
                                     "network-synapses.hdf5")

        with self.subTest(stage="No-pruning"):

            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=None,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()
            sp = []

            # Load the pruned data and check it

            sl = SnuddaLoad(pruned_output)
            # TODO: Call a plot function to plot entire network with synapses and all

            self.assertEqual(sl.data["nSynapses"], (20 * 8 + 10 * 2) *
                             2)  # Update, now AMPA+GABA, hence *2 at end

            # This checks that all synapses are in order
            # The synapse sort order is destID, sourceID, synapsetype (channel model id).

            syn = sl.data["synapses"][:sl.data["nSynapses"], :]
            syn_order = (syn[:, 1] * len(self.sd.neurons) + syn[:, 0]
                         ) * 12 + syn[:, 6]  # The 12 is maxChannelModelID
            self.assertTrue((np.diff(syn_order) >= 0).all())

            # Note that channel model id is dynamically allocated, starting from 10 (GJ have ID 3)
            # Check that correct number of each type
            self.assertEqual(np.sum(sl.data["synapses"][:, 6] == 10),
                             20 * 8 + 10 * 2)
            self.assertEqual(np.sum(sl.data["synapses"][:, 6] == 11),
                             20 * 8 + 10 * 2)

            self.assertEqual(sl.data["nGapJunctions"], 4 * 4 * 4)
            gj = sl.data["gapJunctions"][:sl.data["nGapJunctions"], :2]
            gj_order = gj[:, 1] * len(self.sd.neurons) + gj[:, 0]
            self.assertTrue((np.diff(gj_order) >= 0).all())

        with self.subTest(stage="load-testing"):
            sl = SnuddaLoad(pruned_output, verbose=True)

            # Try and load a neuron
            n = sl.load_neuron(0)
            self.assertTrue(type(n) == NeuronMorphology)

            syn_ctr = 0
            for s in sl.synapse_iterator(chunk_size=50):
                syn_ctr += s.shape[0]
            self.assertEqual(syn_ctr, sl.data["nSynapses"])

            gj_ctr = 0
            for gj in sl.gap_junction_iterator(chunk_size=50):
                gj_ctr += gj.shape[0]
            self.assertEqual(gj_ctr, sl.data["nGapJunctions"])

            syn, syn_coords = sl.find_synapses(pre_id=14)
            self.assertTrue((syn[:, 0] == 14).all())
            self.assertEqual(syn.shape[0], 40)

            syn, syn_coords = sl.find_synapses(post_id=3)
            self.assertTrue((syn[:, 1] == 3).all())
            self.assertEqual(syn.shape[0], 36)

            cell_id_perm = sl.get_cell_id_of_type("ballanddoublestick",
                                                  random_permute=True,
                                                  num_neurons=28)
            cell_id = sl.get_cell_id_of_type("ballanddoublestick",
                                             random_permute=False)

            self.assertEqual(len(cell_id_perm), 28)
            self.assertEqual(len(cell_id), 28)

            for cid in cell_id_perm:
                self.assertTrue(cid in cell_id)

        # It is important merge file has synapses sorted with dest_id, source_id as sort order since during pruning
        # we assume this to be able to quickly find all synapses on post synaptic cell.
        # TODO: Also include the ChannelModelID in sorting check
        with self.subTest("Checking-merge-file-sorted"):

            for mf in [
                    "temp/synapses-for-neurons-0-to-28-MERGE-ME.hdf5",
                    "temp/gapJunctions-for-neurons-0-to-28-MERGE-ME.hdf5",
                    "network-synapses.hdf5"
            ]:

                merge_file = os.path.join(self.network_path, mf)

                sl = SnuddaLoad(merge_file, verbose=True)
                if "synapses" in sl.data:
                    syn = sl.data["synapses"][:sl.data["nSynapses"], :2]
                    syn_order = syn[:, 1] * len(self.sd.neurons) + syn[:, 0]
                    self.assertTrue((np.diff(syn_order) >= 0).all())

                if "gapJunctions" in sl.data:
                    gj = sl.data["gapJunctions"][:sl.data["nGapJunctions"], :2]
                    gj_order = gj[:, 1] * len(self.sd.neurons) + gj[:, 0]
                    self.assertTrue((np.diff(gj_order) >= 0).all())

        with self.subTest("synapse-f1"):
            # Test of f1
            testing_config_file = os.path.join(self.network_path,
                                               "network-config-test-1.json")
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it

            sl = SnuddaLoad(pruned_output, verbose=True)
            # Setting f1=0.5 in config should remove 50% of GABA synapses, but does so randomly, for AMPA we used f1=0.9
            gaba_id = sl.data["connectivityDistributions"][
                "ballanddoublestick",
                "ballanddoublestick"]["GABA"]["channelModelID"]
            ampa_id = sl.data["connectivityDistributions"][
                "ballanddoublestick",
                "ballanddoublestick"]["AMPA"]["channelModelID"]

            n_gaba = np.sum(sl.data["synapses"][:, 6] == gaba_id)
            n_ampa = np.sum(sl.data["synapses"][:, 6] == ampa_id)

            self.assertTrue((20 * 8 + 10 * 2) * 0.5 -
                            10 < n_gaba < (20 * 8 + 10 * 2) * 0.5 + 10)
            self.assertTrue((20 * 8 + 10 * 2) * 0.9 -
                            10 < n_ampa < (20 * 8 + 10 * 2) * 0.9 + 10)

        with self.subTest("synapse-softmax"):
            # Test of softmax
            testing_config_file = os.path.join(
                self.network_path, "network-config-test-2.json"
            )  # Only GABA synapses in this config
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it
            sl = SnuddaLoad(pruned_output)
            # Softmax reduces number of synapses
            self.assertTrue(sl.data["nSynapses"] < 20 * 8 + 10 * 2)

        with self.subTest("synapse-mu2"):
            # Test of mu2
            testing_config_file = os.path.join(self.network_path,
                                               "network-config-test-3.json")
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it
            sl = SnuddaLoad(pruned_output)
            # With mu2 having 2 synapses means 50% chance to keep them, having 1 will be likely to have it removed
            self.assertTrue(
                20 * 8 * 0.5 - 10 < sl.data["nSynapses"] < 20 * 8 * 0.5 + 10)

        with self.subTest("synapse-a3"):
            # Test of a3
            testing_config_file = os.path.join(self.network_path,
                                               "network-config-test-4.json")
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it
            sl = SnuddaLoad(pruned_output)

            # a3=0.6 means 40% chance to remove all synapses between a pair
            self.assertTrue(
                (20 * 8 + 10 * 2) * 0.6 -
                14 < sl.data["nSynapses"] < (20 * 8 + 10 * 2) * 0.6 + 14)

        with self.subTest("synapse-distance-dependent-pruning"):
            # Testing distance dependent pruning
            testing_config_file = os.path.join(self.network_path,
                                               "network-config-test-5.json")
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it
            sl = SnuddaLoad(pruned_output)

            # "1*(d >= 100e-6)" means we remove all synapses closer than 100 micrometers
            self.assertEqual(sl.data["nSynapses"], 20 * 6)
            self.assertTrue(
                (sl.data["synapses"][:, 8] >=
                 100).all())  # Column 8 -- distance to soma in micrometers

        # TODO: Need to do same test for Gap Junctions also -- but should be same results, since same codebase
        with self.subTest("gap-junction-f1"):
            # Test of f1
            testing_config_file = os.path.join(self.network_path,
                                               "network-config-test-6.json")
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it

            sl = SnuddaLoad(pruned_output)
            # Setting f1=0.7 in config should remove 30% of gap junctions, but does so randomly
            self.assertTrue(
                64 * 0.7 - 10 < sl.data["nGapJunctions"] < 64 * 0.7 + 10)

        with self.subTest("gap-junction-softmax"):
            # Test of softmax
            testing_config_file = os.path.join(self.network_path,
                                               "network-config-test-7.json")
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it
            sl = SnuddaLoad(pruned_output)
            # Softmax reduces number of synapses
            self.assertTrue(sl.data["nGapJunctions"] < 16 * 2 + 10)

        with self.subTest("gap-junction-mu2"):
            # Test of mu2
            testing_config_file = os.path.join(self.network_path,
                                               "network-config-test-8.json")
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it
            sl = SnuddaLoad(pruned_output)
            # With mu2 having 4 synapses means 50% chance to keep them, having 1 will be likely to have it removed
            self.assertTrue(
                64 * 0.5 - 10 < sl.data["nGapJunctions"] < 64 * 0.5 + 10)

        with self.subTest("gap-junction-a3"):
            # Test of a3
            testing_config_file = os.path.join(self.network_path,
                                               "network-config-test-9.json")
            sp = SnuddaPrune(network_path=self.network_path,
                             config_file=testing_config_file,
                             verbose=True,
                             keep_files=True)  # Use default config file
            sp.prune()

            # Load the pruned data and check it
            sl = SnuddaLoad(pruned_output, verbose=True)

            # a3=0.7 means 30% chance to remove all synapses between a pair
            self.assertTrue(
                64 * 0.7 - 10 < sl.data["nGapJunctions"] < 64 * 0.7 + 10)

        if False:  # Distance dependent pruning currently not implemented for gap junctions
            with self.subTest("gap-junction-distance-dependent-pruning"):
                # Testing distance dependent pruning
                testing_config_file = os.path.join(
                    self.network_path, "network-config-test-10.json")
                sp = SnuddaPrune(network_path=self.network_path,
                                 config_file=testing_config_file,
                                 verbose=True,
                                 keep_files=True)  # Use default config file
                sp.prune()

                # Load the pruned data and check it
                sl = SnuddaLoad(pruned_output, verbose=True)

                # "1*(d <= 120e-6)" means we remove all synapses further away than 100 micrometers
                self.assertEqual(sl.data["nGapJunctions"], 2 * 4 * 4)
                self.assertTrue(
                    (sl.data["gapJunctions"][:, 8] <=
                     120).all())  # Column 8 -- distance to soma in micrometers
Ejemplo n.º 12
0
class MyTestCase(unittest.TestCase):
    def setUp(self):

        os.chdir(os.path.dirname(__file__))

        self.network_path = os.path.join("networks", "network_testing_input")
        self.config_file = os.path.join(self.network_path,
                                        "network-config.json")
        self.position_file = os.path.join(self.network_path,
                                          "network-neuron-positions.hdf5")
        self.save_file = os.path.join(self.network_path, "voxels",
                                      "network-putative-synapses.hdf5")

        # Setup network so we can test input generation
        from snudda.init.init import SnuddaInit
        cell_spec = os.path.join(os.path.dirname(__file__), "validation")
        cnc = SnuddaInit(struct_def={},
                         config_file=self.config_file,
                         random_seed=1234)
        cnc.define_striatum(num_dSPN=5,
                            num_iSPN=0,
                            num_FS=5,
                            num_LTS=0,
                            num_ChIN=0,
                            volume_type="cube",
                            neurons_dir=cell_spec)
        cnc.write_json(self.config_file)

        # Place neurons
        from snudda.place.place import SnuddaPlace
        npn = SnuddaPlace(
            config_file=self.config_file,
            log_file=None,
            verbose=True,
            d_view=
            None,  # TODO: If d_view is None code run sin serial, add test parallel
            h5libver="latest")
        npn.parse_config()
        npn.write_data(self.position_file)

        # Detect
        self.sd = SnuddaDetect(config_file=self.config_file,
                               position_file=self.position_file,
                               save_file=self.save_file,
                               rc=None,
                               hyper_voxel_size=120,
                               verbose=True)

        self.sd.detect(restart_detection_flag=True)

        # Prune
        self.network_file = os.path.join(self.network_path,
                                         "network-synapses.hdf5")

        sp = SnuddaPrune(network_path=self.network_path,
                         config_file=None)  # Use default config file
        sp.prune(pre_merge_only=False)

    def test_input_1(self):

        input_time = 10
        input_config = os.path.join(self.network_path, "input-test-1.json")
        spike_file = os.path.join(self.network_path, "input-spikes.hdf5")

        si = SnuddaInput(input_config_file=input_config,
                         hdf5_network_file=self.network_file,
                         spike_data_filename=spike_file,
                         time=input_time,
                         verbose=True)
        si.generate()

        input_data = h5py.File(spike_file, 'r')
        config_data = json.loads(input_data["config"][()])

        # TODO: Add checks

        # Loop through all inputs, and verify them

        for neuron_id_str in input_data["input"].keys():
            neuron_id = int(neuron_id_str)
            neuron_name = si.network_info["neurons"][neuron_id]["name"]
            neuron_type = neuron_name.split("_")[0]

            # Check frequency is as advertised...
            for input_type in input_data["input"][neuron_id_str]:
                input_info = input_data["input"][neuron_id_str][input_type]

                start_time = input_info["start"][()].copy()
                end_time = input_info["end"][()].copy()
                freq = input_info["freq"][()].copy()
                spikes = input_info["spikes"][()]
                n_traces = spikes.shape[0]

                max_len = 1
                if type(start_time) is np.ndarray:
                    max_len = np.maximum(max_len, len(start_time))

                if type(end_time) is np.ndarray:
                    max_len = np.maximum(max_len, len(end_time))

                if type(freq) is np.ndarray:
                    max_len = np.maximum(max_len, len(freq))

                if type(start_time) != np.ndarray:
                    start_time = np.array([start_time] * max_len)

                if type(end_time) != np.ndarray:
                    end_time = np.array([end_time] * max_len)

                if type(freq) != np.ndarray:
                    freq = np.array([freq] * max_len)

                for st, et, f in zip(start_time, end_time, freq):
                    idx_x, idx_y = np.where(
                        np.logical_and(st <= spikes, spikes <= et))

                    f_gen = len(idx_x) / (n_traces * (et - st))
                    print(
                        f"ID {neuron_id_str} {neuron_name} {input_type} f={f}, f_gen={f_gen}"
                    )

                    self.assertTrue(
                        f_gen > f - 4 * np.sqrt(f) / np.sqrt(n_traces))
                    self.assertTrue(
                        f_gen < f + 4 * np.sqrt(f) / np.sqrt(n_traces))
class TouchDetectionHypervoxelIllustration(object):

    def __init__(self):

        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))

        self.network_path = "touch_detection_hypervoxel_illustration_network"
        self.config_file = os.path.join(self.network_path, "network-config.json")
        self.position_file = os.path.join(self.network_path, "network-neuron-positions.hdf5")
        self.save_file = os.path.join(self.network_path, "voxels", "network-putative-synapses.hdf5")

        create_cube_mesh(file_name=os.path.join(self.network_path, "mesh", "simple_mesh.obj"),
                         centre_point=(0, 0, 0),
                         side_len=500e-6)

        sp = SnuddaPlace(config_file=self.config_file, d_view=None)
        sp.parse_config()
        sp.write_data(self.position_file)

        self.sd = SnuddaDetect(config_file=self.config_file, position_file=self.position_file,
                               save_file=self.save_file, rc=None,
                               hyper_voxel_size=60)

        neuron_positions = np.array([[10, 30, 70],  # Postsynaptiska
                                     [50, 60, 70],  # Presynaptiska
                                     ]) * 1e-6

        for idx, pos in enumerate(neuron_positions):
            self.sd.neurons[idx]["position"] = pos

        ang = -np.pi / 2
        R_x = np.array([[1, 0, 0],
                        [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        ang = np.pi * 0.2
        R_y = np.array([[np.cos(ang), 0, np.sin(ang)],
                        [0, 1, 0],
                        [-np.sin(ang), 0, np.cos(ang)]])


        ang = np.pi * (0.5 + 0.2)
        R_z0 = np.array([[np.cos(ang), -np.sin(ang), 0],
                         [np.sin(ang), np.cos(ang), 0],
                         [0, 0, 1]])

        ang = np.pi*0.4
        R_z1 = np.array([[np.cos(ang), -np.sin(ang), 0],
                         [np.sin(ang), np.cos(ang), 0],
                         [0, 0, 1]])

        # Post synaptic
        self.sd.neurons[0]["rotation"] = R_z0

        # Presynaptic neuron
        self.sd.neurons[1]["rotation"] = np.matmul(R_z1, R_y)

        self.sd.detect(restart_detection_flag=True)

        self.sd.process_hyper_voxel(0)
        plt, ax = self.sd.plot_hyper_voxel(plot_neurons=False,
                                           draw_axon_voxels=True,
                                           draw_dendrite_voxels=True,
                                           elev_azim=(50, -22),
                                           title="",
                                           fig_file_name="touch_detection_illustration-voxels.pdf",
                                           dpi=300)

        plt, ax = self.sd.plot_hyper_voxel(plot_neurons=True,
                                           draw_axon_voxels=False,
                                           draw_dendrite_voxels=False,
                                           elev_azim=(50, -22),
                                           title="",
                                           fig_file_name="touch_detection_illustration-morph.pdf",
                                           dpi=300)

        print(f"\n--> Figures written to {self.sd.network_path}/figures")
Ejemplo n.º 14
0
class PruningIllustration(object):

    def __init__(self, verbose=False, n_repeats=1000):

        self.n_repeats = n_repeats

        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))

        self.network_path = "pruning_illustration_network"
        # self.config_file = os.path.join(self.network_path, "network-config.json")
        # self.save_file = os.path.join(self.network_path, "voxels", "network-synapses.hdf5")

        create_cube_mesh(file_name=os.path.join(self.network_path, "mesh", "simple_mesh.obj"),
                         centre_point=(0, 0, 0),
                         side_len=500e-6)

        # Default uses network_config.json
        sp = SnuddaPlace(network_path=self.network_path, d_view=None, verbose=verbose)

        print("Calling read_config")
        sp.parse_config()
        print("Read done")

        position_file = os.path.join(self.network_path, "network-neuron-positions.hdf5")
        sp.write_data(position_file)

        # We want to load in the ball and stick neuron that has 20 micrometer soma diameter, and axon (along y-axis),
        # and dendrite along (x-axis) out to 200 micrometer distance from centre of soma.

        self.sd = SnuddaDetect(network_path=self.network_path, rc=None, hyper_voxel_size=150, verbose=verbose)

        # Reposition the neurons so we know how many synapses and where they will be located before pruning
        neuron_positions = np.array([[0, 59, 0],  # Postsynaptiska
                                     [0, 89, 0],
                                     [0, 119, 0],
                                     [0, 149, 0],
                                     [0, 179, 0],
                                     [0, 209, 0],
                                     [0, 239, 0],
                                     [0, 269, 0],
                                     [0, 299, 0],
                                     [0, 329, 0],
                                     [59, 0, 0],  # Presynaptiska
                                     [89, 0, 0],
                                     [119, 0, 0],
                                     [149, 0, 0],
                                     [179, 0, 0],
                                     [209, 0, 0],
                                     [239, 0, 0],
                                     [269, 0, 0],
                                     [299, 0, 0],
                                     [329, 0, 0],
                                     ]) * 1e-6

        # TODO: Add potential for gap junctions also by having 5 + 5 neurons in other grid

        for idx, pos in enumerate(neuron_positions):
            self.sd.neurons[idx]["position"] = pos

        ang = -np.pi / 2
        R_x = np.array([[1, 0, 0],
                        [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        ang = np.pi / 2
        R_y = np.array([[np.cos(ang), 0, np.sin(ang)],
                        [0, 1, 0],
                        [-np.sin(ang), 0, np.cos(ang)]])

        for idx in range(0, 10):  # Post synaptic neurons
            self.sd.neurons[idx]["rotation"] = R_x

        for idx in range(10, 20):  # Presynaptic neurons
            self.sd.neurons[idx]["rotation"] = R_y

        self.sd.detect(restart_detection_flag=True)

        # Also update so that the new positions are saved in the place file
        rn = RepositionNeurons(position_file)
        for neuron_info in self.sd.neurons:
            rn.place(neuron_info["neuronID"], position=neuron_info["position"], rotation=neuron_info["rotation"],
                     verbose=False)
        rn.close()

        if False:
            self.sd.process_hyper_voxel(1)
            plt, ax = self.sd.plot_hyper_voxel(plot_neurons=True, elev_azim=(90, 0),
                                               draw_axon_voxels=False, draw_dendrite_voxels=False,
                                               draw_axons=True, draw_dendrites=True,
                                               show_axis=False, title="No pruning",
                                               fig_file_name="Pruning-fig-1-no-pruning")
            import pdb
            pdb.set_trace()

    def prune_network(self, pruning_config=None, fig_name=None, title=None, verbose=False, plot_network=True,
                      random_seed=None, n_repeats=None):

        if n_repeats is None:
            n_repeats = self.n_repeats

        work_log = os.path.join(self.network_path, "log", "network-detect-worklog.hdf5")
        pruned_output = os.path.join(self.network_path, "network-synapses.hdf5")

        if pruning_config is not None and not os.path.exists(pruning_config):
            pruning_config = os.path.join(self.network_path, pruning_config)

        # We keep temp files
        sp = SnuddaPrune(network_path=self.network_path, config_file=pruning_config,
                         verbose=verbose, keep_files=True, random_seed=random_seed)  # Use default config file
        sp.prune()

        n_synapses = sp.out_file["network/synapses"].shape[0]
        n_gap_junctions = sp.out_file["network/gapJunctions"].shape[0]

        sp = []

        plot_axon = True
        plot_dendrite = True
        #plot_axon = np.ones((20,), dtype=bool)
        #plot_dendrite = np.ones((20,), dtype=bool)
        #plot_axon[:10] = False
        #plot_dendrite[10:] = False

        if plot_network:
            pn = PlotNetwork(pruned_output)
            plt, ax = pn.plot(fig_name=fig_name, show_axis=False,
                              plot_axon=plot_axon, plot_dendrite=plot_dendrite,
                              title=title, title_pad=-14,
                              elev_azim=(90, 0))

            if n_repeats > 1:
                n_syn_mean, n_syn_std, _, _ = self.gather_pruning_statistics(pruning_config=pruning_config, n_repeats=n_repeats)
                plt.figtext(0.5, 0.15, f"(${n_syn_mean:.1f} \pm {n_syn_std:.1f}$)", ha="center", fontsize=16)
                plt.savefig(fig_name, dpi=300, bbox_inches='tight')

            # Load the pruned data and check it
            # sl = SnuddaLoad(pruned_output)

        return n_synapses, n_gap_junctions

    def gather_pruning_statistics(self, pruning_config, n_repeats):

        n_synapses = np.zeros((n_repeats,))
        n_gap_junctions = np.zeros((n_repeats,))

        ss = np.random.SeedSequence()
        random_seeds = ss.generate_state(n_repeats)

        for i, rand_seed in enumerate(random_seeds):
            n_synapses[i], n_gap_junctions[i] = self.prune_network(pruning_config=pruning_config,
                                                                   plot_network=False,
                                                                   random_seed=rand_seed)

        mean_syn, std_syn = np.mean(n_synapses), np.std(n_synapses)
        mean_gj, std_gj = np.mean(n_gap_junctions), np.std(n_gap_junctions)

        print(f"{pruning_config}\nsynapses : {mean_syn:.1f} +/- {std_syn:.1f}\ngap junctions: {mean_gj:.1f} +/- {std_gj:.1f}")

        return mean_syn, std_syn, mean_gj, std_gj
Ejemplo n.º 15
0
class TestDetect(unittest.TestCase):

    def setUp(self):

        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))

        network_path = os.path.join(os.path.dirname(__file__), "networks", "network_testing_detect")

        create_cube_mesh(file_name=os.path.join(network_path, "mesh", "simple_mesh.obj"),
                         centre_point=(0, 0, 0),
                         side_len=500e-6)

        config_file = os.path.join(network_path, "network-config.json")
        position_file = os.path.join(network_path, "network-neuron-positions.hdf5")
        save_file = os.path.join(network_path, "voxels", "network-putative-synapses.hdf5")

        #  TODO: If d_view is None code run sin serial, add test parallel
        sp = SnuddaPlace(config_file=config_file, d_view=None, verbose=True)

        sp.parse_config()
        sp.write_data(position_file)

        # We want to load in the ball and stick neuron that has 20 micrometer soma diameter, and axon (along y-axis),
        # and dendrite along (x-axis) out to 100 micrometer distance from centre of soma.

        self.sd = SnuddaDetect(config_file=config_file, position_file=position_file,
                               save_file=save_file, rc=None,
                               hyper_voxel_size=130, verbose=True)

    def test_detect(self):

        neuron_positions = np.array([[0, 20, 0],    # Postsynaptiska
                                     [0, 40, 0],
                                     [0, 60, 0],
                                     [0, 80, 0],
                                     [0, 100, 0],
                                     [0, 120, 0],
                                     [0, 140, 0],
                                     [0, 160, 0],
                                     [0, 180, 0],
                                     [0, 200, 0],
                                     [20, 0, 0],    # Presynaptiska
                                     [40, 0, 0],
                                     [60, 0, 0],
                                     [80, 0, 0],
                                     [100, 0, 0],
                                     [120, 0, 0],
                                     [140, 0, 0],
                                     [160, 0, 0],
                                     [180, 0, 0],
                                     [200, 0, 0],
                                     [100, 100, -40],  # To get a gap junction
                                     ])*1e-6

        for idx, pos in enumerate(neuron_positions):
            self.sd.neurons[idx]["position"] = pos

        ang = -np.pi/2
        R_x = np.array([[1, 0, 0],
                        [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        ang = np.pi/2
        R_y = np.array([[np.cos(ang), 0, np.sin(ang)],
                        [0, 1, 0],
                        [-np.sin(ang), 0, np.cos(ang)]])

        ang = -np.pi/2
        R_gj = np.array([[np.cos(ang), 0, np.sin(ang)],
                         [0, 1, 0],
                         [-np.sin(ang), 0, np.cos(ang)]])

        for idx in range(0, 10):    # Post synaptic neurons
            self.sd.neurons[idx]["rotation"] = R_x

        for idx in range(10, 20):   # Presynaptic neurons
            self.sd.neurons[idx]["rotation"] = R_y

        self.sd.neurons[20]["rotation"] = R_gj

        self.sd.detect(restart_detection_flag=True)

        synapse_voxel_loc = self.sd.hyper_voxel_synapses[:self.sd.hyper_voxel_synapse_ctr, 2:5]
        synapse_coords = synapse_voxel_loc * self.sd.voxel_size + self.sd.hyper_voxel_origo

        fig_path = os.path.join("networks", "network_testing_detect", "figures")

        if not os.path.exists(fig_path):
            os.mkdir(fig_path)

        if False:   # Set to True to include plot
            self.sd.plot_hyper_voxel(plot_neurons=True, fig_file_name="touch-detection-validation")

        # TODO: Also add tests for soma-axon synapses

        # Check location and source, targets.
        with self.subTest(stage="gap_junction_check"):
            self.assertEqual(self.sd.hyper_voxel_gap_junction_ctr, 1)
            self.assertTrue((self.sd.hyper_voxel_gap_junctions[0, 0:2] == [4, 20]).all())
            self.assertTrue(self.compare_voxels_to_coordinates(self.sd.hyper_voxel_gap_junctions[0, 6:9],
                                                               np.array([100, 100, 0])*1e-6))
        with self.subTest(stage="synapses_check"):
            print(f"synapse ctr {self.sd.hyper_voxel_synapse_ctr}")

            self.assertEqual(self.sd.hyper_voxel_synapse_ctr, 101)

            for pre_id in range(0, 10):
                for post_id in range(10, 20):
                    self.assertEqual(self.check_neuron_pair_has_synapse(pre_id, post_id), 1)

            for pre_id in range(0, 10):
                for post_id in range(0, 10):
                    self.assertFalse(self.check_neuron_pair_has_synapse(pre_id, post_id))

            for pre_id in range(10, 20):
                for post_id in range(10, 20):
                    self.assertFalse(self.check_neuron_pair_has_synapse(pre_id, post_id))

        with self.subTest(stage="synapse_sorting_check"):
            syn = self.sd.hyper_voxel_synapses[:self.sd.hyper_voxel_synapse_ctr, :2]
            syn_order = syn[:, 1]*len(self.sd.neurons) + syn[:, 0]
            self.assertTrue((np.diff(syn_order) >= 0).all())

        with self.subTest(stage="gap_junction_sorting_check"):
            gj = self.sd.hyper_voxel_gap_junctions[:self.sd.hyper_voxel_gap_junction_ctr, :2]
            gj_order = gj[:, 1]*len(self.sd.neurons) + gj[:, 0]
            self.assertTrue((np.diff(gj_order) >= 0).all())

        # We should probably store the matrix as unsigned.
        self.assertTrue((self.sd.hyper_voxel_synapses >= 0).all())
        self.assertTrue((self.sd.hyper_voxel_gap_junctions >= 0).all())

        with self.subTest(stage="resiz_matrix_check"):
            old = self.sd.hyper_voxel_synapses.copy()
            self.sd.resize_hyper_voxel_synapses_matrix()
            # Check all synapses are preserved when resizing
            self.assertTrue((self.sd.hyper_voxel_synapses[:old.shape[0], :] == old).all())
            # Check new rows are empty
            self.assertTrue((self.sd.hyper_voxel_synapses[old.shape[0]:, :] == 0).all())

        # These test drawing not essential to Snudda, quite slow.
        if False:
            with self.subTest(stage="export_voxel_vis"):
                self.sd.export_voxel_visualisation_csv(neuron_id=np.arange(0, 10))

            with self.subTest(stage="plot_hyper_voxel"):
                # Matplotlib is kind of slow
                self.sd.plot_neurons_in_hyper_voxel(neuron_id=np.arange(0, 10),
                                                    neuron_colour=np.zeros((10, 3)),
                                                    show_plot=False, dpi=90)

            with self.subTest(stage="example-draw"):
                # Just checking that the drawing works
                self.sd.test_voxel_draw()

        print("Checking detect done.")

    def check_neuron_pair_has_synapse(self, pre_neuron, post_neuron):

        connections = dict()

        for synapse_row in self.sd.hyper_voxel_synapses[0:self.sd.hyper_voxel_synapse_ctr,:]:

            loc = (synapse_row[1], synapse_row[0])
            if loc in connections:
                connections[loc] += 1
            else:
                connections[loc] = 1

        if (pre_neuron, post_neuron) in connections:
            # print(f"pre: {pre_neuron}, post: {post_neuron}, connections: {connections[(pre_neuron, post_neuron)]}")
            return connections[(pre_neuron, post_neuron)]
        else:
            # print(f"No connection between pre {pre_neuron} and post {post_neuron}")
            return False

    def convert_to_coordinates(self, voxel_xyz):
        return np.array(voxel_xyz) * self.sd.voxel_size + self.sd.hyper_voxel_origo

    def compare_voxels_to_coordinates(self, voxel_index, coordinates):
        return (np.abs(self.convert_to_coordinates(voxel_index) - np.array(coordinates)) < self.sd.voxel_size).all()

    def test_detect_lines(self):

        # Cases to test
        # id 0-9 connecting to id 10-19, connection angle is 0-45 degrees
        # id 20 is 4 micrometer and parallel to another dendrite, no intersection

        neuron_positions = np.array([[0, 0, 0],    # Postsynaptiska
                                     [10, 10, 15],
                                     [20, 20, 30],
                                     [30, 30, 45],
                                     [40, 40, 60],
                                     [50, 50, 75],
                                     [60, 60, 90],
                                     [70, 70, 105],
                                     [80, 80, 120],
                                     [90, 90, 135],
                                     [50, -100, 0],    # Presynaptiska
                                     [60, -90, 15],
                                     [70, -80, 30],
                                     [80, -70, 45],
                                     [90, -60, 60],
                                     [100, -50, 75],
                                     [110, -40, 90],
                                     [120, -30, 105],
                                     [130, -20, 120],
                                     [140, -10, 135],
                                     [230, 0, 4],  # 4 micrometers from first neuron
                                     ])*1e-6

        for idx, pos in enumerate(neuron_positions):
            self.sd.neurons[idx]["position"] = pos

        ang = -np.pi/2
        R_x = np.array([[1, 0, 0],
                        [0, np.cos(ang), -np.sin(ang)],
                        [0, np.sin(ang), np.cos(ang)]])

        ang = np.pi/2
        R_y = np.array([[np.cos(ang), 0, np.sin(ang)],
                        [0, 1, 0],
                        [-np.sin(ang), 0, np.cos(ang)]])

        for idx in range(0, 10):    # Post synaptic neurons
            self.sd.neurons[idx]["rotation"] = R_x

        for idx, ang in zip(range(10, 20), np.linspace(0, -np.pi/4, 10)):   # Presynaptic neurons

            R_z = np.array([[np.cos(ang), -np.sin(ang), 0],
                            [np.sin(ang), np.cos(ang), 0],
                            [0, 0, 1]])

            print(f"idx = {idx}, ang = {ang}")

            self.sd.neurons[idx]["rotation"] = np.matmul(R_z, R_y)

        ang = np.pi / 2
        R_z = np.array([[np.cos(ang), -np.sin(ang), 0],
                        [np.sin(ang), np.cos(ang), 0],
                        [0, 0, 1]])

        self.sd.neurons[20]["rotation"] = np.matmul(R_z, R_y)

        self.sd.detect(restart_detection_flag=True)

        synapse_voxel_loc = self.sd.hyper_voxel_synapses[:self.sd.hyper_voxel_synapse_ctr, 2:5]
        synapse_coords = synapse_voxel_loc * self.sd.voxel_size + self.sd.hyper_voxel_origo

        if False:   # Set to True to include plot
            self.sd.plot_hyper_voxel(plot_neurons=True, fig_file_name="axon_dend_intersection_angle_0_45")

        with self.subTest(stage="synapses_check"):
            print(f"synapse ctr {self.sd.hyper_voxel_synapse_ctr}")

            self.assertEqual(self.sd.hyper_voxel_synapse_ctr, 10)

            for pre_id in range(0, 10):
                post_id = pre_id + 10
                self.assertEqual(self.check_neuron_pair_has_synapse(pre_id, post_id), 1)