# 3.2. Defining a model Hamiltonian¶

## 3.2.1. Supported features¶

HORTON implements the 1- dimensional Hubbard model Hamiltonian with open and periodic boundary conditions. Note that only
`DenseLinalgFactory`

is supported for model Hamiltonians.

## 3.2.2. The Hubbard model Hamiltonian¶

The Hubbard model Hamiltonian is the simplest model of interacting particles on a lattice and reads

where the first term is a one-electron term and accounts for the nearest-neighbor hopping, while the second term is the repulsive on-site interaction. The \(t\) and \(U\) are user specified parameters and \(\sigma\) is the electron spin.

### 3.2.2.1. Preliminaries¶

In contrast to the molecular Hamiltonian, the Hubbard Hamiltonian does not require
a molecule and `GOBasis`

instance. Instead, a
`DenseLinalgFactory`

instance can
be immediately created,

```
lf = DenseLinalgFactory(n)
```

Note that `CholeskyLinalgFactory`

is not supported.

### 3.2.2.2. Defining the Hamiltonian and boundary conditions (open or periodic)¶

Before the hopping and on-site repulsion terms can be calculated, you need to create
an instance of `Hubbard`

:

```
modelham = Hubbard()
```

By default, the Hubbard Hamiltonian is constructed with periodic boundary conditions. Open boundary conditions can be enforced during the initialization using

```
modelham = Hubbard(pbc=False)
```

The nearest-neighbor hopping term (\(t\) in eq. (1)) is calculated
using the method `compute_kinetic()`

:

```
hopping = modelham.compute_kinetic(lf, t)
```

The the on-site repulsion \(U\) is calculated using the method
`compute_er()`

:

```
onsite = modelham.compute_er(lf, U)
```

Finally, all terms of the 1-dimensional Hubbard Hamiltonian are combined together
and passed to the effective Hamiltonian class, `REffHam`

,
which can then be passed to the restricted Hartree-Fock or DFT modules,

```
terms = [
RTwoIndexTerm(hopping, 'kin'),
RDirectTerm(onsite, 'hartree'),
RExchangeTerm(onsite, 'x_hf'),
]
ham = REffHam(terms)
```

### 3.2.2.3. Filling the lattice¶

The number of electrons/spin-half particles on the lattice is assigned using the
Aufbau occupation number model. An instance of the class
`AufbauOccModel`

will be used later for setting
the occupations.

```
occ_model = AufbauOccModel(m)
```

Note that the number of electrons/spin-half particles must be even and orbitals must be restricted.

### 3.2.2.4. Generate initial guess orbitals and overlap matrix¶

The instance of class `DenseExpansion`

by using
the method `create_expansion()`

is used to initiate the orbitals:

```
orb = lf.create_expansion(n)
```

An initial guess can be obtained with
`guess_core_hamiltonian()`

:

```
guess_core_hamiltonian(olp, hopping, orb)
```

The overlap matrix of the Hubbard model can be computed using the method
`compute_overlap()`

:

```
olp = modelham.compute_overlap(lf)
```

## 3.2.3. Example Python script¶

### 3.2.3.1. Restricted Hartree-Fock calculations using the 1-dim Hubbard model Hamiltonian with PBC¶

This example shows a restricted Hartree-Fock calculation for the half-filled Hubbard model. Both the number of electron spins and sites is 6. The \(t\) parameter is set to -1, while the \(U\) parameter is equal to 2. Periodic boundary conditions are used.

```
from horton import * # pylint: disable=wildcard-import,unused-wildcard-import
# Define Occupation model, expansion coefficients and overlap
# -----------------------------------------------------------
lf = DenseLinalgFactory(6)
occ_model = AufbauOccModel(3)
modelham = Hubbard(pbc=True)
orb = lf.create_expansion(6)
olp = modelham.compute_overlap(lf)
# One and two-body interaction terms
# ----------------------------------
# t-param, t = -1
hopping = modelham.compute_kinetic(lf, -1)
# U-param, U = 2
onsite = modelham.compute_er(lf, 2)
# Perform initial guess
# ---------------------
guess_core_hamiltonian(olp, hopping, orb)
terms = [
RTwoIndexTerm(hopping, 'kin'),
RDirectTerm(onsite, 'hartree'),
RExchangeTerm(onsite, 'x_hf'),
]
ham = REffHam(terms)
# Do a Hartree-Fock calculation
# -----------------------------
scf_solver = PlainSCFSolver()
scf_solver(ham, lf, olp, occ_model, orb)
# CODE BELOW IS FOR horton-regression-test.py ONLY. IT IS NOT PART OF THE EXAMPLE.
rt_results = {
'energy': ham.cache["energy"],
'orb_energies': orb.energies,
'kinetic': ham.cache["energy_kin"],
'hartree': ham.cache["energy_hartree"],
'exchange': ham.cache["energy_x_hf"],
}
# BEGIN AUTOGENERATED CODE. DO NOT CHANGE MANUALLY.
import numpy as np # pylint: disable=wrong-import-position
rt_previous = {
'energy': -5.0,
'exchange': -2.9999999999999982,
'hartree': 5.9999999999999964,
'kinetic': -7.999999999999998,
'orb_energies': np.array([
-1.0000000000000007, -2.3948019172601905e-16, 1.2845788926350238e-16,
1.9999999999999991, 2.0000000000000004, 2.9999999999999991
]),
}
```