コード例 #1
0
ファイル: statmech.py プロジェクト: shihchengli/APE
    def load_save(self):
        self.sampling = SamplingJob(self.label,
                                    self.input_file,
                                    ncpus=self.ncpus)
        self.sampling.parse()
        self.is_QM_MM_INTERFACE = self.sampling.is_QM_MM_INTERFACE
        self.conformer = self.sampling.conformer
        self.csv_path = os.path.join(
            self.output_directory, '{}_samping_result.csv'.format(self.label))
        self.mode_dict, self.energy_dict, self.min_elect = from_sampling_result(
            self.csv_path)
        self.zpe_of_Hohf = self.sampling.zpe
        e0 = self.min_elect * constants.E_h * constants.Na + self.sampling.zpe
        self.conformer.E0 = (e0, "J/mol")
        for mode in self.conformer.modes:
            if isinstance(mode, HarmonicOscillator):
                frequencies = mode.frequencies.value_si
                mode.frequencies = (frequencies * self.frequency_scale_factor,
                                    "cm^-1")
        self.spin_multiplicity = self.conformer.spin_multiplicity
        self.optical_isomers = self.conformer.optical_isomers
        self.symbols = self.sampling.symbols

        # Solve SE of 1-D PES and calculate E S G Cp
        self.polynomial_dict = cubic_spline_interpolations(
            self.energy_dict, self.mode_dict)

        # Extract whether this system is QM/MM system or not
        self.is_QM_MM_INTERFACE = self.sampling.is_QM_MM_INTERFACE
コード例 #2
0
def main():
    args = parse_command_line_arguments()
    input_file = args.file.split('/')[-1]
    ncpus = args.n
    protocol = args.p
    T = args.T
    nsamples = args.ns if args.ns is not None else 1000
    nchains = args.nc if args.nc is not None else 5
    nburn = args.nburn if args.nburn is not None else int(nsamples / 5)
    hpc = args.hpc
    if not protocol:
        protocol = 'TNUTS'
    if not T:
        T = 300
    project_directory = os.path.abspath(os.path.dirname(args.file))

    # SCRATCH directory must be set before script runs
    # This is done for ease of transferability to different hardware setups
    output_directory = os.path.expandvars('$SCRATCH')

    # imaginary bonds for QMMM calculation
    # atom indices starts from 1
    imaginary_bonds = args.i
    if args.i is not None:
        imaginary_bonds_string = imaginary_bonds.strip('[').strip(']')
        imaginary_bonds = []
        for bond in imaginary_bonds_string.split(','):
            atom1, atom2 = bond.split('-')
            imaginary_bonds.append([int(atom1), int(atom2)])

    label = input_file.split('.')[0]
    Log = QChemLog(os.path.join(project_directory, input_file))
    level_of_theory_kwargs = get_level_of_theory(Log)
    samp_object = SamplingJob(input_file=os.path.join(project_directory,
                                                      input_file),
                              label=label,
                              ncpus=ncpus,
                              output_directory=output_directory,
                              protocol=protocol,
                              thresh=0.5,
                              **level_of_theory_kwargs)
    samp_object.parse()
    # With APE updates, should edit APE sampling.py to [only] sample torsions
    #xyz_dict, energy_dict, mode_dict = samp_obj.sampling()
    priors = ['umvt']
    methods = ['NUTS', 'HMC', 'MH']

    sampling_kwargs = dict(draws=nsamples, chains=nchains, tune=nburn)
    MCObj = MCMCTorsions(samp_object, T, sampling_kwargs, hpc=hpc, ncpus=ncpus)

    step_kwargs = dict()
    methods = ['NUTS']
    priors = ['umvt']
    for prior in priors:
        for method in methods:
            MCObj.sample(prior, method, **step_kwargs)
コード例 #3
0
def species(label, *args, **kwargs):
    """Load a species from an input file"""
    global species_dict, job_list, directory
    if label in species_dict:
        raise ValueError(
            'Multiple occurrences of species with label {0!r}.'.format(label))
    logging.info('Loading species {0}...'.format(label))

    spec = Species(label=label)
    species_dict[label] = spec

    path = None
    if len(args) == 1:
        # The argument is a path to a conformer input file
        path = os.path.join(directory, args[0])
        spec.path = path
        job = SamplingJob(label=label,
                          input_file=path,
                          output_directory=output_directory)
        spec.conformer, unscaled_frequencies = QChemLog(path).load_conformer()
        job_list.append(job)
    elif len(args) > 1:
        raise InputError('species {0} can only have two non-keyword argument '
                         'which should be the species label and the '
                         'path to a quantum file.'.format(spec.label))

    if len(kwargs) > 0:
        # The species parameters are given explicitly
        protocol = 'UMVT'
        E0 = None
        multiplicity = None
        charge = None
        rotors = None
        for key, value in kwargs.items():
            if key == 'protocol':
                protocol = value.upper()
            elif key == 'E0':
                E0 = value
            elif key == 'multiplicity':
                multiplicity = value
            elif key == 'charge':
                charge = value
            elif key == 'rotors':
                rotors = value
            else:
                raise TypeError(
                    'species() got an unexpected keyword argument {0!r}.'.
                    format(key))

        spec.conformer.E0 = E0

        job.protocol = protocol
        job.multiplicity = multiplicity
        job.charge = charge
        job.rotors = rotors

    return spec
