Skip to content

Reference

atom

Atom

An atom object, containing states and transitions

Attributes:

Name Type Description
name str

The name of the atom

states: StateRegistry property readonly

StateRegistry: the atomic states.

transitions: TransitionRegistry property readonly

TransitionRegistry: the atomic transitions.

units property readonly

pint.UnitRegistry(): readonly access to the pint UnitRegistry used by the atom.

calc special

polarizability

scalar(state, omega=0)

Calculate the scalar polarizability of a state |Ψ⟩

Approximate the dynamical scalar polarizability α0(ω) of the state |Ψ⟩ by summing over matrix elements

\[ \alpha^0(\omega) = \frac{1}{3(2J+1)} \sum_i \left( \frac{1}{\hbar (E_i - E) - \hbar \omega} + \frac{1}{\hbar (E_i - E) + \hbar \omega} \right) \left|\left<\Psi\left|D\right| \Psi_i\right>\right|^2 \]

Parameters:

Name Type Description Default
state State

state |Ψ⟩ to calculate the polarizability

required
omega Quantity

Angular frequency of the field to calculate the dynamical polarizability. Defaults to zero, in which case it calculates the static polarizability. Must have units of Hz.

0

Returns:

Type Description
Quantity

Scalar polarizability. Has units of C m / (V/m), or dipole moment / electric field.

Source code in atomphys/calc/polarizability.py
def scalar(state, omega: pint.Quantity = 0) -> pint.Quantity:
    """Calculate the scalar polarizability of a state |Ψ⟩

    Approximate the dynamical scalar polarizability α0(ω)
    of the state |Ψ⟩ by summing over matrix elements

    $$
        \\alpha^0(\\omega) =
            \\frac{1}{3(2J+1)}
            \\sum_i
                \\left(
                \\frac{1}{\\hbar (E_i - E) - \\hbar \\omega} +
                \\frac{1}{\\hbar (E_i - E) + \\hbar \\omega}
                \\right)
                \\left|\\left<\\Psi\\left|D\\right| \\Psi_i\\right>\\right|^2
    $$

    Arguments:
        state (State): state |Ψ⟩ to calculate the polarizability
        omega: Angular frequency of the field to calculate
            the dynamical polarizability. Defaults to zero,
            in which case it calculates the static polarizability.
            Must have units of `Hz`.

    Returns:
        Scalar polarizability. Has units of `C m / (V/m)`, or dipole moment / electric field.
    """
    ω = omega
    ħ = state._ureg.ħ
    J = state.J
    X = 1 / (3 * (2 * J + 1)) / ħ
    α = 0

    for transition in state.up:
        ω0 = transition.ω
        d = transition.d
        α += (1 / (ω0 - ω) + 1 / (ω0 + ω)) * d ** 2

    for transition in state.down:
        ω0 = -transition.ω
        d = transition.d
        α += (1 / (ω0 - ω) + 1 / (ω0 + ω)) * d ** 2

    return (α * X).to_base_units()

tensor(state, omega=0)

Calculate the tensor polarizability of a state |Ψ⟩

Approximate the dynamical tensor polarizability α0(ω) of the state |Ψ⟩ by summing over matrix elements

\[ \alpha^2(\omega) = -\sqrt{\frac{20J(2J-1)}{6(J+1)(2J+1)(2J+3)}} \sum_i \left\{ \begin{matrix} 1 & 1 & 2 \\ J & J & J_i \end{matrix} \right\} (-1)^{1+J+J_i} \left( \frac{1}{\hbar (E_i - E) - \hbar \omega} + \frac{1}{\hbar (E_i - E) + \hbar \omega}\right) \left| \left<\Psi\left|D\right| \Psi_i\right>\right|^2 \]

Parameters:

Name Type Description Default
state State

state |Ψ⟩ to calculate the polarizability

required
omega Quantity

Angular frequency of the field to calculate the dynamical polarizability. Defaults to zero, in which case it calculates the static polarizability. Must have units of Hz.

0

Returns:

Type Description

