Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add argument for spline boundary conditions #2114

Merged
merged 7 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/changes/2114.misc
@@ -0,0 +1,2 @@
Added new argument bc_type to take boundary conditions when creating QobjEvo

7 changes: 6 additions & 1 deletion qutip/core/coefficient.py
Expand Up @@ -53,7 +53,8 @@ def _return(base, **kwargs):


def coefficient(base, *, tlist=None, args={}, args_ctypes={},
order=3, compile_opt=None, function_style=None, **kwargs):
order=3, compile_opt=None, function_style=None,
boundary_conditions=None, **kwargs):
"""Build ``Coefficient`` for time dependent systems:

```
Expand Down Expand Up @@ -149,6 +150,9 @@ def f2_t(t, args):
compile_opt : CompilationOptions, optional
Sets of options for the compilation of string based coefficients.

bc_type: 2-tupule or None, optional
Ericgig marked this conversation as resolved.
Show resolved Hide resolved
Specify boundary conditions for spline interpolation.

**kwargs
Extra arguments to pass the the coefficients.
"""
Expand All @@ -159,6 +163,7 @@ def f2_t(t, args):
'order': order,
'compile_opt': compile_opt,
'function_style': function_style,
'bc_type': bc_type,
})

for type_ in coefficient_builders:
Expand Down
13 changes: 11 additions & 2 deletions qutip/core/cy/coefficient.pyx
Expand Up @@ -387,14 +387,23 @@ cdef class InterCoefficient(Coefficient):
order : int
Order of the interpolation. Order ``0`` uses the previous (i.e. left)
value. The order will be reduced to ``len(tlist) - 1`` if it is larger.

bc_type : 2-Tuple or None, optional
Boundary conditions for spline evaluation. Default value is `None` to
enable automatically choosing boundary conditions. Otherwise, a two-length
tuple of form (`deriv_l`, `deriv_r`) must be passed. Here, `deriv_l` denotes
the boundary conditions at ```t = 0``` and deriv_r, the conditions at time
```t```. The condition specified must be an iterable pair of form (`order`,
`value`). Refer to Scipy's documentation for further details:
https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.make_interp_spline.html
Ericgig marked this conversation as resolved.
Show resolved Hide resolved
"""
cdef int order
cdef double dt
cdef double[::1] tlist
cdef complex[:, :] poly
cdef object np_arrays

def __init__(self, coeff_arr, tlist, int order, **_):
def __init__(self, coeff_arr, tlist, int order, bc_type, **_):
tlist = np.array(tlist, dtype=np.float64)
coeff_arr = np.array(coeff_arr, dtype=np.complex128)

Expand All @@ -418,7 +427,7 @@ cdef class InterCoefficient(Coefficient):
elif order >= 2:
# Use scipy to compute the spline and transform it to polynomes
# as used in scipy's PPoly which is easier for us to use.
spline = make_interp_spline(tlist, coeff_arr, k=order)
spline = make_interp_spline(tlist, coeff_arr, k=order, bc_type=bc_type)
# Scipy can move knots, we add them to tlist
tlist = np.sort(np.unique(np.concatenate([spline.t, tlist])))
a = np.arange(spline.k+1)
Expand Down
21 changes: 16 additions & 5 deletions qutip/core/cy/qobjevo.pyx
Expand Up @@ -99,6 +99,17 @@ cdef class QobjEvo:
``qutip.settings.core["function_coefficient_style"]``
is used. Otherwise the supplied value overrides the global setting.


bc_type : 2-Tuple or None, optional
Boundary conditions for spline evaluation. Default value is `None` to
enable automatically choosing boundary conditions. Otherwise, a two-length
tuple of form (`deriv_l`, `deriv_r`) must be passed. Here, `deriv_l` denotes
the boundary conditions at ```t = 0``` and deriv_r, the conditions at time
```t```. The condition specified must be an iterable pair of form (`order`,
`value`). Refer to Scipy's documentation for further details:
https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.make_interp_spline.html


Attributes
----------
dims : list
Expand Down Expand Up @@ -182,7 +193,7 @@ cdef class QobjEvo:
"""
def __init__(QobjEvo self, Q_object, args=None, tlist=None,
order=3, copy=True, compress=True,
function_style=None):
function_style=None, bc_type=None):
if isinstance(Q_object, QobjEvo):
self.dims = Q_object.dims.copy()
self.shape = Q_object.shape
Expand Down Expand Up @@ -217,29 +228,29 @@ cdef class QobjEvo:
self.elements.append(
self._read_element(
op, copy=copy, tlist=tlist, args=args, order=order,
function_style=function_style
function_style=function_style, bc_type=bc_type
)
)
else:
self.elements.append(
self._read_element(
Q_object, copy=copy, tlist=tlist, args=args, order=order,
function_style=function_style
function_style=function_style, bc_type=bc_type
)
)

if compress:
self.compress()

def _read_element(self, op, copy, tlist, args, order, function_style):
def _read_element(self, op, copy, tlist, args, order, function_style, bc_type):
""" Read a Q_object item and return an element for that item. """
if isinstance(op, Qobj):
out = _ConstantElement(op.copy() if copy else op)
qobj = op
elif isinstance(op, list):
out = _EvoElement(
op[0].copy() if copy else op[0],
coefficient(op[1], tlist=tlist, args=args, order=order)
coefficient(op[1], tlist=tlist, args=args, order=order, bc_type=bc_type)
)
qobj = op[0]
elif isinstance(op, _BaseElement):
Expand Down
4 changes: 4 additions & 0 deletions qutip/tests/core/test_coefficient.py
Expand Up @@ -372,6 +372,10 @@ def test_CoeffFromScipy():
from_scipy = coefficient(interp.make_interp_spline(tlist, y, k=3))
_assert_eq_over_interval(coeff, from_scipy, rtol=1e-8, inside=True)

coeff = coefficient(y, tlist=tlist, order=3, bc_type=([(2, 0.0)],[(2, 0.0)]))
awkwardPotato812 marked this conversation as resolved.
Show resolved Hide resolved
from_scipy = coefficient(interp.make_interp_spline(tlist, y, k=3, bc_type="natural"))
_assert_eq_over_interval(coeff, from_scipy, rtol=1e-8, inside=True)


@pytest.mark.parametrize('map_func', [
pytest.param(qutip.solver.parallel.parallel_map, id='parallel_map'),
Expand Down