DFunction#

Discrete function with interpolation

User level function of the Quantarhei package. To be used as:

>>> import quantarhei as qr
>>> f = qr.DFunction()

Discrete representation of a function with several modes of interpolation. Once defined, the function values are obtained by the method at(x), which takes the function argument and optionally a specification of the interpolation type. See examples below.

The linear interpolation is the default initially. Once the function is interpolated by splines (which happens why you call it with approx=”spline”), the default switches to “spline”. You can always enforce the type of interpolation by specifying it explicitely by the approx argument.

Examples

>>> import numpy
>>> x = numpy.linspace(0.0,95.0,20)
>>> y = numpy.exp(-x/30.0)
>>> u = ValueAxis(0.0,len(x),x[1]-x[0])
>>> f = DFunction(u,y)
>>> "%.4f" % f.axis.step
'5.0000'

Values at the points where the function was defined are exact

>>> "%.4f" % f.at(0.0)
'1.0000'
>>> "%.4f" % f.at(5.0)
'0.8465'

This is the exact value between the discrete points on which the function was defined

>>> "%.4f" % numpy.exp(-2.0/30.0)
'0.9355'

Default linear approximation leads to a difference at the second digit

>>> "%.4f" % f.at(2.0)
'0.9386'

Spline approximation is much better

>>> "%.4f" % f.at(2.0,approx='spline')
'0.9355'

Fourier transform of a DFunction

