The starkr package is designed to calculate the Stark matrix and Stark maps for Rubidium-85. The code relies heavily on techniques and algorithms used by [@Zimmerman1979] in their paper analyzing the Stark structure of alkali-metal atoms. The code described below is broken up in to several sections:
library(starkr) library(dplyr) library(ggplot2)
All of the functions that calcuate the underlying pieces of the Stark matrix element may be used independently of the Stark matrix element calculation.
quantum_defect()
calculates the quantum defect of an arbitrary (n, l, j)
state of Rubidium-85. The quantum defect is calculated using a modified version
of equation (16.19) from [insert Gallagher Rydberg Atoms reference] pg. 351.
$$\delta_{n, l, j} = \delta_{0} + \frac{\delta_{2}}{(n - \delta_{0})^{2}}$$
The parameters $\delta_{0}$ and $\delta_{2}$ are experimentally measured values from the following papers [insert Refereneces].
clebsch_gordan()
calculates the Clebsch-Gordan coefficient for an arbitrary
selection of quantum numbers j~1~, j~2~, m~1~, m~2~, j, and m~j~. The conditions
that must be met for a Clebsch-Gordan coefficient are that $m_{1} + m_{2} =
m_{j}$.
There are two functions that calculate the Clebsch-Gordan coefficient within
starkr. The first is clebsch_gordan()
which uses an analytic form which can
be found in Edmonds [insert reference] or Lindgren and Morrison
[insert Reference]. The second is clebsch_gordan2()
which uses an analytic
form found in Cromwell's Group Theory of Physics [insert Reference].
wigner_3j()
is provided for completeness and is not actually used in the
calculation of the Stark matrix element. It is calculated using the
Clebsch-Gordan coefficient.
[Insert Examples]
sphere_mat_element()
calculates the spherical matrix element
$
radial_matrix_element()
calculates the radial matrix element
$
Computing the elements of the Stark matrix and building said matrix requires a few additional functions to work together. First, we have to compute the individual elements of the Stark matrix. Then we have to put all of those elements in to the appropriate spot in the matrix.
The elements of the Stark matrix are calculated using stark_matrix_elem()
.
stark_matrix_elem()
is based on equation 10 from @Zimmerman1979. It requires
the full $(n, l, j, m_{j})$ of quantum numbers for both the initial and final
states. Equation 10 from @Zimmerman1979 is reproduced below:
$$
where W and W' are the energies of the initial and final states respectively and F is the applied electric field. The energy is $W = -1/2(n - \delta)^{2}$ where $\delta$ is the quantum defect for state $(n, l, j, m_{j})$. The Stark matrix element will be equal to zero unless it fulfills the requirement that $m_{j} = m_{j}'$ and $l = l' \pm 1$.
There are still a few pieces left before you will be able to build the Stark
matrix. To properly calculate the Stark map for a given set of states, you
need to include a large number of states of both higher and lower energies.
The suggestion from @Zimmerman1979 is to include the full manifolds for at
least $n \pm 4$. To build the list of states you plan on including in the
Stark matrix, the function state_list()
can be used. state_list()
creates
a matrix with columns n, l, and j and these columns contain all of the possible
n, l, j combinations for a given $m_{j}$. For example, if looking at the
states for the $n = 3$, $m_{j} = \frac{1}{2}$ manifold you would get:
starkr::state_list(3, 3, 1/2, 0, 0)
There are some additional paramters in state_list()
that allow for the
addition of lower angular momentum states. For example, if n_add_min
is set
to 2, then all of the low angular momentum states ($l < 6$) would be included
for nmin - 1 and nmin - 2. n_add_max
is treated similarly, but on the higher
n side. These additional states allow for the states that have the highest
impact on the Stark map without adding too much computational load by inclding
the full manifolds at those n's.
Note: Because the different $m_{j}$ states do not interact, you will need to compute the state list and Stark matrix separately for each $m_{j}$.
Once the state matrix has been calculated, the Stark matrix can be constructed. For building the Stark matrix, you may find it useful to save the n, l, and j columns of the state matrix into their own vectors.
states <- starkr::state_list(15, 15, 1/2, 0, 0) n <- states[, 1] l <- states[, 2] j <- states[, 3] m_j <- 1/2
Now you are ready to construct the Stark matrix!
mat <- starkr::stark_matrix(n, l, j, m_j)
Note that stark_matrix()
will print the row that is currently being
processed with the message:
# Current row being processed: [i]
where [i] is the row number.
The output of stark_matrix()
will look like the following:
mat[1:4, 1:4]
where element [i, k] is the result of stark_matrix_element()
:
$
To diagonalize the Stark matrix, you will need a few additional functions. The
total matrix need find the eigenenergies and eigenstates of the system is a
matrix of zero field energies summed with the Stark matrix. The zero field
energy matrix is calculated using zero_field_energy_mat()
. This function
takes the vector of n, l, and j values used in stark_matrix()
and returns a
diagonal matrix with elements:
$$W_{n, l, j} = \frac{1}{2(n - \delta_{n, l, j})^{2}}$$
zero_energy_mat <- starkr::zero_field_energy_mat(n, l, j) zero_energy_mat[1:4, 1:4]
stark_eigen()
diagonalizes the combined Stark matrix and zero field energy
matrix at a series of electric fields. The user must provide a field vector
with units of V/cm over which the matrix will be diagonalized. This
function returns a matrix of energy eigenvalues in which the rows
are the different field steps and each columns corresponds to a different
starting state.
field <- seq(0, 4, by = 0.5) stark_map <- starkr::stark_eigen(mat, zero_energy_mat, field) stark_map[1:4, 1:4]
The output from stark_eigen()
tends to be pretty messy and it can be hard to
determine which column corresponds to what zero field energy. To fix this, you
can use tidy_stark_energy()
to put your eigen energies in to a form that is
easy to manipulate and plot.
First, you will need to use zero_field_energy_df()
to create a data frame
with all of the zero field energies. This function is similar to the matrix
form in the previous section.
zero_df <- starkr::zero_field_energy_df(n, l, j, m_j) zero_df
tidy_stark_energy()
takes the zero field energy data frame and the Stark
energy matrix as starting arguments. The field vector must be the same
as used in stark_eigen()
. tidy_stark_energy()
takes the zero field energy data frame and arranges the rows to match the
order of the columns in the Stark energy matrix. It then outputs a tidy data
frame with all of the energy and field values and matching $E_{0}$, $n$, $l$,
$j$, $m_{j}$, and a string representation of the state.
tidy_df <- starkr::tidy_stark_energy(zero_df, stark_map, field) tidy_df
Once the data has been put in to a tidy format, it is very simple to plot it.
tidy_df %>% filter(l > 4) %>% ggplot(aes(x = Field, y = E, group = state)) + geom_line()
Now you have a Stark map!
Now that you have created a Stark matrix and Stark map, you can use that
matrix to calculate the radial matrix element for some initial pure zero-field
state and a Stark state at arbitrary field. stark_radial_mat_elem()
takes
the Stark matrix you made earlier, an initial state represented by a character,
and a Stark state also represented by a character and related to its equivalent
zero-field state. You will also need to provide the desired field strength,
the minimum and maximum n that matches your Stark matrix along with the
additional low angular momentum states included in your Stark matrix.
stark_radial_mat_elem(mat, "5,1,1.5,1.5", "15,1,1.5,0.5", field = 10, n_min = 15, n_max = 15, n_add_min = 0, n_add_max = 0)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.