Chaste Commit::a9c8bf7350f67d7cf086e6fe3cf5461521554546
ToroidalHoneycombMeshGenerator.cpp
1/*
2
3Copyright (c) 2005-2026, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice,
15 this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 * Neither the name of the University of Oxford nor the names of its
20 contributors may be used to endorse or promote products derived from this
21 software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#include "ToroidalHoneycombMeshGenerator.hpp"
37
38#include <boost/make_shared.hpp>
39#include <boost/shared_ptr.hpp>
40#include "RandomNumberGenerator.hpp"
42#include "ChasteSyscalls.hpp"
43
44ToroidalHoneycombMeshGenerator::ToroidalHoneycombMeshGenerator(unsigned numNodesAlongWidth, unsigned numNodesAlongDepth, double widthScaleFactor, double depthScaleFactor)
45{
46 mpMesh = nullptr;
47 mDomainWidth = numNodesAlongWidth*widthScaleFactor;
48 mDomainDepth = 0.5*sqrt(3)*numNodesAlongDepth*depthScaleFactor;
49 mNumCellWidth = numNodesAlongWidth; //*1 because cells are considered to be size one
50 mNumCellLength = numNodesAlongDepth;
51 mMeshFilename = "mesh";
52
53 // The code below won't work in parallel
55
56 // An older version of the constructor might allow the wrong argument through to the scale factor
57 assert(widthScaleFactor > 0.0);
58 assert(depthScaleFactor > 0.0);
59
60 // Get a unique mesh filename
61 std::stringstream pid;
62 pid << getpid();
63
64 OutputFileHandler output_file_handler("2D_temporary_honeycomb_mesh_"+ pid.str());
65
66 unsigned num_nodes_along_width = mNumCellWidth;
67 unsigned num_nodes_along_depth = mNumCellLength;
68 double horizontal_spacing = mDomainWidth / (double)num_nodes_along_width;
69 double vertical_spacing = mDomainDepth / (double)num_nodes_along_depth;
70
71 unsigned num_nodes = num_nodes_along_width*num_nodes_along_depth;
72 unsigned num_elem_along_width = num_nodes_along_width-1;
73 unsigned num_elem_along_depth = num_nodes_along_depth-1;
74 unsigned num_elem = 2*num_elem_along_width*num_elem_along_depth;
75 unsigned num_edges = 3*num_elem_along_width*num_elem_along_depth + num_elem_along_width + num_elem_along_depth;
76
77 double x0 = 0.0;
78 double y0 = 0.0;
79
80 // Write node file
81 out_stream p_node_file = output_file_handler.OpenOutputFile(mMeshFilename+".node");
82 (*p_node_file) << std::scientific;
83 //(*p_node_file) << std::setprecision(20);
84 (*p_node_file) << num_nodes << "\t2\t0\t1" << std::endl;
85
86 unsigned node = 0;
87 for (unsigned i=0; i<num_nodes_along_depth; i++)
88 {
89 for (unsigned j=0; j<num_nodes_along_width; j++)
90 {
91 unsigned boundary = 0;
92 if ((i==0) || (i==num_nodes_along_depth-1))
93 {
94 boundary = 1;
95 }
96
97 const double adjustment = i % 2 != 0 ? 0.5 : 0.0;
98 double x = x0 + horizontal_spacing*((double)j + adjustment);
99 double y = y0 + vertical_spacing*(double)i;
100
101 // Avoid floating point errors which upset OffLatticeSimulation
102 if ((y<0.0) && (y>-1e-12))
103 {
104 // Difficult to cover - just corrects floating point errors that have occurred from time to time!
105 // LCOV_EXCL_START
106 y = 0.0;
107 // LCOV_EXCL_STOP
108 }
109
110 (*p_node_file) << node++ << "\t" << x << "\t" << y << "\t" << boundary << std::endl;
111 }
112 }
113 p_node_file->close();
114
115 // Write element file and edge file
116 out_stream p_elem_file = output_file_handler.OpenOutputFile(mMeshFilename+".ele");
117 (*p_elem_file) << std::scientific;
118
119 out_stream p_edge_file = output_file_handler.OpenOutputFile(mMeshFilename+".edge");
120 (*p_node_file) << std::scientific;
121
122 (*p_elem_file) << num_elem << "\t3\t0" << std::endl;
123 (*p_edge_file) << num_edges << "\t1" << std::endl;
124
125 unsigned elem = 0;
126 unsigned edge = 0;
127 for (unsigned i=0; i<num_elem_along_depth; i++)
128 {
129 for (unsigned j=0; j < num_elem_along_width; j++)
130 {
131 unsigned node0 = i*num_nodes_along_width + j;
132 unsigned node1 = i*num_nodes_along_width + j+1;
133 unsigned node2 = (i+1)*num_nodes_along_width + j;
134
135 if (i%2 != 0)
136 {
137 node2 = node2 + 1;
138 }
139
140 (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl;
141
142 unsigned horizontal_edge_is_boundary_edge = 0;
143 unsigned vertical_edge_is_boundary_edge = 0;
144 if (i==0)
145 {
146 horizontal_edge_is_boundary_edge = 1;
147 }
148
149 (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << horizontal_edge_is_boundary_edge << std::endl;
150 (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node2 << "\t" << 0 << std::endl;
151 (*p_edge_file) << edge++ << "\t" << node2 << "\t" << node0 << "\t" << vertical_edge_is_boundary_edge << std::endl;
152
153 node0 = i*num_nodes_along_width + j + 1;
154
155 if (i%2 != 0)
156 {
157 node0 = node0 - 1;
158 }
159 node1 = (i+1)*num_nodes_along_width + j+1;
160 node2 = (i+1)*num_nodes_along_width + j;
161
162 (*p_elem_file) << elem++ << "\t" << node0 << "\t" << node1 << "\t" << node2 << std::endl;
163 }
164 }
165
166 for (unsigned i=0; i<num_elem_along_depth; i++)
167 {
168 unsigned node0, node1;
169
170 if (i%2==0)
171 {
172 node0 = (i+1)*num_nodes_along_width - 1;
173 node1 = (i+2)*num_nodes_along_width - 1;
174 }
175 else
176 {
177 node0 = (i+1)*num_nodes_along_width;
178 node1 = (i)*num_nodes_along_width;
179 }
180 (*p_edge_file) << edge++ << "\t" << node0 << "\t" << node1 << "\t" << 1 << std::endl;
181 }
182
183 for (unsigned j=0; j<num_elem_along_width; j++)
184 {
185 unsigned node0 = num_nodes_along_width*(num_nodes_along_depth-1) + j;
186 unsigned node1 = num_nodes_along_width*(num_nodes_along_depth-1) + j+1;
187 (*p_edge_file) << edge++ << "\t" << node1 << "\t" << node0 << "\t" << 1 << std::endl;
188 }
189
190 p_elem_file->close();
191 p_edge_file->close();
192
193 // Having written the mesh to file, now construct it using TrianglesMeshReader.
194 // Nested scope so the reader closes files before we delete them below.
195 {
196 TrianglesMeshReader<2,2> mesh_reader(output_file_handler.GetOutputDirectoryFullPath() + mMeshFilename);
197 mpMesh = boost::make_shared<Toroidal2dMesh >(mDomainWidth,mDomainDepth);
198 mpMesh->ConstructFromMeshReader(mesh_reader);
199 }
200
201 // Make the mesh Toroidal (we use Triangle library mode inside this ReMesh call)
202 mpMesh->ReMesh();
203
204 // Delete the temporary files
205 output_file_handler.FindFile("").Remove();
206
207 // The original files have been deleted, it is better if the mesh object forgets about them
208 mpMesh->SetMeshHasChangedSinceLoading();
209}
210
211boost::shared_ptr<MutableMesh<2,2> > ToroidalHoneycombMeshGenerator::GetMesh()
212{
213 EXCEPTION("A Toroidal mesh was created but a normal mesh is being requested.");
214 return mpMesh; // Not really
215}
216
217boost::shared_ptr<Toroidal2dMesh> ToroidalHoneycombMeshGenerator::GetToroidalMesh()
218{
219 return boost::static_pointer_cast<Toroidal2dMesh>(mpMesh);
220}
#define EXCEPTION(message)
void Remove() const
boost::shared_ptr< MutableMesh< 2, 2 > > mpMesh
std::string GetOutputDirectoryFullPath() const
FileFinder FindFile(std::string leafName) const
out_stream OpenOutputFile(const std::string &rFileName, std::ios_base::openmode mode=std::ios::out|std::ios::trunc) const
static bool IsSequential()
boost::shared_ptr< Toroidal2dMesh > GetToroidalMesh()
ToroidalHoneycombMeshGenerator(unsigned numNodesAlongWidth, unsigned numNodesAlongDepth, double widthScaleFactor=1.0, double depthScaleFactor=1.0)
boost::shared_ptr< MutableMesh< 2, 2 > > GetMesh()