"""Functions that may be used for the `update_shape` value in the options-dict
for each control (`pulse_options` parameter in :func:`.optimize_pulses`), or
for generating guess pulses"""
import functools
import numpy as np
__all__ = [
'qutip_callback',
'zero_shape',
'one_shape',
'flattop',
'box',
'blackman',
]
[docs]def qutip_callback(func, **kwargs):
"""Convert `func` into the correct form of a QuTiP time-dependent control
QuTiP requires that "callback" functions that are used to express
time-dependent controls take a parameter `t` and `args`. This function
takes a function `func` that takes `t` as its first parameter and an
arbitrary number of other parameters. The given `kwargs` set values for
these other parameters. Parameters not contained in `kwargs` are set
*at runtime* from the `args` dict.
"""
partial_func = functools.partial(func, **kwargs)
def callback(t, args):
if args is None:
args = {}
return partial_func(t, **args)
return callback
[docs]def zero_shape(t):
"""Shape function 0 for all values of `t`"""
return 0
[docs]def one_shape(t):
"""Shape function 1 for all values of `t`"""
return 1
[docs]def flattop(t, t_start, t_stop, t_rise, t_fall=None, func='blackman'):
"""Flat shape (one) with a switch-on/switch-off from zero
The flattop function starts at 0, and ramps to to 1 during the `t_rise`
interval. For ``func='blackman'``, the switch-on shape is half of a
Blackman window (see :func:`blackman`). For ``func='sinsq``, it is a
sine-squared curve. The function then remains at value 1, before ramping
down to 0 again during `t_fall`.
Args:
t (float): Time point or time grid
t_start (float): Start of flattop window
t_stop (float): Stop of flattop window
t_rise (float): Duration of ramp-up, starting at `t_start`
t_fall (float): Duration of ramp-down, ending at `t_stop`.
If not given, ``t_fall=t_rise``.
func (str): One of 'blackman', 'sinsq'
Note:
You may use :class:`numpy.vectorize` to transform this into a shape
function for arrays, :func:`functools.partial` to fix the function
arguments other than `t`, creating a function suitable for the
`update_shape` value of `pulse_options`, and :func:`qutip_callback` to
create a function suitable as a time-dependent control in QuTiP.
"""
if t_fall is None:
t_fall = t_rise
if func == 'blackman':
return _flattop_blackman(t, t_start, t_stop, t_rise, t_fall)
elif func == 'sinsq':
return _flattop_sinsq(t, t_start, t_stop, t_rise, t_fall)
else:
raise ValueError("Invalid func: %s" % func)
def _flattop_sinsq(t, t_start, t_stop, t_rise, t_fall):
if t_start <= t <= t_stop:
f = 1.0
if t <= t_start + t_rise:
f = np.sin(np.pi * (t - t_start) / (2.0 * t_rise)) ** 2
elif t >= t_stop - t_fall:
f = np.sin(np.pi * (t - t_stop) / (2.0 * t_fall)) ** 2
return f
else:
return 0.0
def _flattop_blackman(t, t_start, t_stop, t_rise, t_fall):
if t_start <= t <= t_stop:
f = 1.0
if t <= t_start + t_rise:
f = blackman(t, t_start, t_start + 2 * t_rise)
elif t >= t_stop - t_fall:
f = blackman(t, t_stop - 2 * t_fall, t_stop)
return f
else:
return 0.0
[docs]def box(t, t_start, t_stop):
"""Box-shape (Theta-function)
The shape is 0 before `t_start` and after `t_stop` and 1 elsewhere.
Args:
t (float): Time point or time grid
t_start (float): First value of `t` for which the box has value 1
t_stop (float): Last value of `t` for which the box has value 1
Note:
You may use :class:`numpy.vectorize`, :func:`functools.partial`, or
:func:`qutip_callback`, cf. :func:`flattop`.
"""
if t < t_start:
return 0.0
if t > t_stop:
return 0.0
return 1.0
[docs]def blackman(t, t_start, t_stop, a=0.16):
r"""Blackman window shape
.. math::
B(t; t_0, t_1) =
\frac{1}{2}\left(
1 - a - \cos\left(2\pi \frac{t - t_0}{t_1 - t_0}\right)
+ a \cos\left(4\pi \frac{t - t_0}{t_1 - t_0}\right)
\right)\,,
with $a = 0.16$.
See http://en.wikipedia.org/wiki/Window_function#Blackman_windows
A Blackman shape looks nearly identical to a Gaussian with a 6-sigma
interval between `t_start` and `t_stop`. Unlike the Gaussian,
however, it will go exactly to zero at the edges. Thus, Blackman pulses
are often preferable to Gaussians.
Args:
t (float or numpy.ndarray): Time point or time grid
t_start (float): Starting point $t_0$ of Blackman shape
t_stop (float): End point $t_1$ of Blackman shape
a (float): Blackman coefficient.
Returns:
float or numpy.ndarray: If `t` is a float, return the value of the
Blackman shape at `t`. If `t` is an array, return an array of same
size as `t`, containing the values for the Blackman shape (zero before
`t_start` and after `t_stop`)
"""
T = t_stop - t_start
box_vec = np.vectorize(box)
return (
0.5
* box_vec(t, t_start, t_stop)
* (
1.0
- a
- np.cos(2.0 * np.pi * (t - t_start) / T)
+ a * np.cos(4.0 * np.pi * (t - t_start) / T)
)
)