GooseFEM 1.4.1.dev2+g78f16df
Loading...
Searching...
No Matches
MeshHex8.h
Go to the documentation of this file.
1
9#ifndef GOOSEFEM_MESHHEX8_H
10#define GOOSEFEM_MESHHEX8_H
11
12#include "Mesh.h"
13#include "config.h"
14
15namespace GooseFEM {
16namespace Mesh {
17
21namespace Hex8 {
22
26class Regular : public RegularBase3d<Regular> {
27public:
36 Regular(size_t nelx, size_t nely, size_t nelz, double h = 1.0)
37 {
38 m_h = h;
39 m_nelx = nelx;
40 m_nely = nely;
41 m_nelz = nelz;
42 m_nne = 8;
43 m_ndim = 3;
44
45 GOOSEFEM_ASSERT(m_nelx >= 1ul);
46 GOOSEFEM_ASSERT(m_nely >= 1ul);
47 GOOSEFEM_ASSERT(m_nelz >= 1ul);
48
49 m_nnode = (m_nelx + 1) * (m_nely + 1) * (m_nelz + 1);
50 m_nelem = m_nelx * m_nely * m_nelz;
51 }
52
53private:
54 friend class RegularBase<Regular>;
55 friend class RegularBase3d<Regular>;
56
57 size_t nelx_impl() const
58 {
59 return m_nelx;
60 }
61
62 size_t nely_impl() const
63 {
64 return m_nely;
65 }
66
67 size_t nelz_impl() const
68 {
69 return m_nelz;
70 }
71
72 ElementType elementType_impl() const
73 {
74 return ElementType::Hex8;
75 }
76
77 array_type::tensor<double, 2> coor_impl() const
78 {
79 array_type::tensor<double, 2> ret = xt::empty<double>({m_nnode, m_ndim});
80
81 array_type::tensor<double, 1> x =
82 xt::linspace<double>(0.0, m_h * static_cast<double>(m_nelx), m_nelx + 1);
83 array_type::tensor<double, 1> y =
84 xt::linspace<double>(0.0, m_h * static_cast<double>(m_nely), m_nely + 1);
85 array_type::tensor<double, 1> z =
86 xt::linspace<double>(0.0, m_h * static_cast<double>(m_nelz), m_nelz + 1);
87
88 size_t inode = 0;
89
90 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
91 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
92 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
93 ret(inode, 0) = x(ix);
94 ret(inode, 1) = y(iy);
95 ret(inode, 2) = z(iz);
96 ++inode;
97 }
98 }
99 }
100
101 return ret;
102 }
103
104 array_type::tensor<size_t, 2> conn_impl() const
105 {
106 array_type::tensor<size_t, 2> ret = xt::empty<size_t>({m_nelem, m_nne});
107
108 size_t ielem = 0;
109
110 for (size_t iz = 0; iz < m_nelz; ++iz) {
111 for (size_t iy = 0; iy < m_nely; ++iy) {
112 for (size_t ix = 0; ix < m_nelx; ++ix) {
113 ret(ielem, 0) = iy * (m_nelx + 1) + ix + iz * (m_nely + 1) * (m_nelx + 1);
114 ret(ielem, 1) = iy * (m_nelx + 1) + (ix + 1) + iz * (m_nely + 1) * (m_nelx + 1);
115 ret(ielem, 3) = (iy + 1) * (m_nelx + 1) + ix + iz * (m_nely + 1) * (m_nelx + 1);
116 ret(ielem, 2) =
117 (iy + 1) * (m_nelx + 1) + (ix + 1) + iz * (m_nely + 1) * (m_nelx + 1);
118 ret(ielem, 4) = iy * (m_nelx + 1) + ix + (iz + 1) * (m_nely + 1) * (m_nelx + 1);
119 ret(ielem, 5) =
120 (iy) * (m_nelx + 1) + (ix + 1) + (iz + 1) * (m_nely + 1) * (m_nelx + 1);
121 ret(ielem, 7) =
122 (iy + 1) * (m_nelx + 1) + ix + (iz + 1) * (m_nely + 1) * (m_nelx + 1);
123 ret(ielem, 6) =
124 (iy + 1) * (m_nelx + 1) + (ix + 1) + (iz + 1) * (m_nely + 1) * (m_nelx + 1);
125 ++ielem;
126 }
127 }
128 }
129
130 return ret;
131 }
132
133 array_type::tensor<size_t, 1> nodesFront_impl() const
134 {
135 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nelx + 1) * (m_nely + 1)});
136
137 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
138 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
139 ret(iy * (m_nelx + 1) + ix) = iy * (m_nelx + 1) + ix;
140 }
141 }
142
143 return ret;
144 }
145
146 array_type::tensor<size_t, 1> nodesBack_impl() const
147 {
148 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nelx + 1) * (m_nely + 1)});
149
150 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
151 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
152 ret(iy * (m_nelx + 1) + ix) =
153 iy * (m_nelx + 1) + ix + m_nelz * (m_nely + 1) * (m_nelx + 1);
154 }
155 }
156
157 return ret;
158 }
159
160 array_type::tensor<size_t, 1> nodesLeft_impl() const
161 {
162 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nely + 1) * (m_nelz + 1)});
163
164 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
165 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
166 ret(iz * (m_nely + 1) + iy) = iy * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1);
167 }
168 }
169
170 return ret;
171 }
172
173 array_type::tensor<size_t, 1> nodesRight_impl() const
174 {
175 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nely + 1) * (m_nelz + 1)});
176
177 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
178 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
179 ret(iz * (m_nely + 1) + iy) =
180 iy * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1) + m_nelx;
181 }
182 }
183
184 return ret;
185 }
186
187 array_type::tensor<size_t, 1> nodesBottom_impl() const
188 {
189 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nelx + 1) * (m_nelz + 1)});
190
191 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
192 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
193 ret(iz * (m_nelx + 1) + ix) = ix + iz * (m_nelx + 1) * (m_nely + 1);
194 }
195 }
196
197 return ret;
198 }
199
200 array_type::tensor<size_t, 1> nodesTop_impl() const
201 {
202 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nelx + 1) * (m_nelz + 1)});
203
204 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
205 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
206 ret(iz * (m_nelx + 1) + ix) =
207 ix + m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1);
208 }
209 }
210
211 return ret;
212 }
213
214 array_type::tensor<size_t, 1> nodesFrontFace_impl() const
215 {
216 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nelx - 1) * (m_nely - 1)});
217
218 for (size_t iy = 1; iy < m_nely; ++iy) {
219 for (size_t ix = 1; ix < m_nelx; ++ix) {
220 ret((iy - 1) * (m_nelx - 1) + (ix - 1)) = iy * (m_nelx + 1) + ix;
221 }
222 }
223
224 return ret;
225 }
226
227 array_type::tensor<size_t, 1> nodesBackFace_impl() const
228 {
229 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nelx - 1) * (m_nely - 1)});
230
231 for (size_t iy = 1; iy < m_nely; ++iy) {
232 for (size_t ix = 1; ix < m_nelx; ++ix) {
233 ret((iy - 1) * (m_nelx - 1) + (ix - 1)) =
234 iy * (m_nelx + 1) + ix + m_nelz * (m_nely + 1) * (m_nelx + 1);
235 }
236 }
237
238 return ret;
239 }
240
241 array_type::tensor<size_t, 1> nodesLeftFace_impl() const
242 {
243 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nely - 1) * (m_nelz - 1)});
244
245 for (size_t iz = 1; iz < m_nelz; ++iz) {
246 for (size_t iy = 1; iy < m_nely; ++iy) {
247 ret((iz - 1) * (m_nely - 1) + (iy - 1)) =
248 iy * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1);
249 }
250 }
251
252 return ret;
253 }
254
255 array_type::tensor<size_t, 1> nodesRightFace_impl() const
256 {
257 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nely - 1) * (m_nelz - 1)});
258
259 for (size_t iz = 1; iz < m_nelz; ++iz) {
260 for (size_t iy = 1; iy < m_nely; ++iy) {
261 ret((iz - 1) * (m_nely - 1) + (iy - 1)) =
262 iy * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1) + m_nelx;
263 }
264 }
265
266 return ret;
267 }
268
269 array_type::tensor<size_t, 1> nodesBottomFace_impl() const
270 {
271 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nelx - 1) * (m_nelz - 1)});
272
273 for (size_t iz = 1; iz < m_nelz; ++iz) {
274 for (size_t ix = 1; ix < m_nelx; ++ix) {
275 ret((iz - 1) * (m_nelx - 1) + (ix - 1)) = ix + iz * (m_nelx + 1) * (m_nely + 1);
276 }
277 }
278
279 return ret;
280 }
281
282 array_type::tensor<size_t, 1> nodesTopFace_impl() const
283 {
284 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({(m_nelx - 1) * (m_nelz - 1)});
285
286 for (size_t iz = 1; iz < m_nelz; ++iz) {
287 for (size_t ix = 1; ix < m_nelx; ++ix) {
288 ret((iz - 1) * (m_nelx - 1) + (ix - 1)) =
289 ix + m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1);
290 }
291 }
292
293 return ret;
294 }
295
296 array_type::tensor<size_t, 1> nodesFrontBottomEdge_impl() const
297 {
298 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelx + 1});
299
300 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
301 ret(ix) = ix;
302 }
303
304 return ret;
305 }
306
307 array_type::tensor<size_t, 1> nodesFrontTopEdge_impl() const
308 {
309 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelx + 1});
310
311 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
312 ret(ix) = ix + m_nely * (m_nelx + 1);
313 }
314
315 return ret;
316 }
317
318 array_type::tensor<size_t, 1> nodesFrontLeftEdge_impl() const
319 {
320 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nely + 1});
321
322 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
323 ret(iy) = iy * (m_nelx + 1);
324 }
325
326 return ret;
327 }
328
329 array_type::tensor<size_t, 1> nodesFrontRightEdge_impl() const
330 {
331 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nely + 1});
332
333 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
334 ret(iy) = iy * (m_nelx + 1) + m_nelx;
335 }
336
337 return ret;
338 }
339
340 array_type::tensor<size_t, 1> nodesBackBottomEdge_impl() const
341 {
342 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelx + 1});
343
344 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
345 ret(ix) = ix + m_nelz * (m_nely + 1) * (m_nelx + 1);
346 }
347
348 return ret;
349 }
350
351 array_type::tensor<size_t, 1> nodesBackTopEdge_impl() const
352 {
353 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelx + 1});
354
355 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
356 ret(ix) = m_nely * (m_nelx + 1) + ix + m_nelz * (m_nely + 1) * (m_nelx + 1);
357 }
358
359 return ret;
360 }
361
362 array_type::tensor<size_t, 1> nodesBackLeftEdge_impl() const
363 {
364 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nely + 1});
365
366 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
367 ret(iy) = iy * (m_nelx + 1) + m_nelz * (m_nelx + 1) * (m_nely + 1);
368 }
369
370 return ret;
371 }
372
373 array_type::tensor<size_t, 1> nodesBackRightEdge_impl() const
374 {
375 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nely + 1});
376
377 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
378 ret(iy) = iy * (m_nelx + 1) + m_nelz * (m_nelx + 1) * (m_nely + 1) + m_nelx;
379 }
380
381 return ret;
382 }
383
384 array_type::tensor<size_t, 1> nodesBottomLeftEdge_impl() const
385 {
386 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelz + 1});
387
388 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
389 ret(iz) = iz * (m_nelx + 1) * (m_nely + 1);
390 }
391
392 return ret;
393 }
394
395 array_type::tensor<size_t, 1> nodesBottomRightEdge_impl() const
396 {
397 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelz + 1});
398
399 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
400 ret(iz) = iz * (m_nelx + 1) * (m_nely + 1) + m_nelx;
401 }
402
403 return ret;
404 }
405
406 array_type::tensor<size_t, 1> nodesTopLeftEdge_impl() const
407 {
408 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelz + 1});
409
410 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
411 ret(iz) = m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1);
412 }
413
414 return ret;
415 }
416
417 array_type::tensor<size_t, 1> nodesTopRightEdge_impl() const
418 {
419 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelz + 1});
420
421 for (size_t iz = 0; iz < m_nelz + 1; ++iz) {
422 ret(iz) = m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1) + m_nelx;
423 }
424
425 return ret;
426 }
427
428 array_type::tensor<size_t, 1> nodesFrontBottomOpenEdge_impl() const
429 {
430 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelx - 1});
431
432 for (size_t ix = 1; ix < m_nelx; ++ix) {
433 ret(ix - 1) = ix;
434 }
435
436 return ret;
437 }
438
439 array_type::tensor<size_t, 1> nodesFrontTopOpenEdge_impl() const
440 {
441 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelx - 1});
442
443 for (size_t ix = 1; ix < m_nelx; ++ix) {
444 ret(ix - 1) = ix + m_nely * (m_nelx + 1);
445 }
446
447 return ret;
448 }
449
450 array_type::tensor<size_t, 1> nodesFrontLeftOpenEdge_impl() const
451 {
452 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nely - 1});
453
454 for (size_t iy = 1; iy < m_nely; ++iy) {
455 ret(iy - 1) = iy * (m_nelx + 1);
456 }
457
458 return ret;
459 }
460
461 array_type::tensor<size_t, 1> nodesFrontRightOpenEdge_impl() const
462 {
463 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nely - 1});
464
465 for (size_t iy = 1; iy < m_nely; ++iy) {
466 ret(iy - 1) = iy * (m_nelx + 1) + m_nelx;
467 }
468
469 return ret;
470 }
471
472 array_type::tensor<size_t, 1> nodesBackBottomOpenEdge_impl() const
473 {
474 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelx - 1});
475
476 for (size_t ix = 1; ix < m_nelx; ++ix) {
477 ret(ix - 1) = ix + m_nelz * (m_nely + 1) * (m_nelx + 1);
478 }
479
480 return ret;
481 }
482
483 array_type::tensor<size_t, 1> nodesBackTopOpenEdge_impl() const
484 {
485 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelx - 1});
486
487 for (size_t ix = 1; ix < m_nelx; ++ix) {
488 ret(ix - 1) = m_nely * (m_nelx + 1) + ix + m_nelz * (m_nely + 1) * (m_nelx + 1);
489 }
490
491 return ret;
492 }
493
494 array_type::tensor<size_t, 1> nodesBackLeftOpenEdge_impl() const
495 {
496 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nely - 1});
497
498 for (size_t iy = 1; iy < m_nely; ++iy) {
499 ret(iy - 1) = iy * (m_nelx + 1) + m_nelz * (m_nelx + 1) * (m_nely + 1);
500 }
501
502 return ret;
503 }
504
505 array_type::tensor<size_t, 1> nodesBackRightOpenEdge_impl() const
506 {
507 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nely - 1});
508
509 for (size_t iy = 1; iy < m_nely; ++iy) {
510 ret(iy - 1) = iy * (m_nelx + 1) + m_nelz * (m_nelx + 1) * (m_nely + 1) + m_nelx;
511 }
512
513 return ret;
514 }
515
516 array_type::tensor<size_t, 1> nodesBottomLeftOpenEdge_impl() const
517 {
518 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelz - 1});
519
520 for (size_t iz = 1; iz < m_nelz; ++iz) {
521 ret(iz - 1) = iz * (m_nelx + 1) * (m_nely + 1);
522 }
523
524 return ret;
525 }
526
527 array_type::tensor<size_t, 1> nodesBottomRightOpenEdge_impl() const
528 {
529 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelz - 1});
530
531 for (size_t iz = 1; iz < m_nelz; ++iz) {
532 ret(iz - 1) = iz * (m_nelx + 1) * (m_nely + 1) + m_nelx;
533 }
534
535 return ret;
536 }
537
538 array_type::tensor<size_t, 1> nodesTopLeftOpenEdge_impl() const
539 {
540 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelz - 1});
541
542 for (size_t iz = 1; iz < m_nelz; ++iz) {
543 ret(iz - 1) = m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1);
544 }
545
546 return ret;
547 }
548
549 array_type::tensor<size_t, 1> nodesTopRightOpenEdge_impl() const
550 {
551 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelz - 1});
552
553 for (size_t iz = 1; iz < m_nelz; ++iz) {
554 ret(iz - 1) = m_nely * (m_nelx + 1) + iz * (m_nelx + 1) * (m_nely + 1) + m_nelx;
555 }
556
557 return ret;
558 }
559
560 size_t nodesFrontBottomLeftCorner_impl() const
561 {
562 return 0;
563 }
564
565 size_t nodesFrontBottomRightCorner_impl() const
566 {
567 return m_nelx;
568 }
569
570 size_t nodesFrontTopLeftCorner_impl() const
571 {
572 return m_nely * (m_nelx + 1);
573 }
574
575 size_t nodesFrontTopRightCorner_impl() const
576 {
577 return m_nely * (m_nelx + 1) + m_nelx;
578 }
579
580 size_t nodesBackBottomLeftCorner_impl() const
581 {
582 return m_nelz * (m_nely + 1) * (m_nelx + 1);
583 }
584
585 size_t nodesBackBottomRightCorner_impl() const
586 {
587 return m_nelx + m_nelz * (m_nely + 1) * (m_nelx + 1);
588 }
589
590 size_t nodesBackTopLeftCorner_impl() const
591 {
592 return m_nely * (m_nelx + 1) + m_nelz * (m_nely + 1) * (m_nelx + 1);
593 }
594
595 size_t nodesBackTopRightCorner_impl() const
596 {
597 return m_nely * (m_nelx + 1) + m_nelx + m_nelz * (m_nely + 1) * (m_nelx + 1);
598 }
599
600 double m_h;
601 size_t m_nelx;
602 size_t m_nely;
603 size_t m_nelz;
604 size_t m_nelem;
605 size_t m_nnode;
606 size_t m_nne;
607 size_t m_ndim;
608};
609
613class FineLayer : public RegularBase3d<FineLayer> {
614public:
627 FineLayer(size_t nelx, size_t nely, size_t nelz, double h = 1.0, size_t nfine = 1)
628 {
629 m_h = h;
630 m_nne = 8;
631 m_ndim = 3;
632
633 // basic assumptions
634 GOOSEFEM_ASSERT(nelx >= 1ul);
635 GOOSEFEM_ASSERT(nely >= 1ul);
636 GOOSEFEM_ASSERT(nelz >= 1ul);
637
638 // store basic info
639 m_Lx = m_h * static_cast<double>(nelx);
640 m_Lz = m_h * static_cast<double>(nelz);
641
642 // compute element size in y-direction (use symmetry, compute upper half)
643
644 // temporary variables
645 size_t nmin, ntot;
646 array_type::tensor<size_t, 1> nhx = xt::ones<size_t>({nely});
647 array_type::tensor<size_t, 1> nhy = xt::ones<size_t>({nely});
648 array_type::tensor<size_t, 1> nhz = xt::ones<size_t>({nely});
649 array_type::tensor<int, 1> refine = -1 * xt::ones<int>({nely});
650
651 // minimum height in y-direction (half of the height because of symmetry)
652 if (nely % 2 == 0) {
653 nmin = nely / 2;
654 }
655 else {
656 nmin = (nely + 1) / 2;
657 }
658
659 // minimum number of fine layers in y-direction (minimum 1, middle layer part of this half)
660 if (nfine % 2 == 0) {
661 nfine = nfine / 2 + 1;
662 }
663 else {
664 nfine = (nfine + 1) / 2;
665 }
666
667 if (nfine < 1) {
668 nfine = 1;
669 }
670
671 if (nfine > nmin) {
672 nfine = nmin;
673 }
674
675 // loop over element layers in y-direction, try to coarsen using these rules:
676 // (1) element size in y-direction <= distance to origin in y-direction
677 // (2) element size in x-(z-)direction should fit the total number of elements in
678 // x-(z-)direction (3) a certain number of layers have the minimum size "1" (are fine)
679 for (size_t iy = nfine;;) {
680 // initialize current size in y-direction
681 if (iy == nfine) {
682 ntot = nfine;
683 }
684 // check to stop
685 if (iy >= nely || ntot >= nmin) {
686 nely = iy;
687 break;
688 }
689
690 // rules (1,2) satisfied: coarsen in x-direction (and z-direction)
691 if (3 * nhy(iy) <= ntot && nelx % (3 * nhx(iy)) == 0 && ntot + nhy(iy) < nmin) {
692 // - process refinement in x-direction
693 refine(iy) = 0;
694 nhy(iy) *= 2;
695 auto vnhy = xt::view(nhy, xt::range(iy + 1, _));
696 auto vnhx = xt::view(nhx, xt::range(iy, _));
697 vnhy *= 3;
698 vnhx *= 3;
699
700 // - rule (2) satisfied: coarsen next element layer in z-direction
701 if (iy + 1 < nely && ntot + 2 * nhy(iy) < nmin) {
702 if (nelz % (3 * nhz(iy + 1)) == 0) {
703 // - update the number of elements in y-direction
704 ntot += nhy(iy);
705 // - proceed to next element layer in y-direction
706 ++iy;
707 // - process refinement in z-direction
708 refine(iy) = 2;
709 nhy(iy) = nhy(iy - 1);
710 auto vnhz = xt::view(nhz, xt::range(iy, _));
711 vnhz *= 3;
712 }
713 }
714 }
715
716 // rules (1,2) satisfied: coarse in z-direction
717 else if (3 * nhy(iy) <= ntot && nelz % (3 * nhz(iy)) == 0 && ntot + nhy(iy) < nmin) {
718 // - process refinement in z-direction
719 refine(iy) = 2;
720 nhy(iy) *= 2;
721 auto vnhy = xt::view(nhy, xt::range(iy + 1, _));
722 auto vnhz = xt::view(nhz, xt::range(iy, _));
723 vnhy *= 3;
724 vnhz *= 3;
725 }
726
727 // update the number of elements in y-direction
728 ntot += nhy(iy);
729 // proceed to next element layer in y-direction
730 ++iy;
731 // check to stop
732 if (iy >= nely || ntot >= nmin) {
733 nely = iy;
734 break;
735 }
736 }
737
738 // symmetrize, compute full information
739
740 // allocate mesh constructor parameters
741 m_nhx = xt::empty<size_t>({nely * 2 - 1});
742 m_nhy = xt::empty<size_t>({nely * 2 - 1});
743 m_nhz = xt::empty<size_t>({nely * 2 - 1});
744 m_refine = xt::empty<int>({nely * 2 - 1});
745 m_layer_nelx = xt::empty<size_t>({nely * 2 - 1});
746 m_layer_nelz = xt::empty<size_t>({nely * 2 - 1});
747 m_nnd = xt::empty<size_t>({nely * 2});
748 m_startElem = xt::empty<size_t>({nely * 2 - 1});
749 m_startNode = xt::empty<size_t>({nely * 2});
750
751 // fill
752 // - lower half
753 for (size_t iy = 0; iy < nely; ++iy) {
754 m_nhx(iy) = nhx(nely - iy - 1);
755 m_nhy(iy) = nhy(nely - iy - 1);
756 m_nhz(iy) = nhz(nely - iy - 1);
757 m_refine(iy) = refine(nely - iy - 1);
758 }
759 // - upper half
760 for (size_t iy = 0; iy < nely - 1; ++iy) {
761 m_nhx(iy + nely) = nhx(iy + 1);
762 m_nhy(iy + nely) = nhy(iy + 1);
763 m_nhz(iy + nely) = nhz(iy + 1);
764 m_refine(iy + nely) = refine(iy + 1);
765 }
766
767 // update size
768 nely = m_nhx.size();
769
770 // compute the number of elements per element layer in y-direction
771 for (size_t iy = 0; iy < nely; ++iy) {
772 m_layer_nelx(iy) = nelx / m_nhx(iy);
773 m_layer_nelz(iy) = nelz / m_nhz(iy);
774 }
775
776 // compute the number of nodes per node layer in y-direction
777 // - bottom half
778 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy)
779 m_nnd(iy) = (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy) + 1);
780 // - top half
781 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy)
782 m_nnd(iy + 1) = (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy) + 1);
783
784 // compute mesh dimensions
785
786 // initialize
787 m_nnode = 0;
788 m_nelem = 0;
789 m_startNode(0) = 0;
790
791 // loop over element layers (bottom -> middle, elements become finer)
792 for (size_t i = 0; i < (nely - 1) / 2; ++i) {
793 // - store the first element of the layer
794 m_startElem(i) = m_nelem;
795 // - add the nodes of this layer
796 if (m_refine(i) == 0) {
797 m_nnode += (3 * m_layer_nelx(i) + 1) * (m_layer_nelz(i) + 1);
798 }
799 else if (m_refine(i) == 2) {
800 m_nnode += (m_layer_nelx(i) + 1) * (3 * m_layer_nelz(i) + 1);
801 }
802 else {
803 m_nnode += (m_layer_nelx(i) + 1) * (m_layer_nelz(i) + 1);
804 }
805 // - add the elements of this layer
806 if (m_refine(i) == 0) {
807 m_nelem += (4 * m_layer_nelx(i)) * (m_layer_nelz(i));
808 }
809 else if (m_refine(i) == 2) {
810 m_nelem += (m_layer_nelx(i)) * (4 * m_layer_nelz(i));
811 }
812 else {
813 m_nelem += (m_layer_nelx(i)) * (m_layer_nelz(i));
814 }
815 // - store the starting node of the next layer
816 m_startNode(i + 1) = m_nnode;
817 }
818
819 // loop over element layers (middle -> top, elements become coarser)
820 for (size_t i = (nely - 1) / 2; i < nely; ++i) {
821 // - store the first element of the layer
822 m_startElem(i) = m_nelem;
823 // - add the nodes of this layer
824 if (m_refine(i) == 0) {
825 m_nnode += (5 * m_layer_nelx(i) + 1) * (m_layer_nelz(i) + 1);
826 }
827 else if (m_refine(i) == 2) {
828 m_nnode += (m_layer_nelx(i) + 1) * (5 * m_layer_nelz(i) + 1);
829 }
830 else {
831 m_nnode += (m_layer_nelx(i) + 1) * (m_layer_nelz(i) + 1);
832 }
833 // - add the elements of this layer
834 if (m_refine(i) == 0) {
835 m_nelem += (4 * m_layer_nelx(i)) * (m_layer_nelz(i));
836 }
837 else if (m_refine(i) == 2) {
838 m_nelem += (m_layer_nelx(i)) * (4 * m_layer_nelz(i));
839 }
840 else {
841 m_nelem += (m_layer_nelx(i)) * (m_layer_nelz(i));
842 }
843 // - store the starting node of the next layer
844 m_startNode(i + 1) = m_nnode;
845 }
846 // - add the top row of nodes
847 m_nnode += (m_layer_nelx(nely - 1) + 1) * (m_layer_nelz(nely - 1) + 1);
848 }
849
855 {
856 size_t nely = static_cast<size_t>(m_nhy.size());
857 size_t y = (nely - 1) / 2;
858
859 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(y) * m_layer_nelz(y)});
860
861 for (size_t x = 0; x < m_layer_nelx(y); ++x) {
862 for (size_t z = 0; z < m_layer_nelz(y); ++z) {
863 ret(x + z * m_layer_nelx(y)) = m_startElem(y) + x + z * m_layer_nelx(y);
864 }
865 }
866
867 return ret;
868 }
869
870private:
871 friend class RegularBase<FineLayer>;
872 friend class RegularBase3d<FineLayer>;
873
874 size_t nelx_impl() const
875 {
876 return xt::amax(m_layer_nelx)();
877 }
878
879 size_t nely_impl() const
880 {
881 return xt::sum(m_nhy)();
882 }
883
884 size_t nelz_impl() const
885 {
886 return xt::amax(m_layer_nelz)();
887 }
888 ElementType elementType_impl() const
889 {
890 return ElementType::Hex8;
891 }
892
893 array_type::tensor<double, 2> coor_impl() const
894 {
895 // allocate output
896 array_type::tensor<double, 2> ret = xt::empty<double>({m_nnode, m_ndim});
897
898 // current node, number of element layers
899 size_t inode = 0;
900 size_t nely = static_cast<size_t>(m_nhy.size());
901
902 // y-position of each main node layer (i.e. excluding node layers for refinement/coarsening)
903 // - allocate
904 array_type::tensor<double, 1> y = xt::empty<double>({nely + 1});
905 // - initialize
906 y(0) = 0.0;
907 // - compute
908 for (size_t iy = 1; iy < nely + 1; ++iy) {
909 y(iy) = y(iy - 1) + m_nhy(iy - 1) * m_h;
910 }
911
912 // loop over element layers (bottom -> middle) : add bottom layer (+ refinement layer) of
913 // nodes
914
915 for (size_t iy = 0;; ++iy) {
916 // get positions along the x- and z-axis
917 array_type::tensor<double, 1> x = xt::linspace<double>(0.0, m_Lx, m_layer_nelx(iy) + 1);
918 array_type::tensor<double, 1> z = xt::linspace<double>(0.0, m_Lz, m_layer_nelz(iy) + 1);
919
920 // add nodes of the bottom layer of this element
921 for (size_t iz = 0; iz < m_layer_nelz(iy) + 1; ++iz) {
922 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
923 ret(inode, 0) = x(ix);
924 ret(inode, 1) = y(iy);
925 ret(inode, 2) = z(iz);
926 ++inode;
927 }
928 }
929
930 // stop at middle layer
931 if (iy == (nely - 1) / 2) {
932 break;
933 }
934
935 // add extra nodes of the intermediate layer, for refinement in x-direction
936 if (m_refine(iy) == 0) {
937 // - get position offset in x- and y-direction
938 double dx = m_h * static_cast<double>(m_nhx(iy) / 3);
939 double dy = m_h * static_cast<double>(m_nhy(iy) / 2);
940 // - add nodes of the intermediate layer
941 for (size_t iz = 0; iz < m_layer_nelz(iy) + 1; ++iz) {
942 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
943 for (size_t j = 0; j < 2; ++j) {
944 ret(inode, 0) = x(ix) + dx * static_cast<double>(j + 1);
945 ret(inode, 1) = y(iy) + dy;
946 ret(inode, 2) = z(iz);
947 ++inode;
948 }
949 }
950 }
951 }
952
953 // add extra nodes of the intermediate layer, for refinement in z-direction
954 else if (m_refine(iy) == 2) {
955 // - get position offset in y- and z-direction
956 double dz = m_h * static_cast<double>(m_nhz(iy) / 3);
957 double dy = m_h * static_cast<double>(m_nhy(iy) / 2);
958 // - add nodes of the intermediate layer
959 for (size_t iz = 0; iz < m_layer_nelz(iy); ++iz) {
960 for (size_t j = 0; j < 2; ++j) {
961 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
962 ret(inode, 0) = x(ix);
963 ret(inode, 1) = y(iy) + dy;
964 ret(inode, 2) = z(iz) + dz * static_cast<double>(j + 1);
965 ++inode;
966 }
967 }
968 }
969 }
970 }
971
972 // loop over element layers (middle -> top) : add (refinement layer +) top layer of nodes
973
974 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
975 // get positions along the x- and z-axis
976 array_type::tensor<double, 1> x = xt::linspace<double>(0.0, m_Lx, m_layer_nelx(iy) + 1);
977 array_type::tensor<double, 1> z = xt::linspace<double>(0.0, m_Lz, m_layer_nelz(iy) + 1);
978
979 // add extra nodes of the intermediate layer, for refinement in x-direction
980 if (m_refine(iy) == 0) {
981 // - get position offset in x- and y-direction
982 double dx = m_h * static_cast<double>(m_nhx(iy) / 3);
983 double dy = m_h * static_cast<double>(m_nhy(iy) / 2);
984 // - add nodes of the intermediate layer
985 for (size_t iz = 0; iz < m_layer_nelz(iy) + 1; ++iz) {
986 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
987 for (size_t j = 0; j < 2; ++j) {
988 ret(inode, 0) = x(ix) + dx * static_cast<double>(j + 1);
989 ret(inode, 1) = y(iy) + dy;
990 ret(inode, 2) = z(iz);
991 ++inode;
992 }
993 }
994 }
995 }
996
997 // add extra nodes of the intermediate layer, for refinement in z-direction
998 else if (m_refine(iy) == 2) {
999 // - get position offset in y- and z-direction
1000 double dz = m_h * static_cast<double>(m_nhz(iy) / 3);
1001 double dy = m_h * static_cast<double>(m_nhy(iy) / 2);
1002 // - add nodes of the intermediate layer
1003 for (size_t iz = 0; iz < m_layer_nelz(iy); ++iz) {
1004 for (size_t j = 0; j < 2; ++j) {
1005 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
1006 ret(inode, 0) = x(ix);
1007 ret(inode, 1) = y(iy) + dy;
1008 ret(inode, 2) = z(iz) + dz * static_cast<double>(j + 1);
1009 ++inode;
1010 }
1011 }
1012 }
1013 }
1014
1015 // add nodes of the top layer of this element
1016 for (size_t iz = 0; iz < m_layer_nelz(iy) + 1; ++iz) {
1017 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
1018 ret(inode, 0) = x(ix);
1019 ret(inode, 1) = y(iy + 1);
1020 ret(inode, 2) = z(iz);
1021 ++inode;
1022 }
1023 }
1024 }
1025
1026 return ret;
1027 }
1028
1029 array_type::tensor<size_t, 2> conn_impl() const
1030 {
1031 // allocate output
1032 array_type::tensor<size_t, 2> ret = xt::empty<size_t>({m_nelem, m_nne});
1033
1034 // current element, number of element layers, starting nodes of each node layer
1035 size_t ielem = 0;
1036 size_t nely = static_cast<size_t>(m_nhy.size());
1037 size_t bot, mid, top;
1038
1039 // loop over all element layers
1040 for (size_t iy = 0; iy < nely; ++iy) {
1041 // - get: starting nodes of bottom(, middle) and top layer
1042 bot = m_startNode(iy);
1043 mid = m_startNode(iy) + m_nnd(iy);
1044 top = m_startNode(iy + 1);
1045
1046 // - define connectivity: no coarsening/refinement
1047 if (m_refine(iy) == -1) {
1048 for (size_t iz = 0; iz < m_layer_nelz(iy); ++iz) {
1049 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
1050 ret(ielem, 0) = bot + ix + iz * (m_layer_nelx(iy) + 1);
1051 ret(ielem, 1) = bot + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1052 ret(ielem, 2) = top + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1053 ret(ielem, 3) = top + ix + iz * (m_layer_nelx(iy) + 1);
1054 ret(ielem, 4) = bot + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1055 ret(ielem, 5) = bot + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1056 ret(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1057 ret(ielem, 7) = top + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1058 ielem++;
1059 }
1060 }
1061 }
1062
1063 // - define connectivity: refinement along the x-direction (below the middle layer)
1064 else if (m_refine(iy) == 0 && iy <= (nely - 1) / 2) {
1065 for (size_t iz = 0; iz < m_layer_nelz(iy); ++iz) {
1066 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
1067 // -- bottom element
1068 ret(ielem, 0) = bot + ix + iz * (m_layer_nelx(iy) + 1);
1069 ret(ielem, 1) = bot + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1070 ret(ielem, 2) = mid + (2 * ix + 1) + iz * (2 * m_layer_nelx(iy));
1071 ret(ielem, 3) = mid + (2 * ix) + iz * (2 * m_layer_nelx(iy));
1072 ret(ielem, 4) = bot + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1073 ret(ielem, 5) = bot + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1074 ret(ielem, 6) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_layer_nelx(iy));
1075 ret(ielem, 7) = mid + (2 * ix) + (iz + 1) * (2 * m_layer_nelx(iy));
1076 ielem++;
1077 // -- top-right element
1078 ret(ielem, 0) = bot + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1079 ret(ielem, 1) = top + (3 * ix + 3) + iz * (3 * m_layer_nelx(iy) + 1);
1080 ret(ielem, 2) = top + (3 * ix + 2) + iz * (3 * m_layer_nelx(iy) + 1);
1081 ret(ielem, 3) = mid + (2 * ix + 1) + iz * (2 * m_layer_nelx(iy));
1082 ret(ielem, 4) = bot + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1083 ret(ielem, 5) = top + (3 * ix + 3) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1084 ret(ielem, 6) = top + (3 * ix + 2) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1085 ret(ielem, 7) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_layer_nelx(iy));
1086 ielem++;
1087 // -- top-center element
1088 ret(ielem, 0) = mid + (2 * ix) + iz * (2 * m_layer_nelx(iy));
1089 ret(ielem, 1) = mid + (2 * ix + 1) + iz * (2 * m_layer_nelx(iy));
1090 ret(ielem, 2) = top + (3 * ix + 2) + iz * (3 * m_layer_nelx(iy) + 1);
1091 ret(ielem, 3) = top + (3 * ix + 1) + iz * (3 * m_layer_nelx(iy) + 1);
1092 ret(ielem, 4) = mid + (2 * ix) + (iz + 1) * (2 * m_layer_nelx(iy));
1093 ret(ielem, 5) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_layer_nelx(iy));
1094 ret(ielem, 6) = top + (3 * ix + 2) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1095 ret(ielem, 7) = top + (3 * ix + 1) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1096 ielem++;
1097 // -- top-left element
1098 ret(ielem, 0) = bot + ix + iz * (m_layer_nelx(iy) + 1);
1099 ret(ielem, 1) = mid + (2 * ix) + iz * (2 * m_layer_nelx(iy));
1100 ret(ielem, 2) = top + (3 * ix + 1) + iz * (3 * m_layer_nelx(iy) + 1);
1101 ret(ielem, 3) = top + (3 * ix) + iz * (3 * m_layer_nelx(iy) + 1);
1102 ret(ielem, 4) = bot + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1103 ret(ielem, 5) = mid + (2 * ix) + (iz + 1) * (2 * m_layer_nelx(iy));
1104 ret(ielem, 6) = top + (3 * ix + 1) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1105 ret(ielem, 7) = top + (3 * ix) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1106 ielem++;
1107 }
1108 }
1109 }
1110
1111 // - define connectivity: coarsening along the x-direction (above the middle layer)
1112 else if (m_refine(iy) == 0 && iy > (nely - 1) / 2) {
1113 for (size_t iz = 0; iz < m_layer_nelz(iy); ++iz) {
1114 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
1115 // -- lower-left element
1116 ret(ielem, 0) = bot + (3 * ix) + iz * (3 * m_layer_nelx(iy) + 1);
1117 ret(ielem, 1) = bot + (3 * ix + 1) + iz * (3 * m_layer_nelx(iy) + 1);
1118 ret(ielem, 2) = mid + (2 * ix) + iz * (2 * m_layer_nelx(iy));
1119 ret(ielem, 3) = top + ix + iz * (m_layer_nelx(iy) + 1);
1120 ret(ielem, 4) = bot + (3 * ix) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1121 ret(ielem, 5) = bot + (3 * ix + 1) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1122 ret(ielem, 6) = mid + (2 * ix) + (iz + 1) * (2 * m_layer_nelx(iy));
1123 ret(ielem, 7) = top + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1124 ielem++;
1125 // -- lower-center element
1126 ret(ielem, 0) = bot + (3 * ix + 1) + iz * (3 * m_layer_nelx(iy) + 1);
1127 ret(ielem, 1) = bot + (3 * ix + 2) + iz * (3 * m_layer_nelx(iy) + 1);
1128 ret(ielem, 2) = mid + (2 * ix + 1) + iz * (2 * m_layer_nelx(iy));
1129 ret(ielem, 3) = mid + (2 * ix) + iz * (2 * m_layer_nelx(iy));
1130 ret(ielem, 4) = bot + (3 * ix + 1) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1131 ret(ielem, 5) = bot + (3 * ix + 2) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1132 ret(ielem, 6) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_layer_nelx(iy));
1133 ret(ielem, 7) = mid + (2 * ix) + (iz + 1) * (2 * m_layer_nelx(iy));
1134 ielem++;
1135 // -- lower-right element
1136 ret(ielem, 0) = bot + (3 * ix + 2) + iz * (3 * m_layer_nelx(iy) + 1);
1137 ret(ielem, 1) = bot + (3 * ix + 3) + iz * (3 * m_layer_nelx(iy) + 1);
1138 ret(ielem, 2) = top + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1139 ret(ielem, 3) = mid + (2 * ix + 1) + iz * (2 * m_layer_nelx(iy));
1140 ret(ielem, 4) = bot + (3 * ix + 2) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1141 ret(ielem, 5) = bot + (3 * ix + 3) + (iz + 1) * (3 * m_layer_nelx(iy) + 1);
1142 ret(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1143 ret(ielem, 7) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_layer_nelx(iy));
1144 ielem++;
1145 // -- upper element
1146 ret(ielem, 0) = mid + (2 * ix) + iz * (2 * m_layer_nelx(iy));
1147 ret(ielem, 1) = mid + (2 * ix + 1) + iz * (2 * m_layer_nelx(iy));
1148 ret(ielem, 2) = top + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1149 ret(ielem, 3) = top + ix + iz * (m_layer_nelx(iy) + 1);
1150 ret(ielem, 4) = mid + (2 * ix) + (iz + 1) * (2 * m_layer_nelx(iy));
1151 ret(ielem, 5) = mid + (2 * ix + 1) + (iz + 1) * (2 * m_layer_nelx(iy));
1152 ret(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1153 ret(ielem, 7) = top + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1154 ielem++;
1155 }
1156 }
1157 }
1158
1159 // - define connectivity: refinement along the z-direction (below the middle layer)
1160 else if (m_refine(iy) == 2 && iy <= (nely - 1) / 2) {
1161 for (size_t iz = 0; iz < m_layer_nelz(iy); ++iz) {
1162 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
1163 // -- bottom element
1164 ret(ielem, 0) = bot + ix + iz * (m_layer_nelx(iy) + 1);
1165 ret(ielem, 1) = bot + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1166 ret(ielem, 2) = bot + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1167 ret(ielem, 3) = bot + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1168 ret(ielem, 4) = mid + ix + 2 * iz * (m_layer_nelx(iy) + 1);
1169 ret(ielem, 5) = mid + ix + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1170 ret(ielem, 6) = mid + (ix + 1) + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1171 ret(ielem, 7) = mid + (ix + 1) + 2 * iz * (m_layer_nelx(iy) + 1);
1172 ielem++;
1173 // -- top-back element
1174 ret(ielem, 0) = mid + ix + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1175 ret(ielem, 1) = mid + (ix + 1) + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1176 ret(ielem, 2) = top + (ix + 1) + (3 * iz + 2) * (m_layer_nelx(iy) + 1);
1177 ret(ielem, 3) = top + ix + (3 * iz + 2) * (m_layer_nelx(iy) + 1);
1178 ret(ielem, 4) = bot + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1179 ret(ielem, 5) = bot + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1180 ret(ielem, 6) = top + (ix + 1) + (3 * iz + 3) * (m_layer_nelx(iy) + 1);
1181 ret(ielem, 7) = top + ix + (3 * iz + 3) * (m_layer_nelx(iy) + 1);
1182 ielem++;
1183 // -- top-center element
1184 ret(ielem, 0) = mid + ix + (2 * iz) * (m_layer_nelx(iy) + 1);
1185 ret(ielem, 1) = mid + (ix + 1) + (2 * iz) * (m_layer_nelx(iy) + 1);
1186 ret(ielem, 2) = top + (ix + 1) + (3 * iz + 1) * (m_layer_nelx(iy) + 1);
1187 ret(ielem, 3) = top + ix + (3 * iz + 1) * (m_layer_nelx(iy) + 1);
1188 ret(ielem, 4) = mid + ix + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1189 ret(ielem, 5) = mid + (ix + 1) + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1190 ret(ielem, 6) = top + (ix + 1) + (3 * iz + 2) * (m_layer_nelx(iy) + 1);
1191 ret(ielem, 7) = top + ix + (3 * iz + 2) * (m_layer_nelx(iy) + 1);
1192 ielem++;
1193 // -- top-front element
1194 ret(ielem, 0) = bot + ix + iz * (m_layer_nelx(iy) + 1);
1195 ret(ielem, 1) = bot + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1196 ret(ielem, 2) = top + (ix + 1) + (3 * iz) * (m_layer_nelx(iy) + 1);
1197 ret(ielem, 3) = top + ix + (3 * iz) * (m_layer_nelx(iy) + 1);
1198 ret(ielem, 4) = mid + ix + (2 * iz) * (m_layer_nelx(iy) + 1);
1199 ret(ielem, 5) = mid + (ix + 1) + (2 * iz) * (m_layer_nelx(iy) + 1);
1200 ret(ielem, 6) = top + (ix + 1) + (3 * iz + 1) * (m_layer_nelx(iy) + 1);
1201 ret(ielem, 7) = top + ix + (3 * iz + 1) * (m_layer_nelx(iy) + 1);
1202 ielem++;
1203 }
1204 }
1205 }
1206
1207 // - define connectivity: coarsening along the z-direction (above the middle layer)
1208 else if (m_refine(iy) == 2 && iy > (nely - 1) / 2) {
1209 for (size_t iz = 0; iz < m_layer_nelz(iy); ++iz) {
1210 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
1211 // -- bottom-front element
1212 ret(ielem, 0) = bot + ix + (3 * iz) * (m_layer_nelx(iy) + 1);
1213 ret(ielem, 1) = bot + (ix + 1) + (3 * iz) * (m_layer_nelx(iy) + 1);
1214 ret(ielem, 2) = top + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1215 ret(ielem, 3) = top + ix + iz * (m_layer_nelx(iy) + 1);
1216 ret(ielem, 4) = bot + ix + (3 * iz + 1) * (m_layer_nelx(iy) + 1);
1217 ret(ielem, 5) = bot + (ix + 1) + (3 * iz + 1) * (m_layer_nelx(iy) + 1);
1218 ret(ielem, 6) = mid + (ix + 1) + (2 * iz) * (m_layer_nelx(iy) + 1);
1219 ret(ielem, 7) = mid + ix + (2 * iz) * (m_layer_nelx(iy) + 1);
1220 ielem++;
1221 // -- bottom-center element
1222 ret(ielem, 0) = bot + ix + (3 * iz + 1) * (m_layer_nelx(iy) + 1);
1223 ret(ielem, 1) = bot + (ix + 1) + (3 * iz + 1) * (m_layer_nelx(iy) + 1);
1224 ret(ielem, 2) = mid + (ix + 1) + (2 * iz) * (m_layer_nelx(iy) + 1);
1225 ret(ielem, 3) = mid + ix + (2 * iz) * (m_layer_nelx(iy) + 1);
1226 ret(ielem, 4) = bot + ix + (3 * iz + 2) * (m_layer_nelx(iy) + 1);
1227 ret(ielem, 5) = bot + (ix + 1) + (3 * iz + 2) * (m_layer_nelx(iy) + 1);
1228 ret(ielem, 6) = mid + (ix + 1) + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1229 ret(ielem, 7) = mid + ix + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1230 ielem++;
1231 // -- bottom-back element
1232 ret(ielem, 0) = bot + ix + (3 * iz + 2) * (m_layer_nelx(iy) + 1);
1233 ret(ielem, 1) = bot + (ix + 1) + (3 * iz + 2) * (m_layer_nelx(iy) + 1);
1234 ret(ielem, 2) = mid + (ix + 1) + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1235 ret(ielem, 3) = mid + ix + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1236 ret(ielem, 4) = bot + ix + (3 * iz + 3) * (m_layer_nelx(iy) + 1);
1237 ret(ielem, 5) = bot + (ix + 1) + (3 * iz + 3) * (m_layer_nelx(iy) + 1);
1238 ret(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1239 ret(ielem, 7) = top + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1240 ielem++;
1241 // -- top element
1242 ret(ielem, 0) = mid + ix + (2 * iz) * (m_layer_nelx(iy) + 1);
1243 ret(ielem, 1) = mid + (ix + 1) + (2 * iz) * (m_layer_nelx(iy) + 1);
1244 ret(ielem, 2) = top + (ix + 1) + iz * (m_layer_nelx(iy) + 1);
1245 ret(ielem, 3) = top + ix + iz * (m_layer_nelx(iy) + 1);
1246 ret(ielem, 4) = mid + ix + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1247 ret(ielem, 5) = mid + (ix + 1) + (2 * iz + 1) * (m_layer_nelx(iy) + 1);
1248 ret(ielem, 6) = top + (ix + 1) + (iz + 1) * (m_layer_nelx(iy) + 1);
1249 ret(ielem, 7) = top + ix + (iz + 1) * (m_layer_nelx(iy) + 1);
1250 ielem++;
1251 }
1252 }
1253 }
1254 }
1255
1256 return ret;
1257 }
1258
1259 array_type::tensor<size_t, 1> nodesFront_impl() const
1260 {
1261 // number of element layers in y-direction
1262 size_t nely = static_cast<size_t>(m_nhy.size());
1263
1264 // number of boundary nodes
1265 // - initialize
1266 size_t n = 0;
1267 // - bottom half: bottom node layer (+ middle node layer)
1268 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1269 if (m_refine(iy) == 0) {
1270 n += m_layer_nelx(iy) * 3 + 1;
1271 }
1272 else {
1273 n += m_layer_nelx(iy) + 1;
1274 }
1275 }
1276 // - top half: (middle node layer +) top node layer
1277 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1278 if (m_refine(iy) == 0) {
1279 n += m_layer_nelx(iy) * 3 + 1;
1280 }
1281 else {
1282 n += m_layer_nelx(iy) + 1;
1283 }
1284 }
1285
1286 // allocate node-list
1287 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({n});
1288
1289 // initialize counter: current index in the node-list "ret"
1290 size_t j = 0;
1291
1292 // bottom half: bottom node layer (+ middle node layer)
1293 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1294 // -- bottom node layer
1295 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
1296 ret(j) = m_startNode(iy) + ix;
1297 ++j;
1298 }
1299 // -- refinement layer
1300 if (m_refine(iy) == 0) {
1301 for (size_t ix = 0; ix < 2 * m_layer_nelx(iy); ++ix) {
1302 ret(j) = m_startNode(iy) + ix + m_nnd(iy);
1303 ++j;
1304 }
1305 }
1306 }
1307
1308 // top half: (middle node layer +) top node layer
1309 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1310 // -- refinement layer
1311 if (m_refine(iy) == 0) {
1312 for (size_t ix = 0; ix < 2 * m_layer_nelx(iy); ++ix) {
1313 ret(j) = m_startNode(iy) + ix + m_nnd(iy);
1314 ++j;
1315 }
1316 }
1317 // -- top node layer
1318 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
1319 ret(j) = m_startNode(iy + 1) + ix;
1320 ++j;
1321 }
1322 }
1323
1324 return ret;
1325 }
1326
1327 array_type::tensor<size_t, 1> nodesBack_impl() const
1328 {
1329 // number of element layers in y-direction
1330 size_t nely = static_cast<size_t>(m_nhy.size());
1331
1332 // number of boundary nodes
1333 // - initialize
1334 size_t n = 0;
1335 // - bottom half: bottom node layer (+ middle node layer)
1336 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1337 if (m_refine(iy) == 0) {
1338 n += m_layer_nelx(iy) * 3 + 1;
1339 }
1340 else {
1341 n += m_layer_nelx(iy) + 1;
1342 }
1343 }
1344 // - top half: (middle node layer +) top node layer
1345 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1346 if (m_refine(iy) == 0) {
1347 n += m_layer_nelx(iy) * 3 + 1;
1348 }
1349 else {
1350 n += m_layer_nelx(iy) + 1;
1351 }
1352 }
1353
1354 // allocate node-list
1355 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({n});
1356
1357 // initialize counter: current index in the node-list "ret"
1358 size_t j = 0;
1359
1360 // bottom half: bottom node layer (+ middle node layer)
1361 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1362 // -- bottom node layer
1363 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
1364 ret(j) = m_startNode(iy) + ix + (m_layer_nelx(iy) + 1) * m_layer_nelz(iy);
1365 ++j;
1366 }
1367 // -- refinement layer
1368 if (m_refine(iy) == 0) {
1369 for (size_t ix = 0; ix < 2 * m_layer_nelx(iy); ++ix) {
1370 ret(j) =
1371 m_startNode(iy) + ix + m_nnd(iy) + 2 * m_layer_nelx(iy) * m_layer_nelz(iy);
1372 ++j;
1373 }
1374 }
1375 }
1376
1377 // top half: (middle node layer +) top node layer
1378 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1379 // -- refinement layer
1380 if (m_refine(iy) == 0) {
1381 for (size_t ix = 0; ix < 2 * m_layer_nelx(iy); ++ix) {
1382 ret(j) =
1383 m_startNode(iy) + ix + m_nnd(iy) + 2 * m_layer_nelx(iy) * m_layer_nelz(iy);
1384 ++j;
1385 }
1386 }
1387 // -- top node layer
1388 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
1389 ret(j) = m_startNode(iy + 1) + ix + (m_layer_nelx(iy) + 1) * m_layer_nelz(iy);
1390 ++j;
1391 }
1392 }
1393
1394 return ret;
1395 }
1396
1397 array_type::tensor<size_t, 1> nodesLeft_impl() const
1398 {
1399 // number of element layers in y-direction
1400 size_t nely = static_cast<size_t>(m_nhy.size());
1401
1402 // number of boundary nodes
1403 // - initialize
1404 size_t n = 0;
1405 // - bottom half: bottom node layer (+ middle node layer)
1406 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1407 if (m_refine(iy) == 2) {
1408 n += m_layer_nelz(iy) * 3 + 1;
1409 }
1410 else {
1411 n += m_layer_nelz(iy) + 1;
1412 }
1413 }
1414 // - top half: (middle node layer +) top node layer
1415 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1416 if (m_refine(iy) == 2) {
1417 n += m_layer_nelz(iy) * 3 + 1;
1418 }
1419 else {
1420 n += m_layer_nelz(iy) + 1;
1421 }
1422 }
1423
1424 // allocate node-list
1425 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({n});
1426
1427 // initialize counter: current index in the node-list "ret"
1428 size_t j = 0;
1429
1430 // bottom half: bottom node layer (+ middle node layer)
1431 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1432 // -- bottom node layer
1433 for (size_t iz = 0; iz < m_layer_nelz(iy) + 1; ++iz) {
1434 ret(j) = m_startNode(iy) + iz * (m_layer_nelx(iy) + 1);
1435 ++j;
1436 }
1437 // -- refinement layer
1438 if (m_refine(iy) == 2) {
1439 for (size_t iz = 0; iz < 2 * m_layer_nelz(iy); ++iz) {
1440 ret(j) = m_startNode(iy) + iz * (m_layer_nelx(iy) + 1) + m_nnd(iy);
1441 ++j;
1442 }
1443 }
1444 }
1445
1446 // top half: (middle node layer +) top node layer
1447 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1448 // -- refinement layer
1449 if (m_refine(iy) == 2) {
1450 for (size_t iz = 0; iz < 2 * m_layer_nelz(iy); ++iz) {
1451 ret(j) = m_startNode(iy) + iz * (m_layer_nelx(iy) + 1) + m_nnd(iy);
1452 ++j;
1453 }
1454 }
1455 // -- top node layer
1456 for (size_t iz = 0; iz < m_layer_nelz(iy) + 1; ++iz) {
1457 ret(j) = m_startNode(iy + 1) + iz * (m_layer_nelx(iy) + 1);
1458 ++j;
1459 }
1460 }
1461
1462 return ret;
1463 }
1464
1465 array_type::tensor<size_t, 1> nodesRight_impl() const
1466 {
1467 // number of element layers in y-direction
1468 size_t nely = static_cast<size_t>(m_nhy.size());
1469
1470 // number of boundary nodes
1471 // - initialize
1472 size_t n = 0;
1473 // - bottom half: bottom node layer (+ middle node layer)
1474 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1475 if (m_refine(iy) == 2)
1476 n += m_layer_nelz(iy) * 3 + 1;
1477 else
1478 n += m_layer_nelz(iy) + 1;
1479 }
1480 // - top half: (middle node layer +) top node layer
1481 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1482 if (m_refine(iy) == 2)
1483 n += m_layer_nelz(iy) * 3 + 1;
1484 else
1485 n += m_layer_nelz(iy) + 1;
1486 }
1487
1488 // allocate node-list
1489 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({n});
1490
1491 // initialize counter: current index in the node-list "ret"
1492 size_t j = 0;
1493
1494 // bottom half: bottom node layer (+ middle node layer)
1495 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1496 // -- bottom node layer
1497 for (size_t iz = 0; iz < m_layer_nelz(iy) + 1; ++iz) {
1498 ret(j) = m_startNode(iy) + iz * (m_layer_nelx(iy) + 1) + m_layer_nelx(iy);
1499 ++j;
1500 }
1501 // -- refinement layer
1502 if (m_refine(iy) == 2) {
1503 for (size_t iz = 0; iz < 2 * m_layer_nelz(iy); ++iz) {
1504 ret(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_layer_nelx(iy) + 1) +
1505 m_layer_nelx(iy);
1506 ++j;
1507 }
1508 }
1509 }
1510
1511 // top half: (middle node layer +) top node layer
1512 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1513 // -- refinement layer
1514 if (m_refine(iy) == 2) {
1515 for (size_t iz = 0; iz < 2 * m_layer_nelz(iy); ++iz) {
1516 ret(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_layer_nelx(iy) + 1) +
1517 m_layer_nelx(iy);
1518 ++j;
1519 }
1520 }
1521 // -- top node layer
1522 for (size_t iz = 0; iz < m_layer_nelz(iy) + 1; ++iz) {
1523 ret(j) = m_startNode(iy + 1) + iz * (m_layer_nelx(iy) + 1) + m_layer_nelx(iy);
1524 ++j;
1525 }
1526 }
1527
1528 return ret;
1529 }
1530
1531 array_type::tensor<size_t, 1> nodesBottom_impl() const
1532 {
1533 // number of element layers in y-direction
1534 size_t nely = static_cast<size_t>(m_nhy.size());
1535
1536 // allocate node list
1537 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nnd(nely)});
1538
1539 // counter
1540 size_t j = 0;
1541
1542 // fill node list
1543 for (size_t ix = 0; ix < m_layer_nelx(0) + 1; ++ix) {
1544 for (size_t iz = 0; iz < m_layer_nelz(0) + 1; ++iz) {
1545 ret(j) = m_startNode(0) + ix + iz * (m_layer_nelx(0) + 1);
1546 ++j;
1547 }
1548 }
1549
1550 return ret;
1551 }
1552
1553 array_type::tensor<size_t, 1> nodesTop_impl() const
1554 {
1555 // number of element layers in y-direction
1556 size_t nely = static_cast<size_t>(m_nhy.size());
1557
1558 // allocate node list
1559 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nnd(nely)});
1560
1561 // counter
1562 size_t j = 0;
1563
1564 // fill node list
1565 for (size_t ix = 0; ix < m_layer_nelx(nely - 1) + 1; ++ix) {
1566 for (size_t iz = 0; iz < m_layer_nelz(nely - 1) + 1; ++iz) {
1567 ret(j) = m_startNode(nely) + ix + iz * (m_layer_nelx(nely - 1) + 1);
1568 ++j;
1569 }
1570 }
1571
1572 return ret;
1573 }
1574
1575 array_type::tensor<size_t, 1> nodesFrontFace_impl() const
1576 {
1577 // number of element layers in y-direction
1578 size_t nely = static_cast<size_t>(m_nhy.size());
1579
1580 // number of boundary nodes
1581 // - initialize
1582 size_t n = 0;
1583 // - bottom half: bottom node layer (+ middle node layer)
1584 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
1585 if (m_refine(iy) == 0) {
1586 n += m_layer_nelx(iy) * 3 - 1;
1587 }
1588 else {
1589 n += m_layer_nelx(iy) - 1;
1590 }
1591 }
1592 // - top half: (middle node layer +) top node layer
1593 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
1594 if (m_refine(iy) == 0) {
1595 n += m_layer_nelx(iy) * 3 - 1;
1596 }
1597 else {
1598 n += m_layer_nelx(iy) - 1;
1599 }
1600 }
1601
1602 // allocate node-list
1603 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({n});
1604
1605 // initialize counter: current index in the node-list "ret"
1606 size_t j = 0;
1607
1608 // bottom half: bottom node layer (+ middle node layer)
1609 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
1610 // -- bottom node layer
1611 for (size_t ix = 1; ix < m_layer_nelx(iy); ++ix) {
1612 ret(j) = m_startNode(iy) + ix;
1613 ++j;
1614 }
1615 // -- refinement layer
1616 if (m_refine(iy) == 0) {
1617 for (size_t ix = 0; ix < 2 * m_layer_nelx(iy); ++ix) {
1618 ret(j) = m_startNode(iy) + ix + m_nnd(iy);
1619 ++j;
1620 }
1621 }
1622 }
1623
1624 // top half: (middle node layer +) top node layer
1625 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
1626 // -- refinement layer
1627 if (m_refine(iy) == 0) {
1628 for (size_t ix = 0; ix < 2 * m_layer_nelx(iy); ++ix) {
1629 ret(j) = m_startNode(iy) + ix + m_nnd(iy);
1630 ++j;
1631 }
1632 }
1633 // -- top node layer
1634 for (size_t ix = 1; ix < m_layer_nelx(iy); ++ix) {
1635 ret(j) = m_startNode(iy + 1) + ix;
1636 ++j;
1637 }
1638 }
1639
1640 return ret;
1641 }
1642
1643 array_type::tensor<size_t, 1> nodesBackFace_impl() const
1644 {
1645 // number of element layers in y-direction
1646 size_t nely = static_cast<size_t>(m_nhy.size());
1647
1648 // number of boundary nodes
1649 // - initialize
1650 size_t n = 0;
1651 // - bottom half: bottom node layer (+ middle node layer)
1652 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
1653 if (m_refine(iy) == 0) {
1654 n += m_layer_nelx(iy) * 3 - 1;
1655 }
1656 else {
1657 n += m_layer_nelx(iy) - 1;
1658 }
1659 }
1660 // - top half: (middle node layer +) top node layer
1661 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
1662 if (m_refine(iy) == 0) {
1663 n += m_layer_nelx(iy) * 3 - 1;
1664 }
1665 else {
1666 n += m_layer_nelx(iy) - 1;
1667 }
1668 }
1669
1670 // allocate node-list
1671 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({n});
1672
1673 // initialize counter: current index in the node-list "ret"
1674 size_t j = 0;
1675
1676 // bottom half: bottom node layer (+ middle node layer)
1677 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
1678 // -- bottom node layer
1679 for (size_t ix = 1; ix < m_layer_nelx(iy); ++ix) {
1680 ret(j) = m_startNode(iy) + ix + (m_layer_nelx(iy) + 1) * m_layer_nelz(iy);
1681 ++j;
1682 }
1683 // -- refinement layer
1684 if (m_refine(iy) == 0) {
1685 for (size_t ix = 0; ix < 2 * m_layer_nelx(iy); ++ix) {
1686 ret(j) =
1687 m_startNode(iy) + ix + m_nnd(iy) + 2 * m_layer_nelx(iy) * m_layer_nelz(iy);
1688 ++j;
1689 }
1690 }
1691 }
1692
1693 // top half: (middle node layer +) top node layer
1694 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
1695 // -- refinement layer
1696 if (m_refine(iy) == 0) {
1697 for (size_t ix = 0; ix < 2 * m_layer_nelx(iy); ++ix) {
1698 ret(j) =
1699 m_startNode(iy) + ix + m_nnd(iy) + 2 * m_layer_nelx(iy) * m_layer_nelz(iy);
1700 ++j;
1701 }
1702 }
1703 // -- top node layer
1704 for (size_t ix = 1; ix < m_layer_nelx(iy); ++ix) {
1705 ret(j) = m_startNode(iy + 1) + ix + (m_layer_nelx(iy) + 1) * m_layer_nelz(iy);
1706 ++j;
1707 }
1708 }
1709
1710 return ret;
1711 }
1712
1713 array_type::tensor<size_t, 1> nodesLeftFace_impl() const
1714 {
1715 // number of element layers in y-direction
1716 size_t nely = static_cast<size_t>(m_nhy.size());
1717
1718 // number of boundary nodes
1719 // - initialize
1720 size_t n = 0;
1721 // - bottom half: bottom node layer (+ middle node layer)
1722 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
1723 if (m_refine(iy) == 2) {
1724 n += m_layer_nelz(iy) * 3 - 1;
1725 }
1726 else {
1727 n += m_layer_nelz(iy) - 1;
1728 }
1729 }
1730 // - top half: (middle node layer +) top node layer
1731 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
1732 if (m_refine(iy) == 2) {
1733 n += m_layer_nelz(iy) * 3 - 1;
1734 }
1735 else {
1736 n += m_layer_nelz(iy) - 1;
1737 }
1738 }
1739
1740 // allocate node-list
1741 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({n});
1742
1743 // initialize counter: current index in the node-list "ret"
1744 size_t j = 0;
1745
1746 // bottom half: bottom node layer (+ middle node layer)
1747 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
1748 // -- bottom node layer
1749 for (size_t iz = 1; iz < m_layer_nelz(iy); ++iz) {
1750 ret(j) = m_startNode(iy) + iz * (m_layer_nelx(iy) + 1);
1751 ++j;
1752 }
1753 // -- refinement layer
1754 if (m_refine(iy) == 2) {
1755 for (size_t iz = 0; iz < 2 * m_layer_nelz(iy); ++iz) {
1756 ret(j) = m_startNode(iy) + iz * (m_layer_nelx(iy) + 1) + m_nnd(iy);
1757 ++j;
1758 }
1759 }
1760 }
1761
1762 // top half: (middle node layer +) top node layer
1763 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
1764 // -- refinement layer
1765 if (m_refine(iy) == 2) {
1766 for (size_t iz = 0; iz < 2 * m_layer_nelz(iy); ++iz) {
1767 ret(j) = m_startNode(iy) + iz * (m_layer_nelx(iy) + 1) + m_nnd(iy);
1768 ++j;
1769 }
1770 }
1771 // -- top node layer
1772 for (size_t iz = 1; iz < m_layer_nelz(iy); ++iz) {
1773 ret(j) = m_startNode(iy + 1) + iz * (m_layer_nelx(iy) + 1);
1774 ++j;
1775 }
1776 }
1777
1778 return ret;
1779 }
1780
1781 array_type::tensor<size_t, 1> nodesRightFace_impl() const
1782 {
1783 // number of element layers in y-direction
1784 size_t nely = static_cast<size_t>(m_nhy.size());
1785
1786 // number of boundary nodes
1787 // - initialize
1788 size_t n = 0;
1789 // - bottom half: bottom node layer (+ middle node layer)
1790 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
1791 if (m_refine(iy) == 2) {
1792 n += m_layer_nelz(iy) * 3 - 1;
1793 }
1794 else {
1795 n += m_layer_nelz(iy) - 1;
1796 }
1797 }
1798 // - top half: (middle node layer +) top node layer
1799 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
1800 if (m_refine(iy) == 2) {
1801 n += m_layer_nelz(iy) * 3 - 1;
1802 }
1803 else {
1804 n += m_layer_nelz(iy) - 1;
1805 }
1806 }
1807
1808 // allocate node-list
1809 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({n});
1810
1811 // initialize counter: current index in the node-list "ret"
1812 size_t j = 0;
1813
1814 // bottom half: bottom node layer (+ middle node layer)
1815 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
1816 // -- bottom node layer
1817 for (size_t iz = 1; iz < m_layer_nelz(iy); ++iz) {
1818 ret(j) = m_startNode(iy) + iz * (m_layer_nelx(iy) + 1) + m_layer_nelx(iy);
1819 ++j;
1820 }
1821 // -- refinement layer
1822 if (m_refine(iy) == 2) {
1823 for (size_t iz = 0; iz < 2 * m_layer_nelz(iy); ++iz) {
1824 ret(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_layer_nelx(iy) + 1) +
1825 m_layer_nelx(iy);
1826 ++j;
1827 }
1828 }
1829 }
1830
1831 // top half: (middle node layer +) top node layer
1832 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
1833 // -- refinement layer
1834 if (m_refine(iy) == 2) {
1835 for (size_t iz = 0; iz < 2 * m_layer_nelz(iy); ++iz) {
1836 ret(j) = m_startNode(iy) + m_nnd(iy) + iz * (m_layer_nelx(iy) + 1) +
1837 m_layer_nelx(iy);
1838 ++j;
1839 }
1840 }
1841 // -- top node layer
1842 for (size_t iz = 1; iz < m_layer_nelz(iy); ++iz) {
1843 ret(j) = m_startNode(iy + 1) + iz * (m_layer_nelx(iy) + 1) + m_layer_nelx(iy);
1844 ++j;
1845 }
1846 }
1847
1848 return ret;
1849 }
1850
1851 array_type::tensor<size_t, 1> nodesBottomFace_impl() const
1852 {
1853 // allocate node list
1854 array_type::tensor<size_t, 1> ret =
1855 xt::empty<size_t>({(m_layer_nelx(0) - 1) * (m_layer_nelz(0) - 1)});
1856
1857 // counter
1858 size_t j = 0;
1859
1860 // fill node list
1861 for (size_t ix = 1; ix < m_layer_nelx(0); ++ix) {
1862 for (size_t iz = 1; iz < m_layer_nelz(0); ++iz) {
1863 ret(j) = m_startNode(0) + ix + iz * (m_layer_nelx(0) + 1);
1864 ++j;
1865 }
1866 }
1867
1868 return ret;
1869 }
1870
1871 array_type::tensor<size_t, 1> nodesTopFace_impl() const
1872 {
1873 // number of element layers in y-direction
1874 size_t nely = static_cast<size_t>(m_nhy.size());
1875
1876 // allocate node list
1877 array_type::tensor<size_t, 1> ret =
1878 xt::empty<size_t>({(m_layer_nelx(nely - 1) - 1) * (m_layer_nelz(nely - 1) - 1)});
1879
1880 // counter
1881 size_t j = 0;
1882
1883 // fill node list
1884 for (size_t ix = 1; ix < m_layer_nelx(nely - 1); ++ix) {
1885 for (size_t iz = 1; iz < m_layer_nelz(nely - 1); ++iz) {
1886 ret(j) = m_startNode(nely) + ix + iz * (m_layer_nelx(nely - 1) + 1);
1887 ++j;
1888 }
1889 }
1890
1891 return ret;
1892 }
1893
1894 array_type::tensor<size_t, 1> nodesFrontBottomEdge_impl() const
1895 {
1896 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(0) + 1});
1897
1898 for (size_t ix = 0; ix < m_layer_nelx(0) + 1; ++ix) {
1899 ret(ix) = m_startNode(0) + ix;
1900 }
1901
1902 return ret;
1903 }
1904
1905 array_type::tensor<size_t, 1> nodesFrontTopEdge_impl() const
1906 {
1907 size_t nely = static_cast<size_t>(m_nhy.size());
1908
1909 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(nely - 1) + 1});
1910
1911 for (size_t ix = 0; ix < m_layer_nelx(nely - 1) + 1; ++ix) {
1912 ret(ix) = m_startNode(nely) + ix;
1913 }
1914
1915 return ret;
1916 }
1917
1918 array_type::tensor<size_t, 1> nodesFrontLeftEdge_impl() const
1919 {
1920 size_t nely = static_cast<size_t>(m_nhy.size());
1921
1922 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely + 1});
1923
1924 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1925 ret(iy) = m_startNode(iy);
1926 }
1927
1928 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1929 ret(iy + 1) = m_startNode(iy + 1);
1930 }
1931
1932 return ret;
1933 }
1934
1935 array_type::tensor<size_t, 1> nodesFrontRightEdge_impl() const
1936 {
1937 size_t nely = static_cast<size_t>(m_nhy.size());
1938
1939 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely + 1});
1940
1941 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1942 ret(iy) = m_startNode(iy) + m_layer_nelx(iy);
1943 }
1944
1945 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1946 ret(iy + 1) = m_startNode(iy + 1) + m_layer_nelx(iy);
1947 }
1948
1949 return ret;
1950 }
1951
1952 array_type::tensor<size_t, 1> nodesBackBottomEdge_impl() const
1953 {
1954 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(0) + 1});
1955
1956 for (size_t ix = 0; ix < m_layer_nelx(0) + 1; ++ix) {
1957 ret(ix) = m_startNode(0) + ix + (m_layer_nelx(0) + 1) * (m_layer_nelz(0));
1958 }
1959
1960 return ret;
1961 }
1962
1963 array_type::tensor<size_t, 1> nodesBackTopEdge_impl() const
1964 {
1965 size_t nely = static_cast<size_t>(m_nhy.size());
1966
1967 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(nely - 1) + 1});
1968
1969 for (size_t ix = 0; ix < m_layer_nelx(nely - 1) + 1; ++ix) {
1970 ret(ix) =
1971 m_startNode(nely) + ix + (m_layer_nelx(nely - 1) + 1) * (m_layer_nelz(nely - 1));
1972 }
1973
1974 return ret;
1975 }
1976
1977 array_type::tensor<size_t, 1> nodesBackLeftEdge_impl() const
1978 {
1979 size_t nely = static_cast<size_t>(m_nhy.size());
1980
1981 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely + 1});
1982
1983 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1984 ret(iy) = m_startNode(iy) + (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy));
1985 }
1986
1987 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1988 ret(iy + 1) = m_startNode(iy + 1) + (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy));
1989 }
1990
1991 return ret;
1992 }
1993
1994 array_type::tensor<size_t, 1> nodesBackRightEdge_impl() const
1995 {
1996 size_t nely = static_cast<size_t>(m_nhy.size());
1997
1998 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely + 1});
1999
2000 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
2001 ret(iy) =
2002 m_startNode(iy) + m_layer_nelx(iy) + (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy));
2003 }
2004
2005 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
2006 ret(iy + 1) = m_startNode(iy + 1) + m_layer_nelx(iy) +
2007 (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy));
2008 }
2009
2010 return ret;
2011 }
2012
2013 array_type::tensor<size_t, 1> nodesBottomLeftEdge_impl() const
2014 {
2015 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelz(0) + 1});
2016
2017 for (size_t iz = 0; iz < m_layer_nelz(0) + 1; ++iz) {
2018 ret(iz) = m_startNode(0) + iz * (m_layer_nelx(0) + 1);
2019 }
2020
2021 return ret;
2022 }
2023
2024 array_type::tensor<size_t, 1> nodesBottomRightEdge_impl() const
2025 {
2026 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelz(0) + 1});
2027
2028 for (size_t iz = 0; iz < m_layer_nelz(0) + 1; ++iz) {
2029 ret(iz) = m_startNode(0) + m_layer_nelx(0) + iz * (m_layer_nelx(0) + 1);
2030 }
2031
2032 return ret;
2033 }
2034
2035 array_type::tensor<size_t, 1> nodesTopLeftEdge_impl() const
2036 {
2037 size_t nely = static_cast<size_t>(m_nhy.size());
2038
2039 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelz(nely - 1) + 1});
2040
2041 for (size_t iz = 0; iz < m_layer_nelz(nely - 1) + 1; ++iz) {
2042 ret(iz) = m_startNode(nely) + iz * (m_layer_nelx(nely - 1) + 1);
2043 }
2044
2045 return ret;
2046 }
2047
2048 array_type::tensor<size_t, 1> nodesTopRightEdge_impl() const
2049 {
2050 size_t nely = static_cast<size_t>(m_nhy.size());
2051
2052 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelz(nely - 1) + 1});
2053
2054 for (size_t iz = 0; iz < m_layer_nelz(nely - 1) + 1; ++iz) {
2055 ret(iz) =
2056 m_startNode(nely) + m_layer_nelx(nely - 1) + iz * (m_layer_nelx(nely - 1) + 1);
2057 }
2058
2059 return ret;
2060 }
2061
2062 array_type::tensor<size_t, 1> nodesFrontBottomOpenEdge_impl() const
2063 {
2064 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(0) - 1});
2065
2066 for (size_t ix = 1; ix < m_layer_nelx(0); ++ix) {
2067 ret(ix - 1) = m_startNode(0) + ix;
2068 }
2069
2070 return ret;
2071 }
2072
2073 array_type::tensor<size_t, 1> nodesFrontTopOpenEdge_impl() const
2074 {
2075 size_t nely = static_cast<size_t>(m_nhy.size());
2076
2077 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(nely - 1) - 1});
2078
2079 for (size_t ix = 1; ix < m_layer_nelx(nely - 1); ++ix) {
2080 ret(ix - 1) = m_startNode(nely) + ix;
2081 }
2082
2083 return ret;
2084 }
2085
2086 array_type::tensor<size_t, 1> nodesFrontLeftOpenEdge_impl() const
2087 {
2088 size_t nely = static_cast<size_t>(m_nhy.size());
2089
2090 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely - 1});
2091
2092 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
2093 ret(iy - 1) = m_startNode(iy);
2094 }
2095
2096 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
2097 ret(iy) = m_startNode(iy + 1);
2098 }
2099
2100 return ret;
2101 }
2102
2103 array_type::tensor<size_t, 1> nodesFrontRightOpenEdge_impl() const
2104 {
2105 size_t nely = static_cast<size_t>(m_nhy.size());
2106
2107 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely - 1});
2108
2109 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
2110 ret(iy - 1) = m_startNode(iy) + m_layer_nelx(iy);
2111 }
2112
2113 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
2114 ret(iy) = m_startNode(iy + 1) + m_layer_nelx(iy);
2115 }
2116
2117 return ret;
2118 }
2119
2120 array_type::tensor<size_t, 1> nodesBackBottomOpenEdge_impl() const
2121 {
2122 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(0) - 1});
2123
2124 for (size_t ix = 1; ix < m_layer_nelx(0); ++ix) {
2125 ret(ix - 1) = m_startNode(0) + ix + (m_layer_nelx(0) + 1) * (m_layer_nelz(0));
2126 }
2127
2128 return ret;
2129 }
2130
2131 array_type::tensor<size_t, 1> nodesBackTopOpenEdge_impl() const
2132 {
2133 size_t nely = static_cast<size_t>(m_nhy.size());
2134
2135 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelx(nely - 1) - 1});
2136
2137 for (size_t ix = 1; ix < m_layer_nelx(nely - 1); ++ix) {
2138 ret(ix - 1) =
2139 m_startNode(nely) + ix + (m_layer_nelx(nely - 1) + 1) * (m_layer_nelz(nely - 1));
2140 }
2141
2142 return ret;
2143 }
2144
2145 array_type::tensor<size_t, 1> nodesBackLeftOpenEdge_impl() const
2146 {
2147 size_t nely = static_cast<size_t>(m_nhy.size());
2148
2149 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely - 1});
2150
2151 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
2152 ret(iy - 1) = m_startNode(iy) + (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy));
2153 }
2154
2155 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
2156 ret(iy) = m_startNode(iy + 1) + (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy));
2157 }
2158
2159 return ret;
2160 }
2161
2162 array_type::tensor<size_t, 1> nodesBackRightOpenEdge_impl() const
2163 {
2164 size_t nely = static_cast<size_t>(m_nhy.size());
2165
2166 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely - 1});
2167
2168 for (size_t iy = 1; iy < (nely + 1) / 2; ++iy) {
2169 ret(iy - 1) =
2170 m_startNode(iy) + m_layer_nelx(iy) + (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy));
2171 }
2172
2173 for (size_t iy = (nely - 1) / 2; iy < nely - 1; ++iy) {
2174 ret(iy) = m_startNode(iy + 1) + m_layer_nelx(iy) +
2175 (m_layer_nelx(iy) + 1) * (m_layer_nelz(iy));
2176 }
2177
2178 return ret;
2179 }
2180
2181 array_type::tensor<size_t, 1> nodesBottomLeftOpenEdge_impl() const
2182 {
2183 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelz(0) - 1});
2184
2185 for (size_t iz = 1; iz < m_layer_nelz(0); ++iz) {
2186 ret(iz - 1) = m_startNode(0) + iz * (m_layer_nelx(0) + 1);
2187 }
2188
2189 return ret;
2190 }
2191
2192 array_type::tensor<size_t, 1> nodesBottomRightOpenEdge_impl() const
2193 {
2194 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelz(0) - 1});
2195
2196 for (size_t iz = 1; iz < m_layer_nelz(0); ++iz) {
2197 ret(iz - 1) = m_startNode(0) + m_layer_nelx(0) + iz * (m_layer_nelx(0) + 1);
2198 }
2199
2200 return ret;
2201 }
2202
2203 array_type::tensor<size_t, 1> nodesTopLeftOpenEdge_impl() const
2204 {
2205 size_t nely = static_cast<size_t>(m_nhy.size());
2206
2207 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelz(nely - 1) - 1});
2208
2209 for (size_t iz = 1; iz < m_layer_nelz(nely - 1); ++iz) {
2210 ret(iz - 1) = m_startNode(nely) + iz * (m_layer_nelx(nely - 1) + 1);
2211 }
2212
2213 return ret;
2214 }
2215
2216 array_type::tensor<size_t, 1> nodesTopRightOpenEdge_impl() const
2217 {
2218 size_t nely = static_cast<size_t>(m_nhy.size());
2219
2220 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_layer_nelz(nely - 1) - 1});
2221
2222 for (size_t iz = 1; iz < m_layer_nelz(nely - 1); ++iz) {
2223 ret(iz - 1) =
2224 m_startNode(nely) + m_layer_nelx(nely - 1) + iz * (m_layer_nelx(nely - 1) + 1);
2225 }
2226
2227 return ret;
2228 }
2229
2230 size_t nodesFrontBottomLeftCorner_impl() const
2231 {
2232 return m_startNode(0);
2233 }
2234
2235 size_t nodesFrontBottomRightCorner_impl() const
2236 {
2237 return m_startNode(0) + m_layer_nelx(0);
2238 }
2239
2240 size_t nodesFrontTopLeftCorner_impl() const
2241 {
2242 size_t nely = static_cast<size_t>(m_nhy.size());
2243 return m_startNode(nely);
2244 }
2245
2246 size_t nodesFrontTopRightCorner_impl() const
2247 {
2248 size_t nely = static_cast<size_t>(m_nhy.size());
2249 return m_startNode(nely) + m_layer_nelx(nely - 1);
2250 }
2251
2252 size_t nodesBackBottomLeftCorner_impl() const
2253 {
2254 return m_startNode(0) + (m_layer_nelx(0) + 1) * (m_layer_nelz(0));
2255 }
2256
2257 size_t nodesBackBottomRightCorner_impl() const
2258 {
2259 return m_startNode(0) + m_layer_nelx(0) + (m_layer_nelx(0) + 1) * (m_layer_nelz(0));
2260 }
2261
2262 size_t nodesBackTopLeftCorner_impl() const
2263 {
2264 size_t nely = static_cast<size_t>(m_nhy.size());
2265 return m_startNode(nely) + (m_layer_nelx(nely - 1) + 1) * (m_layer_nelz(nely - 1));
2266 }
2267
2268 size_t nodesBackTopRightCorner_impl() const
2269 {
2270 size_t nely = static_cast<size_t>(m_nhy.size());
2271 return m_startNode(nely) + m_layer_nelx(nely - 1) +
2272 (m_layer_nelx(nely - 1) + 1) * (m_layer_nelz(nely - 1));
2273 }
2274
2275 double m_h;
2276 size_t m_nelx;
2277 size_t m_nely;
2278 size_t m_nelz;
2279 size_t m_nelem;
2280 size_t m_nnode;
2281 size_t m_nne;
2282 size_t m_ndim;
2283 double m_Lx;
2284 double m_Lz;
2285 array_type::tensor<size_t, 1> m_layer_nelx;
2286 array_type::tensor<size_t, 1> m_layer_nelz;
2287 array_type::tensor<size_t, 1> m_nnd;
2288 array_type::tensor<size_t, 1> m_nhx;
2289 array_type::tensor<size_t, 1> m_nhy;
2290 array_type::tensor<size_t, 1> m_nhz;
2291 array_type::tensor<int, 1>
2292 m_refine;
2293 array_type::tensor<size_t, 1> m_startElem;
2294 array_type::tensor<size_t, 1> m_startNode;
2295};
2296
2297} // namespace Hex8
2298} // namespace Mesh
2299} // namespace GooseFEM
2300
2301#endif
Generic mesh operations.
Mesh with fine middle layer, and coarser elements towards the top and bottom.
Definition MeshHex8.h:613
FineLayer(size_t nelx, size_t nely, size_t nelz, double h=1.0, size_t nfine=1)
Constructor.
Definition MeshHex8.h:627
array_type::tensor< size_t, 1 > elementsMiddleLayer() const
Elements in the middle (fine) layer.
Definition MeshHex8.h:854
Regular mesh: equi-sized elements.
Definition MeshHex8.h:26
Regular(size_t nelx, size_t nely, size_t nelz, double h=1.0)
Constructor.
Definition MeshHex8.h:36
CRTP base class for regular meshes in 3d.
Definition Mesh.h:552
auto nelz() const
Number of elements in y-direction == height of the mesh, in units of h,.
Definition Mesh.h:563
CRTP base class for regular meshes.
Definition Mesh.h:181
auto nely() const
Number of elements in y-direction == height of the mesh, in units of h,.
Definition Mesh.h:237
auto h() const
Linear edge size of one 'block'.
Definition Mesh.h:246
auto nelx() const
Number of elements in x-direction == width of the mesh in units of h.
Definition Mesh.h:228
Basic configuration:
#define GOOSEFEM_ASSERT(expr)
All assertions are implementation as::
Definition config.h:97
ElementType
Enumerator for element-types.
Definition Mesh.h:31
@ Hex8
Hexahedron: 8-noded element in 3-d.
xt::xtensor< T, N > tensor
Fixed (static) rank array.
Definition config.h:177
Toolbox to perform finite element computations.
Definition Allocate.h:14
auto AsTensor(const T &arg, const S &shape)
"Broadcast" a scalar stored in an array (e.g.
Definition Allocate.h:167