fpex0.fokker_planck API documentation

# fpex0.fokker_planck

View Source

      1import numpy as np
      2from scipy import sparse
      3
      4class FokkerPlanck:
      5    def __init__(self):
      6        self._NN         = None # variables for FokkerPlanckODE_dfdu()
      7        self._A          = None
      8        self._B          = None
      9
     10    @staticmethod
     11    def FokkerPlanckODE(t, u, h, driftFcn, driftParams, diffusionFcn, diffusionParams):
     12        """
     13        ODE RHS of Fokker-Planck PDE by using the method of lines (MOL) approach.
     14
     15        FP-PDE
     16        >       u_t = - a(t,p) * u_x(t,x)  +  D(t,p) * u_xx(t,x)
     17
     18        FD-Approx
     19        >       u_x  = ( u(t,x+h) - u(t,x-h ) / (2h)
     20        >       u_xx = ( u(t,x+h) - 2u(t,x) + u(t,x-h) ) / h
     21
     22        ## Takes
     23        **t**: Time
     24
     25        **x**: State vector
     26
     27        **h**: MOL interval size
     28
     29        **driftFcn**
     30        <br> Drift function, evaluated at t, driftP.
     31
     32        **driftParams**
     33        <br> Parameter vector for drift function.
     34
     35        **diffusionFcn**
     36        <br> Diffusion function, evaluated at t, driftP.
     37
     38        **diffusionParams**
     39        <br> Parameter vector for diffusion function.
     40
     41        ## Returns
     42        **dx**
     43        <br> rhs vector.
     44        """
     45
     46        # number of grid points and number of simultaneously requested vectors
     47        shape = u.shape
     48        # shape is (N,) if u is a one-dim array
     49        if len(shape) > 1:
     50            (N, vectors) = shape
     51        else:
     52            N = shape[0]
     53            vectors = 1
     54
     55        # preallocate vectors for A*u (approx. of u_x) and B*u (approx. of u_xx)
     56        Bu = np.zeros_like(u)
     57        Au = np.zeros_like(u)
     58
     59        # numpy indexing is works differently for 1d and Nd arrays
     60        if vectors > 1:
     61            # first node
     62            Bu[0,:] = ( -2*u[0,:] + 2*u[1,:] ) / h**2
     63            # Au(1) is zero
     64
     65            # inner nodes (remember: python slicing is exclusive right)
     66            i = np.arange(1,N-1)
     67            Au[i,:] = ( u[i-1,:] - u[i+1,:] ) / (2*h)            # 1st derivative stencil and scale
     68            Bu[i,:] = ( u[i-1,:] - 2*u[i,:] + u[i+1,:] ) / h**2  # 2nd derivative stencil and scale
     69
     70            # last node
     71            Bu[N-1,:] = ( -2*u[N-1,:] + 2*u[N-2,:] ) / h**2
     72            # Au(N) is zero
     73        elif vectors == 1:
     74            # first node
     75            Bu[0] = ( -2*u[0] + 2*u[1] ) / h**2
     76            # Au(1) is zero
     77
     78            # inner nodes (remember: python slicing is exclusive right)
     79            i = np.arange(1,N-1)
     80            Au[i] = ( u[i-1] - u[i+1] ) / (2*h)           # 1st derivative stencil and scale
     81            Bu[i] = ( u[i-1] - 2*u[i] + u[i+1] ) / h**2   # 2nd derivative stencil and scale
     82
     83            # last node
     84            Bu[N-1] = ( -2*u[N-1] + 2*u[N-2] ) / h**2
     85            # Au[N-1] is zero
     86
     87        # evaluate drift and diffusion
     88        alpha = driftFcn(t,driftParams)
     89        D = diffusionFcn(t,diffusionParams)
     90
     91        # assemble rhs
     92        dx = -alpha*Au + D*Bu
     93        return dx
     94
     95
     96    def FokkerPlanckODE_dfdu(self, t, u, h, driftFcn, driftParams, diffusionFcn, diffusionParams):
     97        """
     98        Jacobian of FokkerPlanckODE w.r.t. state u, i.e. df/du.
     99
    100        FP-PDE
    101        >       u_t = - a(t,p) * u_x(t,x)  +  D(t,p) * u_xx(t,x)
    102        >
    103        >       where a is the driftFcn, and b is the diffusionFcn
    104
    105        FD-Approx
    106        >       u_x  = ( u(t,x+h) - u(t,x-h ) / (2h)
    107        >       u_xx = ( u(t,x+h) - 2u(t,x) + u(t,x-h) ) / h
    108
    109        Jacobian
    110        >       df/du = -a(t,p) * A + D(t,p) * B
    111        >
    112        >       where A is the first-derivative stencil [-1 0 1]
    113        >       and B is the second-derivative stencil [1 -2 1] plus Robin boundary
    114
    115        ## Takes
    116        **t**: Time
    117
    118        **x**: State vector
    119
    120        **h**: MOL interval size
    121
    122        **driftFcn**
    123        <br> Drift function, evaluated at t, driftP.
    124
    125        **driftParams**
    126        <br> Parameter vector for drift function.
    127
    128        **diffusionFcn**
    129        <br> Diffusion function, evaluated at t, driftP.
    130
    131        **diffusionParams**
    132        <br> Parameter vector for diffusion function.
    133
    134
    135        ## Returns
    136        **dfdu**
    137        <br> Sparse jacobian of FokkerPlanckODE (scipy.sparse).
    138        """
    139        # dimension
    140        N = len(u)
    141
    142        # if dimension has changed, we have to reassemble the stencil
    143        if N != self._NN:
    144            e1 = np.ones(N)
    145            e0 = np.zeros(N)
    146            # 1st order stencil
    147            self._A =  sparse.dia_matrix(( np.array([e1, e0, -e1]), [-1, 0, 1] ), shape=(N, N))
    148            self._A = sparse.csr_matrix(self._A)   # change format to edit single entries
    149            self._A[0  ,1  ] = 0
    150            self._A[N-1,N-2] = 0
    151            # 2nd order stencil + robin boundary
    152            self._B = sparse.dia_matrix(( np.array([e1 , -2*e1 ,  e1]), [-1,0,1] ), shape=(N, N))
    153            self._B = sparse.csr_matrix(self._B)
    154            self._B[0  ,1  ] = 2
    155            self._B[N-1,N-2] = 2
    156            self._NN = N
    157
    158        # evaluate drift and diffusion
    159        alpha = driftFcn(t, driftParams)
    160        D     = diffusionFcn(t, diffusionParams)
    161
    162        # asseble the jacobian
    163        dfdu = -alpha * self._A / (2*h)  +  D * self._B / h**2
    164        return dfdu
    165
    166    @staticmethod
    167    def defaultDriftFcn(t,p):
    168        """
    169        Default drift function used in FPEX0.
    170
    171        ## Takes
    172        **t**
    173        <br> Current time / heating rate.
    174
    175        **p**
    176        <br> Drift parameter vector (drift-parameters only!).
    177
    178
    179        ## Returns
    180        **fval**
    181        <br> Function value for drift.
    182        """
    183
    184        # linear drift parametrization
    185        fval = p[0] + p[1] * t
    186        return fval
    187
    188    @staticmethod
    189    def defaultDiffusionFcn(t,p,betamax):
    190        """
    191        Default diffusion function used in FPEX0.
    192
    193        ## Takes
    194        **t**
    195        <br> Current time / heating rate.
    196
    197        **p**
    198        <br> Diffusion parameter vector (diffusion-parameters only!).
    199
    200        **betamax**
    201        <br> Maximum time / heat rate (used for ensuring non-negativity).
    202
    203
    204        ## Returns
    205        **fval**
    206        <br> Function value for diffusion.
    207        """
    208
    209        # linear parametrization ensuring non-negativity for non-negative p1 and p2
    210        fval = p[0] + t * (p[1] - p[0]) / betamax
    211
    212        return fval

