VertexMeshWriter.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 
00036 #include "VertexMeshWriter.hpp"
00037 #include "Version.hpp"
00038 #include "Cylindrical2dVertexMesh.hpp"
00039 #include "Toroidal2dVertexMesh.hpp"
00040 
00044 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00045 struct MeshWriterIterators
00046 {
00048     typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator* pNodeIter;
00050     typename VertexMesh<ELEMENT_DIM,SPACE_DIM>::VertexElementIterator* pElemIter;
00051 };
00052 
00054 // Implementation
00056 
00057 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00058 VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::VertexMeshWriter(const std::string& rDirectory,
00059                                                            const std::string& rBaseName,
00060                                                            const bool clearOutputDir)
00061     : AbstractMeshWriter<ELEMENT_DIM, SPACE_DIM>(rDirectory, rBaseName, clearOutputDir),
00062       mpMesh(NULL),
00063       mpIters(new MeshWriterIterators<ELEMENT_DIM, SPACE_DIM>),
00064       mpNodeMap(NULL),
00065       mNodeMapCurrentIndex(0)
00066 {
00067     mpIters->pNodeIter = NULL;
00068     mpIters->pElemIter = NULL;
00069 
00070 #ifdef CHASTE_VTK
00071      // Dubious, since we shouldn't yet know what any details of the mesh are.
00072      mpVtkUnstructedMesh = vtkUnstructuredGrid::New();
00073 #endif //CHASTE_VTK
00074 }
00075 
00076 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00077 VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::~VertexMeshWriter()
00078 {
00079     if (mpIters->pNodeIter)
00080     {
00081         delete mpIters->pNodeIter;
00082         delete mpIters->pElemIter;
00083     }
00084 
00085     delete mpIters;
00086 
00087     if (mpNodeMap)
00088     {
00089         delete mpNodeMap;
00090     }
00091 
00092 #ifdef CHASTE_VTK
00093      // Dubious, since we shouldn't yet know what any details of the mesh are.
00094      mpVtkUnstructedMesh->Delete(); // Reference counted
00095 #endif //CHASTE_VTK
00096 }
00097 
00098 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00099 std::vector<double> VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::GetNextNode()
00100 {
00101     if (mpMesh)
00102     {
00103         // Sanity check
00104         assert(this->mNumNodes == mpMesh->GetNumNodes());
00105 
00106         std::vector<double> coordinates(SPACE_DIM+1);
00107 
00108         // Get the node coordinates using the node iterator (thus skipping deleted nodes)
00109         for (unsigned j=0; j<SPACE_DIM; j++)
00110         {
00111             coordinates[j] = (*(mpIters->pNodeIter))->GetPoint()[j];
00112         }
00113         coordinates[SPACE_DIM] = (*(mpIters->pNodeIter))->IsBoundaryNode();
00114 
00115         ++(*(mpIters->pNodeIter));
00116 
00117         return coordinates;
00118     }
00119     else
00120     {
00121         return AbstractMeshWriter<ELEMENT_DIM,SPACE_DIM>::GetNextNode();
00122     }
00123 }
00124 
00125 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00126 VertexElementData VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::GetNextElementWithFaces()
00127 {
00128     // This method should only be called in 3D
00129     assert(SPACE_DIM == 3);
00130     assert(mpMesh);
00131     assert(this->mNumElements == mpMesh->GetNumElements());
00132 
00133     // Create data structure for this element
00134     VertexElementData elem_data;
00135 
00136     // Store node indices owned by this element
00137     elem_data.NodeIndices.resize((*(mpIters->pElemIter))->GetNumNodes());
00138     for (unsigned j=0; j<elem_data.NodeIndices.size(); j++)
00139     {
00140         unsigned old_index = (*(mpIters->pElemIter))->GetNodeGlobalIndex(j);
00141         elem_data.NodeIndices[j] = mpMesh->IsMeshChanging() ? mpNodeMap->GetNewIndex(old_index) : old_index;
00142     }
00143 
00144     // Store faces owned by this element
00145     elem_data.Faces.resize((*(mpIters->pElemIter))->GetNumFaces());
00146     for (unsigned i=0; i<elem_data.Faces.size(); i++)
00147     {
00148         // Get pointer to this face
00149         VertexElement<ELEMENT_DIM-1, SPACE_DIM>* p_face = (*(mpIters->pElemIter))->GetFace(i);
00150 
00151         // Create data structure for this face
00152         ElementData face_data;
00153 
00154         // Store this face's index
00155         face_data.AttributeValue = p_face->GetIndex();
00156 
00157         // Store node indices owned by this face
00158         face_data.NodeIndices.resize(p_face->GetNumNodes());
00159         for (unsigned j=0; j<face_data.NodeIndices.size(); j++)
00160         {
00161             unsigned old_index = p_face->GetNodeGlobalIndex(j);
00162             face_data.NodeIndices[j] = mpMesh->IsMeshChanging() ? mpNodeMap->GetNewIndex(old_index) : old_index;
00163         }
00164 
00165         // Store this face
00166         elem_data.Faces[i] = face_data;
00167 
00169     }
00170 
00171     // Set attribute
00172     elem_data.AttributeValue = (unsigned)(*(mpIters->pElemIter))->GetAttribute();
00173     ++(*(mpIters->pElemIter));
00174 
00175     return elem_data;
00176 }
00177 
00178 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00179 ElementData VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::GetNextElement()
00180 {
00182 
00183     if (mpMesh)
00184     {
00185         assert(this->mNumElements == mpMesh->GetNumElements());
00186 
00187         ElementData elem_data;
00188         elem_data.NodeIndices.resize((*(mpIters->pElemIter))->GetNumNodes());
00189         for (unsigned j=0; j<elem_data.NodeIndices.size(); j++)
00190         {
00191             unsigned old_index = (*(mpIters->pElemIter))->GetNodeGlobalIndex(j);
00192             elem_data.NodeIndices[j] = mpMesh->IsMeshChanging() ? mpNodeMap->GetNewIndex(old_index) : old_index;
00193         }
00194 
00195         // Set attribute
00196         elem_data.AttributeValue = (*(mpIters->pElemIter))->GetAttribute();
00197         ++(*(mpIters->pElemIter));
00198 
00199         return elem_data;
00200     }
00201     else
00202     {
00203         return AbstractMeshWriter<ELEMENT_DIM, SPACE_DIM>::GetNextElement();
00204     }
00205 }
00206 
00207 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00208 void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::WriteVtkUsingMesh(VertexMesh<ELEMENT_DIM, SPACE_DIM>& rMesh, std::string stamp)
00209 {
00210 #ifdef CHASTE_VTK
00211     assert(SPACE_DIM==3 || SPACE_DIM == 2);
00212 
00213     // Create VTK mesh
00214     MakeVtkMesh(rMesh);
00215 
00216     // Now write VTK mesh to file
00217     assert(mpVtkUnstructedMesh->CheckAttributes() == 0);
00218     vtkXMLUnstructuredGridWriter* p_writer = vtkXMLUnstructuredGridWriter::New();
00219 #if VTK_MAJOR_VERSION >= 6
00220     p_writer->SetInputData(mpVtkUnstructedMesh);
00221 #else
00222     p_writer->SetInput(mpVtkUnstructedMesh);
00223 #endif
00224     // Uninitialised stuff arises (see #1079), but you can remove valgrind problems by removing compression:
00225     // **** REMOVE WITH CAUTION *****
00226     p_writer->SetCompressor(NULL);
00227     // **** REMOVE WITH CAUTION *****
00228 
00229     std::string vtk_file_name = this->mpOutputFileHandler->GetOutputDirectoryFullPath() + this->mBaseName;
00230     if (stamp != "")
00231     {
00232         vtk_file_name += "_" + stamp;
00233     }
00234     vtk_file_name += ".vtu";
00235 
00236     p_writer->SetFileName(vtk_file_name.c_str());
00237     //p_writer->PrintSelf(std::cout, vtkIndent());
00238     p_writer->Write();
00239     p_writer->Delete(); // Reference counted
00240 #endif //CHASTE_VTK
00241 }
00242 
00249 template<>
00250 void VertexMeshWriter<2, 2>::WriteVtkUsingMesh(VertexMesh<2, 2>& rMesh, std::string stamp)
00251 {
00252 #ifdef CHASTE_VTK
00253     // Create VTK mesh
00254     if (dynamic_cast<Toroidal2dVertexMesh*>(&rMesh))
00255     {
00256         MutableVertexMesh<2, 2>* p_mesh_for_vtk = static_cast<Toroidal2dVertexMesh*>(&rMesh)->GetMeshForVtk();
00257         MakeVtkMesh(*p_mesh_for_vtk);
00258 
00259         // Avoid memory leak
00260         delete p_mesh_for_vtk;
00261     }
00262     else if (dynamic_cast<Cylindrical2dVertexMesh*>(&rMesh))
00263     {
00264         MutableVertexMesh<2, 2>* p_mesh_for_vtk = static_cast<Cylindrical2dVertexMesh*>(&rMesh)->GetMeshForVtk();
00265         MakeVtkMesh(*p_mesh_for_vtk);
00266 
00267         // Avoid memory leak
00268         delete p_mesh_for_vtk;
00269     }
00270     else
00271     {
00272         MakeVtkMesh(rMesh);
00273     }
00274 
00275     // Now write VTK mesh to file
00276     assert(mpVtkUnstructedMesh->CheckAttributes() == 0);
00277     vtkXMLUnstructuredGridWriter* p_writer = vtkXMLUnstructuredGridWriter::New();
00278 #if VTK_MAJOR_VERSION >= 6
00279     p_writer->SetInputData(mpVtkUnstructedMesh);
00280 #else
00281     p_writer->SetInput(mpVtkUnstructedMesh);
00282 #endif
00283     // Uninitialised stuff arises (see #1079), but you can remove valgrind problems by removing compression:
00284     // **** REMOVE WITH CAUTION *****
00285     p_writer->SetCompressor(NULL);
00286     // **** REMOVE WITH CAUTION *****
00287 
00288     std::string vtk_file_name = this->mpOutputFileHandler->GetOutputDirectoryFullPath() + this->mBaseName;
00289     if (stamp != "")
00290     {
00291         vtk_file_name += "_" + stamp;
00292     }
00293     vtk_file_name += ".vtu";
00294 
00295     p_writer->SetFileName(vtk_file_name.c_str());
00296     //p_writer->PrintSelf(std::cout, vtkIndent());
00297     p_writer->Write();
00298     p_writer->Delete(); // Reference counted
00299 #endif //CHASTE_VTK
00300 }
00301 
00302 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00303 void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::MakeVtkMesh(VertexMesh<ELEMENT_DIM, SPACE_DIM>& rMesh)
00304 {
00305 #ifdef CHASTE_VTK
00306     // Make the Vtk mesh
00307     vtkPoints* p_pts = vtkPoints::New(VTK_DOUBLE);
00308     p_pts->GetData()->SetName("Vertex positions");
00309     for (unsigned node_num=0; node_num<rMesh.GetNumNodes(); node_num++)
00310     {
00311         c_vector<double, SPACE_DIM> position = rMesh.GetNode(node_num)->rGetLocation();
00312         if (SPACE_DIM==2)
00313         {
00314             p_pts->InsertPoint(node_num, position[0], position[1], 0.0);
00315         }
00316         else
00317         {
00318             p_pts->InsertPoint(node_num, position[0], position[1], position[2]);
00319         }
00320     }
00321 
00322     mpVtkUnstructedMesh->SetPoints(p_pts);
00323     p_pts->Delete(); // Reference counted
00324     for (typename VertexMesh<ELEMENT_DIM,SPACE_DIM>::VertexElementIterator iter = rMesh.GetElementIteratorBegin();
00325          iter != rMesh.GetElementIteratorEnd();
00326          ++iter)
00327     {
00328         vtkCell* p_cell;
00329         if (SPACE_DIM == 2)
00330         {
00331             p_cell = vtkPolygon::New();
00332         }
00333         else
00334         {
00335             p_cell = vtkConvexPointSet::New();
00336         }
00337         vtkIdList* p_cell_id_list = p_cell->GetPointIds();
00338         p_cell_id_list->SetNumberOfIds(iter->GetNumNodes());
00339         for (unsigned j=0; j<iter->GetNumNodes(); ++j)
00340         {
00341             p_cell_id_list->SetId(j, iter->GetNodeGlobalIndex(j));
00342         }
00343         mpVtkUnstructedMesh->InsertNextCell(p_cell->GetCellType(), p_cell_id_list);
00344         p_cell->Delete(); // Reference counted
00345     }
00346 #endif //CHASTE_VTK
00347 }
00348 
00349 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00350 void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::AddCellData(std::string dataName, std::vector<double> dataPayload)
00351 {
00352 #ifdef CHASTE_VTK
00353     vtkDoubleArray* p_scalars = vtkDoubleArray::New();
00354     p_scalars->SetName(dataName.c_str());
00355     for (unsigned i=0; i<dataPayload.size(); i++)
00356     {
00357         p_scalars->InsertNextValue(dataPayload[i]);
00358     }
00359 
00360     vtkCellData* p_cell_data = mpVtkUnstructedMesh->GetCellData();
00361     p_cell_data->AddArray(p_scalars);
00362     p_scalars->Delete(); // Reference counted
00363 #endif //CHASTE_VTK
00364 }
00365 
00366 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00367 void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::AddPointData(std::string dataName, std::vector<double> dataPayload)
00368 {
00369 #ifdef CHASTE_VTK
00370     vtkDoubleArray* p_scalars = vtkDoubleArray::New();
00371     p_scalars->SetName(dataName.c_str());
00372     for (unsigned i=0; i<dataPayload.size(); i++)
00373     {
00374         p_scalars->InsertNextValue(dataPayload[i]);
00375     }
00376 
00377     vtkPointData* p_point_data = mpVtkUnstructedMesh->GetPointData();
00378     p_point_data->AddArray(p_scalars);
00379     p_scalars->Delete(); // Reference counted
00380 #endif //CHASTE_VTK
00381 }
00382 
00384 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00385 void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::WriteFilesUsingMesh(VertexMesh<ELEMENT_DIM,SPACE_DIM>& rMesh)
00386 {
00387     this->mpMeshReader = NULL;
00388     mpMesh = &rMesh;
00389 
00390     this->mNumNodes = mpMesh->GetNumNodes();
00391     this->mNumElements = mpMesh->GetNumElements();
00392 
00393     typedef typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator NodeIterType;
00394     mpIters->pNodeIter = new NodeIterType(mpMesh->GetNodeIteratorBegin());
00395 
00396     typedef typename VertexMesh<ELEMENT_DIM,SPACE_DIM>::VertexElementIterator ElemIterType;
00397     mpIters->pElemIter = new ElemIterType(mpMesh->GetElementIteratorBegin());
00398 
00399     // Set up node map if we might have deleted nodes
00400     mNodeMapCurrentIndex = 0;
00401     if (mpMesh->IsMeshChanging())
00402     {
00403         mpNodeMap = new NodeMap(mpMesh->GetNumAllNodes());
00404         for (NodeIterType it = mpMesh->GetNodeIteratorBegin(); it != mpMesh->GetNodeIteratorEnd(); ++it)
00405         {
00406             mpNodeMap->SetNewIndex(it->GetIndex(), mNodeMapCurrentIndex++);
00407         }
00408     }
00409     WriteFiles();
00410 }
00411 
00412 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00413 void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::WriteFiles()
00414 {
00415     std::string comment = "# " + ChasteBuildInfo::GetProvenanceString();
00416 
00417     // Write node file
00418     std::string node_file_name = this->mBaseName + ".node";
00419     out_stream p_node_file = this->mpOutputFileHandler->OpenOutputFile(node_file_name);
00420 
00421     // Write the node header
00422     unsigned num_attr = 0;
00423     unsigned max_bdy_marker = 1; // as we include boundary node information in the node file
00424     unsigned num_nodes = this->GetNumNodes();
00425 
00426     *p_node_file << num_nodes << "\t";
00427     *p_node_file << SPACE_DIM << "\t";
00428     *p_node_file << num_attr << "\t";
00429     *p_node_file << max_bdy_marker << "\n";
00430     *p_node_file << std::setprecision(6);
00431 
00432     // Write each node's data
00433     for (unsigned item_num=0; item_num<num_nodes; item_num++)
00434     {
00435         std::vector<double> current_item = this->GetNextNode();
00436         *p_node_file << item_num;
00437         for (unsigned i=0; i<SPACE_DIM+1; i++)
00438         {
00439             *p_node_file << "\t" << current_item[i];
00440         }
00441         *p_node_file << "\n";
00442     }
00443     *p_node_file << comment << "\n";
00444     p_node_file->close();
00445 
00446     // Write element file
00447     std::string element_file_name = this->mBaseName + ".cell";
00448     out_stream p_element_file = this->mpOutputFileHandler->OpenOutputFile(element_file_name);
00449 
00450     // Write the element header
00451     num_attr = 1; //Always write element attributes
00452     unsigned num_elements = this->GetNumElements();
00453     *p_element_file << num_elements << "\t" << num_attr << "\n";
00454 
00455     // Write each element's data
00456     for (unsigned item_num=0; item_num<num_elements; item_num++)
00457     {
00458         if (SPACE_DIM == 2) // In 2D, write the node indices owned by this element
00459         {
00460             // Get data for this element
00461             ElementData elem_data = this->GetNextElement();
00462 
00463             // Get the node indices owned by this element
00464             std::vector<unsigned> node_indices = elem_data.NodeIndices;
00465 
00466             // Write this element's index and the number of nodes owned by it to file
00467             *p_element_file << item_num <<  "\t" << node_indices.size();
00468 
00469             // Write the node indices owned by this element to file
00470             for (unsigned i=0; i<node_indices.size(); i++)
00471             {
00472                 *p_element_file << "\t" << node_indices[i];
00473             }
00474 
00475             *p_element_file << "\t" << elem_data.AttributeValue;
00476 
00477             // New line
00478             *p_element_file << "\n";
00479         }
00480         else // 3D
00481         {
00482             assert(SPACE_DIM == 3);
00483 
00484             // Get data for this element
00485             VertexElementData elem_data_with_faces = this->GetNextElementWithFaces();
00486 
00487             // Get the node indices owned by this element
00488             std::vector<unsigned> node_indices = elem_data_with_faces.NodeIndices;
00489 
00490             // Write this element's index and the number of nodes owned by it to file
00491             *p_element_file << item_num <<  "\t" << node_indices.size();
00492 
00493             // Write the node indices owned by this element to file
00494             for (unsigned i=0; i<node_indices.size(); i++)
00495             {
00496                 *p_element_file << "\t" << node_indices[i];
00497             }
00498 
00499             // Get the faces owned by this element (if any)
00500             std::vector<ElementData> faces = elem_data_with_faces.Faces;
00501 
00502             // Write the number of faces owned by this element to file
00503             *p_element_file << "\t" << faces.size();
00504 
00505             for (unsigned j=0; j<faces.size(); j++)
00506             {
00507                 // Get the node indices owned by this face
00508                 std::vector<unsigned> face_node_indices = faces[j].NodeIndices;
00509 
00510                 // Write this face's index and the number of nodes owned by it to file
00511                 *p_element_file << "\t" << faces[j].AttributeValue <<  "\t" << face_node_indices.size();
00512 
00513                 // Write the node indices owned by this element to file
00514                 for (unsigned i=0; i<face_node_indices.size(); i++)
00515                 {
00516                     *p_element_file << "\t" << face_node_indices[i];
00517                 }
00518 
00520             }
00521 
00522             *p_element_file << "\t" << elem_data_with_faces.AttributeValue;
00523 
00524             // New line
00525             *p_element_file << "\n";
00526         }
00527     }
00528 
00529     *p_element_file << comment << "\n";
00530     p_element_file->close();
00531 }
00532 
00534 // Explicit instantiation
00536 
00537 template class VertexMeshWriter<1,1>;
00538 template class VertexMeshWriter<1,2>;
00539 template class VertexMeshWriter<1,3>;
00540 template class VertexMeshWriter<2,2>;
00541 template class VertexMeshWriter<2,3>;
00542 template class VertexMeshWriter<3,3>;

Generated by  doxygen 1.6.2