def check_solve(ham, scf_solver, occ_model, lf, olp, kin, na, *exps): guess_core_hamiltonian(olp, kin, na, *exps) if scf_solver.kind == 'exp': occ_model.assign(*exps) assert scf_solver.error(ham, lf, olp, *exps) > scf_solver.threshold scf_solver(ham, lf, olp, occ_model, *exps) assert scf_solver.error(ham, lf, olp, *exps) < scf_solver.threshold else: occ_model.assign(*exps) dms = [exp.to_dm() for exp in exps] assert scf_solver.error(ham, lf, olp, *dms) > scf_solver.threshold scf_solver(ham, lf, olp, occ_model, *dms) assert scf_solver.error(ham, lf, olp, *dms) < scf_solver.threshold focks = [lf.create_two_index() for i in xrange(ham.ndm)] ham.compute_fock(*focks) for i in xrange(ham.ndm): exps[i].from_fock(focks[i], olp) occ_model.assign(*exps)
def check_solve(ham, scf_solver, occ_model, olp, kin, na, *orbs): guess_core_hamiltonian(olp, kin+na, *orbs) if scf_solver.kind == 'orb': occ_model.assign(*orbs) assert scf_solver.error(ham, olp, *orbs) > scf_solver.threshold scf_solver(ham, olp, occ_model, *orbs) assert scf_solver.error(ham, olp, *orbs) < scf_solver.threshold else: occ_model.assign(*orbs) dms = [orb.to_dm() for orb in orbs] assert scf_solver.error(ham, olp, *dms) > scf_solver.threshold scf_solver(ham, olp, occ_model, *dms) assert scf_solver.error(ham, olp, *dms) < scf_solver.threshold focks = [np.zeros(dms[0].shape) for i in xrange(ham.ndm)] ham.compute_fock(*focks) for i in xrange(ham.ndm): orbs[i].from_fock(focks[i], olp) occ_model.assign(*orbs)
def check_vanadium_sc_hf(scf_solver): """Try to converge the SCF for the neutral vanadium atom with fixe fractional occupations. Parameters ---------- scf_solver : one of the SCFSolver types in HORTON A configured SCF solver that must be tested. """ # vanadium atoms numbers = np.array([23]) pseudo_numbers = numbers.astype(float) coordinates = np.zeros((1, 3), float) # Simple basis set obasis = get_gobasis(coordinates, numbers, 'def2-tzvpd') # Dense matrices lf = DenseLinalgFactory(obasis.nbasis) # Compute integrals olp = obasis.compute_overlap(lf) kin = obasis.compute_kinetic(lf) na = obasis.compute_nuclear_attraction(coordinates, pseudo_numbers, lf) er = obasis.compute_electron_repulsion(lf) # Setup of restricted HF Hamiltonian terms = [ RTwoIndexTerm(kin, 'kin'), RDirectTerm(er, 'hartree'), RExchangeTerm(er, 'x_hf'), RTwoIndexTerm(na, 'ne'), ] ham = REffHam(terms) # Define fractional occupations of interest. (Spin-compensated case) occ_model = FixedOccModel( np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5])) # Allocate orbitals and make the initial guess exp_alpha = lf.create_expansion(obasis.nbasis) guess_core_hamiltonian(olp, kin, na, exp_alpha) # SCF test check_solve(ham, scf_solver, occ_model, lf, olp, kin, na, exp_alpha)
def check_vanadium_sc_hf(scf_solver): """Try to converge the SCF for the neutral vanadium atom with fixe fractional occupations. Parameters ---------- scf_solver : one of the SCFSolver types in HORTON A configured SCF solver that must be tested. """ # vanadium atoms numbers = np.array([23]) pseudo_numbers = numbers.astype(float) coordinates = np.zeros((1, 3), float) # Simple basis set obasis = get_gobasis(coordinates, numbers, 'def2-tzvpd') # Dense matrices lf = DenseLinalgFactory(obasis.nbasis) # Compute integrals olp = obasis.compute_overlap(lf) kin = obasis.compute_kinetic(lf) na = obasis.compute_nuclear_attraction(coordinates, pseudo_numbers, lf) er = obasis.compute_electron_repulsion(lf) # Setup of restricted HF Hamiltonian terms = [ RTwoIndexTerm(kin, 'kin'), RDirectTerm(er, 'hartree'), RExchangeTerm(er, 'x_hf'), RTwoIndexTerm(na, 'ne'), ] ham = REffHam(terms) # Define fractional occupations of interest. (Spin-compensated case) occ_model = FixedOccModel(np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5])) # Allocate orbitals and make the initial guess exp_alpha = lf.create_expansion(obasis.nbasis) guess_core_hamiltonian(olp, kin, na, exp_alpha) # SCF test check_solve(ham, scf_solver, occ_model, lf, olp, kin, na, exp_alpha)
def check_interpolation(ham, lf, olp, kin, na, exps, do_plot=False): dm0s = [exp.to_dm() for exp in exps] guess_core_hamiltonian(olp, kin, na, *exps) dm1s = [exp.to_dm() for exp in exps] check_cubic_wrapper(ham, dm0s, dm1s, do_plot)
def check_dot_hessian_polynomial(olp, core, ham, exps, is_hf=True, extent=1.0, threshold=1e-2, do_plot=False): """Test dot_hessian by making a quadratic energy approximation. The quadratic model is used to interpolate the energy between the given solution (exps) and the core Hamiltonian guess. Parameters ---------- olp : TwoIndex The overlap matrix. core : TwoIndex The core Hamiltonian. ham : EffHam An effective Hamiltonian. exps : Expansion A set of orbitals (one for restricted, two for unrestricted) is_hf : bool Set to True when testing with pure HF. extent : float The extent of the interpolation. 1.0 is whole range. threshold : float The allowed error between the energies. do_plot : bool When True, some plots will be made. Useful for debugging. """ # First alpha density matrix is the given matrix dms1 = [exp.to_dm() for exp in exps] # Second alpha density matrix is that from the core Hamiltonian guess_core_hamiltonian(olp, core, *exps) dms2 = [exp.to_dm() for exp in exps] # Test quadratic interpolation of the energy. This should match very well # with normal energy calculations as the energy is quadratic in the # density matrix. npoint = 11 xs = np.linspace(0.0, extent, npoint) def check(dms_a, dms_b): """Check quadratic energy model between two dms.""" ham.reset(*dms_a) energy_a_0 = ham.compute_energy() focks_a = [dm_a.new() for dm_a in dms_a] ham.compute_fock(*focks_a) delta_dms = [] for idm in xrange(ham.ndm): delta_dm = dms_b[idm].copy() delta_dm.iadd(dms_a[idm], -1) delta_dms.append(delta_dm) ham.reset_delta(*delta_dms) dots_a = [dm_a.new() for dm_a in dms_a] ham.compute_dot_hessian(*dots_a) energy_a_1 = 0.0 energy_a_2 = 0.0 for idm in xrange(ham.ndm): energy_a_1 += focks_a[idm].contract_two( 'ab,ba', delta_dms[idm]) * ham.deriv_scale energy_a_2 += dots_a[idm].contract_two( 'ab,ba', delta_dms[idm]) * ham.deriv_scale**2 # print 'energy_a_0', energy_a_0 # print 'energy_a_1', energy_a_1 # print 'energy_a_2', energy_a_2 # Compute interpolation and compare energies_x = np.zeros(npoint) energies_2nd_order = np.zeros(npoint) derivs_x = np.zeros(npoint) derivs_2nd_order = np.zeros(npoint) for ipoint in xrange(npoint): x = xs[ipoint] dms_x = [] for idm in xrange(ham.ndm): dm_x = dms_a[idm].copy() dm_x.iscale(1 - x) dm_x.iadd(dms_b[idm], x) dms_x.append(dm_x) ham.reset(*dms_x) energies_x[ipoint] = ham.compute_energy() ham.compute_fock(*focks_a) for idm in xrange(ham.ndm): derivs_x[ipoint] += focks_a[idm].contract_two('ab,ba', delta_dms[idm]) * \ ham.deriv_scale energies_2nd_order[ ipoint] = energy_a_0 + x * energy_a_1 + 0.5 * x * x * energy_a_2 derivs_2nd_order[ipoint] = energy_a_1 + x * energy_a_2 # print '%5.2f %15.8f %15.8f' % (x, energies_x[ipoint], energies_2nd_order[ipoint]) if do_plot: # pragma: no cover import matplotlib.pyplot as pt pt.clf() pt.plot(xs, energies_x, 'ro') pt.plot(xs, energies_2nd_order, 'k-') pt.savefig('test_energies.png') pt.clf() pt.plot(xs, derivs_x, 'ro') pt.plot(xs, derivs_2nd_order, 'k-') pt.savefig('test_derivs.png') assert abs(energies_x - energies_2nd_order).max() / np.ptp(energies_x) < threshold assert abs(derivs_x - derivs_2nd_order).max() / np.ptp(derivs_x) < threshold return energy_a_0, energy_a_1, energy_a_2 # 1) using dms1 as reference point _energy1_0, _energy1_1, energy1_2 = check(dms1, dms2) # 2) using dms2 as reference point _energy2_0, _energy2_1, energy2_2 = check(dms2, dms1) if is_hf: # Final check: curvature should be the same in the HF case. assert abs(energy1_2 - energy2_2) < threshold
def check_interpolation(ham, olp, kin, na, orbs, do_plot=False): dm0s = [orb.to_dm() for orb in orbs] guess_core_hamiltonian(olp, kin+na, *orbs) dm1s = [orb.to_dm() for orb in orbs] check_cubic_wrapper(ham, dm0s, dm1s, do_plot)
def check_dot_hessian_polynomial(olp, core, ham, orbs, is_hf=True, extent=1.0, threshold=1e-2, do_plot=False): """Test dot_hessian by making a quadratic energy approximation. The quadratic model is used to interpolate the energy between the given solution (orbs) and the core Hamiltonian guess. Parameters ---------- olp : TwoIndex The overlap matrix. core : TwoIndex The core Hamiltonian. ham : EffHam An effective Hamiltonian. orbs : list of Orbitals objects. A set of orbitals (one for restricted, two for unrestricted) is_hf : bool Set to True when testing with pure HF. extent : float The extent of the interpolation. 1.0 is whole range. threshold : float The allowed error between the energies. do_plot : bool When True, some plots will be made. Useful for debugging. """ # First alpha density matrix is the given matrix dms1 = [orb.to_dm() for orb in orbs] # Second alpha density matrix is that from the core Hamiltonian guess_core_hamiltonian(olp, core, *orbs) dms2 = [orb.to_dm() for orb in orbs] # Test quadratic interpolation of the energy. This should match very well # with normal energy calculations as the energy is quadratic in the # density matrix. npoint = 11 xs = np.linspace(0.0, extent, npoint) def check(dms_a, dms_b): """Check quadratic energy model between two dms.""" ham.reset(*dms_a) energy_a_0 = ham.compute_energy() focks_a = [np.zeros(dm_a.shape) for dm_a in dms_a] ham.compute_fock(*focks_a) delta_dms = [] for idm in xrange(ham.ndm): delta_dms.append(dms_b[idm] - dms_a[idm]) ham.reset_delta(*delta_dms) dots_a = [np.zeros(dm_a.shape) for dm_a in dms_a] ham.compute_dot_hessian(*dots_a) energy_a_1 = 0.0 energy_a_2 = 0.0 for idm in xrange(ham.ndm): energy_a_1 += np.einsum('ab,ba', focks_a[idm], delta_dms[idm])*ham.deriv_scale energy_a_2 += np.einsum('ab,ba', dots_a[idm], delta_dms[idm])*ham.deriv_scale**2 # print 'energy_a_0', energy_a_0 # print 'energy_a_1', energy_a_1 # print 'energy_a_2', energy_a_2 # Compute interpolation and compare energies_x = np.zeros(npoint) energies_2nd_order = np.zeros(npoint) derivs_x = np.zeros(npoint) derivs_2nd_order = np.zeros(npoint) for ipoint in xrange(npoint): x = xs[ipoint] dms_x = [] for idm in xrange(ham.ndm): dm_x = dms_a[idm]*(1-x) + dms_b[idm]*x dms_x.append(dm_x) ham.reset(*dms_x) energies_x[ipoint] = ham.compute_energy() ham.compute_fock(*focks_a) for idm in xrange(ham.ndm): derivs_x[ipoint] += np.einsum('ab,ba', focks_a[idm], delta_dms[idm]) * \ ham.deriv_scale energies_2nd_order[ipoint] = energy_a_0 + x*energy_a_1 + 0.5*x*x*energy_a_2 derivs_2nd_order[ipoint] = energy_a_1 + x*energy_a_2 # print '%5.2f %15.8f %15.8f' % (x, energies_x[ipoint], energies_2nd_order[ipoint]) if do_plot: # pragma: no cover import matplotlib.pyplot as pt pt.clf() pt.plot(xs, energies_x, 'ro') pt.plot(xs, energies_2nd_order, 'k-') pt.savefig('test_energies.png') pt.clf() pt.plot(xs, derivs_x, 'ro') pt.plot(xs, derivs_2nd_order, 'k-') pt.savefig('test_derivs.png') assert abs(energies_x - energies_2nd_order).max()/np.ptp(energies_x) < threshold assert abs(derivs_x - derivs_2nd_order).max()/np.ptp(derivs_x) < threshold return energy_a_0, energy_a_1, energy_a_2 # 1) using dms1 as reference point _energy1_0, _energy1_1, energy1_2 = check(dms1, dms2) # 2) using dms2 as reference point _energy2_0, _energy2_1, energy2_2 = check(dms2, dms1) if is_hf: # Final check: curvature should be the same in the HF case. assert abs(energy1_2 - energy2_2) < threshold