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 #include "HeartGeometryInformation.hpp"
00030
00031 #include <cmath>
00032 #include <fstream>
00033 #include <sstream>
00034 #include "OutputFileHandler.hpp"
00035 #include "Exception.hpp"
00036 #include "PetscTools.hpp"
00037
00038
00039 template<unsigned SPACE_DIM>
00040 const double HeartGeometryInformation<SPACE_DIM>::LEFT_SEPTUM_SIZE = 2.0/3.0;
00041
00042 template<unsigned SPACE_DIM>
00043 const double HeartGeometryInformation<SPACE_DIM>::RIGHT_SEPTUM_SIZE = 1.0/3.0;
00044
00045 template<unsigned SPACE_DIM>
00046 HeartGeometryInformation<SPACE_DIM>::HeartGeometryInformation(AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>& rMesh,
00047 const std::string& rEpiFile,
00048 const std::string& rEndoFile,
00049 bool indexFromZero)
00050 : mpMesh(&rMesh)
00051 {
00052 DistanceMapCalculator<SPACE_DIM, SPACE_DIM> distance_calculator(*mpMesh);
00053
00054
00055 GetNodesAtSurface(rEpiFile, mEpiSurface, indexFromZero);
00056 GetNodesAtSurface(rEndoFile, mEndoSurface, indexFromZero);
00057
00058
00059 distance_calculator.ComputeDistanceMap(mEpiSurface, mDistMapEpicardium);
00060 distance_calculator.ComputeDistanceMap(mEndoSurface, mDistMapEndocardium);
00061 mNumberOfSurfacesProvided = 2;
00062 }
00063
00064 template<unsigned SPACE_DIM>
00065 HeartGeometryInformation<SPACE_DIM>::HeartGeometryInformation (AbstractTetrahedralMesh<SPACE_DIM,SPACE_DIM>& rMesh,
00066 const std::string& rEpiFile,
00067 const std::string& rLVFile,
00068 const std::string& rRVFile,
00069 bool indexFromZero)
00070 : mpMesh(&rMesh)
00071 {
00072 DistanceMapCalculator<SPACE_DIM, SPACE_DIM> distance_calculator(*mpMesh);
00073
00074
00075
00076 GetNodesAtSurface(rEpiFile, mEpiSurface, indexFromZero);
00077
00078 if (rLVFile != "")
00079 {
00080 GetNodesAtSurface(rLVFile, mLVSurface, indexFromZero);
00081 }
00082 else
00083 {
00084 if (rRVFile == "")
00085 {
00086 EXCEPTION("At least one of left ventricle or right ventricle files is required");
00087 }
00088 }
00089 if (rRVFile != "")
00090 {
00091 GetNodesAtSurface(rRVFile, mRVSurface, indexFromZero);
00092 }
00093 distance_calculator.ComputeDistanceMap(mEpiSurface, mDistMapEpicardium);
00094 distance_calculator.ComputeDistanceMap(mLVSurface, mDistMapLeftVentricle);
00095 distance_calculator.ComputeDistanceMap(mRVSurface, mDistMapRightVentricle);
00096
00097 mNumberOfSurfacesProvided = 3;
00098 }
00099
00100
00101 template<unsigned SPACE_DIM>
00102 HeartGeometryInformation<SPACE_DIM>::HeartGeometryInformation (std::string nodeHeterogeneityFileName)
00103 {
00104 mpMesh = NULL;
00105 std::ifstream heterogeneity_file;
00106 heterogeneity_file.open(nodeHeterogeneityFileName.c_str());
00107
00108 if (!(heterogeneity_file.is_open()))
00109 {
00110 heterogeneity_file.close();
00111 EXCEPTION("Could not open heterogeneities file (" << nodeHeterogeneityFileName << ")");
00112 }
00113
00114 while(!heterogeneity_file.eof())
00115 {
00116 int value;
00117
00118 heterogeneity_file >> value;
00119
00120
00121 if( (heterogeneity_file.fail() && !heterogeneity_file.eof()) || value < 0 || value > 2)
00122 {
00123 heterogeneity_file.close();
00124 EXCEPTION("A value in the heterogeneities file (" << nodeHeterogeneityFileName
00125 << ") is out of range (or not an integer). It should be epi = 0, mid = 1, endo = 2");
00126 }
00127
00128 if(!heterogeneity_file.eof())
00129 {
00130 if(value==0)
00131 {
00132 mLayerForEachNode.push_back(EPI);
00133 }
00134 else if(value==1)
00135 {
00136 mLayerForEachNode.push_back(MID);
00137 }
00138 else
00139 {
00140 assert(value==2);
00141 mLayerForEachNode.push_back(ENDO);
00142 }
00143 }
00144 }
00145
00146 heterogeneity_file.close();
00147 }
00148
00149 template<unsigned SPACE_DIM>
00150 void HeartGeometryInformation<SPACE_DIM>::ProcessLine(
00151 const std::string& line, std::set<unsigned>& rSurfaceNodeIndexSet, unsigned offset) const
00152 {
00153 std::stringstream line_stream(line);
00154 while (!line_stream.eof())
00155 {
00156 unsigned item;
00157 line_stream >> item;
00158
00159 if (item == 0 && offset != 0)
00160 {
00161 EXCEPTION("Error when reading surface file. It was assumed not to be indexed from zero, but zero appeared in the list.");
00162 }
00163 rSurfaceNodeIndexSet.insert(item-offset);
00164 }
00165 }
00166
00167
00168 template<unsigned SPACE_DIM>
00169 void HeartGeometryInformation<SPACE_DIM>::GetNodesAtSurface(
00170 const std::string& surfaceFile, std::vector<unsigned>& rSurfaceNodes, bool indexFromZero) const
00171 {
00172
00173 std::ifstream file_stream;
00174 unsigned offset=0;
00175 if (indexFromZero == false)
00176 {
00177 offset=1;
00178 }
00179
00180 file_stream.open(surfaceFile.c_str());
00181 if (!file_stream.is_open())
00182 {
00183 EXCEPTION("Wrong surface definition file name " + surfaceFile);
00184 }
00185
00186
00187 std::set<unsigned> surface_original_node_index_set;
00188
00189
00190 std::string line;
00191 getline(file_stream, line);
00192 do
00193 {
00194 ProcessLine(line, surface_original_node_index_set, offset);
00195
00196 getline(file_stream, line);
00197 }
00198 while(!file_stream.eof());
00199 file_stream.close();
00200
00201
00202 rSurfaceNodes.reserve(surface_original_node_index_set.size());
00203
00204 if (mpMesh->rGetNodePermutation().empty())
00205 {
00206
00207 for(std::set<unsigned>::iterator node_index_it=surface_original_node_index_set.begin();
00208 node_index_it != surface_original_node_index_set.end();
00209 node_index_it++)
00210 {
00211 rSurfaceNodes.push_back(*node_index_it);
00212 }
00213 }
00214 else
00215 {
00216
00217 for(std::set<unsigned>::iterator node_index_it=surface_original_node_index_set.begin();
00218 node_index_it != surface_original_node_index_set.end();
00219 node_index_it++)
00220 {
00221 rSurfaceNodes.push_back(mpMesh->rGetNodePermutation()[*node_index_it]);
00222 }
00223 }
00224 }
00225
00226
00227
00228 template<unsigned SPACE_DIM>
00229 HeartRegionType HeartGeometryInformation<SPACE_DIM>::GetHeartRegion(unsigned nodeIndex) const
00230 {
00231
00232 if (mDistMapRightVentricle[nodeIndex] >= mDistMapEpicardium[nodeIndex] &&
00233 mDistMapRightVentricle[nodeIndex] >= mDistMapLeftVentricle[nodeIndex])
00234 {
00235 return LEFT_VENTRICLE_WALL;
00236 }
00237
00238 if (mDistMapLeftVentricle[nodeIndex] >= mDistMapEpicardium[nodeIndex] &&
00239 mDistMapLeftVentricle[nodeIndex] >= mDistMapRightVentricle[nodeIndex])
00240 {
00241 return RIGHT_VENTRICLE_WALL;
00242 }
00243
00244 if (mDistMapEpicardium[nodeIndex] >= mDistMapLeftVentricle[nodeIndex] &&
00245 mDistMapEpicardium[nodeIndex] >= mDistMapRightVentricle[nodeIndex])
00246 {
00247 if (mDistMapLeftVentricle[nodeIndex]
00248 < LEFT_SEPTUM_SIZE*(mDistMapLeftVentricle[nodeIndex] + mDistMapRightVentricle[nodeIndex]))
00249 {
00250 return LEFT_SEPTUM;
00251 }
00252 else
00253 {
00254 return RIGHT_SEPTUM;
00255 }
00256 }
00257
00258 return UNKNOWN;
00259 }
00260
00261 template<unsigned SPACE_DIM>
00262 double HeartGeometryInformation<SPACE_DIM>::GetDistanceToEndo(unsigned nodeIndex)
00263 {
00264
00265 if ( mNumberOfSurfacesProvided == 3)
00266 {
00267 HeartRegionType node_region = GetHeartRegion(nodeIndex);
00268 switch(node_region)
00269 {
00270 case LEFT_VENTRICLE_WALL:
00271 case LEFT_VENTRICLE_SURFACE:
00272 return mDistMapLeftVentricle[nodeIndex];
00273 break;
00274
00275 case RIGHT_VENTRICLE_WALL:
00276 case RIGHT_VENTRICLE_SURFACE:
00277 return mDistMapRightVentricle[nodeIndex];
00278 break;
00279
00280 case LEFT_SEPTUM:
00281 return mDistMapLeftVentricle[nodeIndex];
00282 break;
00283
00284 case RIGHT_SEPTUM:
00285 return mDistMapRightVentricle[nodeIndex] ;
00286 break;
00287
00288 case UNKNOWN:
00289 #define COVERAGE_IGNORE
00290 std::cerr << "Wrong distances node: " << nodeIndex << "\t"
00291 << "Epi " << mDistMapEpicardium[nodeIndex] << "\t"
00292 << "RV " << mDistMapRightVentricle[nodeIndex] << "\t"
00293 << "LV " << mDistMapLeftVentricle[nodeIndex]
00294 << std::endl;
00295
00296
00297 return 0.0;
00298 break;
00299 #undef COVERAGE_IGNORE
00300
00301 default:
00302 NEVER_REACHED;
00303 }
00304 }
00305
00306 else
00307 {
00308 return mDistMapEndocardium[nodeIndex];
00309 }
00310
00311
00312 NEVER_REACHED;
00313 return 0.0;
00314 }
00315
00316 template<unsigned SPACE_DIM>
00317 double HeartGeometryInformation<SPACE_DIM>::GetDistanceToEpi(unsigned nodeIndex)
00318 {
00319 return mDistMapEpicardium[nodeIndex];
00320 }
00321
00322 template<unsigned SPACE_DIM>
00323 double HeartGeometryInformation<SPACE_DIM>::CalculateRelativeWallPosition(unsigned nodeIndex)
00324 {
00325
00326 double dist_endo = GetDistanceToEndo(nodeIndex);
00327 double dist_epi = GetDistanceToEpi(nodeIndex);
00328 assert( (dist_endo + dist_epi) != 0 );
00329
00330
00331
00332
00333 double relative_position = dist_endo / (dist_endo + dist_epi);
00334 return relative_position;
00335 }
00336
00337 template<unsigned SPACE_DIM>
00338 void HeartGeometryInformation<SPACE_DIM>::DetermineLayerForEachNode(double epiFraction, double endoFraction)
00339 {
00340 if (epiFraction+endoFraction>1)
00341 {
00342 EXCEPTION("The sum of fractions of epicardial and endocardial layers must be lesser than 1");
00343 }
00344
00345 if ((endoFraction<0) || (epiFraction<0))
00346 {
00347 EXCEPTION("A fraction of a layer must be positive");
00348 }
00349
00350 mLayerForEachNode.resize(mpMesh->GetNumNodes());
00351 for(unsigned i=0; i<mpMesh->GetNumNodes(); i++)
00352 {
00353 double position = CalculateRelativeWallPosition(i);
00354 if (position<endoFraction)
00355 {
00356 mLayerForEachNode[i] = ENDO;
00357 }
00358 else if (position<(1-epiFraction))
00359 {
00360 mLayerForEachNode[i] = MID;
00361 }
00362 else
00363 {
00364 mLayerForEachNode[i] = EPI;
00365 }
00366 }
00367 }
00368
00369
00370 template<unsigned SPACE_DIM>
00371 void HeartGeometryInformation<SPACE_DIM>::WriteLayerForEachNode(std::string outputDir, std::string file)
00372 {
00373 OutputFileHandler handler(outputDir,false);
00374 if (PetscTools::AmMaster())
00375 {
00376 out_stream p_file = handler.OpenOutputFile(file);
00377
00378 assert(mLayerForEachNode.size()>0);
00379 for(unsigned i=0; i<mpMesh->GetNumNodes(); i++)
00380 {
00381 if(mLayerForEachNode[i]==EPI)
00382 {
00383 *p_file << "0\n";
00384 }
00385 else if(mLayerForEachNode[i]==MID)
00386 {
00387 *p_file << "1\n";
00388 }
00389 else
00390 {
00391 *p_file << "2\n";
00392 }
00393 }
00394
00395 p_file->close();
00396 }
00397 PetscTools::Barrier("HeartGeometryInformation::WriteLayerForEachNode");
00398 }
00399
00400
00401 template<unsigned SPACE_DIM>
00402 ChasteCuboid<SPACE_DIM> HeartGeometryInformation<SPACE_DIM>::CalculateBoundingBoxOfSurface(const std::vector<unsigned>& rSurfaceNodes)
00403 {
00404
00405 assert(rSurfaceNodes.size()>0);
00406
00407 c_vector<double, SPACE_DIM> my_minimum_point = scalar_vector<double>(SPACE_DIM, DBL_MAX);
00408
00409 c_vector<double, SPACE_DIM> my_maximum_point=-my_minimum_point;
00410
00411
00412 for (unsigned surface_index=0; surface_index<rSurfaceNodes.size(); surface_index++)
00413 {
00414 unsigned global_index=rSurfaceNodes[surface_index];
00415 if (mpMesh->GetDistributedVectorFactory()->IsGlobalIndexLocal(global_index) )
00416 {
00417 c_vector<double, SPACE_DIM> position = mpMesh->GetNode(global_index)->rGetLocation();
00418
00419 for (unsigned i=0; i<SPACE_DIM; i++)
00420 {
00421 if (position[i] < my_minimum_point[i])
00422 {
00423 my_minimum_point[i] = position[i];
00424 }
00425 if (position[i] > my_maximum_point[i])
00426 {
00427 my_maximum_point[i] = position[i];
00428 }
00429 }
00430 }
00431 }
00432
00433
00434 c_vector<double, SPACE_DIM> global_minimum_point;
00435 c_vector<double, SPACE_DIM> global_maximum_point;
00436 MPI_Allreduce(&my_minimum_point[0], &global_minimum_point[0], SPACE_DIM, MPI_DOUBLE, MPI_MIN, PETSC_COMM_WORLD);
00437 MPI_Allreduce(&my_maximum_point[0], &global_maximum_point[0], SPACE_DIM, MPI_DOUBLE, MPI_MAX, PETSC_COMM_WORLD);
00438
00439
00440 ChastePoint<SPACE_DIM> min(global_minimum_point);
00441 ChastePoint<SPACE_DIM> max(global_maximum_point);
00442
00443 return ChasteCuboid<SPACE_DIM>(min, max);
00444 }
00445
00446
00448
00450
00451
00452 template class HeartGeometryInformation<2>;
00453 template class HeartGeometryInformation<3>;