Tensor polarizability. Has units of C m / (V/m), or dipole moment / electric field.

Source code in atomphys/calc/polarizability.py
def tensor(state, omega: pint.Quantity = 0):
    """Calculate the tensor polarizability of a state |Ψ⟩

    Approximate the dynamical tensor polarizability α0(ω)
    of the state |Ψ⟩ by summing over matrix elements

    \\[
        \\alpha^2(\\omega) = -\\sqrt{\\frac{20J(2J-1)}{6(J+1)(2J+1)(2J+3)}}
            \\sum_i
                \\left\\{
                \\begin{matrix}
                1 & 1 & 2 \\\\ J & J & J_i
                \\end{matrix}
                \\right\\}
                (-1)^{1+J+J_i}
                \\left(
                \\frac{1}{\\hbar (E_i - E) - \\hbar \\omega} +
                \\frac{1}{\\hbar (E_i - E) + \\hbar \\omega}\\right)
                \\left|
                \\left<\\Psi\\left|D\\right| \\Psi_i\\right>\\right|^2
    \\]

    Arguments:
        state (State): state |Ψ⟩ to calculate the polarizability
        omega: Angular frequency of the field to calculate
            the dynamical polarizability. Defaults to zero,
            in which case it calculates the static polarizability.
            Must have units of `Hz`.

    Returns:
        Tensor polarizability. Has units of `C m / (V/m)`, or dipole moment / electric field.
    """
    ω = omega
    ħ = state._ureg.ħ
    J = state.J
    X = (
        -(
            ((20 * J * (2 * J - 1)) / (6 * (J + 1) * (2 * J + 1) * (2 * J + 3)))
            ** (1 / 2)
        )
        / ħ
    )
    α = 0

    for transition in state.up:
        ω0 = transition.ω
        d = transition.d
        Jp = transition.f.J
        sixJ = wigner_6j(1, 1, 2, J, J, Jp)
        α += (-1) ** (J + Jp + 1) * sixJ * (1 / (ω0 - ω) + 1 / (ω0 + ω)) * d ** 2

    for transition in state.down:
        ω0 = -transition.ω
        d = transition.d
        Jp = transition.i.J
        sixJ = wigner_6j(1, 1, 2, J, J, Jp)
        α += (-1) ** (J + Jp + 1) * sixJ * (1 / (ω0 - ω) + 1 / (ω0 + ω)) * d ** 2

    return (α * X).to_base_units()

total(state, mJ=None, omega=0, A=0, theta_k=0, theta_p=1.5707963267948966)

Calculate the polarizability of a state for a given field polarization

Calculates the dynamical polarizability α(ω) by taking the sum of the scalar, vector, and tensor poarts according to

\[ \alpha(\omega) = \alpha^0(\omega) + A \cos(\theta_k) \frac{m_J}{J} \alpha^1(\omega) + \frac{1}{2}\left(3 \cos^2(\theta_p) - 1\right)\frac{3m_J^2 - J(J+1)}{J(2J-1)}\alpha^2(\omega) \]

Parameters:

Name Type Description Default
state State

state |Ψ⟩ to calculate the polarizability

required
mJ float

Zeeman sublevel to calculate the vector and tensor polarizability. If None only calculates the scalar component. Must be an integer if J is an integer, or a half-integer if J is a half integer.

None
omega Quantity

angular frequency of the field to calculate the dynamical polarizability. Defaults to zero, in which case it calculates the static polarizability. Must have units of Hz.

0
A float

degree of circular polarization, with ±1 being circular polarization and 0 being linear polarization

0
theta_k float

angle between wave vector and quantization axis

0
theta_p float

angle between polarization vector and quantization axis

1.5707963267948966

Returns:

Type Description
Quantity

Polarizability. Has units of C m / (V/m), or dipole moment / electric field.