コード例 #4
0
ファイル: thermo.py プロジェクト: lbettins/T-NUTS
    def __init__(self,
                 results_directory,
                 T,
                 sampT=300,
                 samp_obj=None,
                 model=None,
                 P=101325,
                 t_protocols=['PG', 'UMVT', 'HO'],
                 t_subprotocols=['C', 'U'],
                 sb_protocols=['HO', 'UMVT'],
                 sb_subprotocols=['HO', 'UMVT']):
        self.resdir = results_directory
        self.model = model
        self.sampT = sampT
        self.T = T
        self.rat = self.sampT / self.T
        self.P = P
        ###
        self.acm, self.bEcm, self.Ecvar,\
                self.DEcm, self.S = create_dfs(self.resdir,
                        sampT=self.sampT)
        ###
        self.samp_obj = samp_obj
        # Reiteration of 'load_save' from ape.statmech
        # Care should be taken to move '.csv' sampling result and the
        # '.out' input file to the results directory
        if self.samp_obj is None:
            for f in os.listdir(self.resdir):
                if not '.out' in f:
                    continue
                input_f = f
                break
            input_file = os.path.join(self.resdir, input_f)
            label = input_f.split('.')[0]
            self.samp_obj = SamplingJob(label, input_file, protocol='UMVT')
            self.samp_obj.parse()
        self.conformer = self.samp_obj.conformer
        self.label = self.samp_obj.label
        self.Thermo = ThermoJob(self.label,
                                self.samp_obj.input_file,
                                output_directory=self.resdir,
                                P=self.P)
        self.Thermo.load_save()
        #self.tmodes = dicts_to_NModes(self.Thermo.mode_dict,
        #        self.Thermo.energy_dict,
        #        xyz_dict=None,
        #        just_tors=True)
        #self.NModes
        self.t_protocols = np.atleast_1d(t_protocols)
        self.t_subprotocols = np.atleast_1d(t_subprotocols)
        self.sb_protocols = np.atleast_1d(sb_protocols)
        self.sb_subprotocols = np.atleast_1d(sb_subprotocols)

        # Data frame initialization
        # label | mode | prot | sub | sbprot | sbsub | E0 | E | S | Cv | Q
        # ----- | ---- | ---- | --- | ------ | ----- | -- | - | - | -- | -
        # Ex.   |      |      |     |        |       |    |   |   |    |
        # "s15" | "sb" |  NaN |  NaN|  "ho"  | "umvt"|  α | β | γ |  δ | ε
        # "s15" |"tors"| "pg" | "cc"| "umvt" |  NaN  |  Α | B | Γ |  Δ | Ε
        # "s15" | "rot"|  NaN |  NaN|  NaN   |  NaN  |  ζ | η | θ |  ι | κ
        # "s15" |"trns"|  NaN |  NaN|  NaN   |  NaN  |  Ζ | Η | Θ |  Ι | Κ
        # "s20" |"tors"| "pg" | "uu"|  "ho"  |  "ho" |  λ | μ | ν |  ξ | π
        # "s1"  |"tors"|"umvt"|  NaN|  NaN   |  NaN  |  Λ | Μ | Ν |  Ξ | Π
        self.csv = os.path.join(
            self.resdir, "thermo{T}_{label}.csv".format(T=self.T,
                                                        label=self.label))
        self.total_thermo = get_data_frame(self.csv)
        self.data_frame = pd.DataFrame({'mode': []})
