Skip to content

new casida solver#194

Open
John-zzh wants to merge 10 commits into
pyscf:masterfrom
John-zzh:ris2
Open

new casida solver#194
John-zzh wants to merge 10 commits into
pyscf:masterfrom
John-zzh:ris2

Conversation

@John-zzh
Copy link
Copy Markdown
Contributor

now support ECP.

@MatthewRHermes
Copy link
Copy Markdown
Collaborator

Can you add a short unit test that validates that this new feature or bugfix works?

@John-zzh John-zzh closed this May 22, 2026
@John-zzh John-zzh changed the title fix ECP bug new casidai solver May 22, 2026
@John-zzh John-zzh changed the title new casidai solver new casida solver May 22, 2026
@John-zzh
Copy link
Copy Markdown
Contributor Author

John-zzh commented May 22, 2026

Can you add a short unit test that validates that this new feature or bugfix works?

Thanks for asking, after checking, now I think there is no such bug....

This PR inlcudes:
A better TDDFT solver, project A+B and A-B into subspace as a+b and a-b, more memory efficient and mathmetically equvalent to the previous solver (project A and B into subspace as a and b).

The test examples passed in various setup.

@John-zzh John-zzh reopened this May 22, 2026
Comment on lines +398 to +542
# def TDDFT_subspace_eigen_solver2(a, b, sigma, pi, nroots):
# ''' [ a b ] x - [ σ π] x Ω = 0 '''
# ''' [ b a ] y [-π -σ] y = 0 '''
# original_dtype = a.dtype
# if original_dtype != np.float64:
# a = a.astype(np.float64)
# b = b.astype(np.float64)
# sigma = sigma.astype(np.float64)
# pi = pi.astype(np.float64)

# d = abs(np.diag(sigma))
# d_mh = d**(-0.5)

# s_m_p = np.einsum('i,ij,j->ij', d_mh, sigma - pi, d_mh)

# '''LU = d^−1/2 (σ − π) d^−1/2'''
# ''' A = LU '''
# L, U = scipy.linalg.lu(s_m_p, permute_l=True)
# L_inv = np.linalg.inv(L)
# U_inv = np.linalg.inv(U)


# U_invT = U_inv.T
# '''U^-T d^−1/2 (a−b) d^-1/2 U^-1 = GG^T '''
# d_amb_d = np.einsum('i,ij,j->ij', d_mh, a-b, d_mh)
# GGT = np.dot(U_invT, np.dot(d_amb_d, U_inv))

# G = np.linalg.cholesky(GGT)
# if np.any(np.isnan(G)):
# eig, eigv = np.linalg.eigh(GGT)
# if eig[0] < -1e-4:
# error_msg = (
# "GGT matrix is not positive definite.\n"
# "SCF not correctly converged is likely to cause this error.\n"
# "For example, scf converged to the wrong state.\n"
# )
# raise RuntimeError(error_msg)

# G_inv = np.linalg.inv(G)

# ''' M = G^T L^−1 d^−1/2 (a+b) d^−1/2 L^−T G '''
# d_apb_d = np.einsum('i,ij,j->ij', d_mh, a+b, d_mh)
# M = np.dot(G.T, np.dot(L_inv, np.dot(d_apb_d, np.dot(L_inv.T, G))))

# omega2, Z = np.linalg.eigh(M)
# if np.any(omega2 <= 0):
# idx = np.nonzero(omega2 > 0)[0]
# omega2 = omega2[idx[:nroots]]
# Z = Z[:,idx[:nroots]]
# else:
# omega2 = omega2[:nroots]
# Z = Z[:,:nroots]
# omega = omega2**0.5

# ''' It requires Z^T Z = 1/Ω '''
# ''' x+y = d^−1/2 L^−T GZ Ω^-0.5 '''
# ''' x−y = d^−1/2 U^−1 G^−T Z Ω^0.5 '''
# x_p_y = np.einsum('i,ik,k->ik', d_mh, L_inv.T.dot(G.dot(Z)), omega**-0.5)
# x_m_y = np.einsum('i,ik,k->ik', d_mh, U_inv.dot(G_inv.T.dot(Z)), omega**0.5)

# x = (x_p_y + x_m_y)/2
# y = x_p_y - x

# if original_dtype != np.float64:
# omega = omega.astype(original_dtype)
# x = x.astype(original_dtype)
# y = y.astype(original_dtype)
# return omega, x, y