Source code in atomphys/calc/polarizability.py
def total(
    state,
    mJ: float = None,
    omega: pint.Quantity = 0,
    A: float = 0,
    theta_k: float = 0,
    theta_p: float = π / 2,
) -> pint.Quantity:
    """Calculate the polarizability of a state for a given field polarization

    Calculates the dynamical polarizability α(ω) by taking the sum of the
    scalar, vector, and tensor poarts according to

    \\[
        \\alpha(\\omega) = \\alpha^0(\\omega) +
        A \\cos(\\theta_k) \\frac{m_J}{J} \\alpha^1(\\omega) +
        \\frac{1}{2}\\left(3 \\cos^2(\\theta_p) - 1\\right)\\frac{3m_J^2 - J(J+1)}{J(2J-1)}\\alpha^2(\\omega)
    \\]

    Arguments:
        state (State): state |Ψ⟩ to calculate the polarizability
        mJ: Zeeman sublevel to calculate the vector and tensor
            polarizability. If `None` only calculates the scalar
            component. Must be an integer if J is an integer, or
            a half-integer if J is a half integer.
        omega: angular frequency of the field to calculate
            the dynamical polarizability. Defaults to zero,
            in which case it calculates the static polarizability.
            Must have units of `Hz`.
        A: degree of circular polarization, with ±1 being circular
            polarization and 0 being linear polarization
        theta_k: angle between wave vector and quantization axis
        theta_p: angle between polarization vector and quantization axis

    Returns:
        Polarizability. Has units of `C m / (V/m)`, or dipole moment / electric field.

    Raises:
        ZeroDivisionError
    """
    θk = theta_k
    θp = theta_p

    J = state.J
    α0 = scalar(state, omega)
    α1 = vector(state, omega)
    α2 = tensor(state, omega)
    if mJ is None:
        return α0
    if not (isint(mJ) or (ishalfint(mJ) and ishalfint(J) and not isint(J))):
        raise ValueError(
            "mJ must be an integer, or a half-integer if J is a half-integer"
        )

    C1 = A * cos(θk) * mJ / J

    try:
        C2 = (
            (3 * cos(θp) ** 2 - 1) / 2 * (3 * mJ ** 2 - J * (J + 1)) / (J * (2 * J - 1))
        )
    except ZeroDivisionError:
        C2 = 0

    return (α0 + C1 * α1 + C2 * α2).to_base_units()

vector(state, omega=0)

Calculate the vector polarizability of a state |Ψ⟩

Approximate the dynamical vector polarizability α1(ω) of the state |Ψ⟩ by summing over matrix elements

\[ \alpha^1(\omega) = \sqrt{\frac{6J}{(J+1)(2J+1)}} \sum_i \left\{ \begin{matrix} 1 & 1 & 1 \\ J & J & J_i \end{matrix} \right\} (-1)^{1+J+J_i} \left( \frac{1}{\hbar (E_i - E) - \hbar \omega} + \frac{1}{\hbar (E_i - E) + \hbar \omega} \right) \left|\left<\Psi\left|D\right| \Psi_i\right>\right|^2 \]

Parameters:

Name Type Description Default
state State

state |Ψ⟩ to calculate the polarizability

required
omega Quantity

Angular frequency of the field to calculate the dynamical polarizability. Defaults to zero, in which case it calculates the static polarizability. Must have units of Hz.

0

Returns:

Type Description

Vector polarizability. Has units of C m / (V/m), or dipole moment / electric field.

