diff --git a/pyprobe/cyclers/arbin.py b/pyprobe/cyclers/arbin.py index 956ea4f0..a42f0418 100644 --- a/pyprobe/cyclers/arbin.py +++ b/pyprobe/cyclers/arbin.py @@ -18,4 +18,4 @@ class Arbin(BaseCycler): "Discharge Capacity (*)": "Discharge Capacity [*]", "Aux_Temperature_1 (*)": "Temperature [*]", } - datetime_format: str = "%d/%m/%Y %H:%M:%S%.f" + datetime_format: str = "%m/%d/%Y %H:%M:%S%.f" diff --git a/pyprobe/cyclers/basecycler.py b/pyprobe/cyclers/basecycler.py index ecc63f38..fe39cc35 100644 --- a/pyprobe/cyclers/basecycler.py +++ b/pyprobe/cyclers/basecycler.py @@ -375,8 +375,10 @@ def date(self) -> pl.Expr: Returns: pl.Expr: A polars expression for the date column. """ - return pl.col("Date").str.to_datetime( - format=self.datetime_format, time_unit="us" + return ( + pl.col("Date") + .str.strip_chars() + .str.to_datetime(format=self.datetime_format, time_unit="us") ) @property diff --git a/tests/cyclers/__init__.py b/tests/cyclers/__init__.py new file mode 100644 index 00000000..a10ccdd8 --- /dev/null +++ b/tests/cyclers/__init__.py @@ -0,0 +1 @@ +"""Module for tests of the cyclers module.""" diff --git a/tests/cyclers/test_arbin.py b/tests/cyclers/test_arbin.py index 4f90ad96..02ead5c2 100644 --- a/tests/cyclers/test_arbin.py +++ b/tests/cyclers/test_arbin.py @@ -1,29 +1,35 @@ """Tests for the Arbin cycler class.""" +from datetime import datetime + +import polars as pl + from pyprobe.cyclers.arbin import Arbin +from .test_basecycler import helper_read_and_process + def test_read_and_process_arbin(benchmark): """Test the full process of reading and processing a file.""" arbin_cycler = Arbin( input_data_path="tests/sample_data/arbin/sample_data_arbin.csv" ) - - def read_and_process(): - return arbin_cycler.pyprobe_dataframe - - pyprobe_dataframe = benchmark(read_and_process) - expected_columns = [ - "Date", - "Time [s]", - "Step", - "Event", - "Current [A]", - "Voltage [V]", - "Capacity [Ah]", - "Temperature [C]", - ] - assert set(pyprobe_dataframe.columns) == set(expected_columns) - assert set( - pyprobe_dataframe.select("Event").unique().collect().to_series().to_list() - ) == set([0, 1, 2]) + expected_df = pl.DataFrame( + { + "Date": [datetime(2024, 9, 20, 8, 37, 5, 772000)], + "Time [s]": [301.214], + "Step": [3], + "Event": [2], + "Current [A]": [2.650138], + "Voltage [V]": [3.599601], + "Capacity [Ah]": [0.0007812400999999999], + "Temperature [C]": [24.68785], + } + ) + expected_events = set([0, 1, 2]) + helper_read_and_process( + benchmark, + arbin_cycler, + expected_final_row=expected_df, + expected_events=expected_events, + ) diff --git a/tests/cyclers/test_basecycler.py b/tests/cyclers/test_basecycler.py index 06578f52..af083556 100644 --- a/tests/cyclers/test_basecycler.py +++ b/tests/cyclers/test_basecycler.py @@ -6,6 +6,7 @@ import polars as pl import polars.testing as pl_testing import pytest +from polars.testing import assert_frame_equal from pyprobe.cyclers.basecycler import BaseCycler @@ -126,6 +127,42 @@ def sample_column_map(): } +def helper_read_and_process( + benchmark, + cycler_instance, + expected_final_row, + expected_events, + expected_columns=[ + "Date", + "Time [s]", + "Step", + "Event", + "Current [A]", + "Voltage [V]", + "Capacity [Ah]", + "Temperature [C]", + ], +): + """A helper function for other cyclers to test processing raw data files.""" + + def read_and_process(): + result = cycler_instance.pyprobe_dataframe + if isinstance(result, pl.LazyFrame): + return result.collect() + else: + return result + + pyprobe_dataframe = benchmark(read_and_process) + print(pyprobe_dataframe.tail(1)) + assert set(pyprobe_dataframe.columns) == set(expected_columns) + assert ( + set(pyprobe_dataframe.select("Event").unique().to_series().to_list()) + == expected_events + ) + assert_frame_equal(expected_final_row, pyprobe_dataframe.tail(1)) + return pyprobe_dataframe + + def test_input_data_path_validator(): """Test the input data path validator.""" # test with invalid path diff --git a/tests/cyclers/test_basytec.py b/tests/cyclers/test_basytec.py index b4335aa7..77a8e302 100644 --- a/tests/cyclers/test_basytec.py +++ b/tests/cyclers/test_basytec.py @@ -3,10 +3,11 @@ from datetime import datetime import polars as pl -from polars.testing import assert_frame_equal from pyprobe.cyclers.basytec import Basytec +from .test_basecycler import helper_read_and_process + def test_read_file_basytec(): """Test reading a Basytec file.""" @@ -18,24 +19,12 @@ def test_read_file_basytec(): assert dataframe["Date"][2] == "2023-06-19 17:56:54.002823" -def test_read_and_process_basytec(): +def test_read_and_process_basytec(benchmark): """Test the full process of reading and processing a file.""" basytec_cycler = Basytec( input_data_path="tests/sample_data/basytec/sample_data_basytec.txt" ) - pyprobe_dataframe = basytec_cycler.pyprobe_dataframe - expected_columns = [ - "Date", - "Time [s]", - "Step", - "Event", - "Current [A]", - "Voltage [V]", - "Capacity [Ah]", - "Temperature [C]", - ] - assert set(pyprobe_dataframe.columns) == set(expected_columns) - last_row = pl.LazyFrame( + last_row = pl.DataFrame( { "Date": datetime(2023, 6, 19, 17, 58, 3, 235803), "Time [s]": [70.235804], @@ -47,4 +36,9 @@ def test_read_and_process_basytec(): "Temperature [C]": [25.47953], } ) - assert_frame_equal(pyprobe_dataframe.tail(1), last_row) + helper_read_and_process( + benchmark, + basytec_cycler, + expected_final_row=last_row, + expected_events=set([0, 1]), + ) diff --git a/tests/cyclers/test_biologic.py b/tests/cyclers/test_biologic.py index 64e3309a..feaabe18 100644 --- a/tests/cyclers/test_biologic.py +++ b/tests/cyclers/test_biologic.py @@ -7,6 +7,8 @@ from pyprobe.cyclers.biologic import Biologic, BiologicMB +from .test_basecycler import helper_read_and_process + @pytest.fixture def biologic_MB_cycler(): @@ -60,25 +62,26 @@ def test_sort_files(): ] -def test_read_and_process(benchmark, biologic_cycler, biologic_MB_cycler): +def test_read_and_process_biologic(benchmark, biologic_cycler): """Test the full process of reading and processing a file.""" - - def read_and_process(): - return biologic_cycler.pyprobe_dataframe - - pyprobe_dataframe = benchmark(read_and_process) - - expected_columns = [ - "Date", - "Time [s]", - "Step", - "Event", - "Current [A]", - "Voltage [V]", - "Capacity [Ah]", - "Temperature [C]", - ] - assert set(pyprobe_dataframe.columns) == set(expected_columns) + last_row = pl.DataFrame( + { + "Date": [datetime(2024, 5, 13, 11, 19, 51, 602139)], + "Time [s]": [139.524007], + "Step": [1], + "Event": [1], + "Current [A]": [-0.899826], + "Voltage [V]": [3.4854481], + "Capacity [Ah]": [-0.03237135133365209], + "Temperature [C]": [23.029291], + } + ) + pyprobe_dataframe = helper_read_and_process( + benchmark, + biologic_cycler, + expected_final_row=last_row, + expected_events=set([0, 1]), + ) pyprobe_dataframe = pyprobe_dataframe.with_columns( [ pl.col("Time [s]").diff().fill_null(strategy="zero").alias("dt"), @@ -86,26 +89,31 @@ def read_and_process(): pl.col("Step").diff().fill_null(strategy="zero").alias("ds"), ] ) - assert not any(pyprobe_dataframe.select(pl.col("dt") < 0).collect().to_numpy()) - assert not any(pyprobe_dataframe.select(pl.col("dd") < 0).collect().to_numpy()) - assert not any(pyprobe_dataframe.select(pl.col("ds") < 0).collect().to_numpy()) - steps = list( - pyprobe_dataframe.select(pl.col("Step")).collect().unique().to_numpy().flatten() - ) - assert set(steps) == set([0, 1]) + assert not any(pyprobe_dataframe.select(pl.col("dt") < 0).to_numpy()) + assert not any(pyprobe_dataframe.select(pl.col("dd") < 0).to_numpy()) + assert not any(pyprobe_dataframe.select(pl.col("ds") < 0).to_numpy()) - pyprobe_dataframe = biologic_MB_cycler.pyprobe_dataframe - expected_columns = [ - "Date", - "Time [s]", - "Step", - "Event", - "Current [A]", - "Voltage [V]", - "Capacity [Ah]", - "Temperature [C]", - ] - assert set(pyprobe_dataframe.columns) == set(expected_columns) + +def test_read_and_process_biologic_MB(benchmark, biologic_MB_cycler): + """Test the full process of reading and processing modulo bat files.""" + last_row = pl.DataFrame( + { + "Date": [datetime(2024, 5, 13, 11, 19, 51, 858016)], + "Time [s]": [256016.11344], + "Step": [5], + "Event": [5], + "Current [A]": [0.450135], + "Voltage [V]": [3.062546], + "Capacity [Ah]": [0.307727], + "Temperature [C]": [22.989878], + } + ) + pyprobe_dataframe = helper_read_and_process( + benchmark, + biologic_MB_cycler, + expected_final_row=last_row, + expected_events=set([0, 1, 2, 3, 4, 5]), + ) pyprobe_dataframe = pyprobe_dataframe.with_columns( [ pl.col("Time [s]").diff().fill_null(strategy="zero").alias("dt"), @@ -113,13 +121,9 @@ def read_and_process(): pl.col("Step").diff().fill_null(strategy="zero").alias("ds"), ] ) - assert not any(pyprobe_dataframe.select(pl.col("dt") < 0).collect().to_numpy()) - assert not any(pyprobe_dataframe.select(pl.col("dd") < 0).collect().to_numpy()) - assert not any(pyprobe_dataframe.select(pl.col("ds") < 0).collect().to_numpy()) - steps = list( - pyprobe_dataframe.select(pl.col("Step")).collect().unique().to_numpy().flatten() - ) - assert set(steps) == set([0, 1, 2, 3, 4, 5]) + assert not any(pyprobe_dataframe.select(pl.col("dt") < 0).to_numpy()) + assert not any(pyprobe_dataframe.select(pl.col("dd") < 0).to_numpy()) + assert not any(pyprobe_dataframe.select(pl.col("ds") < 0).to_numpy()) def test_process_dataframe(monkeypatch): diff --git a/tests/cyclers/test_maccor.py b/tests/cyclers/test_maccor.py index f74ad976..1a3799c2 100644 --- a/tests/cyclers/test_maccor.py +++ b/tests/cyclers/test_maccor.py @@ -7,25 +7,15 @@ from pyprobe.cyclers.maccor import Maccor +from .test_basecycler import helper_read_and_process -def test_read_and_process_maccor(): + +def test_read_and_process_maccor(benchmark): """Test reading and processing a sample Maccor file.""" maccor_cycler = Maccor( input_data_path="tests/sample_data/maccor/sample_data_maccor.csv" ) - pyprobe_dataframe = maccor_cycler.pyprobe_dataframe - expected_columns = [ - "Date", - "Time [s]", - "Step", - "Event", - "Current [A]", - "Voltage [V]", - "Capacity [Ah]", - "Temperature [C]", - ] - assert set(pyprobe_dataframe.columns) == set(expected_columns) - last_row = pl.LazyFrame( + last_row = pl.DataFrame( { "Date": datetime(2023, 11, 23, 15, 56, 24, 60000), "Time [s]": [13.06], @@ -37,7 +27,12 @@ def test_read_and_process_maccor(): "Temperature [C]": [22.2591], } ) - assert_frame_equal(pyprobe_dataframe.tail(1), last_row) + helper_read_and_process( + benchmark, + maccor_cycler, + expected_final_row=last_row, + expected_events=set([0, 1]), + ) @pytest.fixture diff --git a/tests/cyclers/test_neware.py b/tests/cyclers/test_neware.py index 306790b3..0c3bde8a 100644 --- a/tests/cyclers/test_neware.py +++ b/tests/cyclers/test_neware.py @@ -8,6 +8,8 @@ from pyprobe.cyclers.neware import Neware +from .test_basecycler import helper_read_and_process + @pytest.fixture def neware_cycler(): @@ -169,14 +171,20 @@ def test_process_dataframe(): os.remove("tests/sample_data/mock_dataframe.xlsx") -def test_read_and_process(benchmark, neware_cycler): +def test_read_and_process_neware(benchmark, neware_cycler): """Test the full process of reading and processing a file.""" - - def read_and_process(): - return neware_cycler.pyprobe_dataframe - - pyprobe_dataframe = benchmark(read_and_process) - rows = pyprobe_dataframe.shape[0] + last_row = pl.DataFrame( + { + "Date": [datetime(2024, 3, 6, 21, 39, 38, 591000)], + "Time [s]": [562749.497], + "Step": [12], + "Event": [61], + "Current [A]": [0.0], + "Voltage [V]": [3.4513], + "Capacity [Ah]": [0.022805], + } + ) + expected_events = set(range(62)) expected_columns = [ "Date", "Time [s]", @@ -186,12 +194,38 @@ def read_and_process(): "Voltage [V]", "Capacity [Ah]", ] - assert isinstance(pyprobe_dataframe, pl.DataFrame) - assert set(pyprobe_dataframe.columns) == set(expected_columns) + helper_read_and_process( + benchmark, neware_cycler, last_row, expected_events, expected_columns + ) + +def test_read_and_process_neware_multi_file(benchmark): + """Test the full process of reading and processing multiple Neware files.""" neware_cycler = Neware( input_data_path="tests/sample_data/neware/sample_data_neware*.xlsx" ) - pyprobe_dataframe = neware_cycler.pyprobe_dataframe - assert pyprobe_dataframe.shape[0] == rows * 2 - assert set(pyprobe_dataframe.columns) == set(expected_columns) + + last_row = pl.DataFrame( + { + "Date": [datetime(2024, 3, 6, 21, 39, 38, 591000)], + "Time [s]": [562749.497], + "Step": [12], + "Event": [123], + "Current [A]": [0.0], + "Voltage [V]": [3.4513], + "Capacity [Ah]": [0.004219859999949997], + } + ) + expected_events = set(range(124)) + expected_columns = [ + "Date", + "Time [s]", + "Step", + "Event", + "Current [A]", + "Voltage [V]", + "Capacity [Ah]", + ] + helper_read_and_process( + benchmark, neware_cycler, last_row, expected_events, expected_columns + ) diff --git a/tests/sample_data/arbin/sample_data_arbin.csv b/tests/sample_data/arbin/sample_data_arbin.csv index c8c47269..65345954 100644 --- a/tests/sample_data/arbin/sample_data_arbin.csv +++ b/tests/sample_data/arbin/sample_data_arbin.csv @@ -1,14 +1,14 @@ Data Point,Date Time,Test Time (s),Step Time (s),Cycle Index,Step Index,TC_Counter1,TC_Counter2,TC_Counter3,Current (A),Voltage (V),Power (W),Charge Capacity (Ah),Discharge Capacity (Ah),Charge Energy (Wh),Discharge Energy (Wh),Capacity (Ah),mAh/g,ACR (Ohm),dV/dt (V/s),Internal Resistance (Ohm),dQ/dV (Ah/V),dV/dQ (V/Ah),Aux_Temperature_1 (C),Aux_dT/dt_1 (C/s) -1," 09/20/2024 08:32:34.558",30.0005,30.0005,1,1,0,0,0,0,3.534595,0,0,0,0,0,0,0,,1.98217E-05,,,,24.66422,-0.09131343 -2," 09/20/2024 08:33:04.559",60.0008,60.0008,1,1,0,0,0,0,3.534597,0,0,0,0,0,0,0,,2.71962E-05,,,,24.73967,0.02648412 -3," 09/20/2024 08:33:34.559",90.0013,90.0013,1,1,0,0,0,0,3.534578,0,0,0,0,0,0,0,,1.00484E-05,,,,24.71824,0.04604245 -4," 09/20/2024 08:34:04.559",120.0016,120.0016,1,1,0,0,0,0,3.534572,0,0,0,0,0,0,0,,2.60919E-05,,,,24.63211,-0.09084845 -5," 09/20/2024 08:34:34.560",150.0017,150.0017,1,1,0,0,0,0,3.534552,0,0,0,0,0,0,0,,1.1247E-05,,0,0,24.75344,0.06064539 -6," 09/20/2024 08:35:04.560",180.0019,180.0019,1,1,0,0,0,0,3.534617,0,0,0,0,0,0,0,,9.40362E-06,,,,24.62239,-0.1132662 -7," 09/20/2024 08:35:34.560",210.0021,210.0021,1,1,0,0,0,0,3.534601,0,0,0,0,0,0,0,,2.22192E-05,,,,24.75955,0.01128928 -8," 09/20/2024 08:36:04.560",240.0022,240.0022,1,1,0,0,0,0,3.53458,0,0,0,0,0,0,0,,2.30485E-05,,,,24.721,0.0339758 -9," 09/20/2024 08:36:34.560",270.0025,270.0025,1,1,0,0,0,0,3.534572,0,0,0,0,0,0,0,,2.02819E-05,,0,0,24.73034,0.07981738 -10," 09/20/2024 08:37:04.559",300.0008,300.0008,1,1,0,0,0,0,3.534585,0,0,0,0,0,0,0,,2.2678E-05,0,0,0,24.72579,0.03765556 -11," 09/20/2024 08:37:04.562",300.0039,0.0006,1,2,0,0,0,0,3.534586,0,0,0,0,0,0,0,,2.2678E-05,0,0,0,24.72550637,0.037089043 -12," 09/20/2024 08:37:05.256",300.6979,0.0012,1,3,0,0,0,2.647604,3.594547,9.516937015,2.01404E-05,2.04379E-05,7.1302E-05,7.21224E-05,2.01404E-05,0,,0.119767502,,,,24.66201,-0.08973769 -13," 09/20/2024 08:37:05.772",301.214,0.5173,1,3,0,0,0,2.650138,3.599601,9.539439395,0.000400839,2.04379E-05,0.001441009,7.21224E-05,0.000400839,0,,,,,,24.68785,-0.08973769 \ No newline at end of file +1, 09/20/2024 08:32:34.558,30.0005,30.0005,1,1,0,0,0,0,3.534595,0,0,0,0,0,0,0,,1.98217E-05,,,,24.66422,-0.09131343 +2, 09/20/2024 08:33:04.559,60.0008,60.0008,1,1,0,0,0,0,3.534597,0,0,0,0,0,0,0,,2.71962E-05,,,,24.73967,0.02648412 +3, 09/20/2024 08:33:34.559,90.0013,90.0013,1,1,0,0,0,0,3.534578,0,0,0,0,0,0,0,,1.00484E-05,,,,24.71824,0.04604245 +4, 09/20/2024 08:34:04.559,120.0016,120.0016,1,1,0,0,0,0,3.534572,0,0,0,0,0,0,0,,2.60919E-05,,,,24.63211,-0.09084845 +5, 09/20/2024 08:34:34.560,150.0017,150.0017,1,1,0,0,0,0,3.534552,0,0,0,0,0,0,0,,1.1247E-05,,0,0,24.75344,0.06064539 +6, 09/20/2024 08:35:04.560,180.0019,180.0019,1,1,0,0,0,0,3.534617,0,0,0,0,0,0,0,,9.40362E-06,,,,24.62239,-0.1132662 +7, 09/20/2024 08:35:34.560,210.0021,210.0021,1,1,0,0,0,0,3.534601,0,0,0,0,0,0,0,,2.22192E-05,,,,24.75955,0.01128928 +8, 09/20/2024 08:36:04.560,240.0022,240.0022,1,1,0,0,0,0,3.53458,0,0,0,0,0,0,0,,2.30485E-05,,,,24.721,0.0339758 +9, 09/20/2024 08:36:34.560,270.0025,270.0025,1,1,0,0,0,0,3.534572,0,0,0,0,0,0,0,,2.02819E-05,,0,0,24.73034,0.07981738 +10, 09/20/2024 08:37:04.559,300.0008,300.0008,1,1,0,0,0,0,3.534585,0,0,0,0,0,0,0,,2.2678E-05,0,0,0,24.72579,0.03765556 +11, 09/20/2024 08:37:04.562,300.0039,0.0006,1,2,0,0,0,0,3.534586,0,0,0,0,0,0,0,,2.2678E-05,0,0,0,24.72550637,0.037089043 +12, 09/20/2024 08:37:05.256,300.6979,0.0012,1,3,0,0,0,2.647604,3.594547,9.516937015,2.01404E-05,2.04379E-05,7.1302E-05,7.21224E-05,2.01404E-05,0,,0.119767502,,,,24.66201,-0.08973769 +13, 09/20/2024 08:37:05.772,301.214,0.5173,1,3,0,0,0,2.650138,3.599601,9.539439395,0.000400839,2.04379E-05,0.001441009,7.21224E-05,0.000400839,0,,,,,,24.68785,-0.08973769 \ No newline at end of file