Beispiel #1
0
def fullsys_best_guess(comm=None):
    '''Get conventional E of full system by finding best initial guess.

    Iterates over fragments to produce Nfrag charge-local initial guesses.
    Takes best UHF energy from each of the corresponding initial densities, then
    does correlated calculation.
    '''
    if comm is None:
        comm = MPI.comm

    geom.set_frag_auto()
    sub_fragments = geom.fragments[:]
    guess_vecs = []

    esp_list = []
    for i, frag_i in enumerate(sub_fragments):
        monomers = range(len(sub_fragments))
        charges = [int(j == i) for j in monomers]
        esp, vecs = monomerSCF(monomers, charges, embedding=False, comm=comm)
        esp_list.append(esp)
        guess_vecs.append(vecs)

    geom.set_frag_full_system()

    my_calcs = []
    my_guessvecs = MPI.scatter(comm, guess_vecs, master=0)

    for guess in my_guessvecs:
        res = backend.run('esp', [(0, 0, 0, 0)], 1, [], [], guess=guess)
        my_calcs.append(res)

    calcs = MPI.allgather(comm, my_calcs)
    ibest, best = min(enumerate(calcs), key=lambda x: x[1]['E_hf'])
    espfield = calcs[ibest]['esp_charges']

    if params.options['correlation']:
        best = backend.run('energy', [(0, 0, 0, 0)],
                           1, [], [],
                           guess=guess_vecs[ibest])
    res = {}
    res['E1'] = best['E_tot']
    res['E2'] = 0.0
    res['monomers'] = [best]
    res['dimers'] = []
    res['net_charges'] = [1]
    res['esp'] = espfield
    return res
Beispiel #2
0
def monomerSCF(comm=None):
    '''Cycle embedded monomer calculations until ESP charges converge.

    BIM version: include all monomers, take charges from input geometry,
    bq_lists from Globals.neighbor, and embedding option from input file. PBC is
    implicitly handled No need to do anything if embedding option is off.

    Args:
        comm: specify a sub-communicator for parallel execution.
            Default None: use the top-level communicator in Globals.MPI
    Returns:
        espcharges: a list of esp-fit atom-centered charges
    '''
    if comm is None:
        comm = MPI.comm

    options = params.options

    RMSD_TOL = 0.001
    MAXITER  = 10
    RMSD = RMSD_TOL + 1
    itr = 0

    espcharges = [0.0 for at in geom.geometry]
    if not options['embedding']: return espcharges
    natm = float(len(geom.geometry))

    while RMSD > RMSD_TOL and itr < MAXITER:

        espcharges0 = espcharges[:] # copy
        myfrags = MPI.scatter(comm, range(len(geom.fragments)), master=0)
        mycharges = []

        for m in myfrags:
            fragment = [(m,0,0,0)]
            net_chg = geom.charge(m)
            bqlist = neighbor.bq_lists[m]
            result = backend.run('esp', fragment, net_chg, bqlist, espcharges)
            mycharges.append(result['esp_charges'])

        espcharges = MPI.allgather(comm, mycharges)
        espcharges = [chg for m in espcharges for chg in m]
        residual = np.array(espcharges) - np.array(espcharges0)
        RMSD = np.linalg.norm(residual) / natm**0.5
        itr += 1

    if RMSD > RMSD_TOL:
        raise RuntimeError("Monomer SCF did not converge")
    else:
        return espcharges
Beispiel #3
0
def create_bim_fragment(specifier, espcharges):
    '''Create and dispatch a backend fragment calculation.

    Args:
        specifier: tuple specifying the monomer and cell indices for the
            requested calculation.
        espcharges: embedding field charges
    Returns:
        results: results dict from fragment calculation
    '''
    assert len(specifier) in [1, 5, 6]
    #monomer
    if len(specifier) == 1:
        i, = specifier
        fragment = [(i,0,0,0)]
        net_chg = geom.charge(i)
        bqlist = neighbor.bq_lists[i]
    # dimer
    elif len(specifier) == 5:
        i,j,a,b,c = specifier
        fragment = [(i,0,0,0), (j,a,b,c)]
        net_chg = geom.charge(i) + geom.charge(j)
    # monomer in dimer field
    else:
        i,j,a,b,c,bqij = specifier

    # build dimer field
    if len(specifier) == 5 or len(specifier) == 6:
        bqi, bqj = neighbor.bq_lists[i], neighbor.bq_lists[j]
        bqj = [(bq[0], bq[1]+a, bq[2]+b, bq[3]+c) for bq in bqj]
        bqlist = list(set(bqi).union(set(bqj)))

    if len(specifier) == 5:
        bqlist.remove( (i,0,0,0) )
        bqlist.remove( (j,a,b,c) )

    if len(specifier) == 6:
        assert bqij in ['QMi_BQj', 'QMj_BQi']
        if bqij == 'QMi_BQj':
            fragment = [(i,0,0,0)]
            net_chg = geom.charge(i)
            bqlist.remove( (i,0,0,0) )
        else:
            fragment = [(j,a,b,c)]
            net_chg = geom.charge(j)
            bqlist.remove( (j,a,b,c) )
    task, sum_fxn = get_task()
    result = backend.run(task, fragment, net_chg, bqlist, espcharges)
    return result
