def test_obtain_guesses_by_inspection(self): from adcc.workflow import obtain_guesses_by_inspection refstate = cache.refstate["h2o_sto3g"] ground_state = adcc.LazyMp(refstate) matrix2 = adcc.AdcMatrix("adc2", ground_state) matrix1 = adcc.AdcMatrix("adc1", ground_state) # Test that the right number of guesses is returned ... for mat in [matrix1, matrix2]: for i in range(4, 9): res = obtain_guesses_by_inspection(mat, n_guesses=i, kind="singlet") assert len(res) == i for i in range(4, 9): res = obtain_guesses_by_inspection(matrix2, n_guesses=i, kind="triplet", n_guesses_doubles=2) assert len(res) == i with pytest.raises(InputError): obtain_guesses_by_inspection(matrix1, n_guesses=4, kind="any", n_guesses_doubles=2) with pytest.raises(InputError): obtain_guesses_by_inspection(matrix1, n_guesses=40, kind="any")
def dump_matrix(basis, method): key = basis.replace("*", "s").replace("-", "").lower() fn = "water_" + key + "_" + method + ".hdf5" if os.path.isfile(fn): with h5py.File(fn, "r") as fp: return np.asarray(fp["adc_matrix"]) mol = gto.M(atom="""O 0 0 0 H 0 0 1.795239827225189 H 1.693194615993441 0 -0.599043184453037""", basis=basis, unit="Bohr") scfres = scf.RHF(mol) scfres.conv_tol = 1e-13 scfres.kernel() mat = adcc.AdcMatrix(method, adcc.ReferenceState(scfres)) key = basis.replace("*", "s").replace("-", "").lower() mat = mat.to_dense_matrix() fn = "water_" + key + "_" + method + ".hdf5" if not os.path.isfile(fn): with h5py.File(fn, "w") as fp: fp.create_dataset("adc_matrix", data=mat, compression="gzip") with h5py.File(fn, "r") as fp: return np.asarray(fp["adc_matrix"])
def test_intermediates_adc2(self): ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"]) matrix = adcc.AdcMatrix("adc2", ground_state) assert isinstance(matrix.intermediates, Intermediates) intermediates = Intermediates(ground_state) matrix.intermediates = intermediates assert matrix.intermediates == intermediates
def test_adc2_shift_invert_triplets(self): refdata = cache.reference_data["h2o_sto3g"] matrix = adcc.AdcMatrix("adc2", LazyMp(cache.refstate["h2o_sto3g"])) conv_tol = 1e-5 shift = -0.5 # Construct shift and inverted matrix: shinv = IterativeInverse(AdcMatrixShifted(matrix, shift), conv_tol=conv_tol / 10, Pinv=JacobiPreconditioner, callback=cg_print) # Solve for triplets guesses = adcc.guesses_triplet(matrix, n_guesses=5, block="ph") symm = IndexSpinSymmetrisation(matrix, enforce_spin_kind="triplet") res = lanczos(shinv, guesses, n_ep=5, callback=la_print, explicit_symmetrisation=symm) assert res.converged # Undo spectral transformation and compare eigenvalues = sorted(1 / res.eigenvalues - shift) ref_triplets = refdata["adc2"]["triplet"]["eigenvalues"][:5] assert eigenvalues == approx(ref_triplets)
class TestAdcMatrixInterface(unittest.TestCase): def test_properties_adc2(self): case = "h2o_sto3g" method = "adc2" reference_state = cache.refstate[case] ground_state = adcc.LazyMp(reference_state) matrix = adcc.AdcMatrix(method, ground_state) assert matrix.ndim == 2 assert not matrix.is_core_valence_separated assert matrix.shape == (1640, 1640) assert len(matrix) == 1640 assert matrix.axis_blocks == ["ph", "pphh"] assert sorted(matrix.axis_spaces.keys()) == matrix.axis_blocks assert sorted(matrix.axis_lengths.keys()) == matrix.axis_blocks assert matrix.axis_spaces["ph"] == ["o1", "v1"] assert matrix.axis_spaces["pphh"] == ["o1", "o1", "v1", "v1"] assert matrix.axis_lengths["ph"] == 40 assert matrix.axis_lengths["pphh"] == 1600 assert matrix.reference_state == reference_state assert matrix.mospaces == reference_state.mospaces assert isinstance(matrix.timer, adcc.timings.Timer)
class TestAdcMatrixShifted(unittest.TestCase): def construct_matrices(self, case, shift): reference_state = cache.refstate[case] ground_state = adcc.LazyMp(reference_state) matrix = adcc.AdcMatrix("adc3", ground_state) shifted = AdcMatrixShifted(matrix, shift) return matrix, shifted
class TestAdcMatrixInterface(unittest.TestCase): def test_properties_adc2(self): case = "h2o_sto3g" method = "adc2" reference_state = cache.refstate[case] ground_state = adcc.LazyMp(reference_state) matrix = adcc.AdcMatrix(method, ground_state) assert matrix.ndim == 2 assert not matrix.is_core_valence_separated assert matrix.shape == (1640, 1640) assert len(matrix) == 1640 assert matrix.blocks == ["s", "d"] assert matrix.has_block("s") assert matrix.has_block("d") assert not matrix.has_block("t") assert matrix.block_spaces("s") == ["o1", "v1"] assert matrix.block_spaces("d") == ["o1", "o1", "v1", "v1"] assert matrix.reference_state == reference_state assert matrix.mospaces == reference_state.mospaces assert isinstance(matrix.timer, adcc.timings.Timer) assert isinstance(matrix.to_cpp(), libadcc.AdcMatrix)
def template_pcm_linear_response_formaldehyde(self, basis, method, backend): if method != "adc1": pytest.skip("Reference only exists for adc1.") c = config[backend] basename = f"formaldehyde_{basis}_pcm_{method}" result = c["data"][basename] run_hf = c["run_hf"] scfres = run_hf(static_data.xyz["formaldehyde"], basis, charge=0, multiplicity=1, conv_tol=1e-12, conv_tol_grad=1e-11, max_iter=150, pcm_options=c["pcm_options"]) assert_allclose(scfres.energy_scf, result["energy_scf"], atol=1e-8) matrix = adcc.AdcMatrix(method, scfres) solvent = AdcExtraTerm(matrix, {'ph_ph': block_ph_ph_0_pcm}) matrix += solvent assert len(matrix.extra_terms) state = adcc.run_adc(matrix, n_singlets=5, conv_tol=1e-7, environment=False) assert_allclose( state.excitation_energy_uncorrected, result["lr_excitation_energy"], atol=1e-5 ) state_cis = adcc.ExcitedStates(state, property_method="adc0") assert_allclose( state_cis.oscillator_strength, result["lr_osc_strength"], atol=1e-3 ) # invalid combination with pytest.raises(InputError): adcc.run_adc(scfres, method=method, n_singlets=5, environment={"linear_response": True, "ptlr": True}) # no environment specified with pytest.raises(InputError): adcc.run_adc(scfres, method=method, n_singlets=5) # automatically add coupling term state = adcc.run_adc(scfres, method=method, n_singlets=5, conv_tol=1e-7, environment="linear_response") assert_allclose( state.excitation_energy_uncorrected, result["lr_excitation_energy"], atol=1e-5 ) if backend == "psi4": # remove cavity files from PSI4 PCM calculations remove_cavity_psi4()
def test_adc2_triplets(self): refdata = cache.reference_data["h2o_sto3g"] matrix = adcc.AdcMatrix("adc2", LazyMp(cache.refstate["h2o_sto3g"])) # Solve for triplets guesses = adcc.guesses_triplet(matrix, n_guesses=6, block="ph") res = lanczos(matrix, guesses, n_ep=6, which="SM") ref_triplets = refdata["adc2"]["triplet"]["eigenvalues"][:6] assert res.converged assert res.eigenvalues == approx(ref_triplets)
def test_adc2_triplets(self): refdata = cache.reference_data["h2o_sto3g"] matrix = adcc.AdcMatrix("adc2", LazyMp(cache.refstate["h2o_sto3g"])) # Solve for triplets guesses = adcc.guesses_triplet(matrix, n_guesses=10, block="s") res = jacobi_davidson(matrix, guesses, n_ep=10) ref_triplets = refdata["adc2"]["triplet"]["eigenvalues"] assert res.converged assert res.eigenvalues == approx(ref_triplets)
class TestAdcMatrix(unittest.TestCase): def construct_matrix(self, case, method): refdata = cache.reference_data[case] matdata = refdata[method]["matrix"] if "cvs" in method: refstate = cache.refstate_cvs[case] else: refstate = cache.refstate[case] matrix = adcc.AdcMatrix(method, refstate) return matrix, matdata
def template_pe_linear_response_formaldehyde(self, basis, method, backend): if method != "adc2": pytest.skip("Reference only exists for adc2.") basename = f"formaldehyde_{basis}_pe_{method}" tm_result = tmole_data[basename] pe_options = {"potfile": pe_potentials["fa_6w"]} scfres = cached_backend_hf(backend, "formaldehyde", basis, pe_options=pe_options) assert_allclose(scfres.energy_scf, tm_result["energy_scf"], atol=1e-8) matrix = adcc.AdcMatrix(method, scfres) solvent = AdcExtraTerm(matrix, {'ph_ph': block_ph_ph_0_pe}) # manually add the coupling term matrix += solvent assert len(matrix.extra_terms) assert_allclose(matrix.ground_state.energy(2), tm_result["energy_mp2"], atol=1e-8) state = adcc.run_adc(matrix, n_singlets=5, conv_tol=1e-7, environment=False) assert_allclose(state.excitation_energy_uncorrected, tm_result["excitation_energy"], atol=1e-6) # invalid combination with pytest.raises(InputError): adcc.run_adc(scfres, method=method, n_singlets=5, environment={ "linear_response": True, "ptlr": True }) # no scheme specified with pytest.raises(InputError): adcc.run_adc(scfres, method=method, n_singlets=5) # automatically add coupling term state = adcc.run_adc(scfres, method=method, n_singlets=5, conv_tol=1e-7, environment="linear_response") assert_allclose(state.excitation_energy_uncorrected, tm_result["excitation_energy"], atol=1e-6)
def test_estimate_n_guesses(self): from adcc.workflow import estimate_n_guesses refstate = cache.refstate["h2o_sto3g"] ground_state = adcc.LazyMp(refstate) matrix = adcc.AdcMatrix("adc2", ground_state) # Check minimal number of guesses is 4 and at some point # we get more than four guesses assert 4 == estimate_n_guesses(matrix, n_states=1, singles_only=True) assert 4 == estimate_n_guesses(matrix, n_states=2, singles_only=True) for i in range(3, 20): assert i <= estimate_n_guesses( matrix, n_states=i, singles_only=True)
def test_adc1_linear_solve(self): conv_tol = 1e-9 matrix = adcc.AdcMatrix("adc1", cache.refstate["h2o_sto3g"]) rhs = adcc.guess_zero(matrix) rhs["s"].set_random() guess = rhs.copy() guess["s"].set_random() res = conjugate_gradient(matrix, rhs, guess, callback=cgprint, conv_tol=conv_tol) residual = matrix @ res.solution - rhs assert np.sqrt(residual @ residual) < conv_tol
def test_functionality(self): ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"]) matrix = adcc.AdcMatrix("adc2", ground_state) vectors = [adcc.guess_zero(matrix) for i in range(2)] for vec in vectors: vec.set_random() v, w = vectors with pytest.raises(AttributeError): v.pph with pytest.raises(AttributeError): v.pph = w.ph # setattr with expression z = adcc.zeros_like(v) z.ph = v.ph + w.ph z -= w np.testing.assert_allclose(v.ph.to_ndarray(), z.ph.to_ndarray())
def template_singles_view(self, method): if "cvs" in method: reference_state = cache.refstate_cvs["h2o_sto3g"] shape = (8, 8) spaces_s = ["o2", "v1"] else: reference_state = cache.refstate["h2o_sto3g"] shape = (40, 40) spaces_s = ["o1", "v1"] matrix = adcc.AdcMatrix(method, adcc.LazyMp(reference_state)) view = adcc.AdcBlockView(matrix, "s") assert view.ndim == 2 assert view.is_core_valence_separated == ("cvs" in method) assert view.shape == shape assert len(view) == shape[0] assert view.blocks == ["s"] assert view.has_block("s") assert not view.has_block("d") assert not view.has_block("t") assert view.block_spaces("s") == spaces_s assert view.reference_state == reference_state assert view.mospaces == reference_state.mospaces assert isinstance(view.timer, adcc.timings.Timer) assert view.to_cpp() == matrix.to_cpp() # Check diagonal diff = matrix.diagonal("s") - view.diagonal("s") assert diff.dot(diff) < 1e-12 # Check @ (one vector and multiple vectors) invec = adcc.guess_zero(matrix) invec["s"].set_random() # "d" left as zero invec_singles = adcc.AmplitudeVector(invec["s"]) ref = matrix @ invec res = view @ invec_singles diff = res["s"] - ref["s"] assert diff.dot(diff) < 1e-12 res = view @ [invec_singles, invec_singles, invec_singles] diff = [res[i]["s"] - ref["s"] for i in range(3)] assert max(d.dot(d) for d in diff) < 1e-12
def template_singles_view(self, method): if "cvs" in method: reference_state = cache.refstate_cvs["h2o_sto3g"] shape = (8, 8) spaces_ph = ["o2", "v1"] else: reference_state = cache.refstate["h2o_sto3g"] shape = (40, 40) spaces_ph = ["o1", "v1"] matrix = adcc.AdcMatrix(method, adcc.LazyMp(reference_state)) view = matrix.block_view("ph_ph") assert view.ndim == 2 assert view.is_core_valence_separated == ("cvs" in method) assert view.shape == shape assert len(view) == shape[0] assert view.axis_blocks == ["ph"] assert sorted(view.axis_spaces.keys()) == view.axis_blocks assert sorted(view.axis_lengths.keys()) == view.axis_blocks assert view.axis_spaces["ph"] == spaces_ph assert view.axis_lengths["ph"] == shape[0] assert view.reference_state == reference_state assert view.mospaces == reference_state.mospaces assert isinstance(view.timer, adcc.timings.Timer) # Check diagonal diff = matrix.diagonal().ph - view.diagonal().ph assert diff.dot(diff) < 1e-12 # Check @ (one vector and multiple vectors) invec = adcc.guess_zero(matrix) invec.ph.set_random() # "d" left as zero invec_singles = adcc.AmplitudeVector(ph=invec.ph) ref = matrix @ invec res = view @ invec_singles diff = res.ph - ref.ph assert diff.dot(diff) < 1e-12 res = view @ [invec_singles, invec_singles, invec_singles] diff = [res[i].ph - ref.ph for i in range(3)] assert max(d.dot(d) for d in diff) < 1e-12
def test_matvec_adc2(self): ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"]) matrix = adcc.AdcMatrix("adc2", ground_state) vectors = [adcc.guess_zero(matrix) for i in range(3)] for vec in vectors: vec.set_random() v, w, x = vectors # Compute references: refv = matrix.matvec(v) refw = matrix.matvec(w) refx = matrix.matvec(x) # @ operator (1 vector) resv = matrix @ v diffv = refv - resv assert diffv.ph.dot(diffv.ph) < 1e-12 assert diffv.pphh.dot(diffv.pphh) < 1e-12 # @ operator (multiple vectors) resv, resw, resx = matrix @ [v, w, x] diffs = [refv - resv, refw - resw, refx - resx] for i in range(3): assert diffs[i].ph.dot(diffs[i].ph) < 1e-12 assert diffs[i].pphh.dot(diffs[i].pphh) < 1e-12 # compute matvec resv = matrix.matvec(v) diffv = refv - resv assert diffv.ph.dot(diffv.ph) < 1e-12 assert diffv.pphh.dot(diffv.pphh) < 1e-12 resv = matrix.rmatvec(v) diffv = refv - resv assert diffv.ph.dot(diffv.ph) < 1e-12 assert diffv.pphh.dot(diffv.pphh) < 1e-12 # Test apply resv.ph = matrix.block_apply("ph_ph", v.ph) resv.ph += matrix.block_apply("ph_pphh", v.pphh) refv = matrix.matvec(v) diffv = resv.ph - refv.ph assert diffv.dot(diffv) < 1e-12
class TestAdcMatrixDenseExport(unittest.TestCase): def base_test(self, case, method, conv_tol=1e-8, **kwargs): kwargs.setdefault("n_states", 10) n_states = kwargs["n_states"] if "cvs" in method: refstate = cache.refstate_cvs[case] else: refstate = cache.refstate[case] matrix = adcc.AdcMatrix(method, refstate) state = adcc.run_adc(matrix, method=method, conv_tol=conv_tol, **kwargs) dense = matrix.to_dense_matrix() assert_allclose(dense, dense.T, rtol=1e-10, atol=1e-12) n_decimals = 10 spectrum = np.linalg.eigvalsh(dense) rounded = np.unique(np.round(spectrum, n_decimals))[:n_states] assert_allclose(state.excitation_energies, rounded, atol=10 * conv_tol)
def test_diagonalise_adcmatrix(self): from adcc.workflow import diagonalise_adcmatrix refdata = cache.reference_data["h2o_sto3g"] matrix = adcc.AdcMatrix("adc2", adcc.LazyMp(cache.refstate["h2o_sto3g"])) res = diagonalise_adcmatrix(matrix, n_states=3, kind="singlet", eigensolver="davidson") ref_singlets = refdata["adc2"]["singlet"]["eigenvalues"] assert res.converged assert res.eigenvalues == approx(ref_singlets[:3]) guesses = adcc.guesses_singlet(matrix, n_guesses=6, block="ph") res = diagonalise_adcmatrix(matrix, n_states=3, kind="singlet", guesses=guesses) ref_singlets = refdata["adc2"]["singlet"]["eigenvalues"] assert res.converged assert res.eigenvalues == approx(ref_singlets[:3]) with pytest.raises(InputError): # Too low tolerance res = diagonalise_adcmatrix(matrix, n_states=9, kind="singlet", eigensolver="davidson", conv_tol=1e-14) with pytest.raises(InputError): # Wrong solver method res = diagonalise_adcmatrix(matrix, n_states=9, kind="singlet", eigensolver="blubber") with pytest.raises(InputError): # Too few guesses res = diagonalise_adcmatrix(matrix, n_states=9, kind="singlet", eigensolver="davidson", guesses=guesses)
def test_matvec_adc2(self): ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"]) matrix = adcc.AdcMatrix("adc2", ground_state) cppmatrix = libadcc.AdcMatrix("adc2", ground_state) vectors = [adcc.guess_zero(matrix) for i in range(3)] for vec in vectors: vec["s"].set_random() vec["d"].set_random() v, w, x = vectors # Compute references: refv = adcc.empty_like(v) refw = adcc.empty_like(w) refx = adcc.empty_like(x) cppmatrix.compute_matvec(v.to_cpp(), refv.to_cpp()) cppmatrix.compute_matvec(w.to_cpp(), refw.to_cpp()) cppmatrix.compute_matvec(x.to_cpp(), refx.to_cpp()) # @ operator (1 vector) resv = matrix @ v diffv = refv - resv assert diffv["s"].dot(diffv["s"]) < 1e-12 assert diffv["d"].dot(diffv["d"]) < 1e-12 # @ operator (multiple vectors) resv, resw, resx = matrix @ [v, w, x] diffs = [refv - resv, refw - resw, refx - resx] for i in range(3): assert diffs[i]["s"].dot(diffs[i]["s"]) < 1e-12 assert diffs[i]["d"].dot(diffs[i]["d"]) < 1e-12 # compute matvec matrix.compute_matvec(v, resv) diffv = refv - resv assert diffv["s"].dot(diffv["s"]) < 1e-12 assert diffv["d"].dot(diffv["d"]) < 1e-12 matrix.compute_apply("ss", v["s"], resv["s"]) cppmatrix.compute_apply("ss", v["s"], refv["s"]) diffv = resv["s"] - refv["s"] assert diffv.dot(diffv) < 1e-12
def base_adc2(self, kind, guess_function, max_iter=100): refdata = cache.reference_data["h2o_sto3g"] matrix = adcc.AdcMatrix("adc2", cache.refstate["h2o_sto3g"]) conv_tol = 1e-6 guesses = guess_function(matrix, n_guesses=1) symm = IndexSpinSymmetrisation(matrix, enforce_spin_kind=kind) inverse = IterativeInverse(matrix, Pinv=JacobiPreconditioner, conv_tol=conv_tol / 10, construct_guess=guess_from_previous) res = power_method(inverse, guesses[0], conv_tol=conv_tol, explicit_symmetrisation=symm, callback=powprint, max_iter=max_iter) ref_singlets = refdata["adc2"][kind]["eigenvalues"] assert res.converged assert 1 / res.eigenvalues[0] == approx(ref_singlets[0])
def test_construct_adcmatrix(self): from adcc.workflow import construct_adcmatrix # # Construction from hfdata # hfdata = cache.hfdata["h2o_sto3g"] res = construct_adcmatrix(hfdata, method="adc3") assert isinstance(res, adcc.AdcMatrix) assert res.method == adcc.AdcMethod("adc3") assert res.mospaces.core_orbitals == [] assert res.mospaces.frozen_core == [] assert res.mospaces.frozen_virtual == [] res = construct_adcmatrix(hfdata, method="cvs-adc3", core_orbitals=1) assert isinstance(res, adcc.AdcMatrix) assert res.method == adcc.AdcMethod("cvs-adc3") assert res.mospaces.core_orbitals == [0, 7] assert res.mospaces.frozen_core == [] assert res.mospaces.frozen_virtual == [] res = construct_adcmatrix(hfdata, method="adc2", frozen_core=1) assert res.mospaces.core_orbitals == [] assert res.mospaces.frozen_core == [0, 7] assert res.mospaces.frozen_virtual == [] res = construct_adcmatrix(hfdata, method="adc2", frozen_virtual=1) assert res.mospaces.core_orbitals == [] assert res.mospaces.frozen_core == [] assert res.mospaces.frozen_virtual == [6, 13] res = construct_adcmatrix(hfdata, method="adc2", frozen_virtual=1, frozen_core=1) assert res.mospaces.core_orbitals == [] assert res.mospaces.frozen_core == [0, 7] assert res.mospaces.frozen_virtual == [6, 13] invalid_cases = [ dict(), # Missing method dict(method="dadadad"), # Unknown method dict(frozen_core=1), # Missing method dict(frozen_virtual=3), # Missing method dict(core_orbitals=4), # Missing method dict(method="cvs-adc2"), # No core_orbitals dict(method="cvs-adc2", frozen_core=1), dict(method="adc2", core_orbitals=3), # Extra core parameter dict(method="adc2", core_orbitals=3, frozen_virtual=2), ] for case in invalid_cases: with pytest.raises(InputError): construct_adcmatrix(hfdata, **case) # # Construction from LazyMp or ReferenceState # refst_ful = cache.refstate["h2o_sto3g"] refst_cvs = cache.refstate_cvs["h2o_sto3g"] gs_ful, gs_cvs = adcc.LazyMp(refst_ful), adcc.LazyMp(refst_cvs) for obj in [gs_ful, refst_ful]: res = construct_adcmatrix(obj, method="adc2") assert isinstance(res, adcc.AdcMatrix) assert res.method == adcc.AdcMethod("adc2") with pytest.raises(InputError, match=r"Cannot run a core-valence"): construct_adcmatrix(obj, method="cvs-adc2x") with pytest.warns(UserWarning, match=r"^Ignored frozen_core parameter"): construct_adcmatrix(obj, frozen_core=3, method="adc1") with pytest.warns(UserWarning, match=r"^Ignored frozen_virtual parameter"): construct_adcmatrix(obj, frozen_virtual=1, method="adc3") for obj in [gs_cvs, refst_cvs]: res = construct_adcmatrix(obj, method="cvs-adc2x") assert isinstance(res, adcc.AdcMatrix) assert res.method == adcc.AdcMethod("cvs-adc2x") with pytest.raises(InputError): construct_adcmatrix(obj) # Missing method with pytest.raises(InputError, match=r"Cannot run a general"): construct_adcmatrix(obj, method="adc2") with pytest.warns(UserWarning, match=r"^Ignored core_orbitals parameter"): construct_adcmatrix(obj, core_orbitals=2, method="cvs-adc1") # # Construction from ADC matrix # mtx_ful = adcc.AdcMatrix("adc2", gs_ful) mtx_cvs = adcc.AdcMatrix("cvs-adc2", gs_cvs) assert construct_adcmatrix(mtx_ful) == mtx_ful assert construct_adcmatrix(mtx_ful, method="adc2") == mtx_ful assert construct_adcmatrix(mtx_cvs) == mtx_cvs assert construct_adcmatrix(mtx_cvs, method="cvs-adc2") == mtx_cvs with pytest.warns(UserWarning, match=r"Ignored method parameter"): construct_adcmatrix(mtx_ful, method="adc3") with pytest.warns(UserWarning, match=r"^Ignored core_orbitals parameter"): construct_adcmatrix(mtx_cvs, core_orbitals=2) with pytest.warns(UserWarning, match=r"^Ignored frozen_core parameter"): construct_adcmatrix(mtx_ful, frozen_core=3) with pytest.warns(UserWarning, match=r"^Ignored frozen_virtual parameter"): construct_adcmatrix(mtx_cvs, frozen_virtual=1)
def test_extra_term(self): ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"]) matrix_adc1 = adcc.AdcMatrix("adc1", ground_state) with pytest.raises(TypeError): matrix_adc1 += 42 matrix = adcc.AdcMatrix("adc2", ground_state) with pytest.raises(TypeError): adcc.AdcMatrix("adc2", ground_state, diagonal_precomputed=42) with pytest.raises(ValueError): adcc.AdcMatrix("adc2", ground_state, diagonal_precomputed=matrix.diagonal() + 42) with pytest.raises(TypeError): AdcExtraTerm(matrix, "fail") with pytest.raises(TypeError): AdcExtraTerm(matrix, {"fail": "not_callable"}) shift = -0.3 shifted = AdcMatrixShifted(matrix, shift) # TODO: need to use AmplitudeVector to differentiate between # diagonals for ph and pphh # if we just pass numbers, i.e., shift # we get 2*shift on the diagonal ones = matrix.diagonal().ones_like() def __shift_ph(hf, mp, intermediates): def apply(invec): return adcc.AmplitudeVector(ph=shift * invec.ph) diag = adcc.AmplitudeVector(ph=shift * ones.ph) return AdcBlock(apply, diag) def __shift_pphh(hf, mp, intermediates): def apply(invec): return adcc.AmplitudeVector(pphh=shift * invec.pphh) diag = adcc.AmplitudeVector(pphh=shift * ones.pphh) return AdcBlock(apply, diag) extra = AdcExtraTerm(matrix, { 'ph_ph': __shift_ph, 'pphh_pphh': __shift_pphh }) # cannot add to 'pphh_pphh' in ADC(1) matrix with pytest.raises(ValueError): matrix_adc1 += extra shifted_2 = matrix + extra shifted_3 = extra + matrix for manual in [shifted_2, shifted_3]: assert_allclose(shifted.diagonal().ph.to_ndarray(), manual.diagonal().ph.to_ndarray(), atol=1e-12) assert_allclose(shifted.diagonal().pphh.to_ndarray(), manual.diagonal().pphh.to_ndarray(), atol=1e-12) vec = adcc.guess_zero(matrix) vec.set_random() ref = shifted @ vec ret = manual @ vec diff_s = ref.ph - ret.ph diff_d = ref.pphh - ret.pphh assert np.max(np.abs(diff_s.to_ndarray())) < 1e-12 assert np.max(np.abs(diff_d.to_ndarray())) < 1e-12
def test_diagonal_adc2(self): ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"]) matrix = adcc.AdcMatrix("adc2", ground_state) cppmatrix = libadcc.AdcMatrix("adc2", ground_state) diff = cppmatrix.diagonal("s") - matrix.diagonal("s") assert diff.dot(diff) < 1e-12
assert matrix.axis_spaces["ph"] == ["o1", "v1"] assert matrix.axis_spaces["pphh"] == ["o1", "o1", "v1", "v1"] assert matrix.axis_lengths["ph"] == 40 assert matrix.axis_lengths["pphh"] == 1600 assert matrix.reference_state == reference_state assert matrix.mospaces == reference_state.mospaces assert isinstance(matrix.timer, adcc.timings.Timer) def test_properties_cvs_adc1(self): case = "h2o_sto3g" method = "cvs-adc1" reference_state = cache.refstate_cvs[case] ground_state = adcc.LazyMp(reference_state) matrix = adcc.AdcMatrix(method, ground_state) assert matrix.ndim == 2 assert matrix.is_core_valence_separated assert matrix.shape == (8, 8) assert len(matrix) == 8 assert matrix.axis_blocks == ["ph"] assert sorted(matrix.axis_spaces.keys()) == matrix.axis_blocks assert sorted(matrix.axis_lengths.keys()) == matrix.axis_blocks assert matrix.axis_spaces["ph"] == ["o2", "v1"] assert matrix.axis_lengths["ph"] == 8 assert matrix.reference_state == reference_state assert matrix.mospaces == reference_state.mospaces assert isinstance(matrix.timer, adcc.timings.Timer)
def test_reference_h2o_adc2x(self): ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"]) matrix = adcc.AdcMatrix("adc2x", ground_state) self.base_reference(matrix, self.get_ref_h2o())
def test_reference_cn_adc3(self): ground_state = adcc.LazyMp(cache.refstate["cn_sto3g"]) matrix = adcc.AdcMatrix("adc3", ground_state) self.base_reference(matrix, self.get_ref_cn())
def relax_cvs(scfres, method, state, ctol=5e-5): singles_block_only = False if adcc.AdcMethod(method).level > 1 and "d" not in state.matrix.blocks: singles_block_only = True # Singles block only method refstate = adcc.ReferenceState(scfres) origmatrix = adcc.AdcBlockView(adcc.AdcMatrix(method, refstate), "s") else: refstate = adcc.ReferenceState(scfres) origmatrix = adcc.AdcMatrix(method, refstate) matrix = AdcMatrixShifted(origmatrix) explicit_symmetrisation = IndexSpinSymmetrisation( matrix, enforce_spin_kind=state.kind) assert state.kind == "singlet" fullvec = [ guess_zero(matrix, spin_block_symmetrisation="symmetric") for i in range(len(state.excitation_vectors)) ] for i in range(len(state.excitation_vectors)): project_amplitude(state.excitation_vectors[i], fullvec[i]) preconditioner = JacobiPreconditioner(matrix) relaxed_vec = [] relaxed_ene = [] residual_norms = [] for i in range(len(state.excitation_vectors)): print("=================") print(" State {}".format(i)) print("=================") vec = fullvec[i].copy( ) # Not sure this copy is needed, do it for safety origvec = vec ene = state.excitation_energies[i] eneold = ene histories = [] residual = 100000 xold = vec preconditioner.update_shifts(ene - 1e-2) matrix.update_omega(ene - 1e-3) print("--> Starting energy {}: {}".format(i, ene)) for it in range(100): eps = 1e-3 # numerical fuzzing to improve conditioning if residual > eps / 10 and it > 0: matrix.update_omega(ene - eps) preconditioner.update_shifts(ene - eps) res = conjugate_gradient( matrix, rhs=xold, x0=xold, callback=default_print, Pinv=preconditioner, conv_tol=ctol / 10, max_iter=400, ) x = res.solution x = explicit_symmetrisation.symmetrise([x], [origvec])[0] x /= np.sqrt(x @ x) ene = x @ matrix.matmul_orig(x) enediff = ene - eneold overlap = np.sqrt(np.abs(origvec @ x)) resres = matrix.matmul_orig(x) - ene * x residual = np.sqrt(resres @ resres) print("--> Energy {}: {} (enediff: {})" "".format(it, ene, enediff)) print("--> Overlap {}: {}".format(it, overlap)) print("--> Residual {}: {}".format(it, residual)) if np.abs(overlap - 1) > 0.2: if not histories: if i == 0: print( " !!! Low overlap detected and got no history" "... trying again") xold = origvec else: raise RuntimeError("Low overlap and got no history.") # Pick the energy of the historic result with the best overlap # (smallest aberration from 1) ene = sorted(histories, key=lambda x: x[1])[0][0] + eps print( " !!! Low overlap detected! Changing shift to {:.6g} " "and trying again !!!".format(ene)) xold = origvec elif residual < ctol: print("--> converged") break else: xold = x eneold = ene histories.append((ene, np.abs(overlap - 1))) residual_norms.append(np.sqrt(resres @ resres)) relaxed_vec.append(x) relaxed_ene.append(ene) class CvsRelaxationState: pass res = CvsRelaxationState() res.matrix = origmatrix res.kind = "singlet" res.eigenvectors = relaxed_vec res.eigenvalues = np.array(relaxed_ene) property_method = None if singles_block_only: # To not get crashes on property calculation (missing doubles part) property_method = "adc1" sstate = adcc.ExcitedStates(res, method=method, property_method=property_method) sstate.residual_norms = np.array(residual_norms) return sstate