diff --git a/.gitignore b/.gitignore index 45da335..4db5390 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ test_run MouseCells/ .ipynb_checkpoints/ coverage.xml +MouseCells_sAHP/ +tests/exp_data/X/ \ No newline at end of file diff --git a/setup.py b/setup.py index d33e039..c8fbe74 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ "the eFel library. BluePyEfe outputs protocols and features files in a " "format that can then be used by BluePyOpt for electrical model building " "purposes.", - packages=setuptools.find_packages(), + packages=setuptools.find_packages(exclude=["tests"]), python_requires=">=3.8", include_package_data=True, author="BlueBrain Project, EPFL", diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_extractor.py b/tests/test_extractor.py index 4390594..d011acf 100644 --- a/tests/test_extractor.py +++ b/tests/test_extractor.py @@ -6,6 +6,7 @@ import bluepyefe.extract import bluepyefe.tools +from tests.utils import download_sahp_datafiles def get_config(absolute_amplitude=False): @@ -74,6 +75,74 @@ def get_config(absolute_amplitude=False): return files_metadata, bluepyefe.extract.convert_legacy_targets(targets) +def get_sahp_config(absolute_amplitude=False): + download_sahp_datafiles() + + interesting_efeatures = { + "Spikecount": {}, + "mean_frequency": {}, + "ISI_CV": {}, + "AP1_amp": {}, + "AP_width": {}, + } + + files_metadata1 = [] + for file in glob.glob("./tests/exp_data/X/X_sAHP_ch0_*.ibw"): + files_metadata1.append( + { + "i_file": file, + "v_file": file.replace("ch0", "ch1"), + "i_unit": "A", + "v_unit": "V", + "t_unit": "s", + "dt": 0.00025, + "ljp": 14, + "ton": 10, + "tmid": 260, + "tmid2": 360, + "toff": 1360, + } + ) + files_metadata2 = [] + for file in glob.glob("./tests/exp_data/X/X_IDthresh_ch0_*.ibw"): + files_metadata2.append( + { + "i_file": file, + "v_file": file.replace("ch0", "ch1"), + "i_unit": "A", + "v_unit": "V", + "t_unit": "s", + "dt": 0.00025, + "ljp": 14, + } + ) + + files_metadata = { + "MouseNeuron1": {"sAHP": files_metadata1, "IDthresh": files_metadata2}, + } + + if absolute_amplitude: + targets = { + "sAHP": { + "amplitudes": [0.315, 0.225, 0.5, 0.69, 0.41, 0.595], + "tolerances": [0.01], + "efeatures": interesting_efeatures, + "location": "soma", + } + } + + else: + targets = { + "sAHP": { + "amplitudes": [285, 200, 450, 625, 370, 540], + "tolerances": [10.0], + "efeatures": interesting_efeatures, + "location": "soma", + } + } + + return files_metadata, bluepyefe.extract.convert_legacy_targets(targets) + class ExtractorTest(unittest.TestCase): def test_extract(self): @@ -219,6 +288,62 @@ def test_extract_absolute(self): protocols = json.load(fp) self.assertEqual(len(features), len(protocols)) + + def test_extract_sahp(self): + + files_metadata, targets = get_sahp_config() + + cells = bluepyefe.extract.read_recordings(files_metadata=files_metadata) + + cells = bluepyefe.extract.extract_efeatures_at_targets( + cells=cells, targets=targets + ) + + bluepyefe.extract.compute_rheobase(cells, protocols_rheobase=["IDthresh"]) + + self.assertEqual(len(cells), 1) + self.assertEqual(len(cells[0].recordings), 24) + self.assertLess(abs(cells[0].rheobase - 0.1103), 0.01) + + # amplitude test for one recording + # sort the recordings because they can be in any order, + # and we want to select the same one each time we test + sahp_recs = [rec for rec in cells[0].recordings if rec.protocol_name == "sAHP"] + rec1 = sorted(sahp_recs, key=lambda x: x.amp2)[1] + self.assertLess(abs(rec1.amp - 0.0953), 0.01) + self.assertLess(abs(rec1.amp2 - 0.3153), 0.01) + self.assertLess(abs(rec1.amp_rel - 86.4), 0.1) + self.assertLess(abs(rec1.amp2_rel - 285.8), 0.1) + + + protocols = bluepyefe.extract.group_efeatures( + cells, + targets, + use_global_rheobase=True, + protocol_mode="mean" + ) + + _ = bluepyefe.extract.create_feature_protocol_files( + cells=cells, protocols=protocols, output_directory="MouseCells_sAHP" + ) + + for protocol in protocols: + if protocol.name == "sAHP" and protocol.amplitude == 625: + for target in protocol.feature_targets: + if target.efel_feature_name == "Spikecount": + self.assertEqual(target.mean, 6) + break + + bluepyefe.extract.plot_all_recordings_efeatures( + cells, protocols, output_dir="MouseCells_sAHP/" + ) + + with open("MouseCells_sAHP/features.json") as fp: + features = json.load(fp) + with open("MouseCells_sAHP/protocols.json") as fp: + protocols = json.load(fp) + + self.assertEqual(len(features), len(protocols)) if __name__ == "__main__": diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..feecb0d --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,28 @@ +"""Utils""" + +import urllib.request +import shutil +from pathlib import Path + + +def download_sahp_datafiles(): + """Download data files for sAHP and IDthresh traces""" + output_dir = "./tests/exp_data/X/" + gb_url = "https://raw.githubusercontent.com/BlueBrain/SSCxEModelExamples/main/feature_extraction/input-traces/C060109A1-SR-C1/" + sahp_pathname = "X_sAHP" + sahp_ch = ["ch0", "ch1"] + sahp_numbers = list(range(320, 326)) + idthresh_pathname = "X_IDthresh" + idthresh_ch = ["ch0", "ch1"] + idthresh_numbers = list(range(349, 358)) + list(range(362, 371)) + + sahp_paths = [f"{sahp_pathname}_{ch}_{n}.ibw" for ch in sahp_ch for n in sahp_numbers] + idthresh_paths = [f"{idthresh_pathname}_{ch}_{n}.ibw" for ch in idthresh_ch for n in idthresh_numbers] + pathnames = sahp_paths + idthresh_paths + + Path(output_dir).mkdir(exist_ok=True, parents=True) + for pathname in pathnames: + output_path = f"{output_dir}{pathname}" + if not Path(output_path).is_file(): + with urllib.request.urlopen(f"{gb_url}{pathname}") as response, open(output_path, "wb") as out_file: + shutil.copyfileobj(response, out_file) \ No newline at end of file