From 9bb4ef680e52cde891825ba43d50f445f4370075 Mon Sep 17 00:00:00 2001 From: Jacob Wilkins Date: Fri, 28 Feb 2025 13:44:22 +0000 Subject: [PATCH] Finish off Analysis folder --- .github/workflows/tests.yml | 4 +- .../test_helpers/compare_mdt.py | 3 +- .../Tests/UnitTests/Analysis/test_dynamics.py | 1 - .../UnitTests/Analysis/test_resolutions.py | 178 +++--- .../UnitTests/Analysis/test_scattering.py | 521 ++++++++---------- .../UnitTests/Analysis/test_structure.py | 111 +--- .../UnitTests/Analysis/test_thermodynamics.py | 182 +++--- .../UnitTests/Analysis/test_trajectory.py | 87 +-- .../AtomTransmutation/test_transmutation.py | 146 ++--- .../NeutronInstrument/test_instrument.py | 11 +- .../UnitTests/TrajectoryEditor/test_editor.py | 4 +- .../UnitTests/molecules/test_chemistry.py | 7 +- .../UnitTests/molecules/test_connectivity.py | 51 +- .../Tests/UnitTests/molecules/test_rdkit.py | 20 +- MDANSE/Tests/pytest.ini | 4 - MDANSE/pyproject.toml | 4 + 16 files changed, 523 insertions(+), 811 deletions(-) delete mode 100644 MDANSE/Tests/pytest.ini diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0c19b3c4bc..fbffdbe37b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,6 +31,6 @@ jobs: run: (cd MDANSE && python -m pip install .) - name: run unit tests + working-directory: ./MDANSE/ run: | - cd MDANSE/Tests/UnitTests - python -m pytest + pytest diff --git a/MDANSE/Tests/CommonFunctions/test_helpers/compare_mdt.py b/MDANSE/Tests/CommonFunctions/test_helpers/compare_mdt.py index 2a965a29e5..bb77ab5baa 100644 --- a/MDANSE/Tests/CommonFunctions/test_helpers/compare_mdt.py +++ b/MDANSE/Tests/CommonFunctions/test_helpers/compare_mdt.py @@ -39,9 +39,10 @@ def compare_mdt(result_path: Path, benchmark_path: Path, if normalised: np.testing.assert_array_almost_equal( result[f"/{key}"] * result[f"/{key}"].attrs["scaling_factor"], - benchmark[f"/{key}"][subset], + benchmark[f"/{key}"][subset], err_msg=f"Failure in key {key!r}.", ) else: np.testing.assert_array_almost_equal( result[f"/{key}"], benchmark[f"/{key}"][subset], + err_msg=f"Failure in key {key!r}.", ) diff --git a/MDANSE/Tests/UnitTests/Analysis/test_dynamics.py b/MDANSE/Tests/UnitTests/Analysis/test_dynamics.py index 89fff080bd..3646b79f6c 100644 --- a/MDANSE/Tests/UnitTests/Analysis/test_dynamics.py +++ b/MDANSE/Tests/UnitTests/Analysis/test_dynamics.py @@ -132,7 +132,6 @@ def test_dynamics_analysis( job = IJob.create(job_type) job.run(parameters, status=True) - if output_format == "MDAFormat": out_file = temp_name.with_suffix(".mda") result_file = RESULTS_DIR / f"dynamics_analysis_{traj_info[0]}_{job_type}.mda" diff --git a/MDANSE/Tests/UnitTests/Analysis/test_resolutions.py b/MDANSE/Tests/UnitTests/Analysis/test_resolutions.py index 42c9ff3dd0..c52c9b9c16 100644 --- a/MDANSE/Tests/UnitTests/Analysis/test_resolutions.py +++ b/MDANSE/Tests/UnitTests/Analysis/test_resolutions.py @@ -1,29 +1,13 @@ -import tempfile -import os -from os import path - -import h5py -import numpy as np import pytest - -from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData -from MDANSE.Framework.InstrumentResolutions.IInstrumentResolution import ( - IInstrumentResolution, -) +from MDANSE.Framework.InputData.HDFTrajectoryInputData import \ + HDFTrajectoryInputData +from MDANSE.Framework.InstrumentResolutions.IInstrumentResolution import \ + IInstrumentResolution from MDANSE.Framework.Jobs.IJob import IJob +from test_helpers.compare_mdt import compare_mdt +from test_helpers.paths import CONV_DIR, RESULTS_DIR - -short_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "short_trajectory_after_changes.mdt", -) -result_dir = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Results", -) +short_traj = CONV_DIR / "short_trajectory_after_changes.mdt" @pytest.fixture(scope="module") @@ -31,94 +15,90 @@ def trajectory(): trajectory = HDFTrajectoryInputData(short_traj) yield trajectory +@pytest.mark.parametrize("resolution_generator", IInstrumentResolution.subclasses()) +def test_disf(tmp_path, trajectory, resolution_generator): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "q_vectors": ( + "SphericalLatticeQVectors", + {"seed": 0, "shells": (5.0, 36, 10.0), "n_vectors": 10, "width": 9.0}, + ), + "running_mode": ("single-core",), + "trajectory": short_traj, + "weights": "b_incoherent2", + } + + parameters["output_files"] = (temp_name, ("MDAFormat",), "INFO") + instance = IInstrumentResolution.create(resolution_generator) + resolution_defaults = { + name: value[1]["default"] for name, value in instance.settings.items() + } + + print(resolution_generator) + print(resolution_defaults) -def test_disf(trajectory): - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["q_vectors"] = ( - "SphericalLatticeQVectors", - {"seed": 0, "shells": (5.0, 36, 10.0), "n_vectors": 10, "width": 9.0}, + parameters["instrument_resolution"] = ( + resolution_generator, + resolution_defaults, ) - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = short_traj - parameters["weights"] = "b_incoherent2" - for resolution_generator in IInstrumentResolution.subclasses(): - temp_name = tempfile.mktemp() - parameters["output_files"] = (temp_name, ("MDAFormat",), "INFO") - instance = IInstrumentResolution.create(resolution_generator) - resolution_defaults = { - name: value[1]["default"] for name, value in instance.settings.items() - } - print(resolution_generator) - print(resolution_defaults) - parameters["instrument_resolution"] = ( - resolution_generator, - resolution_defaults, - ) - disf = IJob.create("DynamicIncoherentStructureFactor") - disf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - os.remove(temp_name + ".mda") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") - - -list_of_resolutions = IInstrumentResolution.subclasses() - - -@pytest.mark.parametrize("resolution_generator", list_of_resolutions) -def test_dos(trajectory, resolution_generator): - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = short_traj - parameters["weights"] = "b_incoherent2" - temp_name = tempfile.mktemp() + + disf = IJob.create("DynamicIncoherentStructureFactor") + disf.run(parameters, status=True) + + assert out_file.is_file() + assert log_file.is_file() + + +@pytest.mark.parametrize("resolution_generator", IInstrumentResolution.subclasses()) +def test_dos(tmp_path, trajectory, resolution_generator): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + text_file = tmp_path / "output_text.tar" + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "running_mode": ("single-core",), + "trajectory": short_traj, + "weights": "b_incoherent2", + } + parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") + instance = IInstrumentResolution.create(resolution_generator) resolution_defaults = { name: value[1]["default"] for name, value in instance.settings.items() } + print(resolution_generator) print(resolution_defaults) + parameters["instrument_resolution"] = ( resolution_generator, resolution_defaults, ) + disf = IJob.create("DensityOfStates") disf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - result_file = os.path.join(result_dir, f"dos_{resolution_generator}.mda") - - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - for key in [ - "dos_Cu", - "dos_S", - "dos_Sb", - "dos_total", - "vacf_Cu", - "vacf_S", - "vacf_Sb", - "vacf_total", - ]: - np.testing.assert_array_almost_equal( - actual[f"/{key}"] * actual[f"/{key}"].attrs["scaling_factor"], - desired[f"/{key}"], - ) - - os.remove(temp_name + ".mda") - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") + + assert out_file.is_file() + assert log_file.is_file() + assert text_file.is_file() + + result_file = RESULTS_DIR / f"dos_{resolution_generator}.mda" + + keys = [f"{fn}_{elem}" + for fn in ("dos", "vacf") + for elem in ("Cu", "S", "Sb", "total")] + + compare_mdt(out_file, result_file, keys, normalised=True) diff --git a/MDANSE/Tests/UnitTests/Analysis/test_scattering.py b/MDANSE/Tests/UnitTests/Analysis/test_scattering.py index dad03172d6..86b1c6e85b 100644 --- a/MDANSE/Tests/UnitTests/Analysis/test_scattering.py +++ b/MDANSE/Tests/UnitTests/Analysis/test_scattering.py @@ -7,32 +7,12 @@ import pytest from MDANSE.Framework.Jobs.IJob import IJob +from test_helpers.paths import CONV_DIR, RESULTS_DIR +from test_helpers.compare_mdt import compare_mdt - -short_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "short_trajectory_after_changes.mdt", -) -mdmc_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "Ar_mdmc_h5md.h5", -) -com_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "com_trajectory.mdt", -) -result_dir = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Results", -) - +short_traj = CONV_DIR / "short_trajectory_after_changes.mdt" +mdmc_traj = CONV_DIR / "Ar_mdmc_h5md.h5" +com_traj = CONV_DIR / "com_trajectory.mdt" @pytest.fixture(scope="module") def qvector_grid(): @@ -43,147 +23,147 @@ def qvector_grid(): @pytest.fixture(scope="module") -def dcsf(): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["output_files"] = (temp_name, ("MDAFormat",), "INFO") - parameters["q_vectors"] = ( - "SphericalLatticeQVectors", - {"seed": 0, "shells": (5.0, 36, 10.0), "n_vectors": 10, "width": 9.0}, - ) - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = short_traj - parameters["weights"] = "b_coherent" +def dcsf(tmp_path_factory): + temp_name = tmp_path_factory.mktemp("data") / "output_dcsf" + out_file = temp_name.with_suffix(".mda") + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "output_files": (temp_name, ("MDAFormat",), "INFO"), + "q_vectors": ( + "SphericalLatticeQVectors", + {"seed": 0, "shells": (5.0, 36, 10.0), "n_vectors": 10, "width": 9.0}, + ), + "running_mode": ("single-core",), + "trajectory": short_traj, + "weights": "b_coherent", + } + dcsf = IJob.create("DynamicCoherentStructureFactor") dcsf.run(parameters, status=True) - yield temp_name + ".mda" - os.remove(temp_name + ".mda") + + yield out_file @pytest.fixture(scope="module") -def disf(): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["output_files"] = (temp_name, ("MDAFormat",), "INFO") - parameters["q_vectors"] = ( - "SphericalLatticeQVectors", - {"seed": 0, "shells": (5.0, 36, 10.0), "n_vectors": 10, "width": 9.0}, - ) - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = short_traj - parameters["weights"] = "b_incoherent2" +def disf(tmp_path_factory): + temp_name = tmp_path_factory.mktemp("data") / "output_disf" + out_file = temp_name.with_suffix(".mda") + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "output_files": (temp_name, ("MDAFormat",), "INFO"), + "q_vectors": ( + "SphericalLatticeQVectors", + {"seed": 0, "shells": (5.0, 36, 10.0), "n_vectors": 10, "width": 9.0}, + ), + "running_mode": ("single-core",), + "trajectory": short_traj, + "weights": "b_incoherent2", + } + disf = IJob.create("DynamicIncoherentStructureFactor") disf.run(parameters, status=True) - yield temp_name + ".mda" - os.remove(temp_name + ".mda") + + yield out_file @pytest.mark.parametrize( "traj_info", [("short_traj", short_traj), ("mdmc_traj", mdmc_traj), ("com_traj", com_traj)], + ids=lambda x: x[0], ) -def test_dcsf(traj_info, qvector_grid): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") - parameters["q_vectors"] = qvector_grid - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = traj_info[1] - parameters["weights"] = "b_coherent" +def test_dcsf(tmp_path, traj_info, qvector_grid): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + text_file = tmp_path / "output_text.tar" + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "output_files": (temp_name, ("MDAFormat", "TextFormat"), "INFO"), + "q_vectors": qvector_grid, + "running_mode": ("single-core",), + "trajectory": traj_info[1], + "weights": "b_coherent", + } + dcsf = IJob.create("DynamicCoherentStructureFactor") dcsf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - - result_file = os.path.join(result_dir, f"dcsf_{traj_info[0]}.mda") - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - keys = [ - key for key in desired.keys() - if any(key.startswith(j) for j in ["f(q,t)", "s(q,f)"]) - ] - for key in keys: - np.testing.assert_array_almost_equal( - actual[f"/{key}"] * actual[f"/{key}"].attrs["scaling_factor"], - desired[f"/{key}"], - ) - - os.remove(temp_name + ".mda") - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") + + assert out_file.is_file() + assert log_file.is_file() + assert text_file.is_file() + + result_file = RESULTS_DIR / f"dcsf_{traj_info[0]}.mda" + + compare_mdt(out_file, result_file, ("f(q,t)", "s(q,f)"), + startswith=True, normalised=True) @pytest.mark.parametrize( "traj_info", [("short_traj", short_traj), ("mdmc_traj", mdmc_traj), ("com_traj", com_traj)], + ids=lambda x: x[0], ) -def test_ccf(traj_info, qvector_grid): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") - parameters["q_vectors"] = qvector_grid - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = traj_info[1] - parameters["weights"] = "equal" - dcsf = IJob.create("CurrentCorrelationFunction") - dcsf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - - result_file = os.path.join(result_dir, f"ccf_{traj_info[0]}.mda") - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - keys = [ - i for i in desired.keys() if any([j in i for j in ["J(q,f)", "j(q,t)"]]) - ] - for key in keys: - # reference results were not rescaled - np.testing.assert_array_almost_equal( - actual[f"/{key}"], desired[f"/{key}"], - ) - - os.remove(temp_name + ".mda") - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") - - -def test_output_axis_preview(qvector_grid): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") - parameters["q_vectors"] = qvector_grid - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = short_traj - parameters["weights"] = "b_coherent" +def test_ccf(tmp_path, traj_info, qvector_grid): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + text_file = tmp_path / "output_text.tar" + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "output_files": (temp_name, ("MDAFormat", "TextFormat"), "INFO"), + "q_vectors": qvector_grid, + "running_mode": ("single-core",), + "trajectory": traj_info[1], + "weights": "equal", + } + + ccf = IJob.create("CurrentCorrelationFunction") + ccf.run(parameters, status=True) + + assert out_file.is_file() + assert log_file.is_file() + assert text_file.is_file() + + result_file = RESULTS_DIR / f"ccf_{traj_info[0]}.mda" + + compare_mdt(out_file, result_file, ("J(q,f)", "j(q,t)"), startswith=True) + + +def test_output_axis_preview(tmp_path, qvector_grid): + temp_name = tmp_path / "output" + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "output_files": (temp_name, ("MDAFormat", "TextFormat"), "INFO"), + "q_vectors": qvector_grid, + "running_mode": ("single-core",), + "trajectory": short_traj, + "weights": "b_coherent", + } + dcsf = IJob.create("DynamicCoherentStructureFactor") dcsf.setup(parameters) axes = dcsf.preview_output_axis() + print(axes) assert len(axes) == 3 # two configurators return valid arrays @@ -191,161 +171,148 @@ def test_output_axis_preview(qvector_grid): @pytest.mark.parametrize( "traj_info", [("short_traj", short_traj), ("mdmc_traj", mdmc_traj), ("com_traj", com_traj)], + ids=lambda x: x[0], ) -def test_disf(traj_info, qvector_grid): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") - parameters["q_vectors"] = qvector_grid - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = traj_info[1] - parameters["weights"] = "b_incoherent2" +def test_disf(tmp_path, traj_info, qvector_grid): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + text_file = tmp_path / "output_text.tar" + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "output_files": (temp_name, ("MDAFormat", "TextFormat"), "INFO"), + "q_vectors": qvector_grid, + "running_mode": ("single-core",), + "trajectory": traj_info[1], + "weights": "b_incoherent2", + } + disf = IJob.create("DynamicIncoherentStructureFactor") disf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - - result_file = os.path.join(result_dir, f"disf_{traj_info[0]}.mda") - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - keys = [ - i for i in desired.keys() if any([j in i for j in ["f(q,t)", "s(q,f)"]]) - ] - for key in keys: - np.testing.assert_array_almost_equal( - actual[f"/{key}"] * actual[f"/{key}"].attrs["scaling_factor"], - desired[f"/{key}"], - ) - - os.remove(temp_name + ".mda") - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") + + assert out_file.is_file() + assert log_file.is_file() + assert text_file.is_file() + + result_file = RESULTS_DIR / f"disf_{traj_info[0]}.mda" + + compare_mdt(out_file, result_file, ("f(q,t)", "s(q,f)"), + startswith=True, normalised=True) @pytest.mark.parametrize( "traj_info", [("short_traj", short_traj), ("mdmc_traj", mdmc_traj), ("com_traj", com_traj)], + ids=lambda x: x[0], ) -def test_eisf(traj_info, qvector_grid): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1) - parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") - parameters["q_vectors"] = qvector_grid - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = traj_info[1] - parameters["weights"] = "b_incoherent" +def test_eisf(tmp_path, traj_info, qvector_grid): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + text_file = tmp_path / "output_text.tar" + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1), + "output_files": (temp_name, ("MDAFormat", "TextFormat"), "INFO"), + "q_vectors": qvector_grid, + "running_mode": ("single-core",), + "trajectory": traj_info[1], + "weights": "b_incoherent", + } + eisf = IJob.create("ElasticIncoherentStructureFactor") eisf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - - result_file = os.path.join(result_dir, f"eisf_{traj_info[0]}.mda") - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - keys = [i for i in desired.keys() if "eisf" in i] - for key in keys: - np.testing.assert_array_almost_equal( - actual[f"/{key}"] * actual[f"/{key}"].attrs["scaling_factor"], - desired[f"/{key}"], - ) - - os.remove(temp_name + ".mda") - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") + + assert out_file.is_file() + assert log_file.is_file() + assert text_file.is_file() + + result_file = RESULTS_DIR / f"eisf_{traj_info[0]}.mda" + compare_mdt(out_file, result_file, ("eisf",), startswith=True, normalised=True) @pytest.mark.parametrize( "traj_info", [("short_traj", short_traj), ("mdmc_traj", mdmc_traj), ("com_traj", com_traj)], + ids=lambda x: x[0], ) -def test_gdisf(traj_info): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["frames"] = (0, 10, 1, 5) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") - parameters["q_shells"] = (2.0, 12.2, 2.0) - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = traj_info[1] - parameters["weights"] = "b_incoherent2" +def test_gdisf(tmp_path, traj_info): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + text_file = tmp_path / "output_text.tar" + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "frames": (0, 10, 1, 5), + "instrument_resolution": ("Ideal", {}), + "output_files": (temp_name, ("MDAFormat", "TextFormat"), "INFO"), + "q_shells": (2.0, 12.2, 2.0), + "running_mode": ("single-core",), + "trajectory": traj_info[1], + "weights": "b_incoherent2", + } + gdisf = IJob.create("GaussianDynamicIncoherentStructureFactor") gdisf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - - result_file = os.path.join(result_dir, f"gdisf_{traj_info[0]}.mda") - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - keys = [ - i for i in desired.keys() if any([j in i for j in ["f(q,t)", "s(q,f)", "msd"]]) - ] - for key in keys: - np.testing.assert_array_almost_equal( - actual[f"/{key}"] * actual[f"/{key}"].attrs["scaling_factor"], - desired[f"/{key}"] * desired[f"/{key}"].attrs["scaling_factor"], - ) - - os.remove(temp_name + ".mda") - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") - - -def test_ndtsf(disf, dcsf, qvector_grid): - temp_name = tempfile.mktemp() - parameters = {} - parameters["atom_selection"] = None - parameters["atom_transmutation"] = None - parameters["disf_input_file"] = disf - parameters["dcsf_input_file"] = dcsf - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = short_traj - parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") + + assert out_file.is_file() + assert log_file.is_file() + assert text_file.is_file() + + result_file = RESULTS_DIR / f"gdisf_{traj_info[0]}.mda" + + compare_mdt(out_file, result_file, ("f(q,t)", "s(q,f)", "msd"), + startswith=True, normalised=False) + + +def test_ndtsf(tmp_path, disf, dcsf, qvector_grid): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + text_file = tmp_path / "output_text.tar" + + parameters = { + "atom_selection": None, + "atom_transmutation": None, + "disf_input_file": disf, + "dcsf_input_file": dcsf, + "running_mode": ("single-core",), + "trajectory": short_traj, + "output_files": (temp_name, ("MDAFormat", "TextFormat"), "INFO"), + } + ndtsf = IJob.create("NeutronDynamicTotalStructureFactor") ndtsf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - os.remove(temp_name + ".mda") - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") - - -def test_ssfsf(disf): - temp_name = tempfile.mktemp() - parameters = {} - parameters["sample_inc"] = disf - parameters["running_mode"] = ("single-core",) - parameters["instrument_resolution"] = ("Ideal", {}) - parameters["output_files"] = (temp_name, ("MDAFormat", "TextFormat"), "INFO") + + assert out_file.is_file() + assert log_file.is_file() + assert text_file.is_file() + + +def test_ssfsf(tmp_path, disf): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + text_file = tmp_path / "output_text.tar" + + parameters = { + "sample_inc": disf, + "running_mode": ("single-core",), + "instrument_resolution": ("Ideal", {}), + "output_files": (temp_name, ("MDAFormat", "TextFormat"), "INFO"), + } + ndtsf = IJob.create("StructureFactorFromScatteringFunction") ndtsf.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - os.remove(temp_name + ".mda") - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") + + assert out_file.is_file() + assert log_file.is_file() + assert text_file.is_file() diff --git a/MDANSE/Tests/UnitTests/Analysis/test_structure.py b/MDANSE/Tests/UnitTests/Analysis/test_structure.py index 797140cadf..3208782f6c 100644 --- a/MDANSE/Tests/UnitTests/Analysis/test_structure.py +++ b/MDANSE/Tests/UnitTests/Analysis/test_structure.py @@ -1,38 +1,12 @@ -import tempfile -import os -from os import path - import numpy as np -import h5py import pytest - from MDANSE.Framework.Jobs.IJob import IJob +from test_helpers.compare_mdt import compare_mdt +from test_helpers.paths import CONV_DIR, RESULTS_DIR - -short_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "short_trajectory_after_changes.mdt", -) -mdmc_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "Ar_mdmc_h5md.h5", -) -result_dir = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Results", -) - -com_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "com_trajectory.mdt", -) +short_traj = CONV_DIR / "short_trajectory_after_changes.mdt" +mdmc_traj = CONV_DIR / "Ar_mdmc_h5md.h5" +com_traj = CONV_DIR / "com_trajectory.mdt" ################################################################ @@ -67,33 +41,12 @@ def parameters(): parameters["weights"] = "equal" return parameters - -total_list = [] - -for tp in [ - ("short_traj", short_traj), - ("mdmc_traj", mdmc_traj), - ("com_traj", com_traj), -]: - for jt in [ - ("RadiusOfGyration", ["rog"]), - ("DensityProfile", ["dp"]), - ( - "MolecularTrace", - ["molecular_trace", "x_position", "y_position", "z_position"], - ), - ("Eccentricity", ["eccentricity"]), - ]: - for rm in [("single-core", 1), ("multicore", -4)]: - for of in ["MDAFormat", "TextFormat"]: - total_list.append((tp, jt, rm, of)) - -for tp in [ +@pytest.mark.parametrize("traj_info", [ ("short_traj", short_traj), ("mdmc_traj", mdmc_traj), ("com_traj", com_traj), -]: - for jt in [ +], ids=lambda x: x[0]) +@pytest.mark.parametrize("job_info", [ ("SolventAccessibleSurface", ["sas"]), ("RootMeanSquareDeviation", ["rmsd"]), ("RootMeanSquareFluctuation", ["rmsf"]), @@ -102,41 +55,35 @@ def parameters(): ("PairDistributionFunction", ["pdf", "rdf", "tcf"]), ("StaticStructureFactor", ["ssf"]), ("XRayStaticStructureFactor", ["xssf"]), - ]: - for rm in [("single-core", 1)]: - for of in ["MDAFormat"]: - total_list.append((tp, jt, rm, of)) - - -@pytest.mark.parametrize("traj_info,job_info,running_mode,output_format", total_list) +], ids=lambda x: x[0]) +@pytest.mark.parametrize("running_mode", [("single-core", 1)], ids=lambda x: x[0]) +@pytest.mark.parametrize("output_format", ["MDAFormat"]) def test_structure_analysis( - parameters, traj_info, job_info, running_mode, output_format + tmp_path, parameters, traj_info, job_info, running_mode, output_format ): - temp_name = tempfile.mktemp() + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + + job_type, outputs = job_info + parameters["trajectory"] = traj_info[1] parameters["running_mode"] = running_mode parameters["output_files"] = (temp_name, (output_format,), "INFO") + job = IJob.create(job_info[0]) job.run(parameters, status=True) + if output_format == "MDAFormat": - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - result_file = os.path.join( - result_dir, f"structure_analysis_{traj_info[0]}_{job_info[0]}.mda" - ) + out_file = temp_name.with_suffix(".mda") + result_file = RESULTS_DIR / f"structure_analysis_{traj_info[0]}_{job_type}.mda" - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - keys = [i for i in desired.keys() if any([j in i for j in job_info[1]])] - for key in keys: - np.testing.assert_array_almost_equal( - actual[f"/{key}"], desired[f"/{key}"] - ) + assert out_file.is_file() + + compare_mdt(out_file, result_file, tuple(outputs), startswith=True) - os.remove(temp_name + ".mda") elif output_format == "TextFormat": - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") + out_file = temp_name.parent / (temp_name.stem + "_text.tar") + assert out_file.is_file() + + assert log_file.is_file() diff --git a/MDANSE/Tests/UnitTests/Analysis/test_thermodynamics.py b/MDANSE/Tests/UnitTests/Analysis/test_thermodynamics.py index ebd2228026..8dccf64d55 100644 --- a/MDANSE/Tests/UnitTests/Analysis/test_thermodynamics.py +++ b/MDANSE/Tests/UnitTests/Analysis/test_thermodynamics.py @@ -1,132 +1,80 @@ -import tempfile -import os -from os import path -import pytest - import numpy as np -import h5py - +import pytest from MDANSE.Framework.Jobs.IJob import IJob +from test_helpers.compare_mdt import compare_mdt +from test_helpers.paths import CONV_DIR, RESULTS_DIR +short_traj = CONV_DIR / "short_trajectory_after_changes.mdt" +com_traj = CONV_DIR / "com_trajectory.mdt" +mdmc_traj = CONV_DIR / "Ar_mdmc_h5md.h5" -short_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "short_trajectory_after_changes.mdt", -) -com_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "com_trajectory.mdt", -) -mdmc_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "Ar_mdmc_h5md.h5", -) -result_dir = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Results", + +@pytest.mark.parametrize("interp_order", [1, 3]) +@pytest.mark.parametrize("traj_info", [ + ("short_traj", short_traj), + ("mdmc_traj", mdmc_traj), + ("com_traj", com_traj), +], ids=lambda x: x[0], ) +def test_temperature(tmp_path, traj_info, interp_order): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + parameters = { + "frames": (0, 10, 1), + "interpolation_order": interp_order, + "output_files": (temp_name, ("MDAFormat",), "INFO"), + "running_mode": ("single-core",), + "trajectory": traj_info[1], + } -@pytest.mark.parametrize( - "traj_info,interp_order", - [ - (("short_traj", short_traj), 1), - (("short_traj", short_traj), 3), - (("mdmc_traj", mdmc_traj), 1), - (("mdmc_traj", mdmc_traj), 3), - (("com_traj", com_traj), 1), - (("com_traj", com_traj), 3), - ], -) -def test_temperature(traj_info, interp_order): - temp_name = tempfile.mktemp() - parameters = {} - parameters["frames"] = (0, 10, 1) - parameters["interpolation_order"] = interp_order - parameters["output_files"] = (temp_name, ("MDAFormat",), "INFO") - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = traj_info[1] temp = IJob.create("Temperature") temp.run(parameters, status=True) - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - result_file = os.path.join( - result_dir, f"temperature_{traj_info[0]}_{interp_order}.mda" - ) - - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - np.testing.assert_array_almost_equal( - actual["/kinetic_energy"], desired["/kinetic_energy"] - ) - np.testing.assert_array_almost_equal( - actual["/temperature"], desired["/temperature"] - ) - np.testing.assert_array_almost_equal( - actual["/avg_kinetic_energy"], desired["/avg_kinetic_energy"] - ) - np.testing.assert_array_almost_equal( - actual["/avg_temperature"], desired["/avg_temperature"] - ) - - os.remove(temp_name + ".mda") - - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") - - -@pytest.mark.parametrize( - "traj_info,output_format", - [ - (("short_traj", short_traj), "MDAFormat"), - (("short_traj", short_traj), "TextFormat"), - (("mdmc_traj", mdmc_traj), "MDAFormat"), - (("mdmc_traj", mdmc_traj), "TextFormat"), - (("com_traj", com_traj), "MDAFormat"), - (("com_traj", com_traj), "TextFormat"), - ], + assert out_file.is_file() + assert log_file.is_file() + + result_file = RESULTS_DIR / f"temperature_{traj_info[0]}_{interp_order}.mda" + + compare_mdt(out_file, result_file, ("/kinetic_energy", "/temperature", + "/avg_kinetic_energy", "avg_temperature")) + + + +@pytest.mark.parametrize("traj_info", [ + ("short_traj", short_traj), + ("mdmc_traj", mdmc_traj), + ("com_traj", com_traj), +], ids=lambda x: x[0], ) -def test_density(traj_info, output_format): - temp_name = tempfile.mktemp() - parameters = {} - parameters["frames"] = (0, 10, 1) - parameters["output_files"] = (temp_name, (output_format,), "INFO") - parameters["running_mode"] = ("single-core",) - parameters["trajectory"] = traj_info[1] +@pytest.mark.parametrize("output_format", ["MDAFormat", "TextFormat"]) +def test_density(tmp_path, traj_info, output_format): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mda") + log_file = temp_name.with_suffix(".log") + + parameters = { + "frames": (0, 10, 1), + "output_files": (temp_name, (output_format,), "INFO"), + "running_mode": ("single-core",), + "trajectory": traj_info[1], + } den = IJob.create("Density") den.run(parameters, status=True) + if output_format == "MDAFormat": - assert path.exists(temp_name + ".mda") - assert path.isfile(temp_name + ".mda") - result_file = os.path.join(result_dir, f"density_{traj_info[0]}.mda") - - with h5py.File(temp_name + ".mda") as actual, h5py.File(result_file) as desired: - np.testing.assert_array_almost_equal( - actual["/atomic_density"], desired["/atomic_density"] - ) - np.testing.assert_array_almost_equal( - actual["/mass_density"], desired["/mass_density"] - ) - np.testing.assert_array_almost_equal( - actual["/avg_atomic_density"], desired["/avg_atomic_density"] - ) - np.testing.assert_array_almost_equal( - actual["/avg_mass_density"], desired["/avg_mass_density"] - ) - - os.remove(temp_name + ".mda") + out_file = temp_name.with_suffix(".mda") + result_file = RESULTS_DIR / f"density_{traj_info[0]}.mda" + + assert out_file.is_file() + + compare_mdt(out_file, result_file, ("/atomic_density", "/mass_density", + "/avg_atomic_density", "/avg_mass_density"), + startswith=True) + elif output_format == "TextFormat": - assert path.exists(temp_name + "_text.tar") - assert path.isfile(temp_name + "_text.tar") - os.remove(temp_name + "_text.tar") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") + out_file = temp_name.parent / (temp_name.stem + "_text.tar") + assert out_file.is_file() + + assert log_file.is_file() diff --git a/MDANSE/Tests/UnitTests/Analysis/test_trajectory.py b/MDANSE/Tests/UnitTests/Analysis/test_trajectory.py index ffa9f03492..fecbb87dad 100644 --- a/MDANSE/Tests/UnitTests/Analysis/test_trajectory.py +++ b/MDANSE/Tests/UnitTests/Analysis/test_trajectory.py @@ -4,14 +4,9 @@ import pytest from MDANSE.Framework.Jobs.IJob import IJob +from test_helpers.paths import CONV_DIR - -short_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - "..", - "Converted", - "short_trajectory_after_changes.mdt", -) +short_traj = CONV_DIR / "short_trajectory_after_changes.mdt" ################################################################ @@ -46,70 +41,24 @@ def parameters(): parameters["weights"] = "equal" return parameters +@pytest.mark.parametrize("traj_type", [ + pytest.param("RigidBodyTrajectory", + marks=pytest.mark.xfail()), + pytest.param("GlobalMotionFilteredTrajectory", + marks=pytest.mark.xfail()), + "CroppedTrajectory", + "CenterOfMassesTrajectory", + "UnfoldedTrajectory", +]) +def test_trajectory(tmp_path, parameters, traj_type): + temp_name = tmp_path / "output" + out_file = temp_name.with_suffix(".mdt") + log_file = temp_name.with_suffix(".log") -@pytest.mark.xfail(reason="see docstring") -def test_RigidBodyTrajectory(parameters): - """We ignore the failure to merge other changes.""" - temp_name = tempfile.mktemp() - parameters["output_files"] = (temp_name, 64, 128, "gzip", "INFO") - job = IJob.create("RigidBodyTrajectory") - job.run(parameters, status=True) - assert path.exists(temp_name + ".mdt") - assert path.isfile(temp_name + ".mdt") - os.remove(temp_name + ".mdt") - - -@pytest.mark.xfail(reason="see docstring") -def test_GlobalMotionFilteredTrajectory(parameters): - """We ignore the failure here to merge other changes.""" - temp_name = tempfile.mktemp() parameters["output_files"] = (temp_name, 64, 128, "gzip", "INFO") - job = IJob.create("GlobalMotionFilteredTrajectory") - job.run(parameters, status=True) - assert path.exists(temp_name + ".mdt") - assert path.isfile(temp_name + ".mdt") - os.remove(temp_name + ".mdt") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") - -def test_CroppedTrajectory(parameters): - temp_name = tempfile.mktemp() - parameters["output_files"] = (temp_name, 64, 128, "gzip", "INFO") - job = IJob.create("CroppedTrajectory") + job = IJob.create(traj_type) job.run(parameters, status=True) - assert path.exists(temp_name + ".mdt") - assert path.isfile(temp_name + ".mdt") - os.remove(temp_name + ".mdt") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") - -def test_CenterOfMassesTrajectory(parameters): - """This will need to detect molecules before it can - find the centre of each one of them.""" - temp_name = tempfile.mktemp() - parameters["output_files"] = (temp_name, 64, 128, "gzip", "INFO") - job = IJob.create("CenterOfMassesTrajectory") - job.run(parameters, status=True) - assert path.exists(temp_name + ".mdt") - assert path.isfile(temp_name + ".mdt") - os.remove(temp_name + ".mdt") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") - - -def test_UnfoldedTrajectory(parameters): - temp_name = tempfile.mktemp() - parameters["output_files"] = (temp_name, 64, 128, "gzip", "INFO") - job = IJob.create("UnfoldedTrajectory") - job.run(parameters, status=True) - assert path.exists(temp_name + ".mdt") - assert path.isfile(temp_name + ".mdt") - os.remove(temp_name + ".mdt") - assert path.exists(temp_name + ".log") - assert path.isfile(temp_name + ".log") - os.remove(temp_name + ".log") + assert out_file.exists() + assert log_file.exists() diff --git a/MDANSE/Tests/UnitTests/AtomTransmutation/test_transmutation.py b/MDANSE/Tests/UnitTests/AtomTransmutation/test_transmutation.py index 60e92cc42a..8c6d19b3c8 100644 --- a/MDANSE/Tests/UnitTests/AtomTransmutation/test_transmutation.py +++ b/MDANSE/Tests/UnitTests/AtomTransmutation/test_transmutation.py @@ -1,12 +1,11 @@ -import os +from contextlib import nullcontext as success + import pytest from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData from MDANSE.Framework.Configurators.AtomTransmutationConfigurator import AtomTransmuter +from test_helpers.paths import CONV_DIR - -traj_2vb1 = os.path.join( - os.path.dirname(os.path.realpath(__file__)), "..", "Converted", "2vb1.mdt" -) +traj_2vb1 = CONV_DIR / "2vb1.mdt" @pytest.fixture(scope="module") @@ -14,110 +13,43 @@ def protein_trajectory(): protein_trajectory = HDFTrajectoryInputData(traj_2vb1) return protein_trajectory.trajectory - -def test_atom_transmutation_returns_empty_dictionary_when_no_transmutations_are_made( - protein_trajectory, -): - atm_transmuter = AtomTransmuter(protein_trajectory) - mapping = atm_transmuter.get_setting() - assert mapping == {} - - -def test_atom_transmutation_return_dict_with_transmutations_with_incorrect_element_raises_exception( - protein_trajectory, -): - atm_transmuter = AtomTransmuter(protein_trajectory) - with pytest.raises(ValueError): - atm_transmuter.apply_transmutation( - {"all": False, "element": {"S": True}}, "CCC" - ) - - -def test_atom_transmutation_return_dict_with_transmutations_with_s_element_transmutation( - protein_trajectory, -): - atm_transmuter = AtomTransmuter(protein_trajectory) - atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C") - mapping = atm_transmuter.get_setting() - assert mapping == { - 98: "C", - 175: "C", - 468: "C", - 990: "C", - 1160: "C", - 1217: "C", - 1404: "C", - 1557: "C", - 1731: "C", - 1913: "C", - } - - -def test_atom_transmutation_return_dict_with_transmutations_with_s_element_transmutation_and_index_98_transmutation_0( - protein_trajectory, -): +@pytest.mark.parametrize("transmutations, expected", [ + ((), success({})), + + ([({"all": False, "element": {"S": True}}, "CCC")], + pytest.raises(ValueError, match="CCC not found in the atom database")), + + ([({"all": False, "element": {"S": True}}, "C")], + success({98: "C", 175: "C", 468: "C", 990: "C", 1160: "C", + 1217: "C", 1404: "C", 1557: "C", 1731: "C", 1913: "C"}), + ), + + ([({"all": False, "element": {"S": True}}, "C"), + ({"all": False, "index": {98: True}}, "N")], + success({98: "N", 175: "C", 468: "C", 990: "C", 1160: "C", + 1217: "C", 1404: "C", 1557: "C", 1731: "C", 1913: "C"}), + ), + + ([({"all": False, "element": {"S": True}}, "C"), + ({"all": False, "index": {98: True}}, "S")], + success({175: "C", 468: "C", 990: "C", 1160: "C", 1217: "C", + 1404: "C", 1557: "C", 1731: "C", 1913: "C"}), + ), + + ([({"all": False, "element": {"S": True}}, "C"), + ({"all": False, "index": {98: True, 99: True}}, "S")], + success({99: "S", 175: "C", 468: "C", 990: "C", 1160: "C", + 1217: "C", 1404: "C", 1557: "C", 1731: "C", 1913: "C"}), + ), +]) +def test_atom_transmutation(protein_trajectory, transmutations, expected): atm_transmuter = AtomTransmuter(protein_trajectory) - atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C") - atm_transmuter.apply_transmutation({"all": False, "index": {98: True}}, "N") - mapping = atm_transmuter.get_setting() - assert mapping == { - 98: "N", - 175: "C", - 468: "C", - 990: "C", - 1160: "C", - 1217: "C", - 1404: "C", - 1557: "C", - 1731: "C", - 1913: "C", - } - - -def test_atom_transmutation_return_dict_with_transmutations_with_s_element_transmutation_and_index_98_transmutation_1( - protein_trajectory, -): - atm_transmuter = AtomTransmuter(protein_trajectory) - atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C") - atm_transmuter.apply_transmutation({"all": False, "index": {98: True}}, "S") - mapping = atm_transmuter.get_setting() - assert mapping == { - 175: "C", - 468: "C", - 990: "C", - 1160: "C", - 1217: "C", - 1404: "C", - 1557: "C", - 1731: "C", - 1913: "C", - } - - -def test_atom_transmutation_return_dict_with_transmutations_with_s_element_transmutation_and_index_98_transmutation_2( - protein_trajectory, -): - atm_transmuter = AtomTransmuter(protein_trajectory) - atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C") - atm_transmuter.apply_transmutation( - {"all": False, "index": {98: True, 99: True}}, "S" - ) - mapping = atm_transmuter.get_setting() - assert mapping == { - 99: "S", - 175: "C", - 468: "C", - 990: "C", - 1160: "C", - 1217: "C", - 1404: "C", - 1557: "C", - 1731: "C", - 1913: "C", - } - + with expected as val: + for transmute in transmutations: + atm_transmuter.apply_transmutation(*transmute) + assert atm_transmuter.get_setting() == val -def test_atom_transmutation_return_empty_dict_after_reset(protein_trajectory): +def test_atom_transmutation_reset(protein_trajectory): atm_transmuter = AtomTransmuter(protein_trajectory) atm_transmuter.apply_transmutation({"all": False, "element": {"S": True}}, "C") atm_transmuter.apply_transmutation( diff --git a/MDANSE/Tests/UnitTests/NeutronInstrument/test_instrument.py b/MDANSE/Tests/UnitTests/NeutronInstrument/test_instrument.py index f2f192eb9b..5303a72b3a 100644 --- a/MDANSE/Tests/UnitTests/NeutronInstrument/test_instrument.py +++ b/MDANSE/Tests/UnitTests/NeutronInstrument/test_instrument.py @@ -1,9 +1,10 @@ -from MDANSE.NeutronInstruments.NeutronInstrument import NeutronInstrument +import pytest from MDANSE.NeutronInstruments.IdealInstrument import IdealInstrument +from MDANSE.NeutronInstruments.NeutronInstrument import NeutronInstrument -def test_blank_instrument(): - print(NeutronInstrument.subclasses()) - instance = NeutronInstrument.create("IdealInstrument") +@pytest.mark.parametrize("instrument_type", NeutronInstrument.subclasses()) +def test_instrument(instrument_type): + instance = NeutronInstrument.create(instrument_type) assert issubclass(instance.__class__, NeutronInstrument) - assert isinstance(instance, IdealInstrument) + assert type(instance).__name__ == instrument_type diff --git a/MDANSE/Tests/UnitTests/TrajectoryEditor/test_editor.py b/MDANSE/Tests/UnitTests/TrajectoryEditor/test_editor.py index dd8960b124..2d8a86ccd4 100644 --- a/MDANSE/Tests/UnitTests/TrajectoryEditor/test_editor.py +++ b/MDANSE/Tests/UnitTests/TrajectoryEditor/test_editor.py @@ -6,9 +6,9 @@ from MDANSE.MolecularDynamics.Configuration import remove_jumps from test_helpers.compare_mdt import compare_mdt from test_helpers.get_deep_attr import get_deep_attr -from test_helpers.paths import CONV_DIR, CONV_PATH +from test_helpers.paths import CONV_DIR, CONV_DIR -short_traj = CONV_PATH / "trajectory_no_unit_cell.mdt" +short_traj = CONV_DIR / "trajectory_no_unit_cell.mdt" CHARGE_ARRAY = [1.2, 1.2, 1.2, 1.2, 1.2, 1.2, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, diff --git a/MDANSE/Tests/UnitTests/molecules/test_chemistry.py b/MDANSE/Tests/UnitTests/molecules/test_chemistry.py index a3df2918a8..777baf371d 100644 --- a/MDANSE/Tests/UnitTests/molecules/test_chemistry.py +++ b/MDANSE/Tests/UnitTests/molecules/test_chemistry.py @@ -1,11 +1,8 @@ -import os import pytest from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData +from test_helpers.paths import CONV_DIR - -short_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), "..", "Converted", "co2gas_md3.mdt" -) +short_traj = CONV_DIR / "co2gas_md3.mdt" @pytest.fixture(scope="module") diff --git a/MDANSE/Tests/UnitTests/molecules/test_connectivity.py b/MDANSE/Tests/UnitTests/molecules/test_connectivity.py index 2497c6a8a5..8690a8eee6 100644 --- a/MDANSE/Tests/UnitTests/molecules/test_connectivity.py +++ b/MDANSE/Tests/UnitTests/molecules/test_connectivity.py @@ -1,49 +1,46 @@ -import os import pytest from MDANSE.MolecularDynamics.Connectivity import Connectivity from MDANSE.Framework.InputData.HDFTrajectoryInputData import HDFTrajectoryInputData from MDANSE.MolecularDynamics.Trajectory import Trajectory +from test_helpers.paths import CONV_DIR - -short_traj = os.path.join( - os.path.dirname(os.path.realpath(__file__)), "..", "Converted", "co2gas_md3.mdt" -) +short_traj = CONV_DIR / "co2gas_md3.mdt" @pytest.fixture -def trajectory() -> HDFTrajectoryInputData: +def trajectory(): trajectory = HDFTrajectoryInputData(short_traj) yield trajectory.trajectory +@pytest.fixture +def connectivity(trajectory): + conn = Connectivity(trajectory=trajectory) + conn.find_bonds() + return conn -def test_create_connectivity(trajectory: Trajectory): +def test_create_connectivity(trajectory): conn = Connectivity(trajectory=trajectory) - print(conn._unique_elements) assert len(conn._unique_elements) == 2 -def test_find_molecules(trajectory: Trajectory): - conn = Connectivity(trajectory=trajectory) - conn.find_bonds() - assert len(conn._unique_bonds) == 40 - conn.add_bond_information(trajectory.chemical_system) - molecules_found = 0 - for name in trajectory.chemical_system.unique_molecules(): - molecules_found += trajectory.chemical_system.number_of_molecules(name) +def test_find_molecules(trajectory, connectivity): + assert len(connectivity._unique_bonds) == 40 + + connectivity.add_bond_information(trajectory.chemical_system) + + csys = trajectory.chemical_system + molecules_found = sum(csys.number_of_molecules(name) + for name in csys.unique_molecules()) assert molecules_found == 20 -def test_identify_molecules(trajectory: Trajectory): - conn = Connectivity(trajectory=trajectory) - conn.find_bonds() +def test_identify_molecules(trajectory, connectivity): + connectivity.find_bonds() chemical_system = trajectory.chemical_system - conn.add_bond_information(chemical_system) + connectivity.add_bond_information(chemical_system) + molstrings = [] - for molname, mollist in chemical_system._clusters.items(): - assert len(mollist) == 20 - result = True - for ms in molstrings[1:]: - result = result and ms == molstrings[0] - assert result - print(chemical_system.unique_molecules()) + assert all(len(mollist) == 20 + for mollist in chemical_system._clusters.values()) + assert all(ms == molstrings[0] for ms in molstrings[1:]) assert len(chemical_system.unique_molecules()) == 1 diff --git a/MDANSE/Tests/UnitTests/molecules/test_rdkit.py b/MDANSE/Tests/UnitTests/molecules/test_rdkit.py index 7d6913f5a6..e32c70c6e7 100644 --- a/MDANSE/Tests/UnitTests/molecules/test_rdkit.py +++ b/MDANSE/Tests/UnitTests/molecules/test_rdkit.py @@ -1,17 +1,13 @@ -import os import numpy as np -from rdkit.Chem.rdmolfiles import MolFromPDBFile -from rdkit.Chem.rdchem import Mol, GetPeriodicTable -from rdkit.Chem.rdmolops import SanitizeMol -from rdkit.Chem.rdmolops import GetMolFrags import pytest -from MDANSE.IO.MinimalPDBReader import MinimalPDBReader as PDBReader from MDANSE.Chemistry.ChemicalSystem import ChemicalSystem +from MDANSE.IO.MinimalPDBReader import MinimalPDBReader as PDBReader +from rdkit.Chem.rdchem import GetPeriodicTable, Mol +from rdkit.Chem.rdmolfiles import MolFromPDBFile +from rdkit.Chem.rdmolops import GetMolFrags, SanitizeMol +from test_helpers.paths import DATA_DIR - -fname = os.path.join( - os.path.dirname(os.path.realpath(__file__)), "..", "Data", "CO2GAS-dump-1.pdb" -) +fname = DATA_DIR / "CO2GAS-dump-1.pdb" @pytest.fixture() @@ -43,9 +39,8 @@ def test_rdkit(mol_from_rdkit: Mol): def test_splitting(mol_from_rdkit: Mol): gas_bits = GetMolFrags(mol_from_rdkit, asMols=True) - all_lengths = np.array([mol.GetNumAtoms() for mol in gas_bits]) assert len(gas_bits) == 20 - assert np.all(all_lengths == 3) + assert all(mol.GetNumAtoms() == 3 for mol in gas_bits) def test_periodic(): @@ -54,4 +49,3 @@ def test_periodic(): cov = ptable.GetRcovalent(element) vdw = ptable.GetRvdw(element) print(element, cov, vdw) - # assert False # this was just to trigger the printout diff --git a/MDANSE/Tests/pytest.ini b/MDANSE/Tests/pytest.ini deleted file mode 100644 index 712b790c6c..0000000000 --- a/MDANSE/Tests/pytest.ini +++ /dev/null @@ -1,4 +0,0 @@ -[pytest] -pythonpath = "CommonFunctions" -testpaths = "tests" -addopts = "--import-mode=importlib" \ No newline at end of file diff --git a/MDANSE/pyproject.toml b/MDANSE/pyproject.toml index 324f6b67a3..ff3650ad84 100644 --- a/MDANSE/pyproject.toml +++ b/MDANSE/pyproject.toml @@ -59,6 +59,10 @@ MDANSE = ["Chemistry/*.json", mdanse = "MDANSE.Scripts.mdanse:main" [tool.pytest.ini_options] +minversion = "6.0" +testpaths = "Tests" +pythonpath = "Tests/CommonFunctions" +addopts = "--import-mode=importlib" timeout = 240 [tool.ruff]