Source code for HavNegpy.conductivity

# -*- coding: utf-8 -*-
"""
Created on Mon May  9 15:56:07 2022

@author: mkolmang
"""

import numpy as np
import os
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
import mplcursors
import json




[docs]class Conductivity: """ A class to analyze real part of complex conductivity """ def __init__(self): """ Returns ------- None. """ pass
[docs] def create_analysis_file(self): """ Creates a file to save the fit results based on the choice of fit function Provides option to use an existing file and creates a new file if not found Returns ------- None. """ res = input(str("Do you want to use an existing file to save fit results? \n eg: existing file to save HN parameters, y or n:")) global ana_file if res == 'y': ex_file = input("Enter the analysis_file_name:") try: f = open(ex_file) except FileNotFoundError as e: print(f"{e}") else: if os.path.isfile(ex_file): print("file exists") else: ex_file = input("Enter the analysis_file_name:") f = open(ex_file,'w') f.write(str('File') + '\t' + str('T') + '\t' + str('fc')+ '\t' + str('DC') + '\t'+ str('n') + '\n') print(f'{"file created"}',ex_file) ana_file = ex_file return()
[docs] def select_range(self,x,y): """ Selects the region of interest to fit data using mplcursors allows two clicks to select the lower and upper bound of the x-axis and returns the selected x and y vaues for fitting Returns ------- x1 : array log frequency y1 : array log real part of complex conductivity """ x = list(x) y = list(y) plt.figure(1) plt.style.use("seaborn-whitegrid") plt.scatter(x,y,marker='s',color='b',facecolors='none', s=100,linewidth=2) plt.ylabel('log ( $\sigma´$)') plt.xlabel('log f') #plt.legend() plt.style.use("seaborn-whitegrid") mplcursors.cursor(hover=True) zoom_ok = False plt.title('zoom or pan') while not zoom_ok: zoom_ok = plt.waitforbuttonpress() plt.title('press space when ready to select points') plt.title('only two clicks are allowed, select the range') val = plt.ginput(2) val.sort() x_min,x_max = val[0][0], val[1][0] tolerance = 0.03 p1 = round(x_min,3) p2 = round(x_max,3) low_x = p1 - tolerance high_x = p2 + tolerance #print(low_x, high_x) indices = [] indices.clear() for i,j in zip(x,y): if i<= high_x and i>=low_x : k = x.index(i) indices.append(k) a,b = indices[0], indices[-1] x1 = x[a:b+1] y1 = y[a:b+1] #print(x1) #print(y1) x2 = np.array(x1) y2 = np.array(y1) #print(val) print("x_lower_limit",x_min, "x_upper_limit",x_max) return x2,y2
[docs] def jonscher_function(self,x,fc,DC,n): """ Jonscher power law function to fit the conductivity data Parameters ---------- x : float log frequency fc : float onset frequency DC : float DC conductivity value n : float power law exponent Returns ------- y : array estimated log conductivity based on supplied parameters. """ o = 10**(x) y = DC + (np.log10(1+(o/fc)**(n))) return y
[docs] def rbm_function(self,x,fc,DC): """ Jonscher power law function to fit the conductivity data Parameters ---------- x : float log frequency fc : float onset frequency DC : float DC conductivity value n : float power law exponent Returns ------- y : array estimated log conductivity based on supplied parameters. """ o = 10**(x) b = o/fc c = 1 + b**2 d = np.log(np.sqrt(c)) z1 = b*np.arctan(b) z2 = (d**2 + np.arctan(b)**2) z = z1/z2 y = DC + np.log10(z) return y
[docs] def dump_parameters(self): """ dumps the initial fit parameters for fit function as a dictionary in a json file to load it during curve fitting Returns ------- None """ f = float(input("enter the fc value:")) DC = float(input("enter the DC conductivity value:")) n = float(input("enter the exponent:")) fc = 10**f par = {"fc": fc, "DC": DC, "n": n} with open('cond.json',"w") as outfile: json.dump(par,outfile) with open('cond.json',"r") as openfile: loaded_par = json.load(openfile) print("dumped_parameters",loaded_par) return ()
def sel_function(self): """ A function to select the type of fit function during curve fitting Returns ------- func_decision : int choice of the fit function. """ func_decision = int(input( "Choose the fit function\n 1 -- Jonscher, 2 -- RBM:")) return func_decision
[docs] def fit(self,x,y): """ Fits the conductivity data with choice of fit function The fit parameters are declared as global variables to be saved via save_fit function The initial fit parameters are taken from json file and the final fit parameters are dumped in the same json file to be used for next iteration. Parameters ---------- x : array log frequency. y : array log conductivity. Returns ------- fit_par : dictionary dictionary containing the fit parameters. """ func_number = self.sel_function() x1 = np.array(x) y1= np.array(y) global popt1 global fit_fc,fit_DC,fit_n,fit_par plt.figure() if func_number == 1: try: open('cond.json') except FileNotFoundError as e: print(f'{e}' + '\n', "Please dump initial fit parameters using dump.parameters method") else: with open('cond.json',"r") as openfile: loaded_par = json.load(openfile) p0 = [loaded_par['fc'], loaded_par['DC'],loaded_par['n']] cond = self.jonscher_function popt1, pcov1 = curve_fit(cond, x1, y1, p0, bounds = ((1e-6,-15,0), (1e8,6,1))) yfit= cond(x1,*popt1) plt.scatter(x1,y1,marker='s',color='b',facecolors='none',label='data',s=100,linewidth=2) plt.plot(x1,yfit,'r--', label='Jonscher fit',linewidth=2) plt.xlabel('log ( f [Hz])') plt.ylabel('log ( $\sigma´$)') plt.legend() plt.show() fit_fc,fit_DC,fit_n = popt1[:] fit_par = {"fc": fit_fc, "DC": fit_DC, "n": fit_n} print("fit parameters:\n", popt1) print(f' DC cond = {fit_DC:.03f}') with open('cond.json',"w") as outfile: json.dump(fit_par,outfile) with open('cond.json',"r") as openfile: loaded_par = json.load(openfile) print("fit parameters dumped for next iteration",loaded_par) elif func_number ==2: try: open('cond.json') except FileNotFoundError as e: print(f'{e}' + '\n', "Please dump initial fit parameters using dump.parameters method") else: with open('cond.json',"r") as openfile: loaded_par = json.load(openfile) p0 = [loaded_par['fc'], loaded_par['DC']] cond = self.rbm_function popt1, pcov1 = curve_fit(cond, x1, y1, p0, bounds = ((1e-6,-15), (1e8,6))) yfit= cond(x1,*popt1) plt.scatter(x1,y1,marker='s',color='b',facecolors='none',label='data',s=100,linewidth=2) plt.plot(x1,yfit,'r--', label='RBM fit',linewidth=2) plt.xlabel('log ( f [Hz])') plt.ylabel('log ( $\sigma´$)') plt.legend() plt.show() fit_fc,fit_DC = popt1[:] n = 0 fit_par = {"fc": fit_fc, "DC": fit_DC,"n":n} print("fit parameters:\n", popt1) print(f' DC cond = {fit_DC:.03f}') with open('cond.json',"w") as outfile: json.dump(fit_par,outfile) with open('cond.json',"r") as openfile: loaded_par = json.load(openfile) print("fit parameters dumped for next iteration",loaded_par) return fit_par
[docs] def save_fit(self,T): """ saves the fit parameters of fit function in a file, the file must be created via create_analysis_file function Parameters ---------- T : float Temperature,or can also be an integer that corresponds to a file number during analysis. Returns ------- None. """ res_file = open(ana_file,'a') res_file.write( f'{T}' + '\t' + f'{fit_fc:.03f}' + '\t' + f'{fit_DC:.03f}' + '\t' + f'{fit_n:.03f}' +"\n") return ()