HoneycombMeshGenerator.cpp

00001 
00002 /*
00003 
00004 Copyright (C) University of Oxford, 2005-2009
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 #include "HoneycombMeshGenerator.hpp"
00030 
00031 
00032 HoneycombMeshGenerator::HoneycombMeshGenerator(unsigned numNodesAlongWidth, unsigned numNodesAlongLength, unsigned ghosts, bool cylindrical, double scaleFactor)
00033   : mpMesh(NULL),
00034     mCryptWidth(numNodesAlongWidth*scaleFactor),
00035     mNumCellWidth(numNodesAlongWidth), //*1 because cells are considered to be size one
00036     mNumCellLength(numNodesAlongLength),
00037     mCylindrical(cylindrical)
00038 {
00039     mGhostNodeIndices.empty();
00040 
00041     std::stringstream pid; // Gives a unique filename
00042     pid << getpid();
00043     mMeshFilename = "2D_temporary_periodic_crypt_mesh_" + pid.str();
00044     Make2dPeriodicCryptMesh(mCryptWidth, ghosts);
00045     OutputFileHandler output_file_handler("");
00046     std::string output_dir = output_file_handler.GetOutputDirectoryFullPath();
00047 
00048     TrianglesMeshReader<2,2> mesh_reader(output_dir + mMeshFilename);
00049 
00050     if (!mCylindrical)
00051     {
00052         mpMesh = new MutableMesh<2,2>;
00053         mpMesh->ConstructFromMeshReader(mesh_reader);
00054     }
00055     else
00056     {
00057         mpMesh = new Cylindrical2dMesh(mCryptWidth);
00058         mpMesh->ConstructFromMeshReader(mesh_reader);
00059         NodeMap map(mpMesh->GetNumNodes());
00060         mpMesh->ReMesh(map); // This makes the mesh cylindrical (uses Triangle library mode inside this ReMesh call).
00061     }
00062 
00063     // Delete the temporary files
00064     std::string command = "rm " + output_dir + mMeshFilename + ".*";
00065     int return_value = system(command.c_str());
00066     if (return_value != 0)
00067     {
00068         // Can't figure out how to make this throw but seems as if it should be here?
00069         #define COVERAGE_IGNORE
00070         EXCEPTION("HoneycombMeshGenerator cannot delete temporary files\n");
00071         #undef COVERAGE_IGNORE
00072     }
00073 
00074     CancerParameters::Instance()->SetCryptLength(mCryptDepth);
00075     CancerParameters::Instance()->SetCryptWidth(mCryptWidth);
00076 }
00077     
00078     
00079 HoneycombMeshGenerator::~HoneycombMeshGenerator()
00080 {
00081     delete mpMesh;
00082 }
00083 
00084 
00085 MutableMesh<2,2>* HoneycombMeshGenerator::GetMesh()
00086 {
00087     if (mCylindrical)
00088     {
00089         EXCEPTION("A cylindrical mesh was created but a normal mesh is being requested.");
00090     }
00091     return mpMesh;
00092 }
00093 
00094 
00095 Cylindrical2dMesh* HoneycombMeshGenerator::GetCylindricalMesh()
00096 {
00097     if (!mCylindrical)
00098     {
00099         EXCEPTION("A normal mesh was created but a cylindrical mesh is being requested.");
00100     }
00101     return (Cylindrical2dMesh*) mpMesh;
00102 }
00103 
00104 std::vector<unsigned> HoneycombMeshGenerator::GetCellLocationIndices()
00105 {
00106     std::vector<unsigned> location_indices;
00107     
00108     for (unsigned i=0; i<mpMesh->GetNumNodes(); i++)
00109     {
00110         if (mGhostNodeIndices.find(i)==mGhostNodeIndices.end())
00111         {
00112             location_indices.push_back(i);
00113         }
00114     }
00115     return location_indices;
00116 }
00117 
00118 MutableMesh<2,2>* HoneycombMeshGenerator::GetCircularMesh(double radius)
00119 {
00120     assert(!mCylindrical); // Following call only safe if is not a cylindrical mesh
00121 
00122     // Centre the mesh at (0,0)
00123     c_vector<double,2> centre = zero_vector<double>(2);
00124     for (unsigned i=0; i<mpMesh->GetNumNodes(); i++)
00125     {
00126         centre += mpMesh->GetNode(i)->rGetLocation();
00127     }
00128     centre /= (double)mpMesh->GetNumNodes();
00129 
00130     mpMesh->Translate(-centre[0], -centre[1]);
00131 
00132     // Iterate over nodes, deleting any that lie more
00133     // than the specified radius from (0,0)
00134     for (unsigned i=0; i<mpMesh->GetNumAllNodes(); i++)
00135     {
00136         if ( norm_2(mpMesh->GetNode(i)->rGetLocation()) >= radius)
00137         {
00138             mpMesh->DeleteNodePriorToReMesh(i);
00139         }
00140         else
00141         {
00142             // Jiggle the data
00143             c_vector<double,2>& r_location = mpMesh->GetNode(i)->rGetModifiableLocation();
00144             c_vector<double,2> shift;
00145             RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance();
00146             double max_jiggle = radius*5e-6;
00147             shift[0] = max_jiggle*(p_gen->ranf()-0.5);
00148             shift[1] = max_jiggle*(p_gen->ranf()-0.5);
00149             r_location += shift;
00150         }
00151     }
00152 
00153     // Remesh
00154     NodeMap map(mpMesh->GetNumNodes());
00155     mpMesh->ReMesh(map);
00156 
00157     return mpMesh;
00158 }
00159 
00160 void HoneycombMeshGenerator::Make2dPeriodicCryptMesh(double width, unsigned ghosts)
00161 {
00162     OutputFileHandler output_file_handler("");
00163 
00164     if (output_file_handler.IsMaster())
00165     {
00166         out_stream p_node_file = output_file_handler.OpenOutputFile(mMeshFilename+".node");
00167         (*p_node_file) << std::scientific;
00168 
00169         out_stream p_elem_file = output_file_handler.OpenOutputFile(mMeshFilename+".ele");
00170         (*p_elem_file) << std::scientific;
00171 
00172         unsigned numNodesAlongWidth = mNumCellWidth;
00173         unsigned numNodesAlongLength = mNumCellLength;
00174         double horizontal_spacing = width / (double)numNodesAlongWidth;
00175         double vertical_spacing = (sqrt(3)/2)*horizontal_spacing;
00176 
00177         // This line needed to define ghost nodes later...
00178         mCryptDepth = (double)(numNodesAlongLength) * vertical_spacing;
00179 
00180         // Add in the ghost nodes...
00181         if (!mCylindrical)
00182         {
00183             numNodesAlongWidth = numNodesAlongWidth + 2*ghosts;
00184         }
00185         numNodesAlongLength = numNodesAlongLength + 2*ghosts;
00186 
00187         unsigned num_nodes            = numNodesAlongWidth*numNodesAlongLength;
00188         unsigned num_elem_along_width = numNodesAlongWidth-1;
00189         unsigned num_elem_along_length = numNodesAlongLength-1;
00190         unsigned num_elem             = 2*num_elem_along_width*num_elem_along_length;
00191         unsigned num_edges            = 3*num_elem_along_width*num_elem_along_length + num_elem_along_width + num_elem_along_length;
00192 
00193         double x0 = -horizontal_spacing*ghosts;
00194         if (mCylindrical)
00195         {
00196             x0 = 0;
00197         }
00198         double y0 = -vertical_spacing*ghosts;
00199         mBottom = -vertical_spacing*ghosts;
00200         mTop = mBottom + vertical_spacing*(numNodesAlongLength-1);
00201 
00202         (*p_node_file) << num_nodes << "\t2\t0\t1" << std::endl;
00203         unsigned node = 0;
00204 
00205         for (unsigned i=0; i<numNodesAlongLength; i++)
00206         {
00207             for (unsigned j=0; j<numNodesAlongWidth; j++)
00208             {
00209                 if ( i<ghosts || i>=(ghosts+mNumCellLength))
00210                 {
00211                     mGhostNodeIndices.insert(node);
00212                 }
00213                 else if ( !mCylindrical && (j < ghosts || j >= (ghosts+mNumCellWidth)))
00214                 {
00215                     mGhostNodeIndices.insert(node);
00216                 }
00217                 unsigned boundary = 0;
00218                 if ((i==0) || (i==numNodesAlongLength-1))
00219                 {
00220                     boundary = 1;
00221                 }
00222                 if (!mCylindrical)
00223                 {
00224                     if ((j==0) || (j==numNodesAlongWidth-1))
00225                     {
00226                         boundary = 1;
00227                     }
00228                 }
00229 
00230                 double x = x0 + horizontal_spacing*((double)j + 0.25*(1.0+ pow(-1,i+1)));
00231                 double y = y0 + vertical_spacing*(double)i;
00232 
00233                 // Avoid floating point errors which upset CryptSimulation2d
00234                 if ( (y<0.0) && (y>-1e-12) )
00235                 {
00236                     // Difficult to cover - just corrects floating point errors that have occurred from time to time!
00237                     #define COVERAGE_IGNORE
00238                     y = 0.0;
00239                     #undef COVERAGE_IGNORE
00240                 }
00241 
00242                 (*p_node_file) << node++ << "\t" << x << "\t" << y << "\t" << boundary << std::endl;
00243             }
00244         }
00245         p_node_file->close();
00246 
00247         out_stream p_edge_file = output_file_handler.OpenOutputFile(mMeshFilename+".edge");
00248         (*p_node_file) << std::scientific;
00249 
00250         (*p_elem_file) << num_elem << "\t3\t0" << std::endl;
00251         (*p_edge_file) << num_edges << "\t1" << std::endl;
00252 
00253         unsigned elem = 0;
00254         unsigned edge = 0;
00255         for (unsigned i=0; i<num_elem_along_length; i++)
00256         {
00257             for (unsigned j=0; j < num_elem_along_width; j++)
00258             {
00259                 unsigned node0 =     i*numNodesAlongWidth + j;
00260                 unsigned node1 =     i*numNodesAlongWidth + j+1;
00261                 unsigned node2 = (i+1)*numNodesAlongWidth + j;
00262 
00263                 if (i%2 != 0)
00264                 {
00265                     node2 = node2 + 1;
00266                 }
00267 
00268                 (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl;
00269 
00270                 unsigned horizontal_edge_is_boundary_edge = 0;
00271                 unsigned vertical_edge_is_boundary_edge = 0;
00272                 if (i==0)
00273                 {
00274                     horizontal_edge_is_boundary_edge = 1;
00275                 }
00276                 if (j==0 && i%2==0 && !mCylindrical)
00277                 {
00278                     vertical_edge_is_boundary_edge = 1;
00279                 }
00280 
00281                 (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 <<  "\t" << horizontal_edge_is_boundary_edge << std::endl;
00282                 (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node2 <<  "\t" << 0 << std::endl;
00283                 (*p_edge_file) << edge++ << "\t" << node2 << "\t" << node0 <<  "\t" << vertical_edge_is_boundary_edge << std::endl;
00284 
00285                 node0 = i*numNodesAlongWidth + j + 1;
00286 
00287                 if (i%2 != 0)
00288                 {
00289                     node0 = node0 - 1;
00290                 }
00291                 node1 = (i+1)*numNodesAlongWidth + j+1;
00292                 node2 = (i+1)*numNodesAlongWidth + j;
00293 
00294                 (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl;
00295             }
00296         }
00297 
00298         for (unsigned i=0; i<num_elem_along_length; i++)
00299         {
00300             unsigned node0, node1;
00301 
00302             if (i%2==0)
00303             {
00304                  node0 = (i+1)*numNodesAlongWidth - 1;
00305                  node1 = (i+2)*numNodesAlongWidth - 1;
00306             }
00307             else
00308             {
00309                 node0 = (i+1)*numNodesAlongWidth;
00310                 node1 = (i)*numNodesAlongWidth;
00311             }
00312             (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << 1 << std::endl;
00313         }
00314 
00315         for (unsigned j=0; j<num_elem_along_width; j++)
00316         {
00317             unsigned node0 = numNodesAlongWidth*(numNodesAlongLength-1) + j;
00318             unsigned node1 = numNodesAlongWidth*(numNodesAlongLength-1) + j+1;
00319             (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node0 << "\t" << 1 << std::endl;
00320         }
00321 
00322         p_elem_file->close();
00323         p_edge_file->close();
00324     }
00325 
00326     // Wait for the new mesh to be available
00327     PetscTools::Barrier();
00328 }

Generated on Wed Mar 18 12:51:49 2009 for Chaste by  doxygen 1.5.5