Beispiel #4
0
def coupl_chglocal(A, B):
    '''Charge-local dimer method for coupling

    Only works with NW backend and singly ionized molecular cluster cations.

    Args
        A, B: indices for off-diagonal H element calculation
    '''

    esps_Aloc, vecs_Aloc = monomerSCF([A,B], [1,0], comm='serial')
    esps_Bloc, vecs_Bloc = monomerSCF([A,B], [0,1], comm='serial')
    bqs = []
    esp = []

    # Charge local
    frag = [(A,0,0,0), (B,0,0,0)]
    Aloc = backend.run('energy_hf', frag, 1, bqs, esp, noscf=True,
                       guess=vecs_Aloc)
    Bloc = backend.run('energy_hf', frag, 1, bqs, esp, noscf=True,
                       guess=vecs_Bloc)

    # Relaxed dimer
    Aloc_relax = backend.run('energy', frag, 1, bqs, esp, guess=vecs_Aloc)
    Bloc_relax = backend.run('energy', frag, 1, bqs, esp, guess=vecs_Bloc)
    relax = min(Aloc_relax, Bloc_relax, key=lambda x:x['E_tot'])

    E_relax = relax['E_tot']
    E_Aloc  = Aloc['E_tot']
    E_Bloc  = Bloc['E_tot']

    if params.options['correlation']:
        monA_0 = backend.run('energy', [(A,0,0,0)], 0, [(B,0,0,0)], esps_Bloc,
                       guess=vecs_Bloc[0])
        monB_1 = backend.run('energy', [(B,0,0,0)], 1, [(A,0,0,0)], esps_Bloc,
                       guess=vecs_Bloc[1])
        monA_1 = backend.run('energy', [(A,0,0,0)], 1, [(B,0,0,0)], esps_Aloc,
                       guess=vecs_Aloc[0])
        monB_0 = backend.run('energy', [(B,0,0,0)], 0, [(A,0,0,0)], esps_Aloc,
                       guess=vecs_Aloc[1])
        E_Aloc += monA_1['E_corr'] + monB_0['E_corr']
        E_Bloc += monA_0['E_corr'] + monB_1['E_corr']
    assert E_relax <= E_Aloc and E_relax <= E_Bloc
    coupling = -1.0*((E_relax-E_Aloc)*(E_relax-E_Bloc))**0.5

    results = dict(idx=(A,B),coupling=coupling, AB=E_relax, A=E_Aloc, B=E_Bloc)
    return results