コード例 #5
0
ファイル: thermo.py プロジェクト: lbettins/T-NUTS
class MCThermoJob:
    """
    The class to calculate thermodynamic properties
    Units are finalized in kcal/mol or cal/mol, with inputs in Hartree
    ZPE [=] kcal/mol
    E   [=] kcal/mol
    S   [=] cal/mol.K
    Cv  [=] cal/mol.K
    """
    def __init__(self,
                 results_directory,
                 T,
                 sampT=300,
                 samp_obj=None,
                 model=None,
                 P=101325,
                 t_protocols=['PG', 'UMVT', 'HO'],
                 t_subprotocols=['C', 'U'],
                 sb_protocols=['HO', 'UMVT'],
                 sb_subprotocols=['HO', 'UMVT']):
        self.resdir = results_directory
        self.model = model
        self.sampT = sampT
        self.T = T
        self.rat = self.sampT / self.T
        self.P = P
        ###
        self.acm, self.bEcm, self.Ecvar,\
                self.DEcm, self.S = create_dfs(self.resdir,
                        sampT=self.sampT)
        ###
        self.samp_obj = samp_obj
        # Reiteration of 'load_save' from ape.statmech
        # Care should be taken to move '.csv' sampling result and the
        # '.out' input file to the results directory
        if self.samp_obj is None:
            for f in os.listdir(self.resdir):
                if not '.out' in f:
                    continue
                input_f = f
                break
            input_file = os.path.join(self.resdir, input_f)
            label = input_f.split('.')[0]
            self.samp_obj = SamplingJob(label, input_file, protocol='UMVT')
            self.samp_obj.parse()
        self.conformer = self.samp_obj.conformer
        self.label = self.samp_obj.label
        self.Thermo = ThermoJob(self.label,
                                self.samp_obj.input_file,
                                output_directory=self.resdir,
                                P=self.P)
        self.Thermo.load_save()
        #self.tmodes = dicts_to_NModes(self.Thermo.mode_dict,
        #        self.Thermo.energy_dict,
        #        xyz_dict=None,
        #        just_tors=True)
        #self.NModes
        self.t_protocols = np.atleast_1d(t_protocols)
        self.t_subprotocols = np.atleast_1d(t_subprotocols)
        self.sb_protocols = np.atleast_1d(sb_protocols)
        self.sb_subprotocols = np.atleast_1d(sb_subprotocols)

        # Data frame initialization
        # label | mode | prot | sub | sbprot | sbsub | E0 | E | S | Cv | Q
        # ----- | ---- | ---- | --- | ------ | ----- | -- | - | - | -- | -
        # Ex.   |      |      |     |        |       |    |   |   |    |
        # "s15" | "sb" |  NaN |  NaN|  "ho"  | "umvt"|  α | β | γ |  δ | ε
        # "s15" |"tors"| "pg" | "cc"| "umvt" |  NaN  |  Α | B | Γ |  Δ | Ε
        # "s15" | "rot"|  NaN |  NaN|  NaN   |  NaN  |  ζ | η | θ |  ι | κ
        # "s15" |"trns"|  NaN |  NaN|  NaN   |  NaN  |  Ζ | Η | Θ |  Ι | Κ
        # "s20" |"tors"| "pg" | "uu"|  "ho"  |  "ho" |  λ | μ | ν |  ξ | π
        # "s1"  |"tors"|"umvt"|  NaN|  NaN   |  NaN  |  Λ | Μ | Ν |  Ξ | Π
        self.csv = os.path.join(
            self.resdir, "thermo{T}_{label}.csv".format(T=self.T,
                                                        label=self.label))
        self.total_thermo = get_data_frame(self.csv)
        self.data_frame = pd.DataFrame({'mode': []})

    def execute(self):
        self.calcThermo(write=True)
        return self.data_frame, self.csv

    def calcThermo(self, write=True, print_output=True):
        """
        Calculate component thermodynamic quantities.
        Unit conversions performed by each operation.
        Stored in self.data_frame data frame.
        """
        self.calcTransThermo()
        self.calcRotThermo()
        for sb_protocol in self.sb_protocols:
            self.calcSBThermo(protocol=sb_protocol)
        for t_protocol in self.t_protocols:
            if t_protocol == 'PG':
                ############ Pitzer-Gwinn Methods ############
                for t_subprotocol in self.t_subprotocols:
                    ######### PG Classical Partition #########
                    for sb_protocol in self.sb_protocols:
                        ######### Pitzer-Gwinn Factor #########
                        if sb_protocol == 'HO':  # PG factor = HO
                            ######### HO ω's #########
                            for sb_subprotocol in self.sb_subprotocols:
                                self.calcTThermo(protocol=t_protocol,
                                                 subprotocol=t_subprotocol,
                                                 sb_protocol=sb_protocol,
                                                 sb_subprotocol=sb_subprotocol)
                        else:  # PG factor = UMVT / MC
                            self.calcTThermo(protocol=t_protocol,
                                             subprotocol=t_subprotocol,
                                             sb_protocol=sb_protocol,
                                             sb_subprotocol=None)
            else:  # method is not PG (is UMVT)
                self.calcTThermo(protocol=t_protocol,
                                 subprotocol=None,
                                 sb_protocol=None,
                                 sb_subprotocol=None)
        self.total_thermo = pd.concat([self.data_frame],
                                      keys=[self.label],
                                      names=['species'])
        if write:
            self.total_thermo.to_csv(self.csv)
        if print_output:
            pass

    def calcTClassical(self, subprotocol):
        """
        Calculate the classical torsional thermo properties
        using statistical mechanics.
        Unit conversions in situ performed before returning.
        """
        if not subprotocol in ['C', 'U']:
            raise TypeError("Invalid subprotocol")
        ntors = self.samp_obj.n_rotors
        beta = 1 / (constants.kB * self.T) * constants.E_h  # beta in Hartree
        #betac = beta*self.rat
        print("Ratio of temperatures is", self.rat)
        # Unit conversion constants:
        J2cal = 1. / 4.184  # 1cal / 4.184J
        Hartree2kcal = constants.E_h*\
                constants.Na*J2cal/1000   # (J/H)*(1cal/4.184J)*1k
        #################################################
        # Calculate  torsional kinetic (T) contribution #
        #################################################
        D = get_mass_matrix(None,
                            self.T,
                            self.Thermo.mode_dict,
                            protocol="uncoupled")  # SI
        R = 1.985877534e-3  # kcal/mol.K
        beta_si = 1. / (constants.kB * self.T)
        prefactor = 1. / (2 * np.pi * beta_si * np.power(constants.hbar, 2.))
        QT = np.power(prefactor, ntors / 2) * np.power(np.linalg.det(D), 0.5)
        ET = 0.5 * ntors * R * self.T  # ET in kcal/mol
        ST = R * (np.log(QT) + ntors / 2.) * 1000  #S in cal/mol.K
        CvT = R * ntors / 2. * 1000  # Cv in cal/mol.K

        EtclassU, StclassU, CvtclassU, QtclassU, Qv = 0, 0, 0, 1, 1
        for mode in sorted(self.Thermo.mode_dict.keys()):
            if self.Thermo.mode_dict[mode]['mode'] != 'tors':
                continue
            # Calculate classical properties
            NMode = dict_to_NMode(mode, self.Thermo.mode_dict,
                                  self.Thermo.energy_dict, [], [],
                                  self.samp_obj)
            ec, sc, qc, qv, cvc =\
                    solvUMClass(NMode, self.T)
            EtclassU += ec
            StclassU += sc
            CvtclassU += cvc
            QtclassU *= qc
            Qv *= qv
        if "U" in subprotocol:
            return EtclassU, StclassU, CvtclassU, QtclassU
        elif 'C' in subprotocol:
            # Calculate coupled torsional PES contribution for all tors
            #QV = Qv*np.power(np.mean(self.trace.a), self.rat)
            #print("Kinetic pf, coupled:", QT)
            #print("Potential partition function, un/coupled:", Qv, QV)
            #print("Product:", QT*QV)
            ############# CHECK THIS ####################
            #EV = np.mean(self.trace.bE*self.rat)*R*self.T # E in kcal/mol
            #SV = R*(np.log(QV) + np.mean(self.trace.bE)*self.rat)*1000\
            #    # S in cal/mol.K
            #CvV = beta/self.T*\
            #        (np.var(self.trace.bE/betac))\
            #        *Hartree2kcal*1000 # Cv in cal/mol.K
            #QtclassC = QV*QT
            #EtclassC = EV+ET
            #StclassC = SV+ST
            #CvtclassC = CvV+CvT
            ############################################
            # CUMULATIVE MEAN ##########################
            ############################################
            Qcm = Qv * np.power(self.acm, self.rat)  #* QT
            print("partition fn, fperturb;", Qcm)
            print("prior partition:", Qv)
            #Qcm = self.qcm * QT
            #print(Qcm)
            #print(np.log(Qcm))
            Qcm.columns = Qcm.columns.str.replace("a", "E")
            Ecm = self.bEcm * self.rat * R * self.T + ET
            Scm = R * (np.log(Qcm).add(
                self.bEcm * self.rat)) * 1000 + ST  # cal/mol.K

            print("Entropy is:", Scm)
            print("kinetic entropy is", ST)
            #Scm = R*self.S*1000
            #Qcm = np.exp(-self.S - Ecm)
            #print(Scm)
            Cvcm = beta/self.T*\
                    self.Ecvar*Hartree2kcal*1000 + CvT # cal/mol.K
            return Ecm, Scm, Cvcm, Qcm
            return EtclassC, StclassC, CvtclassC, QtclassC

    def calcPGFactor(self, sb_protocol, sb_subprotocol):
        """
        Calculate the thermodynamics associated with PG Q/Cl ratio.
        F refers to the ratio of q/cl partition fns, NOT Helmholtz f.e.
        This carries a quantum term and therefore a ZPE.
        Unit conversions performed by operations prior to returning.
        """
        if not sb_protocol in ["HO", "UMVT"]:
            raise TypeError(
                "Invalid protocol for stretches/bends: valid options\
                            are 'HO' or 'UMVT'.")
        Qc, F, E0, DE, DS, DCv = 1, 1, 0, 0, 0, 0
        if sb_protocol == "HO":
            if not sb_subprotocol in ["HO", "UMVT", "MC"]:
                raise TypeError(
                    "Invalid subprotocol for stretches/bends: valid options\
                            are 'HO', 'UMVT', or 'MC'.")
            kwargs = {
                'samp_obj': self.samp_obj,
                'T': self.T,
                'Thermo_obj': self.Thermo
            }
            ws = get_tors_freqs(protocol=sb_subprotocol, **kwargs)  # s^-1
            for i, w in enumerate(ws):
                # Calculate quantum HO properties
                e0, e, s, q, cv =\
                        solvHO(w, self.T)
                ec, sc, qc, cvc =\
                        solvCHO(w, self.T)
                F *= q / qc
                Qc *= qc
                E0 += e0
                DE += e - ec
                DS += s - sc
                DCv += cv - cvc
        elif sb_protocol == "UMVT":
            for mode in sorted(self.Thermo.mode_dict.keys()):
                if self.Thermo.mode_dict[mode]['mode'] != 'tors':
                    continue
                # Calculate quantum properties
                v, e0, e, s, f, q, cv =\
                        self.Thermo.SolvEig(mode, self.T)
                # Calculate classical properties
                NMode = dict_to_NMode(mode, self.Thermo.mode_dict,
                                      self.Thermo.energy_dict, [], [],
                                      self.samp_obj)
                ec, sc, qc, qv, cvc =\
                        solvUMClass(NMode, self.T)
                F *= q / qc
                Qc *= qc
                E0 += e0
                DE += e - ec
                DS += s - sc
                DCv += cv - cvc
        v = None
        return v, Qc, F, E0, DE, DS, DCv

    def calcTThermo(self, protocol="PG", subprotocol="CC",\
            sb_protocol="HO", sb_subprotocol="HO"):
        """
        Calculate thermodynamics of internal rotations (torsions).
        Two possibilities:
            1. Pitzer-Gwinn
                - Classical partition function
                    1. Coupled
                    2. Uncoupled
                    3. Hybrid
                - PG factor
                    1. Q_HO/Q_CHO(ω)
                        1. ωΗΟ
                        2. ωUMVT
                        3. ωMC
                    2. Q_UMVT/Q_UMC
            2. UM-VT
        Unit conversions done by operations prior to being returned.
        """
        # Calc of torsions follows according to supplied protocol:
        if "PG" in protocol:
            # Calculate class torsional partition function
            Etclass, Stclass, Cvtclass, Qtclass =\
                    self.calcTClassical(subprotocol)
            # Calculate SB Ratio (F)
            v, qc, F, E0, DE, DS, DCv =\
                    self.calcPGFactor(sb_protocol, sb_subprotocol)
            ### Data frames if coupled
            E0 = E0
            E = DE + Etclass
            S = DS + Stclass
            Cv = DCv + Cvtclass
            Q = F * Qtclass
            Qc = Qtclass
            ###
            # SAVE THEM!!!
            if subprotocol == 'C':
                if sb_protocol == 'UMVT':
                    print("PG Entropy is", DS)
                    R = 1.985877534e-3  # kcal/mol.K
                    Hcm = E - E0 + self.trans_dict['e'] + self.rot_dict[
                        'e'] + R * self.T
                    Hcm += self.ho_dict['e'] - self.ho_dict['e0']
                    Scm = S + self.trans_dict['s'] + self.rot_dict['s'] +\
                            self.ho_dict['s']
                    Cvcm = Cv + self.trans_dict['cv'] + self.rot_dict['cv'] +\
                            self.ho_dict['cv']
                    Qpgcm = Q * self.ho_dict['q']

                    name = os.path.join(self.resdir, '{}_{}K.csv')
                    Hcm.to_csv(name.format('H', self.T))
                    Scm.to_csv(name.format('S', self.T))
                    Cvcm.to_csv(name.format('Cv', self.T))
                    Qpgcm.to_csv(name.format('Qpg', self.T))
                    ####
                #For storing in data frame
                E = np.mean(E.iloc[-1])
                S = np.mean(S.iloc[-1])
                Cv = np.mean(Cv.iloc[-1])
                Q = np.mean(Q.iloc[-1])
                Qc = np.mean(Qtclass.iloc[-1])
                ####
        elif protocol == "UMVT":
            E0, E, S, Cv, Q, F, Qc = 0, 0, 0, 0, 1, None, None
            for mode in sorted(self.Thermo.mode_dict.keys()):
                if self.Thermo.mode_dict[mode]['mode'] != 'tors':
                    continue
                v, e0, e, s, f, q, cv =\
                        self.Thermo.SolvEig(mode, self.T)
                E0 += e0
                E += e
                S += s
                Cv += cv
                Q *= q
        elif protocol == 'HO':
            E0, E, S, Cv, Q, F, Qc = 0, 0, 0, 0, 1, None, None
            kwargs = {
                'samp_obj': self.samp_obj,
                'T': self.T,
                'Thermo_obj': self.Thermo
            }
            ws = get_tors_freqs(protocol=protocol, **kwargs)  # s^-1
            for i, w in enumerate(ws):
                # Calculate quantum HO properties
                e0, e, s, q, cv =\
                        solvHO(w, self.T)
                E0 += e0
                E += e
                S += s
                Cv += cv
                Q *= q
        t_dict = {
            'mode': 'tors',
            'T': self.T,
            'protocol': protocol,
            'subprotocol': subprotocol,
            'sb_protocol': sb_protocol,
            'sb_subprotocol': sb_subprotocol,
            'e0': E0,
            'e': E,
            's': S,
            'cv': Cv,
            'q': Q,
            'qc': Qc,
            'f': F
        }
        self.data_frame = self.data_frame.append(t_dict, ignore_index=True)

    def calcSBThermo(self, protocol):
        """
        Calculate thermodynamics of stretches and bends, distinct from tors.
        Relies heavily on outside methods (Yi-Pei Li)
        Two methods, which match PG protocol:
            1. HO
                - use harmonic approximation
            2. UMVT
                - from anharmonic sampling (done prior to MC)
        Unit conversions done in situ before returning
        """
        ZPE, E_int, S_int, Q_int, Cv_int = 0, 0, 0, 1, 0
        if protocol == "HO":
            # Calculate HO thermo for stretches/bends
            freqs = get_sb_freqs(self.Thermo.mode_dict)
            for w in freqs:
                e0, e, s, q, cv =\
                        solvHO(w, self.T)
                ZPE += e0
                E_int += e
                S_int += s
                Q_int *= q
                Cv_int += cv
        elif protocol == "UMVT":
            # Calculate UMVT thermo for stretches/bends
            for mode in sorted(self.Thermo.mode_dict.keys()):
                if self.Thermo.mode_dict[mode][
                        'mode'] == 'tors':  # skip torsions
                    continue
                v, e0, E, S, F, Q, Cv = self.Thermo.SolvEig(mode, self.T)
                ZPE += e0
                E_int += E
                S_int += S
                Q_int *= Q
                Cv_int += Cv
        sb_dict = {
            'mode': 'sb',
            'T': self.T,
            'sb_protocol': protocol,
            'e0': ZPE,
            'e': E_int,
            's': S_int,
            'cv': Cv_int,
            'q': Q_int
        }
        if protocol == 'UMVT':
            self.umn_dict = sb_dict
        elif protocol == 'HO':
            self.ho_dict = sb_dict
        self.data_frame = self.data_frame.append(sb_dict, ignore_index=True)

    def calcTransThermo(self):
        # Calculate global translation (ideal gas, Sackur-Tetrode)
        # Unit conversion included
        E_trans = 1.5 * constants.R * self.T / 4184
        S_trans = self.conformer.modes[0].get_entropy(
            self.T) / 4.184 - constants.R * math.log(self.P / 101325) / 4.184
        Cv_trans = 1.5 * constants.R / 4184 * 1000
        Q_trans = self.conformer.modes[0].get_partition_function(self.T)
        self.trans_dict = {
            'mode': 'trans',
            'T': self.T,
            'e': E_trans,
            's': S_trans,
            'cv': Cv_trans,
            'q': Q_trans
        }
        self.data_frame = self.data_frame.append(self.trans_dict,
                                                 ignore_index=True)

    def calcRotThermo(self):
        # Calculate global rotation (rigid rotor)
        # Unit conversion included
        E_rot = self.conformer.modes[1].get_enthalpy(self.T) / 4184
        S_rot = self.conformer.modes[1].get_entropy(self.T) / 4.184
        Cv_rot = self.conformer.modes[1].get_heat_capacity(self.T) / 4.184
        Q_rot = self.conformer.modes[1].get_partition_function(self.T)
        self.rot_dict = {
            'mode': 'rot',
            'T': self.T,
            'e': E_rot,
            's': S_rot,
            'cv': Cv_rot,
            'q': Q_rot
        }
        self.data_frame = self.data_frame.append(self.rot_dict,
                                                 ignore_index=True)

    def calcVibThermo(self,
                      sb_protocol="HO",
                      t_protocol="PG",
                      t_subprotocol="CC",
                      sb_subprotocol="MC"):
        """
        Calculate component thermo quantities for internal modes.
        Internal modes separted into:
            Torsions
                protocols: 'UMVT', 'PG'(coupled, u/c, uncoupled)
            Stretches / Bends
                protocols: 'HO'(ω: ho, umvt, mc), 'UMVT'
        Unit conversions performed by each operation before returning.
        """
        E0_sb, E_sb, S_sb, Cv_sb, Q_sb =\
                self.calcSBThermo(protocol=sb_protocol) # for non-torsions
        E0_t, E_t, S_t, Cv_t, Q_t =\
                self.calcTThermo(protocol=t_protocol, subprotocol=t_subprotocol,
                        sb_protocol=sb_protocol, sb_subprotocol=sb_subprotocol) # for torsions
        return (E0_sb + E0_t), (E_sb + E_t), (S_sb + S_t), (Cv_sb +
                                                            Cv_t), (Q_sb * Q_t)
