CmguiMeshWriter.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
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 #include "Exception.hpp"
00029 #include "CmguiMeshWriter.hpp"
00030 #include "Version.hpp"
00031 #include <boost/shared_ptr.hpp>
00032 
00033 #include "AbstractTetrahedralMesh.hpp"
00034 #include "DistributedTetrahedralMesh.hpp"
00035 
00037 // Implementation
00039 
00040 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00041 CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::CmguiMeshWriter(const std::string &rDirectory,
00042                                                         const std::string &rBaseName,
00043                                                         bool cleanDirectory)
00044         : AbstractTetrahedralMeshWriter<ELEMENT_DIM,SPACE_DIM>(rDirectory, rBaseName, cleanDirectory)
00045 {
00046     this->mIndexFromZero = false;
00047     mGroupName = this->mBaseName;
00048 
00049     switch (ELEMENT_DIM)
00050     {
00051         case 1:
00052         {
00053             mElementFileHeader = CmguiElementFileHeader1D;
00054             mCoordinatesFileHeader = CmguiCoordinatesFileHeader1D;
00055             mAdditionalFieldHeader = CmguiAdditionalFieldHeader1D;
00056             break;
00057         }
00058         case 2:
00059         {
00060             mElementFileHeader = CmguiElementFileHeader2D;
00061             mCoordinatesFileHeader = CmguiCoordinatesFileHeader2D;
00062             mAdditionalFieldHeader = CmguiAdditionalFieldHeader2D;
00063             break;
00064         }
00065         case 3:
00066         {
00067             mElementFileHeader = CmguiElementFileHeader3D;
00068             mCoordinatesFileHeader = CmguiCoordinatesFileHeader3D;
00069             mAdditionalFieldHeader = CmguiAdditionalFieldHeader3D;
00070             break;
00071         }
00072         default:
00073         {
00074             NEVER_REACHED;
00075         }
00076     }
00077 
00078 
00079     mNumNodesPerElement = ELEMENT_DIM+1;
00080     mReordering.resize(mNumNodesPerElement);
00081     for (unsigned i=0; i<mNumNodesPerElement; i++)
00082     {
00083         mReordering[i] = i;
00084     }
00085 }
00086 
00087 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00088 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::WriteFiles()
00089 {
00091     // Write the exnode file
00093     out_stream p_node_file = OpenNodeFile();
00094     WriteNodeFileHeader(p_node_file);
00095 
00096     // Write each node's data
00097     for (unsigned item_num=0; item_num<this->GetNumNodes(); item_num++)
00098     {
00099         std::vector<double> current_item = this->GetNextNode();
00100 
00101         *p_node_file << "Node:\t" << item_num+1 << "\t";
00102         for (unsigned i=0; i<ELEMENT_DIM; i++)
00103         {
00104             *p_node_file << current_item[i] << "\t";
00105         }
00106 
00107         *p_node_file << "\n";
00108     }
00109     p_node_file->close();
00110 
00112     // Write the exlem file
00114 
00115     std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles();
00116     WriteElementsFileHeader(elem_files);
00117 
00118     // Write each elements's data
00119     for (unsigned item_num=0; item_num<this->GetNumElements(); item_num++)
00120     {
00121         ElementData elem =this->GetNextElement();
00122         std::vector<unsigned> current_element = elem.NodeIndices;
00123 
00125         assert(elem.AttributeValue < mRegionNames.size());
00126 
00127         *elem_files[elem.AttributeValue] << "Element:\t" << item_num+1 << " 0 0 Nodes:\t";
00128         for (unsigned i=0; i<mNumNodesPerElement; i++)
00129         {
00130             *elem_files[elem.AttributeValue] << current_element[mReordering[i]]+1 << "\t";
00131         }
00132 
00133         *elem_files[elem.AttributeValue] << "\n";
00134 
00135     }
00136 
00137     for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
00138     {
00139         elem_files[region_index]->close();
00140     }
00141 }
00142 
00143 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00144 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::SetAdditionalFieldNames(std::vector<std::string>& rFieldNames)
00145 {
00146     mAdditionalFieldNames = rFieldNames;
00147 }
00148 
00149 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00150 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::SetRegionNames(std::vector<std::string>& rRegionNames)
00151 {
00152     mRegionNames = rRegionNames;
00153 }
00154 
00155 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00156 out_stream CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::OpenNodeFile(bool append)
00157 {
00158     std::string node_file_name = this->mBaseName + ".exnode";
00159     return this->mpOutputFileHandler->OpenOutputFile(node_file_name, GetOpenMode(append));
00160 }
00161 
00162 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00163 std::vector<boost::shared_ptr<std::ofstream> > CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::OpenElementFiles(bool append)
00164 {
00165 
00166     std::vector<boost::shared_ptr<std::ofstream> > elem_files;
00167     // If nobody defined region names we default to the same name as the file name.
00168     if (mRegionNames.size() == 0)
00169     {
00170        mRegionNames.push_back(this->mBaseName);
00171     }
00172     elem_files.resize(mRegionNames.size());
00173 
00174     std::string directory = this->mpOutputFileHandler->GetOutputDirectoryFullPath();
00175     for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
00176     {
00177         std::string elem_file_name = mRegionNames[region_index] + ".exelem";
00178 
00179         boost::shared_ptr<std::ofstream> p_output_file(new std::ofstream((directory+elem_file_name).c_str(), GetOpenMode(append)));
00180 #define COVERAGE_IGNORE
00181         if (!p_output_file->is_open())
00182         {
00183             EXCEPTION("Could not open file \"" + elem_file_name + "\" in " + directory);
00184         }
00185 #undef COVERAGE_IGNORE
00186 
00187         // NOTE THAT one could simply do:
00188         //
00189         // elem_files[region_index]  = this->mpOutputFileHandler->OpenOutputFile(elem_file_name, GetOpenMode(append));
00190         //
00191         // but that implies automatic conversion between std::auto_ptr to boost::shared_ptr.
00192         // That is OK with most compilers, but the combination of gcc 4.1 and boost 1.33 complains about that
00193         elem_files[region_index]  = p_output_file;
00194     }
00195     return elem_files;
00196 }
00197 
00198 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00199 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::WriteNodeFileHeader(out_stream& rpNodeFile)
00200 {
00201     // Write provenance info
00202     std::string comment = "! " + ChasteBuildInfo::GetProvenanceString();
00203     *rpNodeFile << comment;
00204 
00205     // Write the node header
00206     *rpNodeFile << "Group name: " << this->mGroupName << "\n";
00207     switch (SPACE_DIM)
00208     {
00209         case 1:
00210         {
00211             *rpNodeFile << CmguiNodeFileHeader1D;
00212             break;
00213         }
00214         case 2:
00215         {
00216             *rpNodeFile << CmguiNodeFileHeader2D;
00217             break;
00218         }
00219         case 3:
00220         {
00221             *rpNodeFile << CmguiNodeFileHeader3D;
00222             break;
00223         }
00224         default:
00225         {
00226             NEVER_REACHED;
00227         }
00228     }
00229 }
00230 
00231 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00232 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::WriteElementsFileHeader(std::vector<boost::shared_ptr<std::ofstream> >& rElemFiles)
00233 {
00234 
00235        for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
00236        {
00237            // Write the elem header
00238 
00239            //write provenance info
00240            std::string comment = "! " + ChasteBuildInfo::GetProvenanceString();
00241            *rElemFiles[region_index] << comment;
00242 
00243            *rElemFiles[region_index] << "Group name: " << mGroupName << "\n";
00244            *rElemFiles[region_index] << mElementFileHeader;
00245 
00246            // Now we need to figure out how many additional fields we have
00247            unsigned number_of_fields = mAdditionalFieldNames.size();
00248            std::stringstream string_of_number_of_fields;
00249 
00250            // We write the number of additional fields + 1 because the coordinates field gets written anyway...
00251            string_of_number_of_fields << number_of_fields+1;
00252 
00253            // ...and write accordingly the total number of fields
00254            *rElemFiles[region_index] << " #Fields="<<string_of_number_of_fields.str()<<"\n";
00255 
00256            // First field (the coordinates field is fixed and alwys there)
00257            *rElemFiles[region_index] << mCoordinatesFileHeader;
00258 
00259            // Now write the specification for each additional field
00260            for (unsigned i = 0; i <  number_of_fields; i++)
00261            {
00262                //unsigned to string
00263                std::stringstream i_string;
00264                i_string << i+2;
00265                *rElemFiles[region_index]<<i_string.str()<<")  "<<mAdditionalFieldNames[i]<<" ,";
00266                *rElemFiles[region_index] << mAdditionalFieldHeader;
00267            }
00268        }
00269 }
00270 
00271 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00272 void CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::CreateFilesWithHeaders()
00273 {
00274     /*
00275      *  Node file
00276      */
00277     out_stream p_node_file = OpenNodeFile();
00278     WriteNodeFileHeader(p_node_file);
00279     p_node_file->close();
00280 
00281     /*
00282      *  Element files
00283      */
00284      // Array with file descriptors for each of regions
00285      std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles();
00286      WriteElementsFileHeader(elem_files);
00287      for (unsigned i = 0; i < elem_files.size(); i++)
00288      {
00289          elem_files[i]->close();
00290      }
00291 }
00292 
00293 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00294 void CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::AppendLocalDataToFiles()
00295 {
00296     //Nodes first
00297     out_stream p_node_file = OpenNodeFile(true);
00298 
00299     typedef typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator NodeIterType;
00300 
00301     for (NodeIterType iter = this->mpDistributedMesh->GetNodeIteratorBegin();
00302          iter != this->mpDistributedMesh->GetNodeIteratorEnd();
00303          ++iter)
00304     {
00305         const c_vector<double, SPACE_DIM>& r_current_item = iter->rGetLocation();
00306         *p_node_file << "Node:\t" << iter->GetIndex()+1 << "\t";
00307         for (unsigned i=0; i<ELEMENT_DIM; i++)
00308         {
00309             *p_node_file << r_current_item[i] << "\t";
00310         }
00311 
00312         *p_node_file << "\n";
00313     }
00314     p_node_file->close();
00315 
00316     //Now Element files
00317 
00318     std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles(true);
00319     typedef typename AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>::ElementIterator ElemIterType;
00320 
00321     for (ElemIterType iter = this->mpDistributedMesh->GetElementIteratorBegin();
00322          iter != this->mpDistributedMesh->GetElementIteratorEnd();
00323          ++iter)
00324     {
00325         if ( this->mpDistributedMesh->CalculateDesignatedOwnershipOfElement(iter->GetIndex()))
00326         {
00327             assert(iter->GetRegion() < mRegionNames.size());//segfault guard
00328 
00329             *elem_files[iter->GetRegion()] << "Element:\t" << iter->GetIndex()+1 << " 0 0 Nodes:\t";
00330             for (unsigned i=0; i<this->mNodesPerElement; i++)
00331             {
00332                 *elem_files[iter->GetRegion()]  << iter->GetNodeGlobalIndex(i)+1 << "\t";
00333             }
00334 
00335             *elem_files[iter->GetRegion()] << "\n";
00336         }
00337     }
00338 
00339     for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
00340     {
00341         elem_files[region_index]->close();
00342     }
00343 
00344 }
00345 
00346 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00347 void CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::WriteFilesFooter()
00348 {
00349     //No need of footers here, but void implementation is needed
00350 }
00351 
00352 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00353 std::ios_base::openmode CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::GetOpenMode(bool append)
00354 {
00355     std::ios_base::openmode mode = std::ios::out;
00356     if (append)
00357     {
00358         mode |= std::ios::app; // Note: bitwise OR operation
00359     }
00360     else
00361     {
00362         mode |= std::ios::trunc;
00363     }
00364     return mode;
00365 }
00366 
00367 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00368 bool CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::CompareCmguiFiles(std::string& rPath1, std::string& rPath2)
00369 {
00370     std::string compare_command = "diff --ignore-matching-lines=\"! \" ";
00371     compare_command += rPath1;
00372     compare_command += " ";
00373     compare_command += rPath2;
00374 
00375     // Compare the new test file with one from the repository
00376     if (system(compare_command.c_str()) == 0)
00377     {
00378         return true;
00379     }
00380     else
00381     {
00382         return false;
00383     }
00384 }
00385 
00387 // Explicit instantiation
00389 
00390 template class CmguiMeshWriter<1,1>;
00391 template class CmguiMeshWriter<1,2>;
00392 template class CmguiMeshWriter<1,3>;
00393 template class CmguiMeshWriter<2,2>;
00394 template class CmguiMeshWriter<2,3>;
00395 template class CmguiMeshWriter<3,3>;
Generated on Thu Dec 22 13:00:16 2011 for Chaste by  doxygen 1.6.3