Source code in atomphys/calc/polarizability.py
def vector(state, omega: pint.Quantity = 0):
    """Calculate the vector polarizability of a state |Ψ⟩

    Approximate the dynamical vector polarizability α1(ω)
    of the state |Ψ⟩ by summing over matrix elements


    \\[
        \\alpha^1(\\omega) =
            \\sqrt{\\frac{6J}{(J+1)(2J+1)}}
            \\sum_i
                \\left\\{
                \\begin{matrix}
                1 & 1 & 1 \\\\ J & J & J_i
                \\end{matrix}
                \\right\\}
                (-1)^{1+J+J_i}
                \\left(
                \\frac{1}{\\hbar (E_i - E) - \\hbar \\omega} +
                \\frac{1}{\\hbar (E_i - E) + \\hbar \\omega}
                \\right)
                \\left|\\left<\\Psi\\left|D\\right| \\Psi_i\\right>\\right|^2
    \\]

    Arguments:
        state (State): state |Ψ⟩ to calculate the polarizability
        omega: Angular frequency of the field to calculate
            the dynamical polarizability. Defaults to zero,
            in which case it calculates the static polarizability.
            Must have units of `Hz`.

    Returns:
        Vector polarizability. Has units of `C m / (V/m)`, or dipole moment / electric field.
    """
    ω = omega
    ħ = state._ureg.ħ
    J = state.J
    X = ((6 * J) / (4 * (2 * J + 1) * (J + 1))) ** (1 / 2) / ħ
    α = 0

    for transition in state.up:
        ω0 = transition.ω
        d = transition.d
        Jp = transition.f.J
        sixJ = wigner_6j(1, 1, 1, J, J, Jp)
        α += (-1) ** (J + Jp + 1) * sixJ * (1 / (ω0 - ω) + 1 / (ω0 + ω)) * d ** 2

    for transition in state.down:
        ω0 = -transition.ω
        d = transition.d
        Jp = transition.i.J
        sixJ = wigner_6j(1, 1, 1, J, J, Jp)
        α += -((-1) ** (J + Jp + 1)) * sixJ * (1 / (ω0 - ω) + 1 / (ω0 + ω)) * d ** 2

    return (α * X).to_base_units()

wigner

ishalfint(x)

check if value is half integer

Parameters:

Name Type Description Default
x float

is this a half integer?

required

Returns:

Type Description
bool

True if x is a half integer and False if it is not.

Source code in atomphys/calc/wigner.py
def ishalfint(x: float) -> bool:
    """check if value is half integer

    Arguments:
        x: is this a half integer?

    Returns:
        True if x is a half integer and False if it is not.
    """
    return 2 * x == floor(2 * x)

isint(x)

checks if value is an integer

Parameters:

Name Type Description Default
x float

is this an integer?

required

Returns:

Type Description
bool

True if x is an integer and False if it is not.

Source code in atomphys/calc/wigner.py
def isint(x: float) -> bool:
    """checks if value is an integer

    Arguments:
        x: is this an integer?

    Returns:
        True if x is an integer and False if it is not.
    """
    return x == floor(x)

istriangle(a, b, c)

checks if triad (a, b, c) obeys the triangle inequality

Parameters:

Name Type Description Default
a float required
b float required
c float required

Returns:

Type Description
bool

True if the triangle inequality is satisfied and False if it is not.

Source code in atomphys/calc/wigner.py
def istriangle(a: float, b: float, c: float) -> bool:
    """checks if triad (a, b, c) obeys the triangle inequality

    Arguments:
        a:
        b:
        c:

    Returns:
        True if the triangle inequality is satisfied and False if it is not.
    """
    return abs(a - b) <= c and c <= a + b

wigner_3j(j1, j2, j3, m1, m2, m3)

Calculate the Wigner 3-j symbol numerically

The Wigner 3-j symbol is calculated numerically using a recursion relation. This approximate calculation is often faster than the exact analytic calculation that is done by sympy.physics.wigner. Due to the finite precision of floating point numbers, this is only good for \(j\) and \(m\) up to about 40, after which it becomes too inaccurate.

The results are cached in the private variable _wigner_3j_cache to speed subsequent calculations.

\(\left( \begin{matrix} j_1 & j_2 & j_3 \\ m_1 & m_2 & m_3 \end{matrix} \right)\)

Parameters:

Name Type Description Default
j1 float required
j2 float required
j3 float required
m1 float required
m2 float required
m3 float required

Returns:

Type Description
float

\(\left( \begin{matrix} j_1 & j_2 & j_3 \\ m_1 & m_2 & m_3 \end{matrix} \right)\)