コード例 #6
0
def transitionState(label, *args, **kwargs):
    """Load a transition state from an input file"""
    global transition_state_dict, job_list, directory
    if label in transition_state_dict:
        raise ValueError(
            'Multiple occurrences of transition state with label {0!r}.'.
            format(label))
    logging.info('Loading transition state {0}...'.format(label))
    ts = TransitionState(label=label)
    transition_state_dict[label] = ts

    if len(args) == 1:
        # The argument is a path to a conformer input file
        path = os.path.join(directory, args[0])
        ts.path = path
        job = SamplingJob(label=label,
                          input_file=path,
                          output_directory=output_directory,
                          is_ts=True)
        Log = QChemLog(path)
        ts.conformer, unscaled_frequencies = Log.load_conformer()
        ts.frequency = (Log.load_negative_frequency(), "cm^-1")
        job_list.append(job)

    elif len(args) == 0:
        # The species parameters are given explicitly
        E0 = None
        modes = []
        spin_multiplicity = 1
        optical_isomers = 1
        frequency = None
        for key, value in kwargs.items():
            if key == 'E0':
                E0 = value
            elif key == 'modes':
                modes = value
            elif key == 'spinMultiplicity':
                spin_multiplicity = value
            elif key == 'opticalIsomers':
                optical_isomers = value
            elif key == 'frequency':
                frequency = value
            else:
                raise TypeError(
                    'transition_state() got an unexpected keyword argument {0!r}.'
                    .format(key))

        ts.conformer = Conformer(E0=E0,
                                 modes=modes,
                                 spin_multiplicity=spin_multiplicity,
                                 optical_isomers=optical_isomers)
        ts.frequency = frequency
    else:
        if len(args) == 0 and len(kwargs) == 0:
            raise InputError(
                'The transition_state needs to reference a quantum job file or contain kinetic information.'
            )
        raise InputError(
            'The transition_state can only link a quantum job or directly input information, not both.'
        )

    if len(kwargs) > 0:
        # The species parameters are given explicitly
        protocol = 'UMVT'
        E0 = None
        rotors = None
        for key, value in kwargs.items():
            if key == 'protocol':
                protocol = value.upper()
            elif key == 'E0':
                E0 = value
            elif key == 'rotors':
                rotors = value
            else:
                raise TypeError(
                    'species() got an unexpected keyword argument {0!r}.'.
                    format(key))

        if protocol == 'UMVT' and rotors is None:
            raise InputError(
                'If the transition state is sampled by using UMVT algorithm, the rotors are needed to be specified.'
            )

        job.protocol = protocol
        ts.conformer.E0 = E0
        job.rotors = rotors

    return ts