class FokkerPlanck: View Source

      5class FokkerPlanck:
      6    def __init__(self):
      7        self._NN         = None # variables for FokkerPlanckODE_dfdu()
      8        self._A          = None
      9        self._B          = None
     10
     11    @staticmethod
     12    def FokkerPlanckODE(t, u, h, driftFcn, driftParams, diffusionFcn, diffusionParams):
     13        """
     14        ODE RHS of Fokker-Planck PDE by using the method of lines (MOL) approach.
     15
     16        FP-PDE
     17        >       u_t = - a(t,p) * u_x(t,x)  +  D(t,p) * u_xx(t,x)
     18
     19        FD-Approx
     20        >       u_x  = ( u(t,x+h) - u(t,x-h ) / (2h)
     21        >       u_xx = ( u(t,x+h) - 2u(t,x) + u(t,x-h) ) / h
     22
     23        ## Takes
     24        **t**: Time
     25
     26        **x**: State vector
     27
     28        **h**: MOL interval size
     29
     30        **driftFcn**
     31        <br> Drift function, evaluated at t, driftP.
     32
     33        **driftParams**
     34        <br> Parameter vector for drift function.
     35
     36        **diffusionFcn**
     37        <br> Diffusion function, evaluated at t, driftP.
     38
     39        **diffusionParams**
     40        <br> Parameter vector for diffusion function.
     41
     42        ## Returns
     43        **dx**
     44        <br> rhs vector.
     45        """
     46
     47        # number of grid points and number of simultaneously requested vectors
     48        shape = u.shape
     49        # shape is (N,) if u is a one-dim array
     50        if len(shape) > 1:
     51            (N, vectors) = shape
     52        else:
     53            N = shape[0]
     54            vectors = 1
     55
     56        # preallocate vectors for A*u (approx. of u_x) and B*u (approx. of u_xx)
     57        Bu = np.zeros_like(u)
     58        Au = np.zeros_like(u)
     59
     60        # numpy indexing is works differently for 1d and Nd arrays
     61        if vectors > 1:
     62            # first node
     63            Bu[0,:] = ( -2*u[0,:] + 2*u[1,:] ) / h**2
     64            # Au(1) is zero
     65
     66            # inner nodes (remember: python slicing is exclusive right)
     67            i = np.arange(1,N-1)
     68            Au[i,:] = ( u[i-1,:] - u[i+1,:] ) / (2*h)            # 1st derivative stencil and scale
     69            Bu[i,:] = ( u[i-1,:] - 2*u[i,:] + u[i+1,:] ) / h**2  # 2nd derivative stencil and scale
     70
     71            # last node
     72            Bu[N-1,:] = ( -2*u[N-1,:] + 2*u[N-2,:] ) / h**2
     73            # Au(N) is zero
     74        elif vectors == 1:
     75            # first node
     76            Bu[0] = ( -2*u[0] + 2*u[1] ) / h**2
     77            # Au(1) is zero
     78
     79            # inner nodes (remember: python slicing is exclusive right)
     80            i = np.arange(1,N-1)
     81            Au[i] = ( u[i-1] - u[i+1] ) / (2*h)           # 1st derivative stencil and scale
     82            Bu[i] = ( u[i-1] - 2*u[i] + u[i+1] ) / h**2   # 2nd derivative stencil and scale
     83
     84            # last node
     85            Bu[N-1] = ( -2*u[N-1] + 2*u[N-2] ) / h**2
     86            # Au[N-1] is zero
     87
     88        # evaluate drift and diffusion
     89        alpha = driftFcn(t,driftParams)
     90        D = diffusionFcn(t,diffusionParams)
     91
     92        # assemble rhs
     93        dx = -alpha*Au + D*Bu
     94        return dx
     95
     96
     97    def FokkerPlanckODE_dfdu(self, t, u, h, driftFcn, driftParams, diffusionFcn, diffusionParams):
     98        """
     99        Jacobian of FokkerPlanckODE w.r.t. state u, i.e. df/du.
    100
    101        FP-PDE
    102        >       u_t = - a(t,p) * u_x(t,x)  +  D(t,p) * u_xx(t,x)
    103        >
    104        >       where a is the driftFcn, and b is the diffusionFcn
    105
    106        FD-Approx
    107        >       u_x  = ( u(t,x+h) - u(t,x-h ) / (2h)
    108        >       u_xx = ( u(t,x+h) - 2u(t,x) + u(t,x-h) ) / h
    109
    110        Jacobian
    111        >       df/du = -a(t,p) * A + D(t,p) * B
    112        >
    113        >       where A is the first-derivative stencil [-1 0 1]
    114        >       and B is the second-derivative stencil [1 -2 1] plus Robin boundary
    115
    116        ## Takes
    117        **t**: Time
    118
    119        **x**: State vector
    120
    121        **h**: MOL interval size
    122
    123        **driftFcn**
    124        <br> Drift function, evaluated at t, driftP.
    125
    126        **driftParams**
    127        <br> Parameter vector for drift function.
    128
    129        **diffusionFcn**
    130        <br> Diffusion function, evaluated at t, driftP.
    131
    132        **diffusionParams**
    133        <br> Parameter vector for diffusion function.
    134
    135
    136        ## Returns
    137        **dfdu**
    138        <br> Sparse jacobian of FokkerPlanckODE (scipy.sparse).
    139        """
    140        # dimension
    141        N = len(u)
    142
    143        # if dimension has changed, we have to reassemble the stencil
    144        if N != self._NN:
    145            e1 = np.ones(N)
    146            e0 = np.zeros(N)
    147            # 1st order stencil
    148            self._A =  sparse.dia_matrix(( np.array([e1, e0, -e1]), [-1, 0, 1] ), shape=(N, N))
    149            self._A = sparse.csr_matrix(self._A)   # change format to edit single entries
    150            self._A[0  ,1  ] = 0
    151            self._A[N-1,N-2] = 0
    152            # 2nd order stencil + robin boundary
    153            self._B = sparse.dia_matrix(( np.array([e1 , -2*e1 ,  e1]), [-1,0,1] ), shape=(N, N))
    154            self._B = sparse.csr_matrix(self._B)
    155            self._B[0  ,1  ] = 2
    156            self._B[N-1,N-2] = 2
    157            self._NN = N
    158
    159        # evaluate drift and diffusion
    160        alpha = driftFcn(t, driftParams)
    161        D     = diffusionFcn(t, diffusionParams)
    162
    163        # asseble the jacobian
    164        dfdu = -alpha * self._A / (2*h)  +  D * self._B / h**2
    165        return dfdu
    166
    167    @staticmethod
    168    def defaultDriftFcn(t,p):
    169        """
    170        Default drift function used in FPEX0.
    171
    172        ## Takes
    173        **t**
    174        <br> Current time / heating rate.
    175
    176        **p**
    177        <br> Drift parameter vector (drift-parameters only!).
    178
    179
    180        ## Returns
    181        **fval**
    182        <br> Function value for drift.
    183        """
    184
    185        # linear drift parametrization
    186        fval = p[0] + p[1] * t
    187        return fval
    188
    189    @staticmethod
    190    def defaultDiffusionFcn(t,p,betamax):
    191        """
    192        Default diffusion function used in FPEX0.
    193
    194        ## Takes
    195        **t**
    196        <br> Current time / heating rate.
    197
    198        **p**
    199        <br> Diffusion parameter vector (diffusion-parameters only!).
    200
    201        **betamax**
    202        <br> Maximum time / heat rate (used for ensuring non-negativity).
    203
    204
    205        ## Returns
    206        **fval**
    207        <br> Function value for diffusion.
    208        """
    209
    210        # linear parametrization ensuring non-negativity for non-negative p1 and p2
    211        fval = p[0] + t * (p[1] - p[0]) / betamax
    212
    213        return fval

