Created
June 14, 2012 18:54
-
-
Save arokem/2932187 to your computer and use it in GitHub Desktop.
Simulation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import tensor as ozt | |
# Global constants for this module: | |
AD = 1.5 | |
RD = 0.5 | |
# This converts b values from the data, so that it matches the units of ADC we | |
# use in the Stejskal/Tanner equation: | |
SCALE_FACTOR = 1000 | |
class ODF(object): | |
""" | |
This class represents a distribution of fiber orientations within a voxel | |
""" | |
def __init__(self, | |
bvecs, | |
weights): | |
self.bvecs = bvecs | |
# Enforce that the weights are a pdf: | |
if np.sum(weights)!=1: | |
e_s = "The ODF is a distribution function, so" | |
e_s += "the weights must sum to 1" | |
raise ValueError(e_s) | |
self.weights = weights | |
class Voxel(object): | |
""" | |
The representation of the measurement in a single voxel with some | |
configuration of fibers crossing through it, represented by an ODF | |
""" | |
def __init__(self, | |
bvecs, | |
bvals, | |
odf, | |
scaling_factor=SCALE_FACTOR, | |
axial_diffusivity=AD, | |
radial_diffusivity=RD): | |
""" | |
The signal in a single voxel is computed from the convolution of a | |
response function with the ODF | |
Parameters | |
---------- | |
bvecs: 3 by n array | |
unit vectors on the sphere. | |
bvals: 1 by n array | |
The measurement parameter defining where on the curve we measure | |
the exponential decay of the signal | |
odf: an ODF class instance | |
The representation of the orientation distribution function. Note | |
that this class also has bvecs, but these bvecs don't have to be | |
the same bvecs as the ones of this class. bvecs In this class refer | |
to measurement directions, while the bvecs in the ODF class refer | |
to directions of fibers within the voxel (not necessarily the | |
same...) | |
S0: float (optional) | |
The signal measured in the non diffusion-weighted scans. Default: 1 | |
scaling_factor: float (optional) | |
To get the right units on the ADC, sometimes the b value needs to | |
be scaled. Typically, divided by 1000 (default). | |
axial_diffusivity, radial_diffusivity: float | |
These parameters | |
""" | |
self.bvecs = bvecs | |
self.bvals = bvals/scaling_factor | |
self.odf = odf | |
# We assume that the response function is a cigar shaped tensor: | |
self.Q = np.array([[axial_diffusivity, 0, 0], | |
[0, radial_diffusivity, 0], | |
[0, 0, radial_diffusivity]]) | |
self.response_function = ozt.Tensor(self.Q, self.bvecs, self.bvals) | |
def signal(self,S0=1): | |
""" | |
The signal generated by the ODF in each bvec direction | |
""" | |
# Initialize to zero: | |
signal = np.zeros(self.bvecs.shape[-1]) | |
# Decompose the response function to its eigen-decomposition: | |
evals, evecs = self.response_function.decompose | |
# We generate the signal for each one of the fibers in the ODF: | |
for odf_idx, odf_vec in enumerate(self.odf.bvecs): | |
this_response = ozt.rotate_to_vector(odf_vec, | |
evals, | |
evecs, | |
self.bvecs, | |
self.bvals) | |
signal += (self.odf.weights[odf_idx] * | |
this_response.predicted_signal(S0)) | |
return signal |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment