GooseFEM 1.4.1.dev2+g78f16df
Loading...
Searching...
No Matches
MeshQuad4.h
Go to the documentation of this file.
1
10#ifndef GOOSEFEM_MESHQUAD4_H
11#define GOOSEFEM_MESHQUAD4_H
12
13#include "Mesh.h"
14#include "config.h"
15
16namespace GooseFEM {
17namespace Mesh {
18
22namespace Quad4 {
23
24// pre-allocation
25namespace Map {
27}
28
32class Regular : public RegularBase2d<Regular> {
33public:
34 Regular() = default;
35
43 Regular(size_t nelx, size_t nely, double h = 1.0)
44 {
45 m_h = h;
46 m_nelx = nelx;
47 m_nely = nely;
48 m_ndim = 2;
49 m_nne = 4;
50
51 GOOSEFEM_ASSERT(m_nelx >= 1);
52 GOOSEFEM_ASSERT(m_nely >= 1);
53
54 m_nnode = (m_nelx + 1) * (m_nely + 1);
55 m_nelem = m_nelx * m_nely;
56 }
57
64 {
65 return xt::arange<size_t>(m_nelem).reshape({m_nely, m_nelx});
66 }
67
68private:
69 friend class RegularBase<Regular>;
70 friend class RegularBase2d<Regular>;
71
72 size_t nelx_impl() const
73 {
74 return m_nelx;
75 }
76
77 size_t nely_impl() const
78 {
79 return m_nely;
80 }
81
82 ElementType elementType_impl() const
83 {
84 return ElementType::Quad4;
85 }
86
87 array_type::tensor<double, 2> coor_impl() const
88 {
89 array_type::tensor<double, 2> ret = xt::empty<double>({m_nnode, m_ndim});
90
91 array_type::tensor<double, 1> x =
92 xt::linspace<double>(0.0, m_h * static_cast<double>(m_nelx), m_nelx + 1);
93 array_type::tensor<double, 1> y =
94 xt::linspace<double>(0.0, m_h * static_cast<double>(m_nely), m_nely + 1);
95
96 size_t inode = 0;
97
98 for (size_t iy = 0; iy < m_nely + 1; ++iy) {
99 for (size_t ix = 0; ix < m_nelx + 1; ++ix) {
100 ret(inode, 0) = x(ix);
101 ret(inode, 1) = y(iy);
102 ++inode;
103 }
104 }
105
106 return ret;
107 }
108
109 array_type::tensor<size_t, 2> conn_impl() const
110 {
111 array_type::tensor<size_t, 2> ret = xt::empty<size_t>({m_nelem, m_nne});
112
113 size_t ielem = 0;
114
115 for (size_t iy = 0; iy < m_nely; ++iy) {
116 for (size_t ix = 0; ix < m_nelx; ++ix) {
117 ret(ielem, 0) = (iy) * (m_nelx + 1) + (ix);
118 ret(ielem, 1) = (iy) * (m_nelx + 1) + (ix + 1);
119 ret(ielem, 3) = (iy + 1) * (m_nelx + 1) + (ix);
120 ret(ielem, 2) = (iy + 1) * (m_nelx + 1) + (ix + 1);
121 ++ielem;
122 }
123 }
124
125 return ret;
126 }
127
128 array_type::tensor<size_t, 1> nodesBottomEdge_impl() const
129 {
130 return xt::arange<size_t>(m_nelx + 1);
131 }
132
133 array_type::tensor<size_t, 1> nodesTopEdge_impl() const
134 {
135 return xt::arange<size_t>(m_nelx + 1) + m_nely * (m_nelx + 1);
136 }
137
138 array_type::tensor<size_t, 1> nodesLeftEdge_impl() const
139 {
140 return xt::arange<size_t>(m_nely + 1) * (m_nelx + 1);
141 }
142
143 array_type::tensor<size_t, 1> nodesRightEdge_impl() const
144 {
145 return xt::arange<size_t>(m_nely + 1) * (m_nelx + 1) + m_nelx;
146 }
147
148 array_type::tensor<size_t, 1> nodesBottomOpenEdge_impl() const
149 {
150 return xt::arange<size_t>(1, m_nelx);
151 }
152
153 array_type::tensor<size_t, 1> nodesTopOpenEdge_impl() const
154 {
155 return xt::arange<size_t>(1, m_nelx) + m_nely * (m_nelx + 1);
156 }
157
158 array_type::tensor<size_t, 1> nodesLeftOpenEdge_impl() const
159 {
160 return xt::arange<size_t>(1, m_nely) * (m_nelx + 1);
161 }
162
163 array_type::tensor<size_t, 1> nodesRightOpenEdge_impl() const
164 {
165 return xt::arange<size_t>(1, m_nely) * (m_nelx + 1) + m_nelx;
166 }
167
168 size_t nodesBottomLeftCorner_impl() const
169 {
170 return 0;
171 }
172
173 size_t nodesBottomRightCorner_impl() const
174 {
175 return m_nelx;
176 }
177
178 size_t nodesTopLeftCorner_impl() const
179 {
180 return m_nely * (m_nelx + 1);
181 }
182
183 size_t nodesTopRightCorner_impl() const
184 {
185 return m_nely * (m_nelx + 1) + m_nelx;
186 }
187
188 double m_h;
189 size_t m_nelx;
190 size_t m_nely;
191 size_t m_nelem;
192 size_t m_nnode;
193 size_t m_nne;
194 size_t m_ndim;
195};
196
200class FineLayer : public RegularBase2d<FineLayer> {
201public:
202 FineLayer() = default;
203
215 FineLayer(size_t nelx, size_t nely, double h = 1.0, size_t nfine = 1)
216 {
217 this->init(nelx, nely, h, nfine);
218 }
219
229 FineLayer(const C& coor, const E& conn)
230 {
231 this->init_by_mapping(coor, conn);
232 }
233
242 {
243 return m_nhx;
244 }
245
254 {
255 return m_nhy;
256 }
257
266 {
267 return m_refine;
268 }
269
278 {
279 return m_layer_nelx;
280 }
281
288 {
289 size_t nely = m_nhy.size();
290 size_t iy = (nely - 1) / 2;
291 return m_startElem(iy) + xt::arange<size_t>(m_layer_nelx(iy));
292 }
293
300 {
301 GOOSEFEM_ASSERT(layer < m_layer_nelx.size());
302 size_t n = m_layer_nelx(layer);
303 if (m_refine(layer) != -1) {
304 n *= 4;
305 }
306 return m_startElem(layer) + xt::arange<size_t>(n);
307 }
308
315 std::vector<size_t> start_stop_rows,
316 std::vector<size_t> start_stop_cols
317 ) const
318 {
319 GOOSEFEM_ASSERT(start_stop_rows.size() == 0 || start_stop_rows.size() == 2);
320 GOOSEFEM_ASSERT(start_stop_cols.size() == 0 || start_stop_cols.size() == 2);
321
322 std::array<size_t, 2> rows;
323 std::array<size_t, 2> cols;
324
325 if (start_stop_rows.size() == 2) {
326 std::copy(start_stop_rows.begin(), start_stop_rows.end(), rows.begin());
327 GOOSEFEM_ASSERT(rows[0] <= this->nely());
328 GOOSEFEM_ASSERT(rows[1] <= this->nely());
329 }
330 else {
331 rows[0] = 0;
332 rows[1] = this->nely();
333 }
334
335 if (start_stop_cols.size() == 2) {
336 std::copy(start_stop_cols.begin(), start_stop_cols.end(), cols.begin());
337 GOOSEFEM_ASSERT(cols[0] <= this->nelx());
338 GOOSEFEM_ASSERT(cols[1] <= this->nelx());
339 }
340 else {
341 cols[0] = 0;
342 cols[1] = this->nelx();
343 }
344
345 if (rows[0] == rows[1] || cols[0] == cols[1]) {
346 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({0});
347 return ret;
348 }
349
350 // Compute dimensions
351
352 auto H = xt::cumsum(m_nhy);
353 size_t yl = 0;
354 if (rows[0] > 0) {
355 yl = xt::argmax(H > rows[0])();
356 }
357 size_t yu = xt::argmax(H >= rows[1])();
358 size_t hx = std::max(m_nhx(yl), m_nhx(yu));
359 size_t xl = (cols[0] - cols[0] % hx) / hx;
360 size_t xu = (cols[1] - cols[1] % hx) / hx;
361
362 // Allocate output
363
364 size_t N = 0;
365
366 for (size_t i = yl; i <= yu; ++i) {
367 // no refinement
368 size_t n = (xu - xl) * hx / m_nhx(i);
369 // refinement
370 if (m_refine(i) != -1) {
371 n *= 4;
372 }
373 N += n;
374 }
375
376 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({N});
377
378 // Write output
379
380 N = 0;
381
382 for (size_t i = yl; i <= yu; ++i) {
383 // no refinement
384 size_t n = (xu - xl) * hx / m_nhx(i);
385 size_t h = hx;
386 // refinement
387 if (m_refine(i) != -1) {
388 n *= 4;
389 h *= 4;
390 }
392 m_startElem(i) + xl * h / m_nhx(i) + xt::arange<size_t>(n);
393 xt::view(ret, xt::range(N, N + n)) = e;
394 N += n;
395 }
396
397 return ret;
398 }
399
410 elementgrid_around_ravel(size_t e, size_t size, bool periodic = true)
411 {
413
414 size_t iy = xt::argmin(m_startElem <= e)() - 1;
415 size_t nel = m_layer_nelx(iy);
416
417 GOOSEFEM_WIP_ASSERT(iy == (m_nhy.size() - 1) / 2);
418
419 auto H = xt::cumsum(m_nhy);
420
421 if (2 * size >= H(H.size() - 1)) {
422 return xt::arange<size_t>(this->nelem());
423 }
424
425 size_t hy = H(iy);
426 size_t l = xt::argmax(H > (hy - size - 1))();
427 size_t u = xt::argmax(H >= (hy + size))();
428 size_t lh = 0;
429 if (l > 0) {
430 lh = H(l - 1);
431 }
432 size_t uh = H(u);
433
434 size_t step = xt::amax(m_nhx)();
435 size_t relx = (e - m_startElem(iy)) % step;
436 size_t mid = (nel / step - (nel / step) % 2) / 2 * step + relx;
437 size_t nroll = (nel - (nel - mid + e - m_startElem(iy)) % nel) / step;
438 size_t dx = m_nhx(u);
439 size_t xl = 0;
440 size_t xu = nel;
441 if (mid >= size) {
442 xl = mid - size;
443 }
444 if (mid + size < nel) {
445 xu = mid + size + 1;
446 }
447 xl = xl - xl % dx;
448 xu = xu - xu % dx;
449 if (mid - xl < size) {
450 if (xl < dx) {
451 xl = 0;
452 }
453 else {
454 xl -= dx;
455 }
456 }
457 if (xu - mid < size) {
458 if (xu > nel - dx) {
459 xu = nel;
460 }
461 else {
462 xu += dx;
463 }
464 }
465
466 auto ret = this->elementgrid_ravel({lh, uh}, {xl, xu});
467 auto map = this->roll(nroll);
468 return xt::view(map, xt::keep(ret));
469 }
470
481 // -
483 elementgrid_leftright(size_t e, size_t left, size_t right, bool periodic = true)
484 {
486
487 size_t iy = xt::argmin(m_startElem <= e)() - 1;
488 size_t nel = m_layer_nelx(iy);
489
490 GOOSEFEM_WIP_ASSERT(iy == (m_nhy.size() - 1) / 2);
491
492 size_t step = xt::amax(m_nhx)();
493 size_t relx = (e - m_startElem(iy)) % step;
494 size_t mid = (nel / step - (nel / step) % 2) / 2 * step + relx;
495 size_t nroll = (nel - (nel - mid + e - m_startElem(iy)) % nel) / step;
496 size_t dx = m_nhx(iy);
497 size_t xl = 0;
498 size_t xu = nel;
499 if (mid >= left) {
500 xl = mid - left;
501 }
502 if (mid + right < nel) {
503 xu = mid + right + 1;
504 }
505 xl = xl - xl % dx;
506 xu = xu - xu % dx;
507 if (mid - xl < left) {
508 if (xl < dx) {
509 xl = 0;
510 }
511 else {
512 xl -= dx;
513 }
514 }
515 if (xu - mid < right) {
516 if (xu > nel - dx) {
517 xu = nel;
518 }
519 else {
520 xu += dx;
521 }
522 }
523
524 auto H = xt::cumsum(m_nhy);
525 size_t yl = 0;
526 if (iy > 0) {
527 yl = H(iy - 1);
528 }
529 auto ret = this->elementgrid_ravel({yl, H(iy)}, {xl, xu});
530 auto map = this->roll(nroll);
531 return xt::view(map, xt::keep(ret));
532 }
533
540 {
541 auto conn = this->conn();
542 size_t nely = static_cast<size_t>(m_nhy.size());
543 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({m_nelem});
544
545 // loop over all element layers
546 for (size_t iy = 0; iy < nely; ++iy) {
547
548 // no refinement
549 size_t shift = n * (m_layer_nelx(iy) / m_layer_nelx(0));
550 size_t nel = m_layer_nelx(iy);
551
552 // refinement
553 if (m_refine(iy) != -1) {
554 shift = n * (m_layer_nelx(iy) / m_layer_nelx(0)) * 4;
555 nel = m_layer_nelx(iy) * 4;
556 }
557
558 // element numbers of the layer, and roll them
559 auto e = m_startElem(iy) + xt::arange<size_t>(nel);
560 xt::view(ret, xt::range(m_startElem(iy), m_startElem(iy) + nel)) = xt::roll(e, shift);
561 }
562
563 return ret;
564 }
565
566private:
567 friend class RegularBase<FineLayer>;
568 friend class RegularBase2d<FineLayer>;
570
571 size_t nelx_impl() const
572 {
573 return xt::amax(m_layer_nelx)();
574 }
575
576 size_t nely_impl() const
577 {
578 return xt::sum(m_nhy)();
579 }
580
581 ElementType elementType_impl() const
582 {
583 return ElementType::Quad4;
584 }
585
586 array_type::tensor<double, 2> coor_impl() const
587 {
588 // allocate output
589 array_type::tensor<double, 2> ret = xt::empty<double>({m_nnode, m_ndim});
590
591 // current node, number of element layers
592 size_t inode = 0;
593 size_t nely = static_cast<size_t>(m_nhy.size());
594
595 // y-position of each main node layer (i.e. excluding node layers for refinement/coarsening)
596 // - allocate
597 array_type::tensor<double, 1> y = xt::empty<double>({nely + 1});
598 // - initialize
599 y(0) = 0.0;
600 // - compute
601 for (size_t iy = 1; iy < nely + 1; ++iy) {
602 y(iy) = y(iy - 1) + m_nhy(iy - 1) * m_h;
603 }
604
605 // loop over element layers (bottom -> middle) : add bottom layer (+ refinement layer) of
606 // nodes
607
608 for (size_t iy = 0;; ++iy) {
609 // get positions along the x- and z-axis
610 array_type::tensor<double, 1> x = xt::linspace<double>(0.0, m_Lx, m_layer_nelx(iy) + 1);
611
612 // add nodes of the bottom layer of this element
613 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
614 ret(inode, 0) = x(ix);
615 ret(inode, 1) = y(iy);
616 ++inode;
617 }
618
619 // stop at middle layer
620 if (iy == (nely - 1) / 2) {
621 break;
622 }
623
624 // add extra nodes of the intermediate layer, for refinement in x-direction
625 if (m_refine(iy) == 0) {
626 // - get position offset in x- and y-direction
627 double dx = m_h * static_cast<double>(m_nhx(iy) / 3);
628 double dy = m_h * static_cast<double>(m_nhy(iy) / 2);
629 // - add nodes of the intermediate layer
630 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
631 for (size_t j = 0; j < 2; ++j) {
632 ret(inode, 0) = x(ix) + dx * static_cast<double>(j + 1);
633 ret(inode, 1) = y(iy) + dy;
634 ++inode;
635 }
636 }
637 }
638 }
639
640 // loop over element layers (middle -> top) : add (refinement layer +) top layer of nodes
641
642 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
643 // get positions along the x- and z-axis
644 array_type::tensor<double, 1> x = xt::linspace<double>(0.0, m_Lx, m_layer_nelx(iy) + 1);
645
646 // add extra nodes of the intermediate layer, for refinement in x-direction
647 if (m_refine(iy) == 0) {
648 // - get position offset in x- and y-direction
649 double dx = m_h * static_cast<double>(m_nhx(iy) / 3);
650 double dy = m_h * static_cast<double>(m_nhy(iy) / 2);
651 // - add nodes of the intermediate layer
652 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
653 for (size_t j = 0; j < 2; ++j) {
654 ret(inode, 0) = x(ix) + dx * static_cast<double>(j + 1);
655 ret(inode, 1) = y(iy) + dy;
656 ++inode;
657 }
658 }
659 }
660
661 // add nodes of the top layer of this element
662 for (size_t ix = 0; ix < m_layer_nelx(iy) + 1; ++ix) {
663 ret(inode, 0) = x(ix);
664 ret(inode, 1) = y(iy + 1);
665 ++inode;
666 }
667 }
668
669 return ret;
670 }
671
672 array_type::tensor<size_t, 2> conn_impl() const
673 {
674 // allocate output
675 array_type::tensor<size_t, 2> ret = xt::empty<size_t>({m_nelem, m_nne});
676
677 // current element, number of element layers, starting nodes of each node layer
678 size_t ielem = 0;
679 size_t nely = static_cast<size_t>(m_nhy.size());
680 size_t bot, mid, top;
681
682 // loop over all element layers
683 for (size_t iy = 0; iy < nely; ++iy) {
684 // - get: starting nodes of bottom(, middle) and top layer
685 bot = m_startNode(iy);
686 mid = m_startNode(iy) + m_nnd(iy);
687 top = m_startNode(iy + 1);
688
689 // - define connectivity: no coarsening/refinement
690 if (m_refine(iy) == -1) {
691 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
692 ret(ielem, 0) = bot + (ix);
693 ret(ielem, 1) = bot + (ix + 1);
694 ret(ielem, 2) = top + (ix + 1);
695 ret(ielem, 3) = top + (ix);
696 ielem++;
697 }
698 }
699
700 // - define connectivity: refinement along the x-direction (below the middle layer)
701 else if (m_refine(iy) == 0 && iy <= (nely - 1) / 2) {
702 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
703 // -- bottom element
704 ret(ielem, 0) = bot + (ix);
705 ret(ielem, 1) = bot + (ix + 1);
706 ret(ielem, 2) = mid + (2 * ix + 1);
707 ret(ielem, 3) = mid + (2 * ix);
708 ielem++;
709 // -- top-right element
710 ret(ielem, 0) = bot + (ix + 1);
711 ret(ielem, 1) = top + (3 * ix + 3);
712 ret(ielem, 2) = top + (3 * ix + 2);
713 ret(ielem, 3) = mid + (2 * ix + 1);
714 ielem++;
715 // -- top-center element
716 ret(ielem, 0) = mid + (2 * ix);
717 ret(ielem, 1) = mid + (2 * ix + 1);
718 ret(ielem, 2) = top + (3 * ix + 2);
719 ret(ielem, 3) = top + (3 * ix + 1);
720 ielem++;
721 // -- top-left element
722 ret(ielem, 0) = bot + (ix);
723 ret(ielem, 1) = mid + (2 * ix);
724 ret(ielem, 2) = top + (3 * ix + 1);
725 ret(ielem, 3) = top + (3 * ix);
726 ielem++;
727 }
728 }
729
730 // - define connectivity: coarsening along the x-direction (above the middle layer)
731 else if (m_refine(iy) == 0 && iy > (nely - 1) / 2) {
732 for (size_t ix = 0; ix < m_layer_nelx(iy); ++ix) {
733 // -- lower-left element
734 ret(ielem, 0) = bot + (3 * ix);
735 ret(ielem, 1) = bot + (3 * ix + 1);
736 ret(ielem, 2) = mid + (2 * ix);
737 ret(ielem, 3) = top + (ix);
738 ielem++;
739 // -- lower-center element
740 ret(ielem, 0) = bot + (3 * ix + 1);
741 ret(ielem, 1) = bot + (3 * ix + 2);
742 ret(ielem, 2) = mid + (2 * ix + 1);
743 ret(ielem, 3) = mid + (2 * ix);
744 ielem++;
745 // -- lower-right element
746 ret(ielem, 0) = bot + (3 * ix + 2);
747 ret(ielem, 1) = bot + (3 * ix + 3);
748 ret(ielem, 2) = top + (ix + 1);
749 ret(ielem, 3) = mid + (2 * ix + 1);
750 ielem++;
751 // -- upper element
752 ret(ielem, 0) = mid + (2 * ix);
753 ret(ielem, 1) = mid + (2 * ix + 1);
754 ret(ielem, 2) = top + (ix + 1);
755 ret(ielem, 3) = top + (ix);
756 ielem++;
757 }
758 }
759 }
760
761 return ret;
762 }
763
764 array_type::tensor<size_t, 1> nodesBottomEdge_impl() const
765 {
766 return m_startNode(0) + xt::arange<size_t>(m_layer_nelx(0) + 1);
767 }
768
769 array_type::tensor<size_t, 1> nodesTopEdge_impl() const
770 {
771 size_t nely = m_nhy.size();
772 return m_startNode(nely) + xt::arange<size_t>(m_layer_nelx(nely - 1) + 1);
773 }
774
775 array_type::tensor<size_t, 1> nodesLeftEdge_impl() const
776 {
777 size_t nely = m_nhy.size();
778
779 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely + 1});
780
781 size_t i = 0;
782 size_t j = (nely + 1) / 2;
783 size_t k = (nely - 1) / 2;
784 size_t l = nely;
785
786 xt::view(ret, xt::range(i, j)) = xt::view(m_startNode, xt::range(i, j));
787 xt::view(ret, xt::range(k + 1, l + 1)) = xt::view(m_startNode, xt::range(k + 1, l + 1));
788
789 return ret;
790 }
791
792 array_type::tensor<size_t, 1> nodesRightEdge_impl() const
793 {
794 size_t nely = m_nhy.size();
795
796 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely + 1});
797
798 size_t i = 0;
799 size_t j = (nely + 1) / 2;
800 size_t k = (nely - 1) / 2;
801 size_t l = nely;
802
803 xt::view(ret, xt::range(i, j)) =
804 xt::view(m_startNode, xt::range(i, j)) + xt::view(m_layer_nelx, xt::range(i, j));
805
806 xt::view(ret, xt::range(k + 1, l + 1)) = xt::view(m_startNode, xt::range(k + 1, l + 1)) +
807 xt::view(m_layer_nelx, xt::range(k, l));
808
809 return ret;
810 }
811
812 array_type::tensor<size_t, 1> nodesBottomOpenEdge_impl() const
813 {
814 return m_startNode(0) + xt::arange<size_t>(1, m_layer_nelx(0));
815 }
816
817 array_type::tensor<size_t, 1> nodesTopOpenEdge_impl() const
818 {
819 size_t nely = m_nhy.size();
820
821 return m_startNode(nely) + xt::arange<size_t>(1, m_layer_nelx(nely - 1));
822 }
823
824 array_type::tensor<size_t, 1> nodesLeftOpenEdge_impl() const
825 {
826 size_t nely = m_nhy.size();
827
828 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely - 1});
829
830 size_t i = 0;
831 size_t j = (nely + 1) / 2;
832 size_t k = (nely - 1) / 2;
833 size_t l = nely;
834
835 xt::view(ret, xt::range(i, j - 1)) = xt::view(m_startNode, xt::range(i + 1, j));
836 xt::view(ret, xt::range(k, l - 1)) = xt::view(m_startNode, xt::range(k + 1, l));
837
838 return ret;
839 }
840
841 array_type::tensor<size_t, 1> nodesRightOpenEdge_impl() const
842 {
843 size_t nely = m_nhy.size();
844
845 array_type::tensor<size_t, 1> ret = xt::empty<size_t>({nely - 1});
846
847 size_t i = 0;
848 size_t j = (nely + 1) / 2;
849 size_t k = (nely - 1) / 2;
850 size_t l = nely;
851
852 xt::view(ret, xt::range(i, j - 1)) = xt::view(m_startNode, xt::range(i + 1, j)) +
853 xt::view(m_layer_nelx, xt::range(i + 1, j));
854
855 xt::view(ret, xt::range(k, l - 1)) = xt::view(m_startNode, xt::range(k + 1, l)) +
856 xt::view(m_layer_nelx, xt::range(k, l - 1));
857
858 return ret;
859 }
860
861 size_t nodesBottomLeftCorner_impl() const
862 {
863 return m_startNode(0);
864 }
865
866 size_t nodesBottomRightCorner_impl() const
867 {
868 return m_startNode(0) + m_layer_nelx(0);
869 }
870
871 size_t nodesTopLeftCorner_impl() const
872 {
873 size_t nely = m_nhy.size();
874 return m_startNode(nely);
875 }
876
877 size_t nodesTopRightCorner_impl() const
878 {
879 size_t nely = m_nhy.size();
880 return m_startNode(nely) + m_layer_nelx(nely - 1);
881 }
882
883 double m_h;
884 size_t m_nelem;
885 size_t m_nnode;
886 size_t m_nne;
887 size_t m_ndim;
888 double m_Lx;
889 array_type::tensor<size_t, 1> m_layer_nelx;
890 array_type::tensor<size_t, 1> m_nhx;
891 array_type::tensor<size_t, 1> m_nhy;
892 array_type::tensor<size_t, 1> m_nnd;
893 array_type::tensor<int, 1> m_refine;
894 array_type::tensor<size_t, 1> m_startElem;
895 array_type::tensor<size_t, 1> m_startNode;
896
900 void init(size_t nelx, size_t nely, double h, size_t nfine = 1)
901 {
902 GOOSEFEM_ASSERT(nelx >= 1ul);
903 GOOSEFEM_ASSERT(nely >= 1ul);
904
905 m_h = h;
906 m_ndim = 2;
907 m_nne = 4;
908 m_Lx = m_h * static_cast<double>(nelx);
909
910 // compute element size in y-direction (use symmetry, compute upper half)
911
912 // temporary variables
913 size_t nmin, ntot;
914 array_type::tensor<size_t, 1> nhx = xt::ones<size_t>({nely});
915 array_type::tensor<size_t, 1> nhy = xt::ones<size_t>({nely});
916 array_type::tensor<int, 1> refine = -1 * xt::ones<int>({nely});
917
918 // minimum height in y-direction (half of the height because of symmetry)
919 if (nely % 2 == 0) {
920 nmin = nely / 2;
921 }
922 else {
923 nmin = (nely + 1) / 2;
924 }
925
926 // minimum number of fine layers in y-direction (minimum 1, middle layer part of this half)
927 if (nfine % 2 == 0) {
928 nfine = nfine / 2 + 1;
929 }
930 else {
931 nfine = (nfine + 1) / 2;
932 }
933
934 if (nfine < 1) {
935 nfine = 1;
936 }
937
938 if (nfine > nmin) {
939 nfine = nmin;
940 }
941
942 // loop over element layers in y-direction, try to coarsen using these rules:
943 // (1) element size in y-direction <= distance to origin in y-direction
944 // (2) element size in x-direction should fit the total number of elements in x-direction
945 // (3) a certain number of layers have the minimum size "1" (are fine)
946 for (size_t iy = nfine;;) {
947 // initialize current size in y-direction
948 if (iy == nfine) {
949 ntot = nfine;
950 }
951 // check to stop
952 if (iy >= nely || ntot >= nmin) {
953 nely = iy;
954 break;
955 }
956
957 // rules (1,2) satisfied: coarsen in x-direction
958 if (3 * nhy(iy) <= ntot && nelx % (3 * nhx(iy)) == 0 && ntot + nhy(iy) < nmin) {
959 refine(iy) = 0;
960 nhy(iy) *= 2;
961 auto vnhy = xt::view(nhy, xt::range(iy + 1, _));
962 auto vnhx = xt::view(nhx, xt::range(iy, _));
963 vnhy *= 3;
964 vnhx *= 3;
965 }
966
967 // update the number of elements in y-direction
968 ntot += nhy(iy);
969 // proceed to next element layer in y-direction
970 ++iy;
971 // check to stop
972 if (iy >= nely || ntot >= nmin) {
973 nely = iy;
974 break;
975 }
976 }
977
978 // symmetrize, compute full information
979
980 // allocate mesh constructor parameters
981 m_nhx = xt::empty<size_t>({nely * 2 - 1});
982 m_nhy = xt::empty<size_t>({nely * 2 - 1});
983 m_refine = xt::empty<int>({nely * 2 - 1});
984 m_layer_nelx = xt::empty<size_t>({nely * 2 - 1});
985 m_nnd = xt::empty<size_t>({nely * 2});
986 m_startElem = xt::empty<size_t>({nely * 2 - 1});
987 m_startNode = xt::empty<size_t>({nely * 2});
988
989 // fill
990 // - lower half
991 for (size_t iy = 0; iy < nely; ++iy) {
992 m_nhx(iy) = nhx(nely - iy - 1);
993 m_nhy(iy) = nhy(nely - iy - 1);
994 m_refine(iy) = refine(nely - iy - 1);
995 }
996 // - upper half
997 for (size_t iy = 0; iy < nely - 1; ++iy) {
998 m_nhx(iy + nely) = nhx(iy + 1);
999 m_nhy(iy + nely) = nhy(iy + 1);
1000 m_refine(iy + nely) = refine(iy + 1);
1001 }
1002
1003 // update size
1004 nely = m_nhx.size();
1005
1006 // compute the number of elements per element layer in y-direction
1007 for (size_t iy = 0; iy < nely; ++iy) {
1008 m_layer_nelx(iy) = nelx / m_nhx(iy);
1009 }
1010
1011 // compute the number of nodes per node layer in y-direction
1012 for (size_t iy = 0; iy < (nely + 1) / 2; ++iy) {
1013 m_nnd(iy) = m_layer_nelx(iy) + 1;
1014 }
1015 for (size_t iy = (nely - 1) / 2; iy < nely; ++iy) {
1016 m_nnd(iy + 1) = m_layer_nelx(iy) + 1;
1017 }
1018
1019 // compute mesh dimensions
1020
1021 // initialize
1022 m_nnode = 0;
1023 m_nelem = 0;
1024 m_startNode(0) = 0;
1025
1026 // loop over element layers (bottom -> middle, elements become finer)
1027 for (size_t i = 0; i < (nely - 1) / 2; ++i) {
1028 // - store the first element of the layer
1029 m_startElem(i) = m_nelem;
1030 // - add the nodes of this layer
1031 if (m_refine(i) == 0) {
1032 m_nnode += (3 * m_layer_nelx(i) + 1);
1033 }
1034 else {
1035 m_nnode += (m_layer_nelx(i) + 1);
1036 }
1037 // - add the elements of this layer
1038 if (m_refine(i) == 0) {
1039 m_nelem += (4 * m_layer_nelx(i));
1040 }
1041 else {
1042 m_nelem += (m_layer_nelx(i));
1043 }
1044 // - store the starting node of the next layer
1045 m_startNode(i + 1) = m_nnode;
1046 }
1047
1048 // loop over element layers (middle -> top, elements become coarser)
1049 for (size_t i = (nely - 1) / 2; i < nely; ++i) {
1050 // - store the first element of the layer
1051 m_startElem(i) = m_nelem;
1052 // - add the nodes of this layer
1053 if (m_refine(i) == 0) {
1054 m_nnode += (5 * m_layer_nelx(i) + 1);
1055 }
1056 else {
1057 m_nnode += (m_layer_nelx(i) + 1);
1058 }
1059 // - add the elements of this layer
1060 if (m_refine(i) == 0) {
1061 m_nelem += (4 * m_layer_nelx(i));
1062 }
1063 else {
1064 m_nelem += (m_layer_nelx(i));
1065 }
1066 // - store the starting node of the next layer
1067 m_startNode(i + 1) = m_nnode;
1068 }
1069 // - add the top row of nodes
1070 m_nnode += m_layer_nelx(nely - 1) + 1;
1071 }
1072
1076 template <class C, class E>
1077 void init_by_mapping(const C& coor, const E& conn)
1078 {
1079 GOOSEFEM_ASSERT(coor.dimension() == 2);
1080 GOOSEFEM_ASSERT(conn.dimension() == 2);
1081 GOOSEFEM_ASSERT(coor.shape(1) == 2);
1082 GOOSEFEM_ASSERT(conn.shape(1) == 4);
1083 GOOSEFEM_ASSERT(conn.shape(0) > 0);
1084 GOOSEFEM_ASSERT(coor.shape(0) >= 4);
1085 GOOSEFEM_ASSERT(xt::amax(conn)() < coor.shape(0));
1086
1087 if (conn.shape(0) == 1) {
1088 this->init(1, 1, coor(conn(0, 1), 0) - coor(conn(0, 0), 0));
1089 GOOSEFEM_CHECK(xt::all(xt::equal(this->conn(), conn)));
1090 GOOSEFEM_CHECK(xt::allclose(this->coor(), coor));
1091 return;
1092 }
1093
1094 // Identify the middle layer
1095
1096 size_t emid = (conn.shape(0) - conn.shape(0) % 2) / 2;
1097 size_t eleft = emid;
1098 size_t eright = emid;
1099
1100 while (conn(eleft, 0) == conn(eleft - 1, 1) && eleft > 0) {
1101 eleft--;
1102 }
1103
1104 while (conn(eright, 1) == conn(eright + 1, 0) && eright < conn.shape(0) - 1) {
1105 eright++;
1106 }
1107
1108 GOOSEFEM_CHECK(xt::allclose(coor(conn(eleft, 0), 0), 0.0));
1109
1110 // Get element sizes along the middle layer
1111
1112 auto n0 = xt::view(conn, xt::range(eleft, eright + 1), 0);
1113 auto n1 = xt::view(conn, xt::range(eleft, eright + 1), 1);
1114 auto n2 = xt::view(conn, xt::range(eleft, eright + 1), 2);
1115 auto dx = xt::view(coor, xt::keep(n1), 0) - xt::view(coor, xt::keep(n0), 0);
1116 auto dy = xt::view(coor, xt::keep(n2), 1) - xt::view(coor, xt::keep(n1), 1);
1117 auto hx = xt::amin(dx)();
1118 auto hy = xt::amin(dy)();
1119
1120 GOOSEFEM_CHECK(xt::allclose(hx, hy));
1121 GOOSEFEM_CHECK(xt::allclose(dx, hx));
1122 GOOSEFEM_CHECK(xt::allclose(dy, hy));
1123
1124 // Extract shape and initialise
1125
1126 size_t nelx = eright - eleft + 1;
1127 size_t nely = static_cast<size_t>((coor(coor.shape(0) - 1, 1) - coor(0, 1)) / hx);
1128 this->init(nelx, nely, hx);
1129 GOOSEFEM_CHECK(xt::all(xt::equal(this->conn(), conn)));
1130 GOOSEFEM_CHECK(xt::allclose(this->coor(), coor));
1132 xt::all(xt::equal(this->elementsMiddleLayer(), eleft + xt::arange<size_t>(nelx)))
1133 );
1134 }
1135};
1136
1140namespace Map {
1141
1146public:
1147 RefineRegular() = default;
1148
1157 : m_coarse(mesh), m_nx(nx), m_ny(ny)
1158 {
1159 m_fine = Regular(nx * m_coarse.nelx(), ny * m_coarse.nely(), m_coarse.h());
1160
1163
1164 m_coarse2fine = xt::empty<size_t>({m_coarse.nelem(), nx * ny});
1165
1166 for (size_t i = 0; i < elmat_coarse.shape(0); ++i) {
1167 for (size_t j = 0; j < elmat_coarse.shape(1); ++j) {
1168 xt::view(m_coarse2fine, elmat_coarse(i, j), xt::all()) = xt::flatten(xt::view(
1169 elmat_fine, xt::range(i * ny, (i + 1) * ny), xt::range(j * nx, (j + 1) * nx)
1170 ));
1171 }
1172 }
1173 }
1174
1180 size_t nx() const
1181 {
1182 return m_nx;
1183 }
1184
1190 size_t ny() const
1191 {
1192 return m_ny;
1193 }
1194
1200 {
1201 return m_coarse;
1202 }
1203
1209 {
1210 return m_fine;
1211 }
1212
1218 {
1219 return m_coarse2fine;
1220 }
1221
1226 [[deprecated]]
1228 {
1229 return m_coarse;
1230 }
1231
1236 [[deprecated]]
1238 {
1239 return m_fine;
1240 }
1241
1246 [[deprecated]]
1248 {
1249 return m_coarse2fine;
1250 }
1251
1260 template <class T, size_t rank>
1262 {
1263 GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.size());
1264
1265 std::array<size_t, rank> shape;
1266 std::copy(data.shape().cbegin(), data.shape().cend(), &shape[0]);
1267 shape[0] = m_coarse2fine.shape(0);
1268
1269 array_type::tensor<T, rank> ret = xt::empty<T>(shape);
1270
1271 for (size_t i = 0; i < m_coarse2fine.shape(0); ++i) {
1272 auto e = xt::view(m_coarse2fine, i, xt::all());
1273 auto d = xt::view(data, xt::keep(e));
1274 xt::view(ret, i) = xt::mean(d, 0);
1275 }
1276
1277 return ret;
1278 }
1279
1290 template <class T, size_t rank, class S>
1292 const array_type::tensor<T, rank>& data,
1294 ) const
1295 {
1296 GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.size());
1297
1298 std::array<size_t, rank> shape;
1299 std::copy(data.shape().cbegin(), data.shape().cend(), &shape[0]);
1300 shape[0] = m_coarse2fine.shape(0);
1301
1302 array_type::tensor<T, rank> ret = xt::empty<T>(shape);
1303
1304 for (size_t i = 0; i < m_coarse2fine.shape(0); ++i) {
1305 auto e = xt::view(m_coarse2fine, i, xt::all());
1306 array_type::tensor<T, rank> d = xt::view(data, xt::keep(e));
1307 array_type::tensor<T, rank> w = xt::view(weights, xt::keep(e));
1308 xt::view(ret, i) = xt::average(d, w, {0});
1309 }
1310
1311 return ret;
1312 }
1313
1326 template <class T, size_t rank>
1328 {
1329 GOOSEFEM_ASSERT(data.shape(0) == m_coarse2fine.shape(0));
1330
1331 std::array<size_t, rank> shape;
1332 std::copy(data.shape().cbegin(), data.shape().cend(), &shape[0]);
1333 shape[0] = m_coarse2fine.size();
1334
1335 array_type::tensor<T, rank> ret = xt::empty<T>(shape);
1336
1337 for (size_t e = 0; e < m_coarse2fine.shape(0); ++e) {
1338 for (size_t i = 0; i < m_coarse2fine.shape(1); ++i) {
1339 xt::view(ret, m_coarse2fine(e, i)) = xt::view(data, e);
1340 }
1341 }
1342
1343 return ret;
1344 }
1345
1346private:
1349 size_t m_nx;
1350 size_t m_ny;
1351 array_type::tensor<size_t, 2> m_coarse2fine;
1352};
1353
1360public:
1361 FineLayer2Regular() = default;
1362
1369 {
1370 // ------------
1371 // Regular-mesh
1372 // ------------
1373
1375 xt::amax(m_finelayer.m_layer_nelx)(), xt::sum(m_finelayer.m_nhy)(), m_finelayer.m_h
1376 );
1377
1378 // -------
1379 // mapping
1380 // -------
1381
1382 // allocate mapping
1383 m_elem_regular.resize(m_finelayer.m_nelem);
1384 m_frac_regular.resize(m_finelayer.m_nelem);
1385
1386 // alias
1387 array_type::tensor<size_t, 1> nhx = m_finelayer.m_nhx;
1388 array_type::tensor<size_t, 1> nhy = m_finelayer.m_nhy;
1389 array_type::tensor<size_t, 1> nelx = m_finelayer.m_layer_nelx;
1390 array_type::tensor<size_t, 1> start = m_finelayer.m_startElem;
1391
1392 // 'matrix' of element numbers of the Regular-mesh
1393 array_type::tensor<size_t, 2> elementgrid = m_regular.elementgrid();
1394
1395 // cumulative number of element-rows of the Regular-mesh per layer of the FineLayer-mesh
1397 xt::concatenate(xt::xtuple(xt::zeros<size_t>({1}), xt::cumsum(nhy)));
1398
1399 // number of element layers in y-direction of the FineLayer-mesh
1400 size_t nely = nhy.size();
1401
1402 // loop over layers of the FineLayer-mesh
1403 for (size_t iy = 0; iy < nely; ++iy) {
1404 // element numbers of the Regular-mesh along this layer of the FineLayer-mesh
1405 auto el_new = xt::view(elementgrid, xt::range(cum_nhy(iy), cum_nhy(iy + 1)), xt::all());
1406
1407 // no coarsening/refinement
1408 // ------------------------
1409
1410 if (m_finelayer.m_refine(iy) == -1) {
1411 // element numbers of the FineLayer-mesh along this layer
1412 array_type::tensor<size_t, 1> el_old = start(iy) + xt::arange<size_t>(nelx(iy));
1413
1414 // loop along this layer of the FineLayer-mesh
1415 for (size_t ix = 0; ix < nelx(iy); ++ix) {
1416 // get the element numbers of the Regular-mesh for this element of the
1417 // FineLayer-mesh
1418 auto block =
1419 xt::view(el_new, xt::all(), xt::range(ix * nhx(iy), (ix + 1) * nhx(iy)));
1420
1421 // write to mapping
1422 for (auto& i : block) {
1423 m_elem_regular[el_old(ix)].push_back(i);
1424 m_frac_regular[el_old(ix)].push_back(1.0);
1425 }
1426 }
1427 }
1428
1429 // refinement along the x-direction (below the middle layer)
1430 // ---------------------------------------------------------
1431
1432 else if (m_finelayer.m_refine(iy) == 0 && iy <= (nely - 1) / 2) {
1433 // element numbers of the FineLayer-mesh along this layer
1434 // rows: coarse block, columns element numbers per block
1436 start(iy) + xt::arange<size_t>(nelx(iy) * 4ul).reshape({-1, 4});
1437
1438 // loop along this layer of the FineLayer-mesh
1439 for (size_t ix = 0; ix < nelx(iy); ++ix) {
1440 // get the element numbers of the Regular-mesh for this block of the
1441 // FineLayer-mesh
1442 auto block =
1443 xt::view(el_new, xt::all(), xt::range(ix * nhx(iy), (ix + 1) * nhx(iy)));
1444
1445 // bottom: wide-to-narrow
1446 {
1447 for (size_t j = 0; j < nhy(iy) / 2; ++j) {
1448 auto e = xt::view(block, j, xt::range(j, nhx(iy) - j));
1449
1450 m_elem_regular[el_old(ix, 0)].push_back(e(0));
1451 m_frac_regular[el_old(ix, 0)].push_back(0.5);
1452
1453 for (size_t k = 1; k < e.size() - 1; ++k) {
1454 m_elem_regular[el_old(ix, 0)].push_back(e(k));
1455 m_frac_regular[el_old(ix, 0)].push_back(1.0);
1456 }
1457
1458 m_elem_regular[el_old(ix, 0)].push_back(e(e.size() - 1));
1459 m_frac_regular[el_old(ix, 0)].push_back(0.5);
1460 }
1461 }
1462
1463 // top: regular small element
1464 {
1465 auto e = xt::view(
1466 block,
1467 xt::range(nhy(iy) / 2, nhy(iy)),
1468 xt::range(1 * nhx(iy) / 3, 2 * nhx(iy) / 3)
1469 );
1470
1471 for (auto& i : e) {
1472 m_elem_regular[el_old(ix, 2)].push_back(i);
1473 m_frac_regular[el_old(ix, 2)].push_back(1.0);
1474 }
1475 }
1476
1477 // left
1478 {
1479 // left-bottom: narrow-to-wide
1480 for (size_t j = 0; j < nhy(iy) / 2; ++j) {
1481 auto e = xt::view(block, j, xt::range(0, j + 1));
1482
1483 for (size_t k = 0; k < e.size() - 1; ++k) {
1484 m_elem_regular[el_old(ix, 3)].push_back(e(k));
1485 m_frac_regular[el_old(ix, 3)].push_back(1.0);
1486 }
1487
1488 m_elem_regular[el_old(ix, 3)].push_back(e(e.size() - 1));
1489 m_frac_regular[el_old(ix, 3)].push_back(0.5);
1490 }
1491
1492 // left-top: regular
1493 {
1494 auto e = xt::view(
1495 block,
1496 xt::range(nhy(iy) / 2, nhy(iy)),
1497 xt::range(0 * nhx(iy) / 3, 1 * nhx(iy) / 3)
1498 );
1499
1500 for (auto& i : e) {
1501 m_elem_regular[el_old(ix, 3)].push_back(i);
1502 m_frac_regular[el_old(ix, 3)].push_back(1.0);
1503 }
1504 }
1505 }
1506
1507 // right
1508 {
1509 // right-bottom: narrow-to-wide
1510 for (size_t j = 0; j < nhy(iy) / 2; ++j) {
1511 auto e = xt::view(block, j, xt::range(nhx(iy) - j - 1, nhx(iy)));
1512
1513 m_elem_regular[el_old(ix, 1)].push_back(e(0));
1514 m_frac_regular[el_old(ix, 1)].push_back(0.5);
1515
1516 for (size_t k = 1; k < e.size(); ++k) {
1517 m_elem_regular[el_old(ix, 1)].push_back(e(k));
1518 m_frac_regular[el_old(ix, 1)].push_back(1.0);
1519 }
1520 }
1521
1522 // right-top: regular
1523 {
1524 auto e = xt::view(
1525 block,
1526 xt::range(nhy(iy) / 2, nhy(iy)),
1527 xt::range(2 * nhx(iy) / 3, 3 * nhx(iy) / 3)
1528 );
1529
1530 for (auto& i : e) {
1531 m_elem_regular[el_old(ix, 1)].push_back(i);
1532 m_frac_regular[el_old(ix, 1)].push_back(1.0);
1533 }
1534 }
1535 }
1536 }
1537 }
1538
1539 // coarsening along the x-direction (above the middle layer)
1540 else if (m_finelayer.m_refine(iy) == 0 && iy > (nely - 1) / 2) {
1541 // element numbers of the FineLayer-mesh along this layer
1542 // rows: coarse block, columns element numbers per block
1544 start(iy) + xt::arange<size_t>(nelx(iy) * 4ul).reshape({-1, 4});
1545
1546 // loop along this layer of the FineLayer-mesh
1547 for (size_t ix = 0; ix < nelx(iy); ++ix) {
1548 // get the element numbers of the Regular-mesh for this block of the
1549 // FineLayer-mesh
1550 auto block =
1551 xt::view(el_new, xt::all(), xt::range(ix * nhx(iy), (ix + 1) * nhx(iy)));
1552
1553 // top: narrow-to-wide
1554 {
1555 for (size_t j = 0; j < nhy(iy) / 2; ++j) {
1556 auto e = xt::view(
1557 block,
1558 nhy(iy) / 2 + j,
1559 xt::range(1 * nhx(iy) / 3 - j - 1, 2 * nhx(iy) / 3 + j + 1)
1560 );
1561
1562 m_elem_regular[el_old(ix, 3)].push_back(e(0));
1563 m_frac_regular[el_old(ix, 3)].push_back(0.5);
1564
1565 for (size_t k = 1; k < e.size() - 1; ++k) {
1566 m_elem_regular[el_old(ix, 3)].push_back(e(k));
1567 m_frac_regular[el_old(ix, 3)].push_back(1.0);
1568 }
1569
1570 m_elem_regular[el_old(ix, 3)].push_back(e(e.size() - 1));
1571 m_frac_regular[el_old(ix, 3)].push_back(0.5);
1572 }
1573 }
1574
1575 // bottom: regular small element
1576 {
1577 auto e = xt::view(
1578 block,
1579 xt::range(0, nhy(iy) / 2),
1580 xt::range(1 * nhx(iy) / 3, 2 * nhx(iy) / 3)
1581 );
1582
1583 for (auto& i : e) {
1584 m_elem_regular[el_old(ix, 1)].push_back(i);
1585 m_frac_regular[el_old(ix, 1)].push_back(1.0);
1586 }
1587 }
1588
1589 // left
1590 {
1591 // left-bottom: regular
1592 {
1593 auto e = xt::view(
1594 block,
1595 xt::range(0, nhy(iy) / 2),
1596 xt::range(0 * nhx(iy) / 3, 1 * nhx(iy) / 3)
1597 );
1598
1599 for (auto& i : e) {
1600 m_elem_regular[el_old(ix, 0)].push_back(i);
1601 m_frac_regular[el_old(ix, 0)].push_back(1.0);
1602 }
1603 }
1604
1605 // left-top: narrow-to-wide
1606 for (size_t j = 0; j < nhy(iy) / 2; ++j) {
1607 auto e =
1608 xt::view(block, nhy(iy) / 2 + j, xt::range(0, 1 * nhx(iy) / 3 - j));
1609
1610 for (size_t k = 0; k < e.size() - 1; ++k) {
1611 m_elem_regular[el_old(ix, 0)].push_back(e(k));
1612 m_frac_regular[el_old(ix, 0)].push_back(1.0);
1613 }
1614
1615 m_elem_regular[el_old(ix, 0)].push_back(e(e.size() - 1));
1616 m_frac_regular[el_old(ix, 0)].push_back(0.5);
1617 }
1618 }
1619
1620 // right
1621 {
1622 // right-bottom: regular
1623 {
1624 auto e = xt::view(
1625 block,
1626 xt::range(0, nhy(iy) / 2),
1627 xt::range(2 * nhx(iy) / 3, 3 * nhx(iy) / 3)
1628 );
1629
1630 for (auto& i : e) {
1631 m_elem_regular[el_old(ix, 2)].push_back(i);
1632 m_frac_regular[el_old(ix, 2)].push_back(1.0);
1633 }
1634 }
1635
1636 // right-top: narrow-to-wide
1637 for (size_t j = 0; j < nhy(iy) / 2; ++j) {
1638 auto e = xt::view(
1639 block, nhy(iy) / 2 + j, xt::range(2 * nhx(iy) / 3 + j, nhx(iy))
1640 );
1641
1642 m_elem_regular[el_old(ix, 2)].push_back(e(0));
1643 m_frac_regular[el_old(ix, 2)].push_back(0.5);
1644
1645 for (size_t k = 1; k < e.size(); ++k) {
1646 m_elem_regular[el_old(ix, 2)].push_back(e(k));
1647 m_frac_regular[el_old(ix, 2)].push_back(1.0);
1648 }
1649 }
1650 }
1651 }
1652 }
1653 }
1654 }
1655
1662 {
1663 return m_regular;
1664 }
1665
1672 {
1673 return m_finelayer;
1674 }
1675
1676 // elements of the Regular mesh per element of the FineLayer mesh
1677 // and the fraction by which the overlap is
1678
1685 std::vector<std::vector<size_t>> map() const
1686 {
1687 return m_elem_regular;
1688 }
1689
1695 std::vector<std::vector<double>> mapFraction() const
1696 {
1697 return m_frac_regular;
1698 }
1699
1705 [[deprecated]]
1707 {
1708 return m_regular;
1709 }
1710
1716 [[deprecated]]
1718 {
1719 return m_finelayer;
1720 }
1721
1722 // elements of the Regular mesh per element of the FineLayer mesh
1723 // and the fraction by which the overlap is
1724
1731 [[deprecated]]
1732 std::vector<std::vector<size_t>> getMap() const
1733 {
1734 return m_elem_regular;
1735 }
1736
1742 [[deprecated]]
1743 std::vector<std::vector<double>> getMapFraction() const
1744 {
1745 return m_frac_regular;
1746 }
1747
1761 template <class T, size_t rank>
1763 {
1764 GOOSEFEM_ASSERT(data.shape(0) == m_finelayer.nelem());
1765
1766 std::array<size_t, rank> shape;
1767 std::copy(data.shape().cbegin(), data.shape().cend(), &shape[0]);
1768 shape[0] = m_regular.nelem();
1769
1770 array_type::tensor<T, rank> ret = xt::zeros<T>(shape);
1771
1772 for (size_t e = 0; e < m_finelayer.nelem(); ++e) {
1773 for (size_t i = 0; i < m_elem_regular[e].size(); ++i) {
1774 xt::view(ret, m_elem_regular[e][i]) += m_frac_regular[e][i] * xt::view(data, e);
1775 }
1776 }
1777
1778 return ret;
1779 }
1780
1781private:
1784 std::vector<std::vector<size_t>> m_elem_regular;
1785 std::vector<std::vector<double>> m_frac_regular;
1786};
1787
1788} // namespace Map
1789
1790} // namespace Quad4
1791} // namespace Mesh
1792} // namespace GooseFEM
1793
1794#endif
Generic mesh operations.
Mesh with fine middle layer, and coarser elements towards the top and bottom.
Definition MeshQuad4.h:200
const array_type::tensor< size_t, 1 > & elemrow_nhy() const
Edge size in y-direction of a block, in units of h, per row of blocks.
Definition MeshQuad4.h:253
array_type::tensor< size_t, 1 > roll(size_t n)
Mapping to 'roll' periodically in the x-direction,.
Definition MeshQuad4.h:539
array_type::tensor< size_t, 1 > elementsLayer(size_t layer) const
Elements along a layer.
Definition MeshQuad4.h:299
array_type::tensor< size_t, 1 > elementgrid_leftright(size_t e, size_t left, size_t right, bool periodic=true)
Select region of elements from 'matrix' of element numbers around an element: left/right from element...
Definition MeshQuad4.h:483
array_type::tensor< size_t, 1 > elementgrid_around_ravel(size_t e, size_t size, bool periodic=true)
Select region of elements from 'matrix' of element numbers around an element: square box with edge-si...
Definition MeshQuad4.h:410
FineLayer(const C &coor, const E &conn)
Reconstruct class for given coordinates / connectivity.
Definition MeshQuad4.h:229
FineLayer(size_t nelx, size_t nely, double h=1.0, size_t nfine=1)
Constructor.
Definition MeshQuad4.h:215
const array_type::tensor< int, 1 > & elemrow_type() const
Per row of blocks: -1: normal layer 0: transition layer to match coarse and finer element on the prev...
Definition MeshQuad4.h:265
const array_type::tensor< size_t, 1 > & elemrow_nhx() const
Edge size in x-direction of a block, in units of h, per row of blocks.
Definition MeshQuad4.h:241
array_type::tensor< size_t, 1 > elementgrid_ravel(std::vector< size_t > start_stop_rows, std::vector< size_t > start_stop_cols) const
Select region of elements from 'matrix' of element numbers.
Definition MeshQuad4.h:314
const array_type::tensor< size_t, 1 > & elemrow_nelem() const
Number of elements per row of blocks.
Definition MeshQuad4.h:277
array_type::tensor< size_t, 1 > elementsMiddleLayer() const
Elements in the middle (fine) layer.
Definition MeshQuad4.h:287
Map a FineLayer mesh to a Regular mesh.
Definition MeshQuad4.h:1359
array_type::tensor< T, rank > mapToRegular(const array_type::tensor< T, rank > &data) const
Map element quantities to Regular.
Definition MeshQuad4.h:1762
std::vector< std::vector< double > > getMapFraction() const
To overlap fraction for each item in the mapping in getMap().
Definition MeshQuad4.h:1743
GooseFEM::Mesh::Quad4::FineLayer fineLayerMesh() const
Obtain the FineLayer mesh (copy of the mesh passed to the constructor).
Definition MeshQuad4.h:1671
std::vector< std::vector< size_t > > map() const
Get element-mapping: elements of the Regular mesh per element of the FineLayer mesh.
Definition MeshQuad4.h:1685
GooseFEM::Mesh::Quad4::Regular regularMesh() const
Obtain the Regular mesh.
Definition MeshQuad4.h:1661
GooseFEM::Mesh::Quad4::FineLayer getFineLayerMesh() const
Obtain the FineLayer mesh (copy of the mesh passed to the constructor).
Definition MeshQuad4.h:1717
GooseFEM::Mesh::Quad4::Regular getRegularMesh() const
Obtain the Regular mesh.
Definition MeshQuad4.h:1706
std::vector< std::vector< double > > mapFraction() const
To overlap fraction for each item in the mapping in map().
Definition MeshQuad4.h:1695
std::vector< std::vector< size_t > > getMap() const
Get element-mapping: elements of the Regular mesh per element of the FineLayer mesh.
Definition MeshQuad4.h:1732
FineLayer2Regular(const GooseFEM::Mesh::Quad4::FineLayer &mesh)
Constructors.
Definition MeshQuad4.h:1368
Refine a Regular mesh: subdivide elements in several smaller elements.
Definition MeshQuad4.h:1145
GooseFEM::Mesh::Quad4::Regular getCoarseMesh() const
Obtain the coarse mesh (copy of the mesh passed to the constructor).
Definition MeshQuad4.h:1227
const array_type::tensor< size_t, 2 > & getMap() const
Get element-mapping: elements of the fine mesh per element of the coarse mesh.
Definition MeshQuad4.h:1247
array_type::tensor< T, rank > mapToFine(const array_type::tensor< T, rank > &data) const
Map element quantities to the fine mesh.
Definition MeshQuad4.h:1327
GooseFEM::Mesh::Quad4::Regular fineMesh() const
Obtain the fine mesh.
Definition MeshQuad4.h:1208
GooseFEM::Mesh::Quad4::Regular coarseMesh() const
Obtain the coarse mesh (copy of the mesh passed to the constructor).
Definition MeshQuad4.h:1199
size_t ny() const
For each coarse element: number of fine elements in y-direction.
Definition MeshQuad4.h:1190
array_type::tensor< T, rank > meanToCoarse(const array_type::tensor< T, rank > &data) const
Compute the mean of the quantity define on the fine mesh when mapped on the coarse mesh.
Definition MeshQuad4.h:1261
RefineRegular(const GooseFEM::Mesh::Quad4::Regular &mesh, size_t nx, size_t ny)
Constructor.
Definition MeshQuad4.h:1156
size_t nx() const
For each coarse element: number of fine elements in x-direction.
Definition MeshQuad4.h:1180
array_type::tensor< T, rank > averageToCoarse(const array_type::tensor< T, rank > &data, const array_type::tensor< S, rank > &weights) const
Compute the average of the quantity define on the fine mesh when mapped on the coarse mesh.
Definition MeshQuad4.h:1291
GooseFEM::Mesh::Quad4::Regular getFineMesh() const
Obtain the fine mesh.
Definition MeshQuad4.h:1237
const array_type::tensor< size_t, 2 > & map() const
Get element-mapping: elements of the fine mesh per element of the coarse mesh.
Definition MeshQuad4.h:1217
Regular mesh: equi-sized elements.
Definition MeshQuad4.h:32
Regular(size_t nelx, size_t nely, double h=1.0)
Constructor.
Definition MeshQuad4.h:43
array_type::tensor< size_t, 2 > elementgrid() const
Element numbers as 'matrix'.
Definition MeshQuad4.h:63
CRTP base class for regular meshes in 2d.
Definition Mesh.h:339
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 coor() const
Nodal coordinates [nnode, ndim].
Definition Mesh.h:264
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
auto nelem() const
Number of elements.
Definition Mesh.h:192
auto conn() const
Connectivity [nelem, nne].
Definition Mesh.h:273
Basic configuration:
#define GOOSEFEM_ASSERT(expr)
All assertions are implementation as::
Definition config.h:97
#define GOOSEFEM_WIP_ASSERT(expr)
Assertion that concerns temporary implementation limitations.
Definition config.h:117
#define GOOSEFEM_CHECK(expr)
Assertion that cannot be switched off.
Definition config.h:107
ElementType
Enumerator for element-types.
Definition Mesh.h:31
@ Quad4
Quadrilateral: 4-noded element in 2-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