FokkerPlanck() View Source

    6    def __init__(self):
    7        self._NN         = None # variables for FokkerPlanckODE_dfdu()
    8        self._A          = None
    9        self._B          = None

@staticmethod
def FokkerPlanckODE(t, u, h, driftFcn, driftParams, diffusionFcn, diffusionParams): View Source

    11    @staticmethod
    12    def FokkerPlanckODE(t, u, h, driftFcn, driftParams, diffusionFcn, diffusionParams):
    13        """
    14        ODE RHS of Fokker-Planck PDE by using the method of lines (MOL) approach.
    15
    16        FP-PDE
    17        >       u_t = - a(t,p) * u_x(t,x)  +  D(t,p) * u_xx(t,x)
    18
    19        FD-Approx
    20        >       u_x  = ( u(t,x+h) - u(t,x-h ) / (2h)
    21        >       u_xx = ( u(t,x+h) - 2u(t,x) + u(t,x-h) ) / h
    22
    23        ## Takes
    24        **t**: Time
    25
    26        **x**: State vector
    27
    28        **h**: MOL interval size
    29
    30        **driftFcn**
    31        <br> Drift function, evaluated at t, driftP.
    32
    33        **driftParams**
    34        <br> Parameter vector for drift function.
    35
    36        **diffusionFcn**
    37        <br> Diffusion function, evaluated at t, driftP.
    38
    39        **diffusionParams**
    40        <br> Parameter vector for diffusion function.
    41
    42        ## Returns
    43        **dx**
    44        <br> rhs vector.
    45        """
    46
    47        # number of grid points and number of simultaneously requested vectors
    48        shape = u.shape
    49        # shape is (N,) if u is a one-dim array
    50        if len(shape) > 1:
    51            (N, vectors) = shape
    52        else:
    53            N = shape[0]
    54            vectors = 1
    55
    56        # preallocate vectors for A*u (approx. of u_x) and B*u (approx. of u_xx)
    57        Bu = np.zeros_like(u)
    58        Au = np.zeros_like(u)
    59
    60        # numpy indexing is works differently for 1d and Nd arrays
    61        if vectors > 1:
    62            # first node
    63            Bu[0,:] = ( -2*u[0,:] + 2*u[1,:] ) / h**2
    64            # Au(1) is zero
    65
    66            # inner nodes (remember: python slicing is exclusive right)
    67            i = np.arange(1,N-1)
    68            Au[i,:] = ( u[i-1,:] - u[i+1,:] ) / (2*h)            # 1st derivative stencil and scale
    69            Bu[i,:] = ( u[i-1,:] - 2*u[i,:] + u[i+1,:] ) / h**2  # 2nd derivative stencil and scale
    70
    71            # last node
    72            Bu[N-1,:] = ( -2*u[N-1,:] + 2*u[N-2,:] ) / h**2
    73            # Au(N) is zero
    74        elif vectors == 1:
    75            # first node
    76            Bu[0] = ( -2*u[0] + 2*u[1] ) / h**2
    77            # Au(1) is zero
    78
    79            # inner nodes (remember: python slicing is exclusive right)
    80            i = np.arange(1,N-1)
    81            Au[i] = ( u[i-1] - u[i+1] ) / (2*h)           # 1st derivative stencil and scale
    82            Bu[i] = ( u[i-1] - 2*u[i] + u[i+1] ) / h**2   # 2nd derivative stencil and scale
    83
    84            # last node
    85            Bu[N-1] = ( -2*u[N-1] + 2*u[N-2] ) / h**2
    86            # Au[N-1] is zero
    87
    88        # evaluate drift and diffusion
    89        alpha = driftFcn(t,driftParams)
    90        D = diffusionFcn(t,diffusionParams)
    91
    92        # assemble rhs
    93        dx = -alpha*Au + D*Bu
    94        return dx

