HeartGeometryInformation.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 #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 // Area of the septum considered to belong to the each ventricle (relative to 1)
00040 template<unsigned SPACE_DIM>
00041 const double HeartGeometryInformation<SPACE_DIM>::LEFT_SEPTUM_SIZE = 2.0/3.0;
00042 
00043 template<unsigned SPACE_DIM>
00044 const double HeartGeometryInformation<SPACE_DIM>::RIGHT_SEPTUM_SIZE = 1.0/3.0;
00045 
00046 template<unsigned SPACE_DIM>
00047 HeartGeometryInformation<SPACE_DIM>::HeartGeometryInformation(TetrahedralMesh<SPACE_DIM,SPACE_DIM>& rMesh,
00048                                                               std::string mEpiFile,
00049                                                               std::string mEndoFile)
00050    : mrMesh(rMesh)
00051 {  
00052     DistanceMapCalculator<SPACE_DIM> distance_calculator(mrMesh);   
00053 
00054     // Get nodes defining each surface
00055     GetNodesAtSurface(mEpiFile, mEpiSurface);
00056     GetNodesAtSurface(mEndoFile, mEndoSurface);
00057 
00058     // Compute the distance map of each surface
00059     distance_calculator.ComputeDistanceMap(mEpiSurface, mDistMapEpicardium);
00060     distance_calculator.ComputeDistanceMap(mEndoSurface, mDistMapEndocardium);
00061 
00062     mNumberOfSurfacesProvided = 2; 
00063 }
00064 
00065 template<unsigned SPACE_DIM>
00066 HeartGeometryInformation<SPACE_DIM>::HeartGeometryInformation (TetrahedralMesh<SPACE_DIM,SPACE_DIM>& rMesh,
00067                                                                std::string mEpiFile,
00068                                                                std::string mLVFile,
00069                                                                std::string mRVFile)
00070     : mrMesh(rMesh)
00071 {
00072     DistanceMapCalculator<SPACE_DIM> distance_calculator(mrMesh);   
00073     
00074     // Get nodes defining each surface
00075     GetNodesAtSurface(mEpiFile, mEpiSurface);
00076     GetNodesAtSurface(mLVFile, mLVSurface);
00077     GetNodesAtSurface(mRVFile, mRVSurface);
00078 
00079     // Compute the distance map of each surface
00080     distance_calculator.ComputeDistanceMap(mEpiSurface, mDistMapEpicardium);
00081     distance_calculator.ComputeDistanceMap(mLVSurface, mDistMapLeftVentricle);
00082     distance_calculator.ComputeDistanceMap(mRVSurface, mDistMapRightVentricle);
00083 
00084     mNumberOfSurfacesProvided = 3; 
00085 }
00086 
00087 template<unsigned SPACE_DIM>
00088 HeartGeometryInformation<SPACE_DIM>::HeartGeometryInformation (TetrahedralMesh<SPACE_DIM,SPACE_DIM>& rMesh,
00089                                                                std::vector<unsigned>& rNodesAtEpi,
00090                                                                std::vector<unsigned>& rNodesAtEndo)
00091     : mrMesh(rMesh)
00092       
00093 {
00094     DistanceMapCalculator<SPACE_DIM> distance_calculator(mrMesh);   
00095 
00096     // Compute the distance map of each surface
00097     distance_calculator.ComputeDistanceMap(rNodesAtEpi, mDistMapEpicardium);
00098     distance_calculator.ComputeDistanceMap(rNodesAtEndo, mDistMapEndocardium);
00099 
00100     mNumberOfSurfacesProvided = 2; 
00101 }   
00102 
00103 template<unsigned SPACE_DIM>
00104 HeartGeometryInformation<SPACE_DIM>::HeartGeometryInformation (TetrahedralMesh<SPACE_DIM,SPACE_DIM>& rMesh,
00105                                                                std::vector<unsigned>& rNodesAtEpi,
00106                                                                std::vector<unsigned>& rNodesAtLv,
00107                                                                std::vector<unsigned>& rNodesAtRv)
00108     : mrMesh(rMesh)
00109 {
00110     DistanceMapCalculator<SPACE_DIM> distance_calculator(mrMesh);   
00111 
00112     // Compute the distance map of each surface
00113     distance_calculator.ComputeDistanceMap(rNodesAtEpi, mDistMapEpicardium);
00114     distance_calculator.ComputeDistanceMap(rNodesAtLv, mDistMapLeftVentricle);
00115     distance_calculator.ComputeDistanceMap(rNodesAtRv, mDistMapRightVentricle);
00116     mNumberOfSurfacesProvided = 3; 
00117 }                                           
00118 
00119 
00120 template<unsigned SPACE_DIM>
00121 void HeartGeometryInformation<SPACE_DIM>::ProcessLine(
00122         const std::string& line, std::set<unsigned>& surfaceNodeIndexSet) const
00123 {
00124     unsigned num_nodes = 0;
00125     std::stringstream line_stream(line);
00126 
00127     while (!line_stream.eof())
00128     {
00129         unsigned item;
00130         line_stream >> item;
00131         // Shift the nodes, since we are assuming MEMFEM format (numbered from 1 on)
00132         surfaceNodeIndexSet.insert(item-1);
00133 
00134         num_nodes++;
00135     }
00136 
00137     if (num_nodes != SPACE_DIM)
00138     {
00139         EXCEPTION("Wrong file format");
00140     }
00141 
00142 }
00143 
00144 
00145 template<unsigned SPACE_DIM>
00146 void HeartGeometryInformation<SPACE_DIM>::GetNodesAtSurface(
00147         const std::string& surfaceFile, std::vector<unsigned>& rSurfaceNodes) const
00148 {
00149     // Open the file defining the surface
00150     std::ifstream file_stream;
00151     file_stream.open(surfaceFile.c_str());
00152     if (!file_stream.is_open())
00153     {
00154         EXCEPTION("Wrong surface definition file name " + surfaceFile);
00155     }
00156 
00157     // Temporary storage for the nodes, helps discarding repeated values
00158     std::set<unsigned> surface_node_index_set;
00159 
00160     // Loop over all the triangles and add node indexes to the set
00161     std::string line;
00162     getline(file_stream, line);
00163     do
00164     {
00165         ProcessLine(line, surface_node_index_set);
00166 
00167         getline(file_stream, line);
00168     }
00169     while(!file_stream.eof());
00170 
00171     // Make vector big enough
00172     rSurfaceNodes.reserve(surface_node_index_set.size());
00173 
00174     // Copy the node indexes from the set to the vector
00175     for(std::set<unsigned>::iterator node_index_it=surface_node_index_set.begin();
00176         node_index_it != surface_node_index_set.end();
00177         node_index_it++)
00178     {
00179         rSurfaceNodes.push_back(*node_index_it);
00180     }
00181 
00182     file_stream.close();
00183 }
00184 
00185 
00186 
00187 template<unsigned SPACE_DIM>
00188 HeartRegionType HeartGeometryInformation<SPACE_DIM>::GetHeartRegion(unsigned nodeIndex) const
00189 {
00190 
00191     if (mDistMapRightVentricle[nodeIndex] >= mDistMapEpicardium[nodeIndex] &&
00192         mDistMapRightVentricle[nodeIndex] >= mDistMapLeftVentricle[nodeIndex])
00193     {
00194         return HeartRegionCode::LEFT_VENTRICLE_WALL;
00195     }
00196 
00197     if (mDistMapLeftVentricle[nodeIndex] >= mDistMapEpicardium[nodeIndex] &&
00198         mDistMapLeftVentricle[nodeIndex] >= mDistMapRightVentricle[nodeIndex])
00199     {
00200         return HeartRegionCode::RIGHT_VENTRICLE_WALL;
00201     }
00202 
00203     if (mDistMapEpicardium[nodeIndex] >= mDistMapLeftVentricle[nodeIndex] &&
00204         mDistMapEpicardium[nodeIndex] >= mDistMapRightVentricle[nodeIndex])
00205     {
00206         if (mDistMapLeftVentricle[nodeIndex]
00207             < LEFT_SEPTUM_SIZE*(mDistMapLeftVentricle[nodeIndex] + mDistMapRightVentricle[nodeIndex]))
00208         {
00209             return HeartRegionCode::LEFT_SEPTUM;
00210         }
00211         else
00212         {
00213             return HeartRegionCode::RIGHT_SEPTUM;
00214         }
00215     }
00216 
00217     return HeartRegionCode::UNKNOWN;
00218 }
00219 
00220 template<unsigned SPACE_DIM>
00221 double HeartGeometryInformation<SPACE_DIM>::GetDistanceToEndo(unsigned nodeIndex)
00222 {
00223     // General case where you provide 3 surfaces: LV, RV, epicardium 
00224     if ( mNumberOfSurfacesProvided == 3)
00225     {
00226         HeartRegionType node_region = GetHeartRegion(nodeIndex);
00227         switch(node_region)
00228         {
00229             case HeartRegionCode::LEFT_VENTRICLE_WALL:
00230             case HeartRegionCode::LEFT_VENTRICLE_SURFACE:
00231                 return mDistMapLeftVentricle[nodeIndex];
00232                 break;
00233 
00234             case HeartRegionCode::RIGHT_VENTRICLE_WALL:
00235             case HeartRegionCode::RIGHT_VENTRICLE_SURFACE:
00236                 return mDistMapRightVentricle[nodeIndex];
00237                 break;
00238 
00239             case HeartRegionCode::LEFT_SEPTUM:
00240                 return mDistMapLeftVentricle[nodeIndex];
00241                 break;
00242 
00243             case HeartRegionCode::RIGHT_SEPTUM:
00244                 return mDistMapRightVentricle[nodeIndex] ;
00245                 break;
00246     
00247             case HeartRegionCode::UNKNOWN:
00248                 #define COVERAGE_IGNORE
00249                 std::cerr << "Wrong distances node: " << nodeIndex << "\t"
00250                           << "Epi " << mDistMapEpicardium[nodeIndex] << "\t"
00251                           << "RV " << mDistMapRightVentricle[nodeIndex] << "\t"
00252                           << "LV " << mDistMapLeftVentricle[nodeIndex]
00253                           << std::endl;
00254     
00255                 // Make wall_thickness=0 as in Martin's code
00256                 return 0.0;
00257                 break;
00258                 #undef COVERAGE_IGNORE
00259 
00260             default:        
00261                 NEVER_REACHED;
00262         }
00263     }
00264     // Simplified case where you only provide epi and endo surface definitions
00265     else
00266     {
00267         return mDistMapEndocardium[nodeIndex];
00268     }
00269     
00270     // gcc wants to see a return statement at the end of the method.
00271     NEVER_REACHED;
00272     return 0.0;
00273 }
00274 
00275 template<unsigned SPACE_DIM>
00276 double HeartGeometryInformation<SPACE_DIM>::GetDistanceToEpi(unsigned nodeIndex)
00277 {
00279     return mDistMapEpicardium[nodeIndex];
00280 }
00281 
00282 template<unsigned SPACE_DIM>
00283 double HeartGeometryInformation<SPACE_DIM>::CalculateRelativeWallPosition(unsigned nodeIndex)
00284 {
00285         
00286     double dist_endo = GetDistanceToEndo(nodeIndex);
00287     double dist_epi = GetDistanceToEpi(nodeIndex);
00288 
00289     double relative_position;
00290         
00291     if ( (dist_endo + dist_epi) != 0 )
00292     {
00293        relative_position = dist_endo / (dist_endo + dist_epi);
00294     }
00295     else
00296     {
00297         /*
00298          *  A node contained on both epicardium and lv (or rv) surfaces has wall thickness 0/0.
00299          *  By setting its value to 0 we consider it contained only on the lv (or rv) surface.
00300          */
00301         relative_position = 0;
00302     }
00303     return relative_position;
00304 }
00305 
00306 template<unsigned SPACE_DIM>
00307 void HeartGeometryInformation<SPACE_DIM>::DetermineLayerForEachNode(double epiFraction, double endoFraction)
00308 {
00309     assert(epiFraction+endoFraction<1);
00310     assert(endoFraction>0);
00311     assert(epiFraction>0);
00312     
00313     mLayerForEachNode.resize(mrMesh.GetNumNodes());
00314     for(unsigned i=0; i<mrMesh.GetNumNodes(); i++)
00315     {
00316         double position = CalculateRelativeWallPosition(i);
00317         if (position<endoFraction)
00318         {
00319             mLayerForEachNode[i] = ENDO;
00320         }
00321         else if (position<(1-epiFraction))
00322         {
00323             mLayerForEachNode[i] = MID;
00324         }
00325         else
00326         {
00327             mLayerForEachNode[i] = EPI;
00328         }
00329     }
00330 }
00331    
00332 
00333 template<unsigned SPACE_DIM>
00334 void HeartGeometryInformation<SPACE_DIM>::WriteLayerForEachNode(std::string outputDir, std::string file)
00335 {
00336     if (PetscTools::AmMaster())
00337     {
00338         OutputFileHandler handler(outputDir,false);
00339         out_stream p_file = handler.OpenOutputFile(file);
00340         
00341         assert(mLayerForEachNode.size()>0);
00342         for(unsigned i=0; i<mrMesh.GetNumNodes(); i++)
00343         {
00344             if(mLayerForEachNode[i]==EPI)
00345             {
00346                 *p_file << "0\n";
00347             }
00348             else if(mLayerForEachNode[i]==MID)
00349             {
00350                 *p_file << "1\n";
00351             }
00352             else // endo
00353             {
00354                 *p_file << "2\n";
00355             }
00356         }
00357         
00358         p_file->close();
00359     }
00360     PetscTools::Barrier(); // Make other processes wait until we're done
00361 }
00362 
00363 
00364 
00366 // Explicit instantiation
00368 
00369 //template class HeartGeometryInformation<1>;
00370 template class HeartGeometryInformation<2>;
00371 template class HeartGeometryInformation<3>;

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