# def TDDFT_subspace_eigen_solver3(a, b, sigma, pi, k):
# ''' [ a b ] x - [ σ π] x Ω = 0
# [ b a ] y [-π -σ] y = 0
# AT=BTΩ
# B^-1/2 A B^-1/2 B^1/2 T = B^1/2 T Ω
# MZ = Z Ω
# M = B^-1/2 A B^-1/2
# Z = B^1/2 T
# '''
# half_size = a.shape[0]
# A = np.empty((2*half_size,2*half_size))
# A[:half_size,:half_size] = a[:,:]
# A[:half_size,half_size:] = b[:,:]
# A[half_size:,:half_size] = b[:,:]
# A[half_size:,half_size:] = a[:,:]

# B = np.empty_like(A)
# B[:half_size,:half_size] = sigma[:,:]
# B[:half_size,half_size:] = pi[:,:]
# B[half_size:,:half_size] = -pi[:,:]
# B[half_size:,half_size:] = -sigma[:,:]
# #B^-1/2
# B_neg_tmp = matrix_power(B, -0.5)
# M = np.dot(B_neg_tmp, A) # B^-1/2 A
# M = np.dot(M, B_neg_tmp) # B^-1/2 A B^-1/2
# omega, Z = np.linalg.eigh(M)

# omega = omega[half_size:k]
# Z = Z[:, half_size:k]

# T = np.dot(B_neg_tmp, Z)
# x = T[:half_size,:]
# y = T[half_size:,:]

# return omega, x, y

# def TDDFT_subspace_eigen_solver(a, b, sigma, pi, k):
# ''' [ a b ] x - [ σ π] x Ω = 0
# [ b a ] y [-π -σ] y = 0
# AT=BTΩ
# A^1/2 T = A^-1/2 B A^-1/2 A^1/2 T Ω
# MZ = Z 1/Ω
# M = A^-1/2 B A^-1/2 A^1/2
# Z = A^1/2 T
# Z is always returned as normlized vectors, which are not what we wanted
# because Z^T Z = [x]^T A^1/2 A^1/2 [x] = [x]^T [ a b ] [x] = [x]^T [ σ π] x Ω = Ω
# [y] [y] [y] [ b a ] [y] [y] [-π -σ] y
# therefore Z=Z*(Ω**0.5)
# k: N_states
# '''
# half_size = a.shape[0]
# A = np.empty((2*half_size,2*half_size))
# A[:half_size,:half_size] = a[:,:]
# A[:half_size,half_size:] = b[:,:]
# A[half_size:,:half_size] = b[:,:]
# A[half_size:,half_size:] = a[:,:]
# B = np.empty_like(A)
# B[:half_size,:half_size] = sigma[:,:]
# B[:half_size,half_size:] = pi[:,:]
# B[half_size:,:half_size] = -pi[:,:]
# B[half_size:,half_size:] = -sigma[:,:]
# #A^-1/2
# A_neg_tmp = matrix_power(A, -0.5, 1e-14)
# M = np.dot(A_neg_tmp, B)
# M = np.dot(M,A_neg_tmp )
# omega, Z = np.linalg.eigh(M)

# omega = 1/omega[-k:][::-1]
# Z = Z[:, -k:][:, ::-1]
# Z = Z*(omega**0.5)

# T = np.dot(A_neg_tmp, Z)
# x = T[:half_size,:]
# y = T[half_size:,:]

# return omega, x, y
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please clean up.

Comment thread pyscf/tdscf/ris.py
Comment on lines +121 to +137
# ---

# auxmol = mol.copy(deep=False)
# auxmol.verbose = 0
# auxmol_basis_keys = mol._basis.keys()
# aux_basis = get_minimal_auxbasis(
# auxmol_basis_keys, theta, fitting_basis, excludeHs=excludeHs)
# auxmol.basis = aux_basis
# auxmol._basis = auxmol.format_basis(aux_basis)

# pre_env = np.asarray(mol._env[:gto.PTR_ENV_START], dtype=np.float64)
# auxmol._atm, auxmol._bas, auxmol._env = auxmol.make_env(
# mol._atom, auxmol._basis, pre_env, mol.nucmod, mol.nucprop)

# auxmol._ecpbas = np.zeros((0, gto.mole.BAS_SLOTS), dtype=np.int32)
# auxmol._built = True
# return auxmol
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please clean up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants