Esempio n. 1
0
def pyflosic2nrlmol(ase_atoms):
    #
    # extract all  information from a nuclei+fod xyz file
    #
    # ase_atoms ... contains both nuclei and fod information
    ase_atoms = read(ase_atoms)
    [geo, nuclei, fod1, fod2, included] = xyz_to_nuclei_fod(ase_atoms)
    e_up = len(fod1)
    e_dn = -1 * len(fod2)
    atoms = nuclei
    fods = fod1.extend(fod2)
    return [atoms, fods, e_up, e_dn]
Esempio n. 2
0
def flosic_optimize(mode,
                    atoms,
                    charge,
                    spin,
                    xc,
                    basis,
                    ecp=None,
                    opt='FIRE',
                    maxstep=0.2,
                    label='OPT_FRMORB',
                    fmax=0.0001,
                    steps=1000,
                    max_cycle=300,
                    conv_tol=1e-5,
                    grid=7,
                    ghost=False,
                    use_newton=False,
                    use_chk=False,
                    verbose=0,
                    debug=False,
                    efield=None,
                    l_ij=None,
                    ods=None,
                    force_consistent=False,
                    fopt='force',
                    fix_fods=False,
                    ham_sic='HOO',
                    vsic_every=1):
    # -----------------------------------------------------------------------------------
    # Input
    # -----------------------------------------------------------------------------------
    # mode 			...	dft only optimize nuclei positions
    #				flosic only optimize FOD positions (one-shot)
    #				flosic-scf only optimize FOD positions (self-consistent)
    # atoms 		...	ase atoms object
    # charge 		... 	charge
    # spin			...	spin state = alpha - beta
    # xc			... 	exchange correlation functional
    # basis	 		... 	GTO basis set
    # ecp			...	if a ECP basis set is used you must give this extra argument
    # opt 			...	optimizer (FIRE, LBFGS, ...)
    # ----------------------------------------------------------------------------------
    # Additional/optional input
    # ----------------------------------------------------------------------------------
    # maxstep		...	stepwidth of the optimizer
    # label			...	label for the outputs (logfile and trajectory file)
    # fmax 			...	maximum force
    # steps 		...     maximum steps for the optimizer
    # max_cycle     	...     maxium scf cycles
    # conv_tol		...	energy threshold
    # grid			... 	numerical mesh
    # ghost 		...	use ghost atom at positions of FODs
    # use_newton		...	use newton scf cycle
    # use_chk		...	restart from chk fiels
    # verbose 		...	output verbosity
    # debug			...	extra output for debugging reasons
    # efield 		...	applying a external efield
    # l_ij			...	developer option: another optimitzation criterion, do not use for production
    # ods			...	developer option orbital damping sic, rescale SIC, do not use for production
    # force_cosistent	...     ase option energy consistent forces
    # fopt			...	optimization trarget, default FOD forces
    # fix_fods		...	freeze FODS during the optimization, might use for 1s/2s FODs
    # ham_sic		...	the different unified Hamiltonians HOO and HOOOV

    opt = opt.upper()
    mode = mode.lower()

    if fix_fods != False:
        c = FixAtoms(fix_fods)
        atoms.set_constraint(c)

    # Select the wished mode.
    # DFT mode
    if mode == 'dft':
        [geo, nuclei, fod1, fod2, included] = xyz_to_nuclei_fod(atoms)
        atoms = nuclei
        calc = PYFLOSIC(atoms=atoms,
                        charge=charge,
                        spin=spin,
                        xc=xc,
                        basis=basis,
                        mode='dft',
                        ecp=ecp,
                        max_cycle=max_cycle,
                        conv_tol=conv_tol,
                        grid=grid,
                        ghost=ghost,
                        use_newton=use_newton,
                        verbose=verbose,
                        debug=debug,
                        efield=efield,
                        l_ij=l_ij,
                        ods=ods,
                        fopt=fopt,
                        ham_sic=ham_sic,
                        vsic_every=vsic_every)
    # FLO-SIC one-shot (os) mode
    if mode == 'flosic-os':
        calc = PYFLOSIC(atoms=atoms,
                        charge=charge,
                        spin=spin,
                        xc=xc,
                        basis=basis,
                        mode='flosic-os',
                        ecp=ecp,
                        max_cycle=max_cycle,
                        conv_tol=conv_tol,
                        grid=grid,
                        ghost=ghost,
                        use_newton=use_newton,
                        verbose=verbose,
                        debug=debug,
                        efield=efield,
                        l_ij=l_ij,
                        ods=ods,
                        fopt=fopt,
                        ham_sic=ham_sic,
                        vsic_every=vsic_every)
    # FLO-SIC scf mode
    if mode == 'flosic-scf':
        calc = PYFLOSIC(atoms=atoms,
                        charge=charge,
                        spin=spin,
                        xc=xc,
                        basis=basis,
                        mode='flosic-scf',
                        ecp=ecp,
                        max_cycle=max_cycle,
                        conv_tol=conv_tol,
                        grid=grid,
                        ghost=ghost,
                        use_newton=use_newton,
                        verbose=verbose,
                        debug=debug,
                        efield=efield,
                        l_ij=l_ij,
                        ods=ods,
                        fopt=fopt,
                        ham_sic=ham_sic,
                        vsic_every=vsic_every)

    # Assign the ase-calculator to the ase-atoms object.
    atoms.set_calculator(calc)

    # Select the wisehd ase-optimizer.
    if opt == 'FIRE':
        dyn = FIRE(atoms,
                   logfile=label + '.log',
                   trajectory=label + '.traj',
                   dt=0.15,
                   maxmove=maxstep)
        #force_consistent=force_consistent)

    if opt == 'LBFGS':
        dyn = LBFGS(atoms,
                    logfile=label + '.log',
                    trajectory=label + '.traj',
                    use_line_search=False,
                    maxstep=maxstep,
                    memory=10)
        #force_consistent=force_consistent)

    if opt == 'BFGS':
        dyn = BFGS(atoms,
                   logfile=label + '.log',
                   trajectory=label + '.traj',
                   maxstep=maxstep)

    if opt == 'LineSearch':
        dyn = BFGSLineSearch(atoms,
                             logfile=label + '.log',
                             trajectory=label + '.traj',
                             maxstep=maxstep)
        #force_consistent = force_consistent)

    if opt == 'CG':
        dyn = SciPyFminCG(atoms,
                          logfile=label + '.log',
                          trajectory=label + '.traj',
                          callback_always=False,
                          alpha=70.0,
                          master=None)
        #force_consistent=force_consistent)
    if opt == 'GPMin':
        from ase.optimize import GPMin
        dyn = GPMin(atoms,
                    logfile=label + '.log',
                    trajectory=label + '.traj',
                    update_prior_strategy='average',
                    update_hyperparams=True)

    # Run the actuall optimization.
    dyn.run(fmax=fmax, steps=steps)
    return atoms
