goodchemistryco / Tangelo

A python package for exploring end-to-end chemistry workflows on quantum computers and simulators.
https://goodchemistryco.github.io/Tangelo/
Other
99 stars 27 forks source link

Added an option for a callable when defining fragment active space #370

Closed alexfleury-sb closed 4 months ago

alexfleury-sb commented 4 months ago

Added an option to define a function to define the DMET fragment active space. As the orbital overlap could change with the chemical potential, it is not trivial to define the frozen_orbitals manually.

Here is an example of how to leverage this option. In this example, we define the fragment active space as HOMO to LUMO, so every fragment in JW (for restricted mean-field DMET) would be 4 qubits.

from tangelo import SecondQuantizedMolecule
from tangelo.problem_decomposition import DMETProblemDecomposition

xyz_H10 = [
    ("H", ( 0.970820393250,  0.000000000000, 0.)),
    ("H", ( 0.785410196625,  0.570633909777, 0.)),
    ("H", ( 0.300000000000,  0.923305061153, 0.)),
    ("H", (-0.300000000000,  0.923305061153, 0.)),
    ("H", (-0.785410196625,  0.570633909777, 0.)),
    ("H", (-0.970820393250,  0.000000000000, 0.)),
    ("H", (-0.785410196625, -0.570633909777, 0.)),
    ("H", (-0.300000000000, -0.923305061153, 0.)),
    ("H", ( 0.300000000000, -0.923305061153, 0.)),
    ("H", ( 0.785410196625, -0.570633909777, 0.))
]
mol_H10_321g = SecondQuantizedMolecule(xyz_H10, q=0, spin=0, basis="3-21g")

def define_dmet_frag_as(homo_minus_m=0, lumo_plus_n=0):

    def callable_for_dmet_object(info_fragment):
        mf_fragment, _, _, _, _, _, _ = info_fragment

        n_molecular_orb = len(mf_fragment.mo_occ)

        n_lumo = mf_fragment.mo_occ.tolist().index(0.)
        n_homo = n_lumo - 1

        frozen_orbitals = [n for n in range(n_molecular_orb) if n not in range(n_homo-homo_minus_m, n_lumo+lumo_plus_n+1)]

        return frozen_orbitals

    return callable_for_dmet_object

opt_dmet = {"molecule": mol_H10_321g,
            "fragment_atoms": [1]*10,
            "fragment_solvers": "fci",
            "fragment_frozen_orbitals": [define_dmet_frag_as(0, 0)]*10,
            }

dmet = DMETProblemDecomposition(opt_dmet)
dmet.build()
dmet.simulate()
alexfleury-sb commented 4 months ago

I added code to address your first 2 points. To test the autocas implementation, we would have to map the info_fragment into what is needed for the function to work. Our code example is getting the xyz, q, and spin to redine a Molcas molecule.