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
예제 #3
0
 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
예제 #4
0
    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
예제 #5
0
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
예제 #7
0
 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)
예제 #10
0
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
예제 #11
0
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
예제 #12
0
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