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

Compute BOLD online in Numba backend #546

Open
maedoc opened this issue Apr 1, 2022 · 1 comment
Open

Compute BOLD online in Numba backend #546

maedoc opened this issue Apr 1, 2022 · 1 comment
Labels
area/scilib enhancement New feature or request

Comments

@maedoc
Copy link
Member

maedoc commented Apr 1, 2022

Describe the new feature or enhancement

When simulating BOLD with the Numba backend, one currently has to first do the simulation then process the time series with the BOLD analyzer. For long time series, it is more memory-efficient to compute the BOLD in an online fashion.

Describe your proposed implementation

import numpy as np
import numba as nb

def make_bold():
    tau_s = nb.float32(0.65)
    tau_f = nb.float32(0.41)
    tau_o = nb.float32(0.98)
    alpha = nb.float32(0.32)
    te = nb.float32(0.04)
    v0 = nb.float32(4.0)
    e0 = nb.float32(0.4)
    epsilon = nb.float32(0.5)
    nu_0 = nb.float32(40.3)
    r_0 = nb.float32(25.0)
    recip_tau_s = nb.float32(1.0 / tau_s)
    recip_tau_f = nb.float32(1.0 / tau_f)
    recip_tau_o = nb.float32(1.0 / tau_o)
    recip_alpha = nb.float32(1.0 / alpha)
    recip_e0 = nb.float32(1.0 / e0)
    k1 = nb.float32(4.3 * nu_0 * e0 * te)
    k2 = nb.float32(epsilon * r_0 * e0 * te)
    k3 = nb.float32(1.0 - epsilon)
    
    @numba.njit
    def bold_step(state, x, dt):
        s = state[0]
        f = state[1]
        v = state[2]
        q = state[3]
        ds = x - recip_tau_s * s - recip_tau_f * (f - 1)
        df = s
        dv = recip_tau_o * (f - v**recip_alpha)
        dq = recip_tau_o * (f * (1 - (1 - e0)**(1 / f)) * recip_e0 - v**recip_alpha * (q / v))
        s += dt * ds
        f += dt * df
        v += dt * dv
        q += dt * dq
        state[0] = s
        state[1] = f
        state[2] = v
        state[3] = q
        return v0 * (k1*(1 - q) + k2*(1 - q / v) + k3*(1 - v))

    return bold_step

This should be integrated with the Numba backend:

  • check if BOLD is requested
  • allocate extra areas for BOLD
  • include calls to bold_step at each time step in the simulation, over each node & svar
  • return BOLD in addition to time series
@maedoc
Copy link
Member Author

maedoc commented Apr 1, 2022

Some of the BOLD derivatives are subject to loss of precision: open Herbie and enter f * (1 - pow(1 - e0, 1 / f)) * recip_e0 - pow(v,recip_alpha) * (q / v), and click v for bit error,
image
Their analysis suggest how to rewrite to drop that bit error from the red line to the blue line.

Fortunately the 1st ODE where x appears is linear wrt. x, so maybe these changes aren't needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/scilib enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant