Chaste Release::3.1
PropagationPropertiesCalculator.cpp
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 }