def find_FancyF(FD_file, woo=None, woh=None): from Converter import Constants from McUtils.Zachary import finite_difference mO = Constants.mass("O", to_AU=True) mH = Constants.mass("H", to_AU=True) freqoo = Constants.convert(woo, "wavenumbers", to_AU=True) muOO = mO / 2 freqoh = Constants.convert(woh, "wavenumbers", to_AU=True) muOH = ((2 * mO) * mH) / ((2 * mO) + mH) finite_vals = np.loadtxt(FD_file, skiprows=7) finite_vals = finite_vals[:, 2:] finite_vals[:, 0] *= 2 ens = finite_vals[:, 2] print( "Energy Difference from Minimum: ", Constants.convert(finite_vals[:, 2] - min(finite_vals[:, 2]), "wavenumbers", to_AU=False)) ohDiffs = np.array([ ens[1] - ens[0], ens[6] - ens[5], ens[11] - ens[10], ens[16] - ens[15], ens[21] - ens[20] ]) print("OH energy differences: ", Constants.convert(ohDiffs, "wavenumbers", to_AU=False)) finite_vals[:, :2] = Constants.convert( finite_vals[:, :2], "angstroms", to_AU=True) # convert to bohr for math idx = np.lexsort( (finite_vals[:, 0], finite_vals[:, 1])) # resort so same oh different oo finite_vals = finite_vals[idx] finite_vals = finite_vals.reshape((5, 5, 3)) FR = np.zeros(5) # compute first derivative wrt oo FR for j in range(finite_vals.shape[0]): x = finite_vals[j, :, 0] # roos y = finite_vals[j, :, 2] # energies print("OO energy difference: ", Constants.convert((y[1] - y[0]), "wavenumbers", to_AU=False)) FR[j] = finite_difference(x, y, 1, end_point_precision=0, stencil=5, only_center=True)[0] print(f"FR: {FR}") # compute mixed derivative FrrR FrrR = finite_difference(finite_vals[:, 1, 1], FR, 2, end_point_precision=0, stencil=5, only_center=True)[0] print(f"FrrR: {FrrR}") Qoo = np.sqrt(1 / muOO / freqoo) Qoh = np.sqrt(1 / muOH / freqoh) fancyF = FrrR * Qoh**2 * Qoo return Constants.convert(fancyF, "wavenumbers", to_AU=False)
def calc_derivs(fd_ohs, fd_oos, FDgrid, FDvalues): from McUtils.Zachary import finite_difference derivs = dict() firstOH = finite_difference(fd_ohs, FDvalues[2, :], 1, end_point_precision=0, stencil=5, only_center=True)[0] firstOO = finite_difference(fd_oos, FDvalues[:, 2], 1, end_point_precision=0, stencil=5, only_center=True)[0] secondOH = finite_difference(fd_ohs, FDvalues[2, :], 2, end_point_precision=0, stencil=5, only_center=True)[0] secondOO = finite_difference(fd_oos, FDvalues[:, 2], 2, end_point_precision=0, stencil=5, only_center=True)[0] thirdOH = finite_difference(fd_ohs, FDvalues[2, :], 3, end_point_precision=0, stencil=5, only_center=True)[0] thirdOO = finite_difference(fd_oos, FDvalues[:, 2], 3, end_point_precision=0, stencil=5, only_center=True)[0] mixedOHOO = finite_difference(FDgrid, FDvalues, (1, 1), stencil=(5, 5), accuracy=0, end_point_precision=0, only_center=True)[0, 0] mixedOHOOOO = finite_difference(FDgrid, FDvalues, (1, 2), stencil=(5, 5), accuracy=0, end_point_precision=0, only_center=True)[0, 0] mixedOHOHOO = finite_difference(FDgrid, FDvalues, (2, 1), stencil=(5, 5), accuracy=0, end_point_precision=0, only_center=True)[0, 0] # convert derivs to XH coordinate derivs["firstOH"] = firstOH * -1 derivs["firstOO"] = firstOO + (1 / 2) * firstOH derivs["secondOH"] = secondOH derivs["secondOO"] = secondOO + (1 / 4) * secondOH + (1 / 2) * mixedOHOO derivs["thirdOH"] = thirdOH * -1 derivs["thirdOO"] = thirdOO + (1 / 8) * thirdOH + (3 / 4) * mixedOHOHOO + (3 / 2) * mixedOHOOOO derivs["mixedOHOO"] = secondOH * -1 + mixedOHOO * -1 derivs["mixedOHOOOO"] = mixedOHOHOO * -1 + (-1 / 4) * thirdOH + mixedOHOHOO * -1 derivs["mixedOHOHOO"] = mixedOHOHOO + (1 / 2) * thirdOH return derivs
def calc_derivs(fd_ohs, fd_oos, FDgrid, FDvalues): from McUtils.Zachary import finite_difference derivs = dict() derivs["firstOH"] = finite_difference(fd_ohs, FDvalues[2, :], 1, end_point_precision=0, stencil=5, only_center=True)[0] derivs["firstOO"] = finite_difference(fd_oos, FDvalues[:, 2], 1, end_point_precision=0, stencil=5, only_center=True)[0] derivs["secondOH"] = finite_difference(fd_ohs, FDvalues[2, :], 2, end_point_precision=0, stencil=5, only_center=True)[0] derivs["secondOO"] = finite_difference(fd_oos, FDvalues[:, 2], 2, end_point_precision=0, stencil=5, only_center=True)[0] derivs["thirdOH"] = finite_difference(fd_ohs, FDvalues[2, :], 3, end_point_precision=0, stencil=5, only_center=True)[0] derivs["thirdOO"] = finite_difference(fd_oos, FDvalues[:, 2], 3, end_point_precision=0, stencil=5, only_center=True)[0] derivs["mixedOHOO"] = finite_difference(FDgrid, FDvalues, (1, 1), stencil=(5, 5), accuracy=0, end_point_precision=0, only_center=True)[0, 0] derivs["mixedOHOOOO"] = finite_difference(FDgrid, FDvalues, (1, 2), stencil=(5, 5), accuracy=0, end_point_precision=0, only_center=True)[0, 0] derivs["mixedOHOHOO"] = finite_difference(FDgrid, FDvalues, (2, 1), stencil=(5, 5), accuracy=0, end_point_precision=0, only_center=True)[0, 0] return derivs
def run_harOH_DVR(self, plotPhasedWfns=False): """ Runs a harmonic approximation using DVR to be fast over the OH coordinate at every OO value.""" from McUtils.Zachary import finite_difference dvr_1D = DVR("ColbertMiller1D") finite_dict = self.logData.finite_dict(midpoint=True) roos = np.array(list(finite_dict.keys())) potential_array = np.zeros((len(finite_dict), self.NumPts, 2)) energies_array = np.zeros((len(finite_dict), self.desiredEnergies)) wavefunctions_array = np.zeros( (len(finite_dict), self.NumPts, self.desiredEnergies)) for j, n in enumerate(finite_dict): x = Constants.convert(finite_dict[n][:, 0], "angstroms", to_AU=True) min_idx = np.argmin(finite_dict[n][:, 1]) sx = x - x[min_idx] y = finite_dict[n][:, 1] k = finite_difference(sx, y, 2, end_point_precision=0, stencil=5, only_center=True)[0] mini = min(sx) - 1.0 maxi = max(sx) + 1.0 res = dvr_1D.run(potential_function="harmonic_oscillator", k=k, mass=self.massdict["muOOH"], divs=self.NumPts, domain=(mini, maxi), num_wfns=self.desiredEnergies) potential = Constants.convert(res.potential_energy.diagonal(), "wavenumbers", to_AU=False) grid = Constants.convert((res.grid + x[min_idx]), "angstroms", to_AU=False) shiftgrid = (n / 2) + grid potential_array[j, :, 0] = shiftgrid potential_array[j, :, 1] = potential ens = Constants.convert((res.wavefunctions.energies + min(y)), "wavenumbers", to_AU=False) energies_array[j, :] = ens wavefunctions_array[j, :, :] = res.wavefunctions.wavefunctions epsilon_pots = np.column_stack((roos, energies_array[:, :4])) npz_filename = os.path.join( self.DVRdir, f"{self.method}_HarmOHDVR_energies{self.desiredEnergies}.npz") # data saved in wavenumbers/angstroms wavefuns_array = self.wfn_flipper(wavefunctions_array, plotPhasedWfns=plotPhasedWfns, pot_array=potential_array) np.savez(npz_filename, method="harm", potential=potential_array, epsilonPots=epsilon_pots, wfns_array=wavefuns_array) return npz_filename
def do_the_freqy_science(finite_dict): """ For the harmonic approximation.. takes the data from a very fine scan around minimum and uses finite differencing to calculate a force constant then OH frequency. :arg finite_dict: :returns freqs: frequencies of the shared proton stretch from the force constant of the roh (wavenumbers)""" from McUtils.Zachary import finite_difference roos = np.array(list(finite_dict.keys())) freqs = np.zeros(len(finite_dict)) mO = O * amutokg mH = H * amutokg muOH = ((2 * mO) * mH) / ((2 * mO) + mH) for j, n in enumerate(finite_dict): x = finite_dict[n][:, 0] * angtom E = finite_dict[n][:, 1] * hartoj # plt.plot(x, E, 'ob') # plt.show() Ediff = (finite_dict[n][1, 1] - finite_dict[n][2, 1]) * hartowave # print('E diff: ', E) # check the energy difference between grid points is good (5-10 cm^-1) k = finite_difference(x, E, 2, end_point_precision=0, stencil=5, only_center=True)[0] freqs[j] = (np.sqrt(k / muOH)) / hztowave fig = plt.figure() plt.plot(roos, freqs, 'ok') return fig
def getFC(self): from McUtils.Zachary import finite_difference # calculate harmonic force constants OO_FD = self.finite_vals[10:15, :] OH_FD = self.finite_vals[2::5, :] Frr = finite_difference(OO_FD[:, 1] - OO_FD[2, 1], OO_FD[:, 2], 2, end_point_precision=0, stencil=5, only_center=True)[0] FRR = finite_difference(OH_FD[:, 0] - OH_FD[2, 0], OH_FD[:, 2], 2, end_point_precision=0, stencil=5, only_center=True)[0] return Frr, FRR
def run_harOO_DVR(self, OHDVRres=None, plotPhasedWfns=False): """Fits epsilon potentials to a harmonic oscillator and then runs an OO DVR over it""" from McUtils.Zachary import finite_difference dvr_1D = DVR("ColbertMiller1D") OHresults = np.load(OHDVRres) epsi_pots = OHresults["epsilonPots"] potential_array = np.zeros((2, self.NumPts, 2)) energies_array = np.zeros((2, self.desiredEnergies)) wavefunctions_array = np.zeros((2, self.NumPts, self.desiredEnergies)) x = Constants.convert(epsi_pots[:, 0], "angstroms", to_AU=True) for j in np.arange(2): en = Constants.convert(epsi_pots[:, j + 1], "wavenumbers", to_AU=True) minE_idx = np.argmin(en) en_s = en[minE_idx - 2:minE_idx + 3] sx = x - x[minE_idx] k = finite_difference(sx[minE_idx - 2:minE_idx + 3], en_s, 2, end_point_precision=0, stencil=5, only_center=True)[0] mini = min(sx) - 1.0 maxi = max(sx) + 0.5 res = dvr_1D.run(potential_function="harmonic_oscillator", k=k, mass=self.massdict["muOO"], divs=self.NumPts, domain=(mini, maxi), num_wfns=self.desiredEnergies) potential = Constants.convert(res.potential_energy.diagonal() + en[minE_idx], "wavenumbers", to_AU=False) potential_array[j, :, 0] = Constants.convert( (res.grid + x[minE_idx]), "angstroms", to_AU=False) potential_array[j, :, 1] = potential ens = Constants.convert(res.wavefunctions.energies + en[minE_idx], "wavenumbers", to_AU=False) energies_array[j, :] = ens wavefunctions_array[j, :, :] = res.wavefunctions.wavefunctions npz_filename = os.path.join( self.DVRdir, f"{self.method}_harmOODVR_w{OHresults['method']}OHDVR_energies{self.desiredEnergies}.npz" ) # data saved in wavenumbers/angstroms wavefuns_array = self.wfn_flipper(wavefunctions_array, plotPhasedWfns=plotPhasedWfns, pot_array=potential_array) np.savez(npz_filename, potential=potential_array, energy_array=energies_array, wfns_array=wavefuns_array) return npz_filename
def getCC(self): from McUtils.Zachary import finite_difference FDgrid = np.array( np.meshgrid(np.unique(self.finite_vals[:, 0]), np.unique(self.finite_vals[:, 1]))).T # create mesh OO/OH FDvalues = np.reshape(self.finite_vals[:, 2], (5, 5)) FancyF3 = finite_difference(FDgrid, FDvalues, (1, 2), stencil=(5, 5), accuracy=0, end_point_precision=0, only_center=True)[0, 0] return (1 / 2) * FancyF3
def find_FancyF(self): import os from Converter import Constants from McUtils.Zachary import finite_difference mO = Constants.mass("O", to_AU=True) mH = Constants.mass("H", to_AU=True) freqoo = Constants.convert(self.omegaOO, "wavenumbers", to_AU=True) muOO = mO / 2 freqoh = Constants.convert(self.omegaOH, "wavenumbers", to_AU=True) muOH = ((2 * mO) * mH) / ((2 * mO) + mH) fs_dir = os.path.join(self.molecule.mol_dir, "Finite Scan Data", "twoD") if self.molecule.MoleculeName == "H9O4pls": finite_vals = np.loadtxt(f"{fs_dir}/2D_finiteSPEtet_01_008.dat", skiprows=7) elif self.molecule.MoleculeName == "H7O3pls": finite_vals = np.loadtxt(f"{fs_dir}/2D_finiteSPEtri_01_008.dat", skiprows=7) else: raise Exception("Can't compute FancyF of that molecule") finite_vals = finite_vals[:, 2:] finite_vals[:, 0] *= 2 # multiply OO/2 by 2 for OO values finite_vals[:, :2] = Constants.convert( finite_vals[:, :2], "angstroms", to_AU=True) # convert OO/OH to bohr finite_vals[:, 2] -= min( finite_vals[:, 2]) # shift minimum to 0 so that energies match FDgrid = np.array( np.meshgrid(np.unique(finite_vals[:, 0]), np.unique(finite_vals[:, 1]))).T # create mesh OO/OH FDvalues = np.reshape(finite_vals[:, 2], (5, 5)) FrrR = finite_difference(FDgrid, FDvalues, (1, 2), stencil=(5, 5), accuracy=0, end_point_precision=0, only_center=True)[0, 0] Qoo = np.sqrt(1 / muOO / freqoo) Qoh = np.sqrt(1 / muOH / freqoh) fancyF = FrrR * Qoh**2 * Qoo return Constants.convert(fancyF, "wavenumbers", to_AU=False)
def deriv_dipoles(interp_dipoles, roh_eq=1.0125, plot=False): """ Calculates the first derivatives of the interpolated dipole surfaces to be used in linear transition moment approximation :param interp_dipoles: big ol' array (col0:roo(ang), col1:roh(ang), col2:x-component, col3:y-component, col4:z-component, 3rd dimension: all different roos) :type interp_dipoles: np.ndarray :param roh_eq: equilibrium bond distance of the roh. :type roh_eq: float (4 decimal places) :param plot: If true, plots the dipole surface and its derivative (default=False) :type plot: bool :return: dipole derivatives (same shape as input) :rtype: np.ndarray """ from McUtils.Zachary import finite_difference import matplotlib.pyplot as plt rohs = interp_dipoles[0, :, 1] dip_vecs = interp_dipoles[:, :, 2:] eq_roh_idx = np.abs(rohs - roh_eq).argmin() g = rohs[eq_roh_idx - 2:eq_roh_idx + 3] new_dip_derivs = np.zeros((len(dip_vecs), 4)) for j in np.arange(3): for k, dip_vec in enumerate(dip_vecs): y = dip_vec[eq_roh_idx - 2:eq_roh_idx + 3, j] new_dip_derivs[k, 0] = interp_dipoles[k, 0, 0] new_dip_derivs[k, j + 1] = finite_difference(g, y, 2, end_point_precision=0, stencil=5, only_center=True)[0] if plot: plt.plot(g, y, 'o') plt.plot(g, new_dip_derivs[k, :, j + 2]) plt.xlabel('OH bond Distance ($\mathrm{\AA}$)') plt.ylabel('Dipole UNITS') plt.show() plt.close() return new_dip_derivs
def do_the_freqy_science(file): """ to continue with the harmonic approximation.. takes the data from a very fine scan around minimum and uses finite differencing to calculate a force constant then HO frequency. :arg file: a PES file, (five) points very close to minimum. :returns freq: frequency of the shared proton stretch from the force constant of the roh (wavenumbers)""" pts = np.loadtxt(file) angtom = 1E-10 hartoj = 4.35974E-18 amutokg = 1.66054E-27 hztowave = 2.99792E10 * (2 * np.pi) x = pts[:, 0] * angtom y = pts[:, 1] * hartoj E = (pts[1, 1] - pts[2, 1]) * 219474.6 # print('E diff: ', E) # check the energy difference between grid points is good (5-10 cm^-1) k = finite_difference(x, y, 2, end_point_precision=0, accuracy=0)[2] H = 1.007825 O = 15.994915 mO = O * amutokg mH = H * amutokg muOH = ((2 * mO) * mH) / ((2 * mO) + mH) freq = (np.sqrt(k / muOH)) / hztowave return freq
def run_harmonic_dvr(finitedat_dict, desired_energies=None, num_pts=None, mass='H', plots=False, save=False): """ Runs the DVR over the OH coordinate at every OO value. :param desired_energies: number of energies/wavefunctions to save to results objects :type desired_energies: int :param num_pts: number of points to cut DVR grid into :type num_pts: int :param plots: If True, plots and saves the potential energy of the cut with the wavefunctions overlaid at their appropriate energies. (default=False) :type plots: bool :param save: If True, saves the results as .npy files (default=False) :type save: bool :return: energies_array (col0-?: energies, rows: oo values), wavefunctions_array (col0-?: wavefunction values, 3rd dimension: oo values) :rtype: 2 np.ndarrays """ from McUtils.Zachary import finite_difference dvr_1D = DVR("ColbertMiller1D") roos = np.array(list(finitedat_dict.keys())) energies_array = np.zeros((len(finitedat_dict), desired_energies)) wavefunctions_array = np.zeros( (len(finitedat_dict), num_pts, desired_energies)) mO = O / amutome if mass == 'H': mH = H / amutome muOH = ((2 * mO) * mH) / ((2 * mO) + mH) mu = muOH if mass == 'D': mD = D / amutome muOD = ((2 * mO) * mD) / ((2 * mO) + mD) mu = muOD for j, n in enumerate(finitedat_dict): x = finitedat_dict[n][:, 0] * angtobohr sx = x - np.amin(x) y = finitedat_dict[n][:, 1] k = finite_difference(sx, y, 2, end_point_precision=0, stencil=5, only_center=True)[0] mini = min(sx) - 1.0 maxi = max(sx) + 1.0 res = dvr_1D.run(potential_function="harmonic_oscillator", k=k, mass=mu, divs=num_pts, domain=(mini, maxi), num_wfns=desired_energies) potential = res.potential_energy.diagonal() * hartowave ens = (res.wavefunctions.energies + min(y)) * hartowave energies_array[j, :] = ens wavefunctions_array[j, :, :] = res.wavefunctions.wavefunctions if plots: ang_grid = (res.grid + np.amin(x)) / angtobohr plt.rcParams.update({'font.size': 22}) plt.plot(ang_grid, potential, '-k', linewidth=6.0) # plt.ylim(0, 25000) # colors = ["purple", "violet", "orchid", "plum", "hotpink"] # for i, wf in enumerate(res.wavefunctions): # wfn = wf.data # * 5000 # wfn += ens[i] # plt.plot(ang_grid, wfn, colors[i]) ng = np.linspace(-0.55, -0.1, 10) g = [ens[0]] * 10 plt.plot(ng, g, "royalblue", linewidth=6.0) e = [ens[1]] * 10 plt.plot(ng, e, 'crimson', linewidth=6.0) plt.ylim(0, 8000) plt.xlim(-0.7, 0.2) plt.show() # plt.title("%s" % n) # plt.savefig(os.path.join( # os.path.dirname(os.path.dirname(__file__)), 'figures', 'cut DVR', 'no linesTGMho_rigid_Roo_%.3f.png' % n)) plt.close() oh_pots = np.column_stack((roos, energies_array[:, :3])) if save: VAA_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "VAA") np.save( os.path.join(VAA_dir, 'anharmonic data', 'rigid_DVR_OHpots.npy'), oh_pots) np.save( os.path.join(VAA_dir, 'anharmonic data', 'rigid_DVR_energies.npy'), energies_array) np.save( os.path.join(VAA_dir, 'anharmonic data', 'DVR wfns', 'rigid_DVR_wavefunctions.npy'), wavefunctions_array) return oh_pots, wavefunctions_array