>>> from .time import TimeAxis
>>> dt = 0.1; Ns = 10000
>>> t = TimeAxis(-(Ns//2)*dt,Ns,dt,atype="complete")
>>> gg = 1.0/30.0
>>> y = numpy.exp(-numpy.abs(t.data)*gg)
>>> f = DFunction(t,y)
>>> F = f.get_Fourier_transform()
>>> print(numpy.allclose(F.at(0.0,approx="spline"),2.0/gg,rtol=1.0e-5))
True
>>> print(numpy.allclose(F.at(1.0),2*gg/(gg**2 + 1.0**2),rtol=1.0e-3))
True
>>> print(numpy.allclose(F.at(0.15),2*gg/(gg**2 + 0.15**2),rtol=1.0e-4))
True
>>> t = TimeAxis(0,Ns,dt)
>>> print(t.atype == "upper-half")
True
>>> gg = 1.0/30.0
>>> y = numpy.exp(-numpy.abs(t.data)*gg)
>>> f = DFunction(t,y)
>>> F = f.get_Fourier_transform()
>>> print(numpy.allclose(F.at(0.0,approx="spline"),2.0/gg,rtol=1.0e-5))
True
>>> print(numpy.allclose(F.at(1.0),2*gg/(gg**2 + 1.0**2),rtol=1.0e-3))
True
>>> print(numpy.allclose(F.at(0.15),2*gg/(gg**2 + 0.15**2),rtol=1.0e-4))
True

DFunction can be complex valued

>>> y = numpy.sin(t.data/10.0) + 1j*numpy.cos(t.data/10.0)
>>> fi = DFunction(t,y)
>>> print(numpy.allclose(fi.at(13.2,approx="spline"),    (numpy.sin(13.2/10.0) + 1j*numpy.cos(13.2/10.0)),rtol=1.0e-7))
True

Only “linear” and “spline” approximations are available >>> fval = fi.at(11.2, approx=”quadratic”) Traceback (most recent call last): … quantarhei.exceptions.QuantarheiError: Unknown interpolation type

Class Details#

class quantarhei.core.dfunction.DFunction(x: ValueAxis | None = None, y: ndarray | None = None)[source]#

Bases: Saveable, DataSaveable

Discrete function with interpolation

Parameters:
  • x (ValueAxis (such as TimeAxis, FrequencyAxis etc.)) – Array of the values of the argument of the discrete function

  • y (numpy.ndarray) – Array of the function values

Examples

How not to create the DFunction:

First argument of the DFunction must be a ValueAxis

>>> x1 = numpy.array([0.0, 1.0, 2.0], dtype=REAL)
>>> y1 = numpy.array([0.0, 12.0, 24.0], dtype=REAL)
>>> f = DFunction(x=x1, y=y1)
Traceback (most recent call last):
    ...
quantarhei.exceptions.QuantarheiError: First argument has to be of a ValueAxis type

Second argument must by a numpy array

>>> x1 = ValueAxis(0.0, 2, 1.0)
>>> y1 = [0.0, 12.0, 24.0]
>>> f = DFunction(x=x1, y=y1)
Traceback (most recent call last):
    ...
quantarhei.exceptions.QuantarheiError: Second argument has to be one-dimensional numpy.ndarray

The two arguments have to have the same size (number of elements)

>>> x1 = ValueAxis(0.0, 2, 1.0)
>>> y1 = numpy.array([0.0, 12.0, 24.0, 36.0], dtype=REAL)
>>> f = DFunction(x=x1, y=y1)
Traceback (most recent call last):
    ...
quantarhei.exceptions.QuantarheiError: Wrong number of elements in 1D numpy.ndarray
>>> x1 = ValueAxis(0.0, 2, 1.0)
>>> y1 = numpy.array([[0.0, 12.0, 24.0], [36.0, 48.0, 60.0]], dtype=REAL)
>>> f = DFunction(x=x1, y=y1)
Traceback (most recent call last):
    ...
quantarhei.exceptions.QuantarheiError: Second argument has to be one-dimensional numpy.ndarray
allowed_interp_types = ('linear', 'spline', 'default')#
change_axis(axis: ValueAxis) None[source]#

Replaces the axis object with a compatible one, zero pads or trims the values

Examples

>>> time = TimeAxis(0.0, 1000, 1.0)
>>> vals = numpy.cos(2.0*numpy.pi*time.data/500.0)
>>> fce = DFunction(time, vals)
>>> print("%.4f" % fce.at(914.0))
0.4707
>>> time1 = TimeAxis(0.0, 1000, 1.0)
>>> fce.change_axis(time1)
>>> fce.axis == time1
True
>>> time2 = TimeAxis(0.0, 900, 1.0)
>>> fce.change_axis(time2)
>>> print("%.4f" % fce.at(914.0))
Traceback (most recent call last):
    ...
quantarhei.exceptions.QuantarheiError: Value out of bounds
>>> print("%.4f" % fce.at(814.0))
-0.6937

Zero-padding

>>> time3 = TimeAxis(0.0, 1000, 1.0)
>>> fce.change_axis(time3)
>>> print("%.4f" % fce.at(814.0))
-0.6937
>>> print("%.4f" % fce.at(914.0))
0.0000
>>> time4 = TimeAxis(0.0, 100, 10.0)
>>> fce.change_axis(time4)
Traceback (most recent call last):
    ...
quantarhei.exceptions.QuantarheiError: Incompatible axis
at(x: Any, approx: str = 'default') Any[source]#

Return the function value at argument x.

The default interpolation is 'linear' until spline interpolation is first requested via approx='spline', after which 'spline' becomes the default.

Parameters:
  • x (float) – Function argument.

  • approx (str, optional) – Interpolation type: 'default', 'linear', or 'spline'. Default is 'default'.

Returns:

float or complex – Interpolated function value at x.

Raises:

Exception – If approx is not one of the allowed interpolation types.

Examples

>>> time = TimeAxis(0.0, 100, 10.0)
>>> vals = numpy.cos(2.0*numpy.pi*time.data/300.0)
>>> fce = DFunction(time, vals)
>>> print("%.8f" % fce.at(213.4))
-0.23949089
>>> print("%.8f" % fce.at(213.4, approx="linear"))
-0.23949089
>>> print("%.8f" % fce.at(213.4, approx="spline"))
-0.24056615
>>> print("%.8f" % numpy.cos(2.0*numpy.pi*213.4/300.0))
-0.24056687

Once the splines are initialized, they become default >>> print(“%.8f” % fce.at(213.4)) -0.24056615

as_spline_function() Callable[[Any], Any][source]#

Returns this function as a normal function of one argument

apply_to_data(func: Callable[[ndarray], ndarray]) None[source]#

Applies a submitted function to the data

>>> x = TimeAxis(0.0, 314, 0.001)
>>> f1 = DFunction(x, x.data)
>>> f2 = DFunction(x, numpy.cos(x.data))
>>> f1.data[100] == f2.data[100]
False
>>> f1.apply_to_data(numpy.cos)
>>> f1.data[100] == f2.data[100]
True
>>> f1.data[160] == f2.data[160]
True
get_Fourier_transform(window: DFunction | None = None) DFunction[source]#

Return the Fourier transform of the DFunction.

Parameters:

window (DFunction, optional) – Window function to multiply the data before transforming. Must share the same axis. If None, a rectangular window of ones is used.

Returns:

DFunction – Fourier-transformed function defined on the dual FrequencyAxis.

Raises:

Exception – If the axis type is not 'complete' or 'upper-half'.

Examples

>>> t = TimeAxis(0.0, 200, 1.0)

The default type of TimeAxis is “upper-half”

>>> print(t.atype)
upper-half

We create a function with this TimeAxis

>>> f = DFunction(t, numpy.exp(((-t.data-50.0)**2)/(30.0**2)))
>>> F = f.get_Fourier_transform()

When TimeAxis is the “upper-half” it is assumed that only half of the function is specified. The “lower-half” corresponds to a complex conjugated function, and FT is real.

>>> rmax = numpy.max(numpy.abs(numpy.real(F.data)))
>>> imax = numpy.max(numpy.abs(numpy.imag(F.data)))
>>> imax/rmax < 1.0e-15
True
>>>

The same with “complete” gives a complex result

>>> t = TimeAxis(0.0, 200, 1.0, atype="complete")
>>> f = DFunction(t, numpy.exp((-(t.data-50.0)**2)/(30.0**2)))
>>> F = f.get_Fourier_transform()
>>> rmax = numpy.max(numpy.abs(numpy.real(F.data)))
>>> imax = numpy.max(numpy.abs(numpy.imag(F.data)))
>>> imax/rmax  < 1.0e-15
False
>>> f.axis.atype="lower-half"
>>> F = f.get_Fourier_transform()
Traceback (most recent call last):
    ...
quantarhei.exceptions.QuantarheiError: Unknown time axis type
get_inverse_Fourier_transform() DFunction[source]#

Returns inverse Fourier transform of the DFunction

>>> import quantarhei as qr
>>> t = TimeAxis(-100.0, 200, 1.0)
>>> f = DFunction(t, numpy.exp(-(t.data**2)/(30.0**2)))
>>> F = f.get_Fourier_transform()
>>> fn = F.get_inverse_Fourier_transform()
>>> numpy.testing.assert_allclose(numpy.real(fn.data[100]), f.data[100])
>>> dw = qr.convert(5.0,"1/cm","int")
>>> w = FrequencyAxis(0.0, 100, dw) #t.get_FrequencyAxis()
>>> delt = qr.convert(30.0,"1/cm","int")
>>> F = DFunction(w, numpy.exp((w.data**2)/(delt**2)))
>>> f = F.get_inverse_Fourier_transform()
>>> isinstance(f.axis, TimeAxis)
True
fit_exponential(guess: list[float] | None = None) ndarray[source]#

Exponential fit of the function

Examples

>>> t = TimeAxis(0.0, 100, 1.0)
>>> f = DFunction(t, 2.3*numpy.exp(-(t.data)/(10.0))+0.32)
>>> popt = f.fit_exponential()
>>> print(popt)
[ 2.3   0.1   0.32]
fit_gaussian(N: int = 1, guess: list[float] | None = None, Nsvf: int = 251) ndarray[source]#

Performs a Gaussian fit of the spectrum based on an initial guess

Parameters:

Nsvf (int) – Length of the Savitzky-Golay filter window (odd integer)

Examples

>>> t = TimeAxis(0.0, 100, 1.0)
>>> f = DFunction(t, 2.3*numpy.exp(-(4.0*numpy.log(2.0))*((t.data-30.0)**2)/(10.0**2))+0.32)
>>> popt = f.fit_gaussian(guess=[1.0, 33.0, 5.0, 0.5])
>>> print(popt)
[  2.3   30.    10.     0.32]
plot(fig: Any = None, title: str | None = None, title_font: Any = None, axis: list[float] | None = None, vmax: float | None = None, vmin: float | None = None, xlabel: str | None = None, ylabel: str | None = None, label_font: Any = None, text: Any = None, text_font: Any = None, label: str | None = None, text_loc: list[float] | None = None, fontsize: str = '20', real_only: bool = True, show: bool = False, color: Any = None, **kwargs: Any) None[source]#

Plotting of the DFunction’s data against the ValueAxis.

Parameters:
  • title (str) – Title of the plot

  • title_font (str) – Name of the title font

savefig(filename: str) None[source]#

Saves current figure into a file