Skip to content

Commit

Permalink
(PR #39) Post-processing parser update
Browse files Browse the repository at this point in the history
* pre-commit: ignore backslash in brackets
* Update parser documentation
* Change `cn` to `cycle-number` and set as range
* Discard unused `time-cycles` key
* Compute and store full-cycle markers
* Compute and store charge/discharge energies
  • Loading branch information
edan-bainglass authored Jan 30, 2024
1 parent c265c06 commit 8d49383
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 24 deletions.
3 changes: 2 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ repos:
hooks:
- id: flake8
# E501 - line length limit
# E502 - backslash in brackets
# E741 - ambiguous variable name, used sparsely when appropriate
# F541 - f-string is missing placeholders
args: ["--ignore=E501,E741,F541"]
args: ["--ignore=E501,E502,E741,F541"]
exclude: *exclude_files

- repo: https://github.com/pre-commit/mirrors-mypy
Expand Down
113 changes: 90 additions & 23 deletions aiida_aurora/utils/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,32 @@
from aiida.orm import ArrayData


def get_data_from_raw(jsdata) -> dict:
"Extract raw data from json file."
def get_data_from_raw(jsdata: dict) -> dict:
"""Extract raw data from json file.
Parameters
----------
`jsdata` : `dict`
The raw JSON data.
Returns
-------
`dict`
The post-processed data.
Raises
------
`TypeError`
If `jsdata` is not a dictionary.
`NotImplementedError`
If `jsdata` contains more than one step.
"""

if not isinstance(jsdata, dict):
raise TypeError('jsdata should be a dictionary')
raise TypeError("jsdata should be a dictionary")

if len(jsdata["steps"]) > 1:
raise NotImplementedError('Analysis of multiple steps is not implemented.')
raise NotImplementedError("multi-step analysis not implemented.")

raw_data = jsdata["steps"][0]["data"]

Expand All @@ -23,50 +41,99 @@ def get_data_from_raw(jsdata) -> dict:
return post_process_data(t, Ewe, I)


def get_data_from_results(array_node) -> dict:
"Extract data from parsed ArrayData node."
def get_data_from_results(array_node: ArrayData) -> dict:
"""Extract data from parsed ArrayData node.
Parameters
----------
`array_node` : `ArrayData`
The cycling experiment results node.
Returns
-------
`dict`
The post-processed data.
Raises
------
`TypeError`
If `array_node` is not an `ArrayData` node.
"""

if not isinstance(array_node, ArrayData):
raise TypeError('array_node should be an ArrayData')
raise TypeError("array_node should be an ArrayData")

# collect data
t = array_node.get_array('step0_uts')
t = array_node.get_array("step0_uts")
t -= t[0]
Ewe = array_node.get_array('step0_Ewe_n')
I = array_node.get_array('step0_I_n')
Ewe = array_node.get_array("step0_Ewe_n")
I = array_node.get_array("step0_I_n")

return post_process_data(t, Ewe, I)


def post_process_data(t: np.ndarray, Ewe: np.ndarray, I: np.ndarray) -> dict:
"""docstring"""
"""Post-process raw data.
Processes:
- Determine half-cycle markers
- Integrate continuous charge
- Collect charge/discharge capacities
-
Parameters
----------
`t` : `np.ndarray`
The raw time data [s].
`Ewe` : `np.ndarray`
The raw voltage data [V].
`I` : `np.ndarray`
The raw current data [A].
Returns
-------
`dict`
The post-processed data.
"""

mask = I != 0 # filter out zero current
t, Ewe, I = t[mask], Ewe[mask], I[mask]

Q = cumtrapz(I, t, axis=0, initial=0)

# mark half-cycles (including first and last values)
idx = np.where(np.diff(np.sign(I), prepend=0) != 0)[0]
idx = np.append(idx, len(I))

# integrate and store charge and discharge currents
Qc, Qd = [], []
# integrate and store charge/discharge capacities/energies
cycle_idx, Qc, Qd, Ec, Ed = [], [], [], [], []

for ii in range(len(idx) - 1):

i0, ie = idx[ii], idx[ii + 1]

if ie - i0 < 10:
continue
q = np.trapz(I[i0:ie], t[i0:ie])
if q > 0:

e = np.trapz(Ewe[i0:ie], Q[i0:ie])

if (q := np.trapz(I[i0:ie], t[i0:ie])) > 0:
cycle_idx.append(i0)
Qc.append(q)
Ec.append(e)
else:
Qd.append(abs(q))
Ed.append(abs(e))

return {
'time': t,
'Ewe': Ewe,
'I': I,
'cn': len(Qd),
'time-cycles': t[idx[2::2]],
'Q': cumtrapz(I, t, axis=0, initial=0) / 3.6,
'Qd': np.array(Qd) / 3.6,
'Qc': np.array(Qc) / 3.6,
"time": t, # [s]
"Ewe": Ewe, # [V]
"I": I, # [A]
"Q": Q / 3.6, # [mAh]
"cycle-number": np.arange(len(Qd)),
"cycle-index": np.array(cycle_idx),
"Qc": np.array(Qc) / 3.6, # [mAh]
"Qd": np.array(Qd) / 3.6, # [mAh]
"Ec": np.array(Ec) / 3600, # [Wh]
"Ed": np.array(Ed) / 3600, # [Wh]
}

0 comments on commit 8d49383

Please sign in to comment.