Skip to content

Commit

Permalink
Merge pull request #69 from GES-ppravatto/main
Browse files Browse the repository at this point in the history
Update to tests
  • Loading branch information
Pierpaolo Pravatto authored Jul 6, 2023
2 parents 020aa47 + 8f8ef77 commit c78aad6
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 48 deletions.
26 changes: 23 additions & 3 deletions echemsuite/cellcycling/experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def __iter__(self):
for cycle in cellcycling:
yield cycle


@property
def reference(self) -> Tuple[int, int]:
"""
Expand All @@ -70,7 +71,9 @@ def reference(self) -> Tuple[int, int]:
return self.__reference

@reference.setter
def reference(self, cellcycling: int, step: int) -> None:
def reference(self, input: Tuple[int, int]) -> None:

cellcycling, step = input
if cellcycling < 0 or cellcycling >= len(self.__cellcycling_steps):
raise ValueError(
f"Cannot use the cellcycling {cellcycling} as reference. Only {len(self.__cellcycling_steps)} are available."
Expand Down Expand Up @@ -436,13 +439,13 @@ def numbers(self) -> List[int]:
return [i+1 for i, _ in enumerate(self)]

@property
def current_steps(self) -> List[int]:
def current_steps(self) -> List[float]:
"""
Returns an array containing the current values associated with each cycle in the experiment
Returns
-------
List[int]
List[float]
A simple array with a progressive number for all datapoints.
"""
current_steps = []
Expand All @@ -451,6 +454,23 @@ def current_steps(self) -> List[int]:
current_steps.append(current)

return current_steps

@property
def cycles(self) -> List[Cycle]:
"""
Returns the array containing all the cycles object associated to each current step
Returns
-------
List[Cycle]
A simple array containing the sequece of Cycle objects associated to each explored current value
"""
cycles = []
for cellcycling in self.__cellcycling_steps:
for cycle in cellcycling:
cycles.append(cycle)

return cycles


def dump_to_excel(self, path: str, volume: float, area: float) -> None:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
# %% ADD MODULE TO SYSPATH
import os
import sys
from pathlib import Path

current_path = os.path.realpath(__file__)

path = Path(current_path)
parent_path = str(path.parents[2].absolute())
sys.path.insert(0, parent_path)

# %% IMPORTS
import pytest
import pandas as pd
import numpy as np
Expand All @@ -28,9 +16,7 @@
)


# %% DEFINE CONSTANT DATASET TO BE USED IN TESTING


# DEFINE CONSTANT DATASET TO BE USED IN TESTING
def get_dataset_const() -> Tuple[pd.Series, pd.Series, pd.Series, datetime]:
time = pd.Series([0.0, 1.0, 2.0, 3.0, 4.0])
voltage = pd.Series([1.2, 1.2, 1.2, 1.2, 1.2])
Expand Down Expand Up @@ -87,8 +73,7 @@ def expected_values_const() -> Tuple[pd.Series, float, pd.Series, pd.Series, flo
return pd.Series(Q), total_capacity, pd.Series(power), pd.Series(energy), total_energy


# %% TEST FUNCTIONS FOR THE HALFCYCLE CLASS USING THE CONSTANT DATASET

# TEST FUNCTIONS FOR THE HALFCYCLE CLASS USING THE CONSTANT DATASET
# Test function to check for exceptions raised during HalfCycle object construction
def test_HalfCycle___init__() -> None:

Expand Down Expand Up @@ -161,8 +146,7 @@ def test_HalfCycle_calculate_energy_function(halfcycle_obj_const, expected_value
assert_almost_equal(halfcycle._total_energy, tE_exp, decimal=6)


# %% TEST FUNCTIONS FOR THE JOIN HALFCYCLE FUNCTION USING THE CONSTANT DATASET

# TEST FUNCTIONS FOR THE JOIN HALFCYCLE FUNCTION USING THE CONSTANT DATASET
# Test regular operation of the join_HalfCycles function
def test_join_HalfCycles_function(halfcycle_obj_const):

Expand Down Expand Up @@ -207,9 +191,7 @@ def test_join_HalfCycles_function_different_type_error(halfcycle_obj_const):
assert False


# %% TEST FUNCTIONS FOR THE CYCLE CLASS USING THE CONSTANT DATASET


# TEST FUNCTIONS FOR THE CYCLE CLASS USING THE CONSTANT DATASET
# Test function to check for exceptions raised during Cycle object construction
def test_Cycle___init__(halfcycle_obj_const):

Expand Down Expand Up @@ -323,9 +305,7 @@ def test_Cycle_calculate_efficiencies_sentinel_value_feature(halfcycle_obj_const



# %% TEST FUNCTIONS FOR THE CELLCYCLING CLASS USING THE CONSTANT DATASET


# TEST FUNCTIONS FOR THE CELLCYCLING CLASS USING THE CONSTANT DATASET
# Test function to check for exceptions raised during CellCycling object construction
def test_CellCycling___init__(cycles_objs_const):

Expand Down Expand Up @@ -560,9 +540,7 @@ def test_CellCycling_properties(cycles_objs_const):
assert cellcycling.numbers == [0, 1, 2, 3, 4]


# %% TEST FOR THE time_adjust FUNCTION


# TEST FOR THE time_adjust FUNCTION
# Test the time_adjust_function no reverse equal time-series
def test_time_adjust_function_equal(cycle_obj_const):
cycle = cycle_obj_const
Expand Down
121 changes: 121 additions & 0 deletions tests/unit/test_cellcycling_experiments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import pytest
from copy import deepcopy
from os.path import dirname, abspath, join

from numpy.testing import assert_array_almost_equal, assert_almost_equal

from echemsuite.cellcycling.read_input import FileManager
from echemsuite.cellcycling.cycles import CellCycling, Cycle, HalfCycle
from echemsuite.cellcycling.experiments import RateExperiment


# Get the path of the tests directory
TEST_DIR = dirname(abspath(__file__))

# Fixture to emulate a folder containing a regular .mpt cycling file
@pytest.fixture(scope="session")
def generate_sample_cellcycling(tmp_path_factory):
mpt_content = """
...
Acquisition started on : 25/12/2022 13:00:00
...
Number of loops : 2
Loop 0 from point number 0 to 5
Loop 1 from point number 6 to 11
mode ox/red error control changes time/s control/V/mA Ewe/V I/mA dq/mA.h (Q-Qo)/mA.h Q charge/discharge/mA.h Ece/V P/W Q discharge/mA.h Q charge/mA.h Capacity/mA.h control/V control/mA Ewe-Ece/V
1 1 0 1 1,000000000000000E+002 8,0000000E+002 1,0000000E+000 8,0000000E+002 4,000000000000000E+000 1,100000000000000E+003 1,100000000000000E+003 3,0000000E-006 1,0000000E+000 0,000000000000000E+000 1,000000000000000E+003 1,000000000000000E+003 0,0000000E+000 8,0000000E+002 1,0000000E+000
1 1 0 1 1,010000000000000E+002 8,0000000E+002 1,1000000E+000 8,0000000E+002 4,000000000000000E+000 1,100000000000000E+003 1,100000000000000E+003 3,0000000E-006 1,0000000E+000 0,000000000000000E+000 1,000000000000000E+003 1,000000000000000E+003 0,0000000E+000 8,0000000E+002 1,0000000E+000
1 1 0 1 1,020000000000000E+002 8,0000000E+002 1,2000000E+000 8,0000000E+002 4,000000000000000E+000 1,100000000000000E+003 1,100000000000000E+003 3,0000000E-006 1,0000000E+000 0,000000000000000E+000 1,000000000000000E+003 1,000000000000000E+003 0,0000000E+000 8,0000000E+002 1,0000000E+000
1 0 0 0 1,030000000000000E+002 -8,0000000E+002 9,0000000E-001 -8,0000000E+002 -4,000000000000000E-005 1,100000000000000E+003 -4,000000000000000E-005 -8,0000000E-004 -4,0000000E-001 5,000000000000000E-005 0,000000000000000E+000 5,000000000000000E-005 0,0000000E+000 -8,0000000E+002 6,0000000E-001
1 0 0 0 1,040000000000000E+002 -8,0000000E+002 8,5000000E-001 -8,0000000E+002 -4,000000000000000E+000 1,100000000000000E+003 -4,000000000000000E+000 -8,0000000E-005 -4,0000000E-001 5,000000000000000E+000 0,000000000000000E+000 5,000000000000000E+000 0,0000000E+000 -8,0000000E+002 6,0000000E-001
1 0 0 0 1,050000000000000E+002 -8,0000000E+002 8,2000000E-001 -8,0000000E+002 -4,000000000000000E+000 1,100000000000000E+003 -4,000000000000000E+000 -8,0000000E-004 -4,0000000E-001 5,000000000000000E+000 0,000000000000000E+000 5,000000000000000E+000 0,0000000E+000 -8,0000000E+002 6,0000000E-001
1 1 0 1 1,060000000000000E+002 8,0000000E+002 1,0000000E+000 8,0000000E+002 4,000000000000000E+000 1,100000000000000E+003 1,100000000000000E+003 3,0000000E-006 1,0000000E+000 0,000000000000000E+000 1,000000000000000E+003 1,000000000000000E+003 0,0000000E+000 8,0000000E+002 1,0000000E+000
1 1 0 1 1,070000000000000E+002 8,0000000E+002 1,1000000E+000 8,0000000E+002 4,000000000000000E+000 1,100000000000000E+003 1,100000000000000E+003 3,0000000E-006 1,0000000E+000 0,000000000000000E+000 1,000000000000000E+003 1,000000000000000E+003 0,0000000E+000 8,0000000E+002 1,0000000E+000
1 1 0 1 1,080000000000000E+002 8,0000000E+002 1,2000000E+000 8,0000000E+002 4,000000000000000E+000 1,100000000000000E+003 1,100000000000000E+003 3,0000000E-006 1,0000000E+000 0,000000000000000E+000 1,000000000000000E+003 1,000000000000000E+003 0,0000000E+000 8,0000000E+002 1,0000000E+000
1 0 0 0 1,090000000000000E+002 -8,0000000E+002 9,0000000E-001 -8,0000000E+002 -4,000000000000000E-005 1,100000000000000E+003 -4,000000000000000E-005 -8,0000000E-004 -4,0000000E-001 5,000000000000000E-005 0,000000000000000E+000 5,000000000000000E-005 0,0000000E+000 -8,0000000E+002 6,0000000E-001
1 0 0 0 1,100000000000000E+002 -8,0000000E+002 8,5000000E-001 -8,0000000E+002 -4,000000000000000E+000 1,100000000000000E+003 -4,000000000000000E+000 -8,0000000E-005 -4,0000000E-001 5,000000000000000E+000 0,000000000000000E+000 5,000000000000000E+000 0,0000000E+000 -8,0000000E+002 6,0000000E-001
1 0 0 0 1,110000000000000E+002 -8,0000000E+002 8,2000000E-001 -8,0000000E+002 -4,000000000000000E+000 1,100000000000000E+003 -4,000000000000000E+000 -8,0000000E-004 -4,0000000E-001 5,000000000000000E+000 0,000000000000000E+000 5,000000000000000E+000 0,0000000E+000 -8,0000000E+002 6,0000000E-001"""

folder = tmp_path_factory.mktemp("regular_mpt_files")
file_path = folder / "myCellcycling.mpt"
file_path.write_text(mpt_content)

manager = FileManager()
manager.fetch_from_folder(folder, ".mpt", autoparse=True)

return manager.get_cellcycling()


# Test the RateExperiment __init__ method with no arguments
def test_RateExperiment___init__():

try:
obj = RateExperiment()
except:
assert False, "Exception occurred during RateExperiment construction"

assert obj.current_steps == []
assert obj.cycles == []
assert obj.reference == (0, 0)

# Test the RateExperiment __init__ method with user provided arguments
def test_RateExperiment___init___with_arguments(generate_sample_cellcycling):

cc = deepcopy(generate_sample_cellcycling)

obj = RateExperiment(current_steps=[0.1, 0.2], cellcycling_steps=[cc, cc])

assert obj.numbers == [1, 2, 3, 4]
assert len(obj.cycles) == 4
assert obj.reference == (0, 0)
assert_array_almost_equal(obj.current_steps, [0.1, 0.1, 0.2, 0.2], decimal=6)


# Test the RateExperiment from_Biologic_battery_module classmethod
def test_RateExperiment_from_Biologic_battery_module():

BASE_FOLDER = join(TEST_DIR, "../..")
BMFILE = join(BASE_FOLDER, "docs/Guide/CellCycling/example_Biologic_BatteryModule/example_BattModule.mpt")

try:
obj = RateExperiment.from_Biologic_battery_module(BMFILE)
except:
assert False, "Exception raised duting classmethod call"

assert obj.reference == (0, 0)
assert len(obj.cycles) == 46
assert_array_almost_equal(obj.current_steps,
[
0.5, 1. , 1. , 1. , 1. , 1. , 1.5, 1.5, 1.5, 1.5, 1.5, 2. , 2. ,
2. , 2. , 2. , 2.5, 2.5, 2.5, 2.5, 2.5, 3. , 3. , 3. , 3. , 3. ,
3.5, 3.5, 3.5, 3.5, 3.5, 4. , 4. , 4. , 4. , 4. , 4.5, 4.5, 4.5,
4.5, 4.5, 5. , 5. , 5. , 5. , 5.
],
decimal=6
)

assert obj.numbers == [n+1 for n in range(46)]


# Test the RateExperiment reference property
def test_RateExperiment_reference_property():

BASE_FOLDER = join(TEST_DIR, "../..")
BMFILE = join(BASE_FOLDER, "docs/Guide/CellCycling/example_Biologic_BatteryModule/example_BattModule.mpt")
obj = RateExperiment.from_Biologic_battery_module(BMFILE)

assert obj.reference == (0, 0)
assert_almost_equal(obj.capacity_retention[0], 100, decimal=6)

obj.reference = (2, 1)
assert obj.reference == (2, 1)
assert_almost_equal(obj.capacity_retention[7], 100, decimal=6)

try:
obj.reference = (20, 0)
except ValueError:
assert True
else:
assert False, "Exception not rised when index out of bounds in provided"

Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
# %% ADD MODULE TO SYSPATH
import os
import sys
from pathlib import Path

current_path = os.path.realpath(__file__)

path = Path(current_path)
parent_path = str(path.parents[2].absolute())
sys.path.insert(0, parent_path)

# %% IMPORTS
import pytest
import pandas as pd
from os.path import abspath, join

from datetime import datetime
from io import TextIOWrapper, BytesIO
from numpy.testing import assert_array_almost_equal
Expand All @@ -24,9 +12,7 @@
)


# %% DEFINE FILE EMULATION FIXTURES FOR GAMRY .DTA FILES


# DEFINE FILE EMULATION FIXTURES FOR GAMRY .DTA FILES
def generate_minimal_dta_file_content(charge: bool, time: str) -> str:

sign = "" if charge else "-"
Expand Down Expand Up @@ -95,7 +81,7 @@ def folder_with_partial_dta_files(tmp_path_factory):
return folder


# %% DEFINE FILE EMULATION FIXTURES FOR BIOLOGIC .MPT FILES
# DEFINE FILE EMULATION FIXTURES FOR BIOLOGIC .MPT FILES


def generate_regular_mpt_file_content() -> str:
Expand Down

0 comments on commit c78aad6

Please sign in to comment.