From b43d366d8884cdbc3b362b2fec1ea0a71cba25a8 Mon Sep 17 00:00:00 2001 From: Matthew R Hermes Date: Thu, 18 Jul 2024 12:42:27 -0500 Subject: [PATCH] lasscf_async subproblem parameters (#104) Address subproblem parameters (max_cycle_macro etc.) with new "impurity_params" and "relax_params" attributes. Use demonstration in examples/lasscf_async/c2h6n4_lasscf88_sto3g.py. --- .../lasscf_async/c2h6n4_lasscf88_sto3g.py | 7 +++++ my_pyscf/mcscf/lasci.py | 6 +++- my_pyscf/mcscf/lasscf_async/combine.py | 3 ++ my_pyscf/mcscf/lasscf_async/crunch.py | 4 +++ my_pyscf/mcscf/lasscf_async/lasscf_async.py | 30 +++++++++++++++++++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/examples/lasscf_async/c2h6n4_lasscf88_sto3g.py b/examples/lasscf_async/c2h6n4_lasscf88_sto3g.py index 6c248181..da3fc09c 100644 --- a/examples/lasscf_async/c2h6n4_lasscf88_sto3g.py +++ b/examples/lasscf_async/c2h6n4_lasscf88_sto3g.py @@ -15,7 +15,14 @@ smults=[[1,1],[3,1],[3,1],[1,3],[1,3]]) las_syn.kernel (mo) print ("Synchronous calculation converged?", las_syn.converged) + las_asyn = asyn.LASSCF (mf, (4,4), ((4,0),(0,4)), spin_sub=(5,5)) +# To fiddle with the optimization parameters of the various subproblems, use +# the "impurity_params" and "relax_params" dictionaries +las_asyn.max_cycle_macro = 50 # by default, all subproblems use this +las_asyn.impurity_params['max_cycle_macro'] = 51 # all fragments +las_asyn.impurity_params[1]['max_cycle_macro'] = 52 # second fragment only (has priority) +las_asyn.relax_params['max_cycle_macro'] = 53 mo = las_asyn.set_fragments_((list (range (3)), list (range (9,12))), mf.mo_coeff) las_asyn.state_average_(weights=[1,0,0,0,0], spins=[[0,0],[2,0],[-2,0],[0,2],[0,-2]], diff --git a/my_pyscf/mcscf/lasci.py b/my_pyscf/mcscf/lasci.py index 2d11b823..206ff077 100644 --- a/my_pyscf/mcscf/lasci.py +++ b/my_pyscf/mcscf/lasci.py @@ -2048,7 +2048,11 @@ def dump_flags (self, verbose=None, _method_name='LASCI'): for i, (no, ne) in enumerate (zip (self.ncas_sub, self.nelecas_sub)): log.info ('LAS %d : (%de+%de, %do)', i, ne[0], ne[1], no) log.info ('nroots = %d', self.nroots) - log.info ('max_memory %d (MB)', self.max_memory) + log.info ('max_cycle_macro = %d', self.max_cycle_macro) + log.info ('max_cycle_micro = %d', self.max_cycle_micro) + log.info ('conv_tol_grad = %s', self.conv_tol_grad) + log.info ('max_memory %d MB (current use %d MB)', self.max_memory, + lib.current_memory()[0]) for i, fcibox in enumerate (self.fciboxes): if getattr (fcibox, 'dump_flags', None): log.info ('fragment %d FCI solver flags:', i) diff --git a/my_pyscf/mcscf/lasscf_async/combine.py b/my_pyscf/mcscf/lasscf_async/combine.py index 770810bf..19421374 100644 --- a/my_pyscf/mcscf/lasscf_async/combine.py +++ b/my_pyscf/mcscf/lasscf_async/combine.py @@ -123,6 +123,9 @@ def relax (las, kf): with flas_stdout_env (las, flas_stdout): flas = lasci.LASCI (las._scf, las.ncas_sub, las.nelecas_sub) flas.__dict__.update (las.__dict__) + params = getattr (las, 'relax_params', {}) + glob = {key: val for key, val in params.items () if isinstance (key, str)} + flas.__dict__.update (glob) e_tot, e_cas, ci, mo_coeff, mo_energy, h2eff_sub, veff = \ flas.kernel (kf.mo_coeff, ci0=kf.ci) ovlp = mo_coeff.conj ().T @ las._scf.get_ovlp () @ mo_coeff diff --git a/my_pyscf/mcscf/lasscf_async/crunch.py b/my_pyscf/mcscf/lasscf_async/crunch.py index 8e107c55..d4637233 100644 --- a/my_pyscf/mcscf/lasscf_async/crunch.py +++ b/my_pyscf/mcscf/lasscf_async/crunch.py @@ -811,6 +811,10 @@ def get_impurity_casscf (las, ifrag, imporb_builder=None): if imporb_builder is not None: imporb_builder.log = logger.new_logger (imc, imc.verbose) imc._imporb_builder = imporb_builder + params = getattr (las, 'impurity_params', {}) + glob = {key: val for key, val in params.items () if isinstance (key, str)} + imc.__dict__.update (glob) + imc.__dict__.update (params.get (ifrag, {})) return imc if __name__=='__main__': diff --git a/my_pyscf/mcscf/lasscf_async/lasscf_async.py b/my_pyscf/mcscf/lasscf_async/lasscf_async.py index ab446249..fb962729 100644 --- a/my_pyscf/mcscf/lasscf_async/lasscf_async.py +++ b/my_pyscf/mcscf/lasscf_async/lasscf_async.py @@ -147,6 +147,29 @@ def get_grad (las, mo_coeff=None, ci=None, ugg=None, kf=None): return ugg.pack (gorb, gci) class LASSCFNoSymm (lasci.LASCINoSymm): + '''Extra attributes: + + frags_orbs : list of length nfrags of list of integers + Identifies the definition of fragments as lists of AOs + impurity_params : list of length nfrags of dict + Key/value pairs are assigned as attributes of the impurity solver CASSCF object. + Use this to address, e.g., conv_tol_grad, max_cycle_macro, etc. of the impurity + subproblems + relax_params : dict + Key/value pairs are assigned as attributes to the active-active relaxation (``LASCI'') + subproblem, similar to impurity_params. Use this to, e.g., set a different max_cycle_macro + for the ``LASCI'' step. + ''' + def __init__(self, mf, ncas, nelecas, ncore=None, spin_sub=None, **kwargs): + lasci.LASCINoSymm.__init__(self, mf, ncas, nelecas, ncore=ncore, spin_sub=spin_sub, + **kwargs) + self.impurity_params = {} + for i in range (self.nfrags): + self.impurity_params[i] = {} + self.relax_params = {} + keys = set (('frags_orbs','impurity_params','relax_params')) + self._keys = self._keys.union (keys) + _ugg = lasscf_sync_o0.LASSCF_UnitaryGroupGenerators _kern = kernel get_grad = get_grad @@ -204,6 +227,13 @@ def _finalize(self): return class LASSCFSymm (lasci.LASCISymm): + def __init__(self, mf, ncas, nelecas, ncore=None, spin_sub=None, **kwargs): + lasci.LASCISymm.__init__(self, mf, ncas, nelecas, ncore=ncore, spin_sub=spin_sub, **kwargs) + self.impurity_params = [{} for i in range (self.nfrags)] + self.relax_params = {} + keys = set (('frags_orbs','impurity_params','relax_params')) + self._keys = self._keys.union (keys) + _ugg = lasscf_sync_o0.LASSCFSymm_UnitaryGroupGenerators _kern = kernel _finalize = LASSCFNoSymm._finalize