コード例 #7
0
ファイル: statmech.py プロジェクト: shihchengli/APE
class Statmech(object):
    """
    A class to solve shrodinger equation, evaluate partition function and related properties of 1-D PES by using statistical thermodynamics
    """
    def __init__(self,
                 label,
                 input_file,
                 output_directory,
                 Tlist=[298.15],
                 P=100000,
                 frequency_scale_factor=1,
                 ncpus=None):
        self.label = label
        self.input_file = input_file
        self.output_directory = output_directory
        self.Tlist = Tlist
        self.P = P
        self.frequency_scale_factor = frequency_scale_factor
        self.ncpus = ncpus
        self.result_info = list()

    def load_save(self):
        self.sampling = SamplingJob(self.label,
                                    self.input_file,
                                    ncpus=self.ncpus)
        self.sampling.parse()
        self.is_QM_MM_INTERFACE = self.sampling.is_QM_MM_INTERFACE
        self.conformer = self.sampling.conformer
        self.csv_path = os.path.join(
            self.output_directory, '{}_samping_result.csv'.format(self.label))
        self.mode_dict, self.energy_dict, self.min_elect = from_sampling_result(
            self.csv_path)
        self.zpe_of_Hohf = self.sampling.zpe
        e0 = self.min_elect * constants.E_h * constants.Na + self.sampling.zpe
        self.conformer.E0 = (e0, "J/mol")
        for mode in self.conformer.modes:
            if isinstance(mode, HarmonicOscillator):
                frequencies = mode.frequencies.value_si
                mode.frequencies = (frequencies * self.frequency_scale_factor,
                                    "cm^-1")
        self.spin_multiplicity = self.conformer.spin_multiplicity
        self.optical_isomers = self.conformer.optical_isomers
        self.symbols = self.sampling.symbols

        # Solve SE of 1-D PES and calculate E S G Cp
        self.polynomial_dict = cubic_spline_interpolations(
            self.energy_dict, self.mode_dict)

        # Extract whether this system is QM/MM system or not
        self.is_QM_MM_INTERFACE = self.sampling.is_QM_MM_INTERFACE

    def calcThermoOfEachMode(self, eig, N, mode, T):
        beta = 1 / (constants.kB * T) * constants.E_h
        Q = 0
        Q_vib = 0
        E = 0
        dQ = 0
        ddQ = 0
        for i in range(N):
            Ei = eig[i]
            Q += exp(-beta * Ei)
            dQ += Ei * exp(-beta * Ei) * beta / T
            ddQ += -2 * Ei * exp(-beta * Ei) * beta / pow(T, 2) + pow(
                Ei, 2) * exp(-beta * Ei) * pow(beta, 2) / pow(T, 2)
            E += Ei * exp(-beta * Ei)
            if i == 0:
                zpve = Ei
            # Measuring energy relative to the zero point vibration frequency
            dE = Ei - zpve
            Q_vib += exp(-beta * dE)
        E /= Q
        is_tors = True if self.mode_dict[mode]['mode'] == 'tors' else False
        if is_tors:
            omega = self.mode_dict[mode]['symmetry_number']
            Q /= omega
            Q_vib /= omega
            dQ /= omega
            ddQ /= omega

        E0 = eig[0]
        v = (eig[1] - eig[0]) * constants.E_h / constants.h / (constants.c *
                                                               100)
        #print(Q)

        F = -math.log(Q) / beta
        S = (E - F) / T
        Cv = (2 / Q * dQ - T * pow(dQ / Q, 2) + T / Q * ddQ) / beta

        return v, E0, E, S, F, Q, Q_vib, Cv

    def SolvEig(self, mode, T):
        Nbasis = 50
        Nbasis_prev = 0
        H_prev = None
        Qold = np.log(sys.float_info[0])
        vold = np.log(sys.float_info[0])
        converge = False
        while not converge:
            Nbasis += 1
            H = SetAnharmonicH(self.polynomial_dict,
                               self.mode_dict,
                               self.energy_dict,
                               mode,
                               Nbasis,
                               N_prev=Nbasis_prev,
                               H_prev=H_prev)
            Nbasis_prev = Nbasis
            H_prev = deepcopy(H)
            eig, v = np.linalg.eigh(H)
            v, E0, E, S, F, Q, Q_vib, Cv = self.calcThermoOfEachMode(
                eig, Nbasis, mode, T)

            if Qold == np.log(sys.float_info[0]):
                self.result_info.append("# \n# \t %d \t\t-\t\t-" %
                                        Nbasis)  #first run
                logging.debug("# \t {} \t\t-\t\t-".format(Nbasis))
            else:
                self.result_info.append("# \n# \t %d \t\t %.10f \t\t %.10f" %
                                        (Nbasis, abs(Q - Qold), abs(v - vold)))
                logging.debug("# \t {:d} \t\t {:.10f} \t\t {:.10f}".format(
                    Nbasis, abs(Q - Qold), abs(v - vold)))

            if ((abs(Q - Qold) < 1e-4) and (abs(v - vold) < 1e-2)):
                self.result_info.append("# Convergence criterion met")
                self.result_info.append(
                    "# ------------------------------------")
                converge = True
                self.result_info.append("# Frequency (cm-1): %.10f" % v)
                self.result_info.append(
                    "# Zero point vibrational energy (hartree): %.10f" % E0)
                self.result_info.append("# Energy (hartree): %.10f" % E)
                self.result_info.append("# Entropy (hartree/K): %.10f" % S)
                self.result_info.append("# Free energy (hartree): %.10f" % F)
                self.result_info.append("# Partition function: %.10f" % Q)
                hartree2kcalmol = constants.E_h * constants.Na / 4184
                E0 *= hartree2kcalmol
                E *= hartree2kcalmol
                S *= hartree2kcalmol * 1000
                F *= hartree2kcalmol
                Cv *= hartree2kcalmol * 1000
                '''
                print("Frequency (cm-1): ",v)
                print("Zero point vibrational energy (kcal/mol): ",E0)
                print("Energy (kcal/mol): ",E )
                print("Entropy (cal/mol/K): ",S)
                print("Free energy (kcal/mol): ",F)
                print("Partition function: ",Q)
                '''

            Qold = Q
            vold = v
        return v, E0, E, S, F, Q, Q_vib, Cv
