# solve for Eigenvalues state = adcc.adc2(scfres, n_singlets=1, conv_tol=1e-8) # setup modified transition moments dips = state.reference_state.operators.electric_dipole rhss = [ compute_modified_transition_moments(state.matrix, dip, "adc2") for dip in dips ] S = np.zeros((len(state.excitation_energies), 3, 3)) for f, ee in enumerate(state.excitation_energies): freq = ee / 2.0 matrix = ShiftedMat("adc2", state.ground_state, freq) preconditioner = JacobiPreconditioner(matrix) explicit_symmetrisation = IndexSymmetrisation(matrix) preconditioner.update_shifts(freq) response = [] # solve all systems of equations for mu in range(3): rhs = rhss[mu] x0 = preconditioner.apply(rhs) res = conjugate_gradient( matrix, rhs=rhs, x0=x0, callback=default_print, Pinv=preconditioner, conv_tol=1e-6, explicit_symmetrisation=explicit_symmetrisation ) response.append(res) for mu in range(3): for nu in range(mu, 3):
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