示例#1
0
def automatic_guessing(ase_nuclei,
                       charge,
                       spin,
                       basis,
                       xc,
                       method='FB',
                       ecp=None,
                       newton=False,
                       grid=3,
                       BS=None,
                       calc='UKS',
                       symmetry=False,
                       verbose=4):
    # ase_nuclei_atoms ...	ase.atoms.object containg only nuclei positions
    # charge	   ...  charge of the system
    # spin		   ...  spin state of the system
    # basis 	   ...  basis set
    # xc 		   ...  exchange-correlation functional
    # method 	   ...  localization method (FB, ER, PM etc.)
    #			Note: FB seems to give very reasonable guesses.
    # ecp		   ...  effective core potential file
    # newton	   ...  second order Newton Raphston scf solver works for LDA and GGA not for SCAN
    # grid 		   ...	grid level
    # BS		   ...  broken symmetry
    # calc	 	   ,,,  UKS or UHF
    # Performe a DFT calculation.

    method = method.upper()
    calc = calc.upper()
    ase_atoms = ase_nuclei
    if ecp is None:
        mol = gto.M(atom=ase2pyscf(ase_atoms),
                    basis=basis,
                    spin=spin,
                    charge=charge,
                    symmetry=symmetry)
    if ecp is not None:
        mol = gto.M(atom=ase2pyscf(ase_atoms),
                    basis=basis,
                    ecp=ecp,
                    spin=spin,
                    charge=charge,
                    symmetry=symmetry)
    mol.verbose = verbose
    if calc == 'UKS':
        mf = scf.UKS(mol)
    if calc == 'UHF':
        mf = scf.UHF(mol)
    if calc == 'RHF':
        mf = scf.RHF(mol)
    mf.grids.level = grid
    mf.max_cycle = 3000
    mf.xc = xc
    # Broken symmetry
    if BS != None:
        mf.kernel()
        idx_flip = mol.search_ao_label(BS)
        dma, dmb = mf.make_rdm1()
        dma_flip = dma[idx_flip.reshape(-1, 1), idx_flip].copy()
        dmb_flip = dmb[idx_flip.reshape(-1, 1), idx_flip].copy()
        dma[idx_flip.reshape(-1, 1), idx_flip] = dmb_flip
        dmb[idx_flip.reshape(-1, 1), idx_flip] = dma_flip
        dm = [dma, dmb]
        if ecp is None:
            mol = gto.M(atom=ase2pyscf(ase_atoms),
                        basis=basis,
                        spin=0,
                        charge=charge,
                        symmetry=symmetry)
        if ecp is not None:
            mol = gto.M(atom=ase2pyscf(ase_atoms),
                        basis=basis,
                        ecp=ecp,
                        spin=0,
                        charge=charge,
                        symmetry=symmetry)
        mol.verbose = verbose
        mf = scf.UKS(mol)
        mf.grids.level = grid
        mf.max_cycle = 3000
        mf.xc = xc
    if newton == True:
        mf = mf.as_scanner()
        mf = mf.newton()
    if BS == None:
        mf.kernel()
    if BS != None:
        mf.run(dm)
    if calc == 'RHF':
        mf = scf.addons.convert_to_uhf(mf)

    # Performe a localization calculation.
    # Both spin channels are localized separately.
    # The orbitals are written out as cube files.
    calc_localized_orbitals(mf, mol, method=method)

    # Collect all cube files per spin channel.
    f1 = glob.glob('*orb*spin1.cube')
    f2 = glob.glob('*orb*spin2.cube')

    # test for nuclei positions
    # for ASE Version: 3.15.1b1
    # we neede the file handle and not the string
    # new:
    f_cube = open(f1[0])
    ase_atoms = cube.read_cube(f_cube)
    # previous: ase_atoms = cube.read_cube(f1[0])
    f_cube.close()

    # Calculate the guess.
    get_guess(atoms=ase_atoms, spin1_cube=f1, spin2_cube=f2, method=method)
示例#2
0
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.
        mf.grids.level = 7  # Level of the numerical grid. 3 is the standard value.
        mf.xc = 'LDA,PW'  # Exchange-correlation functional in the form: (exchange,correlation)
        e_ref = -40.1187154486949
示例#3
0
# Installation of pyberny 
# pip3 install pyberny 

