Change Log

v2.0

This version gives the atomic_physics API a much needed tidy up.

A major design goal for the tidy up was to make things more obvious for the user. This comes at the expense of some function names now being quite a bit more verbose, but that feels like a worthwhile price to pay for clarity!

Misc:

  • We now have a documentation build. Closes #32

  • States are now ordered in decreasing energy order, not increasing! This change allows the Pauli matrices to take on their customary meanings and signs, for example with \(\sigma_+\) being the raising operator and energies being represented by \(+\frac{1}{2}\omega\sigma_z\).

  • Formatting and linting moved from flake8 and black to ruff

  • CI now checks type annotations using pytype

  • Fix assorted type annotation and docstring bugs

  • Significantly expanded test coverage

  • Significantly expanded documentation

  • Added helper functions to convert between different polarization representations

  • Added a helper function to calculate the Rayleigh range of a beam

  • Added a new polarizations module for representing and manipulating polarizations.

  • Added a new RFDrive class. This is a bit heavyweight for just calculating AC Zeeman shifts (which is all we use it for at present) but it is mainly intended for a future optical bloch equations solver.

  • Added a simple TwoStateAtom class to help making simple tests and simulations.

Bug fixes:

  • Calculate derivatives properly in transition sensitivity calculations. Closes #24

  • Fix indexing in AC Zeeman shift calculation. Closes #78

  • Fix incorrect transition frequencies for calcium

API refactor:

  • Named tuples have been replaced with data classes

  • We no longer export classes at the module level. Replace import atomic_physics as ap with from atomic_physics.core import Atom

  • General push to avoid “partially constructed objects” - i.e. objects where we can’t set all the fields at construction time so rely on mutating them in non-obvious ways over the object’s lifetime. This makes the code easier to follow and removes the need for a bunch of checks to see if fields have been initialised.

  • General push to make variable and function names more explicit, even at the cost of increased verbosity (optimizing for least surprise not fewest keystrokes!). Closes #30

  • LevelData now only contains the atomic structure data; information about the energy-ordering of states is now in a separate LevelStates object.

  • Atom.slice has been renamed to Atom.get_slice_for_level. This avoids shadowing the name of a built-in python type.

  • Atom.detuning has been renamed to Atom.get_transition_frequency_for_states. This method supports an additional relative keyword to calculate absolute transition frequencies. Closes #29

  • Atom.index has been split into get_states_for_M, get_state_for_F, get_state_for_MI_MJ. This avoids having one function which does lots of different jobs and has a return type which depends in non-obvious ways on the input parameters.

  • Atom.level has been renamed get_level_for_state

  • added a new Atom.get_transition_for_levels helper function

  • Atom.population has been removed as it wasn’t particularly useful

  • Atom.I0 has been renamed Atom.get_saturation_intensity

  • Atom.P0 has been renamed intensity_to_power

  • Laser.q has been renamed to Laser.polarization

  • Laser.I has been renamed to Laser.intensity

  • Atom.B has been renamed to Atom.magnetic_field

  • Atom.I has been renamed to Atom.nuclear_spin

  • Laser.delta has been renamed to Laser.detuning

  • RateEquations.get_spont has been renamed to RateEquations.get_spont_matrix.

  • RateEquations.get_stim has been renamed to RateEquations.get_stim_matrix.

  • RateEquations.get_transitions has been renamed to RateEquations.get_transitions_matrix.

  • RateEquations.steady_state has been renamed to RateEquations.get_steady_state_populations.

  • RateEquations.get_steady_state_populations now only takes a transitions matrix as an input, not a transitions matrix or a set of lasers (supporting multiple input types saved a little boiler plate at the expense of making things complex/confusing).

  • angular frequencies are denoted w not f

  • Methods where we don’t care about the orderings of states / levels now take a tuple of states / levels rather than asking for an “upper” and “lower” one

  • The AC Zeeman shift code now takes a RFDrive object

  • Polarizations are new represented by Jones vectors rather than +-1 or 0. The old system was relatively easy once one understood it, but only worked for the simple case of rate equations. Anticipating doing more complex things like optical bloch equations, I’ve started moving us over to Jones vectors.

  • Add operators.expectation_value helper method.

  • Add Atom.levels field.

  • Add new Atom.get_states_for_level method.

  • utils.field_insensitive_point now works with values of F and M_F instead of state indices.