2. dft

2.1. solve_poisson

Solve the Poisson equation.

Python

Julia

1return -4 * np.pi * op.Linv(op.O(op.J(n)))
1return -4.0 .* pi .* op_Linv(atoms, op_O(atoms, op_J(atoms, n)))

2.2. get_n_total

Calculate the total electronic density.

Python

Julia

1Yrs = op.I(Y)
2n = atoms.f * np.real(Yrs.conj() * Yrs)
3return np.sum(n, axis=1)
1Yrs = op_I(atoms, Y)
2n = real(conj(Yrs) .* atoms.f .* Yrs)
3return sum(n, dims = 2)

2.3. orth

Orthogonalize coefficient matrix W.

Python

Julia

1U = sqrtm(W.conj().T @ op.O(W))
2return W @ np.linalg.inv(U)
1U = sqrt(W' * op_O(atoms, W))
2return W * inv(U)

2.4. get_grad

Calculate the energy gradient with respect to W.

Python

Julia

1F = np.diag(atoms.f)
2HW = H(op, W, phi, vxc, Vreciproc)
3WHW = W.conj().T @ HW
4OW = op.O(W)
5U = W.conj().T @ OW
6invU = np.linalg.inv(U)
7U12 = sqrtm(invU)
8Ht = U12 @ WHW @ U12
9return (HW - (OW @ invU) @ WHW) @ (U12 @ F @ U12) + OW @ (U12 @ Q(Ht @ F - F @ Ht, U))
1F = Diagonal(atoms.f)
2HW = H(atoms, W, phi, vxc, Vreciproc)
3WHW = W' * HW
4OW = op_O(atoms, W)
5U = W' * OW
6invU = inv(U)
7U12 = sqrt(invU)
8Ht = U12 * WHW * U12
9return (HW .- (OW * invU) * WHW) * (U12 * F * U12) .+ OW * (U12 * Q(Ht * F .- F * Ht, U))

2.5. H

Left-hand side of the eigenvalue equation.

Python

Julia

1Veff = Vreciproc + op.Jdag(op.O(op.J(vxc) + phi))
2return -0.5 * op.L(W) + op.Idag(Veff[:, None] * op.I(W))
1Veff = Vreciproc .+ op_Jdag(atoms, op_O(atoms, op_J(atoms, vxc) .+ phi))
2return -0.5 .* op_L(atoms, W) .+ op_Idag(atoms, Veff .* op_I(atoms, W))

2.6. Q

Operator needed to calculate gradients with non-constant occupations.

Python

Julia

1mu, V = np.linalg.eig(U)
2mu = mu[:, None]
3denom = np.sqrt(mu) @ np.ones((1, len(mu)))
4denom2 = denom + denom.conj().T
5return V @ ((V.conj().T @ inp @ V) / denom2) @ V.conj().T
1F = eigen(U)
2mu, V = F.values, F.vectors
3denom = sqrt.(mu) * ones(1, length(mu))
4denom2 = denom .+ denom'
5return V * ((V' * inp * V) ./ denom2) * V'