Skip to content
This repository was archived by the owner on Jan 27, 2023. It is now read-only.

Commit 1028ee4

Browse files
author
Antonio Ulloa
committed
Added MEG, NAI, PSC, BOLD computation for auditory simulations, and json output data files
1 parent f8bbe5a commit 1028ee4

File tree

419 files changed

+50748
-86
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

419 files changed

+50748
-86
lines changed
Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
# ============================================================================
2+
#
3+
# PUBLIC DOMAIN NOTICE
4+
#
5+
# National Institute on Deafness and Other Communication Disorders
6+
#
7+
# This software/database is a "United States Government Work" under the
8+
# terms of the United States Copyright Act. It was written as part of
9+
# the author's official duties as a United States Government employee and
10+
# thus cannot be copyrighted. This software/database is freely available
11+
# to the public for use. The NIDCD and the U.S. Government have not placed
12+
# any restriction on its use or reproduction.
13+
#
14+
# Although all reasonable efforts have been taken to ensure the accuracy
15+
# and reliability of the software and data, the NIDCD and the U.S. Government
16+
# do not and cannot warrant the performance or results that may be obtained
17+
# by using this software or data. The NIDCD and the U.S. Government disclaim
18+
# all warranties, express or implied, including warranties of performance,
19+
# merchantability or fitness for any particular purpose.
20+
#
21+
# Please cite the author in any work or product based on this material.
22+
#
23+
# ==========================================================================
24+
25+
26+
27+
# ***************************************************************************
28+
#
29+
# Large-Scale Neural Modeling software (LSNM)
30+
#
31+
# Section on Brain Imaging and Modeling
32+
# Voice, Speech and Language Branch
33+
# National Institute on Deafness and Other Communication Disorders
34+
# National Institutes of Health
35+
#
36+
# This file (compute_BOLD_balloon_model_auditory.py) was created on April 1, 2016.
37+
#
38+
#
39+
# Author: Antonio Ulloa
40+
#
41+
# Last updated by Antonio Ulloa on April 1 2016
42+
#
43+
# **************************************************************************/
44+
45+
# compute_BOLD_balloon_model_auditory.py
46+
#
47+
# Calculate and plot fMRI BOLD signal, using the
48+
# Balloon model, as described by Stephan et al (2007)
49+
# and Friston et al (2000), and
50+
# the BOLD signal model, as described by Stephan et al (2007) and
51+
# Friston et al (2000).
52+
# Parameters for both were taken from Friston et al (2000) and they were
53+
# estimated using a 2T scanner, with a TR of 2 seconds,
54+
#
55+
# ... using data from auditory delay-match-to-sample simulation stored in 4
56+
# different synaptic activity files
57+
# It also saves the BOLD timeseries for each and all modules in a python data file
58+
# (*.npy)
59+
#
60+
# The input data (synaptic activities) and the output (BOLD time-series) are numpy arrays
61+
# with columns in the following order:
62+
#
63+
# A1 ROI (right hemisphere, includes LSNM units and TVB nodes)
64+
# A2 ROI (right hemisphere, includes LSNM units and TVB nodes)
65+
# ST ROI (right hemisphere, includes LSNM units and TVB nodes)
66+
# PF ROI (right hemisphere, includes LSNM units and TVB nodes)
67+
#
68+
# Note: only the BOLD activity of one of the synaptic activity files is computed and stored.
69+
70+
import numpy as np
71+
72+
import matplotlib.pyplot as plt
73+
74+
from scipy.integrate import odeint
75+
76+
# define the name of the input files where the synaptic activities are stored
77+
# we have four files: TC-PSL, Tones-PSL, TC-DMS, Tones-DMS
78+
SYN_file_2 = 'output.TC_PSL/synaptic_in_ROI.npy'
79+
SYN_file_3 = 'output.Tones_PSL/synaptic_in_ROI.npy'
80+
SYN_file_4 = 'output.TC_DMS/synaptic_in_ROI.npy'
81+
SYN_file_1 = 'output.Tones_DMS/synaptic_in_ROI.npy'
82+
83+
# define the name of the output file where the BOLD timeseries will be stored
84+
BOLD_file = 'output.Tones_DMS/lsnm_bold_balloon.npy'
85+
86+
# define balloon model parameters...
87+
tau_s = 1.5 # rate constant of vasodilatory signal decay in seconds
88+
# from Friston et al, 2000
89+
90+
tau_f = 4.5 # Time of flow-dependent elimination or feedback regulation
91+
# in seconds, from Friston et al, 2000
92+
93+
alpha = 0.2 # Grubb's vessel stiffness exponent, from Friston et al, 2000
94+
95+
tau_0 = 1.0 # Hemodynamic transit time in seconds
96+
# from Friston et al, 2000
97+
98+
epsilon = 0.1 # efficacy of synaptic activity to induce the signal,
99+
# from Friston et al, 2000
100+
101+
# define BOLD model parameters...
102+
r_0 = 25.0 # Slope of intravascular relaxation rate (Hz)
103+
# (Obata et al, 2004)
104+
105+
nu_0 = 40.3 # Frequency offset at the outer surface of magnetized
106+
# vessels (Hz) (Obata et al, 2004)
107+
108+
e = 1.43 # Ratio of intra- and extravascular BOLD signal at rest
109+
# (Obata et al, 2004)
110+
111+
V_0 = 0.02 # Resting blood volume fraction, from Friston et al, 2000
112+
113+
E_0 = 0.8 # Resting oxygen extraction fraction (Friston et al, 2000)
114+
115+
TE = 0.040 # Echo time for a 1.5T scanner (Friston et al, 2000)
116+
117+
# calculate BOLD model coefficients, from Friston et al (2000)
118+
k1 = 4.3 * nu_0 * E_0 * TE
119+
k2 = e * r_0 * E_0 * TE
120+
k3 = 1.0 - epsilon
121+
122+
def balloon_function(y, t, syn):
123+
'''
124+
Balloon model of hemodynamic change
125+
126+
'''
127+
128+
# unpack initial values
129+
s = y[0]
130+
f = y[1]
131+
v = y[2]
132+
q = y[3]
133+
134+
x = syn[np.floor(t * synaptic_timesteps / T)]
135+
136+
# the balloon model equations
137+
ds = epsilon * x - (1. / tau_s) * s - (1. / tau_f) * (f - 1)
138+
df = s
139+
dv = (1. / tau_0) * (f - v ** (1. / alpha))
140+
dq = (1. / tau_0) * ((f * (1. - (1. - E_0) ** (1. / f)) / E_0) -
141+
(v ** (1. / alpha)) * (q / v))
142+
143+
return [ds, df, dv, dq]
144+
145+
# define neural synaptic time interval in seconds. The simulation data is collected
146+
# one data point at synaptic intervals (10 simulation timesteps). Every simulation
147+
# timestep is equivalent to 3.5 ms.
148+
Ti = 0.0035 * 10
149+
150+
# Total time of scanning experiment in seconds (timesteps X 5)
151+
T = 34.3
152+
153+
# Time for one complete trial in milliseconds
154+
Ttrial = 2.8
155+
156+
# the scanning happened every Tr interval below (in milliseconds). This
157+
# is the time needed to sample hemodynamic activity to produce
158+
# each fMRI image.
159+
Tr = 2
160+
161+
# how many scans do you want to remove from beginning of BOLD timeseries?
162+
scans_to_remove = 0
163+
164+
# read the input file that contains the synaptic activities of all ROIs
165+
syn1 = np.load(SYN_file_1)
166+
syn2 = np.load(SYN_file_2)
167+
syn3 = np.load(SYN_file_3)
168+
syn4 = np.load(SYN_file_4)
169+
170+
print 'LENGTH OF SYNAPTIC TIME-SERIES: ', syn1[0].size
171+
172+
# Throw away first value of each synaptic array (it is always zero)
173+
a1_syn1 = np.delete(syn1[0], 0)
174+
a2_syn1 = np.delete(syn1[1], 0)
175+
st_syn1 = np.delete(syn1[2], 0)
176+
pf_syn1 = np.delete(syn1[3], 0)
177+
a1_syn2 = np.delete(syn2[0], 0)
178+
a2_syn2 = np.delete(syn2[1], 0)
179+
st_syn2 = np.delete(syn2[2], 0)
180+
pf_syn2 = np.delete(syn2[3], 0)
181+
a1_syn3 = np.delete(syn3[0], 0)
182+
a2_syn3 = np.delete(syn3[1], 0)
183+
st_syn3 = np.delete(syn3[2], 0)
184+
pf_syn3 = np.delete(syn3[3], 0)
185+
a1_syn4 = np.delete(syn4[0], 0)
186+
a2_syn4 = np.delete(syn4[1], 0)
187+
st_syn4 = np.delete(syn4[2], 0)
188+
pf_syn4 = np.delete(syn4[3], 0)
189+
190+
# put together all the synaptic activity array that form part of a study, only
191+
# for normalization purposes
192+
# put together synaptic arrays that correspond to the same brain region
193+
a1 = np.append(a1_syn1, [a1_syn2, a1_syn3, a1_syn4])
194+
a2 = np.append(a2_syn1, [a2_syn2, a2_syn3, a2_syn4])
195+
st = np.append(st_syn1, [st_syn2, st_syn3, st_syn4])
196+
pf = np.append(pf_syn1, [pf_syn2, pf_syn3, pf_syn4])
197+
198+
# extract the synaptic activities corresponding to each ROI, and normalize to (0,1):
199+
a1_syn = (a1_syn1-a1.min()) / (a1.max() - a1.min())
200+
a2_syn = (a2_syn1-a2.min()) / (a2.max() - a2.min())
201+
st_syn = (st_syn1-st.min()) / (st.max() - st.min())
202+
pf_syn = (pf_syn1-pf.min()) / (pf.max() - pf.min())
203+
204+
# Extract number of timesteps from one of the synaptic activity arrays
205+
synaptic_timesteps = a1_syn.size
206+
print 'Size of synaptic arrays: ', synaptic_timesteps
207+
208+
# Given neural synaptic time interval and total time of scanning experiment,
209+
# construct a numpy array of time points (data points provided in data files)
210+
time_in_seconds = np.arange(0, T, Ti)
211+
212+
# Hard coded initial conditions
213+
s = 0 # s, blood flow
214+
f = 1. # f, blood inflow
215+
v = 1. # v, venous blood volume
216+
q = 1. # q, deoxyhemoglobin content
217+
218+
# initial conditions vectors
219+
y_0_a1 = [s, f, v, q]
220+
y_0_a2 = [s, f, v, q]
221+
y_0_st = [s, f, v, q]
222+
y_0_pf = [s, f, v, q]
223+
224+
# generate synaptic time array
225+
t_syn = np.arange(0, synaptic_timesteps)
226+
227+
# generate time array for solution
228+
t = time_in_seconds
229+
230+
# Use the following lines to test the balloon BOLD model
231+
#v1_syn[0:300] = .01 # 15 seconds do nothing
232+
#v1_syn[300:320] = .1 # One-second stimulus
233+
#v1_syn[320:920] = .01 # 30-second do nothing
234+
#v1_syn[920:940] = .1 # two-second stimulus
235+
#v1_syn[940:1540] = .01 # 30-second do nothing
236+
#v1_syn[1540:1560]= .1 # three-second stimulus
237+
#v1_syn[1560:2160]= .01 # 30-second do nothing
238+
#v1_syn[2160:2180]= .1 # four-second stimulus
239+
#v1_syn[2180:2780]= .01 # 30-second do nothing
240+
#v1_syn[2780:2800]= .1 # five-second stimulus
241+
#v1_syn[2800:3400]= .01 # 30-second do nothing
242+
#v1_syn[3400:3420]= .1 # one-second stimulus
243+
#v1_syn[3420:3959]= .01 # 30-second do nothing
244+
245+
# solve the ODEs for given initial conditions, parameters, and timesteps
246+
state_a1 = odeint(balloon_function, y_0_a1, t, args=(a1_syn,) )
247+
state_a2 = odeint(balloon_function, y_0_a2, t, args=(a2_syn,) )
248+
state_st = odeint(balloon_function, y_0_st, t, args=(st_syn,) )
249+
state_pf = odeint(balloon_function, y_0_pf, t, args=(pf_syn,) )
250+
251+
# Unpack the state variables used in the BOLD model
252+
s_a1 = state_a1[:, 0]
253+
f_a1 = state_a1[:, 1]
254+
v_a1 = state_a1[:, 2]
255+
q_a1 = state_a1[:, 3]
256+
257+
s_a2 = state_a2[:, 0]
258+
f_a2 = state_a2[:, 1]
259+
v_a2 = state_a2[:, 2]
260+
q_a2 = state_a2[:, 3]
261+
262+
s_st = state_st[:, 0]
263+
f_st = state_st[:, 1]
264+
v_st = state_st[:, 2]
265+
q_st = state_st[:, 3]
266+
267+
s_pf = state_pf[:, 0]
268+
f_pf = state_pf[:, 1]
269+
v_pf = state_pf[:, 2]
270+
q_pf = state_pf[:, 3]
271+
272+
# now, we need to calculate BOLD signal at each timestep, based on v and q obtained from solving
273+
# balloon model ODE above.
274+
a1_BOLD = np.array(V_0 * (k1 * (1. - q_a1) + k2 * (1. - q_a1 / v_a1) + k3 * (1. - v_a1)) )
275+
a2_BOLD = np.array(V_0 * (k1 * (1. - q_a2) + k2 * (1. - q_a2 / v_a2) + k3 * (1. - v_a2)) )
276+
st_BOLD = np.array(V_0 * (k1 * (1. - q_st) + k2 * (1. - q_st / v_st) + k3 * (1. - v_st)) )
277+
pf_BOLD = np.array(V_0 * (k1 * (1. - q_pf) + k2 * (1. - q_pf / v_pf) + k3 * (1. - v_pf)) )
278+
279+
# The following is for display purposes only:
280+
# Construct a numpy array of timesteps (data points provided in data file)
281+
# to convert from timesteps to time in seconds we do the following:
282+
# Each simulation time-step equals 5 milliseconds
283+
# However, we are recording only once every 10 time-steps
284+
# Therefore, each data point in the output files represents 50 milliseconds.
285+
# Thus, we need to multiply the datapoint times 50 ms...
286+
# ... and divide by 1000 to convert to seconds
287+
#t = np.linspace(0, 659*50./1000., num=660)
288+
t = np.linspace(0, synaptic_timesteps * 35.0 / 1000., num=synaptic_timesteps)
289+
290+
# downsample the BOLD signal arrays to produce scan rate of 2 per second
291+
scanning_timescale = np.arange(0, synaptic_timesteps, synaptic_timesteps / (T/Tr))
292+
scanning_timescale = scanning_timescale.astype(int) # don't forget to convert indices to integer
293+
mr_time = t[scanning_timescale]
294+
a1_BOLD = a1_BOLD[scanning_timescale]
295+
a2_BOLD = a2_BOLD[scanning_timescale]
296+
st_BOLD = st_BOLD[scanning_timescale]
297+
pf_BOLD = pf_BOLD[scanning_timescale]
298+
299+
print 'Size of BOLD arrays: ', a1_BOLD.size
300+
301+
# round of mr time for display purposes
302+
mr_time = np.round(mr_time, decimals=0)
303+
304+
# create a numpy array of timeseries
305+
lsnm_BOLD = np.array([a1_BOLD, a2_BOLD, st_BOLD, pf_BOLD])
306+
307+
# now, save all BOLD timeseries to a single file
308+
np.save(BOLD_file, lsnm_BOLD)
309+
310+
# increase font size for display purposes
311+
#plt.rcParams.update({'font.size': 30})
312+
313+
# Set up figure to plot synaptic activity
314+
plt.figure()
315+
316+
plt.suptitle('SIMULATED SYNAPTIC ACTIVITY')
317+
318+
# Plot synaptic activities
319+
plt.plot(t, a1_syn, label='A1')
320+
plt.plot(t, a2_syn, label='A2')
321+
plt.plot(t, st_syn, label='ST')
322+
plt.plot(t, pf_syn, label='PFC')
323+
324+
plt.legend()
325+
326+
# Set up separate figures to plot fMRI BOLD signal
327+
plt.figure()
328+
329+
plt.suptitle('SIMULATED fMRI BOLD SIGNAL')
330+
331+
plt.plot(mr_time, a1_BOLD, label='A1')
332+
333+
plt.plot(mr_time, a2_BOLD, label='A2')
334+
335+
plt.plot(mr_time, st_BOLD, label='ST')
336+
337+
plt.plot(mr_time, pf_BOLD, label='PFC')
338+
339+
plt.legend()
340+
341+
# Show the plots on the screen
342+
plt.show()

0 commit comments

Comments
 (0)