Chaste Release::3.1
AdaptiveTetrahedralMesh.cpp
00001 /*
00002 
00003 Copyright (C) Fujitsu Laboratories of Europe, 2009-2010
00004 
00005 */
00006 
00007 /*
00008 
00009 Copyright (c) 2005-2012, University of Oxford.
00010 All rights reserved.
00011 
00012 University of Oxford means the Chancellor, Masters and Scholars of the
00013 University of Oxford, having an administrative office at Wellington
00014 Square, Oxford OX1 2JD, UK.
00015 
00016 This file is part of Chaste.
00017 
00018 Redistribution and use in source and binary forms, with or without
00019 modification, are permitted provided that the following conditions are met:
00020  * Redistributions of source code must retain the above copyright notice,
00021    this list of conditions and the following disclaimer.
00022  * Redistributions in binary form must reproduce the above copyright notice,
00023    this list of conditions and the following disclaimer in the documentation
00024    and/or other materials provided with the distribution.
00025  * Neither the name of the University of Oxford nor the names of its
00026    contributors may be used to endorse or promote products derived from this
00027    software without specific prior written permission.
00028 
00029 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00030 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00031 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00032 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00033 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00034 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00035 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00036 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00037 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00038 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00039 
00040 */
00041 
00042 
00043 
00044 #ifdef CHASTE_ADAPTIVITY
00045 
00046 #include "AdaptiveTetrahedralMesh.hpp"
00047 #include "HeartConfig.hpp"
00048 #include "OutputFileHandler.hpp"
00049 
00050 AdaptiveTetrahedralMesh::AdaptiveTetrahedralMesh() :
00051     mNumNodes(0),
00052     mNumElements(0),
00053     mNumLocalNodes(0),
00054     mAdaptSuccess(false),
00055     mpDiscreteGeometryConstraints(NULL),
00056     mpErrorMeasure(NULL),
00057     mpAdapt(NULL),
00058     mGoodEdgeRange(0.0),
00059     mBadEdgeCriterion(0.0),
00060     mVerbose(false)
00061 
00062 {
00063         mpVtkUnstructuredGrid = vtkUnstructuredGrid::New();
00064 }
00065 
00066 AdaptiveTetrahedralMesh::~AdaptiveTetrahedralMesh()
00067 {
00068     Reset();//Delete multiple-use pointers
00069     mpVtkUnstructuredGrid->Delete();
00070 }
00071 
00072 void AdaptiveTetrahedralMesh::ConstructFromVtuFile(std::string fileName)
00073 {
00074     vtkXMLUnstructuredGridReader *p_vtk_reader = vtkXMLUnstructuredGridReader::New();
00075     p_vtk_reader->SetFileName(fileName.c_str());
00076     p_vtk_reader->Update();
00077 
00078     mpVtkUnstructuredGrid->DeepCopy(p_vtk_reader->GetOutput());
00079     mpVtkUnstructuredGrid->Update();
00080 
00081     p_vtk_reader->Delete();
00082 
00083     mNumNodes = mpVtkUnstructuredGrid->GetNumberOfPoints();
00084     mNumElements = mpVtkUnstructuredGrid->GetNumberOfCells();
00085     mNumLocalNodes = mNumNodes;       // Since each process has a complete copy of the vtkUnstructuredGrid
00086 }
00087 
00088 void AdaptiveTetrahedralMesh::ConstructFromMesh(AbstractTetrahedralMesh<3,3>* rMesh)
00089 {
00090     vtkPoints *p_pts = vtkPoints::New();
00091     p_pts->SetDataTypeToDouble();
00092     for (unsigned i=0; i<rMesh->GetNumNodes(); i++)
00093     {
00094         p_pts->InsertPoint(i, rMesh->GetNode(i)->rGetLocation().data());
00095     }
00096 
00097     mpVtkUnstructuredGrid->Allocate(rMesh->GetNumNodes(), rMesh->GetNumNodes());
00098     mpVtkUnstructuredGrid->SetPoints(p_pts);
00099     mpVtkUnstructuredGrid->Update();
00100     p_pts->Delete();    // Reference counted
00101 
00102     for (unsigned i=0; i<rMesh->GetNumElements(); i++)
00103     {
00104         vtkTetra *p_tetra = vtkTetra::New();
00105         for (int j = 0; j < 4; ++j)
00106         {
00107             p_tetra->GetPointIds()->SetId(j, rMesh->GetElement(i)->GetNodeGlobalIndex(j));
00108         }
00109         mpVtkUnstructuredGrid->InsertNextCell(p_tetra->GetCellType(), p_tetra->GetPointIds());
00110         mpVtkUnstructuredGrid->Update();
00111         p_tetra->Delete();    // Reference counted
00112     }
00113 
00114     mNumNodes = mpVtkUnstructuredGrid->GetNumberOfPoints();
00115     mNumElements = mpVtkUnstructuredGrid->GetNumberOfCells();
00116     mNumLocalNodes = mNumNodes;       // Since each process has a complete copy of the vtkUnstructuredGrid
00117 }
00118 
00119 void AdaptiveTetrahedralMesh::ConstructFromDistributedMesh(DistributedTetrahedralMesh<3,3>* rMesh)
00120 {
00121     vtkPoints *p_pts = vtkPoints::New();
00122     p_pts->SetDataTypeToDouble();
00123 
00124     std::vector<unsigned> global_node_numbers, halo_nodes;
00125     std::map<unsigned, unsigned> global_to_local_index_map;
00126 
00127 //    vtkUnsignedIntArray *p_scalars = vtkUnsignedIntArray::New();
00128 //    p_scalars->SetName("GlobalNodeNumbers");
00129 
00130     unsigned index = 0;
00131     for (DistributedTetrahedralMesh<3,3>::NodeIterator it=rMesh->GetNodeIteratorBegin();
00132          it != rMesh->GetNodeIteratorEnd();
00133          ++it)
00134     {
00135         p_pts->InsertPoint(index, it->rGetLocation().data());
00136         global_node_numbers.push_back(it->GetIndex());
00137         global_to_local_index_map[it->GetIndex()] = index;
00138         index++;
00139     }
00140 
00141     rMesh->GetHaloNodeIndices(halo_nodes);
00142     for(unsigned i=0; i<halo_nodes.size(); i++)
00143     {
00144         global_node_numbers.push_back(halo_nodes[i]);
00145         p_pts->InsertPoint(index, rMesh->GetNodeOrHaloNode(halo_nodes[i])->rGetLocation().data());
00146         global_to_local_index_map[halo_nodes[i]] = index;
00147         index++;
00148     }
00149 
00150     AddPointData("GlobalNodeNumbers", global_node_numbers);
00151 
00152     mpVtkUnstructuredGrid->Allocate(global_node_numbers.size(), global_node_numbers.size());
00153     mpVtkUnstructuredGrid->SetPoints(p_pts);
00154     mpVtkUnstructuredGrid->Update();
00155     p_pts->Delete();    // Reference counted
00156 
00157     for (DistributedTetrahedralMesh<3,3>::ElementIterator it=rMesh->GetElementIteratorBegin();
00158          it != rMesh->GetElementIteratorEnd();
00159          ++it)
00160     {
00161         vtkTetra *p_tetra = vtkTetra::New();
00162         for (int j = 0; j < 4; ++j)
00163         {
00164             p_tetra->GetPointIds()->SetId(j, global_to_local_index_map[it->GetNodeGlobalIndex(j)]);
00165         }
00166         mpVtkUnstructuredGrid->InsertNextCell(p_tetra->GetCellType(), p_tetra->GetPointIds());
00167         mpVtkUnstructuredGrid->Update();
00168         p_tetra->Delete();    // Reference counted
00169     }
00170 
00171     mNumNodes = rMesh->GetNumNodes();
00172     mNumElements = rMesh->GetNumElements();
00173     mNumLocalNodes = mpVtkUnstructuredGrid->GetNumberOfPoints() - halo_nodes.size();
00174 }
00175 
00176 void AdaptiveTetrahedralMesh::AddPointData(std::string dataName, std::vector<double> dataPayload)
00177 {
00178     vtkDoubleArray *p_scalars = vtkDoubleArray::New();
00179     p_scalars->SetName(dataName.c_str());
00180     for (unsigned i=0; i<dataPayload.size(); i++)
00181     {
00182         p_scalars->InsertNextValue(dataPayload[i]);
00183     }
00184 
00185     mpVtkUnstructuredGrid->GetPointData()->AddArray(p_scalars);
00186     mpVtkUnstructuredGrid->Update();
00187     p_scalars->Delete(); // Reference counted
00188 }
00189 
00190 void AdaptiveTetrahedralMesh::AddPointData(std::string dataName, std::vector<unsigned> dataPayload)
00191 {
00192     vtkUnsignedIntArray *p_scalars = vtkUnsignedIntArray::New();
00193     p_scalars->SetName(dataName.c_str());
00194     for (unsigned i=0; i<dataPayload.size(); i++)
00195     {
00196         p_scalars->InsertNextValue(dataPayload[i]);
00197     }
00198 
00199     mpVtkUnstructuredGrid->GetPointData()->AddArray(p_scalars);
00200     mpVtkUnstructuredGrid->Update();
00201     p_scalars->Delete(); // Reference counted
00202 }
00203 
00204 void AdaptiveTetrahedralMesh::RemoveArray(std::string dataName)
00205 {
00206     mpVtkUnstructuredGrid->GetPointData()->RemoveArray(dataName.c_str());
00207 }
00208 
00209 void AdaptiveTetrahedralMesh::WriteMeshToFile(std::string directory, std::string fileName)
00210 
00211 {
00212     std::string vtk_file_name = directory + fileName;
00213 
00214     vtkXMLUnstructuredGridWriter *vtk_writer = vtkXMLUnstructuredGridWriter::New();
00215     //Uninitialised stuff arises (see #1079), but you can remove
00216     //valgrind problems by removing compression:
00217     // **** REMOVE WITH CAUTION *****
00218     vtk_writer->SetCompressor(NULL);
00219     // **** REMOVE WITH CAUTION *****
00220     vtk_writer->SetFileName(vtk_file_name.c_str());
00221     vtk_writer->SetInput(mpVtkUnstructuredGrid);
00222     vtk_writer->Write();
00223     vtk_writer->Delete();
00224 }
00225 
00226 void AdaptiveTetrahedralMesh::WriteMeshToDistributedFile(std::string directory, std::string fileName)
00227 {
00228     std::string vtk_file_name = directory + fileName;
00229 
00230     vtkXMLPUnstructuredGridWriter *vtk_writer = vtkXMLPUnstructuredGridWriter::New();
00231     //Uninitialised stuff arises (see #1079), but you can remove
00232     //valgrind problems by removing compression:
00233     // **** REMOVE WITH CAUTION *****
00234     vtk_writer->SetCompressor(NULL);
00235     // **** REMOVE WITH CAUTION *****
00236     vtk_writer->SetFileName(vtk_file_name.c_str());
00237     vtk_writer->SetDataModeToBinary();
00238 
00239     vtk_writer->SetNumberOfPieces(PetscTools::GetNumProcs());
00240     vtk_writer->SetGhostLevel(1);
00241     vtk_writer->SetStartPiece(PetscTools::GetMyRank());
00242     vtk_writer->SetEndPiece(PetscTools::GetMyRank());
00243 
00244     vtk_writer->SetInput(mpVtkUnstructuredGrid);
00245     vtk_writer->Write();
00246     vtk_writer->Delete();
00247 }
00248 
00249 vtkUnstructuredGrid* AdaptiveTetrahedralMesh::GetVtkUnstructuredGrid()
00250 {
00251     return mpVtkUnstructuredGrid;
00252 }
00253 
00254 void AdaptiveTetrahedralMesh::SetAdaptCriterion(double range, double criterion)
00255 {
00256     mGoodEdgeRange = range;
00257     mBadEdgeCriterion = criterion;
00258 }
00259 
00260 unsigned AdaptiveTetrahedralMesh::GetNumNodes()
00261 {
00262     return mNumNodes;
00263 }
00264 
00265 unsigned AdaptiveTetrahedralMesh::GetNumLocalNodes()
00266 {
00267     return mNumLocalNodes;
00268 }
00269 
00270 unsigned AdaptiveTetrahedralMesh::GetNumLocalAndHaloNodes()
00271 {
00272     return mpVtkUnstructuredGrid->GetNumberOfPoints();
00273 }
00274 
00275 unsigned AdaptiveTetrahedralMesh::GetNumElements()
00276 {
00277     return mNumElements;
00278 }
00279 
00280 unsigned AdaptiveTetrahedralMesh::GetNumLocalElements()
00281 {
00282     return mpVtkUnstructuredGrid->GetNumberOfCells();
00283 }
00284 
00285 unsigned AdaptiveTetrahedralMesh::GetNumSurfaceElements()
00286 {
00287     return sids.size();
00288 }
00289 
00290 void AdaptiveTetrahedralMesh::CalculateSENListAndSids(double coplanarTolerance)
00291 {
00292     DiscreteGeometryConstraints constraints;
00293 
00294     if (mVerbose) constraints.verbose_on();
00295     constraints.set_coplanar_tolerance( coplanarTolerance );
00296     constraints.set_volume_input(mpVtkUnstructuredGrid);
00297 
00298     constraints.get_coplanar_ids(sids);
00299     constraints.get_surface(SENList);
00300     assert(sids.size()*3==SENList.size());
00301 }
00302 
00303 void AdaptiveTetrahedralMesh::GetGeometryConstraints()
00304 {
00305     assert(mpDiscreteGeometryConstraints==NULL);
00306     mpDiscreteGeometryConstraints = new DiscreteGeometryConstraints;
00307 
00308     if (mVerbose) mpDiscreteGeometryConstraints->verbose_on();
00309     mpDiscreteGeometryConstraints->set_surface_input(mpVtkUnstructuredGrid, SENList, sids);
00310     mpDiscreteGeometryConstraints->get_constraints(max_len);
00311 //    mpDiscreteGeometryConstraints->write_vtk(std::string("sids.vtu"));
00312 }
00313 
00314 void AdaptiveTetrahedralMesh::CalculateErrorMetric()
00315 {
00316     double error           = HeartConfig::Instance()->GetTargetErrorForAdaptivity();
00317     double sigma           = HeartConfig::Instance()->GetSigmaForAdaptivity();
00318     double max_edge_length = HeartConfig::Instance()->GetMaxEdgeLengthForAdaptivity();
00319     double min_edge_length = HeartConfig::Instance()->GetMinEdgeLengthForAdaptivity();
00320     double gradation       = HeartConfig::Instance()->GetGradationForAdaptivity();
00321     unsigned max_nodes     = HeartConfig::Instance()->GetMaxNodesForAdaptivity();
00322     assert(mpErrorMeasure == NULL);
00323     mpErrorMeasure = new ErrorMeasure;
00324 
00325     if (mVerbose) mpErrorMeasure->verbose_on();
00326     mpErrorMeasure->set_input(mpVtkUnstructuredGrid);
00327     mpErrorMeasure->add_field("Vm", error, false, sigma);
00328     mpErrorMeasure->set_max_length(max_edge_length);
00329     mpErrorMeasure->set_max_length(&(max_len[0]), mpVtkUnstructuredGrid->GetNumberOfPoints());
00330     mpErrorMeasure->set_min_length(min_edge_length);
00331     mpErrorMeasure->apply_gradation(gradation);
00332     mpErrorMeasure->set_max_nodes(max_nodes);
00333 
00334     mpErrorMeasure->diagnostics();
00335 }
00336 
00337 double AdaptiveTetrahedralMesh::GetEdgeLengthDistribution(double range)
00338 {
00339     //This is a temporary adaptivity class
00340     Adaptivity an_adapter;
00341     an_adapter.set_from_vtk(mpVtkUnstructuredGrid, true);
00342      return an_adapter.edgeLengthDistribution(range);
00343 }
00344 
00345 void AdaptiveTetrahedralMesh::Adapt()
00346 {
00347     mpAdapt = new Adaptivity;
00348     mAdaptSuccess = false;
00349 
00350     if (mVerbose) mpAdapt->verbose_on();
00351     mpAdapt->set_from_vtk(mpVtkUnstructuredGrid, true);
00352     mpAdapt->set_adapt_sweeps(HeartConfig::Instance()->GetNumberOfAdaptiveSweeps());
00353     mpAdapt->set_surface_mesh(SENList);
00354     mpAdapt->set_surface_ids(sids);
00355 
00356     if ( mpAdapt->edgeLengthDistribution( mGoodEdgeRange ) > mBadEdgeCriterion )
00357     {
00358         mpAdapt->adapt();
00359 
00360         mpAdapt->get_surface_ids(sids);
00361         mpAdapt->get_surface_mesh(SENList);
00362 
00363         vtkUnstructuredGrid *p_new_vtk_unstructured_grid = mpAdapt->get_adapted_vtu();
00364         mpVtkUnstructuredGrid->DeepCopy( p_new_vtk_unstructured_grid );
00365         mpVtkUnstructuredGrid->Update();
00366         p_new_vtk_unstructured_grid->Delete();
00367 
00368         mAdaptSuccess = true;
00369     }
00370     else
00371     {
00373         //mpAdapt->get_adapted_vtu()->Initialize();
00374     }
00375 
00376     mpVtkUnstructuredGrid->GetPointData()->RemoveArray("metric");
00377     mpVtkUnstructuredGrid->Squeeze();
00378 
00379     // Need to free these pointers as fresh instances are required for the next adapt (else odd things happen)
00380     Reset();
00381 
00382     // Update private member variables - note: these assume that the adapt happens sequentially
00383     mNumNodes = mpVtkUnstructuredGrid->GetNumberOfPoints();
00384     mNumElements = mpVtkUnstructuredGrid->GetNumberOfCells();
00385     mNumLocalNodes = mNumNodes;       // Since each process has a complete copy of the vtkUnstructuredGrid
00386 }
00387 
00388 void AdaptiveTetrahedralMesh::AdaptMesh()
00389 {
00390     GetGeometryConstraints();
00391 
00392     CalculateErrorMetric();
00393 
00394     RemoveArray("mean_desired_lengths");
00395     RemoveArray("desired_lengths");
00396 //    SetAdaptCriterion( mGoodEdgeRange, mBadEdgeCriterion );
00397     Adapt();
00398 }
00399 
00400 void AdaptiveTetrahedralMesh::Reset()
00401 {
00402     delete mpDiscreteGeometryConstraints;
00403     delete mpErrorMeasure;
00404     delete mpAdapt;
00405     mpDiscreteGeometryConstraints=NULL;
00406     mpErrorMeasure=NULL;
00407     mpAdapt=NULL;
00408 }
00409 
00410 bool AdaptiveTetrahedralMesh::GetAdaptSuccess()
00411 {
00412     return mAdaptSuccess;
00413 }
00414 
00415 void AdaptiveTetrahedralMesh::MakeVerbose(bool verbose)
00416 {
00417     mVerbose = verbose;
00418 }
00419 
00420 #endif // CHASTE_ADAPTIVITY