Chi-Tech
OrthogonalMeshGenerator.cc
Go to the documentation of this file.
2
3#include "ChiObjectFactory.h"
4
5#include "chi_log.h"
6
7namespace chi_mesh
8{
9
11
13{
15
16 params.SetGeneralDescription("Creates orthogonal meshes.");
17 params.SetDocGroup("doc_MeshGenerators");
18
19 params.AddRequiredParameterArray("node_sets",
20 "Sets of nodes per dimension. Node values "
21 "must be monotonically increasing");
22
23 return params;
24}
25
27 const chi::InputParameters& params)
28 : MeshGenerator(params)
29{
30 //======================================== Parse the node_sets param
31 if (params.ParametersAtAssignment().Has("node_sets"))
32 {
33 auto& node_sets_param = params.GetParam("node_sets");
35
36 for (const auto& node_list_block : node_sets_param)
37 {
39 node_list_block.Type() != chi::ParameterBlockType::ARRAY,
40 "The entries of \"node_sets\" are required to be of type \"Array\".");
41
42 node_sets_.push_back(node_list_block.GetVectorValue<double>());
43 }
44 }
45
46 //======================================== Check they were not empty and <=3
48 node_sets_.empty(),
49 "No nodes have been provided. At least one node set must be provided");
50
52 "More than 3 node sets have been provided. The "
53 "maximum allowed is 3.");
54
55 size_t ns = 0;
56 for (const auto& node_set : node_sets_)
57 {
59 node_set.size() < 2,
60 "Node set " + std::to_string(ns) + " only has " +
61 std::to_string(node_set.size()) +
62 " nodes. A minimum of 2 is required to define a cell.");
63 ++ns;
64 }
65
66 //======================================== Check each node_set
67 size_t set_number = 0;
68 for (const auto& node_set : node_sets_)
69 {
70 ChiInvalidArgumentIf(node_set.empty(),
71 "Node set " + std::to_string(set_number) +
72 " in parameter \"node_sets\" may not be empty");
73
74 bool monotonic = true;
75 double prev_value = node_set[0];
76 for (size_t k = 1; k < node_set.size(); ++k)
77 {
78 if (node_set[k] <= prev_value)
79 {
80 monotonic = false;
81 break;
82 }
83
84 prev_value = node_set[k];
85 }
86 if (not monotonic)
87 {
88 std::stringstream outstr;
89 for (double value : node_set)
90 outstr << value << " ";
91 ChiInvalidArgument("Node sets in parameter \"node_sets\" requires all "
92 "values to be monotonically increasing. Node set: " +
93 outstr.str());
94 }
95 } // for node_set in node_sets_
96}
97
98// ##################################################################
99std::unique_ptr<UnpartitionedMesh>
101 std::unique_ptr<UnpartitionedMesh> input_umesh)
102{
104 input_umesh != nullptr,
105 "OrthogonalMeshGenerator can not be preceded by another"
106 " mesh generator because it cannot process an input mesh");
107
108 if (node_sets_.size() == 1)
110 else if (node_sets_.size() == 2)
112 else if (node_sets_.size() == 3)
114 node_sets_[0], node_sets_[1], node_sets_[2]);
115 else
116 throw std::logic_error(
117 ""); // This will never get triggered because of the checks in constructor
118}
119
120// ##################################################################
121std::unique_ptr<UnpartitionedMesh>
123 const std::vector<double>& vertices)
124{
125 auto umesh = std::make_unique<UnpartitionedMesh>();
126
127 //======================================== Reorient 1D verts along z
128 std::vector<Vertex> zverts;
129 zverts.reserve(vertices.size());
130 for (double z_coord : vertices)
131 zverts.emplace_back(0.0, 0.0, z_coord);
132
133 umesh->GetMeshAttributes() = DIMENSION_1 | ORTHOGONAL;
134
135 //======================================== Create vertices
136 size_t Nz = vertices.size();
137
138 umesh->GetMeshOptions().ortho_Nx = 1;
139 umesh->GetMeshOptions().ortho_Ny = 1;
140 umesh->GetMeshOptions().ortho_Nz = Nz - 1;
141 umesh->GetMeshOptions().boundary_id_map[4] = "ZMAX";
142 umesh->GetMeshOptions().boundary_id_map[5] = "ZMIN";
143
144 umesh->GetVertices().reserve(Nz);
145 for (auto& vertex : zverts)
146 umesh->GetVertices().push_back(vertex);
147
148 //======================================== Create cells
149 const size_t max_cz = zverts.size() - 2;
150 for (size_t c = 0; c < (zverts.size() - 1); ++c)
151 {
152 auto cell =
154
155 cell->vertex_ids = {c, c + 1};
156
159
160 left_face.vertex_ids = {c};
161 rite_face.vertex_ids = {c + 1};
162
163 // if (c == 0) left_face.neighbor = 5 /*ZMIN*/;
164 // if (c == (zverts.size() - 2)) rite_face.neighbor = 4 /*ZMAX*/;
165
166 left_face.neighbor = c - 1;
167 rite_face.neighbor = c + 1;
168 left_face.has_neighbor = true;
169 rite_face.has_neighbor = true;
170
171 // boundary logic
172 // clang-format off
173 if (c == 0) { left_face.neighbor = 5 /*ZMIN*/; left_face.has_neighbor = false; }
174 if (c == max_cz) { rite_face.neighbor = 4 /*ZMAX*/; rite_face.has_neighbor = false; }
175 // clang-format on
176
177 cell->faces.push_back(left_face);
178 cell->faces.push_back(rite_face);
179
180 umesh->AddCell(cell);
181 }
182
183 umesh->ComputeCentroidsAndCheckQuality();
184 umesh->BuildMeshConnectivity();
185
186 return umesh;
187}
188
189// ##################################################################
190std::unique_ptr<UnpartitionedMesh>
192 const std::vector<double>& vertices_1d_x,
193 const std::vector<double>& vertices_1d_y)
194{
195 auto umesh = std::make_unique<UnpartitionedMesh>();
196
197 umesh->GetMeshAttributes() = DIMENSION_2 | ORTHOGONAL;
198
199 //======================================== Create vertices
200 const size_t Nx = vertices_1d_x.size();
201 const size_t Ny = vertices_1d_y.size();
202
203 umesh->GetMeshOptions().ortho_Nx = Nx - 1;
204 umesh->GetMeshOptions().ortho_Ny = Ny - 1;
205 umesh->GetMeshOptions().ortho_Nz = 1;
206 umesh->GetMeshOptions().boundary_id_map[0] = "XMAX";
207 umesh->GetMeshOptions().boundary_id_map[1] = "XMIN";
208 umesh->GetMeshOptions().boundary_id_map[2] = "YMAX";
209 umesh->GetMeshOptions().boundary_id_map[3] = "YMIN";
210
211 typedef std::vector<uint64_t> VecIDs;
212 std::vector<VecIDs> vertex_ij_to_i_map(Ny, VecIDs(Nx));
213 umesh->GetVertices().reserve(Nx * Ny);
214 {
215 uint64_t k = 0;
216 for (size_t i = 0; i < Ny; ++i)
217 {
218 for (size_t j = 0; j < Nx; ++j)
219 {
220 vertex_ij_to_i_map[i][j] = k++;
221 umesh->GetVertices().emplace_back(
222 vertices_1d_x[j], vertices_1d_y[i], 0.0);
223 } // for j
224 } // for i
225 }
226
227 std::vector<VecIDs> cells_ij_to_i_map(Ny - 1, VecIDs(Nx - 1));
228 {
229 uint64_t k = 0;
230 for (size_t i = 0; i < (Ny - 1); ++i)
231 for (size_t j = 0; j < (Nx - 1); ++j)
232 cells_ij_to_i_map[i][j] = k++;
233 }
234
235 //======================================== Create cells
236 auto& vmap = vertex_ij_to_i_map;
237 auto& cmap = cells_ij_to_i_map;
238 const size_t max_j = Nx - 2;
239 const size_t max_i = Ny - 2;
240 for (size_t i = 0; i < (Ny - 1); ++i)
241 {
242 for (size_t j = 0; j < (Nx - 1); ++j)
243 {
246
247 // vertex ids: face ids:
248 // 2
249 // 3---2 x---x
250 // | | 3| |1
251 // 0---1 x---x
252 // 0
253
254 cell->vertex_ids = {
255 vmap[i][j], vmap[i][j + 1], vmap[i + 1][j + 1], vmap[i + 1][j]};
256
257 for (int v = 0; v < 4; ++v)
258 {
260
261 if (v < 3)
262 face.vertex_ids =
263 std::vector<uint64_t>{cell->vertex_ids[v], cell->vertex_ids[v + 1]};
264 else
265 face.vertex_ids =
266 std::vector<uint64_t>{cell->vertex_ids[v], cell->vertex_ids[0]};
267
268 face.neighbor = true;
269 // clang-format off
270 if (v == 1 and i != max_j) face.neighbor = cmap[i][j+1]/*XMAX*/;
271 if (v == 3 and i != 0 ) face.neighbor = cmap[i][j-1]/*XMIN*/;
272 if (v == 2 and i != max_i) face.neighbor = cmap[i+1][j]/*YMAX*/;
273 if (v == 0 and i != 0 ) face.neighbor = cmap[i-1][j]/*YMIN*/;
274
275 // boundary logic
276 if (v == 1 and j == max_j) { face.neighbor = 0 /*XMAX*/; face.has_neighbor = false; }
277 if (v == 3 and j == 0 ) { face.neighbor = 1 /*XMIN*/; face.has_neighbor = false; }
278 if (v == 2 and i == max_i) { face.neighbor = 2 /*YMAX*/; face.has_neighbor = false; }
279 if (v == 0 and i == 0 ) { face.neighbor = 3 /*YMIN*/; face.has_neighbor = false; }
280 // clang-format on
281
282 cell->faces.push_back(face);
283 }
284
285 umesh->AddCell(cell);
286 } // for j
287 } // for i
288
289 umesh->ComputeCentroidsAndCheckQuality();
290 umesh->BuildMeshConnectivity();
291
292 return umesh;
293}
294
295// ##################################################################
296std::unique_ptr<UnpartitionedMesh>
298 const std::vector<double>& vertices_1d_x,
299 const std::vector<double>& vertices_1d_y,
300 const std::vector<double>& vertices_1d_z)
301{
302 auto umesh = std::make_unique<UnpartitionedMesh>();
303
304 umesh->GetMeshAttributes() = DIMENSION_3 | ORTHOGONAL;
305
306 //======================================== Create vertices
307 size_t Nx = vertices_1d_x.size();
308 size_t Ny = vertices_1d_y.size();
309 size_t Nz = vertices_1d_z.size();
310
311 umesh->GetMeshOptions().ortho_Nx = Nx - 1;
312 umesh->GetMeshOptions().ortho_Ny = Ny - 1;
313 umesh->GetMeshOptions().ortho_Nz = Nz - 1;
314 umesh->GetMeshOptions().boundary_id_map[0] = "XMAX";
315 umesh->GetMeshOptions().boundary_id_map[1] = "XMIN";
316 umesh->GetMeshOptions().boundary_id_map[2] = "YMAX";
317 umesh->GetMeshOptions().boundary_id_map[3] = "YMIN";
318 umesh->GetMeshOptions().boundary_id_map[4] = "ZMAX";
319 umesh->GetMeshOptions().boundary_id_map[5] = "ZMIN";
320
321 // i is j, and j is i, MADNESS explanation:
322 // In math convention the i-index refers to the ith row
323 // and the j-index refers to the jth row. We try to follow
324 // the same logic here.
325
326 typedef std::vector<uint64_t> VecIDs;
327 typedef std::vector<VecIDs> VecVecIDs;
328 std::vector<VecVecIDs> vertex_ijk_to_i_map(Ny);
329 for (auto& vec : vertex_ijk_to_i_map)
330 vec.resize(Nx, VecIDs(Nz));
331
332 umesh->GetVertices().reserve(Nx * Ny * Nz);
333 {
334 uint64_t c = 0;
335 for (size_t i = 0; i < Ny; ++i)
336 {
337 for (size_t j = 0; j < Nx; ++j)
338 {
339 for (size_t k = 0; k < Nz; ++k)
340 {
341 vertex_ijk_to_i_map[i][j][k] = c++;
342 umesh->GetVertices().emplace_back(
343 vertices_1d_x[j], vertices_1d_y[i], vertices_1d_z[k]);
344 } // for k
345 } // for j
346 } // for i
347 }
348
349 std::vector<VecVecIDs> cells_ijk_to_i_map(Ny - 1);
350 for (auto& vec : cells_ijk_to_i_map)
351 vec.resize(Nx - 1, VecIDs(Nz - 1));
352
353 {
354 uint64_t c = 0;
355 for (size_t i = 0; i < (Ny - 1); ++i)
356 for (size_t j = 0; j < (Nx - 1); ++j)
357 for (size_t k = 0; k < (Nz - 1); ++k)
358 cells_ijk_to_i_map[i][j][k] = c++;
359 }
360
361 //======================================== Create cells
362 auto& vmap = vertex_ijk_to_i_map;
363 auto& cmap = cells_ijk_to_i_map;
364 const size_t max_j = Nx - 2;
365 const size_t max_i = Ny - 2;
366 const size_t max_k = Nz - 2;
367 for (size_t i = 0; i < (Ny - 1); ++i)
368 {
369 for (size_t j = 0; j < (Nx - 1); ++j)
370 {
371 for (size_t k = 0; k < (Nz - 1); ++k)
372 {
375
376 cell->vertex_ids = std::vector<uint64_t>{vmap[i][j][k],
377 vmap[i][j + 1][k],
378 vmap[i + 1][j + 1][k],
379 vmap[i + 1][j][k],
380
381 vmap[i][j][k + 1],
382 vmap[i][j + 1][k + 1],
383 vmap[i + 1][j + 1][k + 1],
384 vmap[i + 1][j][k + 1]};
385
386 // East face
387 {
389
390 face.vertex_ids = std::vector<uint64_t>{vmap[i][j + 1][k],
391 vmap[i + 1][j + 1][k],
392 vmap[i + 1][j + 1][k + 1],
393 vmap[i][j + 1][k + 1]};
394 face.neighbor = (j == max_j) ? 0 /*XMAX*/ : cmap[i][j + 1][k];
395 face.has_neighbor = (j != max_j);
396 cell->faces.push_back(face);
397 }
398 // West face
399 {
401
402 face.vertex_ids = std::vector<uint64_t>{vmap[i][j][k],
403 vmap[i][j][k + 1],
404 vmap[i + 1][j][k + 1],
405 vmap[i + 1][j][k]};
406 face.neighbor = (j == 0) ? 1 /*XMIN*/ : cmap[i][j - 1][k];
407 face.has_neighbor = (j != 0);
408 cell->faces.push_back(face);
409 }
410 // North face
411 {
413
414 face.vertex_ids = std::vector<uint64_t>{vmap[i + 1][j][k],
415 vmap[i + 1][j][k + 1],
416 vmap[i + 1][j + 1][k + 1],
417 vmap[i + 1][j + 1][k]};
418 face.neighbor = (i == max_i) ? 2 /*YMAX*/ : cmap[i + 1][j][k];
419 face.has_neighbor = (i != max_i);
420 cell->faces.push_back(face);
421 }
422 // South face
423 {
425
426 face.vertex_ids = std::vector<uint64_t>{vmap[i][j][k],
427 vmap[i][j + 1][k],
428 vmap[i][j + 1][k + 1],
429 vmap[i][j][k + 1]};
430 face.neighbor = (i == 0) ? 3 /*YMIN*/ : cmap[i - 1][j][k];
431 face.has_neighbor = (i != 0);
432 cell->faces.push_back(face);
433 }
434 // Top face
435 {
437
438 face.vertex_ids = std::vector<uint64_t>{vmap[i][j][k + 1],
439 vmap[i][j + 1][k + 1],
440 vmap[i + 1][j + 1][k + 1],
441 vmap[i + 1][j][k + 1]};
442 face.neighbor = (k == max_k) ? 4 /*ZMAX*/ : cmap[i][j][k + 1];
443 face.has_neighbor = (k != max_k);
444 cell->faces.push_back(face);
445 }
446 // Bottom face
447 {
449
450 face.vertex_ids = std::vector<uint64_t>{vmap[i][j][k],
451 vmap[i + 1][j][k],
452 vmap[i + 1][j + 1][k],
453 vmap[i][j + 1][k]};
454 face.neighbor = (k == 0) ? 5 /*ZMIN*/ : cmap[i][j][k - 1];
455 face.has_neighbor = (k != 0);
456 cell->faces.push_back(face);
457 }
458
459 umesh->AddCell(cell);
460 } // for k
461 } // for j
462 } // for i
463
464 umesh->ComputeCentroidsAndCheckQuality();
465 umesh->BuildMeshConnectivity();
466
467 return umesh;
468}
469
470} // namespace chi_mesh
#define ChiInvalidArgumentIf(condition, message)
#define ChiInvalidArgument(message)
void SetDocGroup(const std::string &doc_group)
void AddRequiredParameterArray(const std::string &name, const std::string &doc_string)
const ParameterBlock & ParametersAtAssignment() const
void SetGeneralDescription(const std::string &description)
void RequireBlockTypeIs(ParameterBlockType type) const
bool Has(const std::string &param_name) const
ParameterBlock & GetParam(const std::string &param_name)
static chi::InputParameters GetInputParameters()
static std::unique_ptr< UnpartitionedMesh > CreateUnpartitioned1DOrthoMesh(const std::vector< double > &vertices)
std::vector< std::vector< double > > node_sets_
static chi::InputParameters GetInputParameters()
std::unique_ptr< UnpartitionedMesh > GenerateUnpartitionedMesh(std::unique_ptr< UnpartitionedMesh > input_umesh) override
OrthogonalMeshGenerator(const chi::InputParameters &params)
static std::unique_ptr< UnpartitionedMesh > CreateUnpartitioned2DOrthoMesh(const std::vector< double > &vertices_1d_x, const std::vector< double > &vertices_1d_y)
static std::unique_ptr< UnpartitionedMesh > CreateUnpartitioned3DOrthoMesh(const std::vector< double > &vertices_1d_x, const std::vector< double > &vertices_1d_y, const std::vector< double > &vertices_1d_z)
RegisterChiObject(chi_mesh, BooleanLogicalVolume)
@ DIMENSION_1
Definition: chi_mesh.h:72
@ DIMENSION_2
Definition: chi_mesh.h:73
@ ORTHOGONAL
Definition: chi_mesh.h:75
@ DIMENSION_3
Definition: chi_mesh.h:74