00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "PseudoEcgCalculator.hpp"
00037 #include "HeartRegionCodes.hpp"
00038 #include "HeartConfig.hpp"
00039 #include "PetscTools.hpp"
00040 #include "Version.hpp"
00041 #include <iostream>
00042
00043 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00044 double PseudoEcgCalculator<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> ::GetIntegrand(ChastePoint<SPACE_DIM>& rX,
00045 c_vector<double,PROBLEM_DIM>& rU,
00046 c_matrix<double,PROBLEM_DIM,SPACE_DIM>& rGradU)
00047 {
00048 c_vector<double,SPACE_DIM> r_vector = rX.rGetLocation()- mProbeElectrode.rGetLocation();
00049 double norm_r = norm_2(r_vector);
00050 if (norm_r <= DBL_EPSILON)
00051 {
00052 EXCEPTION("Probe is on a mesh Gauss point.");
00053 }
00054 c_vector<double,SPACE_DIM> grad_one_over_r = - (r_vector)*SmallPow( (1/norm_r) , 3);
00055 matrix_row<c_matrix<double, PROBLEM_DIM, SPACE_DIM> > grad_u_row(rGradU, 0);
00056 double integrand = inner_prod(grad_u_row, grad_one_over_r);
00057
00058 return -mDiffusionCoefficient*integrand;
00059 }
00060
00061 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00062 PseudoEcgCalculator<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::PseudoEcgCalculator(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>& rMesh,
00063 const ChastePoint<SPACE_DIM>& rProbeElectrode,
00064 const FileFinder& rDirectory,
00065 std::string hdf5File,
00066 std::string variableName,
00067 unsigned timestepStride)
00068 : mrMesh(rMesh),
00069 mProbeElectrode(rProbeElectrode),
00070 mVariableName(variableName),
00071 mTimestepStride(timestepStride)
00072 {
00073 mpDataReader = new Hdf5DataReader(rDirectory, hdf5File);
00074 mNumberOfNodes = mpDataReader->GetNumberOfRows();
00075 mNumTimeSteps = mpDataReader->GetVariableOverTime(mVariableName, 0u).size();
00076 mDiffusionCoefficient = 1.0;
00077
00078 assert(mNumberOfNodes == mrMesh.GetNumNodes());
00079 }
00080
00081 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00082 bool PseudoEcgCalculator<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::ShouldSkipThisElement(Element<ELEMENT_DIM,SPACE_DIM>& rElement)
00083 {
00084 bool result = false;
00085 if (mVariableName=="V")
00086 {
00087
00088 result = HeartRegionCode::IsRegionBath(rElement.GetUnsignedAttribute());
00089 }
00090 return result;
00091 }
00092
00093 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00094 PseudoEcgCalculator<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::~PseudoEcgCalculator()
00095 {
00096 delete mpDataReader;
00097 }
00098
00099 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00100 void PseudoEcgCalculator<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::SetDiffusionCoefficient(double diffusionCoefficient)
00101 {
00102 assert(diffusionCoefficient>=0);
00103 mDiffusionCoefficient = diffusionCoefficient;
00104 }
00105
00106 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00107 double PseudoEcgCalculator<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::ComputePseudoEcgAtOneTimeStep (unsigned timeStep)
00108 {
00109 Vec solution_at_one_time_step = PetscTools::CreateVec(mNumberOfNodes);
00110 mpDataReader->GetVariableOverNodes(solution_at_one_time_step, mVariableName , timeStep);
00111
00112 double pseudo_ecg_at_one_timestep;
00113 try
00114 {
00115 pseudo_ecg_at_one_timestep = this->Calculate(mrMesh, solution_at_one_time_step);
00116 }
00117 catch (Exception &e)
00118 {
00119 PetscTools::Destroy(solution_at_one_time_step);
00120 throw e;
00121 }
00122 PetscTools::Destroy(solution_at_one_time_step);
00123 return pseudo_ecg_at_one_timestep;
00124 }
00125
00126 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00127 void PseudoEcgCalculator<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::WritePseudoEcg ()
00128 {
00129
00130 std::vector<double> time_points = mpDataReader->GetUnlimitedDimensionValues();
00131
00132 std::stringstream stream;
00133 stream << "PseudoEcgFromElectrodeAt" << "_" << mProbeElectrode.GetWithDefault(0)
00134 << "_" << mProbeElectrode.GetWithDefault(1)
00135 << "_" << mProbeElectrode.GetWithDefault(2) << ".dat";
00136 OutputFileHandler output_file_handler(HeartConfig::Instance()->GetOutputDirectory() + "/output", false);
00137 out_stream p_file=out_stream(NULL);
00138 if (PetscTools::AmMaster())
00139 {
00140 p_file = output_file_handler.OpenOutputFile(stream.str());
00141 *p_file << "#Time(ms)\tPseudo-ECG\n";
00142 }
00143 for (unsigned time_step = 0; time_step < mNumTimeSteps; time_step+=mTimestepStride)
00144 {
00145 double pseudo_ecg_at_one_timestep = ComputePseudoEcgAtOneTimeStep(time_step);
00146 if (PetscTools::AmMaster())
00147 {
00148 *p_file << time_points[time_step] << "\t" <<pseudo_ecg_at_one_timestep << "\n";
00149 }
00150 }
00151 if (PetscTools::AmMaster())
00152 {
00153
00154 std::string comment = "# " + ChasteBuildInfo::GetProvenanceString();
00155 *p_file << comment;
00156 p_file->close();
00157 }
00158 }
00160
00162
00163 template class PseudoEcgCalculator<1,1,1>;
00164 template class PseudoEcgCalculator<1,2,1>;
00165 template class PseudoEcgCalculator<1,3,1>;
00166 template class PseudoEcgCalculator<2,2,1>;
00167
00168 template class PseudoEcgCalculator<3,3,1>;
00169