Source code for cellpy.utils.batch_tools.batch_analyzers

import logging

import pandas as pd

from cellpy.exceptions import UnderDefined
from cellpy.utils.batch_tools.batch_core import BaseAnalyzer
from cellpy.utils.batch_tools.dumpers import ram_dumper
from cellpy.utils.batch_tools.engines import summary_engine
from cellpy.utils.ocv_rlx import select_ocv_points


[docs]class BaseSummaryAnalyzer(BaseAnalyzer): def __init__(self): super().__init__() self._assign_engine(summary_engine) self._assign_dumper(ram_dumper)
[docs]class ICAAnalyzer(BaseAnalyzer): def __init__(self): super().__init__()
[docs]class EISAnalyzer(BaseAnalyzer): def __init__(self): super().__init__()
[docs]class OCVRelaxationAnalyzer(BaseAnalyzer): """Analyze open curcuit relaxation curves. This analyzer is still under development. (Partly) implented so far: select_ocv_points -> farms. To get the DataFrames from the farms, you can use >>> ocv_point_frames = OCVRelaxationAnalyzer.last Attributes: selection_method: criteria for selecting points (martin: select first and last, and then last/2, last/2/2 etc. until you have reached the wanted number of points; fixed_time: select first, and same interval; defaults to "martin") number_of_points: number of points you want. defaults to 5 interval: interval between each point (in use only for methods where interval makes sense). If it is a list, then number_of_points will be calculated as len(interval) + 1 (and override the set number_of_points). defaults to 10 relative_voltage: set to True if you would like the voltage to be relative to the voltage before starting the ocv rlx step. Defaults to False. Remark that for the initial rxl step (when you just have put your cell on the tester) does not have any prior voltage. The relative voltage will then be versus the first measurement point. defaults to False report_times: also report the ocv rlx total time if True (defaults to False) direction ("up", "down" or "both"): select "up" if you would like to process only the ocv rlx steps where the voltage is relaxing upwards and vize versa. Defaults to "both Notes: This analyzer is not working as intended yet. Todos: - include better engine-dumper methodology and dump stuff to both memory and file(s) (should add this to BaseAnalyser) - recieve settings and parameters - option (dumper) for plotting? - automatic fitting of OCV rlx data? """ def __init__(self): super().__init__() self.engines = [] self.dumpers = [] self.current_engine = None self._assign_engine(self.ocv_points_engine) # self._assign_dumper(self.screen_dumper) # prms for select_ocv_points self.selection_method = "martin" self.number_of_points = 5 self.interval = 10 self.relative_voltage = False self.report_times = False self.include_times = True self.direction = None def _assign_engine(self, engine): self.engines.append(engine) def _assign_dumper(self, dumper): self.dumpers.append(dumper)
[docs] def screen_dumper(self, **kwargs): for farm in self.farms: print(farm)
@property def last(self) -> list: return self.farms[-1] @property def dframe(self) -> pd.DataFrame: return self.farms[-1][-1]
[docs] def run_engine(self, engine): logging.debug(f"start engine::{engine.__name__}]") self.current_engine = engine self.farms, self.barn = engine(experiments=self.experiments, farms=self.farms) logging.debug("::engine ended")
[docs] def run_dumper(self, dumper): logging.debug(f"start dumper::{dumper.__name__}]") dumper( experiments=self.experiments, farms=self.farms, barn=self.barn, engine=self.current_engine, ) logging.debug("::dumper ended")
[docs] def do(self): if not self.experiments: raise UnderDefined("cannot run until you have assigned an experiment") for engine in self.engines: self.empty_the_farms() logging.debug(f"running - {str(engine)}") self.run_engine(engine) for dumper in self.dumpers: logging.debug(f"exporting - {str(dumper)}") self.run_dumper(dumper)
[docs] def ocv_points_engine(self, **kwargs): experiments = kwargs["experiments"] farms = kwargs["farms"] barn = None for experiment, farm in zip(experiments, farms): dframes = [] for cell_label in experiment.cell_data_frames: logging.info(f"Analyzing {cell_label}") if experiment.all_in_memory: logging.debug("CellpyData picked from memory") cell = experiment.cell_data_frames[cell_label] if cell.empty: logging.warning("Oh-no! Empty CellpyData-object") else: logging.debug("CellpyData loaded from Cellpy-file") cell = experiment.data[cell_label] if cell.empty: logging.warning("Oh-no! Empty CellpyData-object") df = select_ocv_points( cell, cell_label=cell_label, include_times=self.include_times, selection_method=self.selection_method, number_of_points=self.number_of_points, interval=self.interval, relative_voltage=self.relative_voltage, report_times=self.report_times, direction=self.direction, ) dframes.append(df) concat_df = pd.concat(dframes) farm.append(concat_df) return farms, barn
[docs] def do2(self): for experiment, farm in zip(self.experiments, self.farms): for cell_label in experiment.cell_data_frames: logging.info(f"Analyzing {cell_label}") if experiment.all_in_memory: logging.debug("CellpyData picked from memory") cell = experiment.cell_data_frames[cell_label] if cell.empty: logging.warning("Oh-no! Empty CellpyData-object") else: logging.debug("CellpyData loaded from Cellpy-file") cell = experiment.data[cell_label] if cell.empty: logging.warning("Oh-no! Empty CellpyData-object") df = select_ocv_points( cell, cell_label=cell_label, selection_method=self.selection_method, number_of_points=self.number_of_points, interval=self.interval, relative_voltage=self.relative_voltage, report_times=self.report_times, direction=self.direction, ) farm.append(df) return self.farms