Source code in atomphys/calc/wigner.py
@lru_cache(maxsize=None)
def wigner_3j(
    j1: float, j2: float, j3: float, m1: float, m2: float, m3: float
) -> float:
    """Calculate the Wigner 3-j symbol numerically

    The Wigner 3-j symbol is calculated numerically using a recursion relation.
    This approximate calculation is often faster than the exact analytic
    calculation that is done by `sympy.physics.wigner`.
    Due to the finite precision of floating point numbers, this is only good
    for $j$ and $m$ up to about 40, after which it becomes too inaccurate.

    The results are cached in the private variable `_wigner_3j_cache` to
    speed subsequent calculations.

    $\\left(
    \\begin{matrix}
    j_1 & j_2 & j_3 \\\\ m_1 & m_2 & m_3
    \\end{matrix}
    \\right)$

    Arguments:
        j1:
        j2:
        j3:
        m1:
        m2:
        m3:

    Returns:
        $\\left(
        \\begin{matrix}
        j_1 & j_2 & j_3 \\\\ m_1 & m_2 & m_3
        \\end{matrix}
        \\right)$
    """
    if (
        not ishalfint(j1)
        or not ishalfint(j2)
        or not ishalfint(j3)
        or not ishalfint(m1)
        or not ishalfint(m2)
        or not ishalfint(m3)
    ):
        raise ValueError("All arguments must be integers or half-integers")

    if j1 > 40 or j2 > 40 or j3 > 40 or m1 > 40 or m2 > 40 or m3 > 40:
        raise OverflowError(
            "can't handle numbers this larger, use a sympy.physics.wigner"
        )

    # sum of second row must equal zero
    if m1 + m2 + m3 != 0:
        return 0

    # triangle inequality
    if not istriangle(j1, j2, j3):
        return 0

    if (
        j1 - m1 != floor(j1 - m1)
        or j2 - m2 != floor(j2 - m2)
        or j3 - m3 != floor(j3 - m3)
    ):
        return 0

    if abs(m1) > j1 or abs(m2) > j2 or abs(m3) > j3:
        return 0

    wigner = 0
    for t in range(
        int(max(0, j2 - m1 - j3, j1 + m2 - j3)),
        int(min(j1 + j2 - j3, j1 - m1, j2 + m2)) + 1,
    ):
        wigner += (-1) ** t / (
            factorial(t)
            * factorial(t - (j2 - m1 - j3))
            * factorial(t - (j1 + m2 - j3))
            * factorial(j1 + j2 - j3 - t)
            * factorial(j1 - m1 - t)
            * factorial(j2 + m2 - t)
        )
    wigner *= (-1) ** (j1 - j2 - m3) * sqrt(
        Δ(j1, j2, j3)
        * factorial(j1 + m1)
        * factorial(j1 - m1)
        * factorial(j2 + m2)
        * factorial(j2 - m2)
        * factorial(j3 + m3)
        * factorial(j3 - m3)
    )

    return wigner

wigner_6j(j1, j2, j3, J1, J2, J3)

Calculate the Wigner 6-j symbol numerically

The Wigner 6-j symbol is calculated numerically using a recursion relation. This approximate calculation is often faster than the exact analytic calculation that is done by sympy.physics.wigner.

The results are cached in the private variable _wigner_6j_cache to speed subsequent calculations.

\(\left\{ \begin{matrix} j_1 & j_2 & j_3 \\ J_1 & J_2 & J_3 \end{matrix} \right\}\)

Parameters:

Name Type Description Default
j1 float required
j2 float required
j3 float required
J1 float required
J2 float required
J3 float required

Returns:

Type Description
float

\(\left\{ \begin{matrix} j_1 & j_2 & j_3 \\ J_1 & J_2 & J_3 \end{matrix} \right\}\)

