def compute_hessian(self, molecule): """ #magic (if magic was easy) """ optstash = p4util.OptionsState(['PRINT']) core.set_global_option('PRINT', 0) core.print_out("\n\n Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n") core.print_out(" Computing the Hessian through finite difference of gradients.\n\n") # Setup the molecule molclone = molecule.clone() molclone.reinterpret_coordentry(False) molclone.fix_orientation(True) molclone.fix_com(True) # Record undisplaced symmetry for projection of diplaced point groups core.set_parent_symmetry(molecule.schoenflies_symbol()) gradients = [] for geom in core.fd_geoms_freq_1(molecule, -1): molclone.set_geometry(geom) molclone.update_geometry() gradients.append(self.compute_gradient(molclone)) H = core.fd_freq_1(molecule, gradients, -1) # H.print_out() optstash.restore() return H
def cubeprop(wfn, **kwargs): """Evaluate properties on a grid and generate cube files. .. versionadded:: 0.5 *wfn* parameter passed explicitly :returns: None :type wfn: :py:class:`~psi4.core.Wavefunction` :param wfn: set of molecule, basis, orbitals from which to generate cube files :examples: >>> # [1] Cube files for all orbitals >>> E, wfn = energy('b3lyp', return_wfn=True) >>> cubeprop(wfn) >>> # [2] Cube files for density (alpha, beta, total, spin) and four orbitals >>> # (two alpha, two beta) >>> set cubeprop_tasks ['orbitals', 'density'] >>> set cubeprop_orbitals [5, 6, -5, -6] >>> E, wfn = energy('scf', return_wfn=True) >>> cubeprop(wfn) """ # By default compute the orbitals if not core.has_global_option_changed('CUBEPROP_TASKS'): core.set_global_option('CUBEPROP_TASKS', ['ORBITALS']) if ((core.get_global_option('INTEGRAL_PACKAGE') == 'ERD') and ('ESP' in core.get_global_option('CUBEPROP_TASKS'))): raise ValidationError('INTEGRAL_PACKAGE ERD does not play nicely with electrostatic potential, so stopping.') cp = core.CubeProperties(wfn) cp.compute_properties()
def compute_hessian(self, molecule): """ #magic (if magic was easy) """ optstash = p4util.OptionsState(['PRINT']) core.set_global_option('PRINT', 0) core.print_out( "\n\n Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n" ) core.print_out( " Computing the Hessian through finite difference of gradients.\n\n" ) # Setup the molecule molclone = molecule.clone() molclone.reinterpret_coordentry(False) molclone.fix_orientation(True) molclone.fix_com(True) # Record undisplaced symmetry for projection of diplaced point groups core.set_parent_symmetry(molecule.schoenflies_symbol()) gradients = [] for geom in core.fd_geoms_freq_1(molecule, -1): molclone.set_geometry(geom) molclone.update_geometry() gradients.append(self.compute_gradient(molclone)) H = core.fd_freq_1(molecule, gradients, -1) # H.print_out() optstash.restore() return H
def set_options(options_dict): """ Sets Psi4 global options from an input dictionary. """ for k, v, in options_dict.items(): core.set_global_option(k.upper(), v)
def scf_set_reference_local(name, is_dft=False): """ Figures out the correct SCF reference to set locally """ optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE']) # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): core.set_global_option('SCF_TYPE', 'DF') # Alter reference name if needed user_ref = core.get_option('SCF', 'REFERENCE') sup = build_superfunctional_from_dictionary(functionals[name], 1, 1, True)[0] if sup.needs_xc() or is_dft: if (user_ref == 'RHF'): core.set_local_option('SCF', 'REFERENCE', 'RKS') elif (user_ref == 'UHF'): core.set_local_option('SCF', 'REFERENCE', 'UKS') elif (user_ref == 'ROHF'): raise ValidationError('ROHF reference for DFT is not available.') elif (user_ref == 'CUHF'): raise ValidationError('CUHF reference for DFT is not available.') # else we are doing HF and nothing needs to be overloaded return optstash
def scf_set_reference_local(name, is_dft=False): """ Figures out the correct SCF reference to set locally """ optstash = p4util.OptionsState( ['SCF_TYPE'], ['SCF', 'REFERENCE']) # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): core.set_global_option('SCF_TYPE', 'DF') # Alter reference name if needed user_ref = core.get_option('SCF', 'REFERENCE') sup = build_superfunctional_from_dictionary(functionals[name], 1, 1, True)[0] if sup.needs_xc() or is_dft: if (user_ref == 'RHF'): core.set_local_option('SCF', 'REFERENCE', 'RKS') elif (user_ref == 'UHF'): core.set_local_option('SCF', 'REFERENCE', 'UKS') elif (user_ref == 'ROHF'): raise ValidationError('ROHF reference for DFT is not available.') elif (user_ref == 'CUHF'): raise ValidationError('CUHF reference for DFT is not available.') # else we are doing HF and nothing needs to be overloaded return optstash
def restore(self): core.set_global_option(self.option, self.value_global) if not self.haschanged_global: core.revoke_global_option_changed(self.option) if self.module: core.set_local_option(self.module, self.option, self.value_local) if not self.haschanged_local: core.revoke_local_option_changed(self.module, self.option)
def _core_jk_build(orbital_basis: core.BasisSet, aux: core.BasisSet = None, jk_type: str = None, do_wK: bool = None, memory: int = None) -> core.JK: """ Constructs a Psi4 JK object from an input basis. Parameters ---------- orbital_basis Orbital basis to use in the JK object. aux Optional auxiliary basis set for density-fitted tensors. Defaults to the DF_BASIS_SCF if set, otherwise the correspond JKFIT basis to the passed in `orbital_basis`. jk_type Type of JK object to build (DF, Direct, PK, etc). Defaults to the current global SCF_TYPE option. Returns ------- JK Uninitialized JK object. Example ------- jk = psi4.core.JK.build(bas) jk.set_memory(int(5e8)) # 4GB of memory jk.initialize() ... jk.C_left_add(matirx) jk.compute() jk.C_clear() ... """ optstash = optproc.OptionsState(["SCF_TYPE"]) if jk_type is not None: core.set_global_option("SCF_TYPE", jk_type) if aux is None: if core.get_global_option("SCF_TYPE") == "DF": aux = core.BasisSet.build(orbital_basis.molecule(), "DF_BASIS_SCF", core.get_option("SCF", "DF_BASIS_SCF"), "JKFIT", orbital_basis.name(), orbital_basis.has_puream()) else: aux = core.BasisSet.zero_ao_basis_set() if (do_wK is None) or (memory is None): jk = core.JK.build_JK(orbital_basis, aux) else: jk = core.JK.build_JK(orbital_basis, aux, bool(do_wK), int(memory)) optstash.restore() return jk
def restore(self): """Restore value and has_changed status to saved condition.""" core.set_global_option(self.option, self.value_global) if not self.haschanged_global: core.revoke_global_option_changed(self.option) if self.module: core.set_local_option(self.module, self.option, self.value_local) if not self.haschanged_local: core.revoke_local_option_changed(self.module, self.option)
def _core_jk_build(orbital_basis, aux=None, jk_type=None, do_wK=None, memory=None): """ Constructs a Psi4 JK object from an input basis. Parameters ---------- orbital_basis : :py:class:`~psi4.core.BasisSet` Orbital basis to use in the JK object. aux : :py:class:`~psi4.core.BasisSet`, optional Optional auxiliary basis set for density-fitted tensors. Defaults to the DF_BASIS_SCF if set, otherwise the correspond JKFIT basis to the passed in `orbital_basis`. jk_type : str, optional Type of JK object to build (DF, Direct, PK, etc). Defaults to the current global SCF_TYPE option. Returns ------- :py:class:`~psi4.core.JK` Uninitialized JK object. Example ------- jk = psi4.core.JK.build(bas) jk.set_memory(int(5e8)) # 4GB of memory jk.initialize() ... jk.C_left_add(matirx) jk.compute() jk.C_clear() ... """ optstash = optproc.OptionsState(["SCF_TYPE"]) if jk_type is not None: core.set_global_option("SCF_TYPE", jk_type) if aux is None: if core.get_global_option("SCF_TYPE") == "DF": aux = core.BasisSet.build(orbital_basis.molecule(), "DF_BASIS_SCF", core.get_option("SCF", "DF_BASIS_SCF"), "JKFIT", orbital_basis.name(), orbital_basis.has_puream()) else: aux = core.BasisSet.zero_ao_basis_set() if (do_wK is None) or (memory is None): jk = core.JK.build_JK(orbital_basis, aux) else: jk = core.JK.build_JK(orbital_basis, aux, bool(do_wK), int(memory)) optstash.restore() return jk
def check_disk_df(name, optstash): optstash.add_option(['SCF_TYPE']) # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE') or core.get_global_option('SCF_TYPE') == "DF": core.set_global_option('SCF_TYPE', 'DISK_DF') core.print_out(f""" For method '{name}', SCF Algorithm Type (re)set to DISK_DF.\n""") else: if core.get_global_option('SCF_TYPE') == "MEM_DF": raise ValidationError(f" Method '{name}' requires SCF_TYPE = DISK_DF, please use SCF_TYPE = DF to automatically choose the correct DFJK implementation.")
def compute_hessian( self, molecule: 'psi4.core.Molecule', wfn: 'psi4.core.Wavefunction' = None) -> 'psi4.core.Matrix': """Compute dispersion Hessian based on engine, dispersion level, and parameters in `self`. Uses finite difference, as no dispersion engine has analytic second derivatives. Parameters ---------- molecule : psi4.core.Molecule System for which to compute empirical dispersion correction. wfn : Location to set QCVariables Returns ------- psi4.core.Matrix (3*nat, 3*nat) dispersion Hessian [Eh/a0/a0]. """ optstash = p4util.OptionsState(['PRINT'], ['PARENT_SYMMETRY']) core.set_global_option('PRINT', 0) core.print_out( "\n\n Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n" ) core.print_out( " Computing the Hessian through finite difference of gradients.\n\n" ) # Setup the molecule molclone = molecule.clone() molclone.reinterpret_coordentry(False) molclone.fix_orientation(True) molclone.fix_com(True) # Record undisplaced symmetry for projection of diplaced point groups core.set_global_option("PARENT_SYMMETRY", molecule.schoenflies_symbol()) findif_meta_dict = driver_findif.hessian_from_gradients_geometries( molclone, -1) for displacement in findif_meta_dict["displacements"].values(): geom_array = np.reshape(displacement["geometry"], (-1, 3)) molclone.set_geometry(core.Matrix.from_array(geom_array)) molclone.update_geometry() displacement["gradient"] = self.compute_gradient( molclone).np.ravel().tolist() H = driver_findif.assemble_hessian_from_gradients(findif_meta_dict, -1) if wfn is not None: wfn.set_variable('DISPERSION CORRECTION HESSIAN', H) optstash.restore() return core.Matrix.from_array(H)
def set_options(options_dict, verbose=1): """Sets Psi4 options from an input dictionary. Parameters ---------- options_dict : dict Dictionary where keys are "option_name" for global options or "module_name__option_name" (double underscore separation) for option local to "module_name". Values are the option value. All are case insensitive. verbose : int, optional Control print volume. Returns ------- None """ optionre = re.compile(r'\A(?P<module>\w+__)?(?P<option>\w+)\Z', re.IGNORECASE) rejected = {} for k, v, in options_dict.items(): mobj = optionre.match(k.strip()) module = mobj.group('module').upper()[:-2] if mobj.group( 'module') else None option = mobj.group('option').upper() if module: if ((module, option, v) not in [ ('SCF', 'GUESS', 'READ') ]) and ((module, option) not in [('PCM', 'INPUT')]): # TODO guess/read exception is for distributed driver. should be handled differently. try: core.set_local_option(module, option, v) except RuntimeError as err: rejected[k] = (v, err) if verbose > 1: print('Setting: core.set_local_option', module, option, v) if (module, option) == ("PCM", "INPUT"): pcm_helper(v) else: try: core.set_global_option(option, v) except RuntimeError as err: rejected[k] = (v, err) if verbose > 1: print('Setting: core.set_global_option', option, v) if rejected: raise ValidationError(f'Error setting options: {rejected}')
def __enter__(self): self.optstash = p4util.optproc.OptionsState(*self.psikwargs.keys()) for k, v in self.psikwargs.items(): # Integer options need to be passed as an integer type, # or else it fails to set and doesn't throw an error. if re.match('^\d+$', v) is not None: v = int(v) if len(k) == 1: core.set_global_option(k[0], v) else: core.set_local_option(k[0], k[1], v)
def psi4_set_options(my_options,mod_name,wfn): for i in my_options.get_keys(): opt="" if mod_name in pulsar_2_psi4 and i in pulsar_2_psi4[mod_name]: opt=pulsar_2_psi4[mod_name][i] elif i in pulsar_2_psi4["GLOBAL"]: opt=pulsar_2_psi4["GLOBAL"][i] else: continue da_opt=my_options.get(i) if i=="BASIS_SET": bs_name=wfn.system.as_universe()[0].basis_sets[da_opt].description psi4.set_global_option(opt,bs_name) else:psi4.set_global_option(opt,da_opt)
def check_disk_df(name, optstash): optstash.add_option(['SCF_TYPE']) # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): core.set_global_option('SCF_TYPE', 'DISK_DF') core.print_out(""" Method '%s' requires SCF_TYPE = DISK_DF, setting.\n""" % name) elif core.get_global_option('SCF_TYPE') == "DF": core.set_global_option('SCF_TYPE', 'DISK_DF') core.print_out(""" Method '%s' requires SCF_TYPE = DISK_DF, setting.\n""" % name) else: if core.get_global_option('SCF_TYPE') != "DISK_DF": raise ValidationError(" %s requires SCF_TYPE = DISK_DF, please use SCF_TYPE = DF to automatically choose the correct DFJK implementation." % name)
def scf_compute_energy(self): """Base class Wavefunction requires this function. Here it is simply a wrapper around initialize(), iterations(), finalize_energy(). It returns the SCF energy computed by finalize_energy(). """ if core.get_option('SCF', 'DF_SCF_GUESS') and (core.get_global_option('SCF_TYPE') == 'DIRECT'): # speed up DIRECT algorithm (recomputes full (non-DF) integrals # each iter) by first converging via fast DF iterations, then # fully converging in fewer slow DIRECT iterations. aka Andy trick 2.0 core.print_out(" Starting with a DF guess...\n\n") with p4util.OptionsStateCM(['SCF_TYPE']): core.set_global_option('SCF_TYPE', 'DF') self.initialize() try: self.iterations() except SCFConvergenceError: self.finalize() raise SCFConvergenceError("""SCF DF preiterations""", self.iteration_, self, 0, 0) core.print_out("\n DF guess converged.\n\n") # reset the DIIS & JK objects in prep for DIRECT if self.initialized_diis_manager_: self.diis_manager_.reset_subspace() self.initialize_jk(self.memory_jk_) else: self.initialize() try: self.iterations() except SCFConvergenceError as e: if core.get_option("SCF", "FAIL_ON_MAXITER"): core.print_out(" Failed to converge.\n") # energy = 0.0 # A P::e fn to either throw or protest upon nonconvergence # die_if_not_converged() raise e else: core.print_out( " Energy and/or wave function did not converge, but proceeding anyway.\n\n" ) else: core.print_out(" Energy and wave function converged.\n\n") scf_energy = self.finalize_energy() return scf_energy
def _core_set_global_option_python(key, EXTERN): """ This is a fairly hacky way to get around EXTERN issues. Effectively we are routing this option Python side through attributes until the general Options overhaul. """ if (key != "EXTERN"): raise ValidationError("Options: set_global_option_python does not recognize keyword %s" % key) if EXTERN is None: core.EXTERN = None core.set_global_option("EXTERN", False) elif isinstance(EXTERN, core.ExternalPotential): # Well this is probably the worst hack I have done, thats saying something core.EXTERN = EXTERN core.set_global_option("EXTERN", True) else: raise ValidationError("Options: set_global_option_python can either be a NULL or External Potential object")
def set_cholesky_from(mtd_type): type_val = core.get_global_option(mtd_type) if type_val == 'CD': core.set_local_option('GPU_DFCC', 'DF_BASIS_CC', 'CHOLESKY') # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): optstash.add_option(['SCF_TYPE']) core.set_global_option('SCF_TYPE', 'CD') core.print_out(""" SCF Algorithm Type (re)set to CD.\n""") elif type_val in ['DF', 'DISK_DF']: if core.get_option('GPU_DFCC', 'DF_BASIS_CC') == 'CHOLESKY': core.set_local_option('GPU_DFCC', 'DF_BASIS_CC', '') proc_util.check_disk_df(name.upper(), optstash) else: raise ValidationError("""Invalid type '%s' for DFCC""" % type_val)
def set_cholesky_from(mtd_type): type_val = core.get_global_option(mtd_type) if type_val == 'CD': core.set_local_option('GPU_DFCC', 'DF_BASIS_CC', 'CHOLESKY') # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): optstash.add_option(['SCF_TYPE']) core.set_global_option('SCF_TYPE', 'CD') core.print_out(""" SCF Algorithm Type (re)set to CD.\n""") elif type_val == 'DF': if core.get_option('GPU_DFCC', 'DF_BASIS_CC') == 'CHOLESKY': core.set_local_option('GPU_DFCC', 'DF_BASIS_CC', '') proc_util.check_disk_df(name.upper(), optstash) else: raise ValidationError("""Invalid type '%s' for DFCC""" % type_val)
def set_options(options_dict, verbose=1): """Sets Psi4 options from an input dictionary. Parameters ---------- options_dict : dict Dictionary where keys are "option_name" for global options or "module_name__option_name" (double underscore separation) for option local to "module_name". Values are the option value. All are case insensitive. verbose : int, optional Control print volume. Returns ------- None """ optionre = re.compile(r'\A(?P<module>\w+__)?(?P<option>\w+)\Z', re.IGNORECASE) rejected = {} for k, v, in options_dict.items(): mobj = optionre.match(k) module = mobj.group('module').upper()[:-2] if mobj.group('module') else None option = mobj.group('option').upper() if module: if (module, option, v) not in [('SCF', 'GUESS', 'READ')]: # TODO guess/read exception is for distributed driver. should be handled differently. try: core.set_local_option(module, option, v) except RuntimeError as err: rejected[k] = (v, err) if verbose > 1: print('Setting: core.set_local_option', module, option, v) else: try: core.set_global_option(option, v) except RuntimeError as err: rejected[k] = (v, err) if verbose > 1: print('Setting: core.set_global_option', option, v) if rejected: raise ValidationError(f'Error setting options: {rejected}')
def scf_compute_energy(self): """Base class Wavefunction requires this function. Here it is simply a wrapper around initialize(), iterations(), finalize_energy(). It returns the SCF energy computed by finalize_energy(). """ if core.get_option('SCF', 'DF_SCF_GUESS') and (core.get_global_option('SCF_TYPE') == 'DIRECT'): # speed up DIRECT algorithm (recomputes full (non-DF) integrals # each iter) by first converging via fast DF iterations, then # fully converging in fewer slow DIRECT iterations. aka Andy trick 2.0 core.print_out(" Starting with a DF guess...\n\n") with p4util.OptionsStateCM(['SCF_TYPE']): core.set_global_option('SCF_TYPE', 'DF') self.initialize() try: self.iterations() except SCFConvergenceError: self.finalize() raise SCFConvergenceError("""SCF DF preiterations""", self.iteration_, self, 0, 0) core.print_out("\n DF guess converged.\n\n") # reset the DIIS & JK objects in prep for DIRECT if self.initialized_diis_manager_: self.diis_manager().reset_subspace() self.initialize_jk(self.memory_jk_) else: self.initialize() try: self.iterations() except SCFConvergenceError as e: if core.get_option("SCF", "FAIL_ON_MAXITER"): core.print_out(" Failed to converge.\n") # energy = 0.0 # A P::e fn to either throw or protest upon nonconvergence # die_if_not_converged() raise e else: core.print_out(" Energy did not converge, but proceeding anyway.\n\n") else: core.print_out(" Energy converged.\n\n") scf_energy = self.finalize_energy() return scf_energy
def pcm_helper(block): """ Passes multiline string *block* to PCMSolver parser. Parameters ---------- block: multiline string with PCM input in PCMSolver syntax. """ suffix = str(os.getpid()) + '.' + str(uuid.uuid4())[:8] pcmsolver_fname = 'pcmsolver.' + suffix + '.inp' with open(pcmsolver_fname, 'w') as handle: handle.write(block) import pcmsolver parsed_pcm = pcmsolver.parse_pcm_input(pcmsolver_fname) os.remove(pcmsolver_fname) pcmsolver_parsed_fname = '@pcmsolver.' + suffix with open(pcmsolver_parsed_fname, 'w') as tmp: tmp.write(parsed_pcm) core.set_global_option('PCMSOLVER_PARSED_FNAME', '{}'.format(pcmsolver_parsed_fname))
def process_option(spaces, module, key, value, line): """Function to process a line with set or in a set block into global/local domain and keyword/value. """ module = module.upper() key = key.upper() isbasis = True if 'BASIS' in key else False value = quotify(value.strip(), isbasis=isbasis) if module == "GLOBALS" or module == "GLOBAL" or module == "" or module.isspace(): # If it's really a global, we need slightly different syntax if runalso: core.set_global_option(key, dequotify(value)) return "%score.set_global_option(\"%s\", %s)\n" % (spaces, key, value) else: # It's a local option, so we need the module name in there too if runalso: core.set_local_option(module, key, dequotify(value)) return "%score.set_local_option(\"%s\", \"%s\", %s)\n" % (spaces, module, key, value)
def compute_hessian(self, molecule): """Compute dispersion Hessian based on engine, dispersion level, and parameters in `self`. Uses finite difference, as no dispersion engine has analytic second derivatives. Parameters ---------- molecule : psi4.core.Molecule System for which to compute empirical dispersion correction. Returns ------- psi4.core.Matrix (3*nat, 3*nat) dispersion Hessian [Eh/a0/a0]. """ optstash = p4util.OptionsState(['PRINT']) core.set_global_option('PRINT', 0) core.print_out("\n\n Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n") core.print_out(" Computing the Hessian through finite difference of gradients.\n\n") # Setup the molecule molclone = molecule.clone() molclone.reinterpret_coordentry(False) molclone.fix_orientation(True) molclone.fix_com(True) # Record undisplaced symmetry for projection of diplaced point groups core.set_parent_symmetry(molecule.schoenflies_symbol()) findif_meta_dict = driver_findif.hessian_from_gradient_geometries(molclone, -1) for displacement in findif_meta_dict["displacements"].values(): geom_array = np.reshape(displacement["geometry"], (-1, 3)) molclone.set_geometry(core.Matrix.from_array(geom_array)) molclone.update_geometry() displacement["gradient"] = self.compute_gradient(molclone).np.ravel().tolist() H = driver_findif.compute_hessian_from_gradients(findif_meta_dict, -1) optstash.restore() return core.Matrix.from_array(H)
def compute_hessian(self, molecule): """Compute dispersion Hessian based on engine, dispersion level, and parameters in `self`. Uses finite difference, as no dispersion engine has analytic second derivatives. Parameters ---------- molecule : psi4.core.Molecule System for which to compute empirical dispersion correction. Returns ------- psi4.core.Matrix (3*nat, 3*nat) dispersion Hessian [Eh/a0/a0]. """ optstash = p4util.OptionsState(['PRINT']) core.set_global_option('PRINT', 0) core.print_out("\n\n Analytical Dispersion Hessians are not supported by dftd3 or gcp.\n") core.print_out(" Computing the Hessian through finite difference of gradients.\n\n") # Setup the molecule molclone = molecule.clone() molclone.reinterpret_coordentry(False) molclone.fix_orientation(True) molclone.fix_com(True) # Record undisplaced symmetry for projection of diplaced point groups core.set_parent_symmetry(molecule.schoenflies_symbol()) gradients = [] for geom in driver_findif.hessian_from_gradient_geometries(molecule, -1): molclone.set_geometry(geom) molclone.update_geometry() gradients.append(self.compute_gradient(molclone)) H = driver_findif.compute_hessian_from_gradient(molecule, gradients, -1) optstash.restore() return core.Matrix.from_array(H)
def reset_pe_options(pofm): """Acts on Process::environment.options to clear it, the set it to state encoded in `pofm`. Parameters ---------- pofm : dict Result of psi4.driver.p4util.prepare_options_for_modules(changedOnly=True, commandsInsteadDict=False) Returns ------- None """ core.clean_options() for go, dgo in pofm['GLOBALS'].items(): if dgo['has_changed']: core.set_global_option(go, dgo['value']) for module in _modules: for lo, dlo in pofm[module].items(): if dlo['has_changed']: core.set_local_option(module, lo, dlo['value'])
def _reset_pe_options(pofm: Dict): """Acts on ``Process::environment.options`` to clear it, then set it to state encoded in **pofm**. Parameters ---------- pofm Result of :py:func:`psi4.driver.p4util.prepare_options_for_modules(changedOnly=True, commandsInsteadDict=False, stateInsteadMediated=True)` Returns ------- None """ core.clean_options() for go, dgo in pofm['GLOBALS'].items(): if dgo['has_changed']: core.set_global_option(go, dgo['value']) for module in _modules: for lo, dlo in pofm[module].items(): if dlo['has_changed']: core.set_local_option(module, lo, dlo['value'])
def _init_df(self, calc): if self.no_reuse: return if calc.B == 'd': candidates = [ calcid('m1', 'd', calc.Z), calcid('m2', 'd', calc.Z), calcid('d', 'd', calc.Z) ] core.set_global_option("DF_INTS_IO", "SAVE") for c in filter(lambda c: c in self.wfn_cache, candidates): oldns = self.fmt_ns(c) newns = self.fmt_ns(calc) core.IO.change_file_namespace(psif.PSIF_DFSCF_BJ, oldns, newns) core.set_global_option("DF_INTS_IO", "LOAD") else: core.set_global_option("DF_INTS_IO", "NONE")
def run_sapt_dft(name, **kwargs): optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE'], ['SCF', 'DFT_GRAC_SHIFT'], ['SCF', 'SAVE_JK']) core.tstart() # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): core.set_global_option('SCF_TYPE', 'DF') core.prepare_options_for_module("SAPT") # Get the molecule of interest ref_wfn = kwargs.get('ref_wfn', None) if ref_wfn is None: sapt_dimer = kwargs.pop('molecule', core.get_active_molecule()) else: core.print_out( 'Warning! SAPT argument "ref_wfn" is only able to use molecule information.' ) sapt_dimer = ref_wfn.molecule() sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule( sapt_dimer, "dimer") # Grab overall settings mon_a_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_A") mon_b_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_B") do_delta_hf = core.get_option("SAPT", "SAPT_DFT_DO_DHF") sapt_dft_functional = core.get_option("SAPT", "SAPT_DFT_FUNCTIONAL") # Print out the title and some information core.print_out("\n") core.print_out( " ---------------------------------------------------------\n") core.print_out(" " + "SAPT(DFT) Procedure".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith".center(58) + "\n") core.print_out( " ---------------------------------------------------------\n") core.print_out("\n") core.print_out( " !!! WARNING: SAPT(DFT) capability is in beta. Please use with caution. !!!\n\n" ) core.print_out(" ==> Algorithm <==\n\n") core.print_out(" SAPT DFT Functional %12s\n" % str(sapt_dft_functional)) core.print_out(" Monomer A GRAC Shift %12.6f\n" % mon_a_shift) core.print_out(" Monomer B GRAC Shift %12.6f\n" % mon_b_shift) core.print_out(" Delta HF %12s\n" % ("True" if do_delta_hf else "False")) core.print_out(" JK Algorithm %12s\n" % core.get_global_option("SCF_TYPE")) core.print_out("\n") core.print_out(" Required computations:\n") if (do_delta_hf): core.print_out(" HF (Dimer)\n") core.print_out(" HF (Monomer A)\n") core.print_out(" HF (Monomer B)\n") core.print_out(" DFT (Monomer A)\n") core.print_out(" DFT (Monomer B)\n") core.print_out("\n") if (sapt_dft_functional != "HF") and ((mon_a_shift == 0.0) or (mon_b_shift == 0.0)): raise ValidationError( 'SAPT(DFT): must set both "SAPT_DFT_GRAC_SHIFT_A" and "B".') if (core.get_option('SCF', 'REFERENCE') != 'RHF'): raise ValidationError( 'SAPT(DFT) currently only supports restricted references.') core.IO.set_default_namespace('dimer') data = {} if (core.get_global_option('SCF_TYPE') == 'DF'): # core.set_global_option('DF_INTS_IO', 'LOAD') core.set_global_option('DF_INTS_IO', 'SAVE') # # Compute dimer wavefunction hf_wfn_dimer = None if do_delta_hf: if (core.get_global_option('SCF_TYPE') == 'DF'): core.set_global_option('DF_INTS_IO', 'SAVE') core.timer_on("SAPT(DFT): Dimer SCF") hf_data = {} hf_wfn_dimer = scf_helper("SCF", molecule=sapt_dimer, banner="SAPT(DFT): delta HF Dimer", **kwargs) hf_data["HF DIMER"] = core.variable("CURRENT ENERGY") core.timer_off("SAPT(DFT): Dimer SCF") core.timer_on("SAPT(DFT): Monomer A SCF") if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'dimer', 'monomerA') hf_wfn_A = scf_helper("SCF", molecule=monomerA, banner="SAPT(DFT): delta HF Monomer A", **kwargs) hf_data["HF MONOMER A"] = core.variable("CURRENT ENERGY") core.timer_off("SAPT(DFT): Monomer A SCF") core.timer_on("SAPT(DFT): Monomer B SCF") core.set_global_option("SAVE_JK", True) if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerA', 'monomerB') hf_wfn_B = scf_helper("SCF", molecule=monomerB, banner="SAPT(DFT): delta HF Monomer B", **kwargs) hf_data["HF MONOMER B"] = core.variable("CURRENT ENERGY") core.set_global_option("SAVE_JK", False) core.timer_off("SAPT(DFT): Monomer B SCF") # Grab JK object and set to A (so we do not save many JK objects) sapt_jk = hf_wfn_B.jk() hf_wfn_A.set_jk(sapt_jk) core.set_global_option("SAVE_JK", False) # Move it back to monomer A if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerB', 'dimer') core.print_out("\n") core.print_out( " ---------------------------------------------------------\n" ) core.print_out(" " + "SAPT(DFT): delta HF Segment".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith and Rob Parrish".center(58) + "\n") core.print_out( " ---------------------------------------------------------\n" ) core.print_out("\n") # Build cache hf_cache = sapt_jk_terms.build_sapt_jk_cache(hf_wfn_A, hf_wfn_B, sapt_jk, True) # Electrostatics core.timer_on("SAPT(DFT):SAPT:elst") elst = sapt_jk_terms.electrostatics(hf_cache, True) hf_data.update(elst) core.timer_off("SAPT(DFT):SAPT:elst") # Exchange core.timer_on("SAPT(DFT):SAPT:exch") exch = sapt_jk_terms.exchange(hf_cache, sapt_jk, True) hf_data.update(exch) core.timer_off("SAPT(DFT):SAPT:exch") # Induction core.timer_on("SAPT(DFT):SAPT:ind") ind = sapt_jk_terms.induction( hf_cache, sapt_jk, True, maxiter=core.get_option("SAPT", "MAXITER"), conv=core.get_option("SAPT", "D_CONVERGENCE"), Sinf=core.get_option("SAPT", "DO_IND_EXCH_SINF")) hf_data.update(ind) core.timer_off("SAPT(DFT):SAPT:ind") dhf_value = hf_data["HF DIMER"] - hf_data["HF MONOMER A"] - hf_data[ "HF MONOMER B"] core.print_out("\n") core.print_out( print_sapt_hf_summary(hf_data, "SAPT(HF)", delta_hf=dhf_value)) data["Delta HF Correction"] = core.variable("SAPT(DFT) Delta HF") sapt_jk.finalize() del hf_wfn_A, hf_wfn_B, sapt_jk if hf_wfn_dimer is None: dimer_wfn = core.Wavefunction.build(sapt_dimer, core.get_global_option("BASIS")) else: dimer_wfn = hf_wfn_dimer # Set the primary functional core.set_local_option('SCF', 'REFERENCE', 'RKS') # Compute Monomer A wavefunction core.timer_on("SAPT(DFT): Monomer A DFT") if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'dimer', 'monomerA') if mon_a_shift: core.set_global_option("DFT_GRAC_SHIFT", mon_a_shift) core.IO.set_default_namespace('monomerA') wfn_A = scf_helper(sapt_dft_functional, post_scf=False, molecule=monomerA, banner="SAPT(DFT): DFT Monomer A", **kwargs) data["DFT MONOMERA"] = core.variable("CURRENT ENERGY") core.set_global_option("DFT_GRAC_SHIFT", 0.0) core.timer_off("SAPT(DFT): Monomer A DFT") # Compute Monomer B wavefunction core.timer_on("SAPT(DFT): Monomer B DFT") if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerA', 'monomerB') if mon_b_shift: core.set_global_option("DFT_GRAC_SHIFT", mon_b_shift) core.set_global_option("SAVE_JK", True) core.IO.set_default_namespace('monomerB') wfn_B = scf_helper(sapt_dft_functional, post_scf=False, molecule=monomerB, banner="SAPT(DFT): DFT Monomer B", **kwargs) data["DFT MONOMERB"] = core.variable("CURRENT ENERGY") # Save JK object sapt_jk = wfn_B.jk() wfn_A.set_jk(sapt_jk) core.set_global_option("SAVE_JK", False) core.set_global_option("DFT_GRAC_SHIFT", 0.0) core.timer_off("SAPT(DFT): Monomer B DFT") # Write out header scf_alg = core.get_global_option("SCF_TYPE") sapt_dft_header(sapt_dft_functional, mon_a_shift, mon_b_shift, bool(do_delta_hf), scf_alg) # Call SAPT(DFT) sapt_jk = wfn_B.jk() sapt_dft(dimer_wfn, wfn_A, wfn_B, sapt_jk=sapt_jk, data=data, print_header=False) # Copy data back into globals for k, v in data.items(): core.set_variable(k, v) core.tstop() return dimer_wfn
def run_json_qcschema(json_data, clean, json_serialization, keep_wfn=False): """ An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4. Parameters ---------- json_data : JSON Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details. Notes ----- !Warning! This function is experimental and likely to change in the future. Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema. Examples -------- """ # Clean a few things _clean_psi_environ(clean) # This is currently a forced override if json_data["schema_name"] in ["qc_schema_input", "qcschema_input"]: json_data["schema_name"] = "qcschema_input" else: raise KeyError("Schema name of '{}' not understood".format( json_data["schema_name"])) if json_data["schema_version"] != 1: raise KeyError("Schema version of '{}' not understood".format( json_data["schema_version"])) if json_data.get("nthreads", False) is not False: core.set_num_threads(json_data["nthreads"], quiet=True) # Build molecule if "schema_name" in json_data["molecule"]: molschemus = json_data["molecule"] # dtype >=2 else: molschemus = json_data # dtype =1 mol = core.Molecule.from_schema(molschemus) # Update molecule geometry as we orient and fix_com json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist() # Set options kwargs = json_data["keywords"].pop("function_kwargs", {}) p4util.set_options(json_data["keywords"]) # Setup the computation method = json_data["model"]["method"] core.set_global_option("BASIS", json_data["model"]["basis"]) kwargs.update({"return_wfn": True, "molecule": mol}) # Handle special properties case if json_data["driver"] == "properties": if "properties" not in kwargs: kwargs["properties"] = list(default_properties_) # Actual driver run val, wfn = methods_dict_[json_data["driver"]](method, **kwargs) # Pull out a standard set of SCF properties if "extras" not in json_data: json_data["extras"] = {} json_data["extras"]["qcvars"] = {} current_qcvars_only = json_data["extras"].get("current_qcvars_only", False) if json_data["extras"].get("wfn_qcvars_only", False): psi_props = wfn.variables( include_deprecated_keys=(not current_qcvars_only)) else: psi_props = core.variables( include_deprecated_keys=(not current_qcvars_only)) for k, v in psi_props.items(): if k not in json_data["extras"]["qcvars"]: json_data["extras"]["qcvars"][k] = _serial_translation( v, json=json_serialization) # Still a bit of a mess at the moment add in local vars as well. for k, v in wfn.variables().items(): if k not in json_data["extras"]["qcvars"]: # interpreting wfn_qcvars_only as no deprecated qcvars either if not (json_data["extras"].get("wfn_qcvars_only", False) and (any([ k.upper().endswith(" DIPOLE " + cart) for cart in ["X", "Y", "Z"] ]) or any([ k.upper().endswith(" QUADRUPOLE " + cart) for cart in ["XX", "YY", "ZZ", "XY", "XZ", "YZ"] ]) or k.upper() in [ "SOS-MP2 CORRELATION ENERGY", "SOS-MP2 TOTAL ENERGY", "SOS-PI-MP2 CORRELATION ENERGY", "SOS-PI-MP2 TOTAL ENERGY", "SCS-MP3 CORRELATION ENERGY", "SCS-MP3 TOTAL ENERGY", ])): json_data["extras"]["qcvars"][k] = _serial_translation( v, json=json_serialization) # Handle the return result if json_data["driver"] == "energy": json_data["return_result"] = val elif json_data["driver"] in ["gradient", "hessian"]: json_data["return_result"] = _serial_translation( val, json=json_serialization) elif json_data["driver"] == "properties": ret = {} mtd = json_data["model"]["method"].upper() # Dipole/quadrupole still special case if "dipole" in kwargs["properties"]: ret["dipole"] = _serial_translation(psi_props[mtd + " DIPOLE"], json=json_serialization) if "quadrupole" in kwargs["properties"]: ret["quadrupole"] = _serial_translation(psi_props[mtd + " QUADRUPOLE"], json=json_serialization) ret.update( _convert_variables(wfn.variables(), context="properties", json=json_serialization)) json_data["return_result"] = ret else: raise KeyError("Did not understand Driver key %s." % json_data["driver"]) props = { "calcinfo_nbasis": wfn.nso(), "calcinfo_nmo": wfn.nmo(), "calcinfo_nalpha": wfn.nalpha(), "calcinfo_nbeta": wfn.nbeta(), "calcinfo_natom": mol.geometry().shape[0], "nuclear_repulsion_energy": mol.nuclear_repulsion_energy( ), # use this b/c psivar is monomer for SAPT } props.update( _convert_variables(psi_props, context="generics", json=json_serialization)) if not list( set(['CBS NUMBER', 'NBODY NUMBER', 'FINDIF NUMBER']) & set(json_data["extras"]["qcvars"].keys())): props.update( _convert_variables(psi_props, context="scf", json=json_serialization)) # Write out post-SCF keywords if "MP2 CORRELATION ENERGY" in psi_props: props.update( _convert_variables(psi_props, context="mp2", json=json_serialization)) if "CCSD CORRELATION ENERGY" in psi_props: props.update( _convert_variables(psi_props, context="ccsd", json=json_serialization)) if "CCSD(T) CORRELATION ENERGY" in psi_props: props.update( _convert_variables(psi_props, context="ccsd(t)", json=json_serialization)) json_data["properties"] = props json_data["success"] = True json_data["provenance"]["module"] = wfn.module() if keep_wfn: json_data["wavefunction"] = _convert_wavefunction(wfn) files = { "psi4.grad": Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".grad"), "psi4.hess": Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".hess"), # binary "psi4.180.npy": Path(core.get_writer_file_prefix(wfn.molecule().name()) + ".180.npy"), "timer.dat": Path( "timer.dat" ), # ok for `psi4 --qcschema` but no file collected for `qcengine.run_program(..., "psi4")` } json_data["native_files"] = { fl: flpath.read_text() for fl, flpath in files.items() if flpath.exists() } # Reset state _clean_psi_environ(clean) json_data["schema_name"] = "qcschema_output" return json_data
def run_json_qc_schema(json_data, clean): """ An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4. Parameters ---------- json_data : JSON Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details. Notes ----- !Warning! This function is experimental and likely to change in the future. Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema. Examples -------- """ # Clean a few things _clean_psi_environ(clean) # This is currently a forced override if json_data["schema_name"] != "qc_schema_input": raise KeyError("Schema name of '{}' not understood".format(json_data["schema_name"])) if json_data["schema_version"] != 1: raise KeyError("Schema version of '{}' not understood".format(json_data["schema_version"])) if json_data.get("nthreads", False) is not False: psi4.set_num_threads(json_data["nthreads"], quiet=True) json_data["provenance"] = {"creator": "Psi4", "version": psi4.__version__, "routine": "psi4.json.run_json"} # Build molecule mol = core.Molecule.from_schema(json_data) # Update molecule geometry as we orient and fix_com json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist() # Set options for k, v in json_data["keywords"].items(): core.set_global_option(k, v) # Setup the computation method = json_data["model"]["method"] core.set_global_option("BASIS", json_data["model"]["basis"]) kwargs = {"return_wfn": True, "molecule": mol} # Handle special properties case if json_data["driver"] == "properties": if "properties" in json_data["model"]: kwargs["properties"] = [x.lower() for x in json_data["model"]["properties"]] extra = set(kwargs["properties"]) - can_do_properties_ if len(extra): raise KeyError("Did not understand property key %s." % kwargs["properties"]) else: kwargs["properties"] = list(can_do_properties_) # Actual driver run val, wfn = methods_dict_[json_data["driver"]](method, **kwargs) # Pull out a standard set of SCF properties psi_props = psi4.core.get_variables() json_data["psi4:qcvars"] = psi_props # Handle the return result if json_data["driver"] == "energy": json_data["return_result"] = val elif json_data["driver"] in ["gradient", "hessian"]: json_data["return_result"] = val.np.ravel().tolist() elif json_data["driver"] == "properties": ret = {} mtd = json_data["model"]["method"].upper() if "dipole" in kwargs["properties"]: ret["dipole"] = [psi_props[mtd + " DIPOLE " + x] for x in ["X", "Y", "Z"]] if "quadrupole" in kwargs["properties"]: ret["quadrupole"] = [psi_props[mtd + " QUADRUPOLE " + x] for x in ["XX", "XY", "XZ", "YY", "YZ", "ZZ"]] if "mulliken_charges" in kwargs["properties"]: ret["mulliken_charges"] = wfn.get_array("MULLIKEN_CHARGES").np.ravel().tolist() if "lowdin_charges" in kwargs["properties"]: ret["lowdin_charges"] = wfn.get_array("LOWDIN_CHARGES").np.ravel().tolist() if "wiberg_lowdin_indices" in kwargs["properties"]: ret["wiberg_lowdin_indices"] = wfn.get_array("WIBERG_LOWDIN_INDICES").np.ravel().tolist() if "mayer_indices" in kwargs["properties"]: ret["mayer_indices"] = wfn.get_array("MAYER_INDICES").np.ravel().tolist() json_data["return_result"] = ret else: raise KeyError("Did not understand Driver key %s." % json_data["driver"]) props = { "calcinfo_nbasis": wfn.nso(), "calcinfo_nmo": wfn.nmo(), "calcinfo_nalpha": wfn.nalpha(), "calcinfo_nbeta": wfn.nbeta(), "calcinfo_natom": mol.geometry().shape[0], "scf_one_electron_energy": psi_props["ONE-ELECTRON ENERGY"], "scf_two_electron_energy": psi_props["TWO-ELECTRON ENERGY"], "nuclear_repulsion_energy": psi_props["NUCLEAR REPULSION ENERGY"], "scf_dipole_moment": [psi_props[x] for x in ["SCF DIPOLE X", "SCF DIPOLE Y", "SCF DIPOLE Z"]], "scf_iterations": int(psi_props["SCF ITERATIONS"]), "scf_total_energy": psi_props["SCF TOTAL ENERGY"], "return_energy": psi_props["CURRENT ENERGY"], } # Pull out optional SCF keywords other_scf = [("DFT VV10 ENERGY", "scf_vv10_energy"), ("DFT XC ENERGY", "scf_xc_energy"), ("DISPERSION CORRECTION ENERGY", "scf_dispersion_correction_energy")] for pkey, skey in other_scf: if (pkey in psi_props) and (psi_props[pkey] != 0): props[skey] = psi_props[pkey] # Write out MP2 keywords if "MP2 CORRELATION ENERGY" in psi_props: props["mp2_same_spin_correlation_energy"] = psi_props["MP2 SAME-SPIN CORRELATION ENERGY"] props["mp2_opposite_spin_correlation_energy"] = psi_props["MP2 OPPOSITE-SPIN CORRELATION ENERGY"] props["mp2_singles_energy"] = 0.0 props["mp2_doubles_energy"] = psi_props["MP2 CORRELATION ENERGY"] props["mp2_total_correlation_energy"] = psi_props["MP2 CORRELATION ENERGY"] props["mp2_total_energy"] = psi_props["MP2 TOTAL ENERGY"] json_data["properties"] = props json_data["success"] = True # Reset state _clean_psi_environ(clean) json_data["schema_name"] = "qc_schema_output" return json_data
def run_json_original_v1_1(json_data, clean): """ Runs and updates the input JSON data. This was a trial specification introduced in Psi4 v1.1. This will be deprecated in Psi4 v1.3 in favour of the QC JSON format found here: http://molssi-qc-schema.readthedocs.io/en/latest/index.html# Parameters ---------- json_data : JSON input Required input fields: - molecule : str A string representation of the molecule. Any valid psi4 synatx is valid. - driver : str The driver method to use valid arguments are "energy", "gradient", "property" - args : str Input arguments to the driver function - kwargs : dict Input dictionary to the driver function Optional input fields: - kwargs : dict Additional kwargs to be passed to the driver. - options : dict Global options to set in the Psi4 run. - scratch_location : str Overide the default scratch location. - return_output : bool Return the full string reprsentation of the output or not. Output fields: - return_value : float, psi4.core.Vector, psi4.core.Matrix The return value of the input function. - variables : dict The list of Psi4 variables generated from the run. - success : bool Indicates if the run was successful or not. - error : str If an error is raised the result is returned here. - raw_output : str The full Psi4 output if requested. Notes ----- !Warning! This function is experimental and likely to change in the future. Please report any suggestions or uses of this function on github.com/psi4/psi4. Examples -------- # CP corrected Helium dimer energy in the STO-3G basis. >>> json_data = {} >>> json_data["molecule"] = "He 0 0 0\n--\nHe 0 0 1" >>> json_data["driver"] = "energy" >>> json_data["method"] = 'SCF' >>> json_data["kwargs"] = {"bsse_type": "cp"} >>> json_data["options"] = {"BASIS": "STO-3G"} >>> run_json(json_data) { "raw_output": "Output storing was not requested.", "options": { "BASIS": "STO-3G" }, "driver": "energy", "molecule": "He 0 0 0\n--\nHe 0 0 1", "method": "SCF", "variables": { "SCF N ITERS": 2.0, "SCF DIPOLE Y": 0.0, "CURRENT DIPOLE Y": 0.0, "CP-CORRECTED 2-BODY INTERACTION ENERGY": 0.1839360538612116, "HF TOTAL ENERGY": -5.433191881443323, "SCF TOTAL ENERGY": -5.433191881443323, "TWO-ELECTRON ENERGY": 4.124089347186247, "SCF ITERATION ENERGY": -5.433191881443323, "CURRENT DIPOLE X": 0.0, "CURRENT DIPOLE Z": 0.0, "CURRENT REFERENCE ENERGY": -5.433191881443323, "CURRENT ENERGY": 0.1839360538612116, "COUNTERPOISE CORRECTED TOTAL ENERGY": -5.433191881443323, "SCF DIPOLE Z": 0.0, "COUNTERPOISE CORRECTED INTERACTION ENERGY": 0.1839360538612116, "NUCLEAR REPULSION ENERGY": 2.11670883436, "SCF DIPOLE X": 0.0, "ONE-ELECTRON ENERGY": -11.67399006298957 }, "return_value": 0.1839360538612116, "error": "", "success": true, "provenance": { "creator": "Psi4", "routine": "psi4.run_json", "version": "1.1a1" }, "kwargs": { "bsse_type": "cp" } } """ # Clean a few things _clean_psi_environ(clean) # Set a few variables json_data["error"] = "" json_data["success"] = False json_data["raw_output"] = None json_data[ "warning"] = "Warning! This format will be deprecated in Psi4 v1.3. Please switch the standard QC JSON format." # Add the provenance data prov = {} prov["version"] = psi4.__version__ prov["routine"] = "psi4.run_json" prov["creator"] = "Psi4" json_data["provenance"] = prov # Check input for check in ["driver", "method", "molecule"]: if check not in list(json_data): json_data["error"] = "Minimum input requires the %s field." % check return json_data # Check driver call if json_data["driver"] not in list(methods_dict_): json_data["error"] = "Driver parameters '%s' not recognized" % str(json_data["driver"]) return json_data # Set options if "options" in json_data.keys() and (json_data["options"] is not None): for k, v in json_data["options"].items(): core.set_global_option(k, v) # Rework args args = json_data["method"] if not isinstance(args, (list, tuple)): args = [args] # Deep copy kwargs if "kwargs" in list(json_data): kwargs = copy.deepcopy(json_data["kwargs"]) else: kwargs = {} kwargs["molecule"] = molutil.geometry(json_data["molecule"]) # Full driver call kwargs["return_wfn"] = True if json_data["driver"] not in methods_dict_: raise KeyError("Driver type '%s' not recognized." % str(json_data["driver"])) val, wfn = methods_dict_[json_data["driver"]](*args, **kwargs) if isinstance(val, (float, int)): json_data["return_value"] = val elif isinstance(val, (core.Matrix, core.Vector)): json_data["return_value"] = val.to_serial() else: raise TypeError("Unrecognized return value of type %s\n" % type(val)) json_data["variables"] = core.get_variables() json_data["success"] = True # Reset state _clean_psi_environ(clean) return json_data
def ip_fitting(name, omega_l=0.05, omega_r=2.5, omega_convergence=1.0e-3, maxiter=20, **kwargs): """Optimize DFT omega parameter for molecular system. Parameters ---------- name : string or function DFT functional string name or function defining functional whose omega is to be optimized. omega_l : float, optional Minimum omega to be considered during fitting. omega_r : float, optional Maximum omega to be considered during fitting. molecule : :ref:`molecule <op_py_molecule>`, optional Target molecule (neutral) for which omega is to be tuned, if not last defined. omega_convergence : float, optional Threshold below which to consider omega converged. (formerly omega_tolerance) maxiter : int, optional Maximum number of iterations towards omega convergence. Returns ------- float Optimal omega parameter. """ optstash = p4util.OptionsState(['SCF', 'REFERENCE'], ['SCF', 'GUESS'], ['SCF', 'DF_INTS_IO'], ['SCF', 'DFT_OMEGA'], ['DOCC'], ['SOCC']) kwargs = p4util.kwargs_lower(kwargs) # By default, do not read previous 180 orbitals file read = False read180 = '' if 'read' in kwargs: read = True read180 = kwargs['read'] if core.get_option('SCF', 'REFERENCE') != 'UKS': core.print_out( """ Requested procedure `ip_fitting` runs further calculations with UKS reference.\n""" ) core.set_local_option('SCF', 'REFERENCE', 'UKS') # Make sure the molecule the user provided is the active one, and neutral molecule = kwargs.pop('molecule', core.get_active_molecule()) molecule.update_geometry() if molecule.molecular_charge() != 0: raise ValidationError( """IP Fitting requires neutral molecule to start.""") if molecule.schoenflies_symbol() != 'c1': core.print_out( """ Requested procedure `ip_fitting` does not make use of molecular symmetry: """ """further calculations in C1 point group.\n""") molecule = molecule.clone() molecule.reset_point_group('c1') molecule.update_geometry() charge0 = molecule.molecular_charge() mult0 = molecule.multiplicity() # How many electrons are there? N = 0 for A in range(molecule.natom()): N += molecule.Z(A) N -= charge0 N = int(N) Nb = int((N - mult0 + 1) / 2) Na = int(N - Nb) # Work in the ot namespace for this procedure core.IO.set_default_namespace("ot") # Burn in to determine orbital eigenvalues if read: core.set_local_option("SCF", "GUESS", "READ") copy_file_to_scratch(read180, 'psi', 'ot', 180) core.set_local_option("SCF", "DF_INTS_IO", "SAVE") E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Burn-in', **kwargs) core.set_local_option("SCF", "DF_INTS_IO", "LOAD") if not wfn.functional().is_x_lrc(): raise ValidationError( """Not sensible to optimize omega for non-long-range-correction functional.""" ) # Determine H**O, to determine mult1 eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Na == Nb: H**O = -Nb elif Nb == 0: H**O = Na else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] if E_a >= E_b: H**O = Na else: H**O = -Nb Na1 = Na Nb1 = Nb if H**O > 0: Na1 -= 1 else: Nb1 -= 1 charge1 = charge0 + 1 mult1 = Na1 - Nb1 + 1 omegas = [] E0s = [] E1s = [] kIPs = [] IPs = [] types = [] # Right endpoint core.set_local_option('SCF', 'DFT_OMEGA', omega_r) # Neutral if read: core.set_local_option("SCF", "GUESS", "READ") p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180) molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) E0r, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Right Endpoint', **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) E_HOMOr = E_HOMO core.IO.change_file_namespace(180, "ot", "neutral") # Cation if read: core.set_local_option("SCF", "GUESS", "READ") p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180) molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) E1r = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Right Endpoint', **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IPr = E1r - E0r kIPr = -E_HOMOr delta_r = IPr - kIPr if IPr > kIPr: raise ValidationError( """\n***IP Fitting Error: Right Omega limit should have kIP > IP: {} !> {}""" .format(kIPr, IPr)) omegas.append(omega_r) types.append('Right Limit') E0s.append(E0r) E1s.append(E1r) IPs.append(IPr) kIPs.append(kIPr) # Use previous orbitals from here out core.set_local_option("SCF", "GUESS", "READ") # Left endpoint core.set_local_option('SCF', 'DFT_OMEGA', omega_l) # Neutral core.IO.change_file_namespace(180, "neutral", "ot") molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) core.set_global_option("DOCC", [Nb]) core.set_global_option("SOCC", [Na - Nb]) E0l, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Left Endpoint', **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) E_HOMOl = E_HOMO core.IO.change_file_namespace(180, "ot", "neutral") # Cation core.IO.change_file_namespace(180, "cation", "ot") molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) core.set_global_option("DOCC", [Nb1]) core.set_global_option("SOCC", [Na1 - Nb1]) E1l = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Left Endpoint', **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IPl = E1l - E0l kIPl = -E_HOMOl delta_l = IPl - kIPl if IPl < kIPl: raise ValidationError( """\n***IP Fitting Error: Left Omega limit should have kIP < IP: {} !< {}""" .format(kIPl, IPl)) omegas.append(omega_l) types.append('Left Limit') E0s.append(E0l) E1s.append(E1l) IPs.append(IPl) kIPs.append(kIPl) converged = False repeat_l = 0 repeat_r = 0 for step in range(maxiter): # Regula Falsi (modified) if repeat_l > 1: delta_l /= 2.0 if repeat_r > 1: delta_r /= 2.0 omega = -(omega_r - omega_l) / (delta_r - delta_l) * delta_l + omega_l core.set_local_option('SCF', 'DFT_OMEGA', omega) # Neutral core.IO.change_file_namespace(180, "neutral", "ot") molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) core.set_global_option("DOCC", [Nb]) core.set_global_option("SOCC", [Na - Nb]) E0, wfn = driver.energy( 'scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Omega = {:11.3E}'.format(omega), **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) core.IO.change_file_namespace(180, "ot", "neutral") # Cation core.IO.change_file_namespace(180, "cation", "ot") molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) core.set_global_option("DOCC", [Nb1]) core.set_global_option("SOCC", [Na1 - Nb1]) E1 = driver.energy( 'scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Omega = {:11.3E}'.format(omega), **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IP = E1 - E0 kIP = -E_HOMO delta = IP - kIP if kIP > IP: omega_r = omega E0r = E0 E1r = E1 IPr = IP kIPr = kIP delta_r = delta repeat_r = 0 repeat_l += 1 else: omega_l = omega E0l = E0 E1l = E1 IPl = IP kIPl = kIP delta_l = delta repeat_l = 0 repeat_r += 1 omegas.append(omega) types.append('Regula-Falsi') E0s.append(E0) E1s.append(E1) IPs.append(IP) kIPs.append(kIP) # Termination if abs(omega_l - omega_r) < omega_convergence: converged = True break core.IO.set_default_namespace("") core.print_out("""\n ==> IP Fitting Results <==\n\n""") core.print_out(""" => Occupation Determination <= \n\n""") core.print_out(""" %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O')) core.print_out(""" Neutral: %6d %6d %6d %6d %6d %6d\n""" % (N, Na, Nb, charge0, mult0, H**O)) core.print_out(""" Cation: %6d %6d %6d %6d %6d\n\n""" % (N - 1, Na1, Nb1, charge1, mult1)) core.print_out(""" => Regula Falsi Iterations <=\n\n""") core.print_out(""" %3s %11s %14s %14s %14s %s\n""" % ('N', 'Omega', 'IP', 'kIP', 'Delta', 'Type')) for k in range(len(omegas)): core.print_out( """ %3d %11.3E %14.6E %14.6E %14.6E %s\n""" % (k + 1, omegas[k], IPs[k], kIPs[k], IPs[k] - kIPs[k], types[k])) optstash.restore() if converged: core.print_out("""\n IP Fitting Converged\n""") core.print_out(""" Final omega = %14.6E\n""" % ((omega_l + omega_r) / 2)) core.print_out( """\n "M,I. does the dying. Fleet just does the flying."\n""") core.print_out(""" -Starship Troopers\n""") else: raise ConvergenceError("""IP Fitting """, step + 1) return ((omega_l + omega_r) / 2)
def run_json_qcschema(json_data, clean): """ An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4. Parameters ---------- json_data : JSON Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details. Notes ----- !Warning! This function is experimental and likely to change in the future. Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema. Examples -------- """ # Clean a few things _clean_psi_environ(clean) # This is currently a forced override if json_data["schema_name"] in ["qc_schema_input", "qcschema_input"]: json_data["schema_name"] = "qcschema_input" else: raise KeyError("Schema name of '{}' not understood".format(json_data["schema_name"])) if json_data["schema_version"] != 1: raise KeyError("Schema version of '{}' not understood".format(json_data["schema_version"])) if json_data.get("nthreads", False) is not False: psi4.set_num_threads(json_data["nthreads"], quiet=True) json_data["provenance"] = {"creator": "Psi4", "version": psi4.__version__, "routine": "psi4.json.run_json"} # Build molecule if "schema_name" in json_data["molecule"]: molschemus = json_data["molecule"] # dtype >=2 else: molschemus = json_data # dtype =1 mol = core.Molecule.from_schema(molschemus) # Update molecule geometry as we orient and fix_com json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist() # Set options kwargs = json_data["keywords"].pop("function_kwargs", {}) psi4.set_options(json_data["keywords"]) # Setup the computation method = json_data["model"]["method"] core.set_global_option("BASIS", json_data["model"]["basis"]) kwargs.update({"return_wfn": True, "molecule": mol}) # Handle special properties case if json_data["driver"] == "properties": if "properties" in json_data["model"]: kwargs["properties"] = [x.lower() for x in json_data["model"]["properties"]] extra = set(kwargs["properties"]) - can_do_properties_ if len(extra): raise KeyError("Did not understand property key %s." % kwargs["properties"]) else: kwargs["properties"] = list(can_do_properties_) # Actual driver run val, wfn = methods_dict_[json_data["driver"]](method, **kwargs) # Pull out a standard set of SCF properties if "extras" not in json_data: json_data["extras"] = {} json_data["extras"]["qcvars"] = {} if json_data["extras"].get("wfn_qcvars_only", False): psi_props = wfn.variables() else: psi_props = psi4.core.variables() for k, v in psi_props.items(): if k not in json_data["extras"]["qcvars"]: json_data["extras"]["qcvars"][k] = _json_translation(v) # Still a bit of a mess at the moment add in local vars as well. for k, v in wfn.variables().items(): if k not in json_data["extras"]["qcvars"]: json_data["extras"]["qcvars"][k] = _json_translation(v) # Handle the return result if json_data["driver"] == "energy": json_data["return_result"] = val elif json_data["driver"] in ["gradient", "hessian"]: json_data["return_result"] = val.np.ravel().tolist() elif json_data["driver"] == "properties": ret = {} mtd = json_data["model"]["method"].upper() # Dipole/quadrupole still special case if "dipole" in kwargs["properties"]: ret["dipole"] = [psi_props[mtd + " DIPOLE " + x] for x in ["X", "Y", "Z"]] if "quadrupole" in kwargs["properties"]: ret["quadrupole"] = [psi_props[mtd + " QUADRUPOLE " + x] for x in ["XX", "XY", "XZ", "YY", "YZ", "ZZ"]] ret.update(_convert_variables(wfn.variables(), context="properties")) json_data["return_result"] = ret else: raise KeyError("Did not understand Driver key %s." % json_data["driver"]) props = { "calcinfo_nbasis": wfn.nso(), "calcinfo_nmo": wfn.nmo(), "calcinfo_nalpha": wfn.nalpha(), "calcinfo_nbeta": wfn.nbeta(), "calcinfo_natom": mol.geometry().shape[0], } props.update(_convert_variables(psi_props, context="generics")) if not list(set(['CBS NUMBER', 'NBODY NUMBER', 'FINDIF NUMBER']) & set(json_data["extras"]["qcvars"].keys())): props.update(_convert_variables(psi_props, context="scf")) # Write out MP2 keywords if "MP2 CORRELATION ENERGY" in psi_props: props.update(_convert_variables(psi_props, context="mp2")) json_data["properties"] = props json_data["success"] = True # Reset state _clean_psi_environ(clean) json_data["schema_name"] = "qcschema_output" return json_data
def basis_helper(block, name='', key='BASIS', set_option=True): """For PsiAPI mode, forms a basis specification function from *block* and associates it with keyword *key* under handle *name*. Registers the basis spec with Psi4 so that it can be applied again to future molecules. For usage, see mints2, mints9, and cc54 test cases. Unless *set_option* is False, *name* will be set as current active *key*, equivalent to `set key name` or `set_option({key: name})`. """ key = key.upper() name = ('anonymous' + str(uuid.uuid4())[:8]) if name == '' else name cleanbas = basname(name).replace('-', '') # further remove hyphens so can be function name block = qcel.util.filter_comments(block) command_lines = re.split('\n', block) symbol_re = re.compile(r'^\s*assign\s+(?P<symbol>[A-Z]{1,3})\s+(?P<basis>[-+*\(\)\w]+)\s*$', re.IGNORECASE) label_re = re.compile( r'^\s*assign\s+(?P<label>(?P<symbol>[A-Z]{1,3})(?:(_\w+)|(\d+))?)\s+(?P<basis>[-+*\(\)\w]+)\s*$', re.IGNORECASE) all_re = re.compile(r'^\s*assign\s+(?P<basis>[-+*\(\)\w]+)\s*$', re.IGNORECASE) basislabel = re.compile(r'\s*\[\s*([-*\(\)\w]+)\s*\]\s*') def anon(mol, role): basstrings = {} # Start by looking for assign lines, and remove them leftover_lines = [] assignments = False for line in command_lines: if symbol_re.match(line): m = symbol_re.match(line) mol.set_basis_by_symbol(m.group('symbol'), m.group('basis'), role=role) assignments = True elif label_re.match(line): m = label_re.match(line) mol.set_basis_by_label(m.group('label'), m.group('basis'), role=role) assignments = True elif all_re.match(line): m = all_re.match(line) mol.set_basis_all_atoms(m.group('basis'), role=role) assignments = True else: # Ignore blank lines and accumulate remainder if line and not line.isspace(): leftover_lines.append(line.strip()) # Now look for regular basis set definitions basblock = list(filter(None, basislabel.split('\n'.join(leftover_lines)))) if len(basblock) == 1: if not assignments: # case with no [basname] markers where whole block is contents of gbs file mol.set_basis_all_atoms(name, role=role) basstrings[basname(name)] = basblock[0] else: message = ( "Conflicting basis set specification: assign lines present but shells have no [basname] label." "") raise TestComparisonError(message) else: # case with specs separated by [basname] markers for idx in range(0, len(basblock), 2): basstrings[basname(basblock[idx])] = basblock[idx + 1] return basstrings anon.__name__ = 'basisspec_psi4_yo__' + cleanbas qcdb.libmintsbasisset.basishorde[name.upper()] = anon if set_option: core.set_global_option(key, name)
def run_sf_sapt(name, **kwargs): optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE'], ['SCF', 'DFT_GRAC_SHIFT'], ['SCF', 'SAVE_JK']) core.tstart() # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): core.set_global_option('SCF_TYPE', 'DF') core.prepare_options_for_module("SAPT") # Get the molecule of interest ref_wfn = kwargs.get('ref_wfn', None) if ref_wfn is None: sapt_dimer = kwargs.pop('molecule', core.get_active_molecule()) else: core.print_out( 'Warning! SAPT argument "ref_wfn" is only able to use molecule information.' ) sapt_dimer = ref_wfn.molecule() sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule( sapt_dimer, "dimer") # Print out the title and some information core.print_out("\n") core.print_out( " ---------------------------------------------------------\n") core.print_out(" " + "Spin-Flip SAPT Procedure".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith and Konrad Patkowski".center(58) + "\n") core.print_out( " ---------------------------------------------------------\n") core.print_out("\n") core.print_out(" ==> Algorithm <==\n\n") core.print_out(" JK Algorithm %12s\n" % core.get_option("SCF", "SCF_TYPE")) core.print_out("\n") core.print_out(" Required computations:\n") core.print_out(" HF (Monomer A)\n") core.print_out(" HF (Monomer B)\n") core.print_out("\n") if (core.get_option('SCF', 'REFERENCE') != 'ROHF'): raise ValidationError( 'Spin-Flip SAPT currently only supports restricted open-shell references.' ) # Run the two monomer computations core.IO.set_default_namespace('dimer') data = {} if (core.get_global_option('SCF_TYPE') == 'DF'): core.set_global_option('DF_INTS_IO', 'SAVE') # Compute dimer wavefunction wfn_A = scf_helper("SCF", molecule=monomerA, banner="SF-SAPT: HF Monomer A", **kwargs) core.set_global_option("SAVE_JK", True) wfn_B = scf_helper("SCF", molecule=monomerB, banner="SF-SAPT: HF Monomer B", **kwargs) sapt_jk = wfn_B.jk() core.set_global_option("SAVE_JK", False) core.print_out("\n") core.print_out( " ---------------------------------------------------------\n") core.print_out(" " + "Spin-Flip SAPT Exchange and Electrostatics".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith and Konrad Patkowski".center(58) + "\n") core.print_out( " ---------------------------------------------------------\n") core.print_out("\n") sf_data = sapt_sf_terms.compute_sapt_sf(sapt_dimer, sapt_jk, wfn_A, wfn_B) # Print the results core.print_out(" Spin-Flip SAPT Results\n") core.print_out(" " + "-" * 103 + "\n") for key, value in sf_data.items(): value = sf_data[key] print_vals = (key, value * 1000, value * constants.hartree2kcalmol, value * constants.hartree2kJmol) string = " %-26s % 15.8f [mEh] % 15.8f [kcal/mol] % 15.8f [kJ/mol]\n" % print_vals core.print_out(string) core.print_out(" " + "-" * 103 + "\n\n") dimer_wfn = core.Wavefunction.build(sapt_dimer, wfn_A.basisset()) # Set variables psivar_tanslator = { "Elst10": "SAPT ELST ENERGY", "Exch10(S^2) [diagonal]": "SAPT EXCH10(S^2),DIAGONAL ENERGY", "Exch10(S^2) [off-diagonal]": "SAPT EXCH10(S^2),OFF-DIAGONAL ENERGY", "Exch10(S^2) [highspin]": "SAPT EXCH10(S^2),HIGHSPIN ENERGY", } for k, v in sf_data.items(): psi_k = psivar_tanslator[k] dimer_wfn.set_variable(psi_k, v) core.set_variable(psi_k, v) # Copy over highspin core.set_variable("SAPT EXCH ENERGY", sf_data["Exch10(S^2) [highspin]"]) core.tstop() return dimer_wfn
def run_sf_sapt(name, **kwargs): optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE'], ['SCF', 'DFT_GRAC_SHIFT'], ['SCF', 'SAVE_JK']) core.tstart() # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): core.set_global_option('SCF_TYPE', 'DF') core.prepare_options_for_module("SAPT") # Get the molecule of interest ref_wfn = kwargs.get('ref_wfn', None) if ref_wfn is None: sapt_dimer = kwargs.pop('molecule', core.get_active_molecule()) else: core.print_out('Warning! SAPT argument "ref_wfn" is only able to use molecule information.') sapt_dimer = ref_wfn.molecule() sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule(sapt_dimer, "dimer") # Print out the title and some information core.print_out("\n") core.print_out(" ---------------------------------------------------------\n") core.print_out(" " + "Spin-Flip SAPT Procedure".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith and Konrad Patkowski".center(58) + "\n") core.print_out(" ---------------------------------------------------------\n") core.print_out("\n") core.print_out(" ==> Algorithm <==\n\n") core.print_out(" JK Algorithm %12s\n" % core.get_option("SCF", "SCF_TYPE")) core.print_out("\n") core.print_out(" Required computations:\n") core.print_out(" HF (Monomer A)\n") core.print_out(" HF (Monomer B)\n") core.print_out("\n") if (core.get_option('SCF', 'REFERENCE') != 'ROHF'): raise ValidationError('Spin-Flip SAPT currently only supports restricted open-shell references.') # Run the two monomer computations core.IO.set_default_namespace('dimer') data = {} if (core.get_global_option('SCF_TYPE') == 'DF'): core.set_global_option('DF_INTS_IO', 'SAVE') # Compute dimer wavefunction wfn_A = scf_helper("SCF", molecule=monomerA, banner="SF-SAPT: HF Monomer A", **kwargs) core.set_global_option("SAVE_JK", True) wfn_B = scf_helper("SCF", molecule=monomerB, banner="SF-SAPT: HF Monomer B", **kwargs) sapt_jk = wfn_B.jk() core.set_global_option("SAVE_JK", False) core.print_out("\n") core.print_out(" ---------------------------------------------------------\n") core.print_out(" " + "Spin-Flip SAPT Exchange and Electrostatics".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith and Konrad Patkowski".center(58) + "\n") core.print_out(" ---------------------------------------------------------\n") core.print_out("\n") sf_data = sapt_sf_terms.compute_sapt_sf(sapt_dimer, sapt_jk, wfn_A, wfn_B) # Print the results core.print_out(" Spin-Flip SAPT Results\n") core.print_out(" " + "-" * 103 + "\n") for key, value in sf_data.items(): value = sf_data[key] print_vals = (key, value * 1000, value * constants.hartree2kcalmol, value * constants.hartree2kJmol) string = " %-26s % 15.8f [mEh] % 15.8f [kcal/mol] % 15.8f [kJ/mol]\n" % print_vals core.print_out(string) core.print_out(" " + "-" * 103 + "\n\n") dimer_wfn = core.Wavefunction.build(sapt_dimer, wfn_A.basisset()) # Set variables psivar_tanslator = { "Elst10": "SAPT ELST ENERGY", "Exch10(S^2) [diagonal]": "SAPT EXCH10(S^2),DIAGONAL ENERGY", "Exch10(S^2) [off-diagonal]": "SAPT EXCH10(S^2),OFF-DIAGONAL ENERGY", "Exch10(S^2) [highspin]": "SAPT EXCH10(S^2),HIGHSPIN ENERGY", } for k, v in sf_data.items(): psi_k = psivar_tanslator[k] dimer_wfn.set_variable(psi_k, v) core.set_variable(psi_k, v) # Copy over highspin core.set_variable("SAPT EXCH ENERGY", sf_data["Exch10(S^2) [highspin]"]) core.tstop() return dimer_wfn
def _set_convergence_criterion(ptype, method_name, scf_Ec, pscf_Ec, scf_Dc, pscf_Dc, gen_Ec, verbose=1): r""" This function will set local SCF and global energy convergence criterion to the defaults listed at: http://www.psicode.org/psi4manual/master/scf.html#convergence-and- algorithm-defaults. SCF will be converged more tightly if a post-SCF method is select (pscf_Ec, and pscf_Dc) else the looser (scf_Ec, and scf_Dc convergence criterion will be used). ptype - Procedure type (energy, gradient, etc). Nearly always test on procedures['energy'] since that's guaranteed to exist for a method. method_name - Name of the method scf_Ec - E convergence criterion for scf target method pscf_Ec - E convergence criterion for scf of post-scf target method scf_Dc - D convergence criterion for scf target method pscf_Dc - D convergence criterion for scf of post-scf target method gen_Ec - E convergence criterion for post-scf target method """ optstash = p4util.OptionsState(['SCF', 'E_CONVERGENCE'], ['SCF', 'D_CONVERGENCE'], ['E_CONVERGENCE']) # Kind of want to move this out of here _method_exists(ptype, method_name) if verbose >= 2: print(' Setting convergence', end=' ') # Set method-dependent scf convergence criteria, check against energy routines if not core.has_option_changed('SCF', 'E_CONVERGENCE'): if procedures['energy'][method_name] == proc.run_scf: core.set_local_option('SCF', 'E_CONVERGENCE', scf_Ec) if verbose >= 2: print(scf_Ec, end=' ') else: core.set_local_option('SCF', 'E_CONVERGENCE', pscf_Ec) if verbose >= 2: print(pscf_Ec, end=' ') else: if verbose >= 2: print('CUSTOM', core.get_option('SCF', 'E_CONVERGENCE'), end=' ') if not core.has_option_changed('SCF', 'D_CONVERGENCE'): if procedures['energy'][method_name] == proc.run_scf: core.set_local_option('SCF', 'D_CONVERGENCE', scf_Dc) if verbose >= 2: print(scf_Dc, end=' ') else: core.set_local_option('SCF', 'D_CONVERGENCE', pscf_Dc) if verbose >= 2: print(pscf_Dc, end=' ') else: if verbose >= 2: print('CUSTOM', core.get_option('SCF', 'D_CONVERGENCE'), end=' ') # Set post-scf convergence criteria (global will cover all correlated modules) if not core.has_global_option_changed('E_CONVERGENCE'): if procedures['energy'][method_name] != proc.run_scf: core.set_global_option('E_CONVERGENCE', gen_Ec) if verbose >= 2: print(gen_Ec, end=' ') else: if procedures['energy'][method_name] != proc.run_scf: if verbose >= 2: print('CUSTOM', core.get_global_option('E_CONVERGENCE'), end=' ') if verbose >= 2: print('') return optstash
def _set_convergence_criterion(ptype, method_name, scf_Ec, pscf_Ec, scf_Dc, pscf_Dc, gen_Ec, verbose=1): r""" This function will set local SCF and global energy convergence criterion to the defaults listed at: http://www.psicode.org/psi4manual/master/scf.html#convergence-and- algorithm-defaults. SCF will be converged more tightly if a post-SCF method is select (pscf_Ec, and pscf_Dc) else the looser (scf_Ec, and scf_Dc convergence criterion will be used). ptype - Procedure type (energy, gradient, etc). Nearly always test on procedures['energy'] since that's guaranteed to exist for a method. method_name - Name of the method scf_Ec - E convergence criterion for scf target method pscf_Ec - E convergence criterion for scf of post-scf target method scf_Dc - D convergence criterion for scf target method pscf_Dc - D convergence criterion for scf of post-scf target method gen_Ec - E convergence criterion for post-scf target method """ optstash = p4util.OptionsState( ['SCF', 'E_CONVERGENCE'], ['SCF', 'D_CONVERGENCE'], ['E_CONVERGENCE']) # Kind of want to move this out of here _method_exists(ptype, method_name) if verbose >= 2: print(' Setting convergence', end=' ') # Set method-dependent scf convergence criteria, check against energy routines if not core.has_option_changed('SCF', 'E_CONVERGENCE'): if procedures['energy'][method_name] == proc.run_scf: core.set_local_option('SCF', 'E_CONVERGENCE', scf_Ec) if verbose >= 2: print(scf_Ec, end=' ') else: core.set_local_option('SCF', 'E_CONVERGENCE', pscf_Ec) if verbose >= 2: print(pscf_Ec, end=' ') else: if verbose >= 2: print('CUSTOM', core.get_option('SCF', 'E_CONVERGENCE'), end=' ') if not core.has_option_changed('SCF', 'D_CONVERGENCE'): if procedures['energy'][method_name] == proc.run_scf: core.set_local_option('SCF', 'D_CONVERGENCE', scf_Dc) if verbose >= 2: print(scf_Dc, end=' ') else: core.set_local_option('SCF', 'D_CONVERGENCE', pscf_Dc) if verbose >= 2: print(pscf_Dc, end=' ') else: if verbose >= 2: print('CUSTOM', core.get_option('SCF', 'D_CONVERGENCE'), end=' ') # Set post-scf convergence criteria (global will cover all correlated modules) if not core.has_global_option_changed('E_CONVERGENCE'): if procedures['energy'][method_name] != proc.run_scf: core.set_global_option('E_CONVERGENCE', gen_Ec) if verbose >= 2: print(gen_Ec, end=' ') else: if procedures['energy'][method_name] != proc.run_scf: if verbose >= 2: print('CUSTOM', core.get_global_option('E_CONVERGENCE'), end=' ') if verbose >= 2: print('') return optstash
def basis_helper(block, name='', key='BASIS', set_option=True): """For PsiAPI mode, forms a basis specification function from *block* and associates it with keyword *key* under handle *name*. Registers the basis spec with Psi4 so that it can be applied again to future molecules. For usage, see mints2, mints9, and cc54 test cases. Unless *set_option* is False, *name* will be set as current active *key*, equivalent to `set key name` or `set_option({key: name})`. """ key = key.upper() name = ('anonymous' + str(uuid.uuid4())[:8]) if name == '' else name cleanbas = basname(name).replace( '-', '') # further remove hyphens so can be function name block = qcel.util.filter_comments(block) command_lines = re.split('\n', block) symbol_re = re.compile( r'^\s*assign\s+(?P<symbol>[A-Z]{1,3})\s+(?P<basis>[-+*\(\)\w]+)\s*$', re.IGNORECASE) label_re = re.compile( r'^\s*assign\s+(?P<label>(?P<symbol>[A-Z]{1,3})(?:(_\w+)|(\d+))?)\s+(?P<basis>[-+*\(\)\w]+)\s*$', re.IGNORECASE) all_re = re.compile(r'^\s*assign\s+(?P<basis>[-+*\(\)\w]+)\s*$', re.IGNORECASE) basislabel = re.compile(r'\s*\[\s*([-*\(\)\w]+)\s*\]\s*') def anon(mol, role): basstrings = {} # Start by looking for assign lines, and remove them leftover_lines = [] assignments = False for line in command_lines: if symbol_re.match(line): m = symbol_re.match(line) mol.set_basis_by_symbol(m.group('symbol'), m.group('basis'), role=role) assignments = True elif label_re.match(line): m = label_re.match(line) mol.set_basis_by_label(m.group('label'), m.group('basis'), role=role) assignments = True elif all_re.match(line): m = all_re.match(line) mol.set_basis_all_atoms(m.group('basis'), role=role) assignments = True else: # Ignore blank lines and accumulate remainder if line and not line.isspace(): leftover_lines.append(line.strip()) # Now look for regular basis set definitions basblock = list( filter(None, basislabel.split('\n'.join(leftover_lines)))) if len(basblock) == 1: if not assignments: # case with no [basname] markers where whole block is contents of gbs file mol.set_basis_all_atoms(name, role=role) basstrings[basname(name)] = basblock[0] else: message = ( "Conflicting basis set specification: assign lines present but shells have no [basname] label." "") raise TestComparisonError(message) else: # case with specs separated by [basname] markers for idx in range(0, len(basblock), 2): basstrings[basname(basblock[idx])] = basblock[idx + 1] return basstrings anon.__name__ = 'basisspec_psi4_yo__' + cleanbas qcdb.libmintsbasisset.basishorde[name.upper()] = anon if set_option: core.set_global_option(key, name)
def run_json(json_data): """ Runs and updates the input JSON data. Parameters ---------- json_data : JSON input Required input fields: - molecule : str A string representation of the molecule. Any valid psi4 synatx is valid. - driver : str The driver method to use valid arguments are "energy", "gradient", "property" - args : str Input arguments to the driver function - kwargs : dict Input dictionary to the driver function Optional input fields: - kwargs : dict Additional kwargs to be passed to the driver. - options : dict Global options to set in the Psi4 run. - scratch_location : str Overide the default scratch location. - return_output : bool Return the full string reprsentation of the output or not. Output fields: - return_value : float, psi4.core.Vector, psi4.core.Matrix The return value of the input function. - variables : dict The list of Psi4 variables generated from the run. - success : bool Indicates if the run was successful or not. - error : str If an error is raised the result is returned here. - raw_output : str The full Psi4 output if requested. Notes ----- !Warning! This function is experimental and likely to change in the future. Please report any suggestions or uses of this function on github.com/psi4/psi4. Examples -------- # CP corrected Helium dimer energy in the STO-3G basis. >>> json_data = {} >>> json_data["molecule"] = "He 0 0 0\n--\nHe 0 0 1" >>> json_data["driver"] = "energy" >>> json_data["method"] = 'SCF' >>> json_data["kwargs"] = {"bsse_type": "cp"} >>> json_data["options"] = {"BASIS": "STO-3G"} >>> run_json(json_data) { "raw_output": "Output storing was not requested.", "options": { "BASIS": "STO-3G" }, "driver": "energy", "molecule": "He 0 0 0\n--\nHe 0 0 1", "method": "SCF", "variables": { "SCF N ITERS": 2.0, "SCF DIPOLE Y": 0.0, "CURRENT DIPOLE Y": 0.0, "CP-CORRECTED 2-BODY INTERACTION ENERGY": 0.1839360538612116, "HF TOTAL ENERGY": -5.433191881443323, "SCF TOTAL ENERGY": -5.433191881443323, "TWO-ELECTRON ENERGY": 4.124089347186247, "SCF ITERATION ENERGY": -5.433191881443323, "CURRENT DIPOLE X": 0.0, "CURRENT DIPOLE Z": 0.0, "CURRENT REFERENCE ENERGY": -5.433191881443323, "CURRENT ENERGY": 0.1839360538612116, "COUNTERPOISE CORRECTED TOTAL ENERGY": -5.433191881443323, "SCF DIPOLE Z": 0.0, "COUNTERPOISE CORRECTED INTERACTION ENERGY": 0.1839360538612116, "NUCLEAR REPULSION ENERGY": 2.11670883436, "SCF DIPOLE X": 0.0, "ONE-ELECTRON ENERGY": -11.67399006298957 }, "return_value": 0.1839360538612116, "error": "", "success": true, "provenance": { "creator": "Psi4", "routine": "psi4.run_json", "version": "1.1a1" }, "kwargs": { "bsse_type": "cp" } } """ # Set a few variables json_data["error"] = "" json_data["raw_output"] = "Output storing was not requested." json_data["success"] = False json_data["raw_output"] = None # Check input for check in ["driver", "method", "molecule"]: if check not in list(json_data): json_data["error"] = "Minimum input requires the %s field." % check return json_data # Check driver call if json_data["driver"] not in list(methods_dict): json_data["error"] = "Driver parameters '%s' not recognized" % str(json_data["driver"]) return json_data # Set scratch if "scratch_location" in list(json_data): psi4_io = core.IOManager.shared_object() psi4_io.set_default_path(json_data["scratch_location"]) # Set memory if "memory" in list(json_data): psi4.core.set_memory(int(json_data["memory"])) # Do we return the output? return_output = json_data.pop("return_output", False) if return_output: outfile = str(uuid.uuid4()) + ".json_out" core.set_output_file(outfile, False) json_data["raw_output"] = "Not yet run." try: # Set options if "options" in json_data.keys() and (json_data["options"] is not None): for k, v in json_data["options"].items(): core.set_global_option(k, v) # Rework args args = json_data["method"] if not isinstance(args, (list, tuple)): args = [args] # Deep copy kwargs if "kwargs" in list(json_data): kwargs = copy.deepcopy(json_data["kwargs"]) else: kwargs = {} kwargs["molecule"] = molutil.geometry(json_data["molecule"]) # Full driver call kwargs["return_wfn"] = True val, wfn = methods_dict[json_data["driver"]](*args, **kwargs) if isinstance(val, (float)): json_data["return_value"] = val elif isinstance(val, (core.Matrix, core.Vector)): json_data["return_value"] = val.to_serial() else: json_data["error"] += "Unrecognized return value of type %s\n" % type(val) json_data["return_value"] = val json_data["variables"] = core.get_variables() json_data["success"] = True prov = {} prov["version"] = psi4.__version__ prov["routine"] = "psi4.run_json" prov["creator"] = "Psi4" json_data["provenance"] = prov except Exception as error: json_data["error"] += repr(error) json_data["success"] = False if return_output: with open(outfile, 'r') as f: json_data["raw_output"] = f.read() os.unlink(outfile) return json_data
def run_json_qc_schema(json_data, clean): """ An implementation of the QC JSON Schema (molssi-qc-schema.readthedocs.io/en/latest/index.html#) implementation in Psi4. Parameters ---------- json_data : JSON Please see molssi-qc-schema.readthedocs.io/en/latest/spec_components.html for further details. Notes ----- !Warning! This function is experimental and likely to change in the future. Please report any suggestions or uses of this function on github.com/MolSSI/QC_JSON_Schema. Examples -------- """ # Clean a few things _clean_psi_environ(clean) # This is currently a forced override if json_data["schema_name"] in ["qc_schema_input", "qcschema_input"]: json_data["schema_name"] = "qc_schema_input" # humor qcel 0.1.3 else: raise KeyError("Schema name of '{}' not understood".format(json_data["schema_name"])) if json_data["schema_version"] != 1: raise KeyError("Schema version of '{}' not understood".format(json_data["schema_version"])) if json_data.get("nthreads", False) is not False: psi4.set_num_threads(json_data["nthreads"], quiet=True) json_data["provenance"] = {"creator": "Psi4", "version": psi4.__version__, "routine": "psi4.json.run_json"} # Build molecule mol = core.Molecule.from_schema(json_data) # Update molecule geometry as we orient and fix_com json_data["molecule"]["geometry"] = mol.geometry().np.ravel().tolist() # Set options for k, v in json_data["keywords"].items(): core.set_global_option(k, v) # Setup the computation method = json_data["model"]["method"] core.set_global_option("BASIS", json_data["model"]["basis"]) kwargs = {"return_wfn": True, "molecule": mol} # Handle special properties case if json_data["driver"] == "properties": if "properties" in json_data["model"]: kwargs["properties"] = [x.lower() for x in json_data["model"]["properties"]] extra = set(kwargs["properties"]) - can_do_properties_ if len(extra): raise KeyError("Did not understand property key %s." % kwargs["properties"]) else: kwargs["properties"] = list(can_do_properties_) # Actual driver run val, wfn = methods_dict_[json_data["driver"]](method, **kwargs) # Pull out a standard set of Psi variables psi_props = psi4.core.scalar_variables() json_data["psi4:qcvars"] = psi_props # Still a bit of a mess at the moment add in local vars as well. for k, v in wfn.variables().items(): if k not in json_data["psi4:qcvars"]: json_data["psi4:qcvars"][k] = _json_translation(v) # Handle the return result if json_data["driver"] == "energy": json_data["return_result"] = val elif json_data["driver"] in ["gradient", "hessian"]: json_data["return_result"] = val.np.ravel().tolist() elif json_data["driver"] == "properties": ret = {} mtd = json_data["model"]["method"].upper() # Dipole/quadrupole still special case if "dipole" in kwargs["properties"]: ret["dipole"] = [psi_props[mtd + " DIPOLE " + x] for x in ["X", "Y", "Z"]] if "quadrupole" in kwargs["properties"]: ret["quadrupole"] = [psi_props[mtd + " QUADRUPOLE " + x] for x in ["XX", "XY", "XZ", "YY", "YZ", "ZZ"]] ret.update(_convert_variables(wfn.variables(), context="properties")) json_data["return_result"] = ret else: raise KeyError("Did not understand Driver key %s." % json_data["driver"]) props = { "calcinfo_nbasis": wfn.nso(), "calcinfo_nmo": wfn.nmo(), "calcinfo_nalpha": wfn.nalpha(), "calcinfo_nbeta": wfn.nbeta(), "calcinfo_natom": mol.geometry().shape[0], } props.update(_convert_variables(psi_props, context="generics")) props.update(_convert_variables(psi_props, context="scf")) # Write out MP2 keywords if "MP2 CORRELATION ENERGY" in psi_props: props.update(_convert_variables(psi_props, context="mp2")) json_data["properties"] = props json_data["success"] = True # Reset state _clean_psi_environ(clean) json_data["schema_name"] = "qcschema_output" return json_data
def ip_fitting(name, omega_l=0.05, omega_r=2.5, omega_convergence=1.0e-3, maxiter=20, **kwargs): """Optimize DFT omega parameter for molecular system. Parameters ---------- name : string or function DFT functional string name or function defining functional whose omega is to be optimized. omega_l : float, optional Minimum omega to be considered during fitting. omega_r : float, optional Maximum omega to be considered during fitting. molecule : :ref:`molecule <op_py_molecule>`, optional Target molecule (neutral) for which omega is to be tuned, if not last defined. omega_convergence : float, optional Threshold below which to consider omega converged. (formerly omega_tolerance) maxiter : int, optional Maximum number of iterations towards omega convergence. Returns ------- float Optimal omega parameter. """ optstash = p4util.OptionsState( ['SCF', 'REFERENCE'], ['SCF', 'GUESS'], ['SCF', 'DF_INTS_IO'], ['SCF', 'DFT_OMEGA'], ['DOCC'], ['SOCC']) kwargs = p4util.kwargs_lower(kwargs) # By default, do not read previous 180 orbitals file read = False read180 = '' if 'read' in kwargs: read = True read180 = kwargs['read'] if core.get_option('SCF', 'REFERENCE') != 'UKS': core.print_out(""" Requested procedure `ip_fitting` runs further calculations with UKS reference.\n""") core.set_local_option('SCF', 'REFERENCE', 'UKS') # Make sure the molecule the user provided is the active one, and neutral molecule = kwargs.pop('molecule', core.get_active_molecule()) molecule.update_geometry() if molecule.molecular_charge() != 0: raise ValidationError("""IP Fitting requires neutral molecule to start.""") if molecule.schoenflies_symbol() != 'c1': core.print_out(""" Requested procedure `ip_fitting` does not make use of molecular symmetry: """ """further calculations in C1 point group.\n""") molecule = molecule.clone() molecule.reset_point_group('c1') molecule.update_geometry() charge0 = molecule.molecular_charge() mult0 = molecule.multiplicity() # How many electrons are there? N = 0 for A in range(molecule.natom()): N += molecule.Z(A) N -= charge0 N = int(N) Nb = int((N - mult0 + 1) / 2) Na = int(N - Nb) # Work in the ot namespace for this procedure core.IO.set_default_namespace("ot") # Burn in to determine orbital eigenvalues if read: core.set_local_option("SCF", "GUESS", "READ") copy_file_to_scratch(read180, 'psi', 'ot', 180) core.set_local_option("SCF", "DF_INTS_IO", "SAVE") E, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Burn-in', **kwargs) core.set_local_option("SCF", "DF_INTS_IO", "LOAD") if not wfn.functional().is_x_lrc(): raise ValidationError("""Not sensible to optimize omega for non-long-range-correction functional.""") # Determine H**O, to determine mult1 eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Na == Nb: H**O = -Nb elif Nb == 0: H**O = Na else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] if E_a >= E_b: H**O = Na else: H**O = -Nb Na1 = Na Nb1 = Nb if H**O > 0: Na1 -= 1 else: Nb1 -= 1 charge1 = charge0 + 1 mult1 = Na1 - Nb1 + 1 omegas = [] E0s = [] E1s = [] kIPs = [] IPs = [] types = [] # Right endpoint core.set_local_option('SCF', 'DFT_OMEGA', omega_r) # Neutral if read: core.set_local_option("SCF", "GUESS", "READ") p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180) molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) E0r, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Right Endpoint', **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) E_HOMOr = E_HOMO core.IO.change_file_namespace(180, "ot", "neutral") # Cation if read: core.set_local_option("SCF", "GUESS", "READ") p4util.copy_file_to_scratch(read180, 'psi', 'ot', 180) molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) E1r = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Right Endpoint', **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IPr = E1r - E0r kIPr = -E_HOMOr delta_r = IPr - kIPr if IPr > kIPr: raise ValidationError("""\n***IP Fitting Error: Right Omega limit should have kIP > IP: {} !> {}""".format(kIPr, IPr)) omegas.append(omega_r) types.append('Right Limit') E0s.append(E0r) E1s.append(E1r) IPs.append(IPr) kIPs.append(kIPr) # Use previous orbitals from here out core.set_local_option("SCF", "GUESS", "READ") # Left endpoint core.set_local_option('SCF', 'DFT_OMEGA', omega_l) # Neutral core.IO.change_file_namespace(180, "neutral", "ot") molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) core.set_global_option("DOCC", [Nb]) core.set_global_option("SOCC", [Na - Nb]) E0l, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Left Endpoint', **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) E_HOMOl = E_HOMO core.IO.change_file_namespace(180, "ot", "neutral") # Cation core.IO.change_file_namespace(180, "cation", "ot") molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) core.set_global_option("DOCC", [Nb1]) core.set_global_option("SOCC", [Na1 - Nb1]) E1l = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Left Endpoint', **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IPl = E1l - E0l kIPl = -E_HOMOl delta_l = IPl - kIPl if IPl < kIPl: raise ValidationError("""\n***IP Fitting Error: Left Omega limit should have kIP < IP: {} !< {}""".format(kIPl, IPl)) omegas.append(omega_l) types.append('Left Limit') E0s.append(E0l) E1s.append(E1l) IPs.append(IPl) kIPs.append(kIPl) converged = False repeat_l = 0 repeat_r = 0 for step in range(maxiter): # Regula Falsi (modified) if repeat_l > 1: delta_l /= 2.0 if repeat_r > 1: delta_r /= 2.0 omega = - (omega_r - omega_l) / (delta_r - delta_l) * delta_l + omega_l core.set_local_option('SCF', 'DFT_OMEGA', omega) # Neutral core.IO.change_file_namespace(180, "neutral", "ot") molecule.set_molecular_charge(charge0) molecule.set_multiplicity(mult0) core.set_global_option("DOCC", [Nb]) core.set_global_option("SOCC", [Na - Nb]) E0, wfn = driver.energy('scf', dft_functional=name, return_wfn=True, molecule=molecule, banner='IP Fitting SCF: Neutral, Omega = {:11.3E}'.format(omega), **kwargs) eps_a = wfn.epsilon_a() eps_b = wfn.epsilon_b() if Nb == 0: E_HOMO = eps_a.np[int(Na - 1)] else: E_a = eps_a.np[int(Na - 1)] E_b = eps_b.np[int(Nb - 1)] E_HOMO = max(E_a, E_b) core.IO.change_file_namespace(180, "ot", "neutral") # Cation core.IO.change_file_namespace(180, "cation", "ot") molecule.set_molecular_charge(charge1) molecule.set_multiplicity(mult1) core.set_global_option("DOCC", [Nb1]) core.set_global_option("SOCC", [Na1 - Nb1]) E1 = driver.energy('scf', dft_functional=name, molecule=molecule, banner='IP Fitting SCF: Cation, Omega = {:11.3E}'.format(omega), **kwargs) core.IO.change_file_namespace(180, "ot", "cation") IP = E1 - E0 kIP = -E_HOMO delta = IP - kIP if kIP > IP: omega_r = omega E0r = E0 E1r = E1 IPr = IP kIPr = kIP delta_r = delta repeat_r = 0 repeat_l += 1 else: omega_l = omega E0l = E0 E1l = E1 IPl = IP kIPl = kIP delta_l = delta repeat_l = 0 repeat_r += 1 omegas.append(omega) types.append('Regula-Falsi') E0s.append(E0) E1s.append(E1) IPs.append(IP) kIPs.append(kIP) # Termination if abs(omega_l - omega_r) < omega_convergence: converged = True break core.IO.set_default_namespace("") core.print_out("""\n ==> IP Fitting Results <==\n\n""") core.print_out(""" => Occupation Determination <= \n\n""") core.print_out(""" %6s %6s %6s %6s %6s %6s\n""" % ('N', 'Na', 'Nb', 'Charge', 'Mult', 'H**O')) core.print_out(""" Neutral: %6d %6d %6d %6d %6d %6d\n""" % (N, Na, Nb, charge0, mult0, H**O)) core.print_out(""" Cation: %6d %6d %6d %6d %6d\n\n""" % (N - 1, Na1, Nb1, charge1, mult1)) core.print_out(""" => Regula Falsi Iterations <=\n\n""") core.print_out(""" %3s %11s %14s %14s %14s %s\n""" % ('N','Omega','IP','kIP','Delta','Type')) for k in range(len(omegas)): core.print_out(""" %3d %11.3E %14.6E %14.6E %14.6E %s\n""" % (k + 1, omegas[k], IPs[k], kIPs[k], IPs[k] - kIPs[k], types[k])) optstash.restore() if converged: core.print_out("""\n IP Fitting Converged\n""") core.print_out(""" Final omega = %14.6E\n""" % ((omega_l + omega_r) / 2)) core.print_out("""\n "M,I. does the dying. Fleet just does the flying."\n""") core.print_out(""" -Starship Troopers\n""") else: raise ConvergenceError("""IP Fitting """, step + 1) return ((omega_l + omega_r) / 2)
def run_sapt_dft(name, **kwargs): optstash = p4util.OptionsState(['SCF', 'SCF_TYPE'], ['SCF', 'REFERENCE'], ['SCF', 'DFT_FUNCTIONAL'], ['SCF', 'DFT_GRAC_SHIFT'], ['SCF', 'SAVE_JK']) core.tstart() # Alter default algorithm if not core.has_option_changed('SCF', 'SCF_TYPE'): core.set_local_option('SCF', 'SCF_TYPE', 'DF') core.prepare_options_for_module("SAPT") # Get the molecule of interest ref_wfn = kwargs.get('ref_wfn', None) if ref_wfn is None: sapt_dimer = kwargs.pop('molecule', core.get_active_molecule()) else: core.print_out('Warning! SAPT argument "ref_wfn" is only able to use molecule information.') sapt_dimer = ref_wfn.molecule() sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule(sapt_dimer, "dimer") # Grab overall settings mon_a_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_A") mon_b_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_B") do_delta_hf = core.get_option("SAPT", "SAPT_DFT_DO_DHF") sapt_dft_functional = core.get_option("SAPT", "SAPT_DFT_FUNCTIONAL") # Print out the title and some information core.print_out("\n") core.print_out(" ---------------------------------------------------------\n") core.print_out(" " + "SAPT(DFT) Procedure".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith".center(58) + "\n") core.print_out(" ---------------------------------------------------------\n") core.print_out("\n") core.print_out(" ==> Algorithm <==\n\n") core.print_out(" SAPT DFT Functional %12s\n" % str(sapt_dft_functional)) core.print_out(" Monomer A GRAC Shift %12.6f\n" % mon_a_shift) core.print_out(" Monomer B GRAC Shift %12.6f\n" % mon_b_shift) core.print_out(" Delta HF %12s\n" % ("True" if do_delta_hf else "False")) core.print_out(" JK Algorithm %12s\n" % core.get_option("SCF", "SCF_TYPE")) core.print_out("\n") core.print_out(" Required computations:\n") if (do_delta_hf): core.print_out(" HF (Dimer)\n") core.print_out(" HF (Monomer A)\n") core.print_out(" HF (Monomer B)\n") core.print_out(" DFT (Monomer A)\n") core.print_out(" DFT (Monomer B)\n") core.print_out("\n") if (sapt_dft_functional != "HF") and ((mon_a_shift == 0.0) or (mon_b_shift == 0.0)): raise ValidationError('SAPT(DFT): must set both "SAPT_DFT_GRAC_SHIFT_A" and "B".') if (core.get_option('SCF', 'REFERENCE') != 'RHF'): raise ValidationError('SAPT(DFT) currently only supports restricted references.') core.IO.set_default_namespace('dimer') data = {} core.set_global_option("SAVE_JK", True) if (core.get_option('SCF', 'SCF_TYPE') == 'DF'): # core.set_global_option('DF_INTS_IO', 'LOAD') core.set_global_option('DF_INTS_IO', 'SAVE') # # Compute dimer wavefunction hf_cache = {} hf_wfn_dimer = None if do_delta_hf: if (core.get_option('SCF', 'SCF_TYPE') == 'DF'): core.set_global_option('DF_INTS_IO', 'SAVE') hf_data = {} hf_wfn_dimer = scf_helper( "SCF", molecule=sapt_dimer, banner="SAPT(DFT): delta HF Dimer", **kwargs) hf_data["HF DIMER"] = core.get_variable("CURRENT ENERGY") if (core.get_option('SCF', 'SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'dimer', 'monomerA') hf_wfn_A = scf_helper( "SCF", molecule=monomerA, banner="SAPT(DFT): delta HF Monomer A", **kwargs) hf_data["HF MONOMER A"] = core.get_variable("CURRENT ENERGY") if (core.get_option('SCF', 'SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerA', 'monomerB') hf_wfn_B = scf_helper( "SCF", molecule=monomerB, banner="SAPT(DFT): delta HF Monomer B", **kwargs) hf_data["HF MONOMER B"] = core.get_variable("CURRENT ENERGY") # Move it back to monomer A if (core.get_option('SCF', 'SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerB', 'dimer') core.print_out("\n") core.print_out(" ---------------------------------------------------------\n") core.print_out(" " + "SAPT(DFT): delta HF Segement".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith and Rob Parrish".center(58) + "\n") core.print_out(" ---------------------------------------------------------\n") core.print_out("\n") # Build cache and JK sapt_jk = hf_wfn_B.jk() hf_cache = sapt_jk_terms.build_sapt_jk_cache(hf_wfn_A, hf_wfn_B, sapt_jk, True) # Electostatics elst = sapt_jk_terms.electrostatics(hf_cache, True) hf_data.update(elst) # Exchange exch = sapt_jk_terms.exchange(hf_cache, sapt_jk, True) hf_data.update(exch) # Induction ind = sapt_jk_terms.induction( hf_cache, sapt_jk, True, maxiter=core.get_option("SAPT", "MAXITER"), conv=core.get_option("SAPT", "D_CONVERGENCE")) hf_data.update(ind) dhf_value = hf_data["HF DIMER"] - hf_data["HF MONOMER A"] - hf_data["HF MONOMER B"] core.print_out("\n") core.print_out(print_sapt_hf_summary(hf_data, "SAPT(HF)", delta_hf=dhf_value)) data["Delta HF Correction"] = core.get_variable("SAPT(DFT) Delta HF") if hf_wfn_dimer is None: dimer_wfn = core.Wavefunction.build(sapt_dimer, core.get_global_option("BASIS")) else: dimer_wfn = hf_wfn_dimer # Set the primary functional core.set_global_option("DFT_FUNCTIONAL", core.get_option("SAPT", "SAPT_DFT_FUNCTIONAL")) core.set_local_option('SCF', 'REFERENCE', 'RKS') # Compute Monomer A wavefunction if (core.get_option('SCF', 'SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'dimer', 'monomerA') if mon_a_shift: core.set_global_option("DFT_GRAC_SHIFT", mon_a_shift) # Save the JK object core.IO.set_default_namespace('monomerA') wfn_A = scf_helper("SCF", molecule=monomerA, banner="SAPT(DFT): DFT Monomer A", **kwargs) data["DFT MONOMERA"] = core.get_variable("CURRENT ENERGY") core.set_global_option("DFT_GRAC_SHIFT", 0.0) # Compute Monomer B wavefunction if (core.get_option('SCF', 'SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerA', 'monomerB') if mon_b_shift: core.set_global_option("DFT_GRAC_SHIFT", mon_b_shift) core.IO.set_default_namespace('monomerB') wfn_B = scf_helper("SCF", molecule=monomerB, banner="SAPT(DFT): DFT Monomer B", **kwargs) data["DFT MONOMERB"] = core.get_variable("CURRENT ENERGY") core.set_global_option("DFT_GRAC_SHIFT", 0.0) # Print out the title and some information core.print_out("\n") core.print_out(" ---------------------------------------------------------\n") core.print_out(" " + "SAPT(DFT): Intermolecular Interaction Segment".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith and Rob Parrish".center(58) + "\n") core.print_out(" ---------------------------------------------------------\n") core.print_out("\n") core.print_out(" ==> Algorithm <==\n\n") core.print_out(" SAPT DFT Functional %12s\n" % str(sapt_dft_functional)) core.print_out(" Monomer A GRAC Shift %12.6f\n" % mon_a_shift) core.print_out(" Monomer B GRAC Shift %12.6f\n" % mon_b_shift) core.print_out(" Delta HF %12s\n" % ("True" if do_delta_hf else "False")) core.print_out(" JK Algorithm %12s\n" % core.get_option("SCF", "SCF_TYPE")) # Build cache and JK sapt_jk = wfn_B.jk() cache = sapt_jk_terms.build_sapt_jk_cache(wfn_A, wfn_B, sapt_jk, True) # Electostatics elst = sapt_jk_terms.electrostatics(cache, True) data.update(elst) # Exchange exch = sapt_jk_terms.exchange(cache, sapt_jk, True) data.update(exch) # Induction ind = sapt_jk_terms.induction( cache, sapt_jk, True, maxiter=core.get_option("SAPT", "MAXITER"), conv=core.get_option("SAPT", "D_CONVERGENCE")) data.update(ind) # Dispersion primary_basis = wfn_A.basisset() core.print_out("\n") aux_basis = core.BasisSet.build(sapt_dimer, "DF_BASIS_MP2", core.get_option("DFMP2", "DF_BASIS_MP2"), "RIFIT", core.get_global_option('BASIS')) fdds_disp = sapt_mp2_terms.df_fdds_dispersion(primary_basis, aux_basis, cache) data.update(fdds_disp) if core.get_option("SAPT", "SAPT_DFT_MP2_DISP_ALG") == "FISAPT": mp2_disp = sapt_mp2_terms.df_mp2_fisapt_dispersion(wfn_A, primary_basis, aux_basis, cache, do_print=True) else: mp2_disp = sapt_mp2_terms.df_mp2_sapt_dispersion( dimer_wfn, wfn_A, wfn_B, primary_basis, aux_basis, cache, do_print=True) data.update(mp2_disp) # Print out final data core.print_out("\n") core.print_out(print_sapt_dft_summary(data, "SAPT(DFT)")) # Copy data back into globals for k, v in data.items(): core.set_variable(k, v) core.tstop() return dimer_wfn
def run_sapt_dft(name, **kwargs): optstash = p4util.OptionsState(['SCF_TYPE'], ['SCF', 'REFERENCE'], ['SCF', 'DFT_GRAC_SHIFT'], ['SCF', 'SAVE_JK']) core.tstart() # Alter default algorithm if not core.has_global_option_changed('SCF_TYPE'): core.set_global_option('SCF_TYPE', 'DF') core.prepare_options_for_module("SAPT") # Get the molecule of interest ref_wfn = kwargs.get('ref_wfn', None) if ref_wfn is None: sapt_dimer = kwargs.pop('molecule', core.get_active_molecule()) else: core.print_out('Warning! SAPT argument "ref_wfn" is only able to use molecule information.') sapt_dimer = ref_wfn.molecule() sapt_dimer, monomerA, monomerB = proc_util.prepare_sapt_molecule(sapt_dimer, "dimer") # Grab overall settings mon_a_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_A") mon_b_shift = core.get_option("SAPT", "SAPT_DFT_GRAC_SHIFT_B") do_delta_hf = core.get_option("SAPT", "SAPT_DFT_DO_DHF") sapt_dft_functional = core.get_option("SAPT", "SAPT_DFT_FUNCTIONAL") # Print out the title and some information core.print_out("\n") core.print_out(" ---------------------------------------------------------\n") core.print_out(" " + "SAPT(DFT) Procedure".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith".center(58) + "\n") core.print_out(" ---------------------------------------------------------\n") core.print_out("\n") core.print_out(" !!! WARNING: SAPT(DFT) capability is in beta. Please use with caution. !!!\n\n") core.print_out(" ==> Algorithm <==\n\n") core.print_out(" SAPT DFT Functional %12s\n" % str(sapt_dft_functional)) core.print_out(" Monomer A GRAC Shift %12.6f\n" % mon_a_shift) core.print_out(" Monomer B GRAC Shift %12.6f\n" % mon_b_shift) core.print_out(" Delta HF %12s\n" % ("True" if do_delta_hf else "False")) core.print_out(" JK Algorithm %12s\n" % core.get_global_option("SCF_TYPE")) core.print_out("\n") core.print_out(" Required computations:\n") if (do_delta_hf): core.print_out(" HF (Dimer)\n") core.print_out(" HF (Monomer A)\n") core.print_out(" HF (Monomer B)\n") core.print_out(" DFT (Monomer A)\n") core.print_out(" DFT (Monomer B)\n") core.print_out("\n") if (sapt_dft_functional != "HF") and ((mon_a_shift == 0.0) or (mon_b_shift == 0.0)): raise ValidationError('SAPT(DFT): must set both "SAPT_DFT_GRAC_SHIFT_A" and "B".') if (core.get_option('SCF', 'REFERENCE') != 'RHF'): raise ValidationError('SAPT(DFT) currently only supports restricted references.') core.IO.set_default_namespace('dimer') data = {} if (core.get_global_option('SCF_TYPE') == 'DF'): # core.set_global_option('DF_INTS_IO', 'LOAD') core.set_global_option('DF_INTS_IO', 'SAVE') # # Compute dimer wavefunction hf_wfn_dimer = None if do_delta_hf: if (core.get_global_option('SCF_TYPE') == 'DF'): core.set_global_option('DF_INTS_IO', 'SAVE') hf_data = {} hf_wfn_dimer = scf_helper("SCF", molecule=sapt_dimer, banner="SAPT(DFT): delta HF Dimer", **kwargs) hf_data["HF DIMER"] = core.get_variable("CURRENT ENERGY") if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'dimer', 'monomerA') hf_wfn_A = scf_helper("SCF", molecule=monomerA, banner="SAPT(DFT): delta HF Monomer A", **kwargs) hf_data["HF MONOMER A"] = core.get_variable("CURRENT ENERGY") core.set_global_option("SAVE_JK", True) if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerA', 'monomerB') hf_wfn_B = scf_helper("SCF", molecule=monomerB, banner="SAPT(DFT): delta HF Monomer B", **kwargs) hf_data["HF MONOMER B"] = core.get_variable("CURRENT ENERGY") core.set_global_option("SAVE_JK", False) # Grab JK object and set to A (so we do not save many JK objects) sapt_jk = hf_wfn_B.jk() hf_wfn_A.set_jk(sapt_jk) core.set_global_option("SAVE_JK", False) # Move it back to monomer A if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerB', 'dimer') core.print_out("\n") core.print_out(" ---------------------------------------------------------\n") core.print_out(" " + "SAPT(DFT): delta HF Segement".center(58) + "\n") core.print_out("\n") core.print_out(" " + "by Daniel G. A. Smith and Rob Parrish".center(58) + "\n") core.print_out(" ---------------------------------------------------------\n") core.print_out("\n") # Build cache hf_cache = sapt_jk_terms.build_sapt_jk_cache(hf_wfn_A, hf_wfn_B, sapt_jk, True) # Electostatics elst = sapt_jk_terms.electrostatics(hf_cache, True) hf_data.update(elst) # Exchange exch = sapt_jk_terms.exchange(hf_cache, sapt_jk, True) hf_data.update(exch) # Induction ind = sapt_jk_terms.induction( hf_cache, sapt_jk, True, maxiter=core.get_option("SAPT", "MAXITER"), conv=core.get_option("SAPT", "D_CONVERGENCE"), Sinf=core.get_option("SAPT", "DO_IND_EXCH_SINF")) hf_data.update(ind) dhf_value = hf_data["HF DIMER"] - hf_data["HF MONOMER A"] - hf_data["HF MONOMER B"] core.print_out("\n") core.print_out(print_sapt_hf_summary(hf_data, "SAPT(HF)", delta_hf=dhf_value)) data["Delta HF Correction"] = core.get_variable("SAPT(DFT) Delta HF") sapt_jk.finalize() del hf_wfn_A, hf_wfn_B, sapt_jk if hf_wfn_dimer is None: dimer_wfn = core.Wavefunction.build(sapt_dimer, core.get_global_option("BASIS")) else: dimer_wfn = hf_wfn_dimer # Set the primary functional core.set_local_option('SCF', 'REFERENCE', 'RKS') # Compute Monomer A wavefunction if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'dimer', 'monomerA') if mon_a_shift: core.set_global_option("DFT_GRAC_SHIFT", mon_a_shift) # Save the JK object core.IO.set_default_namespace('monomerA') wfn_A = scf_helper( sapt_dft_functional, post_scf=False, molecule=monomerA, banner="SAPT(DFT): DFT Monomer A", **kwargs) data["DFT MONOMERA"] = core.get_variable("CURRENT ENERGY") core.set_global_option("DFT_GRAC_SHIFT", 0.0) # Compute Monomer B wavefunction if (core.get_global_option('SCF_TYPE') == 'DF'): core.IO.change_file_namespace(97, 'monomerA', 'monomerB') if mon_b_shift: core.set_global_option("DFT_GRAC_SHIFT", mon_b_shift) core.set_global_option("SAVE_JK", True) core.IO.set_default_namespace('monomerB') wfn_B = scf_helper( sapt_dft_functional, post_scf=False, molecule=monomerB, banner="SAPT(DFT): DFT Monomer B", **kwargs) data["DFT MONOMERB"] = core.get_variable("CURRENT ENERGY") # Save JK object sapt_jk = wfn_B.jk() wfn_A.set_jk(sapt_jk) core.set_global_option("SAVE_JK", False) core.set_global_option("DFT_GRAC_SHIFT", 0.0) # Write out header scf_alg = core.get_global_option("SCF_TYPE") sapt_dft_header(sapt_dft_functional, mon_a_shift, mon_b_shift, bool(do_delta_hf), scf_alg) # Call SAPT(DFT) sapt_jk = wfn_B.jk() sapt_dft(dimer_wfn, wfn_A, wfn_B, sapt_jk=sapt_jk, data=data, print_header=False) # Copy data back into globals for k, v in data.items(): core.set_variable(k, v) core.tstop() return dimer_wfn
def run_gaussian_2(name, **kwargs): # throw an exception for open-shells if (core.get_option('SCF','REFERENCE') != 'RHF' ): raise ValidationError("""g2 computations require "reference rhf".""") # stash user options: optstash = p4util.OptionsState( ['FNOCC','COMPUTE_TRIPLES'], ['FNOCC','COMPUTE_MP4_TRIPLES'], ['FREEZE_CORE'], ['MP2_TYPE'], ['SCF','SCF_TYPE']) # override default scf_type core.set_local_option('SCF','SCF_TYPE','PK') # optimize geometry at scf level core.clean() core.set_global_option('BASIS',"6-31G(D)") driver.optimize('scf') core.clean() # scf frequencies for zpe # NOTE This line should not be needed, but without it there's a seg fault scf_e, ref = driver.frequency('scf', return_wfn=True) # thermodynamic properties du = core.get_variable('INTERNAL ENERGY CORRECTION') dh = core.get_variable('ENTHALPY CORRECTION') dg = core.get_variable('GIBBS FREE ENERGY CORRECTION') freqs = ref.frequencies() nfreq = freqs.dim(0) freqsum = 0.0 for i in range(0, nfreq): freqsum += freqs.get(i) zpe = freqsum / p4const.psi_hartree2wavenumbers * 0.8929 * 0.5 core.clean() # optimize geometry at mp2 (no frozen core) level # note: freeze_core isn't an option in MP2 core.set_global_option('FREEZE_CORE',"FALSE") core.set_global_option('MP2_TYPE', 'CONV') driver.optimize('mp2') core.clean() # qcisd(t) core.set_local_option('FNOCC','COMPUTE_MP4_TRIPLES',"TRUE") core.set_global_option('FREEZE_CORE',"TRUE") core.set_global_option('BASIS',"6-311G(D_P)") ref = driver.proc.run_fnocc('qcisd(t)', return_wfn=True, **kwargs) # HLC: high-level correction based on number of valence electrons nirrep = ref.nirrep() frzcpi = ref.frzcpi() nfzc = 0 for i in range (0,nirrep): nfzc += frzcpi[i] nalpha = ref.nalpha() - nfzc nbeta = ref.nbeta() - nfzc # hlc of gaussian-2 hlc = -0.00481 * nalpha -0.00019 * nbeta # hlc of gaussian-1 hlc1 = -0.00614 * nalpha eqci_6311gdp = core.get_variable("QCISD(T) TOTAL ENERGY") emp4_6311gd = core.get_variable("MP4 TOTAL ENERGY") emp2_6311gd = core.get_variable("MP2 TOTAL ENERGY") core.clean() # correction for diffuse functions core.set_global_option('BASIS',"6-311+G(D_P)") driver.energy('mp4') emp4_6311pg_dp = core.get_variable("MP4 TOTAL ENERGY") emp2_6311pg_dp = core.get_variable("MP2 TOTAL ENERGY") core.clean() # correction for polarization functions core.set_global_option('BASIS',"6-311G(2DF_P)") driver.energy('mp4') emp4_6311g2dfp = core.get_variable("MP4 TOTAL ENERGY") emp2_6311g2dfp = core.get_variable("MP2 TOTAL ENERGY") core.clean() # big basis mp2 core.set_global_option('BASIS',"6-311+G(3DF_2P)") #run_fnocc('_mp2',**kwargs) driver.energy('mp2') emp2_big = core.get_variable("MP2 TOTAL ENERGY") core.clean() eqci = eqci_6311gdp e_delta_g2 = emp2_big + emp2_6311gd - emp2_6311g2dfp - emp2_6311pg_dp e_plus = emp4_6311pg_dp - emp4_6311gd e_2df = emp4_6311g2dfp - emp4_6311gd eg2 = eqci + e_delta_g2 + e_plus + e_2df eg2_mp2_0k = eqci + (emp2_big - emp2_6311gd) + hlc + zpe core.print_out('\n') core.print_out(' ==> G1/G2 Energy Components <==\n') core.print_out('\n') core.print_out(' QCISD(T): %20.12lf\n' % eqci) core.print_out(' E(Delta): %20.12lf\n' % e_delta_g2) core.print_out(' E(2DF): %20.12lf\n' % e_2df) core.print_out(' E(+): %20.12lf\n' % e_plus) core.print_out(' E(G1 HLC): %20.12lf\n' % hlc1) core.print_out(' E(G2 HLC): %20.12lf\n' % hlc) core.print_out(' E(ZPE): %20.12lf\n' % zpe) core.print_out('\n') core.print_out(' ==> 0 Kelvin Results <==\n') core.print_out('\n') eg2_0k = eg2 + zpe + hlc core.print_out(' G1: %20.12lf\n' % (eqci + e_plus + e_2df + hlc1 + zpe)) core.print_out(' G2(MP2): %20.12lf\n' % eg2_mp2_0k) core.print_out(' G2: %20.12lf\n' % eg2_0k) core.set_variable("G1 TOTAL ENERGY",eqci + e_plus + e_2df + hlc1 + zpe) core.set_variable("G2 TOTAL ENERGY",eg2_0k) core.set_variable("G2(MP2) TOTAL ENERGY",eg2_mp2_0k) core.print_out('\n') T = core.get_global_option('T') core.print_out(' ==> %3.0lf Kelvin Results <==\n'% T) core.print_out('\n') internal_energy = eg2_mp2_0k + du - zpe / 0.8929 enthalpy = eg2_mp2_0k + dh - zpe / 0.8929 gibbs = eg2_mp2_0k + dg - zpe / 0.8929 core.print_out(' G2(MP2) energy: %20.12lf\n' % internal_energy ) core.print_out(' G2(MP2) enthalpy: %20.12lf\n' % enthalpy) core.print_out(' G2(MP2) free energy: %20.12lf\n' % gibbs) core.print_out('\n') core.set_variable("G2(MP2) INTERNAL ENERGY",internal_energy) core.set_variable("G2(MP2) ENTHALPY",enthalpy) core.set_variable("G2(MP2) FREE ENERGY",gibbs) internal_energy = eg2_0k + du - zpe / 0.8929 enthalpy = eg2_0k + dh - zpe / 0.8929 gibbs = eg2_0k + dg - zpe / 0.8929 core.print_out(' G2 energy: %20.12lf\n' % internal_energy ) core.print_out(' G2 enthalpy: %20.12lf\n' % enthalpy) core.print_out(' G2 free energy: %20.12lf\n' % gibbs) core.set_variable("CURRENT ENERGY",eg2_0k) core.set_variable("G2 INTERNAL ENERGY",internal_energy) core.set_variable("G2 ENTHALPY",enthalpy) core.set_variable("G2 FREE ENERGY",gibbs) core.clean() optstash.restore() # return 0K g2 results return eg2_0k