コード例 #8
0
            fixed_molecule_string=samp_obj.fixed_molecule_string,
            opt=samp_obj.opt,
            number_of_fixed_atoms=samp_obj.number_of_fixed_atoms)
    args = (path, file_name, samp_obj.ncpus)

    xyz, internal = get_geometry_at(x, samp_obj)
    E,grad = get_energy_gradient(xyz,*args,**kwargs)
    B = internal.B_prim
    Bt_inv = np.linalg.pinv(B.dot(B.T)).dot(B)

    grad = Bt_inv.dot(grad)[torsion_inds] 
    grad *= signs

    subprocess.Popen(['rm {input_path}/{file_name}.q.out'.format(input_path=path,
        file_name=file_name)], shell=True)

    return E,grad

if __name__ == '__main__':
    directory = '/Users/lancebettinson/Documents/entropy/um-vt/PROPIONIC_ACID'
    freq_file = os.path.join(directory,'propanoic.out')
    label = 'propanoic'
    from ape.sampling import SamplingJob
    samp_obj = SamplingJob(label,freq_file,output_directory=directory,
            protocol='TNUTS')
    samp_obj.parse()
    samp_obj.sampling()
    xyz = get_geometry_at([26*2*np.pi/360,11*2*np.pi/360,45*2*np.pi/360], samp_obj)
    print(xyz)
    
