def _scan_sp(ts_info, coord_name, vscnlvl_scn_run_fs, vscnlvl_scn_save_fs, mod_var_sp1_thy_info, overwrite, cas_kwargs): """ get sps for the scan; cas options and gen lines should be same """ # Set up script and kwargs for the irc run script_str, _, sp_kwargs, _ = qchem_params(*mod_var_sp1_thy_info[0:2]) sp_kwargs.update(cas_kwargs) # Compute the single-point energies along the scan for locs in vscnlvl_scn_save_fs[-1].existing([[coord_name]]): # Set up single point filesys vscnlvl_scn_run_fs[-1].create(locs) geo_run_path = vscnlvl_scn_run_fs[-1].path(locs) geo_save_path = vscnlvl_scn_save_fs[-1].path(locs) geo = vscnlvl_scn_save_fs[-1].file.geometry.read(locs) zma = vscnlvl_scn_save_fs[-1].file.zmatrix.read(locs) # Run the energy sp.run_energy(zma, geo, ts_info, mod_var_sp1_thy_info, vscnlvl_scn_save_fs, geo_run_path, geo_save_path, locs, script_str, overwrite, highspin=False, **sp_kwargs)
def _vtst_hess_ene(ts_info, coord_name, mod_thy_info, mod_vsp1_thy_info, scn_save_fs, scn_run_fs, overwrite, **cas_kwargs): """ VTST Hessians and Energies """ scn_locs = scn_save_fs[-1].existing([coord_name]) ioprinter.running('Hessians and Gradients and Energies...', newline=1) hess_script_str, _, hess_kwargs, _ = qchem_params(*mod_thy_info[0:2]) hess_kwargs.update(cas_kwargs) script_str, _, ene_kwargs, _ = qchem_params(*mod_vsp1_thy_info[0:2]) ene_kwargs.update(cas_kwargs) for locs in scn_locs: geo_run_path = scn_run_fs[-1].path(locs) geo_save_path = scn_save_fs[-1].path(locs) scn_run_fs[-1].create(locs) zma, geo = filesys.inf.cnf_fs_zma_geo(scn_save_fs, locs) sp.run_hessian(zma, geo, ts_info, mod_thy_info, scn_save_fs, geo_run_path, geo_save_path, locs, hess_script_str, overwrite, **hess_kwargs) sp.run_gradient(zma, geo, ts_info, mod_thy_info, scn_save_fs, geo_run_path, geo_save_path, locs, hess_script_str, overwrite, **hess_kwargs) sp.run_energy(zma, geo, ts_info, mod_vsp1_thy_info, scn_save_fs, geo_run_path, geo_save_path, locs, script_str, overwrite, **ene_kwargs)
def _reac_sep_ene(rct_info, sp_thy_info, rcts_cnf_fs, run_prefix, overwrite, sp_script_str, **kwargs): """ Determine the sum of electronic energies of two reactants specified at the level of theory described in the theory info object. Will calculate the energy if it is not currently in the SAVE filesystem. """ # get the single reference energy for each of the reactant configurations spc_enes = [] for (run_fs, save_fs, mlocs, mpath), inf in zip(rcts_cnf_fs, rct_info): # Set the modified thy info mod_sp_thy_info = tinfo.modify_orb_label(sp_thy_info, inf) # Build filesys zma_fs = autofile.fs.zmatrix(mpath) # Read the geometry and set paths zma = zma_fs[-1].file.zmatrix.read([0]) geo = save_fs[-1].file.geometry.read(mlocs) # Build the single point filesys objects sp_save_fs = autofile.fs.single_point(mpath) # Calculate the save single point energy sp.run_energy(zma, geo, inf, mod_sp_thy_info, run_fs, save_fs, mlocs, run_prefix, sp_script_str, overwrite, **kwargs) exists = sp_save_fs[-1].file.energy.exists(mod_sp_thy_info[1:4]) if not exists: ioprinter.warning_message('No ene found') ene = None else: ene = sp_save_fs[-1].file.energy.read(mod_sp_thy_info[1:4]) # Append ene to list spc_enes.append(ene) # Analyze the energies in the list inf_ene = 0.0 for ene, inf in zip(spc_enes, rct_info): if ene is not None: inf_ene += ene else: ioprinter.error_message( 'Single reference energy job fails', f'for {inf}: ', 'Energy needed to evaluate infinite separation energy') inf_ene = None if inf_ene is not None: ioprinter.info_message(f'Reactant Energy [au]: {inf_ene}') return inf_ene
def _multiref_inf_sep_ene(hs_info, ref_zma, rct_info, rcts_cnf_fs, run_prefix, thy_info, var_scn_thy_info, var_sp1_thy_info, var_sp2_thy_info, hs_var_sp1_thy_info, hs_var_sp2_thy_info, var_sp1_method_dct, var_sp2_method_dct, scn_run_fs, scn_save_fs, inf_locs, overwrite=False, **cas_kwargs): """ Obtain the electronic energy for a set of reactants at infinite separation for a multi-reference electronic structure method. Since multireference methods are not size-consistent, we cannot sum the electronic energies of the two reactants from individual calculations. One could determine this energy by calculating the it where the two reactants are in the same input but the intermolecular distance is set arbitrarily large; unfortunately, this leads to convergence issues. To resulve this, the following approach is used: At a given reference point, the high-spin low-spin splitting at that reference point, and the high level energy for the high spin state at the reference geometry and for the fragments scn = thy for optimizations sp1 = low-spin single points sp2 = high-spin single points for inf sep inf = spc0 + spc1 - hs_sr_e + hs_mr_ene """ # Set groups for loops hs_thy_infs = (hs_var_sp2_thy_info, hs_var_sp1_thy_info) thy_infs = (var_sp2_thy_info, var_sp1_thy_info) method_dcts = (var_sp2_method_dct, var_sp1_method_dct) # Calculate the energies for the two cases for idx, (meth_dct, thy_inf) in enumerate(zip(method_dcts, hs_thy_infs)): if idx == 0: ioprinter.info_message( " - Running high-spin single reference energy ...") else: ioprinter.info_message( " - Running high-spin multi reference energy ...") ioprinter.info_message(' - Method:', tinfo.string(var_scn_thy_info, thy_inf)) # Calculate the single point energy script_str, kwargs = qchem_params(meth_dct) cas_kwargs.update(kwargs) geo = scn_save_fs[-1].file.geometry.read(inf_locs) zma = scn_save_fs[-1].file.zmatrix.read(inf_locs) # geo = automol.zmat.geometry(ref_zma) sp.run_energy(zma, geo, hs_info, thy_inf, scn_run_fs, scn_save_fs, inf_locs, run_prefix, script_str, overwrite, highspin=True, **cas_kwargs) # Read the energty from the filesystem geo_save_path = scn_save_fs[-1].path(inf_locs) hs_save_fs = autofile.fs.high_spin(geo_save_path) if not hs_save_fs[-1].file.energy.exists(thy_inf[1:4]): ioprinter.error_message( 'High-spin energy job failed: ', 'energy is needed to evaluate infinite separation energy') ene = None else: ene = hs_save_fs[-1].file.energy.read(thy_inf[1:4]) if idx == 0: hs_sr_ene = ene else: hs_mr_ene = ene # Get the single reference energy for each of the reactant configurations ioprinter.info_message('') ioprinter.info_message( 'Running single-point calculations for reactants (need DFT)...') ioprinter.info_message('Method:', tinfo.string(thy_info, var_sp2_thy_info)) sp_script_str, kwargs = qchem_params(var_sp2_method_dct) reac_ene = _reac_sep_ene(rct_info, var_sp2_thy_info, rcts_cnf_fs, run_prefix, overwrite, sp_script_str, **kwargs) # Calculate the infinite seperation energy all_enes = (reac_ene, hs_sr_ene, hs_mr_ene) if all(ene is not None for ene in all_enes): _inf_sep_ene = reac_ene - hs_sr_ene + hs_mr_ene ioprinter.info_message('Infinite Separation Energy [au]: ' f'{_inf_sep_ene}') else: _inf_sep_ene = None print('inf ene components') print('reac', reac_ene) print('hs sr', hs_sr_ene) print('hs mr', hs_mr_ene) return _inf_sep_ene
def _run_potentials(ts_info, scan_inf_dct, thy_inf_dct, thy_method_dct, mref_params, es_keyword_dct, runfs_dct, savefs_dct): """ Run and save the scan along both grids while (1) optimization: constraining only reaction coordinate, then (2) optimization: constraining all intermolecular coordinates (3) single-point energy on scan (1) """ # Get fs and method objects scn_run_fs = runfs_dct['vscnlvl_scn'] scn_save_fs = savefs_dct['vscnlvl_scn'] cscn_run_fs = runfs_dct['vscnlvl_cscn'] cscn_save_fs = savefs_dct['vscnlvl_cscn'] sp_scn_save_fs = savefs_dct['vscnlvl_scn'] scn_thy_info = thy_inf_dct['mod_var_scnlvl'] sp_thy_info = thy_inf_dct['mod_var_splvl1'] opt_script_str, opt_kwargs = qchem_params( thy_method_dct['var_scnlvl'], elstruct.Job.OPTIMIZATION) cas_kwargs = mref_params['var_scnlvl'] opt_kwargs.update(cas_kwargs) sp_script_str, sp_kwargs = qchem_params( thy_method_dct['var_splvl1']) sp_cas_kwargs = mref_params['var_splvl1'] sp_kwargs.update(sp_cas_kwargs) # Run optimization scans for constraints in (None, scan_inf_dct['constraint_dct']): if constraints is None: _run_fs = scn_run_fs _save_fs = scn_save_fs info_message('Running full scans..', newline=1) else: _run_fs = cscn_run_fs _save_fs = cscn_save_fs info_message('Running constrained scans..', newline=1) thy_inf_str = tinfo.string(scn_thy_info) info_message('Method:', tinfo.string(scn_thy_info)) # Loop over grids (both should start at same point and go in and out) for grid in scan_inf_dct['coord_grids']: info_message(f'Grid: {grid}') scan.execute_scan( zma=scan_inf_dct['inf_sep_zma'], spc_info=ts_info, mod_thy_info=thy_inf_dct['mod_var_scnlvl'], coord_names=scan_inf_dct['coord_names'], coord_grids=(grid,), scn_run_fs=_run_fs, scn_save_fs=_save_fs, scn_typ='relaxed', script_str=opt_script_str, overwrite=es_keyword_dct['overwrite'], update_guess=scan_inf_dct['update_guess'], reverse_sweep=False, saddle=False, constraint_dct=constraints, retryfail=True, **cas_kwargs ) info_message('') # Run the single points on top of the initial, full scan if sp_thy_info is not None: info_message('') info_message('Running single-point calculations on the full scan...') info_message('Method:', tinfo.string(scn_thy_info, sp_thy_info)) for locs in scn_save_fs[-1].existing((scan_inf_dct['coord_names'],)): scn_run_fs[-1].create(locs) geo = scn_save_fs[-1].file.geometry.read(locs) zma = scn_save_fs[-1].file.zmatrix.read(locs) sp.run_energy(zma, geo, ts_info, sp_thy_info, scn_run_fs, scn_save_fs, locs, runfs_dct['prefix'], sp_script_str, es_keyword_dct['overwrite'], highspin=False, **sp_kwargs)