Skip to content

Commit e365079

Browse files
fix the memory issue (#322)
1 parent 8bcd26d commit e365079

1 file changed

Lines changed: 53 additions & 40 deletions

File tree

dptb/nn/energy.py

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -163,47 +163,60 @@ def solve(self, h_container, s_container, kpoints: Union[list, torch.Tensor, np
163163
eigvals_list = []
164164
eigvecs_list = []
165165

166-
for k in kpoints:
167-
hk = h_container.sample_k(k, symm=True)
168-
169-
if s_container is not None:
170-
sk = s_container.sample_k(k, symm=True)
171-
hk -= self.sigma * sk
172-
A = hk.to_scipy(format="csr")
173-
M = sk
174-
else:
175-
hk.shift(-self.sigma)
176-
A = hk.to_scipy(format="csr")
177-
M = None
178-
179-
A.sort_indices()
180-
A.sum_duplicates()
181-
N = A.shape[0]
182-
183-
# Try PARDISO first, fall back to scipy SuperLU if PARDISO fails
184-
# (MKL PARDISO has a known bug with certain block-structured patterns)
185-
solver = PyPardisoSolver(mtype=13)
186-
solver.factorize(A)
187-
188-
def matvec(b):
189-
return solver.solve(A, b)
166+
# Create a single solver instance and reuse it across k-points.
167+
# PARDISO stores LU factors in opaque `pt` handles; creating a new
168+
# solver per k-point without calling free_memory() leaks all that
169+
# internal MKL memory.
170+
solver = PyPardisoSolver(mtype=13)
171+
172+
try:
173+
for k in kpoints:
174+
hk = h_container.sample_k(k, symm=True)
190175

191-
Op = LinearOperator((N, N), matvec=matvec, dtype=A.dtype)
192-
193-
try:
194-
# Use larger NCV to help convergence, especially for clustered eigenvalues
195-
ncv = max(2*self.neig + 1, 20)
196-
vals, vecs = eigsh(A=hk, M=M, k=self.neig, sigma=0.0, OPinv=Op, mode=self.mode, which="LM", ncv=ncv)
197-
except Exception:
198-
# Retry with larger NCV if ARPACK fails (e.g. error 3: No shifts could be applied)
199-
# This often happens when eigenvalues are clustered near the shift
200-
ncv = max(5*self.neig, 50)
201-
vals, vecs = eigsh(A=hk, M=M, k=self.neig, sigma=0.0, OPinv=Op, mode=self.mode, which="LM", ncv=ncv)
202-
203-
eigvals_list.append(vals + self.sigma)
204-
if return_eigenvectors:
205-
eigvecs_list.append(vecs)
206-
176+
if s_container is not None:
177+
sk = s_container.sample_k(k, symm=True)
178+
hk -= self.sigma * sk
179+
A = hk.to_scipy(format="csr")
180+
M = sk
181+
else:
182+
hk.shift(-self.sigma)
183+
A = hk.to_scipy(format="csr")
184+
M = None
185+
186+
A.sort_indices()
187+
A.sum_duplicates()
188+
N = A.shape[0]
189+
190+
solver.factorize(A)
191+
192+
def matvec(b):
193+
return solver.solve(A, b)
194+
195+
Op = LinearOperator((N, N), matvec=matvec, dtype=A.dtype)
196+
197+
try:
198+
# Use larger NCV to help convergence, especially for clustered eigenvalues
199+
ncv = max(2*self.neig + 1, 20)
200+
vals, vecs = eigsh(A=hk, M=M, k=self.neig, sigma=0.0, OPinv=Op, mode=self.mode, which="LM", ncv=ncv)
201+
except Exception:
202+
# Retry with larger NCV if ARPACK fails (e.g. error 3: No shifts could be applied)
203+
# This often happens when eigenvalues are clustered near the shift
204+
ncv = max(5*self.neig, 50)
205+
vals, vecs = eigsh(A=hk, M=M, k=self.neig, sigma=0.0, OPinv=Op, mode=self.mode, which="LM", ncv=ncv)
206+
207+
# Release PARDISO's internal LU factorization memory for this
208+
# k-point before moving to the next one. Without this, the
209+
# factorization buffers from *every* k-point accumulate.
210+
solver.free_memory()
211+
del Op
212+
213+
eigvals_list.append(vals + self.sigma)
214+
if return_eigenvectors:
215+
eigvecs_list.append(vecs)
216+
finally:
217+
# Guarantee all internal PARDISO memory is released even on error.
218+
solver.free_memory(everything=True)
219+
207220
if return_eigenvectors:
208221
return eigvals_list, eigvecs_list
209222
else:

0 commit comments

Comments
 (0)