ODE RHS of Fokker-Planck PDE by using the method of lines (MOL) approach.

FP-PDE

>       u_t = - a(t,p) * u_x(t,x)  +  D(t,p) * u_xx(t,x)

FD-Approx

>       u_x  = ( u(t,x+h) - u(t,x-h ) / (2h)
>       u_xx = ( u(t,x+h) - 2u(t,x) + u(t,x-h) ) / h

## Takes

t: Time

x: State vector

h: MOL interval size

driftFcn
Drift function, evaluated at t, driftP.

driftParams
Parameter vector for drift function.

diffusionFcn
Diffusion function, evaluated at t, driftP.

diffusionParams
Parameter vector for diffusion function.

## Returns

dx
rhs vector.

def FokkerPlanckODE_dfdu(self, t, u, h, driftFcn, driftParams, diffusionFcn, diffusionParams): View Source

     97    def FokkerPlanckODE_dfdu(self, t, u, h, driftFcn, driftParams, diffusionFcn, diffusionParams):
     98        """
     99        Jacobian of FokkerPlanckODE w.r.t. state u, i.e. df/du.
    100
    101        FP-PDE
    102        >       u_t = - a(t,p) * u_x(t,x)  +  D(t,p) * u_xx(t,x)
    103        >
    104        >       where a is the driftFcn, and b is the diffusionFcn
    105
    106        FD-Approx
    107        >       u_x  = ( u(t,x+h) - u(t,x-h ) / (2h)
    108        >       u_xx = ( u(t,x+h) - 2u(t,x) + u(t,x-h) ) / h
    109
    110        Jacobian
    111        >       df/du = -a(t,p) * A + D(t,p) * B
    112        >
    113        >       where A is the first-derivative stencil [-1 0 1]
    114        >       and B is the second-derivative stencil [1 -2 1] plus Robin boundary
    115
    116        ## Takes
    117        **t**: Time
    118
    119        **x**: State vector
    120
    121        **h**: MOL interval size
    122
    123        **driftFcn**
    124        <br> Drift function, evaluated at t, driftP.
    125
    126        **driftParams**
    127        <br> Parameter vector for drift function.
    128
    129        **diffusionFcn**
    130        <br> Diffusion function, evaluated at t, driftP.
    131
    132        **diffusionParams**
    133        <br> Parameter vector for diffusion function.
    134
    135
    136        ## Returns
    137        **dfdu**
    138        <br> Sparse jacobian of FokkerPlanckODE (scipy.sparse).
    139        """
    140        # dimension
    141        N = len(u)
    142
    143        # if dimension has changed, we have to reassemble the stencil
    144        if N != self._NN:
    145            e1 = np.ones(N)
    146            e0 = np.zeros(N)
    147            # 1st order stencil
    148            self._A =  sparse.dia_matrix(( np.array([e1, e0, -e1]), [-1, 0, 1] ), shape=(N, N))
    149            self._A = sparse.csr_matrix(self._A)   # change format to edit single entries
    150            self._A[0  ,1  ] = 0
    151            self._A[N-1,N-2] = 0
    152            # 2nd order stencil + robin boundary
    153            self._B = sparse.dia_matrix(( np.array([e1 , -2*e1 ,  e1]), [-1,0,1] ), shape=(N, N))
    154            self._B = sparse.csr_matrix(self._B)
    155            self._B[0  ,1  ] = 2
    156            self._B[N-1,N-2] = 2
    157            self._NN = N
    158
    159        # evaluate drift and diffusion
    160        alpha = driftFcn(t, driftParams)
    161        D     = diffusionFcn(t, diffusionParams)
    162
    163        # asseble the jacobian
    164        dfdu = -alpha * self._A / (2*h)  +  D * self._B / h**2
    165        return dfdu

Jacobian of FokkerPlanckODE w.r.t. state u, i.e. df/du.

FP-PDE

>       u_t = - a(t,p) * u_x(t,x)  +  D(t,p) * u_xx(t,x)

>       where a is the driftFcn, and b is the diffusionFcn

FD-Approx

>       u_x  = ( u(t,x+h) - u(t,x-h ) / (2h)
>       u_xx = ( u(t,x+h) - 2u(t,x) + u(t,x-h) ) / h

Jacobian

>       df/du = -a(t,p) * A + D(t,p) * B

>       where A is the first-derivative stencil [-1 0 1]
>       and B is the second-derivative stencil [1 -2 1] plus Robin boundary

## Takes

t: Time

x: State vector

h: MOL interval size

driftFcn
Drift function, evaluated at t, driftP.

driftParams
Parameter vector for drift function.

diffusionFcn
Diffusion function, evaluated at t, driftP.

diffusionParams
Parameter vector for diffusion function.

## Returns

dfdu
Sparse jacobian of FokkerPlanckODE (scipy.sparse).

@staticmethod
def defaultDriftFcn(t, p): View Source

    167    @staticmethod
    168    def defaultDriftFcn(t,p):
    169        """
    170        Default drift function used in FPEX0.
    171
    172        ## Takes
    173        **t**
    174        <br> Current time / heating rate.
    175
    176        **p**
    177        <br> Drift parameter vector (drift-parameters only!).
    178
    179
    180        ## Returns
    181        **fval**
    182        <br> Function value for drift.
    183        """
    184
    185        # linear drift parametrization
    186        fval = p[0] + p[1] * t
    187        return fval

Default drift function used in FPEX0.

## Takes

t
Current time / heating rate.

p
Drift parameter vector (drift-parameters only!).

## Returns

fval
Function value for drift.

@staticmethod
def defaultDiffusionFcn(t, p, betamax): View Source

    189    @staticmethod
    190    def defaultDiffusionFcn(t,p,betamax):
    191        """
    192        Default diffusion function used in FPEX0.
    193
    194        ## Takes
    195        **t**
    196        <br> Current time / heating rate.
    197
    198        **p**
    199        <br> Diffusion parameter vector (diffusion-parameters only!).
    200
    201        **betamax**
    202        <br> Maximum time / heat rate (used for ensuring non-negativity).
    203
    204
    205        ## Returns
    206        **fval**
    207        <br> Function value for diffusion.
    208        """
    209
    210        # linear parametrization ensuring non-negativity for non-negative p1 and p2
    211        fval = p[0] + t * (p[1] - p[0]) / betamax
    212
    213        return fval

Default diffusion function used in FPEX0.

## Takes

t
Current time / heating rate.

p
Diffusion parameter vector (diffusion-parameters only!).

betamax
Maximum time / heat rate (used for ensuring non-negativity).

## Returns

fval
Function value for diffusion.