Source code in atomphys/calc/wigner.py
@lru_cache(maxsize=None)
def wigner_6j(
    j1: float, j2: float, j3: float, J1: float, J2: float, J3: float
) -> float:
    """Calculate the Wigner 6-j symbol numerically

    The Wigner 6-j symbol is calculated numerically using a recursion relation.
    This approximate calculation is often faster than the exact analytic
    calculation that is done by `sympy.physics.wigner`.

    The results are cached in the private variable `_wigner_6j_cache` to
    speed subsequent calculations.

    $\\left\\{
    \\begin{matrix}
    j_1 & j_2 & j_3 \\\\ J_1 & J_2 & J_3
    \\end{matrix}
    \\right\\}$

    Arguments:
        j1:
        j2:
        j3:
        J1:
        J2:
        J3:

    Returns:
        $\\left\\{
        \\begin{matrix}
        j_1 & j_2 & j_3 \\\\ J_1 & J_2 & J_3
        \\end{matrix}
        \\right\\}$
    """
    if (
        not ishalfint(j1)
        or not ishalfint(j2)
        or not ishalfint(j3)
        or not ishalfint(J1)
        or not ishalfint(J2)
        or not ishalfint(J3)
    ):
        raise ValueError("All arguments must be integers or half-integers")

    # triangle inequality for each triad
    if (
        not istriangle(j1, j2, j3)
        or not istriangle(j1, J2, J3)
        or not istriangle(J1, j2, J3)
        or not istriangle(J1, J2, j3)
    ):
        return 0

    # each triad must sum to an integer
    if (
        not isint(j1 + j2 + j3)
        or not isint(j1 + J2 + J3)
        or not isint(J1 + j2 + J3)
        or not isint(J1 + J2 + j3)
    ):
        return 0

    wigner = 0
    for t in range(
        int(max(0, j1 + j2 + j3, j1 + J2 + J3, J1 + j2 + J3, J1 + J2 + j3)),
        int(min(j1 + j2 + J1 + J2, j2 + j3 + J2 + J3, j3 + j1 + J3 + J1)) + 1,
    ):
        wigner += (
            (-1) ** t
            * factorial(t + 1)
            / (
                factorial(t - (j1 + j2 + j3))
                * factorial(t - (j1 + J2 + J3))
                * factorial(t - (J1 + j2 + J3))
                * factorial(t - (J1 + J2 + j3))
                * factorial((j1 + j2 + J1 + J2) - t)
                * factorial((j2 + j3 + J2 + J3) - t)
                * factorial((j3 + j1 + J3 + J1) - t)
            )
        )
    wigner *= sqrt(Δ(j1, j2, j3) * Δ(j1, J2, J3) * Δ(J1, j2, J3) * Δ(J1, J2, j3))

    return wigner

Δ(a, b, c)

Helper function for wigner symbols

Calculates the intermediate expression

\(\Delta = \frac{(a+b-c)!(a-b+c)!(-a+b+c)!}{(a+b+c+1)!}\)

Parameters:

Name Type Description Default
a float required
b float required
c float required

Returns:

Type Description
float

\(\Delta\)

Source code in atomphys/calc/wigner.py
def Δ(a: float, b: float, c: float) -> float:
    """Helper function for wigner symbols

    Calculates the intermediate expression

    $\\Delta = \\frac{(a+b-c)!(a-b+c)!(-a+b+c)!}{(a+b+c+1)!}$

    Arguments:
        a:
        b:
        c:

    Returns:
        $\\Delta$
    """
    return (
        factorial(a + b - c)
        * factorial(a - b + c)
        * factorial(-a + b + c)
        / factorial(a + b + c + 1)
    )

data special

nist

remove_annotations(s)

remove annotations from energy strings in NIST ASD

Source code in atomphys/data/nist.py
def remove_annotations(s: str) -> str:
    """remove annotations from energy strings in NIST ASD"""
    # re_energy = re.compile("-?\\d+\\.\\d*|$")
    # return re_energy.findall(s)[0]

    # this is about 3.5× faster than re.findall, but it's less flexible
    # overall this can make a several hundred ms difference when loading
    return s.strip("()[]aluxyz +?").replace("&dagger;", "")

state

Coupling (Enum)

An enumeration.

StateRegistry (UserList)

append(self, state)

S.append(value) -- append value to the end of the sequence

