def test_uccsd_3(): """Test projective UCCSD on Ne using RHF/cc-pVDZ orbitals""" import forte.proc.scc as scc import forte import psi4 import os.path forte.startup() ref_energy = -107.655681875111 psi4.set_options({'FORTE__FROZEN_DOCC': [2]}) options = forte.prepare_forte_options() forte_objects = forte.prepare_forte_objects_from_fcidump( options, os.path.dirname(__file__)) state_weights_map, mo_space_info, scf_info, fcidump = forte_objects ints = forte.make_ints_from_fcidump(fcidump, options, mo_space_info) as_ints = forte.make_active_space_ints(mo_space_info, ints, 'CORRELATED', []) calc_data = scc.run_cc(as_ints, scf_info, mo_space_info, cc_type='ucc', max_exc=2, e_convergence=1.0e-10) forte.cleanup() psi4.core.clean() energy = calc_data[-1][1] print(f' UCCSD energy: {energy}') assert energy == pytest.approx(ref_energy, 1.0e-9)
def mr_dsrg_pt2(job_type, forte_objects, ints, options): """ Driver to perform a MCSRGPT2_MO computation. :return: the computed energy """ final_energy = 0.0 ref_wfn, state_weights_map, mo_space_info, scf_info, fcidump = forte_objects state = forte.make_state_info_from_psi(options) # generate a list of states with their own weights state_map = forte.to_state_nroots_map(state_weights_map) cas_type = options.get_str("ACTIVE_SPACE_SOLVER") actv_type = options.get_str("FCIMO_ACTV_TYPE") if actv_type == "CIS" or actv_type == "CISD": raise Exception('Forte: VCIS/VCISD is not supported for MR-DSRG-PT2') max_rdm_level = 2 if options.get_str("THREEPDC") == "ZERO" else 3 as_ints = forte.make_active_space_ints(mo_space_info, ints, "ACTIVE", ["RESTRICTED_DOCC"]) ci = forte.make_active_space_solver(cas_type, state_map, scf_info, mo_space_info, as_ints, options) ci.compute_energy() rdms = ci.compute_average_rdms(state_weights_map, max_rdm_level, forte.RDMsType.spin_dependent) semi = forte.SemiCanonical(mo_space_info, ints, options) semi.semicanonicalize(rdms) mcsrgpt2_mo = forte.MCSRGPT2_MO(rdms, options, ints, mo_space_info) energy = mcsrgpt2_mo.compute_energy() return energy
def _run(self): """Run an active space solver computation""" # compute the guess orbitals if not self.input_nodes[0].executed: flog('info', 'ActiveSpaceSolver: MOs not available in mo_solver. Calling mo_solver run()') self.input_nodes[0].run() else: flog('info', 'ActiveSpaceSolver: MOs read from mo_solver object') # make the state_map state_map = to_state_nroots_map(self._states) # make the mo_space_info object self.make_mo_space_info(self._mo_space_info_map) # prepare the options options = {'E_CONVERGENCE': self.e_convergence, 'R_CONVERGENCE': self.r_convergence} # values from self._options (user specified) replace those from options full_options = {**options, **self._options} flog('info', 'ActiveSpaceSolver: adding options') local_options = ForteOptions(forte_options) local_options.set_from_dict(full_options) flog('info', 'ActiveSpaceSolver: getting integral from the model object') self.ints = self.model.ints(self.data, local_options) # Make an active space integral object flog('info', 'ActiveSpaceSolver: making active space integrals') self.as_ints = make_active_space_ints(self.mo_space_info, self.ints, "ACTIVE", ["RESTRICTED_DOCC"]) # create an active space solver object and compute the energy flog('info', 'ActiveSpaceSolver: creating active space solver object') self._active_space_solver = make_active_space_solver( self._type, state_map, self.scf_info, self.mo_space_info, self.as_ints, local_options ) flog('info', 'ActiveSpaceSolver: calling compute_energy() on active space solver object') state_energies_list = self._active_space_solver.compute_energy() flog('info', 'ActiveSpaceSolver: compute_energy() done') flog('info', f'ActiveSpaceSolver: active space energy = {state_energies_list}') self._results.add('active space energy', state_energies_list, 'Active space energy', 'Eh') return self
def forte_driver(state_weights_map, scf_info, options, ints, mo_space_info): """ Driver to perform a Forte calculation using new solvers. :param state_weights_map: dictionary of {state: weights} :param scf_info: a SCFInfo object of Forte :param options: a ForteOptions object of Forte :param ints: a ForteIntegrals object of Forte :param mo_space_info: a MOSpaceInfo object of Forte :return: the computed energy """ # map state to number of roots state_map = forte.to_state_nroots_map(state_weights_map) # create an active space solver object and compute the energy active_space_solver_type = options.get_str('ACTIVE_SPACE_SOLVER') as_ints = forte.make_active_space_ints(mo_space_info, ints, "ACTIVE", ["RESTRICTED_DOCC"]) active_space_solver = forte.make_active_space_solver( active_space_solver_type, state_map, scf_info, mo_space_info, as_ints, options) state_energies_list = active_space_solver.compute_energy() if options.get_bool('SPIN_ANALYSIS'): rdms = active_space_solver.compute_average_rdms( state_weights_map, 2, forte.RDMsType.spin_dependent) forte.perform_spin_analysis(rdms, options, mo_space_info, as_ints) # solver for dynamical correlation from DSRG correlation_solver_type = options.get_str('CORRELATION_SOLVER') if correlation_solver_type != 'NONE': dsrg_proc = ProcedureDSRG(active_space_solver, state_weights_map, mo_space_info, ints, options, scf_info) return_en = dsrg_proc.compute_energy() dsrg_proc.print_summary() dsrg_proc.push_to_psi4_environment() else: average_energy = forte.compute_average_state_energy( state_energies_list, state_weights_map) return_en = average_energy return return_en
def test_ul_uccsd_1(): """Test projective unlinked UCCSD on H4 using RHF/STO-3G orbitals""" import pytest import forte.proc.scc as scc import forte import psi4 import os.path forte.startup() ref_energy = -1.9437216535661626 # from Jonathon psi4.set_options({ 'FORTE__FCIDUMP_FILE': 'INTDUMP2', 'FORTE__FCIDUMP_DOCC': [2], 'FORTE__FROZEN_DOCC': [0], }) options = forte.prepare_forte_options() forte_objects = forte.prepare_forte_objects_from_fcidump( options, os.path.dirname(__file__)) state_weights_map, mo_space_info, scf_info, fcidump = forte_objects ints = forte.make_ints_from_fcidump(fcidump, options, mo_space_info) as_ints = forte.make_active_space_ints(mo_space_info, ints, 'CORRELATED', []) calc_data = scc.run_cc(as_ints, scf_info, mo_space_info, cc_type='ucc', max_exc=2, e_convergence=1.0e-10, linked=False, diis_start=2) forte.cleanup() psi4.core.clean() energy = calc_data[-1][2] assert energy == pytest.approx(ref_energy, 1.0e-6)
def forte_driver(state_weights_map, scf_info, options, ints, mo_space_info): max_rdm_level = 3 # TODO: set this (Francesco) return_en = 0.0 state_map = forte.to_state_nroots_map(state_weights_map) # Create an active space solver object and compute the energy active_space_solver_type = options.get_str('ACTIVE_SPACE_SOLVER') as_ints = forte.make_active_space_ints(mo_space_info, ints, "ACTIVE", ["RESTRICTED_DOCC"]) active_space_solver = forte.make_active_space_solver( active_space_solver_type, state_map, scf_info, mo_space_info, as_ints, options) active_space_solver.set_max_rdm_level(max_rdm_level) state_energies_list = active_space_solver.compute_energy() # Notes (York): # cases to run active space solver: reference relaxation, state-average dsrg # cases to run contracted ci solver (will be put in ActiveSpaceSolver): contracted state-average dsrg Etemp1, Etemp2 = 0.0, 0.0 # Create a dynamical correlation solver object correlation_solver_type = options.get_str('CORRELATION_SOLVER') if correlation_solver_type != 'NONE': # Grab the reference reference = active_space_solver.compute_average_reference( state_weights_map) # TODO: this should be chosen in a smart way # Compute unitary matrices Ua and Ub that rotate the orbitals to the semicanonical basis semi = forte.SemiCanonical(mo_space_info, ints, options) if options.get_bool("SEMI_CANONICAL"): semi.semicanonicalize(reference, max_rdm_level) Ua = semi.Ua_t() Ub = semi.Ub_t() dsrg = forte.make_dsrg_method(correlation_solver_type, reference, scf_info, options, ints, mo_space_info) dsrg.set_Uactv(Ua, Ub) Edsrg = dsrg.compute_energy() psi4.core.set_scalar_variable('UNRELAXED ENERGY', Edsrg) # dipole moment related do_dipole = options.get_bool("DSRG_DIPOLE") if do_dipole: if correlation_solver_type == 'MRDSRG' or correlation_solver_type == 'THREE-DSRG-MRPT2': do_dipole = False psi4.core.print_out( "\n !Dipole moment is not implemented for {}.".format( correlation_solver_type)) warnings.warn("Dipole moment is not implemented for MRDSRG.", UserWarning) udm_x = psi4.core.variable('UNRELAXED DIPOLE X') udm_y = psi4.core.variable('UNRELAXED DIPOLE Y') udm_z = psi4.core.variable('UNRELAXED DIPOLE Z') udm_t = psi4.core.variable('UNRELAXED DIPOLE') def dipole_routine(dsrg_method, reference): dipole_moments = dsrg_method.nuclear_dipole() dipole_dressed = dsrg_method.deGNO_DMbar_actv() for i in range(3): dipole_moments[i] += dipole_dressed[i].contract_with_densities( reference) dm_total = math.sqrt(sum([i * i for i in dipole_moments])) dipole_moments.append(dm_total) return dipole_moments # determine the relaxation procedure relax_mode = options.get_str("RELAX_REF") is_multi_state = True if options.get_str( "CALC_TYPE") != "SS" else False if relax_mode == 'NONE' and is_multi_state: relax_mode = 'ONCE' if relax_mode == 'NONE': return Edsrg elif relax_mode == 'ONCE': maxiter = 1 elif relax_mode == 'TWICE': maxiter = 2 else: maxiter = options.get_int('MAXITER_RELAX_REF') # filter out some ms-dsrg algorithms ms_dsrg_algorithm = options.get_str("DSRG_MULTI_STATE") if is_multi_state and ("SA" not in ms_dsrg_algorithm): raise NotImplementedError( "MS or XMS is disabled due to the reconstruction.") if ms_dsrg_algorithm == "SA_SUB" and relax_mode != 'ONCE': raise NotImplementedError( "Need to figure out how to compute relaxed SA density.") # prepare for reference relaxation iteration relax_conv = options.get_double("RELAX_E_CONVERGENCE") e_conv = options.get_double("E_CONVERGENCE") converged = False if relax_mode != 'ONCE' and relax_mode != 'TWICE' else True # store (unrelaxed, relaxed) quantities dsrg_energies = [] dsrg_dipoles = [] for N in range(maxiter): # Grab the effective Hamiltonian in the actice space ints_dressed = dsrg.compute_Heff_actv() # Compute the energy if is_multi_state and ms_dsrg_algorithm == "SA_SUB": state_energies_list = active_space_solver.compute_contracted_energy( ints_dressed) Erelax = forte.compute_average_state_energy( state_energies_list, state_weights_map) return Erelax else: # Make a new ActiveSpaceSolver with the new ints as_solver_relaxed = forte.make_active_space_solver( active_space_solver_type, state_map, scf_info, mo_space_info, ints_dressed, options) as_solver_relaxed.set_max_rdm_level(max_rdm_level) state_energies_list = as_solver_relaxed.compute_energy() Erelax = forte.compute_average_state_energy( state_energies_list, state_weights_map) dsrg_energies.append((Edsrg, Erelax)) if do_dipole: if is_multi_state: psi4.core.print_out( "\n !DSRG transition dipoles are disabled temporarily." ) warnings.warn( "DSRG transition dipoles are disabled temporarily.", UserWarning) else: reference = as_solver_relaxed.compute_average_reference( state_weights_map) x, y, z, t = dipole_routine(dsrg, reference) dsrg_dipoles.append( ((udm_x, udm_y, udm_z, udm_t), (x, y, z, t))) psi4.core.print_out( "\n\n {} partially relaxed dipole moment:".format( correlation_solver_type)) psi4.core.print_out( "\n X: {:10.6f} Y: {:10.6f}" " Z: {:10.6f} Total: {:10.6f}\n".format(x, y, z, t)) # test convergence and break loop if abs(Edsrg - Etemp1) < relax_conv and abs(Erelax - Etemp2) < relax_conv \ and abs(Edsrg - Erelax) < e_conv: converged = True break Etemp1, Etemp2 = Edsrg, Erelax # continue iterations if N + 1 != maxiter: # Compute the reference in the original basis # reference available if done relaxed dipole if do_dipole and (not is_multi_state): reference = semi.transform_reference( Ua, Ub, reference, max_rdm_level) else: reference = semi.transform_reference( Ua, Ub, as_solver_relaxed.compute_average_reference( state_weights_map), max_rdm_level) # Now semicanonicalize the reference and orbitals semi.semicanonicalize(reference, max_rdm_level) Ua = semi.Ua_t() Ub = semi.Ub_t() # Compute DSRG in the semicanonical basis dsrg = forte.make_dsrg_method(correlation_solver_type, reference, scf_info, options, ints, mo_space_info) dsrg.set_Uactv(Ua, Ub) Edsrg = dsrg.compute_energy() if do_dipole: udm_x = psi4.core.variable('UNRELAXED DIPOLE X') udm_y = psi4.core.variable('UNRELAXED DIPOLE Y') udm_z = psi4.core.variable('UNRELAXED DIPOLE Z') udm_t = psi4.core.variable('UNRELAXED DIPOLE') # printing if (not is_multi_state) or maxiter > 1: psi4.core.print_out( "\n\n => {} Reference Relaxation Energy Summary <=\n".format( correlation_solver_type)) indent = ' ' * 4 dash = '-' * 71 title = indent + "{:5} {:>31} {:>31}\n".format( ' ', "Fixed Ref. (a.u.)", "Relaxed Ref. (a.u.)") title += indent + "{} {} {}\n".format(' ' * 5, '-' * 31, '-' * 31) title += indent + "{:5} {:>20} {:>10} {:>20} {:>10}\n".format( "Iter.", "Total Energy", "Delta", "Total Energy", "Delta") psi4.core.print_out("\n{}".format(title + indent + dash)) E0_old, E1_old = 0.0, 0.0 for n, pair in enumerate(dsrg_energies): E0, E1 = pair psi4.core.print_out("\n{}{:>5} {:>20.12f} {:>10.3e}" " {:>20.12f} {:>10.3e}".format( indent, n + 1, E0, E0 - E0_old, E1, E1 - E1_old)) E0_old, E1_old = E0, E1 psi4.core.print_out("\n{}{}".format(indent, dash)) if do_dipole and (not is_multi_state): psi4.core.print_out( "\n\n => {} Reference Relaxation Dipole Summary <=\n".format( correlation_solver_type)) psi4.core.print_out("\n {} unrelaxed dipole moment:".format( correlation_solver_type)) psi4.core.print_out( "\n X: {:10.6f} Y: {:10.6f} " "Z: {:10.6f} Total: {:10.6f}\n".format(*dsrg_dipoles[0][0])) psi4.core.set_scalar_variable('UNRELAXED DIPOLE', dsrg_dipoles[0][0][-1]) psi4.core.print_out( "\n {} partially relaxed dipole moment:".format( correlation_solver_type)) psi4.core.print_out( "\n X: {:10.6f} Y: {:10.6f} " "Z: {:10.6f} Total: {:10.6f}\n".format(*dsrg_dipoles[0][1])) psi4.core.set_scalar_variable('PARTIALLY RELAXED DIPOLE', dsrg_dipoles[0][1][-1]) if maxiter > 1: psi4.core.print_out("\n {} relaxed dipole moment:".format( correlation_solver_type)) psi4.core.print_out("\n X: {:10.6f} Y: {:10.6f} " "Z: {:10.6f} Total: {:10.6f}\n".format( *dsrg_dipoles[1][0])) psi4.core.set_scalar_variable('RELAXED DIPOLE', dsrg_dipoles[1][0][-1]) # set energies to environment psi4.core.set_scalar_variable('PARTIALLY RELAXED ENERGY', dsrg_energies[0][1]) if maxiter > 1: psi4.core.set_scalar_variable('RELAXED ENERGY', dsrg_energies[1][0]) # throw not converging error if relaxation not converged if not converged: psi4.core.set_scalar_variable('CURRENT UNRELAXED ENERGY', dsrg_energies[-1][0]) psi4.core.set_scalar_variable('CURRENT RELAXED ENERGY', dsrg_energies[-1][1]) psi4.core.set_scalar_variable('CURRENT ENERGY', dsrg_energies[-1][1]) raise psi4.core.ConvergenceError( "DSRG relaxation does not converge in {} cycles".format( maxiter)) else: if relax_mode != 'ONCE' and relax_mode != 'TWICE': psi4.core.set_scalar_variable('FULLY RELAXED ENERGY', dsrg_energies[-1][1]) psi4.core.set_scalar_variable('CURRENT ENERGY', dsrg_energies[-1][1]) if do_dipole and (not is_multi_state): psi4.core.print_out( "\n {} fully relaxed dipole moment:".format( correlation_solver_type)) psi4.core.print_out( "\n X: {:10.6f} Y: {:10.6f} " "Z: {:10.6f} Total: {:10.6f}\n".format( *dsrg_dipoles[-1][1])) psi4.core.set_scalar_variable('FULLY RELAXED DIPOLE', dsrg_dipoles[-1][1][-1]) return Erelax else: average_energy = forte.compute_average_state_energy( state_energies_list, state_weights_map) return_en = average_energy return return_en
def test_sparse_ci2(): import math import psi4 import forte import itertools import numpy as np import pytest from forte import forte_options ref_fci = -5.623851783330647 psi4.core.clean() # need to clean the options otherwise this job will interfere forte.clean_options() h2o = psi4.geometry(""" He He 1 1.0 """) psi4.set_options({'basis': 'cc-pVDZ'}) _, wfn = psi4.energy('scf', return_wfn=True) na = wfn.nalpha() nb = wfn.nbeta() nirrep = wfn.nirrep() wfn_symmetry = 0 forte.startup() forte.banner() psi4_options = psi4.core.get_options() psi4_options.set_current_module('FORTE') forte_options.get_options_from_psi4(psi4_options) # Setup forte and prepare the active space integral class nmopi = wfn.nmopi() point_group = wfn.molecule().point_group().symbol() mo_space_info = forte.make_mo_space_info(nmopi, point_group, forte_options) ints = forte.make_ints_from_psi4(wfn, forte_options, mo_space_info) as_ints = forte.make_active_space_ints(mo_space_info, ints, 'ACTIVE', ['RESTRICTED_DOCC']) print('\n\n => Sparse FCI Test <=') print(' Number of irreps: {}'.format(nirrep)) nmo = wfn.nmo() nmopi = [wfn.nmopi()[h] for h in range(nirrep)] nmopi_str = [str(wfn.nmopi()[h]) for h in range(nirrep)] mo_sym = [] for h in range(nirrep): for i in range(nmopi[h]): mo_sym.append(h) print(' Number of orbitals per irreps: [{}]'.format(','.join(nmopi_str))) print(' Symmetry of the MOs: ', mo_sym) hf_reference = forte.Determinant() hf_reference.create_alfa_bit(0) hf_reference.create_beta_bit(0) print(' Hartree-Fock determinant: {}'.format(hf_reference.str(10))) # Compute the HF energy hf_energy = as_ints.nuclear_repulsion_energy() + as_ints.slater_rules(hf_reference, hf_reference) print(' Nuclear repulsion energy: {}'.format(as_ints.nuclear_repulsion_energy())) print(' Reference energy: {}'.format(hf_energy)) # Build a list of determinants orblist = [i for i in range(nmo)] dets = [] for astr in itertools.combinations(orblist, na): for bstr in itertools.combinations(orblist, nb): sym = 0 d = forte.Determinant() for a in astr: d.create_alfa_bit(a) sym = sym ^ mo_sym[a] for b in bstr: d.create_beta_bit(b) sym = sym ^ mo_sym[b] if (sym == wfn_symmetry): dets.append(d) print(' Determinant {} has symmetry {}'.format(d.str(nmo), sym)) print(f'\n Size of the derminant basis: {len(dets)}') energy, evals, evecs, spin = forte.diag(dets, as_ints, 1, 1, "FULL") print(energy) efci = energy[0] + as_ints.nuclear_repulsion_energy() print('\n FCI Energy: {}\n'.format(efci)) assert efci == pytest.approx(ref_fci, abs=1e-9) # Clean up forte (necessary) forte.cleanup()
def prepare_forte_objects(wfn, mo_spaces=None, active_space='ACTIVE', core_spaces=['RESTRICTED_DOCC'], localize=False, localize_spaces=[]): """Take a psi4 wavefunction object and prepare the ForteIntegrals, SCFInfo, and MOSpaceInfo objects Parameters ---------- wfn : psi4 Wavefunction A psi4 Wavefunction object mo_spaces : dict A dictionary with the size of each space (e.g., {'ACTIVE' : [3]}) active_space : str The MO space treated as active (default: 'ACTIVE') core_spaces : list(str) The MO spaces treated as active (default: ['RESTRICTED_DOCC']) localize : bool Do localize the orbitals? (defaul: False) localize_spaces : list(str) A list of spaces to localize (default: []) Returns ------- tuple(ForteIntegrals, ActiveSpaceIntegrals, SCFInfo, MOSpaceInfo, map(StateInfo : list) a tuple containing the ForteIntegrals, SCFInfo, and MOSpaceInfo objects and a map of states and weights """ # fill in the options object psi4_options = psi4.core.get_options() psi4_options.set_current_module('FORTE') options = forte.forte_options options.get_options_from_psi4(psi4_options) if ('DF' in options.get_str('INT_TYPE')): aux_basis = psi4.core.BasisSet.build( wfn.molecule(), 'DF_BASIS_MP2', psi4.core.get_global_option('DF_BASIS_MP2'), 'RIFIT', psi4.core.get_global_option('BASIS')) wfn.set_basisset('DF_BASIS_MP2', aux_basis) if (options.get_str('MINAO_BASIS')): minao_basis = psi4.core.BasisSet.build( wfn.molecule(), 'MINAO_BASIS', psi4_options.get_str('MINAO_BASIS')) wfn.set_basisset('MINAO_BASIS', minao_basis) # Prepare base objects scf_info = forte.SCFInfo(wfn) nmopi = wfn.nmopi() point_group = wfn.molecule().point_group().symbol() if mo_spaces == None: mo_space_info = forte.make_mo_space_info(nmopi, point_group, options) else: mo_space_info = forte.make_mo_space_info_from_map( nmopi, point_group, mo_spaces, []) state_weights_map = forte.make_state_weights_map(options, mo_space_info) ints = forte.make_ints_from_psi4(wfn, options, mo_space_info) if localize: localizer = forte.Localize(forte.forte_options, ints, mo_space_info) localizer.set_orbital_space(localize_spaces) localizer.compute_transformation() Ua = localizer.get_Ua() ints.rotate_orbitals(Ua, Ua) # the space that defines the active orbitals. We select only the 'ACTIVE' part # the space(s) with non-active doubly occupied orbitals as_ints = forte.make_active_space_ints(mo_space_info, ints, active_space, core_spaces) return (ints, as_ints, scf_info, mo_space_info, state_weights_map)
def test_sparse_ci(): import math import psi4 import forte import itertools import numpy as np import pytest from forte import forte_options ref_fci = -1.101150330132956 psi4.core.clean() h2o = psi4.geometry(""" H H 1 1.0 """) psi4.set_options({'basis': 'sto-3g'}) E_scf, wfn = psi4.energy('scf', return_wfn=True) na = wfn.nalpha() nb = wfn.nbeta() nirrep = wfn.nirrep() wfn_symmetry = 0 forte.startup() forte.banner() psi4_options = psi4.core.get_options() psi4_options.set_current_module('FORTE') forte_options.get_options_from_psi4(psi4_options) # Setup forte and prepare the active space integral class mo_space_info = forte.make_mo_space_info(wfn, forte_options) ints = forte.make_forte_integrals(wfn, forte_options, mo_space_info) as_ints = forte.make_active_space_ints(mo_space_info, ints, 'ACTIVE', ['RESTRICTED_DOCC']) as_ints.print() print('\n\n => Sparse FCI Test <=') print(' Number of irreps: {}'.format(nirrep)) nmo = wfn.nmo() nmopi = [wfn.nmopi()[h] for h in range(nirrep)] nmopi_str = [str(wfn.nmopi()[h]) for h in range(nirrep)] mo_sym = [] for h in range(nirrep): for i in range(nmopi[h]): mo_sym.append(h) print(' Number of orbitals per irreps: [{}]'.format(','.join(nmopi_str))) print(' Symmetry of the MOs: ', mo_sym) hf_reference = forte.Determinant() hf_reference.create_alfa_bit(0) hf_reference.create_beta_bit(0) print(' Hartree-Fock determinant: {}'.format(hf_reference.str(2))) # Compute the HF energy hf_energy = as_ints.nuclear_repulsion_energy() + as_ints.slater_rules( hf_reference, hf_reference) print(' Nuclear repulsion energy: {}'.format( as_ints.nuclear_repulsion_energy())) print(' Reference energy: {}'.format(hf_energy)) # Build a list of determinants orblist = [i for i in range(nmo)] dets = [] for astr in itertools.combinations(orblist, na): for bstr in itertools.combinations(orblist, nb): sym = 0 d = forte.Determinant() for a in astr: d.create_alfa_bit(a) sym = sym ^ mo_sym[a] for b in bstr: d.create_beta_bit(b) sym = sym ^ mo_sym[b] if (sym == wfn_symmetry): dets.append(d) print(' Determinant {} has symmetry {}'.format( d.str(nmo), sym)) # Build the Hamiltonian matrix using 'slater_rules' nfci = len(dets) H = np.ndarray((nfci, nfci)) for I in range(nfci): # off-diagonal terms for J in range(I + 1, nfci): HIJ = as_ints.slater_rules(dets[I], dets[J]) H[I][J] = H[J][I] = HIJ # diagonal term H[I][I] = as_ints.nuclear_repulsion_energy() + as_ints.slater_rules( dets[I], dets[I]) # Find the lowest eigenvalue efci = np.linalg.eigh(H)[0][0] print('\n FCI Energy: {}\n'.format(efci)) assert efci == pytest.approx(ref_fci, 1.0e-9) # Clean up forte (necessary) forte.cleanup()
def forte_driver(state_weights_map, scf_info, options, ints, mo_space_info): max_rdm_level = 3 # TODO: set this (Francesco) return_en = 0.0 state_map = forte.to_state_nroots_map(state_weights_map) # Create an active space solver object and compute the energy active_space_solver_type = options.get_str('ACTIVE_SPACE_SOLVER') as_ints = forte.make_active_space_ints(mo_space_info, ints, "ACTIVE", ["RESTRICTED_DOCC"]); active_space_solver = forte.make_active_space_solver(active_space_solver_type,state_map,scf_info,mo_space_info,as_ints,options) state_energies_list = active_space_solver.compute_energy() # Notes (York): # cases to run active space solver: reference relaxation, state-average dsrg # cases to run contracted ci solver (will be put in ActiveSpaceSolver): contracted state-average dsrg Etemp1, Etemp2 = 0.0, 0.0 # Create a dynamical correlation solver object correlation_solver_type = options.get_str('CORRELATION_SOLVER') if correlation_solver_type != 'NONE': # Grab the reference rdms = active_space_solver.compute_average_rdms(state_weights_map, 3) # TODO: max_rdm_level should be chosen in a smart way # Compute unitary matrices Ua and Ub that rotate the orbitals to the semicanonical basis semi = forte.SemiCanonical(mo_space_info, ints, options) if options.get_bool("SEMI_CANONICAL"): semi.semicanonicalize(rdms, max_rdm_level) Ua = semi.Ua_t() Ub = semi.Ub_t() dsrg = forte.make_dsrg_method(correlation_solver_type, rdms, scf_info, options, ints, mo_space_info) dsrg.set_Uactv(Ua, Ub) Edsrg = dsrg.compute_energy() psi4.core.set_scalar_variable('UNRELAXED ENERGY', Edsrg) # dipole moment related do_dipole = options.get_bool("DSRG_DIPOLE") if do_dipole: if correlation_solver_type == 'MRDSRG' or correlation_solver_type == 'THREE-DSRG-MRPT2': do_dipole = False psi4.core.print_out("\n !Dipole moment is not implemented for {}.".format(correlation_solver_type)) warnings.warn("Dipole moment is not implemented for MRDSRG.", UserWarning) udm_x = psi4.core.variable('UNRELAXED DIPOLE X') udm_y = psi4.core.variable('UNRELAXED DIPOLE Y') udm_z = psi4.core.variable('UNRELAXED DIPOLE Z') udm_t = psi4.core.variable('UNRELAXED DIPOLE') def dipole_routine(dsrg_method, rdms): dipole_moments = dsrg_method.nuclear_dipole() dipole_dressed = dsrg_method.deGNO_DMbar_actv() for i in range(3): dipole_moments[i] += dipole_dressed[i].contract_with_rdms(rdms) dm_total = math.sqrt(sum([i * i for i in dipole_moments])) dipole_moments.append(dm_total) return dipole_moments # determine the relaxation procedure relax_mode = options.get_str("RELAX_REF") is_multi_state = True if options.get_str("CALC_TYPE") != "SS" else False if relax_mode == 'NONE' and is_multi_state: relax_mode = 'ONCE' if relax_mode == 'NONE': return Edsrg elif relax_mode == 'ONCE': maxiter = 1 elif relax_mode == 'TWICE': maxiter = 2 else: maxiter = options.get_int('MAXITER_RELAX_REF') # filter out some ms-dsrg algorithms ms_dsrg_algorithm = options.get_str("DSRG_MULTI_STATE") if is_multi_state and ("SA" not in ms_dsrg_algorithm): raise NotImplementedError("MS or XMS is disabled due to the reconstruction.") if ms_dsrg_algorithm == "SA_SUB" and relax_mode != 'ONCE': raise NotImplementedError("Need to figure out how to compute relaxed SA density.") # prepare for reference relaxation iteration relax_conv = options.get_double("RELAX_E_CONVERGENCE") e_conv = options.get_double("E_CONVERGENCE") converged = False if relax_mode != 'ONCE' and relax_mode != 'TWICE' else True # store (unrelaxed, relaxed) quantities dsrg_energies = [] dsrg_dipoles = [] for N in range(maxiter): # Grab the effective Hamiltonian in the actice space ints_dressed = dsrg.compute_Heff_actv() # Compute the energy if is_multi_state and ms_dsrg_algorithm == "SA_SUB": sa_sub_max_rdm = 2 # TODO: This should be 3 if do_hbar3 is true state_energies_list = active_space_solver.compute_contracted_energy(ints_dressed, sa_sub_max_rdm) Erelax = forte.compute_average_state_energy(state_energies_list,state_weights_map) return Erelax else: # Make a new ActiveSpaceSolver with the new ints as_solver_relaxed = forte.make_active_space_solver(active_space_solver_type, state_map,scf_info, mo_space_info,ints_dressed, options) state_energies_list = as_solver_relaxed.compute_energy() Erelax = forte.compute_average_state_energy(state_energies_list,state_weights_map) dsrg_energies.append((Edsrg, Erelax)) if do_dipole: if is_multi_state: psi4.core.print_out("\n !DSRG transition dipoles are disabled temporarily.") warnings.warn("DSRG transition dipoles are disabled temporarily.", UserWarning) else: rdms = as_solver_relaxed.compute_average_rdms(state_weights_map, 3) x, y, z, t = dipole_routine(dsrg, rdms) dsrg_dipoles.append(((udm_x, udm_y, udm_z, udm_t), (x, y, z, t))) psi4.core.print_out("\n\n {} partially relaxed dipole moment:".format(correlation_solver_type)) psi4.core.print_out("\n X: {:10.6f} Y: {:10.6f}" " Z: {:10.6f} Total: {:10.6f}\n".format(x, y, z, t)) # test convergence and break loop if abs(Edsrg - Etemp1) < relax_conv and abs(Erelax - Etemp2) < relax_conv \ and abs(Edsrg - Erelax) < e_conv: converged = True break Etemp1, Etemp2 = Edsrg, Erelax # continue iterations if N + 1 != maxiter: # Compute the rdms in the original basis # rdms available if done relaxed dipole if do_dipole and (not is_multi_state): rdms = semi.transform_rdms(Ua, Ub, rdms, max_rdm_level) else: rdms = semi.transform_rdms(Ua, Ub, as_solver_relaxed.compute_average_rdms(state_weights_map, 3), max_rdm_level) # Now semicanonicalize the reference and orbitals semi.semicanonicalize(rdms, max_rdm_level) Ua = semi.Ua_t() Ub = semi.Ub_t() # Compute DSRG in the semicanonical basis dsrg = forte.make_dsrg_method(correlation_solver_type, rdms, scf_info, options, ints, mo_space_info) dsrg.set_Uactv(Ua, Ub) Edsrg = dsrg.compute_energy() if do_dipole: udm_x = psi4.core.variable('UNRELAXED DIPOLE X') udm_y = psi4.core.variable('UNRELAXED DIPOLE Y') udm_z = psi4.core.variable('UNRELAXED DIPOLE Z') udm_t = psi4.core.variable('UNRELAXED DIPOLE') # printing if (not is_multi_state) or maxiter > 1: psi4.core.print_out("\n\n => {} Reference Relaxation Energy Summary <=\n".format(correlation_solver_type)) indent = ' ' * 4 dash = '-' * 71 title = indent + "{:5} {:>31} {:>31}\n".format(' ', "Fixed Ref. (a.u.)", "Relaxed Ref. (a.u.)") title += indent + "{} {} {}\n".format(' ' * 5, '-' * 31, '-' * 31) title += indent + "{:5} {:>20} {:>10} {:>20} {:>10}\n".format("Iter.", "Total Energy", "Delta", "Total Energy", "Delta") psi4.core.print_out("\n{}".format(title + indent + dash)) E0_old, E1_old = 0.0, 0.0 for n, pair in enumerate(dsrg_energies): E0, E1 = pair psi4.core.print_out("\n{}{:>5} {:>20.12f} {:>10.3e}" " {:>20.12f} {:>10.3e}".format(indent, n + 1, E0, E0 - E0_old, E1, E1 - E1_old)) E0_old, E1_old = E0, E1 psi4.core.print_out("\n{}{}".format(indent, dash)) if do_dipole and (not is_multi_state): psi4.core.print_out("\n\n => {} Reference Relaxation Dipole Summary <=\n".format(correlation_solver_type)) psi4.core.print_out("\n {} unrelaxed dipole moment:".format(correlation_solver_type)) psi4.core.print_out("\n X: {:10.6f} Y: {:10.6f} " "Z: {:10.6f} Total: {:10.6f}\n".format(*dsrg_dipoles[0][0])) psi4.core.set_scalar_variable('UNRELAXED DIPOLE', dsrg_dipoles[0][0][-1]) psi4.core.print_out("\n {} partially relaxed dipole moment:".format(correlation_solver_type)) psi4.core.print_out("\n X: {:10.6f} Y: {:10.6f} " "Z: {:10.6f} Total: {:10.6f}\n".format(*dsrg_dipoles[0][1])) psi4.core.set_scalar_variable('PARTIALLY RELAXED DIPOLE', dsrg_dipoles[0][1][-1]) if maxiter > 1: psi4.core.print_out("\n {} relaxed dipole moment:".format(correlation_solver_type)) psi4.core.print_out("\n X: {:10.6f} Y: {:10.6f} " "Z: {:10.6f} Total: {:10.6f}\n".format(*dsrg_dipoles[1][0])) psi4.core.set_scalar_variable('RELAXED DIPOLE', dsrg_dipoles[1][0][-1]) # set energies to environment psi4.core.set_scalar_variable('PARTIALLY RELAXED ENERGY', dsrg_energies[0][1]) if maxiter > 1: psi4.core.set_scalar_variable('RELAXED ENERGY', dsrg_energies[1][0]) # throw not converging error if relaxation not converged if not converged: psi4.core.set_scalar_variable('CURRENT UNRELAXED ENERGY', dsrg_energies[-1][0]) psi4.core.set_scalar_variable('CURRENT RELAXED ENERGY', dsrg_energies[-1][1]) psi4.core.set_scalar_variable('CURRENT ENERGY', dsrg_energies[-1][1]) raise psi4.core.ConvergenceError("DSRG relaxation does not converge in {} cycles".format(maxiter)) else: if relax_mode != 'ONCE' and relax_mode != 'TWICE': psi4.core.set_scalar_variable('FULLY RELAXED ENERGY', dsrg_energies[-1][1]) psi4.core.set_scalar_variable('CURRENT ENERGY', dsrg_energies[-1][1]) if do_dipole and (not is_multi_state): psi4.core.print_out("\n {} fully relaxed dipole moment:".format(correlation_solver_type)) psi4.core.print_out("\n X: {:10.6f} Y: {:10.6f} " "Z: {:10.6f} Total: {:10.6f}\n".format(*dsrg_dipoles[-1][1])) psi4.core.set_scalar_variable('FULLY RELAXED DIPOLE', dsrg_dipoles[-1][1][-1]) return Erelax else : average_energy = forte.compute_average_state_energy(state_energies_list,state_weights_map) return_en = average_energy return return_en
def run_sci(ints, scf_info, wfn, selector): mo_space_map = { 'RESTRICTED_DOCC': selector.restricted_docc, 'ACTIVE': selector.active, 'RESTRICTED_UOCC': selector.restricted_uocc } mo_reordering = selector.mo_reorder # print(mo_space_map) # print(mo_reordering) mo_space_info = forte.make_mo_space_info_from_map(wfn, mo_space_map, reorder=mo_reordering) # print(mo_space_info.get_corr_abs_mo('ACTIVE')) # print(mo_space_info.get_corr_abs_mo('RESTRICTED_DOCC')) # print(mo_space_info.get_corr_abs_mo('RESTRICTED_UOCC')) nact = 0 for n in mo_space_map['ACTIVE']: nact += n nactv = sum(mo_space_map['ACTIVE']) nrdocc = sum(mo_space_map['RESTRICTED_DOCC']) # options = psi4.core.get_options() # options.set_current_module('FORTE') # forte.forte_options.update_psi_options(options) options = forte.forte_options options.set_str('ACTIVE_REF_TYPE', 'CISD') options.set_int('SCI_MAX_CYCLE', 3) options.set_str('SCI_EXCITED_ALGORITHM', 'AVERAGE') options.set_str('INT_TYPE', 'CHOLESKY') options.set_int('ASCI_CDET', 50) options.set_int('ASCI_TDET', 200) as_ints = forte.make_active_space_ints(mo_space_info, ints, "ACTIVE", ["RESTRICTED_DOCC"]) na = wfn.nalpha() nb = wfn.nbeta() npair = (na + nb) // 2 nunpair = na + nb - 2 * npair na = npair + nunpair na = npair state_vec = [] state_map = {} lowest_twice_ms = abs(na - nb) for k in range(2): na_act = na - nrdocc + k nb_act = nb - nrdocc - k # print("k = ", k) # print("na_act = ", na_act) # print("nb_act = ", nb_act) # print("binom({},{}) = {}".format(na_act,nactv,scipy.special.binom(nactv,na_act))) # print("binom({},{}) = {}".format(nb_act,nactv,scipy.special.binom(nactv,nb_act))) num_dets = min( 3, int( scipy.special.binom(nactv, na_act) * scipy.special.binom(nactv, nb_act))) # print(k, num_dets) twice_ms = na - nb + 2 * k multiplicity = twice_ms + 1 state = forte.StateInfo(na=na + k, nb=nb - k, multiplicity=multiplicity, twice_ms=twice_ms, irrep=0) # state_vec.append((,num_dets)) if num_dets > 0: state_map[state] = num_dets # state_1 = forte.StateInfo(na=na+1,nb=nb-1,multiplicity=3,twice_ms=1,irrep=0) # num_states = 3 # if nact <= 2: # num_states = 1 # state_map = {state_vec[0][0] : state_vec[0][1], state_vec[1][0] : state_vec[1][1]} #, state_1 : num_states} as_solver = forte.make_active_space_solver('ASCI', state_map, scf_info, mo_space_info, as_ints, forte.forte_options) en = as_solver.compute_energy() energies = [] occs = [] for key, val in en.items(): for n, energy in enumerate(val): ref = as_solver.rdms({(key, key): [(n, n)]}, 1) # ordm = forte.get_rdm_data(ref[0], 1) # TODO-PR reintroduce # occs.append(get_occ(ordm, nact)) # TODO-PR reintroduce occs.append(0.0) label = "{}-{}".format(n + 1, key.multiplicity_label()) energies.append((en[key][n], label, key.multiplicity())) return energies, occs