コード例 #9
0
        xyz = self.transform_geometry_to(phi)
        coordinates = self.internal.c3d
        self.conformer.coordinates = (coordinates, "angstroms")
        I = []
        for i in range(self.n_rotors):
            I.append(
                    self.conformer.get_internal_reduced_moment_of_inertia(
                        self.pivots[i], self.tops[i])*constants.Na * 1e23) # amu*Å^2
        return np.array(I)

if __name__ == '__main__':
    directory = '/Users/lancebettinson/Documents/entropy/um-vt/MeOOH'
    freq_file = os.path.join(directory,'MeOOH.out')
    label = 'MeOOH'
    from ape.sampling import SamplingJob
    samp_obj = SamplingJob(label,freq_file,output_directory=directory,
            protocol='TNUTS')
    samp_obj.parse()
    samp_obj.csv_path = os.path.join(directory,
            'MeOOH_sampling_result.csv')
    xyz_dict, energy_dict, mode_dict = samp_obj.sampling()
    tmodes = dicts_to_NModes(mode_dict, energy_dict, xyz_dict,
                samp_obj=samp_obj, just_tors=True)
    syms = np.array([mode.get_symmetry_number() for mode in tmodes])
    geom = Geometry(samp_obj, samp_obj.torsion_internal, syms)
    
    x = np.random.random((10,2))
    for xi in x:
        print("coordinate transformation at",xi)
        I = geom.calc_I(xi)
        print(I)