PropagationPropertiesCalculator.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #include "UblasIncludes.hpp"
00030 #include "PropagationPropertiesCalculator.hpp"
00031 #include "CellProperties.hpp"
00032 #include "Exception.hpp"
00033 #include <sstream>
00034 #include "HeartEventHandler.hpp"
00035 
00036 PropagationPropertiesCalculator::PropagationPropertiesCalculator(Hdf5DataReader* pDataReader,
00037                                                                  const std::string voltageName)
00038     : mpDataReader(pDataReader),
00039       mVoltageName(voltageName),
00040       mTimes(mpDataReader->GetUnlimitedDimensionValues()),
00041       mCachedNodeGlobalIndex(UNSIGNED_UNSET)
00042 {}
00043 
00044 PropagationPropertiesCalculator::~PropagationPropertiesCalculator()
00045 {
00046     // We don't own the data reader, so we don't destroy it.
00047 }
00048 
00049 double PropagationPropertiesCalculator::CalculateMaximumUpstrokeVelocity(unsigned globalNodeIndex)
00050 {
00051     std::vector<double>& r_voltages = rCacheVoltages(globalNodeIndex);
00052     CellProperties cell_props(r_voltages, mTimes);
00053     return cell_props.GetLastMaxUpstrokeVelocity();
00054 }
00055 
00056 std::vector<double> PropagationPropertiesCalculator::CalculateAllMaximumUpstrokeVelocities(unsigned globalNodeIndex, double threshold)
00057 {
00058     std::vector<double>& r_voltages = rCacheVoltages(globalNodeIndex);
00059     CellProperties cell_props(r_voltages, mTimes, threshold);
00060     return cell_props.GetMaxUpstrokeVelocities();
00061 }
00062 
00063 std::vector<double> PropagationPropertiesCalculator::CalculateUpstrokeTimes(unsigned globalNodeIndex, double threshold)
00064 {
00065     std::vector<double>& r_voltages = rCacheVoltages(globalNodeIndex);
00066     CellProperties cell_props(r_voltages, mTimes, threshold);
00067     return cell_props.GetTimesAtMaxUpstrokeVelocity();
00068 }
00069 
00070 double PropagationPropertiesCalculator::CalculateActionPotentialDuration(const double percentage,
00071                                                                          unsigned globalNodeIndex)
00072 {
00073     if (percentage < 1.0 || percentage >= 100.0)
00074     {
00075         EXCEPTION("First argument of CalculateActionPotentialDuration() is expected to be a percentage");
00076     }
00077     std::vector<double>& r_voltages = rCacheVoltages(globalNodeIndex);
00078     CellProperties cell_props(r_voltages, mTimes);
00079     return cell_props.GetLastActionPotentialDuration(percentage);
00080 }
00081 
00082 std::vector<double> PropagationPropertiesCalculator::CalculateAllActionPotentialDurations(const double percentage,
00083                                                                                           unsigned globalNodeIndex,
00084                                                                                           double threshold)
00085 {
00086     std::vector<double>& r_voltages = rCacheVoltages(globalNodeIndex);
00087     CellProperties cell_props(r_voltages, mTimes, threshold);
00088     return cell_props.GetAllActionPotentialDurations(percentage);
00089 }
00090 
00091 std::vector<std::vector<double> > PropagationPropertiesCalculator::CalculateAllActionPotentialDurationsForNodeRange(
00092         const double percentage,
00093         unsigned lowerNodeIndex,
00094         unsigned upperNodeIndex,
00095         double threshold)
00096 {
00097     std::vector<std::vector<double> > output_data;
00098     output_data.reserve(upperNodeIndex-lowerNodeIndex+1);
00099     unsigned num_nodes_per_data_block = 100; // number of nodes
00100     unsigned num_complete_blocks = (upperNodeIndex-lowerNodeIndex) / num_nodes_per_data_block;
00101     unsigned size_last_block = (upperNodeIndex-lowerNodeIndex) % num_nodes_per_data_block;
00102 
00103     for (unsigned block_num=0;
00104          block_num<num_complete_blocks+1;
00105          block_num++)
00106     {
00107         unsigned num_nodes_to_read;
00108         if (block_num != num_complete_blocks)
00109         {
00110             num_nodes_to_read = num_nodes_per_data_block;
00111         }
00112         else
00113         {
00114             num_nodes_to_read = size_last_block;
00115         }
00116 
00117         if (num_nodes_to_read > 0)
00118         {
00119             // Read a big block of data
00120             unsigned low_node = lowerNodeIndex + block_num*num_nodes_per_data_block;
00121             unsigned high_node = low_node + num_nodes_to_read;
00122             std::vector<std::vector<double> > voltages = mpDataReader->GetVariableOverTimeOverMultipleNodes(mVoltageName, low_node, high_node);
00123 
00124             for (unsigned node_within_block=0;
00125                  node_within_block < num_nodes_to_read;
00126                  node_within_block++)
00127             {
00128                 std::vector<double>& r_voltages = voltages[node_within_block];
00129                 CellProperties cell_props(r_voltages, mTimes, threshold);
00130                 std::vector<double> apds;
00131                 try
00132                 {
00133                     apds = cell_props.GetAllActionPotentialDurations(percentage);
00134                     assert(apds.size() != 0);
00135                 }
00136                 catch (Exception& e)
00137                 {
00138                     assert(e.GetShortMessage()=="No full action potential was recorded" ||
00139                            e.GetShortMessage()=="AP did not occur, never exceeded threshold voltage.");
00140                     apds.push_back(0);
00141                     assert(apds.size() == 1);
00142                 }
00143                 output_data.push_back(apds);
00144             }
00145         }
00146     }
00147     return output_data;
00148 }
00149 
00150 double PropagationPropertiesCalculator::CalculatePeakMembranePotential(unsigned globalNodeIndex)
00151 {
00152     std::vector<double>& r_voltages = rCacheVoltages(globalNodeIndex);
00153     double max = -DBL_MAX;
00154     for (unsigned i=0; i<r_voltages.size(); i++)
00155     {
00156         if (r_voltages[i]>max)
00157         {
00158             max = r_voltages[i];
00159         }
00160     }
00161     return max;
00162 }
00163 
00164 double PropagationPropertiesCalculator::CalculateConductionVelocity(unsigned globalNearNodeIndex,
00165                                                                     unsigned globalFarNodeIndex,
00166                                                                     const double euclideanDistance)
00167 {
00168     double t_near = 0;
00169     double t_far = 0;
00170     std::vector<double>& r_near_voltages = rCacheVoltages(globalNearNodeIndex);
00171     std::vector<double> far_voltages = mpDataReader->GetVariableOverTime(mVoltageName, globalFarNodeIndex);
00172 
00173     CellProperties near_cell_props(r_near_voltages, mTimes);
00174     CellProperties far_cell_props(far_voltages, mTimes);
00175 
00176     //The size of each vector is the number of APs that reached that node
00177     unsigned aps_near_node = near_cell_props.GetMaxUpstrokeVelocities().size();
00178     unsigned aps_far_node = far_cell_props.GetMaxUpstrokeVelocities().size();
00179 
00180     //These should never be empty. If so, an exception should have been thrown in the GetMaxUpstrokeVelocities() method.
00181     assert(aps_near_node > 0);
00182     assert(aps_far_node > 0);
00183 
00184     //if the same number of APs reached both nodes, get the last one...
00185     if (aps_near_node == aps_far_node)
00186     {
00187         t_near = near_cell_props.GetTimeAtLastMaxUpstrokeVelocity();
00188         t_far = far_cell_props.GetTimeAtLastMaxUpstrokeVelocity();
00189     }
00190     //...otherwise get the one with the smallest value, which is the last AP to reach both nodes
00191     //This prevents possible calculation of negative conduction velocities
00192     //for repeated stimuli
00193     else if (aps_near_node > aps_far_node)
00194     {
00195         t_near = near_cell_props.GetTimesAtMaxUpstrokeVelocity()[aps_far_node-1];
00196         t_far = far_cell_props.GetTimesAtMaxUpstrokeVelocity()[aps_far_node-1];
00197     }
00198     else
00199     {
00200         t_near = near_cell_props.GetTimesAtMaxUpstrokeVelocity()[aps_near_node-1];
00201         t_far = far_cell_props.GetTimesAtMaxUpstrokeVelocity()[aps_near_node-1];
00202     }
00203 
00205     if ((globalNearNodeIndex == globalFarNodeIndex) || ( fabs(t_far - t_near) < 1e-8))
00206     {
00207         // globalNearNodeIndex and globalFarNodeIndex are the same node, preventing a 0/0
00208         // or
00209         // AP number i is happening at the same time at nodes globalNearNodeIndex and globalFarNodeIndex
00210         return 0.0;
00211     }
00212     else
00213     {
00214         return euclideanDistance / (t_far - t_near);
00215     }
00216 
00217 
00218 }
00219 
00220 std::vector<double> PropagationPropertiesCalculator::CalculateAllConductionVelocities(unsigned globalNearNodeIndex,
00221                                                                                       unsigned globalFarNodeIndex,
00222                                                                                       const double euclideanDistance)
00223 {
00224     std::vector<double> conduction_velocities;
00225 
00226     std::vector<double> t_near;
00227     std::vector<double> t_far;
00228     unsigned number_of_aps = 0;
00229 
00230     std::vector<double>& r_near_voltages = rCacheVoltages(globalNearNodeIndex);
00231     std::vector<double> far_voltages = mpDataReader->GetVariableOverTime(mVoltageName, globalFarNodeIndex);
00232 
00233     CellProperties near_cell_props(r_near_voltages, mTimes);
00234     CellProperties far_cell_props(far_voltages, mTimes);
00235 
00236     t_near = near_cell_props.GetTimesAtMaxUpstrokeVelocity();
00237     t_far = far_cell_props.GetTimesAtMaxUpstrokeVelocity();
00238 
00239     //exception should have been thrown within the GetTimesAtMaxUpstrokeVelocity method if the threshold is never reached
00240     //and these vectors are empty
00241     assert(t_near.size() !=0);
00242     assert(t_far.size() !=0);
00243 
00244     //Check the node where the least number of aps is reached.
00245     //We will calculate only where AP reached both nodes
00246     if (t_near.size() > t_far.size())
00247     {
00248         number_of_aps = t_far.size();
00249     }
00250     else
00251     {
00252         number_of_aps = t_near.size();
00253     }
00254     //now fill the vector
00255 
00256     if (globalNearNodeIndex == globalFarNodeIndex)
00257     {
00258         // globalNearNodeIndex and globalFarNodeIndex are the same node, preventing a 0/0
00259         for (unsigned i = 0 ; i < number_of_aps;i++)
00260         {
00261             conduction_velocities.push_back(0.0);
00262         }
00263     }
00264     else
00265     {
00266         for (unsigned i = 0 ; i < number_of_aps;i++)
00267         {
00269             if ( fabs(t_far[i] - t_near[i]) < 1e-8)
00270             {
00271                 // AP number i is happening at the same time at nodes globalNearNodeIndex and globalFarNodeIndex
00272                 conduction_velocities.push_back(0.0);
00273             }
00274             else
00275             {
00276                 conduction_velocities.push_back(euclideanDistance / (t_far[i] - t_near[i]));
00277             }
00278         }
00279     }
00280 
00281     return conduction_velocities;
00282 }
00283 
00284 
00285 std::vector<unsigned> PropagationPropertiesCalculator::CalculateAllAboveThresholdDepolarisations(unsigned globalNodeIndex, double threshold)
00286 {
00287     std::vector<double>& r_voltages = rCacheVoltages(globalNodeIndex);
00288     CellProperties cell_props(r_voltages, mTimes, threshold);
00289     return cell_props.GetNumberOfAboveThresholdDepolarisationsForAllAps();
00290 }
00291 
00292 
00293 unsigned PropagationPropertiesCalculator::CalculateAboveThresholdDepolarisationsForLastAp(unsigned globalNodeIndex, double threshold)
00294 {
00295     std::vector<double>& r_voltages = rCacheVoltages(globalNodeIndex);
00296     CellProperties cell_props(r_voltages, mTimes, threshold);
00297     return cell_props.GetNumberOfAboveThresholdDepolarisationsForLastAp();
00298 }
00299 
00300 
00301 std::vector<double>& PropagationPropertiesCalculator::rCacheVoltages(unsigned globalNodeIndex)
00302 {
00303     if (globalNodeIndex != mCachedNodeGlobalIndex)
00304     {
00305         mCachedVoltages = mpDataReader->GetVariableOverTime(mVoltageName, globalNodeIndex);
00306         mCachedNodeGlobalIndex = globalNodeIndex;
00307     }
00308     return mCachedVoltages;
00309 }
Generated on Thu Dec 22 13:00:06 2011 for Chaste by  doxygen 1.6.3