Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00036 #include "UblasIncludes.hpp" 00037 #include "PropagationPropertiesCalculator.hpp" 00038 #include "CellProperties.hpp" 00039 #include "Exception.hpp" 00040 #include <sstream> 00041 #include "HeartEventHandler.hpp" 00042 00043 PropagationPropertiesCalculator::PropagationPropertiesCalculator(Hdf5DataReader* pDataReader, 00044 const std::string voltageName) 00045 : mpDataReader(pDataReader), 00046 mVoltageName(voltageName), 00047 mTimes(mpDataReader->GetUnlimitedDimensionValues()), 00048 mCachedNodeGlobalIndex(UNSIGNED_UNSET) 00049 {} 00050 00051 PropagationPropertiesCalculator::~PropagationPropertiesCalculator() 00052 { 00053 // We don't own the data reader, so we don't destroy it. 00054 } 00055 00056 double PropagationPropertiesCalculator::CalculateMaximumUpstrokeVelocity(unsigned globalNodeIndex) 00057 { 00058 std::vector<double>& r_voltages = rGetCachedVoltages(globalNodeIndex); 00059 CellProperties cell_props(r_voltages, mTimes); 00060 return cell_props.GetLastMaxUpstrokeVelocity(); 00061 } 00062 00063 std::vector<double> PropagationPropertiesCalculator::CalculateAllMaximumUpstrokeVelocities(unsigned globalNodeIndex, double threshold) 00064 { 00065 std::vector<double>& r_voltages = rGetCachedVoltages(globalNodeIndex); 00066 CellProperties cell_props(r_voltages, mTimes, threshold); 00067 return cell_props.GetMaxUpstrokeVelocities(); 00068 } 00069 00070 std::vector<double> PropagationPropertiesCalculator::CalculateUpstrokeTimes(unsigned globalNodeIndex, double threshold) 00071 { 00072 std::vector<double>& r_voltages = rGetCachedVoltages(globalNodeIndex); 00073 CellProperties cell_props(r_voltages, mTimes, threshold); 00074 return cell_props.GetTimesAtMaxUpstrokeVelocity(); 00075 } 00076 00077 double PropagationPropertiesCalculator::CalculateActionPotentialDuration(const double percentage, 00078 unsigned globalNodeIndex) 00079 { 00080 if (percentage < 1.0 || percentage >= 100.0) 00081 { 00082 EXCEPTION("First argument of CalculateActionPotentialDuration() is expected to be a percentage"); 00083 } 00084 std::vector<double>& r_voltages = rGetCachedVoltages(globalNodeIndex); 00085 CellProperties cell_props(r_voltages, mTimes); 00086 return cell_props.GetLastActionPotentialDuration(percentage); 00087 } 00088 00089 std::vector<double> PropagationPropertiesCalculator::CalculateAllActionPotentialDurations(const double percentage, 00090 unsigned globalNodeIndex, 00091 double threshold) 00092 { 00093 std::vector<double>& r_voltages = rGetCachedVoltages(globalNodeIndex); 00094 CellProperties cell_props(r_voltages, mTimes, threshold); 00095 return cell_props.GetAllActionPotentialDurations(percentage); 00096 } 00097 00098 std::vector<std::vector<double> > PropagationPropertiesCalculator::CalculateAllActionPotentialDurationsForNodeRange( 00099 const double percentage, 00100 unsigned lowerNodeIndex, 00101 unsigned upperNodeIndex, 00102 double threshold) 00103 { 00104 std::vector<std::vector<double> > output_data; 00105 output_data.reserve(upperNodeIndex-lowerNodeIndex+1); 00106 unsigned num_nodes_per_data_block = 100; // number of nodes 00107 unsigned num_complete_blocks = (upperNodeIndex-lowerNodeIndex) / num_nodes_per_data_block; 00108 unsigned size_last_block = (upperNodeIndex-lowerNodeIndex) % num_nodes_per_data_block; 00109 00110 for (unsigned block_num=0; 00111 block_num<num_complete_blocks+1; 00112 block_num++) 00113 { 00114 unsigned num_nodes_to_read; 00115 if (block_num != num_complete_blocks) 00116 { 00117 num_nodes_to_read = num_nodes_per_data_block; 00118 } 00119 else 00120 { 00121 num_nodes_to_read = size_last_block; 00122 } 00123 00124 if (num_nodes_to_read > 0) 00125 { 00126 // Read a big block of data 00127 unsigned low_node = lowerNodeIndex + block_num*num_nodes_per_data_block; 00128 unsigned high_node = low_node + num_nodes_to_read; 00129 std::vector<std::vector<double> > voltages = mpDataReader->GetVariableOverTimeOverMultipleNodes(mVoltageName, low_node, high_node); 00130 00131 for (unsigned node_within_block=0; 00132 node_within_block < num_nodes_to_read; 00133 node_within_block++) 00134 { 00135 std::vector<double>& r_voltages = voltages[node_within_block]; 00136 CellProperties cell_props(r_voltages, mTimes, threshold); 00137 std::vector<double> apds; 00138 try 00139 { 00140 apds = cell_props.GetAllActionPotentialDurations(percentage); 00141 assert(apds.size() != 0); 00142 } 00143 catch (Exception& e) 00144 { 00145 assert(e.GetShortMessage()=="No full action potential was recorded" || 00146 e.GetShortMessage()=="AP did not occur, never exceeded threshold voltage."); 00147 apds.push_back(0); 00148 assert(apds.size() == 1); 00149 } 00150 output_data.push_back(apds); 00151 } 00152 } 00153 } 00154 return output_data; 00155 } 00156 00157 double PropagationPropertiesCalculator::CalculatePeakMembranePotential(unsigned globalNodeIndex) 00158 { 00159 std::vector<double>& r_voltages = rGetCachedVoltages(globalNodeIndex); 00160 double max = -DBL_MAX; 00161 for (unsigned i=0; i<r_voltages.size(); i++) 00162 { 00163 if (r_voltages[i]>max) 00164 { 00165 max = r_voltages[i]; 00166 } 00167 } 00168 return max; 00169 } 00170 00171 double PropagationPropertiesCalculator::CalculateConductionVelocity(unsigned globalNearNodeIndex, 00172 unsigned globalFarNodeIndex, 00173 const double euclideanDistance) 00174 { 00175 double t_near = 0; 00176 double t_far = 0; 00177 std::vector<double>& r_near_voltages = rGetCachedVoltages(globalNearNodeIndex); 00178 std::vector<double> far_voltages = mpDataReader->GetVariableOverTime(mVoltageName, globalFarNodeIndex); 00179 00180 CellProperties near_cell_props(r_near_voltages, mTimes); 00181 CellProperties far_cell_props(far_voltages, mTimes); 00182 00183 //The size of each vector is the number of APs that reached that node 00184 unsigned aps_near_node = near_cell_props.GetMaxUpstrokeVelocities().size(); 00185 unsigned aps_far_node = far_cell_props.GetMaxUpstrokeVelocities().size(); 00186 00187 //These should never be empty. If so, an exception should have been thrown in the GetMaxUpstrokeVelocities() method. 00188 assert(aps_near_node > 0); 00189 assert(aps_far_node > 0); 00190 00191 //if the same number of APs reached both nodes, get the last one... 00192 if (aps_near_node == aps_far_node) 00193 { 00194 t_near = near_cell_props.GetTimeAtLastMaxUpstrokeVelocity(); 00195 t_far = far_cell_props.GetTimeAtLastMaxUpstrokeVelocity(); 00196 } 00197 //...otherwise get the one with the smallest value, which is the last AP to reach both nodes 00198 //This prevents possible calculation of negative conduction velocities 00199 //for repeated stimuli 00200 else if (aps_near_node > aps_far_node) 00201 { 00202 t_near = near_cell_props.GetTimesAtMaxUpstrokeVelocity()[aps_far_node-1]; 00203 t_far = far_cell_props.GetTimesAtMaxUpstrokeVelocity()[aps_far_node-1]; 00204 } 00205 else 00206 { 00207 t_near = near_cell_props.GetTimesAtMaxUpstrokeVelocity()[aps_near_node-1]; 00208 t_far = far_cell_props.GetTimesAtMaxUpstrokeVelocity()[aps_near_node-1]; 00209 } 00210 00212 if ((globalNearNodeIndex == globalFarNodeIndex) || ( fabs(t_far - t_near) < 1e-8)) 00213 { 00214 // globalNearNodeIndex and globalFarNodeIndex are the same node, preventing a 0/0 00215 // or 00216 // AP number i is happening at the same time at nodes globalNearNodeIndex and globalFarNodeIndex 00217 return 0.0; 00218 } 00219 else 00220 { 00221 return euclideanDistance / (t_far - t_near); 00222 } 00223 00224 00225 } 00226 00227 std::vector<double> PropagationPropertiesCalculator::CalculateAllConductionVelocities(unsigned globalNearNodeIndex, 00228 unsigned globalFarNodeIndex, 00229 const double euclideanDistance) 00230 { 00231 std::vector<double> conduction_velocities; 00232 00233 std::vector<double> t_near; 00234 std::vector<double> t_far; 00235 unsigned number_of_aps = 0; 00236 00237 std::vector<double>& r_near_voltages = rGetCachedVoltages(globalNearNodeIndex); 00238 std::vector<double> far_voltages = mpDataReader->GetVariableOverTime(mVoltageName, globalFarNodeIndex); 00239 00240 CellProperties near_cell_props(r_near_voltages, mTimes); 00241 CellProperties far_cell_props(far_voltages, mTimes); 00242 00243 t_near = near_cell_props.GetTimesAtMaxUpstrokeVelocity(); 00244 t_far = far_cell_props.GetTimesAtMaxUpstrokeVelocity(); 00245 00246 //exception should have been thrown within the GetTimesAtMaxUpstrokeVelocity method if the threshold is never reached 00247 //and these vectors are empty 00248 assert(t_near.size() !=0); 00249 assert(t_far.size() !=0); 00250 00251 //Check the node where the least number of aps is reached. 00252 //We will calculate only where AP reached both nodes 00253 if (t_near.size() > t_far.size()) 00254 { 00255 number_of_aps = t_far.size(); 00256 } 00257 else 00258 { 00259 number_of_aps = t_near.size(); 00260 } 00261 //now fill the vector 00262 00263 if (globalNearNodeIndex == globalFarNodeIndex) 00264 { 00265 // globalNearNodeIndex and globalFarNodeIndex are the same node, preventing a 0/0 00266 for (unsigned i = 0 ; i < number_of_aps;i++) 00267 { 00268 conduction_velocities.push_back(0.0); 00269 } 00270 } 00271 else 00272 { 00273 for (unsigned i = 0 ; i < number_of_aps;i++) 00274 { 00276 if ( fabs(t_far[i] - t_near[i]) < 1e-8) 00277 { 00278 // AP number i is happening at the same time at nodes globalNearNodeIndex and globalFarNodeIndex 00279 conduction_velocities.push_back(0.0); 00280 } 00281 else 00282 { 00283 conduction_velocities.push_back(euclideanDistance / (t_far[i] - t_near[i])); 00284 } 00285 } 00286 } 00287 00288 return conduction_velocities; 00289 } 00290 00291 00292 std::vector<unsigned> PropagationPropertiesCalculator::CalculateAllAboveThresholdDepolarisations(unsigned globalNodeIndex, double threshold) 00293 { 00294 std::vector<double>& r_voltages = rGetCachedVoltages(globalNodeIndex); 00295 CellProperties cell_props(r_voltages, mTimes, threshold); 00296 return cell_props.GetNumberOfAboveThresholdDepolarisationsForAllAps(); 00297 } 00298 00299 00300 unsigned PropagationPropertiesCalculator::CalculateAboveThresholdDepolarisationsForLastAp(unsigned globalNodeIndex, double threshold) 00301 { 00302 std::vector<double>& r_voltages = rGetCachedVoltages(globalNodeIndex); 00303 CellProperties cell_props(r_voltages, mTimes, threshold); 00304 return cell_props.GetNumberOfAboveThresholdDepolarisationsForLastAp(); 00305 } 00306 00307 00308 std::vector<double>& PropagationPropertiesCalculator::rGetCachedVoltages(unsigned globalNodeIndex) 00309 { 00310 if (globalNodeIndex != mCachedNodeGlobalIndex) 00311 { 00312 mCachedVoltages = mpDataReader->GetVariableOverTime(mVoltageName, globalNodeIndex); 00313 mCachedNodeGlobalIndex = globalNodeIndex; 00314 } 00315 return mCachedVoltages; 00316 }