pyDRTtools

repository·master·Indexed 41 days ago

https://github.com/ciuccislab/pydrttools

A Python-based GUI and toolbox for computing the Distribution of Relaxation Times (DRT) from Electrochemical Impedance Spectroscopy (EIS) data. It features Tikhonov regularization, Bayesian credible interval estimation, and Hilbert-transform subroutines for data quality assessment. The library supports various Radial Basis Function (RBF) types and cross-validation methods for optimal regularization parameter selection.

Tokens
3K
Snippets
9
Records
12
Agent score
51%

What's inside pyDRTtools

  1. Overview of pyDRTtools capabilities

    master

    pyDRTtools is a Python-based GUI tool designed to analyze Electrochemical Impedance Spectroscopy (EIS) data using the Distribution of Relaxation Times (DRT) model.

    Key features include:

    • DRT Computation: Uses Tikhonov regularization via an intuitive GUI.
    • Optimization: Multiple options for optimizing DRT estimation.
    • Uncertainty Quantification: A sampler to determine the credible intervals of your DRT.
    • Parameter Selection: Tools for the optimal selection of the regularization parameter.
    • Data Quality Assessment: Hilbert-transform subroutines to assess and score the quality of EIS data.
  2. Install pyDRTtools via Conda and Pip

    master

    To install pyDRTtools, you need Python >= 3. The recommended installation procedure uses an Anaconda prompt to create a dedicated environment with the necessary scientific dependencies and then installs the package via pip.

    Follow these steps:

    1. Create a new Conda environment named DRT with the required packages.
    2. Activate the environment.
    3. Install cvxopt and PyQt5 via pip.
    4. Install pyDRTtools via pip.
    conda create --name DRT pip ipython pandas matplotlib scikit-learn spyder
    conda activate DRT
    pip install cvxopt PyQt5
    pip install pyDRTtools
  3. Analyze multiple EIS spectra simultaneously

    master

    To analyze a series of EIS measurements (e.g., varying temperature or concentration), wrap the single-spectrum analysis workflow in a loop. This allows you to collect DRT vectors and reconstructed impedances for all conditions, which can then be used to generate contour plots or comparative Nyquist plots.

    # Example loop structure for multiple experiments
    for n in range(N_exp):
        # 1. Load data
        # 2. Compute epsilon
        # 3. Assemble A_re, A_im, A, and M2
        # 4. Compute optimal lambda
        # 5. Solve quadratic problem
        # 6. Store results in lists (e.g., gamma_DRT_list[n])
  4. Analyze a single EIS spectrum with pyDRTtools

    master

    To perform Distribution of Relaxation Times (DRT) analysis on a single Electrochemical Impedance Spectroscopy (EIS) spectrum, follow these steps:

    1. Load Data: Load your frequency and impedance data (Real and Imaginary parts) into NumPy arrays.
    2. Define Timescales: Create a vector of timescales (tau_vec) using np.logspace over your desired range.
    3. Configure Discretization: Choose an rbf_type (e.g., 'Gaussian', 'Piecewise Linear', 'C0 Matern', 'C2 Matern', 'C4 Matern', 'C6 Matern', or 'Inverse Quadratic') and a shape_control method (e.g., 'FWHM Coefficient').
    4. Compute Matrices:
      • Use basics.compute_epsilon to find the epsilon parameter.
      • Use basics.assemble_A_re and basics.assemble_A_im to build the discretization matrices for the real and imaginary parts. Note that you must manually augment these matrices to include Ohmic resistance ($R_{\infty}$) and inductance ($L_0$) contributions.
      • Use basics.assemble_M_2 to create the second-order differentiation matrix for ridge regression.
    5. Regularization: Find the optimal regularization parameter lambda_value using basics.optimal_lambda with a cross-validation method like 'GCV'.
    6. Deconvolution: Use basics.quad_format_combined to prepare the quadratic programming problem, then solve it using cvxopt.solvers.qp to recover the DRT ($\gamma$).
    # 1. Setup parameters
    rbf_type = 'Gaussian'
    shape_control = 'FWHM Coefficient'
    coeff = 0.5
    
    # 2. Compute epsilon and discretization matrices
    epsilon = basics.compute_epsilon(freq_vec, coeff, rbf_type, shape_control)
    A_re = basics.assemble_A_re(freq_vec, tau_vec, epsilon, rbf_type)
    # Augment A_re for R_inf and L_0
    A_re = np.hstack((np.ones((N_freqs, 1)), np.zeros((N_freqs, 1)), A_re))
    
    A_im = basics.assemble_A_im(freq_vec, tau_vec, epsilon, rbf_type)
    # Augment A_im for R_inf and L_0
    A_im = np.hstack((np.zeros((N_freqs, 1)), 2*np.pi*freq_vec.reshape((N_freqs, 1)), A_im))
    
    A = np.vstack((A_re, A_im))
    
    # 3. Differentiation matrix
    M2 = np.zeros((N_taus+2, N_taus+2))
    M2[2:,2:] = basics.assemble_M_2(tau_vec, epsilon, rbf_type)
    
    # 4. Optimal lambda and solve
    lambda_value = basics.optimal_lambda(A_re, A_im, np.real(Z_exp), np.imag(Z_exp), M2, -3, 'GCV')
    H_combined, c_combined = basics.quad_format_combined(A_re, A_im, np.real(Z_exp), np.imag(Z_exp), M2, lambda_value)
    
    # Solve using cvxopt
    from cvxopt import matrix, solvers
    # (Assuming G and h are defined for constraints)
    sol = solvers.qp(matrix(H_combined), matrix(c_combined), G, h)
    x = np.array(sol['x']).flatten()
    
    # Extract results
    R_inf_DRT, L_0_DRT = x[0:2]
    gamma_DRT = x[2:]
  5. Generate multiple EIS datasets using the 2xZARC model

    master

    You can generate a batch of EIS datasets by iterating through a list of varying parameters (e.g., varying charge-transfer resistance $R_{ct}$) while keeping other model parameters constant. This is useful for creating datasets for machine learning or parameter sensitivity studies.

    The 2xZARC model calculates impedance as: $Z_{total} = R_{\infty} + Z_{ZARC,1} + Z_{ZARC,2}$.

    R_inf = 10
    R_ct_1_list = [5, 15, 25, 35, 45, 55]
    phi_1 = 0.8
    tau_1 = 0.1
    R_ct_2 = 50
    phi_2 = 0.8
    tau_2 = 0.0001
    sigma_n_exp = 0.5
    
    for n in range(len(R_ct_1_list)):
        Z_exact_1 = R_ct_1_list[n]/(1.+(1j*2.*np.pi*freq_vec*tau_1)**phi_1)
        Z_exact_2 = R_ct_2/(1.+(1j*2.*np.pi*freq_vec*tau_2)**phi_2)
        Z_exact = R_inf + Z_exact_1 + Z_exact_2
        Z_exp = Z_exact + sigma_n_exp*(np.random.normal(0, 1, N_freqs)+1j*np.random.normal(0, 1, N_freqs))
        
        df = pd.DataFrame.from_dict({'Freq': freq_vec, 'Real': np.real(Z_exp), 'Imag': np.imag(Z_exp)})
        df.to_csv(f'2ZARC{n}.csv')
  6. Generate a single EIS spectrum using the 1xZARC model

    master

    To generate a single Electrochemical Impedance Spectroscopy (EIS) spectrum, you can model the impedance using a ZARC (constant phase element based) model. The total impedance is calculated as the sum of an ohmic resistance ($R_{\infty}$) and one or more ZARC elements.

    To simulate realistic experimental data, you can add white noise to the exact impedance using a standard deviation parameter (sigma_n_exp).

    Steps:

    1. Define model parameters ($R_{\infty}$, $R_{ct}$, $\phi$, $\tau$).
    2. Create a log-equispaced frequency vector.
    3. Calculate the exact impedance using the formula: $Z_{ZARC} = \frac{R_{ct}}{1 + (j \cdot 2\pi f \tau)^{\phi}}$.
    4. Add complex white noise to simulate experimental error.
    import numpy as np
    import matplotlib.pyplot as plt
    import pandas as pd
    
    # 1. Model parameters
    R_inf = 10
    R_ct_1 = 50
    phi_1 = 0.8
    tau_1 = 0.1
    
    # 2. Frequencies
    log_freq_min, log_freq_max = -2., 6.
    N_freqs = 10*int(log_freq_max-log_freq_min)+1
    freq_vec = np.logspace(log_freq_min, log_freq_max, num=N_freqs, endpoint=True)
    
    # 3. Exact Impedance (1xZARC)
    Z_exact_1 = R_ct_1/(1.+(1j*2.*np.pi*freq_vec*tau_1)**phi_1)
    Z_exact = R_inf + Z_exact_1
    
    # 4. Add noise
    np.random.seed(12129)
    sigma_n_exp = 0.5
    Z_exp = Z_exact + sigma_n_exp*(np.random.normal(0, 1, N_freqs)+1j*np.random.normal(0, 1, N_freqs))
    
    # Plotting
    plt.plot(np.real(Z_exp), -np.imag(Z_exp), 'o', color='red')
  7. Save generated EIS data to CSV

    master

    Generated EIS data can be exported to a CSV file using pandas. It is recommended to store the frequency, real part, and imaginary part of the impedance in separate columns.

    import pandas as pd
    
    # Assuming freq_vec and Z_exp are already defined
    df = pd.DataFrame.from_dict({
        'Freq': freq_vec, 
        'Real': np.real(Z_exp), 
        'Imag': np.imag(Z_exp)
    })
    df.to_csv('./data/2ZARCs/2XZARCequal.csv')
  8. Recover impedance from DRT

    master

    Once you have the deconvolved DRT vector x (which includes $R_{\infty}$, $L_0$, and the $\gamma$ values), you can reconstruct the impedance $Z$ using the discretization matrix $A$ via a matrix product:

    $Z_{DRT} = A \cdot x$

    Note that the resulting vector contains both real and imaginary parts concatenated, so you must split and reconstruct the complex impedance.

    # Recover the impedance as a matrix product
    Z_DRT = A @ x
    # Reconstruct complex impedance from concatenated real/imag parts
    Z_DRT = Z_DRT[0:N_freqs] + 1j * Z_DRT[N_freqs:]