CellProperties.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
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 
00030 #include "CellProperties.hpp"
00031 #include "Exception.hpp"
00032 #include <cmath>
00033 
00034 #include <iostream>
00035 
00036 enum APPhases { BELOWTHRESHOLD , ABOVETHRESHOLD };
00037 
00038 void CellProperties::CalculateProperties()
00039 {
00040     // Check we have some suitable data to process
00041     if (mrTime.size() < 1)
00042     {
00043         EXCEPTION("Insufficient time steps to calculate physiological properties.");
00044     }
00045 
00046     double prev_v = mrVoltage[0];
00047     double prev_t = mrTime[0];
00048     double current_upstroke_velocity = 0;
00049     double current_time_of_upstroke_velocity = 0;
00050     double current_resting_value=-DBL_MAX;
00051     double current_peak=-DBL_MAX;
00052     double current_minimum_velocity=DBL_MAX;
00053     double prev_upstroke_vel=0;
00054     unsigned ap_counter = 0;
00055     
00056     APPhases ap_phase = BELOWTHRESHOLD;
00057 
00058     unsigned time_steps = mrTime.size()-1; //The number of time steps is the number of intervals
00059 
00060     for (unsigned i=1; i<=time_steps; i++)
00061     {
00062         double v = mrVoltage[i];
00063         double t = mrTime[i];
00064         double upstroke_vel;
00065 
00066         if (i==1)
00067         {   // artificially set initial upstroke_vel to be zero otherwise
00068             // end up dividing by zero
00069             upstroke_vel = 0;
00070         }
00071         else
00072         {
00073             upstroke_vel = (v - prev_v) / (t - prev_t);
00074         }
00075         
00076         //Look for the upstroke velocity and when it happens (could be below or above threshold).
00077         if(upstroke_vel>=current_upstroke_velocity)
00078         {
00079             current_upstroke_velocity = upstroke_vel;
00080             current_time_of_upstroke_velocity = t;
00081         }
00082         
00083         switch (ap_phase)
00084         {
00085             case BELOWTHRESHOLD:
00086                 //while below threshold, find the resting value by checking where the velocity is minimal
00087                 //i.e. when it is flattest
00088                 if(fabs(upstroke_vel)<=current_minimum_velocity)
00089                 {
00090                     current_minimum_velocity=fabs(upstroke_vel);
00091                     current_resting_value = v;
00092                 }   
00093                 
00094                 // If we cross the threshold, this counts as an AP
00095                 if( v>mThreshold && prev_v <= mThreshold )
00096                 {
00097                     //register the resting value and re-initialise the minimum velocity
00098                     mRestingValues.push_back(current_resting_value); 
00099                     current_minimum_velocity = DBL_MAX;
00100                     
00101                     //Register the onset time. Linear interpolation.
00102                     mOnsets.push_back(prev_t + (t-prev_t)/(v-prev_v)*(mThreshold-prev_v));
00103                     
00104                     //If it is not the first AP, calculate cycle length for the last two APs
00105                     if (ap_counter>0)
00106                     {
00107                         mCycleLengths.push_back( mOnsets[ap_counter]-mOnsets[ap_counter-1] );
00108                     }
00109                     
00110                     ap_phase = ABOVETHRESHOLD;
00111                 }
00112                 break;
00113 
00114             case ABOVETHRESHOLD:
00115                 //While above threshold, look for the peak potential for the current AP
00116                 if (v>current_peak)
00117                 {
00118                    current_peak = v;
00119                 }
00120                 
00121                 // If we cross the threshold again, the AP is over
00122                 // and we register all the parameters.
00123                 if( v<mThreshold && prev_v >= mThreshold )
00124                 {
00125                     //register peak value for this AP
00126                     mPeakValues.push_back(current_peak);
00127                     //Re-initialise the current_peak.
00128                     current_peak = mThreshold;
00129                     
00130                     //register maximum upstroke velocity for this AP
00131                     mMaxUpstrokeVelocities.push_back(current_upstroke_velocity);
00132                     //re-initialise current_upstroke_velocity
00133                     current_upstroke_velocity = 0.0;
00134                     
00135                     //register time when maximum upstroke velocity occurred for this AP
00136                     mTimesAtMaxUpstrokeVelocity.push_back(current_time_of_upstroke_velocity);
00137                     //re-initialise current_time_of_upstroke_velocity=t;
00138                     current_time_of_upstroke_velocity = 0.0;
00139                     
00140                     //update the counter.
00141                     ap_counter++;                
00142                     ap_phase = BELOWTHRESHOLD;
00143                 }
00144                 break;
00145         }
00146 
00147         prev_v = v;
00148         prev_t = t;
00149         prev_upstroke_vel = upstroke_vel;
00150     }
00151     
00152     // One last check. If the simulation ends halfway through an AP
00153     // i.e. if the vectors of onsets has more elements than the vectors
00154     // of peak and upstroke properties (that are updated at the end of the AP),
00155     // then we register the peak and upstroke values so far
00156     // for the last incomplete AP. 
00157     if (mOnsets.size()>mMaxUpstrokeVelocities.size()) 
00158     {
00159         mMaxUpstrokeVelocities.push_back(current_upstroke_velocity);
00160     }
00161     if (mOnsets.size()>mPeakValues.size())
00162     {
00163         mPeakValues.push_back(current_peak);
00164     }
00165     if (mOnsets.size()>mTimesAtMaxUpstrokeVelocity.size()) 
00166     {
00167         mTimesAtMaxUpstrokeVelocity.push_back(current_time_of_upstroke_velocity);
00168     }
00169 }
00170 
00171 
00172 std::vector<double> CellProperties::CalculateActionPotentialDurations(const double percentage,
00173                                             std::vector<double>& rOnsets,
00174                                             std::vector<double>& rRestingPotentials,
00175                                             std::vector<double>& rPeakPotentials)
00176 {
00177     double prev_v = -DBL_MAX; 
00178     unsigned APcounter=0;//will keep count of the APDs that we calculate
00179     bool apd_is_calculated=true;//this will ensure we hit the target only once per AP.
00180     std::vector<double> apds;
00181     double target = DBL_MAX;
00182     
00183     for (unsigned i=0; i<mrTime.size(); i++)
00184     {
00185         double t = mrTime[i];
00186         double v = mrVoltage[i];
00187         
00188         //First we make sure we stop calculating after the last AP has been calculated
00189         if (APcounter<rPeakPotentials.size())
00190         {
00191             //Set the target potential
00192             target  = rRestingPotentials[APcounter]+0.01*(100-percentage)*(rPeakPotentials[APcounter]-rRestingPotentials[APcounter]);
00193         
00194             //if we reach the peak, we need to start to calculate an APD
00195             if (fabs(v-rPeakPotentials[APcounter])<=1e-6)
00196             {
00197                apd_is_calculated=false;
00198             }
00199             //if we hit the target while repolarising 
00200             //and we are told this apd is not calculated yet.
00201             if ( prev_v>v && prev_v>=target && v<=target && apd_is_calculated==false)
00202             {
00203                 apds.push_back (t - rOnsets[APcounter]);
00204                 APcounter++;
00205                 apd_is_calculated=true;
00206             }
00207         }
00208         prev_v = v;
00209     }
00210     
00211     return apds;
00212 }
00213 
00214 
00215 std::vector<double> CellProperties::GetAllActionPotentialDurations(const double percentage)
00216 {
00217     if (mOnsets.size() == 0)
00218     {
00219         // possible false error here if the simulation started at time < 0
00220         EXCEPTION("No action potential occurred");
00221     }
00222 
00223     std::vector<double> apds = CalculateActionPotentialDurations(percentage, 
00224                                                         mOnsets,
00225                                                         mRestingValues,
00226                                                         mPeakValues);
00227 
00228     return apds;
00229 }
00230 
00231 double CellProperties::GetLastActionPotentialDuration(const double percentage)
00232 {
00233     if (mOnsets.size() == 0)
00234     {
00235         // possible false error here if the simulation started at time < 0
00236         EXCEPTION("No action potential occurred");
00237     }
00238 
00239     std::vector<double> apds = CalculateActionPotentialDurations(percentage, 
00240                                                         mOnsets,
00241                                                         mRestingValues,
00242                                                         mPeakValues);
00243     if (apds.size()==0)
00244     {
00245         EXCEPTION("No complete action potential occurred");
00246     }
00247     
00248     //return the last apd                                                    
00249     return apds[apds.size()-1];
00250 }
00251 
00252 std::vector<double> CellProperties::GetActionPotentialAmplitudes()
00253 {
00254     unsigned size = mPeakValues.size();
00255     std::vector<double> amplitudes(size);
00256     for (unsigned i=0; i< size ;i++)
00257     {
00258         amplitudes[i] = (mPeakValues[i] - mRestingValues[i]);
00259     }
00260     return amplitudes; 
00261 }
00262 double CellProperties::GetLastMaxUpstrokeVelocity()
00263 {
00264     unsigned size = mMaxUpstrokeVelocities.size();
00265     if (size==0)
00266     {
00267         EXCEPTION("Upstroke never occurred");
00268     }   
00269     return mMaxUpstrokeVelocities[size-1];
00270     
00271 }
00272 double CellProperties::GetTimeAtLastMaxUpstrokeVelocity()
00273 {
00274     unsigned size = mTimesAtMaxUpstrokeVelocity.size();
00275     if (size==0)
00276     {
00277         EXCEPTION("Upstroke never occurred");
00278     }   
00279     return mTimesAtMaxUpstrokeVelocity[size-1];
00280 }
00281 

Generated on Wed Mar 18 12:51:52 2009 for Chaste by  doxygen 1.5.5