Source code for pygacity.pythontex.monkeypatches.chemeqsystem

"""
Monkeypatches for ChemEqSystem class in sandler module (imported from sandlertools) to add LaTeX reporting capabilities.
"""

from sandlertools import ChemEqSystem
from ..texutils import format_sig, table_as_tex, Cp_as_tex, algebraify, symneg
import roman
import numpy as np

[docs] def texgen_kacalculations(self, simplified=False, sig=5) -> str: """ Generates LaTeX string for equilibrium constant calculations. Parameters ---------- simplified : bool, optional whether to use simplified van't Hoff equation (default is False) sig : int, optional number of significant figures for formatting (default is 5) Returns ------- str LaTeX formatted string of equilibrium constant calculations """ ka_calcslines = [] R_val = self.R.m_as('J/(mol*K)') if hasattr(self.R, 'magnitude') else float(self.R) T_val = self.T.m_as('K') if hasattr(self.T, 'magnitude') else float(self.T) T0_val = self.T0.m_as('K') if hasattr(self.T0, 'magnitude') else float(self.T0) Rval = f'{R_val:.3f}' Tval = f'{T_val:.2f}' T0val = f'{T0_val:.2f}' for i in range(self.M): rxn_super = '' if self.M > 1: ka_calcslines.append(rf'\underline{{Reaction {roman.toRoman(i+1)}}}\\') rxn_super = f'^{{{roman.toRoman(i+1)}}}' ka0 = 'K_a'+rxn_super + r'(T_0)' kaT = 'K_a'+rxn_super + r'(T)' ka0_val = f'{format_sig(self.Ka0[i],sig)}' kaT_val = f'{format_sig(self.KaT[i],sig)}' kaT_simplified_val = f'{format_sig(self.KaT_simplified[i],sig)}' n_gr = r'-\gr'+rxn_super n_hr = r'-\hr'+rxn_super n_gr_val = symneg(self.dGr[i], 5) n_hr_val = symneg(self.dHr[i], 5) ka_calcslines.append(r'\begin{align*}') # first line -- show calculation of Ka0 ka_calcslines.append(ka0 + r' & = ' + r'\exp\left[\frac{' + n_gr + r'}{R T_0}\right]') ka_calcslines.append(r' = ' + r'\exp\left[\frac{' + n_gr_val + r'}{(' + Rval + r')(' + T0val + r')}\right]') ka_calcslines.append(r' = ' + ka0_val + r'\\') if simplified: # second line -- show simplified van't Hoff calculation symbolically ka_calcslines.append( kaT + r' & = ' + ka0 + r'\exp\left[\frac{' + n_hr + r'}{R}\left(\frac{1}{T} - \frac{1}{T_0}\right)\right]\\') # third line -- show simplified van't Hoff calculation numerically ka_calcslines.append( r' & = (' + ka0_val + r')\exp\left[\frac{' + n_hr_val + r'}{' + Rval + r'}' r'\left(\frac{1}{' + Tval + r'} - \frac{1}{' + T0val + r'}\right)\right]\\') ka_calcslines.append(r'& = ' + kaT_simplified_val + r'\\') else: """ arg1 = self.dCp[0]/self.R * np.log(self.T/self.T0) arg2 = self.dCp[1]/(2*self.R) * (self.T - self.T0) arg3 = self.dCp[2]/(6*self.R) * (self.T**2 - self.T0**2) arg4 = self.dCp[3]/(12*self.R) * (self.T**3 - self.T0**3) bigterm1 = arg1 + arg2 + arg3 + arg4 rtdiff = 1/self.R*(1/self.T - 1/self.T0) term5 = -self.dHr term6 = self.dCp[0] * self.T0 term7 = self.dCp[1] / 2 * self.T0**2 term8 = self.dCp[2] / 3 * self.T0**3 term9 = self.dCp[3] / 4 * self.T0**4 bigterm2 = rtdiff * (term5 + term6 + term7 + term8 + term9) logratio = bigterm1 + bigterm2 self.KaT = self.Ka0 * np.exp(logratio)""" vht = self.vantHoff_terms Cp = self.dCp[4*i:4*(i+1)] # heat-capacity difference coefficients for reaction i # second line -- show full van't Hoff calculation symbolically lnKK = r'\ln\frac{' + kaT + r'}{' + ka0 + r'}' arg1 = r'\frac{a}{R}\ln{\frac{T}{T_0}}' arg2 = r'\frac{b}{2R}(T - T_0)' arg3 = r'\frac{c}{6R}(T^2 - T_0^2)' arg4 = r'\frac{d}{12R}(T^3 - T_0^3)' bigterm1 = arg1 + r' + ' + arg2 + r' + ' + arg3 + r' + ' + arg4 rtdiff = r'\frac{1}{R}\left(\frac{1}{T} - \frac{1}{T_0}\right)' term5 = n_hr term6 = r'a T_0' term7 = r'\frac{b}{2} T_0^2' term8 = r'\frac{c}{3} T_0^3' term9 = r'\frac{d}{4} T_0^4' bigterm2 = rtdiff + r' \left(' + term5 + r' + ' + term6 + r' + ' + term7 + r' + ' + term8 + r' + ' + term9 + r'\right)' ka_calcslines.append( lnKK + r' & = ' + bigterm1 + r'\\') ka_calcslines.append( r' & + ' + bigterm2 + r'\\') arg1_subst_var = f'\\frac{{{Cp[0]:.3f}}}{{{R_val:.3f}}}\\ln{{\\frac{{{T_val:.2f}}}{{{T0_val:.2f}}}}}' arg2_subst_var = f'\\frac{{{Cp[1]:.4f}}}{{2\\times{R_val:.3f}}}({T_val:.2f} - {T0_val:.2f})' arg3_subst_var = f'\\frac{{{Cp[2]:.4f}}}{{6\\times{R_val:.3f}}}({T_val**2:.2f} - {T0_val**2:.2f})' arg4_subst_var = f'\\frac{{{Cp[3]:.4f}}}{{12\\times{R_val:.3f}}}({T_val**3:.2f} - {T0_val**3:.2f})' bigterm1_subst = arg1_subst_var + r' + ' + arg2_subst_var + r' + ' + arg3_subst_var + r' + ' + arg4_subst_var rtdiff_subst = f'\\frac{{1}}{{{R_val:.3f}}}\\left(\\frac{{1}}{{{T_val:.2f}}} - \\frac{{1}}{{{T0_val:.2f}}}\\right)' term5_subst = n_hr_val term6_subst = f'{Cp[0]:.3f} \\times {T0_val:.2f}' term7_subst = f'\\frac{{{Cp[1]:.4f}}}{{2}} \\times {T0_val**2:.2f}' term8_subst = f'\\frac{{{Cp[2]:.4f}}}{{3}} \\times {T0_val**3:.2f}' term9_subst = f'\\frac{{{Cp[3]:.4f}}}{{4}} \\times {T0_val**4:.2f}' bigterm2_subst = rtdiff_subst + r' \left(' + term5_subst + r' + ' + term6_subst + r' + ' + term7_subst + r' + ' + term8_subst + r' + ' + term9_subst + r'\right)' ka_calcslines.append( r'& = ' + bigterm1_subst + r'\\') ka_calcslines.append( r'& + ' + bigterm2_subst + r'\\') arg1_eval = f'{vht["arg1"]:.5f}' arg2_eval = f'{vht["arg2"]:.5f}' arg3_eval = f'{vht["arg3"]:.5f}' arg4_eval = f'{vht["arg4"]:.5f}' bigterm1_eval = arg1_eval + r' + ' + arg2_eval + r' + ' + arg3_eval + r' + ' + arg4_eval rtdiff_eval = f'{vht["rtdiff"]:.5e}' term5_eval = n_hr_val term6_eval = f'{vht["term6"]:.5f}' term7_eval = f'{vht["term7"]:.5f}' term8_eval = f'{vht["term8"]:.5f}' term9_eval = f'{vht["term9"]:.5f}' bigterm2_eval = rtdiff_eval + r' \left(' + term5_eval + r' + ' + term6_eval + r' + ' + term7_eval + r' + ' + term8_eval + r' + ' + term9_eval + r'\right)' ka_calcslines.append( r'& = ' + bigterm1_eval + r'\\') ka_calcslines.append( r'& + ' + bigterm2_eval + r'\\') logratio_eval = f'{float(vht["logratio"][i]):.5f}' ka_calcslines.append( r'& = ' + logratio_eval + r'\\') ka_calcslines.append( kaT + r' & = ' + ka0_val + r'\exp\left[' + logratio_eval + r'\right]\\') ka_calcslines.append( r'& = ' + kaT_val + r'\\') ka_calcslines.append(r'\end{align*}') return '\n'.join(ka_calcslines)
[docs] def stoichiometrictable_as_tex(self, sig: int = 3): """ Generates LaTeX formatted stoichiometric table. Parameters ---------- sig : int, optional number of significant figures for floating point numbers (default is 3) Returns ------- str LaTeX formatted stoichiometric table """ total_row = ['Totals:'] col1 = [c.as_tex() for c in self.components] # fstr = f'{{:.{sig}g}}' col2 = [r'\(' + format_sig(n, sig=sig) + r'\)' for n in self.N0] total_row += [r'\(' + format_sig(self.N0.sum(), sig=sig) + r'\)'] tabledict = {'Species': col1, r'$N_{0,i}$': col2} tabledict[f'$N_{{i}}$'] = [] Nus = [self.nu[j].sum() for j in range(self.M)] Nis = [] for i,c in enumerate(self.components): Ni = format_sig(self.N0[i], sig=sig) for j,r in enumerate(self.reactions): nu_sign = [' + ' if self.nu[j][i]>=0 else ' - ' for i in range(self.C)] Xj = f'X_{{{roman.toRoman(j+1)}}}' if self.M>1 else 'X' Ni += f'{nu_sign[i]}\\left({format_sig(np.fabs(self.nu[j][i]), sig=sig)}\\right){Xj}' Nis.append(Ni) tabledict[f'$N_{{i}}$'].append(r'\('+Ni+r'\)') Ni_total = format_sig(self.N0.sum(), sig=sig) for j in range(self.M): nu_sign = ' + ' if Nus[j]>=0 else ' - ' Xj = f'X_{{{roman.toRoman(j+1)}}}' if self.M>1 else 'X' Ni_total += f'{nu_sign}\\left({format_sig(np.fabs(Nus[j]), sig=sig)}\\right){Xj}' total_row += [r'\('+Ni_total+r'\)'] tabledict[f'$y_{{i}} = N_{{i}} / \\sum_{{i}} N_{{i}}$'] = [] for i in range(self.C): yi = r'\left[' + Nis[i] + r'\right] / \left[' + Ni_total + r'\right]' tabledict[f'$y_{{i}} = N_{{i}} / \\sum_{{i}} N_{{i}}$'].append(r'\('+yi+r'\)') total_row += [r'\(1.0\)'] return table_as_tex(tabledict, sig=sig, total_row=total_row, index=False)
[docs] def thermochemicaltable_as_tex(self, sig: int = 3): """ Generates LaTeX formatted thermochemical data table for components. Parameters ---------- sig : int, optional number of significant figures for floating point numbers (default is 3) Returns ------- str LaTeX formatted thermochemical data table """ # if self.dHf is a pint.Quantity, get its units # to use in the table header if hasattr(self.components[0].dHf, 'units'): dHf_units = f'{self.components[0].dHf.units:~P}' dGf_units = f'{self.components[0].dGf.units:~P}' else: dHf_units = 'J/mol' dGf_units = 'J/mol' return table_as_tex({ 'Species':[c.as_tex() for c in self.components], rf'$\hf$ ({dHf_units})':[c.dHf.m for c in self.components], rf'$\gf$ ({dGf_units})':[c.dGf.m for c in self.components]}, drop_zeros=[False,True,True], sig = sig)
ChemEqSystem.texgen_kacalculations = texgen_kacalculations ChemEqSystem.stoichiometrictable_as_tex = stoichiometrictable_as_tex ChemEqSystem.thermochemicaltable_as_tex = thermochemicaltable_as_tex