Beispiel #1
0
    def place_neurons(self, args):
        # self.networkPath = args.path
        print("Placing neurons")
        print(f"Network path: {self.network_path}")

        log_file_name = os.path.join(self.network_path, "log",
                                     "logFile-place-neurons.txt")

        random_seed = args.randomseed

        self.setup_log_file(log_file_name)  # sets self.logFile

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

        from snudda.place.place import SnuddaPlace

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

        sp = SnuddaPlace(network_path=self.network_path,
                         log_file=self.logfile,
                         verbose=args.verbose,
                         d_view=self.d_view,
                         h5libver=h5libver,
                         raytrace_borders=args.raytrace_borders,
                         random_seed=random_seed)

        sp.place()

        self.stop_parallel()
        self.close_log_file()
Beispiel #2
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()
Beispiel #3
0
    def test_population_units(self, stage="place-pop-unit-random"):

        network_path = os.path.join(os.path.dirname(__file__), "networks",
                                    "network_place_pop_unit_random")
        cnc = SnuddaInit(struct_def={}, network_path=network_path)
        cnc.define_striatum(num_dSPN=1000,
                            num_iSPN=1000,
                            num_FS=20,
                            num_LTS=0,
                            num_ChIN=0,
                            volume_type="cube")
        cnc.add_population_unit_random(structure_name="Striatum",
                                       neuron_types=["dSPN", "iSPN"],
                                       fraction_of_neurons=0.5)
        cnc.add_population_unit_random(structure_name="Striatum",
                                       neuron_types=["dSPN", "iSPN"],
                                       fraction_of_neurons=0.2)
        cnc.add_population_unit_random(structure_name="Striatum",
                                       neuron_types=["dSPN"],
                                       fraction_of_neurons=0.3)
        cnc.add_population_unit_random(structure_name="Striatum",
                                       neuron_types=["iSPN"],
                                       fraction_of_neurons=0.15)
        cnc.add_population_unit_random(structure_name="Striatum",
                                       neuron_types=["iSPN"],
                                       fraction_of_neurons=0.15,
                                       unit_id=10)
        cnc.write_json()

        npn = SnuddaPlace(network_path=network_path,
                          h5libver="latest",
                          verbose=True)
        npn.parse_config()
        npn.write_data()
Beispiel #4
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)
Beispiel #5
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)
Beispiel #6
0
    def setUp(self):

        # We want to setup a volume with density variations
        if os.path.dirname(__file__):
            os.chdir(os.path.dirname(__file__))
        print(
            f"Current directory (detect): {os.path.dirname(os.path.realpath(__file__))}"
        )

        neuron_dir = os.path.join(os.path.dirname(__file__), "validation")
        self.network_path = os.path.join("networks", "network_density")
        self.config_file = os.path.join(self.network_path,
                                        "network-config.json")
        cnc = SnuddaInit(struct_def={},
                         config_file=self.config_file,
                         random_seed=1234)

        mesh_file = os.path.join(self.network_path, "mesh", "slice.obj")

        cnc.define_striatum(num_dSPN=0,
                            num_iSPN=0,
                            num_FS=2000,
                            num_LTS=0,
                            num_ChIN=0,
                            mesh_file=mesh_file,
                            mesh_bin_width=5e-4,
                            neurons_dir=neuron_dir)

        create_slice_mesh(file_name=mesh_file,
                          centre_point=[1e-3, 1e-3, 1e-3],
                          x_len=2e-3,
                          y_len=2e-3,
                          z_len=2e-3,
                          description="Test slice")

        # Linear density = x coordinate, obs we give a relative density profile
        # (real density is scaled based on number of neurons)
        density_function = "abs(x)"
        cnc.add_neuron_density("Striatum",
                               "FSN",
                               density_func=density_function)

        cnc.write_json(self.config_file)

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

        npn = SnuddaPlace(config_file=self.config_file,
                          log_file=None,
                          verbose=True,
                          d_view=None,
                          h5libver="latest")

        npn.parse_config()
        npn.write_data(self.position_file)
Beispiel #7
0
    def test_place(self):

        # Place neurons

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

        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(position_file)

        with self.subTest(stage="neuron_count"):
            num_cells = 20
            self.assertEqual(npn.all_neuron_positions().shape[0], num_cells)
            self.assertEqual(len(npn.neurons), num_cells)

        with self.subTest(stage="d_min"):
            # Check that minimum distance between neurons, d_min is fulfilled
            all_pos = npn.all_neuron_positions()
            for pos in all_pos:
                d_min = 1e-5
                # Not too close (self comparison allowed to be equal, hence -1)
                self.assertTrue(
                    np.sum(np.linalg.norm(all_pos - pos, axis=1) >= d_min) ==
                    all_pos.shape[0] - 1)

                # Not too far apart
                d_max = 1e4  # This is just for this simulation, to catch if there are some spurious neurons
                self.assertTrue(
                    np.sum(np.linalg.norm(all_pos - pos, axis=1) <= d_max) ==
                    all_pos.shape[0])
    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 = []
Beispiel #9
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()
Beispiel #10
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()
Beispiel #11
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)
    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")