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