HoneycombMeshGenerator.cpp

00001 
00002 /*
00003 
00004 Copyright (C) University of Oxford, 2005-2011
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 Chaste is free software: you can redistribute it and/or modify it
00013 under the terms of the GNU Lesser General Public License as published
00014 by the Free Software Foundation, either version 2.1 of the License, or
00015 (at your option) any later version.
00016 
00017 Chaste is distributed in the hope that it will be useful, but WITHOUT
00018 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00019 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00020 License for more details. The offer of Chaste under the terms of the
00021 License is subject to the License being interpreted in accordance with
00022 English Law and subject to any action against the University of Oxford
00023 being under the jurisdiction of the English Courts.
00024 
00025 You should have received a copy of the GNU Lesser General Public License
00026 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00027 
00028 */
00029 
00030 #include "HoneycombMeshGenerator.hpp"
00031 #include "TrianglesMeshReader.hpp"
00032 #include "OutputFileHandler.hpp"
00033 #include "RandomNumberGenerator.hpp"
00034 #include "MathsCustomFunctions.hpp"
00035 
00036 HoneycombMeshGenerator::HoneycombMeshGenerator(unsigned numNodesAlongWidth, unsigned numNodesAlongLength, unsigned ghosts, double scaleFactor)
00037   : mpMesh(NULL),
00038     mDomainWidth(numNodesAlongWidth*scaleFactor),
00039     mNumCellWidth(numNodesAlongWidth), //*1 because cells are considered to be size one
00040     mNumCellLength(numNodesAlongLength)
00041 {
00042     // The getpid code below won't work in parallel
00043     assert(PetscTools::IsSequential());
00044 
00045     // An older version of the constructor might allow the wrong argument through to the scale factor
00046     assert(scaleFactor > 0.0);
00047 
00048     // Get a unique mesh filename
00049     std::stringstream pid;
00050     pid << getpid();
00051     mMeshFilename = "2D_temporary_honeycomb_mesh_" + pid.str();
00052 
00053     mGhostNodeIndices.empty();
00054 
00055     OutputFileHandler output_file_handler("");
00056     std::string output_dir = output_file_handler.GetOutputDirectoryFullPath();
00057 
00058     if (PetscTools::AmMaster())
00059     {
00060         unsigned numNodesAlongWidth = mNumCellWidth;
00061         unsigned numNodesAlongLength = mNumCellLength;
00062         double horizontal_spacing = mDomainWidth / (double)numNodesAlongWidth;
00063         double vertical_spacing = (sqrt(3)/2)*horizontal_spacing;
00064 
00065         // This line is needed to define ghost nodes later
00066         mDomainDepth = (double)(numNodesAlongLength) * vertical_spacing;
00067 
00068         // Take account of ghost nodes
00069         numNodesAlongWidth = numNodesAlongWidth + 2*ghosts;
00070         numNodesAlongLength = numNodesAlongLength + 2*ghosts;
00071 
00072         unsigned num_nodes            = numNodesAlongWidth*numNodesAlongLength;
00073         unsigned num_elem_along_width = numNodesAlongWidth-1;
00074         unsigned num_elem_along_length = numNodesAlongLength-1;
00075         unsigned num_elem             = 2*num_elem_along_width*num_elem_along_length;
00076         unsigned num_edges            = 3*num_elem_along_width*num_elem_along_length + num_elem_along_width + num_elem_along_length;
00077 
00078         double x0 = -horizontal_spacing*ghosts;
00079         double y0 = -vertical_spacing*ghosts;
00080 
00081         mBottom = -vertical_spacing*ghosts;
00082         mTop = mBottom + vertical_spacing*(numNodesAlongLength-1);
00083 
00084         // Write node file
00085         out_stream p_node_file = output_file_handler.OpenOutputFile(mMeshFilename+".node");
00086         (*p_node_file) << std::scientific;
00087         (*p_node_file) << num_nodes << "\t2\t0\t1" << std::endl;
00088 
00089         unsigned node = 0;
00090         for (unsigned i=0; i<numNodesAlongLength; i++)
00091         {
00092             for (unsigned j=0; j<numNodesAlongWidth; j++)
00093             {
00094                 if (i<ghosts || i>=(ghosts+mNumCellLength))
00095                 {
00096                     mGhostNodeIndices.insert(node);
00097                 }
00098                 else if (j < ghosts || j >= (ghosts+mNumCellWidth))
00099                 {
00100                     mGhostNodeIndices.insert(node);
00101                 }
00102                 unsigned boundary = 0;
00103                 if (i==0 || i==numNodesAlongLength-1 || j==0 || j==numNodesAlongWidth-1)
00104                 {
00105                     boundary = 1;
00106                 }
00107 
00108                 double x = x0 + horizontal_spacing*((double)j + 0.25*(1.0+ SmallPow(-1,i+1)));
00109                 double y = y0 + vertical_spacing*(double)i;
00110 
00111                 // Avoid floating point errors which upset OffLatticeSimulation
00112                 if ( (y<0.0) && (y>-1e-12) )
00113                 {
00114                     // Difficult to cover - just corrects floating point errors that have occurred from time to time!
00115                     #define COVERAGE_IGNORE
00116                     y = 0.0;
00117                     #undef COVERAGE_IGNORE
00118                 }
00119 
00120                 (*p_node_file) << node++ << "\t" << x << "\t" << y << "\t" << boundary << std::endl;
00121             }
00122         }
00123         p_node_file->close();
00124 
00125         // Write element file and edge file
00126         out_stream p_elem_file = output_file_handler.OpenOutputFile(mMeshFilename+".ele");
00127         (*p_elem_file) << std::scientific;
00128 
00129         out_stream p_edge_file = output_file_handler.OpenOutputFile(mMeshFilename+".edge");
00130         (*p_node_file) << std::scientific;
00131 
00132         (*p_elem_file) << num_elem << "\t3\t0" << std::endl;
00133         (*p_edge_file) << num_edges << "\t1" << std::endl;
00134 
00135         unsigned elem = 0;
00136         unsigned edge = 0;
00137         for (unsigned i=0; i<num_elem_along_length; i++)
00138         {
00139             for (unsigned j=0; j < num_elem_along_width; j++)
00140             {
00141                 unsigned node0 =     i*numNodesAlongWidth + j;
00142                 unsigned node1 =     i*numNodesAlongWidth + j+1;
00143                 unsigned node2 = (i+1)*numNodesAlongWidth + j;
00144 
00145                 if (i%2 != 0)
00146                 {
00147                     node2 = node2 + 1;
00148                 }
00149 
00150                 (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl;
00151 
00152                 unsigned horizontal_edge_is_boundary_edge = 0;
00153                 unsigned vertical_edge_is_boundary_edge = 0;
00154                 if (i==0)
00155                 {
00156                     horizontal_edge_is_boundary_edge = 1;
00157                 }
00158                 if (j==0 && i%2==0)
00159                 {
00160                     vertical_edge_is_boundary_edge = 1;
00161                 }
00162 
00163                 (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << horizontal_edge_is_boundary_edge << std::endl;
00164                 (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node2 << "\t" << 0 << std::endl;
00165                 (*p_edge_file) << edge++ << "\t" << node2 << "\t" << node0 << "\t" << vertical_edge_is_boundary_edge << std::endl;
00166 
00167                 node0 = i*numNodesAlongWidth + j + 1;
00168 
00169                 if (i%2 != 0)
00170                 {
00171                     node0 = node0 - 1;
00172                 }
00173                 node1 = (i+1)*numNodesAlongWidth + j+1;
00174                 node2 = (i+1)*numNodesAlongWidth + j;
00175 
00176                 (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl;
00177             }
00178         }
00179 
00180         for (unsigned i=0; i<num_elem_along_length; i++)
00181         {
00182             unsigned node0, node1;
00183 
00184             if (i%2==0)
00185             {
00186                  node0 = (i+1)*numNodesAlongWidth - 1;
00187                  node1 = (i+2)*numNodesAlongWidth - 1;
00188             }
00189             else
00190             {
00191                 node0 = (i+1)*numNodesAlongWidth;
00192                 node1 = (i)*numNodesAlongWidth;
00193             }
00194             (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << 1 << std::endl;
00195         }
00196 
00197         for (unsigned j=0; j<num_elem_along_width; j++)
00198         {
00199             unsigned node0 = numNodesAlongWidth*(numNodesAlongLength-1) + j;
00200             unsigned node1 = numNodesAlongWidth*(numNodesAlongLength-1) + j+1;
00201             (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node0 << "\t" << 1 << std::endl;
00202         }
00203 
00204         p_elem_file->close();
00205         p_edge_file->close();
00206     }
00207 
00208     // Wait for the new mesh to be available
00209     PetscTools::Barrier();
00210 
00211     // Having written the mesh to file, now construct it using TrianglesMeshReader
00212     TrianglesMeshReader<2,2> mesh_reader(output_dir + mMeshFilename);
00213     mpMesh = new MutableMesh<2,2>;
00214     mpMesh->ConstructFromMeshReader(mesh_reader);
00215 
00216     // Delete the temporary files
00217     std::string command = "rm " + output_dir + mMeshFilename + ".*";
00218     int return_value = system(command.c_str());
00219     if (return_value != 0)
00220     {
00221         // Can't figure out how to make this throw but seems as if it should be here?
00222         #define COVERAGE_IGNORE
00223         EXCEPTION("HoneycombMeshGenerator cannot delete temporary files\n");
00224         #undef COVERAGE_IGNORE
00225     }
00226 
00227     // The original files have been deleted, it is better if the mesh object forgets about them
00228     mpMesh->SetMeshHasChangedSinceLoading();
00229 }
00230 
00231 HoneycombMeshGenerator::~HoneycombMeshGenerator()
00232 {
00233     delete mpMesh;
00234 }
00235 
00236 MutableMesh<2,2>* HoneycombMeshGenerator::GetMesh()
00237 {
00238     return mpMesh;
00239 }
00240 
00241 std::vector<unsigned> HoneycombMeshGenerator::GetCellLocationIndices()
00242 {
00243     std::vector<unsigned> location_indices;
00244 
00245     for (unsigned i=0; i<mpMesh->GetNumNodes(); i++)
00246     {
00247         if (mGhostNodeIndices.find(i)==mGhostNodeIndices.end())
00248         {
00249             location_indices.push_back(i);
00250         }
00251     }
00252     return location_indices;
00253 }
00254 
00255 MutableMesh<2,2>* HoneycombMeshGenerator::GetCircularMesh(double radius)
00256 {
00257 
00258     if(mGhostNodeIndices.size() != 0u)
00259     {
00260         EXCEPTION("Cannot call GetCircularMesh on a HoneycombMesh with ghost nodes");
00261     }
00262     // Centre the mesh at (0,0)
00263     c_vector<double,2> centre = zero_vector<double>(2);
00264     for (unsigned i=0; i<mpMesh->GetNumNodes(); i++)
00265     {
00266         centre += mpMesh->GetNode(i)->rGetLocation();
00267     }
00268     centre /= (double)mpMesh->GetNumNodes();
00269 
00270     mpMesh->Translate(-centre[0], -centre[1]);
00271 
00272     // Iterate over nodes, deleting any that lie more than the specified radius from (0,0)
00273     for (unsigned i=0; i<mpMesh->GetNumAllNodes(); i++)
00274     {
00275         if (norm_2(mpMesh->GetNode(i)->rGetLocation()) >= radius)
00276         {
00277             mpMesh->DeleteNodePriorToReMesh(i);
00278         }
00279         else
00280         {
00281             // Jiggle the data
00282             c_vector<double,2>& r_location = mpMesh->GetNode(i)->rGetModifiableLocation();
00283             c_vector<double,2> shift;
00284             RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00285             double max_jiggle = radius*5e-6;
00286             shift[0] = max_jiggle*(p_gen->ranf()-0.5);
00287             shift[1] = max_jiggle*(p_gen->ranf()-0.5);
00288             r_location += shift;
00289         }
00290     }
00291 
00292     // Remesh
00293     NodeMap map(mpMesh->GetNumNodes());
00294     mpMesh->ReMesh(map);
00295 
00296     return mpMesh;
00297 }
00298 
00299 double HoneycombMeshGenerator::GetDomainDepth()
00300 {
00301     return mDomainDepth;
00302 }
00303 
00304 double HoneycombMeshGenerator::GetDomainWidth()
00305 {
00306     return mDomainWidth;
00307 }
Generated on Thu Dec 22 13:00:04 2011 for Chaste by  doxygen 1.6.3