Esempio n. 3
0
import unittest
from pyscf import gto, dft
from ase.io import read
from flosic_os import xyz_to_nuclei_fod, ase2pyscf, flosic
from flosic_scf import FLOSIC
from nrlmol_basis import get_dfo_basis
from ase_pyflosic_optimizer import flosic_optimize
from ase.units import Ha

# Geometry
#f_xyz = '../examples/advanced_applications/CH4.xyz'
f_xyz = 'CH4.xyz'
sysname = 'CH4'
molecule = read(f_xyz)
geo, nuclei, fod1, fod2, included = xyz_to_nuclei_fod(molecule)
spin = 0
charge = 0
mol = gto.M(atom=ase2pyscf(nuclei),
            basis=get_dfo_basis(sysname),
            spin=spin,
            charge=charge)


class KnownValues(unittest.TestCase):
    def test_dft(self):
        # DFT
        mf = dft.UKS(mol)
        mf.verbose = 4  # Amount of output. 4: full output.
        mf.max_cycle = 300  # Number of SCF iterations.
        mf.conv_tol = 1e-6  # Accuracy of the SCF cycle.
Esempio n. 4
0
# And then calculate the low-spin total ground state energy.

E_LS_DFT = dft_object.kernel()

# First, we read the structure for the high spin configuration.

