plt.tight_layout() plt.savefig("y_vs_x.pdf", format='pdf') plt.show() # # Compare fits for ethane # In[15]: ch3ch3_interpolated = pyiast.InterpolatorIsotherm(df_ch3ch3, loading_key="Loading(mmol/g)", pressure_key="Pressure(bar)", fill_value=df_ch3ch3["Loading(mmol/g)"].max()) ch3ch3_langmuir = pyiast.ModelIsotherm(df_ch3ch3, loading_key="Loading(mmol/g)", pressure_key="Pressure(bar)", model="Langmuir") p_plot = np.logspace(np.log(df_ch3ch3['Pressure(bar)'].min()), np.log(80), num=200) fig = plt.figure() plt.xlabel("Pressure (bar)") plt.ylabel("Ethane uptake (mmol/g)") plt.scatter(df_ch3ch3['Pressure(bar)'], df_ch3ch3['Loading(mmol/g)'], marker='o', color='r', s=40, label='Data', clip_on=False) plt.plot(p_plot, ch3ch3_interpolated.loading(p_plot), color='k', linewidth=1, label='Linear interpolation', linestyle='--')
df_isotherm = pd.read_csv(filename) # set defaults for optimization algorithm guesses min = None good_guess = {'K':1, 'M':1} # run through set of starting guesses for the optimization algorithm for K in [300, 350, 400, 450, 500]: for M in ['-inf', 'inf', 1, 2, 3, 4, 5, 6]: # this is in try block because pyiast throws an exception if its optimization takes too long # (also a large reason why many satrting guesses are tried try: # print guesses print(f"{K}, {M}") # create model isotherm = pyiast.ModelIsotherm(df_isotherm, loading_key="Q" ,pressure_key = "pressure" , model = "Langmuir", param_guess={'K': K, 'M':M}) # if it's the best model, use those parameter guesses if isotherm.rmse < min or min == None: good_guess['K'], good_guess['M'] = K, M except: pass # in try block for same reason # (if no good guesses are found and it still fails) try: print("\n\nattempt\n\n") isotherm = pyiast.ModelIsotherm(df_isotherm, loading_key="Q" ,pressure_key = "pressure" , model = "Langmuir", param_guess={'K':good_guess['K'], 'M':good_guess['M']}) # if no exception is thrown, prints "success" print("\n\nsuccess\n\n") isotherm.print_params()
def run(test=False): # Set to False if you **do not** want to recalculate pure gas adsorption isotherms is_simulate_loadings = False loadings_file = 'loadings.dat' # Option to draw the isotherms: it is either **'ToFile'** or **'ToScreen'** (case insensitive). # Any other value will be interpreted as no graphics graphing = 'none' # Gas names as they will be referred through simulations gas_names = ['ch4', 'co2'] # Corresponding mole fractions of gases that will allow us to calculate their partial pressures through the Dalton's law mol_frac = [0.5, 0.5] # Calibrated previously functional forms of chemical potentials of gases for GCMC simulations as a functions of pressure chem_pots = [ lambda x: 2.4153 * numpy.log(x) - 36.722, lambda x: 2.40 * numpy.log(x) - 40.701 ] # Root directory for some data (For PySIMM examples it is ) data_dir = osp.join('..', '09_cassandra_simulations', 'gcmc') # Setup of adsorbate model gases = [] for gn in gas_names: gases.append(system.read_lammps(osp.join(data_dir, gn + '.lmps'))) gases[-1].forcefield = 'trappe/amber' # Setup of adsorbent model frame = system.read_lammps('pim.lmps') frame.forcefield = 'trappe/amber' # Constant for loadings calculations molec2mmols_g = 1e+3 / frame.mass # Setup of the GCMC simulations css = cassandra.Cassandra(frame) sim_settings = css.read_input('run_props.inp') # This function in given context will calculate the loading from short GCMC simulations def calculate_isotherm_point(gas_name, press): run_fldr = osp.join(gas_name, str(press)) idx = gas_names.index(gas_name) # sim_settings.update({'Run_Name': 'gcmc'}) css.add_gcmc(species=gases[idx], is_new=True, chem_pot=chem_pots[idx](press), out_folder=run_fldr, props_file='gcmc.inp', **sim_settings) css.run() full_prp = css.run_queue[0].get_prp() return molec2mmols_g * numpy.average( full_prp[3][int(len(2 * full_prp[3]) / 3):]) # This function in given context will load the pre-calculated loading value from previously done GCMC simulations def load_isotherm_point(gas_name, press): with open(loadings_file, 'r') as pntr: stream = pntr.read() tmp = stream.split('\n' + gas_name)[1] idx = re.search('[a-zA-Z]|\Z', tmp) value = re.findall('\n{:}\s+\d+\.\d+'.format(press), tmp[:idx.start()])[0] return float(re.split('\s+', value)[-1]) # Calculation of adsorption isotherms for pure CH4 and CO2 gases for further usage in IAST simulations. # This is the **MOST TIME CONSUMING STEP** in this example, if you want to skip it switch the key is_simulated to False # The IAST will be done using PyIAST package, thus isotherms are wrapped into the corresponding object gas_press = [0.1, 1, 5, 10, 25, 50] lk = 'Loading(mmol/g)' pk = 'Pressure(bar)' isotherms = [] loadings = dict.fromkeys(gas_names) for gn in gas_names: loadings[gn] = [] for p in gas_press: if is_simulate_loadings: data = calculate_isotherm_point(gn, p) else: data = load_isotherm_point(gn, p) loadings[gn].append(data) isotherms.append( pyiast.ModelIsotherm(pandas.DataFrame(zip(gas_press, loadings[gn]), columns=[pk, lk]), loading_key=lk, pressure_key=pk, model='BET', optimization_method='Powell')) # The PyIAST run for calculating of mixed adsorption isotherm # Initial guesses of adsorbed mole fractions do span broad range of values, because PyIAST might not find # solution at certain values of mole fractions and through an exception guesses = [[a, 1 - a] for a in numpy.linspace(0.01, 0.99, 50)] for in_g in guesses: mix_loadings = [] try: for p in gas_press: mix_loadings.append( list( pyiast.iast(p * numpy.array(mol_frac), isotherms, verboseflag=False, adsorbed_mole_fraction_guess=in_g))) mix_loadings = numpy.array(mix_loadings) break except: print('Initial guess {:} had failed to converge'.format(in_g)) continue mix_loadings = numpy.sum(mix_loadings, axis=1) mix_isotherm = pyiast.ModelIsotherm(pandas.DataFrame(zip( gas_press, mix_loadings), columns=[pk, lk]), loading_key=lk, pressure_key=pk, model='BET', optimization_method='L-BFGS-B') # Output: Graphing of constructed isotherms def _plot_isotherms(ax, loc_gp, loc_isoth, loc_mix_load, loc_mix_isoth): rng = numpy.linspace(min(loc_gp), max(loc_gp), 100) ax.plot(loc_gp, loadings[gas_names[0]], 'og', lw=2.5, label='{:} loadings'.format(gas_names[0].upper())) ax.plot(rng, [loc_isoth[0].loading(t) for t in rng], '--g', lw=2, label='BET fit of {:} loadings'.format(gas_names[0].upper())) ax.plot(loc_gp, loadings[gas_names[1]], 'or', lw=2.5, label='{:} loadings'.format(gas_names[1].upper())) ax.plot(rng, [loc_isoth[1].loading(t) for t in rng], '--r', lw=2, label='BET fit of {:} loadings'.format(gas_names[1].upper())) ax.plot(loc_gp, loc_mix_load, 'ob', lw=2.5, label='1-to-1 mixture loadings') ax.plot(rng, [loc_mix_isoth.loading(t) for t in rng], '--b', lw=2, label='BET fit of 1-to-1 mixture loadings') ax.set_xlabel('Gas pressure [bar]', fontsize=20) ax.set_ylabel('Loading [mmol / g]', fontsize=20) ax.tick_params(axis='both', labelsize=16) ax.grid(True) ax.legend(fontsize=16) mplp.tight_layout() if graphing.lower() == 'tofile': fig, axs = mplp.subplots(1, 1, figsize=(10, 5)) _plot_isotherms(axs, gas_press, isotherms, mix_loadings, mix_isotherm) mplp.savefig('pim1_mix_adsorption.png', dpi=192) elif graphing.lower() == 'toscreen': mplp.figure() axs = mplp.gca() _plot_isotherms(axs, gas_press, isotherms, mix_loadings, mix_isotherm) mplp.show() with open('iast_loadings.dat', 'w') as pntr: pntr.write('{:}\t\t{:}\n'.format(pk, lk)) pntr.write('{:}-{:} 1-to-1\n'.format(gas_names[0], gas_names[1])) for p, ml in zip(gas_press, mix_loadings): pntr.write('{:}\t\t{:}\n'.format(p, ml))
# ## Test model fits # Loop through all models, generate synthetic data using parameters in `model_params` and the `loading` function here, then fit model using pyIAST. Plot data and fits, check that pyIAST identified parameters match the model. # In[5]: for model in models: print("Testing model:", model) # Generate synthetic data df = pd.DataFrame() df['P'] = np.linspace(0, 1, 40) df['L'] = loading(df['P'], model) # use pyIAST to fit model to data isotherm = pyiast.ModelIsotherm( df, pressure_key='P', loading_key='L', model=model) isotherm.print_params() # plot fit P_plot = np.linspace(0, 1, 100) fig = plt.figure() plt.scatter(df['P'], df['L'], label='Synthetic data', clip_on=False) plt.plot(P_plot, isotherm.loading(P_plot), label='pyIAST fit') plt.xlim([0, 1]) plt.ylim(ymin=0) plt.xlabel('Pressure') plt.ylabel('Uptake') plt.title(model) plt.legend(loc='lower right') plt.show()
dfs = [ pd.DataFrame({ 'P': pressure, 'L': M * langmuirKs[i] * pressure / (1.0 + langmuirKs[i] * pressure) }) for i in range(3) ] # Use pyIAST to fit Lanmguir models to the data, then plot fits # In[4]: isotherms = [ pyiast.ModelIsotherm(dfs[i], pressure_key='P', loading_key='L', model='Langmuir') for i in range(3) ] for i in range(len(isotherms)): isotherms[i].print_params() pyiast.plot_isotherm(isotherms[i]) # Plot synthetic data all in one plot for paper # In[5]: p_plot = np.logspace(-3, np.log10(11)) # for plotting fig = plt.figure(facecolor='w') for i in range(len(isotherms)):
import pyiast as pt import pandas as pd my_data = pd.read_excel("path_to_excel_file") # load dataframe from excel my_data.to_csv("path_to_save_file.csv") # save it as .csv isotherm = pt.ModelIsotherm( my_data, loading_key="Loading(mmol/g)", pressure_key="Pressure(bar)", model="Langmuir" ) # "Langmuir", "M", "K", "Quadratic", "BET", "DSLangmuir", "TemkinApprox", "Henry" isotherm.print_params() small = None big = None while True: inp = input("please input a number:") if inp == "done": break try: num = int(inp) except ValueError: print("Error: not a number") continue if small is None: small = big = num
import pyiast import pandas as pd ##################################################### ### plots a model of the isotherm ### ### see pyIAST documentation for available models ### ##################################################### # replace path with csv containing isotherm data df_isotherm = pd.read_csv("/users/noahwhelpley/Downloads/Book2.csv") isotherm = pyiast.ModelIsotherm(df_isotherm, loading_key="Q", pressure_key="pressure", model="Langmuir") isotherm.print_params() pyiast.plot_isotherm(isotherm)
lk = 'Loading(mmol/g)' pk = 'Pressure(bar)' isotherms = [] loadings = dict.fromkeys(gas_names) for gn in gas_names: loadings[gn] = [] for p in gas_press: if is_simulate_loadings: data = calculate_isotherm_point(gn, p) else: data = load_isotherm_point(gn, p) loadings[gn].append(data) isotherms.append( pyiast.ModelIsotherm(pandas.DataFrame(zip(gas_press, loadings[gn]), columns=[pk, lk]), loading_key=lk, pressure_key=pk, model='BET', optimization_method='Powell')) # The PyIAST run for calculating of mixed adsorption isotherm # Initial guesses of adsorbed mole fractions do span broad range of values, because PyIAST might not find # solution at certain values of mole fractions and through an exception guesses = [[a, 1 - a] for a in numpy.linspace(0.01, 0.99, 50)] for in_g in guesses: mix_loadings = [] try: for p in gas_press: mix_loadings.append( list( pyiast.iast(p * numpy.array(mol_frac), isotherms,