Beispiel #5
0
def monomerSCF(monomers, net_charges, embedding=None, comm=None):
    '''Cycle embedded monomer calculations until the ESP charges converge.

    VBCT version: specify N monomers and their net charges
    explicitly.  No support for cutoffs/periodicity: every monomer is
    embedded in the field of all other N-1 monomers. Able to override default
    embedding option. Monomer MO vectors are saved; thus one cycle runs even
    if embedding option is turned off.

    Args
        monomers: a list of monomer indices
        net_charges: net charge of each monomer
        embedding: Override True/False specified in input.
            Default None: use the value specified in input.
        comm: specify a sub-communicator for parallel execution.
            If string 'serial' is specified, bypass MPI communication.
            Default None: use the top-level communicator in Globals.MPI
    Returns
        espcharges: a list of esp-fit atom-centered charges
        movecs: a list of MO vectors for each monomer
    '''
    if comm is None:
        comm = MPI.comm

    RMSD_TOL = 0.001
    MAXITER = 10
    RMSD = RMSD_TOL + 1
    itr = 0

    if embedding is None:
        embedding = params.options['embedding']
    else:
        assert type(embedding) is bool

    espcharges = [0.0 for at in geom.geometry]

    while RMSD > RMSD_TOL and itr < MAXITER:

        espcharges0 = espcharges[:]  # copy
        if comm is not 'serial':
            myfrags = MPI.scatter(comm, zip(monomers, net_charges), master=0)
        else:
            myfrags = zip(monomers, net_charges)
        mycharges = []
        myvecs = []

        for (m, net_chg) in myfrags:
            fragment = [(m, 0, 0, 0)]
            if embedding:
                bqlist = [(j, 0, 0, 0) for j in monomers if j != m]
            else:
                bqlist = []
            result = backend.run('esp',
                                 fragment,
                                 net_chg,
                                 bqlist,
                                 espcharges,
                                 save=True)
            mycharges.append(result['esp_charges'])
            myvecs.append(result['movecs'])

        if comm is not 'serial':
            movecs = MPI.allgather(comm, myvecs)
            monomer_espcharges = MPI.allgather(comm, mycharges)
        else:
            movecs = myvecs
            monomer_espcharges = mycharges
        for (m, charges) in zip(monomers, monomer_espcharges):
            for (at, chg) in zip(geom.fragments[m], charges):
                espcharges[at] = chg

        residual = np.array(espcharges) - np.array(espcharges0)
        RMSD = np.linalg.norm(residual)
        itr += 1
        if not embedding or len(monomers) == 1:
            return espcharges, movecs

    if RMSD > RMSD_TOL:
        raise RuntimeError("Monomer SCF did not converge")
    else:
        return espcharges, movecs
Beispiel #6
0
def diag_chglocal(charges, espfield, movecs, comm=None):
    '''Charge-local dimer method for diagonal element calculation.

    Only works with NW backend and singly ionized molecular cluster cations.

    Args
        charges: list of net charges on each fragment
        espfield: list of esp-fit atomic charges for entire system
        movecs: list of MO coeff files for each fragment
        comm: MPI communicator or subcommunicator
    '''
    if comm is None:
        comm = MPI.comm

    embed_flag = params.options['embedding']

    nfrag = len(geom.fragments)
    monomers = range(nfrag)
    dimers = list(combinations(monomers, 2))

    my_mon_idxs   = MPI.scatter(comm, monomers, master=0)
    my_dim_idxs   = MPI.scatter(comm,   dimers, master=0)
    my_mon_calcs  = []
    my_dim_calcs  = []

    for m in my_mon_idxs:
        bqlist = []
        if embed_flag:
            bqlist = make_embed_list(m, monomers)
        frag = [(m,0,0,0)]
        res = backend.run('energy', frag, charges[m], bqlist, espfield,
                          guess=movecs[m])
        my_mon_calcs.append(res)

    for d in my_dim_idxs:
        i,j = d
        chg_i, chg_j = charges[i], charges[j]
        chg = charges[i]+charges[j]

        frag = [(d[0],0,0,0), (d[1],0,0,0)]
        guess = [movecs[i], movecs[j]]

        bqlist = []
        if embed_flag:
            bqlist = make_embed_list(d, monomers)

        if chg_i != chg_j:
            assert chg == 1
            charge_local = True
            calc = 'energy_hf'
        else:
            assert chg == 0
            charge_local = False
            calc = 'energy'

        res = backend.run(calc, frag, chg, bqlist, espfield, guess=guess,
                          noscf=charge_local)
        my_dim_calcs.append(res)

    mon_calcs = MPI.allgather(comm, my_mon_calcs)
    dim_calcs = MPI.allgather(comm, my_dim_calcs)
    results = {}

    E1 = sum([mon['E_tot'] for mon in mon_calcs])
    results['E1'] = E1
    E2 = 0.0
    for (i,j), dim in zip(dimers, dim_calcs):
        Eij = dim['E_tot']
        if 'E_corr' in dim:
            Ei = mon_calcs[i]['E_tot']
            Ej = mon_calcs[j]['E_tot']
        else:
            Ei = mon_calcs[i]['E_hf']
            Ej = mon_calcs[j]['E_hf']
        E2 += Eij - Ei - Ej
    results['E2'] = E2
    results['monomers'] = mon_calcs
    results['dimers'] = dim_calcs
    results['net_charges'] = charges
    results['esp'] = espfield

    return results