atoms = read('HHeH_s2.xyz')

# Now, we set up the mole object.

spin = 2 
charge = 0
xc = 'LDA,PW'
b = 'cc-pVQZ'
[geo,nuclei,fod1,fod2,included] =  xyz_to_nuclei_fod(atoms)
mol = gto.M(atom=ase2pyscf(nuclei), basis=b,spin=spin,charge=charge)
#mol.verbose = 4

# Now we set up the calculator.

sic_object = FLOSIC(mol=mol,xc=xc,fod1=fod1,fod2=fod2,ham_sic='HOO')
sic_object.conv_tol = 1e-7
sic_object.max_cycle = 300

# With this, we can calculate the high-spin total ground state energy.

E_HS_SIC = sic_object.kernel()

# Next, we need the low-spin solution. The first steps are completely similar to the high-spin calculation.
Esempio n. 5
0
    import numpy as np
    from pyscf import gto
    import os
    from ase import Atom, Atoms

    po.mpi_start()

    # Path to the xyz file
    f_xyz = os.path.dirname(os.path.realpath(
        __file__)) + '/../examples/ase_pyflosic_optimizer/LiH.xyz'
    f_xyz = 'SiH4_guess.xyz'
    # Read the input file.
    ase_atoms = read(f_xyz)

    # Split the input file.
    pyscf_atoms, nuclei, fod1, fod2, included = xyz_to_nuclei_fod(ase_atoms)

    CH3SH = '''
    C -0.04795000 +1.14952000 +0.00000000
    S -0.04795000 -0.66486000 +0.00000000
    H +1.28308000 -0.82325000 +0.00000000
    H -1.09260000 +1.46143000 +0.00000000
    H +0.43225000 +1.55121000 +0.89226000
    H +0.43225000 +1.55121000 -0.89226000
    '''
    # this are the spin-up descriptors
    fod1 = Atoms([
        Atom('X', (-0.04795000, -0.66486000, +0.00000000)),
        Atom('X', (-0.04795000, +1.14952000, +0.00000000)),
        Atom('X', (-1.01954312, +1.27662578, +0.00065565)),
        Atom('X', (+1.01316012, -0.72796570, -0.00302478)),
Esempio n. 6
0
    def calculate(self,
                  atoms,
                  properties=['energy'],
                  system_changes=['positions']):
        self.num_iter += 1
        atoms = self.get_atoms()
        self.atoms = atoms
        Calculator.calculate(self, atoms, properties, system_changes)
        if self.mode == 'dft':
            # DFT only mode
            from pyscf import gto, scf, grad, dft
            [geo, nuclei, fod1, fod2, included] = xyz_to_nuclei_fod(self.atoms)
            nuclei = ase2pyscf(nuclei)
            mol = gto.M(atom=nuclei,
                        basis=self.basis,
                        spin=self.spin,
                        charge=self.charge)
            mf = scf.UKS(mol)
            mf.xc = self.xc
            # Verbosity of the mol object (o lowest output, 4 might enough output for debugging)
            mf.verbose = self.verbose
            mf.max_cycle = self.max_cycle
            mf.conv_tol = self.conv_tol
            mf.grids.level = self.grid
            if self.n_rad is not None and self.n_ang is not None:
                mf.grids.atom_grid = (self.n_rad, self.n_ang)
            mf.grids.prune = prune_dict[self.prune]
            e = mf.kernel()
            self.mf = mf
            self.results['energy'] = e * Ha
            self.results['dipole'] = dipole = mf.dip_moment(verbose=0)
            self.results['evalues'] = mf.mo_energy
        if self.mode == 'flosic-os':
            # FLOSIC SCF mode
            from pyscf import gto, scf
            [geo, nuclei, fod1, fod2, included] = xyz_to_nuclei_fod(self.atoms)
            # FLOSIC one shot mode
            #mf = flosic(self.atoms,charge=self.charge,spin=self.spin,xc=self.xc,basis=self.basis,debug=False,verbose=self.verbose)
            # Effective core potentials need so special treatment.
            if self.ecp == None:
                if self.ghost == False:
                    mol = gto.M(atom=ase2pyscf(nuclei),
                                basis=self.basis,
                                spin=self.spin,
                                charge=self.charge)
                if self.ghost == True:
                    mol = gto.M(atom=ase2pyscf(nuclei),
                                basis=self.basis,
                                spin=self.spin,
                                charge=self.charge)
                    mol.basis = {
                        'default': self.basis,
                        'GHOST1': gto.basis.load('sto3g', 'H'),
                        'GHOST2': gto.basis.load('sto3g', 'H')
                    }
            if self.ecp != None:
                mol = gto.M(atom=ase2pyscf(nuclei),
                            basis=self.basis,
                            spin=self.spin,
                            charge=self.charge,
                            ecp=self.ecp)
            mf = scf.UKS(mol)
            mf.xc = self.xc
            # Verbosity of the mol object (o lowest output, 4 might enough output for debugging)
            mf.verbose = self.verbose
            # Binary output format of pyscf.
            # Save MOs, orbital energies, etc.
            if self.use_chk == True and self.use_newton == False:
                mf.chkfile = 'pyflosic.chk'
            # Load from previous run, if exist, the checkfile.
            # Hopefully this will speed up the calculation.
            if self.use_chk == True and self.use_newton == False and os.path.isfile(
                    'pyflosic.chk'):
                mf.init_guess = 'chk'
                mf.update('pyflosic.chk')
            if self.use_newton == True:
                mf = mf.as_scanner()
                mf = mf.newton()
            mf.max_cycle = self.max_cycle
            mf.conv_tol = self.conv_tol
            mf.grids.level = self.grid
            if self.n_rad is not None and self.n_ang is not None:
                mf.grids.atom_grid = (self.n_rad, self.n_ang)
            mf.grids.prune = prune_dict[self.prune]
            e = mf.kernel()
            self.mf = mf
            mf = flosic(mol,
                        mf,
                        fod1,
                        fod2,
                        sysname=None,
                        datatype=np.float64,
                        print_dm_one=False,
                        print_dm_all=False,
                        debug=self.debug,
                        calc_forces=True,
                        ham_sic=self.ham_sic)
            self.results['energy'] = mf['etot_sic'] * Ha
            # unit conversion from Ha/Bohr to eV/Ang
            #self.results['fodforces'] = -1*mf['fforces']/(Ha/Bohr)
            self.results['fodforces'] = -1 * mf['fforces'] * (Ha / Bohr)
            print('Analytical FOD force [Ha/Bohr]')
            print(mf['fforces'])
            print('fmax = %0.6f [Ha/Bohr]' % np.sqrt(
                (mf['fforces']**2).sum(axis=1).max()))
            self.results['dipole'] = mf['dipole']
            self.results['evalues'] = mf['evalues']
        if self.mode == 'flosic-scf':
            #if self.mf is None:
            # FLOSIC SCF mode
            from pyscf import gto
            [geo, nuclei, fod1, fod2, included] = xyz_to_nuclei_fod(self.atoms)
            # Effective core potentials need so special treatment.
            if self.ecp == None:
                if self.ghost == False:
                    mol = gto.M(atom=ase2pyscf(nuclei),
                                basis=self.basis,
                                spin=self.spin,
                                charge=self.charge)
                if self.ghost == True:
                    mol = gto.M(atom=ase2pyscf(nuclei),
                                basis=self.basis,
                                spin=self.spin,
                                charge=self.charge)
                    mol.basis = {
                        'default': self.basis,
                        'GHOST1': gto.basis.load('sto3g', 'H'),
                        'GHOST2': gto.basis.load('sto3g', 'H')
                    }
            if self.ecp != None:
                mol = gto.M(atom=ase2pyscf(nuclei),
                            basis=self.basis,
                            spin=self.spin,
                            charge=self.charge,
                            ecp=self.ecp)
            if self.efield != None:
                m0 = FLOSIC(mol=mol,
                            xc=self.xc,
                            fod1=fod1,
                            fod2=fod2,
                            grid_level=self.grid,
                            debug=self.debug,
                            l_ij=self.l_ij,
                            ods=self.ods,
                            fixed_vsic=self.fixed_vsic,
                            num_iter=self.num_iter,
                            vsic_every=self.vsic_every,
                            ham_sic=self.ham_sic)
                # test efield to enforce some pseudo chemical environment
                # and break symmetry of density
                m0.grids.level = self.grid
                m0.conv_tol = self.conv_tol
                # small efield
                m0.max_cycle = 1
                h = -0.0001  #-0.1
                apply_field(mol, m0, E=(0, 0, 0 + h))
                m0.kernel()
            mf = FLOSIC(mol=mol,
                        xc=self.xc,
                        fod1=fod1,
                        fod2=fod2,
                        grid_level=self.grid,
                        calc_forces=self.calc_forces,
                        debug=self.debug,
                        l_ij=self.l_ij,
                        ods=self.ods,
                        fixed_vsic=self.fixed_vsic,
                        num_iter=self.num_iter,
                        vsic_every=self.vsic_every,
                        ham_sic=self.ham_sic)
            # Verbosity of the mol object (o lowest output, 4 might enough output for debugging)
            mf.verbose = self.verbose
            # Binary output format of pyscf.
            # Save MOs, orbital energies, etc.
            if self.use_chk == True and self.use_newton == False:
                mf.chkfile = 'pyflosic.chk'
            # Load from previous run, if exist, the checkfile.
            # Hopefully this will speed up the calculation.
            if self.use_chk == True and self.use_newton == False and os.path.isfile(
                    'pyflosic.chk'):
                mf.init_guess = 'chk'
                mf.update('pyflosic.chk')
            if self.use_newton == True:
                mf = mf.as_scanner()
                mf = mf.newton()
            mf.max_cycle = self.max_cycle
            mf.conv_tol = self.conv_tol
            mf.grids.level = self.grid
            if self.n_rad is not None and self.n_ang is not None:
                mf.grids.atom_grid = (self.n_rad, self.n_ang)
                mf.calc_uks.grids.atom_grid = (self.n_rad, self.n_ang)
            mf.grids.prune = prune_dict[self.prune]
            mf.calc_uks.grids.prune = prune_dict[self.prune]
            e = mf.kernel()
            self.mf = mf
            # Return some results to the pyflosic_ase_caculator object.
            self.results['esic'] = mf.esic * Ha
            self.results['energy'] = e * Ha
            self.results['fixed_vsic'] = mf.fixed_vsic

            # if self.mf is not None:
            #     from pyscf import gto
            #     [geo,nuclei,fod1,fod2,included] =  xyz_to_nuclei_fod(self.atoms)
            #     # Effective core potentials need so special treatment.
            #     if self.ecp == None:
            #         if self.ghost == False:
            #             mol = gto.M(atom=ase2pyscf(nuclei), basis=self.basis,spin=self.spin,charge=self.charge)
            #         if self.ghost == True:
            #             mol = gto.M(atom=ase2pyscf(nuclei), basis=self.basis,spin=self.spin,charge=self.charge)
            #             mol.basis ={'default':self.basis,'GHOST1':gto.basis.load('sto3g', 'H'),'GHOST2':gto.basis.load('sto3g', 'H')}
            #     if self.ecp != None:
            #         mol = gto.M(atom=ase2pyscf(nuclei), basis=self.basis,spin=self.spin,charge=self.charge,ecp=self.ecp)
            #     self.mf.num_iter = self.num_iter
            #     self.mf.max_cycle = self.max_cycle
            #     self.mf.mol = mol
            #     self.mf.fod1 = fod1
            #     self.mf.fod2 = fod2
            #     e = self.mf.kernel()
            #     # Return some results to the pyflosic_ase_caculator object.
            #     self.results['esic'] = self.mf.esic*Ha
            #     self.results['energy'] = e*Ha
            #     self.results['fixed_vsic'] = self.mf.fixed_vsic
            #
            if self.fopt == 'force' or self.fopt == 'esic-force':
                #
                # The standard optimization uses
                # the analytical FOD forces
                #
                fforces = self.mf.get_fforces()
                #fforces = -1*fforce
                # unit conversion Hartree/Bohr to eV/Angstroem
                #self.results['fodforces'] = -1*fforces*(Ha/Bohr)
                self.results['fodforces'] = fforces * (Ha / Bohr)
                print('Analytical FOD force [Ha/Bohr]')
                print(fforces)
                print('fmax = %0.6f [Ha/Bohr]' % np.sqrt(
                    (fforces**2).sum(axis=1).max()))

            if self.fopt == 'lij':
                #
                # This is under development.
                # Trying to replace the FOD forces.
                #
                self.lambda_ij = self.mf.lambda_ij
                self.results['lambda_ij'] = self.mf.lambda_ij
                #fforces = []
                #nspin = 2
                #for s in range(nspin):
                #	# printing the lampda_ij matrix for both spin channels
                #	print 'lambda_ij'
                #	print lambda_ij[s,:,:]
                #	print 'RMS lambda_ij'
                #	M = lambda_ij[s,:,:]
                #	fforces_tmp =  (M-M.T)[np.triu_indices((M-M.T).shape[0])]
                #	fforces.append(fforces_tmp.tolist())
                #print np.array(fforces).shape
                try:
                    #
                    # Try to calculate the FOD forces from the differences
                    # of SIC eigenvalues
                    #
                    evalues_old = self.results['evalues']
                    print(evalues_old)
                    evalues_new = self.mf.evalues
                    print(evalues_new)
                    delta_evalues_up = (evalues_old[0][0:len(fod1)] -
                                        evalues_new[0][0:len(fod1)]).tolist()
                    delta_evalues_dn = (evalues_old[1][0:len(fod2)] -
                                        evalues_new[1][0:len(fod2)]).tolist()
                    print(delta_evalues_up)
                    print(delta_evalues_dn)
                    lij_force = delta_evalues_up
                    lij_force.append(delta_evalues_dn)
                    lij_force = np.array(lij_force)
                    lij_force = np.array(lij_force,
                                         (np.shape(lij_force)[0], 3))
                    print('FOD force evalued from evalues')
                    print(lij_force)
                    self.results['fodforces'] = lij_force
                except:
                    #
                    # If we are in the first iteration
                    # we can still use the analystical FOD forces
                    # as starting values
                    #
                    fforces = self.mf.get_fforces()
                    print(fforces)
                    #self.results['fodforces'] = -1*fforces*(Ha/Bohr)
                    self.results['fodforces'] = fforces * (Ha / Bohr)
                    print('Analytical FOD force [Ha/Bohr]')
                    print(fforces)
                    print('fmax = %0.6f [Ha/Bohr]' % np.sqrt(
                        (fforces**2).sum(axis=1).max()))

            self.results['dipole'] = self.mf.dip_moment()
            self.results['evalues'] = self.mf.evalues

        if atoms is not None:
            self.atoms = atoms.copy()
Esempio n. 7
0
    def get_forces(self, atoms=None):
        if atoms != None:
            self.atoms = atoms
        # get nuclei and FOD forces
        # calculates forces if required
        if self.atoms == None:
            self.atoms = atoms
        # Note: The gradients for UKS are only available in the dev branch of pyscf.
        if self.mode == 'dft' or self.mode == 'both':
            from pyscf.grad import uks
            if self.mf == None:
                from pyscf import gto, scf, dft
                [geo, nuclei, fod1, fod2,
                 included] = xyz_to_nuclei_fod(self.atoms)
                nuclei = ase2pyscf(nuclei)
                mol = gto.M(atom=nuclei,
                            basis=self.basis,
                            spin=self.spin,
                            charge=self.charge)
                mf = scf.UKS(mol)
                mf.xc = self.xc
                mf.conv_tol = self.conv_tol
                mf.max_cycle = self.max_cycle
                mf.verbose = self.verbose
                mf.grids.level = self.grid
                if self.n_rad is not None and self.n_ang is not None:
                    mf.grids.atom_grid = (self.n_rad, self.n_ang)
                mf.grids.prune = prune_dict[self.prune]
                if self.xc == 'LDA,PW' or self.xc == 'PBE,PBE':
                    # The 2nd order scf cycle (Newton) speed up calculations,
                    # but does not work for MGGAs like SCAN,SCAN.
                    mf = mf.as_scanner()
                    mf = mf.newton()
                mf.kernel()
                self.mf = mf
                gf = uks.Gradients(mf)
                forces = gf.kernel()
            #if self.mf != None:
            #	gf = uks.Gradients(self.mf)
            #        forces = gf.kernel()
            gf = uks.Gradients(self.mf)
            forces = gf.kernel() * (Ha / Bohr)
            #print(forces)

        if self.mode == 'flosic-os' or self.mode == 'flosic-scf':
            [geo, nuclei, fod1, fod2, included] = xyz_to_nuclei_fod(self.atoms)
            forces = np.zeros_like(nuclei.get_positions())

        if self.mode == 'dft':
            # mode for nuclei only optimization (fods fixed)
            forces = forces.tolist()
            totalforces = []
            totalforces.extend(forces)
            [geo, nuclei, fod1, fod2, included] = xyz_to_nuclei_fod(self.atoms)
            fod1forces = np.zeros_like(fod1.get_positions())
            fod2forces = np.zeros_like(fod2.get_positions())
            totalforces.extend(fod1forces)
            totalforces.extend(fod2forces)
            totalforces = np.array(totalforces)
            # pyscf gives the gradient not the force
            totalforces = -1 * totalforces

        if self.mode == 'flosic-os' or self.mode == 'flosic-scf':
            # mode for FOD only optimization (nuclei fixed)
            if self.results['fodforces'] is None:
                fodforces = self.get_fodforces(self.atoms)
            fodforces = self.results['fodforces']
            # fix nuclei with zeroing the forces
            forces = forces
            forces = forces.tolist()
            totalforces = []
            totalforces.extend(forces)
            totalforces.extend(fodforces)
            totalforces = np.array(totalforces)

        if self.mode == 'both':
            # mode for both (nuclei+fods) optimzation
            if self.results['fodforces'] is None:
                fodforces = self.get_fodforces(self.atoms)
            fodforces = self.results['fodforces']
            forces = forces.tolist()
            totalforces = []
            totalforces.extend(forces)
            totalforces.extend(fodforces)
            totalforces = np.array(totalforces)

        return totalforces
from ase.io import read
from flosic_os import xyz_to_nuclei_fod, ase2pyscf
from pyscf import dft, gto
from flosic_scf import FLOSIC
import numpy as np

# This example shows how the different exchange-correlation energy contributions can be visualized with FLO-SIC. The testing system is a Li atom.
# First we define the input from which the mole object will be build later.

atom = read('Li.xyz')
geo, nuclei, fod1, fod2, included = xyz_to_nuclei_fod(atom)
spin = 1
charge = 0
b = 'cc-pvqz'

# As we will later do exchange-correlation and exchange only calculation it makes sense to define both functionals here.

xc = 'LDA,PW'
x = 'LDA,'

# Now we can build the mole object.

mol = gto.M(atom=ase2pyscf(nuclei), basis=b, spin=spin, charge=charge)

# The next part is the definition of the calculator objects.
# For both xc and x we create a separate calculator object.

dftx = dft.UKS(mol)
dftx.xc = x
dftxc = dft.UKS(mol)
dftxc.xc = xc