00001 #ifndef INDII_FMRI_HEMODYNAMIC_FLOWBALLOONMODEL_HPP 00002 #define INDII_FMRI_HEMODYNAMIC_FLOWBALLOONMODEL_HPP 00003 00004 #include "BalloonModel.hpp" 00005 00006 #include "indii/ml/aux/vector.hpp" 00007 00008 namespace indii { 00009 namespace fmri { 00010 namespace hemodynamic { 00011 00012 /** 00013 * Balloon %model driven by blood flow. 00014 * 00015 * @author Lawrence Murray <lawrence@indii.org> 00016 * @version $Rev: 285 $ 00017 * @date $Date: 2007-07-20 17:25:40 +0100 (Fri, 20 Jul 2007) $ 00018 * 00019 * This class implements the Balloon Model described by @ref 00020 * Buxton1998 "Buxton et al. (1998)". This system models a venous 00021 * compartment as a balloon, described by a volume and deoxyhemoglobin 00022 * (dHb) content. These combine to produce the Blood Oxygenation Level 00023 * Dependent (BOLD) signal. 00024 * 00025 * The %model is driven by blood flow into the venous 00026 * compartment. This causes the compartment to expand like a balloon, 00027 * increasing the pressure exerted by it and consequently the blood 00028 * flow out of the compartment. Concurrently, oxygen extraction, and 00029 * therefore the rate of dHb production, is more efficient at slower 00030 * flow rates. These simple interactions simulate a biologically 00031 * plausible BOLD signal. 00032 * 00033 * @section FlowBalloonModel_details Details 00034 * 00035 * The state variables \f$q\f$, representing normalised dHb content, 00036 * and \f$v\f$, representing normalised venous volume, are updated 00037 * according to the system of differential equations given by @ref 00038 * Buxton1998 "Buxton et al. (1998)": 00039 * 00040 * @anchor diffsystem 00041 * \f{eqnarray*} 00042 * \frac{dq}{dt} &=& \frac{1}{\tau_0}\left[ 00043 * f_{in}(t)\frac{E(t)}{E_0} - 00044 * f_{out}(v)\frac{q}{v} 00045 * \right] \\ 00046 * \frac{dv}{dt} &=& \frac{1}{\tau_0}\left[ 00047 * f_{in}(t) - f_{out}(v) 00048 * \right] 00049 * \f} 00050 * 00051 * Other symbols represent biophysical parameters and functions of the 00052 * system, handled using indii::ml::ode::ParameterCollection and 00053 * indii::ml::ode::FunctionCollection, with default values given in 00054 * FlowBalloonModelDefaults. 00055 * 00056 * Singularities are handled using limits. See 00057 * FlowBalloonModelDefaults::DQDT. 00058 * 00059 * @section FlowBalloonModel_usage Usage 00060 * 00061 * The basic usage idiom is as follows. Firstly create an instance of 00062 * FlowBalloonModel and set up the initial state: 00063 * 00064 * @code 00065 * FlowBalloonModel bm; 00066 * indii::ml::aux::vector y(bm.suggestInitialState()); 00067 * @endcode 00068 * 00069 * The %model may then be simulated by solving the differential system 00070 * using indii::ml::ode::AdaptiveRungeKutta: 00071 * 00072 * @code 00073 * indii::ml::ode::AdaptiveRungeKutta solver(&bm, y); 00074 * double end = 60.0; 00075 * double t = 0.0; 00076 * 00077 * while (t < end) { 00078 * t = solver.step(end); 00079 * } 00080 * @endcode 00081 * 00082 * In order for the %model to do something interesting, however, you 00083 * will want to at least override the default FlowBalloonModel::F_IN 00084 * function with your own custom function that controls flow. The 00085 * following function, for example, generates a flow of 2.0 for 1 s, 00086 * followed by a constant flow of 1.0: 00087 * 00088 * @code 00089 * double F_IN(double t, const double y[], void* o) { 00090 * if (t < 1.0) { 00091 * return 2.0; 00092 * } else { 00093 * return 1.0; 00094 * } 00095 * } 00096 * @endcode 00097 * 00098 * Note the signature of this function, described by 00099 * indii::ml::ode::f_t. The %model can be made to use this function by 00100 * calling setFunction() before the first call to step(): 00101 * 00102 * @code 00103 * bm.setFunction(FlowBalloonModel::F_IN, F_IN); 00104 * @endcode 00105 * 00106 * Other biophysical parameters and functions may be customised using 00107 * the setParameter() and setFunction() methods inherited from 00108 * indii::ml::ode::ParameterCollection and 00109 * indii::ml::ode::FunctionCollection. 00110 * 00111 * Finally, you will want to actually retrieve the state of the %model 00112 * after each call to step() using getVariable() or getState(). For 00113 * example, modifying the loop above: 00114 * 00115 * @code 00116 * while (t < end) { 00117 * t = solver.step(end); 00118 * 00119 * std::cout << t << ','; 00120 * std::cout << solver.getVariable(FlowBalloonModel::Q) << ','; 00121 * std::cout << solver.getVariable(FlowBalloonModel::V) << std::endl; 00122 * } 00123 * @endcode 00124 * 00125 * or: 00126 * 00127 * @code 00128 * while (t < end) { 00129 * t = solver.step(end); 00130 * y = solver.getState(); 00131 * 00132 * std::cout << t << ','; 00133 * std::cout << y(FlowBalloonModel::Q) << ','; 00134 * std::cout << y(FlowBalloonModel::V) << std::endl; 00135 * } 00136 * @endcode 00137 * 00138 * The values of biophysical functions, which are time dependent, may 00139 * be retrieved using getFunction() if they are of interest also. 00140 */ 00141 class FlowBalloonModel : public BalloonModel { 00142 public: 00143 /** 00144 * State variable indices. 00145 */ 00146 enum StateVariable { 00147 /** 00148 * \f$q = \frac{Q(t)}{Q_0}\f$; normalised dHb content of venous 00149 * compartment at the current time. 00150 */ 00151 Q, 00152 00153 /** 00154 * \f$v = \frac{V(t)}{V_0}\f$; normalised volume of the venous 00155 * compartment at the current time. 00156 */ 00157 V 00158 }; 00159 00160 /** 00161 * Parameter indices. 00162 */ 00163 enum BiophysicalParameter { 00164 /** 00165 * \f$V_0\f$; volume of the venous compartment at rest. 00166 */ 00167 V_0, 00168 00169 /** 00170 * \f$E_0\f$; oxygen extraction rate of the venous compartment at 00171 * rest. 00172 */ 00173 E_0, 00174 00175 /** 00176 * \f$\tau_0 = \frac{V_0}{F_0}\f$; mean transit time through the 00177 * venous compartment at rest. 00178 */ 00179 TAU_0, 00180 00181 /** 00182 * \f$\alpha\f$; Grubb's exponent. 00183 */ 00184 ALPHA 00185 }; 00186 00187 /** 00188 * Function indices. 00189 */ 00190 enum BiophysicalFunction { 00191 /** 00192 * \f$f_{in}(t) = \frac{F_{in}(t)}{F_0}\f$; normalised flow into 00193 * the venous compartment. 00194 */ 00195 F_IN, 00196 00197 /** 00198 * \f$f_{out}(t) = \frac{F_{out}(t)}{F_0}\f$; normalised flow out 00199 * of the venous compartment. 00200 */ 00201 F_OUT, 00202 00203 /** 00204 * \f$E(t)\f$; oxygen extraction rate of the venous compartment. 00205 */ 00206 E 00207 }; 00208 00209 /** 00210 * Create new %model with the default biophysical parameters and 00211 * functions defined in FlowBalloonModelDefaults. 00212 */ 00213 FlowBalloonModel(); 00214 00215 /** 00216 * Destructor. 00217 */ 00218 virtual ~FlowBalloonModel(); 00219 00220 virtual indii::ml::aux::vector suggestInitialState(); 00221 00222 /** 00223 * @see indii::ml::ode::DifferentialModel 00224 */ 00225 virtual void calculateDerivatives(double t, const double y[], double dydt[]); 00226 00227 private: 00228 /** 00229 * Number of state variables. 00230 */ 00231 static const unsigned int DIMENSIONS = 2; 00232 00233 /** 00234 * Number of parameters. 00235 */ 00236 static const unsigned int NUM_PARAMETERS = 4; 00237 00238 /** 00239 * Number of functions. 00240 */ 00241 static const unsigned int NUM_FUNCTIONS = 3; 00242 00243 }; 00244 00245 } 00246 } 00247 } 00248 00249 #endif
1.5.2