WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

t_as_lambda option control #89

@cjcscott

Description

@cjcscott

In some recent work on the solvers I've come across some confusing aspects of the code with respect to CC solver calculations with or without solution of the lambda equations. It seems like we need to properly decide what functionality we support and how to control it, as at the moment the interaction of various options are definitely confusing.
Much of these changes stem from 085372b, where we removed t_as_lambda as a CCSD solver option. IIRC there was some discussion of what behaviour we wanted with these options between automatically applying this approximation if required (with warnings) vs failing with a NotCalculatedError.

I can't remember what the conclusion of this was- we currently do the former, so I'm going to assume that in the rest of this. The CCSD solver has the form

        if self.opts.solve_lambda:
...
        else:
            self.log.info("Using Lambda=T approximation for Lambda-amplitudes.")
            l1, l2 = self.solver.t1, self.solver.t2

so in the absence of solving the lambda equations the l1 and l2 values will be set to t1 and t2 regardless of anything else.

The confusion comes in when then looking at routines to calculate global wavefunction and density matrix values, where we seem to have a fair amount of code trying to implement the other approach, and allow calculation of the t_as_lambda=True expectation values when solve_lambda=True, but with inconsistent approaches to control this option.

Looking for instance at get_global_t1_rhf in ewf/amplitudes.py we have code expecting control of this approximation to be in the fragment option t_as_lambda (can be inherited from emb):

    for x in emb.get_fragments(contributes=True, mpi_rank=mpi.rank, sym_parent=None):
        pwf = x.results.pwf.restore().as_ccsd()
        if for_dm2 and x.solver == 'MP2':
            continue
        t1x = pwf.l1 if (get_lambda and not x.opts.t_as_lambda) else pwf.t1
        if t1x is None:
            raise NotCalculatedError("Fragment %s" % x)

while in ewf/rdm.py various functions have a similar keyword argument for control (that doesn't default to emb.opts.t_as_lambda in actual calls):

def make_rdm1_ccsd_global_wf(emb, t_as_lambda=False, with_t1=True, svd_tol=1e-3, ovlp_tol=None, use_sym=True,
                             late_t2_sym=True, mpi_target=None, slow=False):
...
               l2 = wfy.t2 if (t_as_lambda or fy_parent.solver == 'MP2') else wfy.l2
                if l2 is None:
                    raise RuntimeError("No L2-amplitudes found for %s!" % fy)

In calculation of correlation energies this t_as_lambda option is the difference between the 'dm-t2only' and 'dm' energy functionals.
As far as I can tell thanks to the code in the CCSD solver it's impossible for either of these values to be None and result in an error?

However, the main concern comes when looking at code (thankfully usually in the the slow implementations of various functions) which uses

        l1 = emb.get_global_l1() if not t_as_lambda else t1
        l2 = emb.get_global_l2() if not t_as_lambda else t2

These calls actually become calls to get_global_t1_rhf in ewf/amplitudes.py above, so depend on fragment.opts.t_as_lambda. To obtain the actual l1 value here then requires t_as_lambda=False, emb.opts.t_as_lambda=False, and solve_lambda=True. Someone using this function could be forgiven for thinking that t_as_lambda=False should be sufficient without setting the other parameters (which all default to appropriate values).

I'd say the first thing decide is when in a calculation we want to apply this approximation (in the solver or expectation value calculation).
The next thing would be taking into account that we're automatically applying this approximation where necessary in functions to calculate expectation values. Something like force_t_as_lambda or no_t_as_lambda to make it clear that the result can sometimes already incorporate this approximation regardless of this parameter value might be a little more transparent.
This obviously goes hand-in-hand with ensuring that we have a consistent approach to this between different functions.

(Sorry for the wall of text- I was getting test failures in ewf/test_tailoring.py which I traced back to this ambiguity after some effort and thought it best to raise while I had my head around it!)

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions