diff --git a/docs/intro.md b/docs/intro.md index e6944b7..efe2744 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -1,6 +1,6 @@ # GES-echem-suite Documentation -Version: [0.2.1b](ReleaseNotes) +Version: [0.2.1b2](ReleaseNotes) The `GES-echem-suite` library is a small collection of tools for the manipulation and analysis of electrochemical data. The library allows to load, organize, and process the data-files collected during electrochemical experiments such as battery cycling and cyclic voltammetries. diff --git a/docs/release-notes.md b/docs/release-notes.md index d79795c..5b9ceba 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,13 @@ (ReleaseNotes)= # Release notes +* Version 0.2.1b2 + * Added classmethod to `RateExperiment` to load ARBIN `.csv` files. + * Added timestamp propery to `CellCycling` class to more easily track the start of the experiment. + * Added a `quickload_folder` method to the `cellcycling.read_input` module. + * Added classmethod to `RateExperiment` to load GAMRY standard folder format. + * Update to the documentation with more examples and new types of plot + * Version 0.2.1b * Added a graphicaltools module to help the user in the creation of graphs and plots * Defined a simple `Color` class to hold, manipulate and carry around RGB color values. diff --git a/echemsuite/cellcycling/experiments.py b/echemsuite/cellcycling/experiments.py index b760d33..8d67c8c 100644 --- a/echemsuite/cellcycling/experiments.py +++ b/echemsuite/cellcycling/experiments.py @@ -285,21 +285,29 @@ def from_Biologic_battery_module(cls, path: str) -> RateExperiment: return obj @classmethod - def from_ARBIN_csv_file(cls, csv_path: str, variation_threshold: float = 1.) -> RateExperiment: + def from_ARBIN_csv_file( + cls, + csv_path: str, + variation_threshold: float = 1.0, + current_digits: int = 3, + ) -> RateExperiment: """ Classmethod dedicated to the construction of a RateExperiment object starting from a ARBIN csv file. Please - notice that the ARBIN .csv files do not specify the current associated to each step explicitly, as such the + notice that the ARBIN .csv files do not specify the current associated to each step explicitly, as such the average current per halfcycle will be used in the definition of the various rate steps. The division of the cell-cyclicing objects in different rate steps is generated automatically by the method using a fixed percentage threshold value. When the percentage variation threshold is exceeded the cell-cycling object is - moved to a new current step. + moved to a new current step. The current steps of the experiments are computed automatically as averages and + rounded to a user specified number of digits (default: 3) Arguments --------- csv_path: str The path to the `.csv` file generated from the ARBIN battery cycler. variation_threshold: float - The threshold (in percentage) to be used in the indetification of a new current step (default: 1%) + The threshold (in percentage) to be used in the indetification of a new current step (default: 1%). + current_digits: int + Number of digits to be kept in saving the average current values computed form the data-files (default: 3). Raises ------ @@ -402,7 +410,7 @@ def parse_arbin_timestamp(timestamp_str: str) -> datetime: # If the relative error exceeds the 1% threshold or we reached the end of the halfcycles list trigger the # creation of the cell-cycling object corresponding to the current step - if relative_error > 1 or hidx == len(halfcycles) - 1: + if relative_error > variation_threshold or hidx == len(halfcycles) - 1: # If a charge halfcycle is left in the buffer conclude the cycle buffer with the last charge if charge is not None: cycle = Cycle(number=len(cycles_buffer) + 1, charge=charge, discharge=None) @@ -428,7 +436,7 @@ def parse_arbin_timestamp(timestamp_str: str) -> datetime: charge = None # Format the current steps list by rounding the current values to the third decimal place - current_steps = [round(i, 3) for i in current_steps] + current_steps = [round(i, current_digits) for i in current_steps] # Creat a RateExperiment object with the obtained data ad return it obj = cls(current_steps=current_steps, cellcycling_steps=cellcycling_steps) @@ -438,7 +446,7 @@ def parse_arbin_timestamp(timestamp_str: str) -> datetime: def from_GAMRY_folder_tree(cls, basefolder: str, current_digits: int = 3) -> RateExperiment: """ Classmethod dedicated to the construction of a RateExperiment object starting from a folder tree generated by - GAMRY instruments during multi-step cycling experiments. The folder structure expected is the following: a + GAMRY instruments during multi-step cycling experiments. The folder structure expected is the following: a `basefolder` containing a set of step data-folders (with variable names) each of which contains a `CHARGE_DISCHARGE` folder containing the desired .DTA files encoding the charge/discharge cell-cycling at a given current. The current steps of the experiments are computed automatically as averages and rounded to a user specified @@ -450,7 +458,7 @@ def from_GAMRY_folder_tree(cls, basefolder: str, current_digits: int = 3) -> Rat The path to the `basefolder` containing the data-folders for each step. current_digits: int Number of digits to be kept in saving the average current values computed form the data-files (default: 3). - + Raises ------ ValueError @@ -461,20 +469,19 @@ def from_GAMRY_folder_tree(cls, basefolder: str, current_digits: int = 3) -> Rat # Check if the specified basefolder exists if not isdir(basefolder): raise ValueError(f"The folder '{basefolder}' does not exist.") - + # Define an empty list to store all the cell-cycling experimental data cellcycling_steps: List[CellCycling] = [] # Cycle over the content of the basefolder for folder_name in listdir(basefolder): - # Define an hypotetical search path for the CHARGE_DISCHARGE target folder path = join(join(basefolder, folder_name), "CHARGE_DISCHARGE") # Check if the folder containing the data is found if not isdir(path): continue - + # Try to load the data from the CHARGE_DISCHARGE folder if the load fails (e.g. the folder is empty) # return a warning messange to the user cellcycling: CellCycling = None @@ -484,18 +491,17 @@ def from_GAMRY_folder_tree(cls, basefolder: str, current_digits: int = 3) -> Rat warn(f"Failed to load file from {path}. The folder will be skipped") else: cellcycling_steps.append(cellcycling) - + # Check if data has been loaded, if not raise an exception if cellcycling_steps == []: raise RuntimeError("No valid GAMRY cell-cycling data has been found in the specified folder.") # Sort the cell-cycling objects based on their timestamp cellcycling_steps.sort(key=lambda x: x.timestamp) - + # Evaluate the current value for each step computing the average current during the charge and discharge halfcyles current_steps: List[float] = [] for cellcycling in cellcycling_steps: - iavg: float = 0 nsamples: int = 0 for cycle in cellcycling: @@ -503,8 +509,8 @@ def from_GAMRY_folder_tree(cls, basefolder: str, current_digits: int = 3) -> Rat for current in halfcycle: iavg += abs(current) nsamples += 1 - - iavg = round(iavg/nsamples, current_digits) + + iavg = round(iavg / nsamples, current_digits) current_steps.append(iavg) # Create a RateExperiment object and return it diff --git a/meta.yaml b/meta.yaml index 2ef03bc..742cc0f 100644 --- a/meta.yaml +++ b/meta.yaml @@ -1,5 +1,5 @@ {% set name = "GES-echem-suite" %} -{% set version = "0.2.1b" %} +{% set version = "0.2.1b2" %} @@ -20,12 +20,12 @@ build: requirements: host: - - python>=3.7 + - python>=3.8 - pip - setuptools run: - - python>=3.7 + - python>=3.8 - numpy - pandas>=1.3.0 - scipy diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b5caed1 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,30 @@ +[metadata] +name = GES-echem-suite + +[options] +packages = + echemsuite + echemsuite.cellcycling + echemsuite.cyclicvoltammetry +install_requires = + numpy + pandas>=1.3.0 + scipy + matplotlib + openpyxl + palettable + +python_requires = >=3.8 +package_dir = =. +zip_safe = no + +[options.extras_require] +testing = + pytest>=6.0 + pytest-cov>=2.0 + mypy>=0.910 + flake8>=3.9 + tox>=3.24 + +[flake8] +max-line-length = 160 \ No newline at end of file diff --git a/setup.py b/setup.py index 475e118..4e374f8 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setuptools.setup( name="GES-echem-suite", - version="0.2.1b", + version="0.2.1b2", description="", long_description="", packages=["echemsuite"], diff --git a/tox.ini b/tox.ini index df22848..a054430 100644 --- a/tox.ini +++ b/tox.ini @@ -1,12 +1,11 @@ [tox] -minversion = 3.7.0 -envlist = py37, py38, py39, py310 +minversion = 3.8.0 +envlist = py38, py39, py310 isolated_build = true skipsdist = True [gh-actions] python = - 3.7: py37 3.8: py38 3.9: py39 3.10: py310