from pathlib import Path
import unittest
import numpy as np
from ibllib.pipes import histology
from ibllib.pipes.ephys_alignment import (EphysAlignment, TIP_SIZE_UM, _cumulative_distance)
import iblatlas.atlas as atlas
# TODO Place this in setUpModule()
brain_atlas = atlas.AllenAtlas(res_um=25)
[docs]
class TestHistology(unittest.TestCase):
[docs]
def setUp(self) -> None:
self.path_tracks = Path(__file__).parent.joinpath('fixtures', 'histology', 'tracks')
[docs]
def test_histology_get_brain_regions(self):
# first part of the test is to check on an actual track file
for file_track in self.path_tracks.rglob("*_pts.csv"):
xyz = histology.load_track_csv(file_track, brain_atlas=brain_atlas)
channels, ins = histology.get_brain_regions(xyz=xyz, brain_atlas=brain_atlas)
# also check that it works from an insertion
channels, ins2 = histology.get_brain_regions(xyz=ins.xyz, brain_atlas=brain_atlas)
self.assertTrue(channels.acronym[-1] == 'VISpm1')
self.assertTrue(channels.acronym[0] == 'APN')
a = np.array([ins.x, ins.y, ins.z, ins.phi, ins.theta, ins.depth])
b = np.array([ins2.x, ins2.y, ins2.z, ins2.phi, ins2.theta, ins2.depth])
self.assertTrue(np.all(np.isclose(a, b)))
[docs]
def test_histology_insertion_from_track(self):
for file_track in self.path_tracks.rglob("*_pts.csv"):
xyz = histology.load_track_csv(file_track, brain_atlas=brain_atlas)
insertion = atlas.Insertion.from_track(xyz, brain_atlas=brain_atlas)
# checks that the tip coordinate is not the deepest point but its projection
self.assertFalse(np.all(np.isclose(insertion.tip, xyz[-1])))
[docs]
def test_get_brain_exit_entry(self):
traj = atlas.Trajectory.fit(np.array([[0, 0, 0], [0, 0, 0.005]]))
top = atlas.Insertion.get_brain_entry(traj, brain_atlas=brain_atlas)
bottom = atlas.Insertion.get_brain_exit(traj, brain_atlas=brain_atlas)
ix, iy = (brain_atlas.bc.x2i(0), brain_atlas.bc.y2i(0))
self.assertTrue(np.isclose(brain_atlas.top[iy, ix], top[2]))
self.assertTrue(np.isclose(brain_atlas.bottom[iy, ix], bottom[2]))
[docs]
def test_filename_parser(self):
tdata = [
{'input': Path("/gna/electrode_tracks_SWC_014/2019-12-12_SWC_014_001_probe01_fit.csv"),
'output': {'date': '2019-12-12', 'experiment_number': 1, 'name': 'probe01',
'subject': 'SWC_014'}},
{'input': Path("/gna/datadisk/Data/Histology/"
"tracks/ZM_2407/2019-11-06_ZM_2407_001_probe_00_pts.csv"),
'output': {'date': '2019-11-06', 'experiment_number': 1, 'name': 'probe_00',
'subject': 'ZM_2407'}},
{'input': Path("/gna/2019-12-06_KS023_001_probe01_pts.csv"),
'output': {'date': '2019-12-06', 'experiment_number': 1, 'name': 'probe01',
'subject': 'KS023'}},
]
for t in tdata:
track_file = t['input']
assert t['output'] == histology._parse_filename(track_file)
# Load in data for ephys alignment testing
data = np.load(Path(Path(__file__).parent.joinpath('fixtures', 'ephysalignment'),
'alignment_data.npz'), allow_pickle=True)
xyz_picks = data['xyz_picks']
feature_prev = data['feature_prev']
track_prev = data['track_prev']
xyz_channels_ref = data['xyz_channels_ref']
brain_regions_ref = data['brain_regions_ref']
depths = np.arange(20, 3860, 20) / 1e6
[docs]
class TestsEphysAlignment(unittest.TestCase):
[docs]
def setUp(self):
self.ephysalign = EphysAlignment(xyz_picks, brain_atlas=brain_atlas)
self.feature = self.ephysalign.feature_init
self.track = self.ephysalign.track_init
[docs]
def test_no_scaling(self):
xyz_channels = self.ephysalign.get_channel_locations(self.feature, self.track,
depths=depths)
coords = np.r_[[xyz_picks[-1, :]], [xyz_channels[0, :]]]
dist_to_fist_electrode = np.around(_cumulative_distance(coords)[-1], 5)
assert np.isclose(dist_to_fist_electrode, (TIP_SIZE_UM + 20) / 1e6)
[docs]
def test_offset(self):
feature_val = 500 / 1e6
track_val = 1000 / 1e6
tracks = np.sort(np.r_[self.track[[0, -1]], track_val])
track_new = self.ephysalign.feature2track(tracks, self.feature, self.track)
feature_new = np.sort(np.r_[self.feature[[0, -1]], feature_val])
track_new = self.ephysalign.adjust_extremes_uniform(feature_new, track_new)
xyz_channels = self.ephysalign.get_channel_locations(feature_new, track_new, depths=depths)
coords = np.r_[[xyz_picks[-1, :]], [xyz_channels[0, :]]]
dist_to_fist_electrode = np.around(_cumulative_distance(coords)[-1], 5)
assert np.isclose(dist_to_fist_electrode, ((TIP_SIZE_UM + 20) / 1e6 + feature_val))
track_val = self.ephysalign.track2feature(track_val, feature_new, track_new)
self.assertTrue(np.all(np.isclose(track_val, feature_val)))
region_new, _ = self.ephysalign.scale_histology_regions(feature_new, track_new)
_, scale_factor = self.ephysalign.get_scale_factor(region_new)
self.assertTrue(np.all(np.isclose(scale_factor, 1)))
[docs]
def test_linear_scaling(self):
feature_val = np.array([500, 700, 2000]) / 1e6
track_val = np.array([1000, 1300, 2700]) / 1e6
tracks = np.sort(np.r_[self.track[[0, -1]], track_val])
track_new = self.ephysalign.feature2track(tracks, self.feature, self.track)
feature_new = np.sort(np.r_[self.feature[[0, -1]], feature_val])
fit = np.polyfit(feature_new[1:-1], track_new[1:-1], 1)
linear_fit = np.around(1 / fit[0], 3)
feature_new, track_new = self.ephysalign.adjust_extremes_linear(feature_new,
track_new,
extend_feature=1)
region_new, _ = self.ephysalign.scale_histology_regions(feature_new, track_new)
_, scale_factor = self.ephysalign.get_scale_factor(region_new)
self.assertTrue(np.isclose(np.around(scale_factor[0], 3), linear_fit))
self.assertTrue(np.isclose(np.around(scale_factor[-1], 3), linear_fit))
[docs]
class TestsEphysReconstruction(unittest.TestCase):
[docs]
def setUp(self):
self.ephysalign = EphysAlignment(xyz_picks, track_prev=track_prev,
feature_prev=feature_prev, brain_atlas=brain_atlas)
self.feature = self.ephysalign.feature_init
self.track = self.ephysalign.track_init
[docs]
def test_channel_locations(self):
xyz_channels = self.ephysalign.get_channel_locations(self.feature, self.track,
depths=depths)
self.assertTrue(np.all(np.isclose(xyz_channels[0, :], xyz_channels_ref[0])))
self.assertTrue(np.all(np.isclose(xyz_channels[-1, :], xyz_channels_ref[-1])))
brain_regions = self.ephysalign.get_brain_locations(xyz_channels)
self.assertTrue(np.all(np.equal(np.unique(brain_regions.acronym), brain_regions_ref)))
if __name__ == "__main__":
unittest.main(exit=False, verbosity=2)