# Read the structure. 
# This starting structure includes both nuclei and FOD positions. 
ase_atoms = read('LiH.xyz') 
# We want only to optimize the nuclear positions. 
[geo,nuclei,fod1,fod2,included] =  xyz_to_nuclei_fod(ase_atoms)
ase_atoms  = nuclei 
# Calulation parameters. 
charge = 0 
spin = 0 
basis = get_dfo_basis('LiH')
xc = 'LDA,PW'
# Set up the pyscf structure object. 
mol = gto.M(atom=ase2pyscf(ase_atoms),spin=spin,charge=charge,basis=basis)
mol.verbose = 4 
# DFT pyscf calculation.
mf = dft.UKS(mol)
mf.max_cycle = 300
mf.conv_tol = 1e-6
mf.xc = xc
mf = mf.newton()
mf = mf.as_scanner()
# SCF single point for starting geometry. 
e = mf.kernel()
# Starting Gradients  
gf = uks.Gradients(mf)
gf.grid_response = True
gf.kernel()
# Optimization
示例#4
0
	# "Calculation of magnetic coupling constants with hybrid density functionals" 
	# @  https://jyx.jyu.fi/dspace/bitstream/handle/123456789/45989/URN%3ANBN%3Afi%3Ajyu-201505211947.pdf?sequence=1, Eq.(84) 
	# for further information.
    return -2*(HS - LS)/(S2_HS-S2_LS)*219474

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

atoms = read('HHeH.xyz')

# Now, we set up the mole object.

spin = 2 
charge = 0
xc = 'LDA,PW'
b = 'cc-pVQZ'
mol = gto.M(atom=ase2pyscf(atoms), basis=b,spin=spin,charge=charge)

# Now we set up the calculator.

dft_object = dft.UKS(mol)
dft_object.max_cycle= 300
dft_object.xc = xc
dft_object.conv_tol = 1e-7

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

E_HS_DFT = dft_object.kernel()

# Next, we need the low-spin solution. The first steps are completely similar to the high-spin calculation.
# In addition we now apply a small electric field.
示例#5
0
import matplotlib.pyplot as plt

# This example shows how the density can be visualized on the numerical grid.
# The routines provided by plot_density.py are very straightforward and only need a system name in order to perform this visualization.
# The default plotting axis is the z-axis; modify the routine in whatever way you wish.

# The only input we need are a mole object, the system name (only for output purposes) and the FOD geometry.
# The example system will be an H2 molecule with spin 2.
# We first have to set up a mole object.

sysname = 'H2'
molecule = read('H2_stretched_density.xyz')
geo, nuclei, fod1, fod2, included = xyz_to_nuclei_fod(molecule)
spin = 2
b = 'cc-pvqz'
mol = gto.M(atom=ase2pyscf(nuclei), basis={'default': b}, spin=spin)

# Set the calculation parameters.

gridlevel = 4
convtol = 1e-6
maxcycle = 50
xc = 'LDA,PW'

# Do the DFT calculation.

print('Starting DFT calculation.')
mf = dft.UKS(mol)
mf.max_cycle = maxcycle
mf.conv_tol = convtol
mf.grids.level = gridlevel
try:
    from ase.io import read
except ImportError:
    raise SystemExit('The package \'ase\' is required for this example!')
try:
    from flosic_os import ase2pyscf, xyz_to_nuclei_fod
    from flosic_scf import FLOSIC
except ImportError:
    raise SystemExit('The package \'pyflosic\' is required for this example!')
from pyscf import gto
from var_mesh import var_mesh

# Set up calculation details
molecule = read('H2.xyz')
geo, nuclei, fod1, fod2, included = xyz_to_nuclei_fod(molecule)
mol = gto.M(atom=ase2pyscf(nuclei), basis='6-311++Gss', spin=0, charge=0)
sic_object = FLOSIC(mol, xc='lda,pw', fod1=fod1, fod2=fod2, ham_sic='HOO')
sic_object.max_cycle = 300
sic_object.conv_tol = 1e-7

# By default a grid level of 3 is used, save its size
mesh_size = len(sic_object.calc_uks.grids.coords)
sic_object.calc_uks.grids = var_mesh(sic_object.calc_uks.grids)

# Start the calculation
total_energy_sic = sic_object.kernel()
homo_flosic = sic_object.homo_flosic

# Display mesh sizes and energy values
print('Mesh size before: %d' % mesh_size)
print('Mesh size after: %d' % len(sic_object.calc_uks.grids.coords))
示例#7
0
geo, nuclei, fod1, fod2, included = xyz_to_nuclei_fod(molecule)

# We also need the spin and the charge.

spin_0 = 0
spin_2 = 2
charge = 0

# Furthermore we have to pick a basis set.
# We use the minimal basis set here in order to keep computational cost low.

b = 'sto3g'

# With that we can build the mole object.

mol_0 = gto.M(atom=ase2pyscf(nuclei),
              basis={'default': b},
              spin=spin_0,
              charge=charge)
mol_2 = gto.M(atom=ase2pyscf(nuclei),
              basis={'default': b},
              spin=spin_2,
              charge=charge)

# We further need to specify the numerical grid level used in the self-consistent FLO-SIC calculation.

grid_level = 4

# We need to choose an exchange-correlation functional.

xc = 'LDA,PW'  # Exchange-correlation functional in the form: (exchange,correlation)
示例#8
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()
示例#9
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