Chaste Release::3.1
|
00001 00002 /* 00003 00004 Copyright (c) 2005-2012, University of Oxford. 00005 All rights reserved. 00006 00007 University of Oxford means the Chancellor, Masters and Scholars of the 00008 University of Oxford, having an administrative office at Wellington 00009 Square, Oxford OX1 2JD, UK. 00010 00011 This file is part of Chaste. 00012 00013 Redistribution and use in source and binary forms, with or without 00014 modification, are permitted provided that the following conditions are met: 00015 * Redistributions of source code must retain the above copyright notice, 00016 this list of conditions and the following disclaimer. 00017 * Redistributions in binary form must reproduce the above copyright notice, 00018 this list of conditions and the following disclaimer in the documentation 00019 and/or other materials provided with the distribution. 00020 * Neither the name of the University of Oxford nor the names of its 00021 contributors may be used to endorse or promote products derived from this 00022 software without specific prior written permission. 00023 00024 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00025 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00026 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00027 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00028 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00029 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00030 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00031 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00032 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00033 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00034 00035 */ 00036 00037 #include "HoneycombMeshGenerator.hpp" 00038 00039 #include <boost/foreach.hpp> 00040 #include "TrianglesMeshReader.hpp" 00041 #include "OutputFileHandler.hpp" 00042 #include "RandomNumberGenerator.hpp" 00043 #include "MathsCustomFunctions.hpp" 00044 00045 HoneycombMeshGenerator::HoneycombMeshGenerator(unsigned numNodesAlongWidth, unsigned numNodesAlongLength, unsigned ghosts, double scaleFactor) 00046 : mpMesh(NULL), 00047 mDomainWidth(numNodesAlongWidth*scaleFactor), 00048 mNumCellWidth(numNodesAlongWidth), //*1 because cells are considered to be size one 00049 mNumCellLength(numNodesAlongLength) 00050 { 00051 // The code below won't work in parallel 00052 assert(PetscTools::IsSequential()); 00053 00054 // An older version of the constructor might allow the wrong argument through to the scale factor 00055 assert(scaleFactor > 0.0); 00056 00057 // Get a unique mesh filename 00058 std::stringstream pid; 00059 pid << getpid(); 00060 mMeshFilename = "2D_temporary_honeycomb_mesh_" + pid.str(); 00061 00062 mGhostNodeIndices.empty(); 00063 00064 OutputFileHandler output_file_handler(""); 00065 std::string output_dir = output_file_handler.GetOutputDirectoryFullPath(); 00066 00067 unsigned num_nodes_along_width = mNumCellWidth; 00068 unsigned num_nodes_along_length = mNumCellLength; 00069 double horizontal_spacing = mDomainWidth / (double)num_nodes_along_width; 00070 double vertical_spacing = (sqrt(3)/2)*horizontal_spacing; 00071 00072 // This line is needed to define ghost nodes later 00073 mDomainDepth = (double)(num_nodes_along_length) * vertical_spacing; 00074 00075 // Take account of ghost nodes 00076 num_nodes_along_width += 2*ghosts; 00077 num_nodes_along_length += 2*ghosts; 00078 00079 unsigned num_nodes = num_nodes_along_width*num_nodes_along_length; 00080 unsigned num_elem_along_width = num_nodes_along_width-1; 00081 unsigned num_elem_along_length = num_nodes_along_length-1; 00082 unsigned num_elem = 2*num_elem_along_width*num_elem_along_length; 00083 unsigned num_edges = 3*num_elem_along_width*num_elem_along_length + num_elem_along_width + num_elem_along_length; 00084 00085 double x0 = -horizontal_spacing*ghosts; 00086 double y0 = -vertical_spacing*ghosts; 00087 00088 mBottom = -vertical_spacing*ghosts; 00089 mTop = mBottom + vertical_spacing*(num_nodes_along_length-1); 00090 00091 // Write node file 00092 out_stream p_node_file = output_file_handler.OpenOutputFile(mMeshFilename+".node"); 00093 (*p_node_file) << std::scientific; 00094 (*p_node_file) << std::setprecision(20); 00095 (*p_node_file) << num_nodes << "\t2\t0\t1" << std::endl; 00096 00097 unsigned node = 0; 00098 for (unsigned i=0; i<num_nodes_along_length; i++) 00099 { 00100 for (unsigned j=0; j<num_nodes_along_width; j++) 00101 { 00102 if (i<ghosts || i>=(ghosts+mNumCellLength)) 00103 { 00104 mGhostNodeIndices.insert(node); 00105 } 00106 else if (j < ghosts || j >= (ghosts+mNumCellWidth)) 00107 { 00108 mGhostNodeIndices.insert(node); 00109 } 00110 unsigned boundary = 0; 00111 if (i==0 || i==num_nodes_along_length-1 || j==0 || j==num_nodes_along_width-1) 00112 { 00113 boundary = 1; 00114 } 00115 00116 double x = x0 + horizontal_spacing*((double)j + 0.25*(1.0+ SmallPow(-1,i+1))); 00117 double y = y0 + vertical_spacing*(double)i; 00118 00119 // Avoid floating point errors which upset OffLatticeSimulation 00120 if ( (y<0.0) && (y>-1e-12) ) 00121 { 00122 // Difficult to cover - just corrects floating point errors that have occurred from time to time! 00123 #define COVERAGE_IGNORE 00124 y = 0.0; 00125 #undef COVERAGE_IGNORE 00126 } 00127 00128 (*p_node_file) << node++ << "\t" << x << "\t" << y << "\t" << boundary << std::endl; 00129 } 00130 } 00131 p_node_file->close(); 00132 00133 // Write element file and edge file 00134 out_stream p_elem_file = output_file_handler.OpenOutputFile(mMeshFilename+".ele"); 00135 (*p_elem_file) << std::scientific; 00136 00137 out_stream p_edge_file = output_file_handler.OpenOutputFile(mMeshFilename+".edge"); 00138 (*p_node_file) << std::scientific; 00139 00140 (*p_elem_file) << num_elem << "\t3\t0" << std::endl; 00141 (*p_edge_file) << num_edges << "\t1" << std::endl; 00142 00143 unsigned elem = 0; 00144 unsigned edge = 0; 00145 for (unsigned i=0; i<num_elem_along_length; i++) 00146 { 00147 for (unsigned j=0; j < num_elem_along_width; j++) 00148 { 00149 unsigned node0 = i*num_nodes_along_width + j; 00150 unsigned node1 = i*num_nodes_along_width + j+1; 00151 unsigned node2 = (i+1)*num_nodes_along_width + j; 00152 00153 if (i%2 != 0) 00154 { 00155 node2 = node2 + 1; 00156 } 00157 00158 (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl; 00159 00160 unsigned horizontal_edge_is_boundary_edge = 0; 00161 unsigned vertical_edge_is_boundary_edge = 0; 00162 if (i==0) 00163 { 00164 horizontal_edge_is_boundary_edge = 1; 00165 } 00166 if (j==0 && i%2==0) 00167 { 00168 vertical_edge_is_boundary_edge = 1; 00169 } 00170 00171 (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << horizontal_edge_is_boundary_edge << std::endl; 00172 (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node2 << "\t" << 0 << std::endl; 00173 (*p_edge_file) << edge++ << "\t" << node2 << "\t" << node0 << "\t" << vertical_edge_is_boundary_edge << std::endl; 00174 00175 node0 = i*num_nodes_along_width + j + 1; 00176 00177 if (i%2 != 0) 00178 { 00179 node0 = node0 - 1; 00180 } 00181 node1 = (i+1)*num_nodes_along_width + j+1; 00182 node2 = (i+1)*num_nodes_along_width + j; 00183 00184 (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl; 00185 } 00186 } 00187 00188 for (unsigned i=0; i<num_elem_along_length; i++) 00189 { 00190 unsigned node0, node1; 00191 00192 if (i%2==0) 00193 { 00194 node0 = (i+1)*num_nodes_along_width - 1; 00195 node1 = (i+2)*num_nodes_along_width - 1; 00196 } 00197 else 00198 { 00199 node0 = (i+1)*num_nodes_along_width; 00200 node1 = (i)*num_nodes_along_width; 00201 } 00202 (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << 1 << std::endl; 00203 } 00204 00205 for (unsigned j=0; j<num_elem_along_width; j++) 00206 { 00207 unsigned node0 = num_nodes_along_width*(num_nodes_along_length-1) + j; 00208 unsigned node1 = num_nodes_along_width*(num_nodes_along_length-1) + j+1; 00209 (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node0 << "\t" << 1 << std::endl; 00210 } 00211 00212 p_elem_file->close(); 00213 p_edge_file->close(); 00214 00215 00216 // Having written the mesh to file, now construct it using TrianglesMeshReader 00217 TrianglesMeshReader<2,2> mesh_reader(output_dir + mMeshFilename); 00218 mpMesh = new MutableMesh<2,2>; 00219 mpMesh->ConstructFromMeshReader(mesh_reader); 00220 00221 // Delete the temporary files 00222 FileFinder output_dir_finder(output_dir); 00223 BOOST_FOREACH(FileFinder temp_file, output_dir_finder.FindMatches(mMeshFilename + ".*")) 00224 { 00225 temp_file.Remove(true); 00226 } 00227 00228 // The original files have been deleted, it is better if the mesh object forgets about them 00229 mpMesh->SetMeshHasChangedSinceLoading(); 00230 } 00231 00232 HoneycombMeshGenerator::~HoneycombMeshGenerator() 00233 { 00234 delete mpMesh; 00235 } 00236 00237 MutableMesh<2,2>* HoneycombMeshGenerator::GetMesh() 00238 { 00239 return mpMesh; 00240 } 00241 00242 std::vector<unsigned> HoneycombMeshGenerator::GetCellLocationIndices() 00243 { 00244 std::vector<unsigned> location_indices; 00245 00246 for (unsigned i=0; i<mpMesh->GetNumNodes(); i++) 00247 { 00248 if (mGhostNodeIndices.find(i)==mGhostNodeIndices.end()) 00249 { 00250 location_indices.push_back(i); 00251 } 00252 } 00253 return location_indices; 00254 } 00255 00256 MutableMesh<2,2>* HoneycombMeshGenerator::GetCircularMesh(double radius) 00257 { 00258 if (!mGhostNodeIndices.empty()) 00259 { 00260 EXCEPTION("Cannot call GetCircularMesh on a HoneycombMesh with ghost nodes"); 00261 } 00262 00263 // Centre the mesh at (0,0) 00264 c_vector<double,2> centre = zero_vector<double>(2); 00265 for (unsigned i=0; i<mpMesh->GetNumNodes(); i++) 00266 { 00267 centre += mpMesh->GetNode(i)->rGetLocation(); 00268 } 00269 centre /= (double)mpMesh->GetNumNodes(); 00270 00271 mpMesh->Translate(-centre[0], -centre[1]); 00272 00273 // Iterate over nodes, deleting any that lie more than the specified radius from (0,0) 00274 for (unsigned i=0; i<mpMesh->GetNumAllNodes(); i++) 00275 { 00276 if (norm_2(mpMesh->GetNode(i)->rGetLocation()) >= radius) 00277 { 00278 mpMesh->DeleteNodePriorToReMesh(i); 00279 } 00280 else 00281 { 00282 // Jiggle the data 00283 c_vector<double,2>& r_location = mpMesh->GetNode(i)->rGetModifiableLocation(); 00284 c_vector<double,2> shift; 00285 RandomNumberGenerator* p_gen = RandomNumberGenerator::Instance(); 00286 double max_jiggle = radius*5e-6; 00287 shift[0] = max_jiggle*(p_gen->ranf()-0.5); 00288 shift[1] = max_jiggle*(p_gen->ranf()-0.5); 00289 r_location += shift; 00290 } 00291 } 00292 00293 // Remesh 00294 NodeMap map(mpMesh->GetNumNodes()); 00295 mpMesh->ReMesh(map); 00296 00297 return mpMesh; 00298 } 00299 00300 double HoneycombMeshGenerator::GetDomainDepth() 00301 { 00302 return mDomainDepth; 00303 } 00304 00305 double HoneycombMeshGenerator::GetDomainWidth() 00306 { 00307 return mDomainWidth; 00308 }