Chaste Release::3.1
CmguiMeshWriter.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 #include "Exception.hpp"
00036 #include "CmguiMeshWriter.hpp"
00037 #include "Version.hpp"
00038 #include <boost/shared_ptr.hpp>
00039 
00040 #include "AbstractTetrahedralMesh.hpp"
00041 #include "DistributedTetrahedralMesh.hpp"
00042 
00044 // Implementation
00046 
00047 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00048 CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::CmguiMeshWriter(const std::string &rDirectory,
00049                                                         const std::string &rBaseName,
00050                                                         bool cleanDirectory)
00051         : AbstractTetrahedralMeshWriter<ELEMENT_DIM,SPACE_DIM>(rDirectory, rBaseName, cleanDirectory)
00052 {
00053     this->mIndexFromZero = false;
00054     mGroupName = this->mBaseName;
00055 
00056     switch (ELEMENT_DIM)
00057     {
00058         case 1:
00059         {
00060             mElementFileHeader = CmguiElementFileHeader1D;
00061             mCoordinatesFileHeader = CmguiCoordinatesFileHeader1D;
00062             mAdditionalFieldHeader = CmguiAdditionalFieldHeader1D;
00063             break;
00064         }
00065         case 2:
00066         {
00067             mElementFileHeader = CmguiElementFileHeader2D;
00068             mCoordinatesFileHeader = CmguiCoordinatesFileHeader2D;
00069             mAdditionalFieldHeader = CmguiAdditionalFieldHeader2D;
00070             break;
00071         }
00072         case 3:
00073         {
00074             mElementFileHeader = CmguiElementFileHeader3D;
00075             mCoordinatesFileHeader = CmguiCoordinatesFileHeader3D;
00076             mAdditionalFieldHeader = CmguiAdditionalFieldHeader3D;
00077             break;
00078         }
00079         default:
00080         {
00081             NEVER_REACHED;
00082         }
00083     }
00084 
00085 
00086     mNumNodesPerElement = ELEMENT_DIM+1;
00087     mReordering.resize(mNumNodesPerElement);
00088     for (unsigned i=0; i<mNumNodesPerElement; i++)
00089     {
00090         mReordering[i] = i;
00091     }
00092 }
00093 
00094 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00095 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::WriteFiles()
00096 {
00098     // Write the exnode file
00100     out_stream p_node_file = OpenNodeFile();
00101     WriteNodeFileHeader(p_node_file);
00102 
00103     // Write each node's data
00104     for (unsigned item_num=0; item_num<this->GetNumNodes(); item_num++)
00105     {
00106         std::vector<double> current_item = this->GetNextNode();
00107 
00108         *p_node_file << "Node:\t" << item_num+1 << "\t";
00109         for (unsigned i=0; i<ELEMENT_DIM; i++)
00110         {
00111             *p_node_file << current_item[i] << "\t";
00112         }
00113 
00114         *p_node_file << "\n";
00115     }
00116     p_node_file->close();
00117 
00119     // Write the exlem file
00121 
00122     std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles();
00123     WriteElementsFileHeader(elem_files);
00124 
00125     // Write each elements's data
00126     for (unsigned item_num=0; item_num<this->GetNumElements(); item_num++)
00127     {
00128         ElementData elem =this->GetNextElement();
00129         std::vector<unsigned> current_element = elem.NodeIndices;
00130 
00132         assert(elem.AttributeValue < mRegionNames.size());
00133 
00134         *elem_files[elem.AttributeValue] << "Element:\t" << item_num+1 << " 0 0 Nodes:\t";
00135         for (unsigned i=0; i<mNumNodesPerElement; i++)
00136         {
00137             *elem_files[elem.AttributeValue] << current_element[mReordering[i]]+1 << "\t";
00138         }
00139 
00140         *elem_files[elem.AttributeValue] << "\n";
00141 
00142     }
00143 
00144     for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
00145     {
00146         elem_files[region_index]->close();
00147     }
00148 }
00149 
00150 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00151 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::SetAdditionalFieldNames(std::vector<std::string>& rFieldNames)
00152 {
00153     mAdditionalFieldNames = rFieldNames;
00154 }
00155 
00156 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00157 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::SetRegionNames(std::vector<std::string>& rRegionNames)
00158 {
00159     mRegionNames = rRegionNames;
00160 }
00161 
00162 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00163 out_stream CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::OpenNodeFile(bool append)
00164 {
00165     std::string node_file_name = this->mBaseName + ".exnode";
00166     return this->mpOutputFileHandler->OpenOutputFile(node_file_name, GetOpenMode(append));
00167 }
00168 
00169 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00170 std::vector<boost::shared_ptr<std::ofstream> > CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::OpenElementFiles(bool append)
00171 {
00172 
00173     std::vector<boost::shared_ptr<std::ofstream> > elem_files;
00174     // If nobody defined region names we default to the same name as the file name.
00175     if (mRegionNames.size() == 0)
00176     {
00177        mRegionNames.push_back(this->mBaseName);
00178     }
00179     elem_files.resize(mRegionNames.size());
00180 
00181     std::string directory = this->mpOutputFileHandler->GetOutputDirectoryFullPath();
00182     for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
00183     {
00184         std::string elem_file_name = mRegionNames[region_index] + ".exelem";
00185 
00186         boost::shared_ptr<std::ofstream> p_output_file(new std::ofstream((directory+elem_file_name).c_str(), GetOpenMode(append)));
00187 #define COVERAGE_IGNORE
00188         if (!p_output_file->is_open())
00189         {
00190             EXCEPTION("Could not open file \"" + elem_file_name + "\" in " + directory);
00191         }
00192 #undef COVERAGE_IGNORE
00193 
00194         // NOTE THAT one could simply do:
00195         //
00196         // elem_files[region_index]  = this->mpOutputFileHandler->OpenOutputFile(elem_file_name, GetOpenMode(append));
00197         //
00198         // but that implies automatic conversion between std::auto_ptr to boost::shared_ptr.
00199         // That is OK with most compilers, but the combination of gcc 4.1 and boost 1.33 complains about that
00200         elem_files[region_index]  = p_output_file;
00201     }
00202     return elem_files;
00203 }
00204 
00205 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00206 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::WriteNodeFileHeader(out_stream& rpNodeFile)
00207 {
00208     // Write provenance info
00209     std::string comment = "! " + ChasteBuildInfo::GetProvenanceString();
00210     *rpNodeFile << comment;
00211 
00212     // Write the node header
00213     *rpNodeFile << "Group name: " << this->mGroupName << "\n";
00214     switch (SPACE_DIM)
00215     {
00216         case 1:
00217         {
00218             *rpNodeFile << CmguiNodeFileHeader1D;
00219             break;
00220         }
00221         case 2:
00222         {
00223             *rpNodeFile << CmguiNodeFileHeader2D;
00224             break;
00225         }
00226         case 3:
00227         {
00228             *rpNodeFile << CmguiNodeFileHeader3D;
00229             break;
00230         }
00231         default:
00232         {
00233             NEVER_REACHED;
00234         }
00235     }
00236 }
00237 
00238 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00239 void CmguiMeshWriter<ELEMENT_DIM,SPACE_DIM>::WriteElementsFileHeader(std::vector<boost::shared_ptr<std::ofstream> >& rElemFiles)
00240 {
00241 
00242        for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
00243        {
00244            // Write the elem header
00245 
00246            //write provenance info
00247            std::string comment = "! " + ChasteBuildInfo::GetProvenanceString();
00248            *rElemFiles[region_index] << comment;
00249 
00250            *rElemFiles[region_index] << "Group name: " << mGroupName << "\n";
00251            *rElemFiles[region_index] << mElementFileHeader;
00252 
00253            // Now we need to figure out how many additional fields we have
00254            unsigned number_of_fields = mAdditionalFieldNames.size();
00255            std::stringstream string_of_number_of_fields;
00256 
00257            // We write the number of additional fields + 1 because the coordinates field gets written anyway...
00258            string_of_number_of_fields << number_of_fields+1;
00259 
00260            // ...and write accordingly the total number of fields
00261            *rElemFiles[region_index] << " #Fields="<<string_of_number_of_fields.str()<<"\n";
00262 
00263            // First field (the coordinates field is fixed and alwys there)
00264            *rElemFiles[region_index] << mCoordinatesFileHeader;
00265 
00266            // Now write the specification for each additional field
00267            for (unsigned i = 0; i <  number_of_fields; i++)
00268            {
00269                //unsigned to string
00270                std::stringstream i_string;
00271                i_string << i+2;
00272                *rElemFiles[region_index]<<i_string.str()<<")  "<<mAdditionalFieldNames[i]<<" ,";
00273                *rElemFiles[region_index] << mAdditionalFieldHeader;
00274            }
00275        }
00276 }
00277 
00278 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00279 void CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::CreateFilesWithHeaders()
00280 {
00281     /*
00282      *  Node file
00283      */
00284     out_stream p_node_file = OpenNodeFile();
00285     WriteNodeFileHeader(p_node_file);
00286     p_node_file->close();
00287 
00288     /*
00289      *  Element files
00290      */
00291      // Array with file descriptors for each of regions
00292      std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles();
00293      WriteElementsFileHeader(elem_files);
00294      for (unsigned i = 0; i < elem_files.size(); i++)
00295      {
00296          elem_files[i]->close();
00297      }
00298 }
00299 
00300 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00301 void CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::AppendLocalDataToFiles()
00302 {
00303     //Nodes first
00304     out_stream p_node_file = OpenNodeFile(true);
00305 
00306     typedef typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator NodeIterType;
00307 
00308     for (NodeIterType iter = this->mpDistributedMesh->GetNodeIteratorBegin();
00309          iter != this->mpDistributedMesh->GetNodeIteratorEnd();
00310          ++iter)
00311     {
00312         const c_vector<double, SPACE_DIM>& r_current_item = iter->rGetLocation();
00313         *p_node_file << "Node:\t" << iter->GetIndex()+1 << "\t";
00314         for (unsigned i=0; i<ELEMENT_DIM; i++)
00315         {
00316             *p_node_file << r_current_item[i] << "\t";
00317         }
00318 
00319         *p_node_file << "\n";
00320     }
00321     p_node_file->close();
00322 
00323     //Now Element files
00324 
00325     std::vector<boost::shared_ptr<std::ofstream> > elem_files = OpenElementFiles(true);
00326     typedef typename AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>::ElementIterator ElemIterType;
00327 
00328     for (ElemIterType iter = this->mpDistributedMesh->GetElementIteratorBegin();
00329          iter != this->mpDistributedMesh->GetElementIteratorEnd();
00330          ++iter)
00331     {
00332         if ( this->mpDistributedMesh->CalculateDesignatedOwnershipOfElement(iter->GetIndex()))
00333         {
00334             assert(iter->GetUnsignedAttribute() < mRegionNames.size());//segfault guard
00335 
00336             *elem_files[iter->GetUnsignedAttribute()] << "Element:\t" << iter->GetIndex()+1 << " 0 0 Nodes:\t";
00337             for (unsigned i=0; i<this->mNodesPerElement; i++)
00338             {
00339                 *elem_files[iter->GetUnsignedAttribute()]  << iter->GetNodeGlobalIndex(i)+1 << "\t";
00340             }
00341 
00342             *elem_files[iter->GetUnsignedAttribute()] << "\n";
00343         }
00344     }
00345 
00346     for (unsigned region_index=0; region_index<mRegionNames.size(); region_index++)
00347     {
00348         elem_files[region_index]->close();
00349     }
00350 
00351 }
00352 
00353 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00354 void CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::WriteFilesFooter()
00355 {
00356     //No need of footers here, but void implementation is needed
00357 }
00358 
00359 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00360 std::ios_base::openmode CmguiMeshWriter<ELEMENT_DIM, SPACE_DIM>::GetOpenMode(bool append)
00361 {
00362     std::ios_base::openmode mode = std::ios::out;
00363     if (append)
00364     {
00365         mode |= std::ios::app; // Note: bitwise OR operation
00366     }
00367     else
00368     {
00369         mode |= std::ios::trunc;
00370     }
00371     return mode;
00372 }
00373 
00375 // Explicit instantiation
00377 
00378 template class CmguiMeshWriter<1,1>;
00379 template class CmguiMeshWriter<1,2>;
00380 template class CmguiMeshWriter<1,3>;
00381 template class CmguiMeshWriter<2,2>;
00382 template class CmguiMeshWriter<2,3>;
00383 template class CmguiMeshWriter<3,3>;