Source code in atomphys/state.py
def append(self, state: State):
    self._assert_State(state)
    super().append(state)

extend(self, states)

S.extend(iterable) -- extend sequence by appending elements from the iterable

Source code in atomphys/state.py
def extend(self, states):
    [self._assert_State(state) for state in states]
    super().extend(states)

insert(self, index, state)

S.insert(index, value) -- insert value before index

Source code in atomphys/state.py
def insert(self, index: int, state: State):
    self._assert_State(state)
    super().insert(index, state)

term

Coupling (Enum)

An enumeration.

parse_term(term)

parse term symbol string in NIST ASD

Source code in atomphys/term.py
def parse_term(term: str) -> dict:
    """
    parse term symbol string in NIST ASD
    """
    if "Limit" in term:
        return {"ionization_limit": True}

    parity = -1 if "*" in term else 1

    match = LS_term.search(term)
    if match is None:
        match = J1J2_term.search(term)
    if match is None:
        match = LK_term.search(term)
    if match is None:
        return {"parity": parity}

    def convert(key, value):
        if key in ["S", "S2"]:
            return float(Fraction((int(value) - 1) / 2))
        if key in ["J1", "J2", "J", "K"]:
            return float(Fraction(value))
        if key == "L":
            return L[value]

    term = {
        key: convert(key, value) for key, value in match.groupdict().items() if value
    }

    return {**term, "parity": parity}

transition

TransitionRegistry (UserList)

append(self, transition)

S.append(value) -- append value to the end of the sequence

Source code in atomphys/transition.py
def append(self, transition: Transition):
    self._assert_Transition(transition)
    super().append(transition)

extend(self, transitions)

S.extend(iterable) -- extend sequence by appending elements from the iterable

Source code in atomphys/transition.py
def extend(self, transitions):
    [self._assert_Transition(transition) for transition in transitions]
    super().extend(transitions)

insert(self, index, transition)

S.insert(index, value) -- insert value before index

Source code in atomphys/transition.py
def insert(self, index: int, transition: Transition):
    self._assert_Transition(transition)
    super().insert(index, transition)

util

fsolve(func, x0, x1=None, tol=1.49012e-08, maxfev=100)

Find the roots of a function using the secant method.

Return the roots of the equation func(x) = 0 given a starting estimate x0. A second starting estimate x1 for the next iteration of the secant method can be supplied.

Parameters:

Name Type Description Default
func Callable

a function f(x) that takes a single argument x

required
x0

The starting estimate for the roots of `func(x) = 0``

required
x1

A second starting estimate for the next iteration of

None
tol float

The calculation will terminate if the relative error between two consecutive iterates is at most tol

1.49012e-08
maxfev int

The maximum number of calls to the function.

100

Returns:

Type Description

The root of the function f(x).

Source code in atomphys/util.py
def fsolve(func: Callable, x0, x1=None, tol: float = 1.49012e-08, maxfev: int = 100):
    """
    Find the roots of a function using the secant method.

    Return the roots of the equation `func(x) = 0` given a
    starting estimate `x0`. A second starting estimate `x1`
    for the next iteration of the secant method can be supplied.

    Arguments:
        func: a function `f(x)` that takes a single argument `x`
        x0: The starting estimate for the roots of `func(x) = 0``
        x1: A second starting estimate for the next iteration of
        the secant method. Defaults to `1.0001 * x0`.
        tol: The calculation will terminate if the relative
            error between two consecutive iterates is at most `tol`
        maxfev: The maximum number of calls to the function.

    Returns:
        The root of the function `f(x)`.
    """
    if x1 is None:
        x1 = x0 * 1.001 if x0 else 0.001
    fx0, fx1 = func(x0), func(x1)
    i = 2
    while (abs(fx0) > 0) and (abs((fx1 - fx0) / fx0) > tol) and (i < maxfev + 1):
        x0, x1 = x1, x1 - fx1 * (x1 - x0) / (fx1 - fx0)
        fx0, fx1 = fx1, func(x1)
        i += 1
    return x1
Back to top