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

Generated on Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5