This is a simple package that provides utility function to compute normal modes from a Hessian matrix, and then work with them.
The other use of this package is to give me a space to ramble about normal modes, and I will shamelessly use this README for this purpose.
Because I find the subject confusing, and the introductions describing the problem as well, I think it is worth laying down the basics here.
We are interested in the ground state of an equilibrium Hamiltonian
Then we do a Taylor expansion of the potential, leading to
where
and the Hamiltonian
where
We introduce the diagonal mass weighting matrix
where
We have what we need to define the new coordinates
Inserting it in the Hamiltonian we get the decoupled system of harmonic oscillators (see the annex for the derivation)
We can check wikipedia to get whatever we need from it, like for example the Wigner distribution for sampling, and it is how it was implemented in the package.
The package aim at providing an interface to normal modes, but what are they? That's where it gets confusing. The andidates are
- The eigen vectors
${\rm \bf u}_j$ that (the columns of$\rm \bf U$ ). They are normed and orthogonal, but live in the mass weighted space. - The columns of
$\rm \bf MU$ . They live in real space, but they are neither normed nor orthogonal. - The columns of
$\rm \bf MU$ normalized. Still not orthogonal to each other but at least they have norm 1. In addition all information about$\rm \bf M$ is removed, which is needed to convert between$\rm \bf x$ and$\rm \bf z$ or to perform Wigner sampling. So those are ofter return together with so-called mode masses, the norm of the columns of$\rm \bf MU$ before being normed5.
As far as I know the last one is what, despite my strong feelings, is known as normal modes. To avoid users a slow descent into madness, the package provides a specific object type NormalDecomposition(hessian)
, that stores the useful information and encapsulate the inner confusing parts. Available are
normal_modes
: The normal modes (in real space), useful for example to plot them.sample
: Perform Wigner sampling, and get the displacements from the mean for positions and momenta.frequencies
: Frequencies of the modes (in GHz).wave_number
: Wave numbers of the modes (in inverse cm).reduced_mass
: Reduced masses of the modes (in AMU), following this question and (I believe) similar to what Gamess does.
We want to substitute
By the definition of the diagonal matrix
where
For the other term, we use Leibnitz chain rule, starting with the first derivative only
Next we use
where
Now it would be really beautiful if
as it would make everything collapse. Thankfully with our choice of
Putting it in and using the fact that
Footnotes
-
I am indeed using the julia function
vcat
to describe this mathematical operation, I have never found a better way to express it. ↩ -
This makes sense because in the position representation the potential is not an operator but just a scalar. ↩
-
Which is the mass of the atom from which this component comes from. Essentially in the vector of mass $m_i$ each mass is repeated 3 times, once for each spatial dimension of each atom. ↩
-
Eigenvalue are in theory positive or zero, because the Hamiltonian is semi-positive definite and symmetric. Numerically the smallest eigenvalues can be negative instead of exactly zero. ↩
-
Which is pure lunacy if you ask me, the code I was using was norming the component in one function, and then immediately unnorming them in the next one. ↩
-
We transpose a scalar, which is a trick I like very much and which is surprisingly useful. ↩