1919
2020
2121from gpu4pyscf .tdscf import math_helper
22- from gpu4pyscf .tdscf .math_helper import gpu_mem_info , release_memory
22+ from gpu4pyscf .tdscf .math_helper import gpu_mem_info , release_memory , get_avail_gpumem , get_avail_cpumem
2323from gpu4pyscf .lib .cupy_helper import asarray as cuasarray
2424
2525
@@ -260,8 +260,7 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
260260 initguess_fn = None , precond_fn = None , rhs = None ,
261261 omega_shift = None , n_states = 20 ,conv_tol = 1e-5 ,
262262 max_iter = 35 , extra_init = 8 , gs_initial = False , gram_schmidt = True ,
263- restart_iter = None ,
264- single = False , in_ram = False , print_eigeneV_along = False ,
263+ restart_subspace = None , single = False , in_ram = False ,
265264 verbose = logger .NOTE ):
266265 '''
267266 This solver is used to solve the following problems:
@@ -332,17 +331,16 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
332331 maximum iterations
333332 extra_init: int
334333 extra number of states to be initialized
335- restart_iter: int or None
336- restart the Krylov solver periodically after this iteration. Default None, no restart.
334+ restart_subspace: int or None
335+ restart the Krylov solver periodically if the subspace size is larger than this value.
336+ Default None, no restart.
337337 gs_initial: bool
338338 apply gram_schmidt procedure on the initial guess,
339339 only in the case of gram_schmidt = True, but given wired initial guess
340340 gram_schmidt: bool
341341 use Gram-Schmidt orthogonalization
342342 single: bool
343343 use single precision
344- print_eigeneV_along:
345- print energies in each iteration
346344 verbose: logger.Logger
347345 logger object
348346
@@ -404,13 +402,25 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
404402 # record the initial size of the Krylov subspace
405403 n_init = size_new
406404
407- if restart_iter is not None and restart_iter > 0 :
408- max_N_mv = size_new + restart_iter * n_states
405+ log .info (f'single trial vector X_ia size: { A_size * hdiag .itemsize / 1024 ** 2 :.2f} MB' )
406+ if restart_subspace is None :
407+ ''' calculate the maximum number of vectors allowed by the memory'''
408+ if in_ram :
409+ available_mem = get_avail_cpumem ()
410+ else :
411+ available_mem = get_avail_gpumem ()
412+
413+ restart_subspace = int ((available_mem * 0.9 ) // (2 * A_size * hdiag .itemsize ))
414+ log .info (f'the maximum number of vectors allowed by the memory is { restart_subspace } ' )
409415 else :
410- max_N_mv = size_new + max_iter * n_states
416+ log .info (f'user specified the maximum number of vectors is { restart_subspace } ' )
417+
418+ max_N_mv = min (size_new + max_iter * n_states , restart_subspace )
419+ log .info (f'the maximum number of vectors in V_holder and W_holder is { max_N_mv } ' )
411420
412421 # Initialize arrays
413422 V_holder_mem = max_N_mv * A_size * hdiag .itemsize / 1024 ** 3
423+
414424 if in_ram :
415425 rss = current_memory ()[0 ] / 1024 # current memory usage in GB
416426 log .info (f'the maximum CPU memory usage throughout the Krylov solver is around { 2 * V_holder_mem + rss :.2f} GB' )
@@ -566,6 +576,7 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
566576 log .info (gpu_mem_info (' MVP stored in W_holder' ))
567577
568578 _time_add (log , t_mvp , t0 )
579+ log .timer (f' MVP total cost' , * t0 )
569580
570581 ''' Project into Krylov subspace '''
571582 t0 = log .init_timer ()
@@ -607,8 +618,7 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
607618
608619 omega = omega [:n_states ]
609620 x = x [:, :n_states ]
610- if print_eigeneV_along :
611- log .info (f' Energies (eV): { [round (e ,3 ) for e in (omega * HARTREE2EV ).tolist ()]} ' )
621+ log .info (f' Energies (eV): { [round (e ,3 ) for e in (omega * HARTREE2EV ).tolist ()]} ' )
612622
613623 elif problem_type == 'linear' :
614624 x = cp .linalg .solve (sub_A , sub_rhs )
@@ -690,7 +700,7 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
690700 data = {
691701 "con_tol" : conv_tol ,
692702 "max_iter" : max_iter ,
693- "restart_iter " : restart_iter ,
703+ "restart_subspace " : restart_subspace ,
694704 "in_ram" : in_ram ,
695705 "problem_type" : problem_type ,
696706 "n_states" : n_states ,
@@ -719,9 +729,12 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
719729
720730 else :
721731
722- if restart_iter is not None and (ii + 1 ) % restart_iter == 0 :
723- log .info (f' !!! restarting Krylov solver at iteration { ii + 1 } (every { restart_iter } iterations)' )
732+ unconverged_idx = cp .where (r_norms .ravel () > conv_tol )[0 ]
733+ log .info (f' number of unconverged states: { unconverged_idx .size } ' )
734+
724735
736+ if restart_subspace is not None and size_new + unconverged_idx .size > restart_subspace :
737+ log .info (f' !!! restart subspace (subspace { size_new + unconverged_idx .size } > { restart_subspace } )' )
725738 ''' fill N_state solution into the V_holder, but keep the initial guess vectors
726739 to fully remove the numerical noise, W_holder is also restarted
727740 '''
@@ -742,9 +755,6 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
742755 # residual_unconv = residual[index_bool, :] with boolean indexing creates a copy, which costs extra memory
743756 # instead, manually move the unconverged residual vectors forehead, use residual[:unconverged_idx.size, :] to save memory
744757
745- unconverged_idx = cp .where (r_norms .ravel () > conv_tol )[0 ]
746- log .info (f' number of unconverged states: { unconverged_idx .size } ' )
747-
748758 pos = 0
749759 for idx in unconverged_idx :
750760 if idx != pos :
@@ -769,12 +779,11 @@ def krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue',
769779 t0 = log .init_timer ()
770780 log .info (gpu_mem_info (' ▸ Preconditioning ends' ))
771781
772- # _V_holder, size_new = fill_holder(V_holder, size_old, X_new)
773- log .info (' putting new guesses into the holder' )
782+ log .info (' putting new guesses into the holder' )
774783
775784 size_old = size_new
776785 size_new = fill_holder (V_holder , size_old , X_new )
777- log .timer (' new guesses put into the holder' , * t0 )
786+ log .timer (' new guesses put into the holder' , * t0 )
778787
779788 del X_new , residual
780789 release_memory ()
@@ -826,8 +835,8 @@ def nested_krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue'
826835 init_mvp = None , precond_mvp = None , extra_init = 3 , extra_init_diag = 8 ,
827836 init_conv_tol = 1e-3 , init_max_iter = 10 ,
828837 precond_conv_tol = 1e-2 , precond_max_iter = 10 ,
829- init_restart_iter = None , precond_restart_iter = None , restart_iter = None ,
830- in_ram = False , print_eigeneV_along = False ):
838+ init_restart_subspace = None , precond_restart_subspace = None , restart_subspace = None ,
839+ in_ram = False ):
831840 '''
832841 Wrapper for Krylov solver to handle preconditioned eigenvalue, linear, or shifted linear problems.
833842 requires the non-diagonal approximation of A matrix, i.e., ris approximation.
@@ -892,7 +901,7 @@ def nested_krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue'
892901 problem_type = init_problem_type , hdiag = hdiag ,
893902 matrix_vector_product = init_mvp ,
894903 conv_tol = init_conv_tol , max_iter = init_max_iter ,
895- restart_iter = init_restart_iter ,
904+ restart_subspace = init_restart_subspace ,
896905 gram_schmidt = gram_schmidt , single = single , verbose = log .verbose - 2
897906 )
898907 else :
@@ -909,7 +918,7 @@ def nested_krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue'
909918 problem_type = precond_problem_type , hdiag = hdiag ,
910919 matrix_vector_product = precond_mvp ,
911920 conv_tol = precond_conv_tol , max_iter = precond_max_iter ,
912- restart_iter = precond_restart_iter ,
921+ restart_subspace = precond_restart_subspace ,
913922 gram_schmidt = gram_schmidt , single = single , verbose = log .verbose - 1
914923 )
915924 else :
@@ -928,7 +937,7 @@ def nested_krylov_solver(matrix_vector_product, hdiag, problem_type='eigenvalue'
928937 initguess_fn = initguess_fn , precond_fn = precond_fn ,
929938 conv_tol = conv_tol , max_iter = max_iter ,
930939 gram_schmidt = gram_schmidt , single = single , verbose = verbose ,
931- restart_iter = restart_iter , in_ram = in_ram , print_eigeneV_along = print_eigeneV_along ,
940+ restart_subspace = restart_subspace , in_ram = in_ram
932941 )
933942 log .info (RIS_PRECOND_CITATION_INFO )
934943 return output
0 commit comments