OOFEM 3.0
Loading...
Searching...
No Matches
subdivision.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35#include "subdivision.h"
36#include "material.h"
37#include "errorestimator.h"
38#include "domain.h"
39#include "node.h"
40#include "element.h"
41#include "mathfem.h"
42#include "masterdof.h"
43#include "simpleslavedof.h"
44#include "nonlocalbarrier.h"
45#include "initialcondition.h"
46#include "classfactory.h"
47#include "outputmanager.h"
48#include "crosssection.h"
49#include "function.h"
50#include "timer.h"
51#include "remeshingcrit.h"
52#include "dynamicinputrecord.h"
53#include "engngm.h"
54
55#include <queue>
56#include <set>
57
58#ifdef __OOFEG
59 #include "oofeggraphiccontext.h"
60#endif
61
62#ifdef __MPI_PARALLEL_MODE
63 #include "parallel.h"
64 #include "problemcomm.h"
65 #include "communicator.h"
66 #include "datastream.h"
68#endif
69
70namespace oofem {
71
72REGISTER_Mesher(Subdivision, MPT_SUBDIVISION);
73
74//#define __VERBOSE_PARALLEL
75#define DEBUG_CHECK
76//#define DEBUG_INFO
77//#define DEBUG_SMOOTHING
78
79// QUICK_HACK enables comparison of sequential and parallel version when smoothing is applied;
80// sequential nodes on parallel interface are marked as boundary (in input file);
81// important: there is a limitation:
82// single element is allowed to have only 2 (in 2D) or 3 (in 3D) nodes marked as boundary
83// if quick hack is used, standard identification of boundary nodes during bisection is
84// replaced by simplified version;
85// also smoothing of nodes is driven by coordinates based ordering which should ensure
86// that sequential nodes (on individual parallel partitions) are smoothed in the same
87// order as parallel nodes
88
89//#define QUICK_HACK
90
91#ifdef __OOFEG
92 #define DRAW_IRREGULAR_NODES
93 #define DRAW_REMOTE_ELEMENTS
94 //#define DRAW_MESH_BEFORE_BISECTION
95 #define DRAW_MESH_AFTER_BISECTION
96 //#define DRAW_MESH_AFTER_EACH_BISECTION_LEVEL
97#endif
98
99
100
101//#define NM // Nooru Mohamed
102//#define BRAZIL_2D // splitting brazil test
103//#define THREEPBT_3D // 3pbt
104#define HEADEDSTUD // headed stud
105
106
107
108/* builds connectivity of top level node only however at any level of the subdivision */
109
110int Subdivision :: RS_Node :: buildTopLevelNodeConnectivity(ConnectivityTable *ct)
111{
112 IntArray me(1), connElems;
113 me.at(1) = this->giveNumber();
114
115 ct->giveNodeNeighbourList(connElems, me);
116 this->connectedElements.preallocate( connElems.giveSize() ); // estimate size of the list
117
118 for ( int el : connElems ) {
119
120#ifdef __MPI_PARALLEL_MODE
121 if ( this->mesh->giveElement(el)->giveParallelMode() != Element_local ) {
122 continue;
123 }
124#endif
125
126 // use nonzero chunk, the estimated size may be not large enough
127 this->mesh->giveElement(el)->buildTopLevelNodeConnectivity(this);
128 }
129
130 return connectedElements.giveSize();
131}
132
133
134void Subdivision :: RS_Element :: buildTopLevelNodeConnectivity(Subdivision :: RS_Node *node)
135{
136 if ( this->isTerminal() ) {
137 node->insertConnectedElement( this->giveNumber() );
138 return;
139 }
140
141 for ( int el = 1; el <= this->giveChildren()->giveSize(); el++ ) {
142 Subdivision::RS_Element *elem = mesh->giveElement( this->giveChildren()->at(el) );
143 for ( int i = 1; i <= elem->giveNodes()->giveSize(); i++ ) {
144 if ( elem->giveNode(i) == node->giveNumber() ) {
146 break;
147 }
148 }
149 }
150}
151
152
153#ifdef __MPI_PARALLEL_MODE
154
155int
156Subdivision :: RS_Node :: importConnectivity(ConnectivityTable *ct)
157{
158 IntArray me(1), connElems;
159 int cnt = 0;
160 me.at(1) = this->giveNumber();
161
162 ct->giveNodeNeighbourList(connElems, me);
163 this->connectedElements.preallocate( connElems.giveSize() ); // estimate size of the list
164
165 for ( int el : connElems ) {
166 if ( this->mesh->giveElement(el)->giveParallelMode() != Element_local ) {
167 continue;
168 }
169
170 // use zero chunk, the array is large enough
171 this->connectedElements.insertSorted(el, 0);
172 cnt++;
173 }
174
175 return cnt;
176}
177
178
179
180void
181Subdivision :: RS_Node :: numberSharedEdges()
182{
183 int num = this->giveNumber();
184 IntArray connNodes;
185 const IntArray &connElems = *this->giveConnectedElements();
186
187 for ( int el : connElems ) {
188 this->mesh->giveElement( el )->numberSharedEdges(num, connNodes);
189 }
190}
191
192
193void
194Subdivision :: RS_Triangle :: numberSharedEdges(int iNode, IntArray &connNodes)
195{
196 int eNum = this->mesh->giveNumberOfEdges();
197
198 for ( int jNode : nodes ) {
199 if ( jNode == iNode ) {
200 continue;
201 }
202
203 if ( this->mesh->giveNode(jNode)->giveParallelMode() != DofManager_shared ) {
204 continue;
205 }
206
207 // potential shared edge
208
209 if ( connNodes.contains(jNode) ) {
210 continue; // edge already processed (from iNode)
211 }
212
213 connNodes.followedBy(jNode, 10);
214
215 int eIndex = giveEdgeIndex(iNode, jNode);
216
217 if ( shared_edges.giveSize() ) {
218 if ( shared_edges.at(eIndex) ) {
219 continue; // edge already processed (from jNode)
220 }
221 }
222
223 // create edge (even if it might not be shared)
224 Subdivision :: RS_SharedEdge *_edge = new Subdivision :: RS_SharedEdge(this->mesh);
225 _edge->setEdgeNodes(iNode, jNode);
226
227 this->mesh->addEdge(_edge);
228 eNum++;
229
230 // get the tentative partitions
231 // they must be confirmed via mutual communication
232 IntArray partitions;
233 if ( _edge->giveSharedPartitions(partitions) ) {
234 _edge->setPartitions(partitions);
235
236 // I do rely on the fact that in 2D shared edge can be incident only to one element !!!
237 if ( !shared_edges.giveSize() ) {
239 }
240
241 shared_edges.at(eIndex) = eNum;
242 }
243 }
244}
245
246
247void
248Subdivision :: RS_Tetra :: numberSharedEdges(int iNode, IntArray &connNodes)
249{
250 int eNum = this->mesh->giveNumberOfEdges();
251
252 for ( int jNode : nodes ) {
253 if ( jNode == iNode ) {
254 continue;
255 }
256
257 if ( this->mesh->giveNode(jNode)->giveParallelMode() != DofManager_shared ) {
258 continue;
259 }
260
261 // potential shared edge
262
263 if ( connNodes.contains(jNode) ) {
264 continue; // edge already processed (from iNode)
265 }
266
267 connNodes.followedBy(jNode, 20);
268
269 int eIndex = giveEdgeIndex(iNode, jNode);
270
271 if ( shared_edges.giveSize() ) {
272 if ( shared_edges.at(eIndex) ) {
273 continue; // edge already processed (from jNode)
274 }
275 }
276
277 // create edge (even if it might not be shared)
278 Subdivision :: RS_SharedEdge *_edge = new Subdivision :: RS_SharedEdge(this->mesh);
279 _edge->setEdgeNodes(iNode, jNode);
280
281 this->mesh->addEdge(_edge);
282 ++eNum;
283
284 // get the tentative partitions
285 // they must be confirmed via mutual communication
286 IntArray partitions;
287 if ( _edge->giveSharedPartitions(partitions) ) {
288 _edge->setPartitions(partitions);
289 if ( !this->giveSharedEdges()->giveSize() ) {
290 this->makeSharedEdges();
291 }
292
293 shared_edges.at(eIndex) = eNum;
294
295 // put edge on all elements sharing it
296 const IntArray *iElems, *jElems;
297
298 iElems = mesh->giveNode(iNode)->giveConnectedElements();
299 jElems = mesh->giveNode(jNode)->giveConnectedElements();
300
301 IntArray common;
302 if ( iElems->giveSize() <= jElems->giveSize() ) {
303 common.preallocate( iElems->giveSize() );
304 } else {
305 common.preallocate( jElems->giveSize() );
306 }
307
308 // I do rely on the fact that the arrays are ordered !!!
309 // I am using zero chunk because common is large enough
310 int elems = iElems->findCommonValuesSorted(* jElems, common, 0);
311 #ifdef DEBUG_CHECK
312 if ( !elems ) {
313 OOFEM_ERROR("potentionally shared edge %d is not shared by common elements", eNum);
314 }
315
316 #endif
317 for ( int ie = 1; ie <= elems; ie++ ) {
318 Subdivision :: RS_Element *elem = mesh->giveElement( common.at(ie) );
319 if ( elem == this ) {
320 continue;
321 }
322
323 eIndex = elem->giveEdgeIndex(iNode, jNode);
324 if ( !elem->giveSharedEdges()->giveSize() ) {
325 elem->makeSharedEdges();
326 }
327
328 elem->setSharedEdge(eIndex, eNum);
329 }
330 }
331 }
332}
333
334
335// CAUTION: gives the tentative partitions;
336// they must be confirmed via mutual communication
337
338int
339Subdivision :: RS_SharedEdge :: giveSharedPartitions(IntArray &partitions)
340{
341 int count = 0;
342 int myrank = this->mesh->giveSubdivision()->giveRank();
343 const IntArray *iPartitions = mesh->giveNode(iNode)->givePartitions();
344 const IntArray *jPartitions = mesh->giveNode(jNode)->givePartitions();
345
346 // find common partitions;
347 // this could be done more efficiently (using method findCommonValuesSorted)
348 // if array iPartitions and jPartitions were sorted;
349 // however they are not sorted in current version
350 int ipsize = iPartitions->giveSize();
351 for ( int i = 1; i <= ipsize; i++ ) {
352 if ( jPartitions->contains( iPartitions->at(i) ) && ( iPartitions->at(i) != myrank ) ) {
353 partitions.followedBy(iPartitions->at(i), 2);
354 count++;
355 }
356 }
357
358 return count;
359}
360
361#endif
362
363
364double
365Subdivision :: RS_Element :: giveRequiredDensity()
366{
367 double answer = 0.0;
368 for ( int n: nodes ) {
369 answer += mesh->giveNode( n )->giveRequiredDensity();
370 }
371
372 answer = answer / nodes.giveSize();
373 return answer;
374}
375
376
377int
378Subdivision :: RS_Element :: giveTopParent()
379{
380 RS_Element *elem = this;
381 while ( elem->giveNumber() != elem->giveParent() ) {
382 elem = mesh->giveElement( elem->giveParent() );
383 }
384
385 return elem->giveNumber();
386}
387
388
389Subdivision :: RS_Triangle :: RS_Triangle(int number, RS_Mesh *mesh, int parent, IntArray &nodes) :
390 Subdivision :: RS_Element(number, mesh, parent, nodes)
391{
392 irregular_nodes.resize(3);
393 irregular_nodes.zero();
394 neghbours_base_elements.resize(3);
395 neghbours_base_elements.zero();
396
397#ifdef DEBUG_CHECK
398 if ( nodes.findFirstIndexOf(0) ) {
399 OOFEM_ERROR("0 node of element %d", this->number);
400 }
401
402#endif
403}
404
405
406Subdivision :: RS_Tetra :: RS_Tetra(int number, RS_Mesh *mesh, int parent, IntArray &nodes) :
407 Subdivision :: RS_Element(number, mesh, parent, nodes)
408{
409 irregular_nodes.resize(6);
410 irregular_nodes.zero();
411 side_leIndex.resize(4);
412 side_leIndex.zero();
413 neghbours_base_elements.resize(4);
414 neghbours_base_elements.zero();
415
416#ifdef DEBUG_CHECK
417 if ( nodes.findFirstIndexOf(0) ) {
418 OOFEM_ERROR("0 node of element %d", this->number);
419 }
420
421#endif
422}
423
424
425int
426Subdivision :: RS_Triangle :: evaluateLongestEdge()
427{
428 if ( !this->leIndex ) { // prevent multiple evaluation
429 double elength1, elength2, elength3;
430
431 elength1 = distance_square( *mesh->giveNode( this->nodes.at(1) )->giveCoordinates(), * ( mesh->giveNode( this->nodes.at(2) )->giveCoordinates() ) );
432 elength2 = distance_square( *mesh->giveNode( this->nodes.at(2) )->giveCoordinates(), * ( mesh->giveNode( this->nodes.at(3) )->giveCoordinates() ) );
433 elength3 = distance_square( *mesh->giveNode( this->nodes.at(3) )->giveCoordinates(), * ( mesh->giveNode( this->nodes.at(1) )->giveCoordinates() ) );
434
435 leIndex = 1;
436 if ( elength2 > elength1 ) {
437 leIndex = 2;
438 if ( elength3 > elength2 ) {
439 leIndex = 3;
440 }
441 } else if ( elength3 > elength1 ) {
442 leIndex = 3;
443 }
444 }
445
446 return ( leIndex );
447}
448
449
450int
451Subdivision :: RS_Tetra :: evaluateLongestEdge()
452{
453 if ( !this->leIndex ) { // prevent multiple evaluation
454 // IMPORTANT: ambiguity must be handled !!!
455
456 // in order to achieve that shared tetra faces are subdivided in compatible way,
457 // always the same longest edge must be identified;
458 // this may be problem if there are two or more edges of the "same" length
459 // then the longest is dependent on the order in which edges are processed;
460 // also in order to get always the same distance of two nodes, the nodes should be processes in the same order;
461
462 // however it is not clear whether one may rely that the same distance is always obtained for the same pair of nodes
463 // (in proper order) especially if processed on different processors
464 // in parallel environment some additional communication may be needed !!! HUHU
465
466 // if the second largest edge is not equal to the largest edge and if the largest and second largest edges
467 // are opposite edges, no action is theoretically required;
468 // but because it is not clear whether different result would be obtained if edge lengths are evaluated
469 // using node ordering, this possibility (of no action) is not considered
470
471 double elength [ 6 ], maxlength, maxlen [ 4 ];
472 int i, j, side, l_nd [ 4 ], ind [ 6 ];
473 // array ed_side contains face numbers shared by the edge (indexing from 0)
474 int nd [ 4 ] = {
475 0, 1, 2, 3
476 }, ed_side [ 6 ] [ 2 ] = { { 0, 1 }, { 0, 2 }, { 0, 3 }, { 3, 1 }, { 1, 2 }, { 2, 3 } };
477 // array ed contains edge numbers (1 to 6) connecting the node with each node (1 to 4)
478 // (indexing from 1, zero means, that node is not connected by an edge with itself)
479 int ed [ 4 ] [ 4 ] = { { 0, 1, 3, 4 }, { 1, 0, 2, 5 }, { 3, 2, 0, 6 }, { 4, 5, 6, 0 } };
480#ifdef __MPI_PARALLEL_MODE
481 int g_nd [ 4 ];
482#endif
483 bool swap;
484
485 // sort node ids
486 for ( i = 0; i < 4; i++ ) {
487 l_nd [ i ] = nodes.at(i + 1);
488#ifdef __MPI_PARALLEL_MODE
489 g_nd [ i ] = mesh->giveNode(l_nd [ i ])->giveGlobalNumber();
490#endif
491 }
492
493 swap = true;
494 while ( swap ) {
495 swap = false;
496 for ( i = 0; i < 3; i++ ) {
497#ifdef __MPI_PARALLEL_MODE
498 if ( g_nd [ i ] > g_nd [ i + 1 ] ) {
499#else
500 if ( l_nd [ i ] > l_nd [ i + 1 ] ) {
501#endif
502 int tmp;
503#ifdef __MPI_PARALLEL_MODE
504 tmp = g_nd [ i ];
505 g_nd [ i ] = g_nd [ i + 1 ];
506 g_nd [ i + 1 ] = tmp;
507#endif
508 tmp = l_nd [ i ];
509 l_nd [ i ] = l_nd [ i + 1 ];
510 l_nd [ i + 1 ] = tmp;
511 tmp = nd [ i ];
512 nd [ i ] = nd [ i + 1 ];
513 nd [ i + 1 ] = tmp;
514 swap = true;
515 }
516 }
517 }
518
519 // assign edge indices from smallest node id !!!
520 ind [ 0 ] = ed [ nd [ 0 ] ] [ nd [ 1 ] ];
521 ind [ 1 ] = ed [ nd [ 0 ] ] [ nd [ 2 ] ];
522 ind [ 2 ] = ed [ nd [ 0 ] ] [ nd [ 3 ] ];
523 ind [ 3 ] = ed [ nd [ 1 ] ] [ nd [ 2 ] ];
524 ind [ 4 ] = ed [ nd [ 1 ] ] [ nd [ 3 ] ];
525 ind [ 5 ] = ed [ nd [ 2 ] ] [ nd [ 3 ] ];
526
527 // evaluate edge lengths from smallest node id !!!
528 elength [ 0 ] = distance_square( *mesh->giveNode(l_nd [ 0 ])->giveCoordinates(), * ( mesh->giveNode(l_nd [ 1 ])->giveCoordinates() ) );
529 elength [ 1 ] = distance_square( *mesh->giveNode(l_nd [ 0 ])->giveCoordinates(), * ( mesh->giveNode(l_nd [ 2 ])->giveCoordinates() ) );
530 elength [ 2 ] = distance_square( *mesh->giveNode(l_nd [ 0 ])->giveCoordinates(), * ( mesh->giveNode(l_nd [ 3 ])->giveCoordinates() ) );
531 elength [ 3 ] = distance_square( *mesh->giveNode(l_nd [ 1 ])->giveCoordinates(), * ( mesh->giveNode(l_nd [ 2 ])->giveCoordinates() ) );
532 elength [ 4 ] = distance_square( *mesh->giveNode(l_nd [ 1 ])->giveCoordinates(), * ( mesh->giveNode(l_nd [ 3 ])->giveCoordinates() ) );
533 elength [ 5 ] = distance_square( *mesh->giveNode(l_nd [ 2 ])->giveCoordinates(), * ( mesh->giveNode(l_nd [ 3 ])->giveCoordinates() ) );
534
535 // get absolutely largest edge and the largest edge on individual sides
536 // process edges in the same order in which their length was evaluated !!!
537 maxlength = maxlen [ 0 ] = maxlen [ 1 ] = maxlen [ 2 ] = maxlen [ 3 ] = 0.0;
538 for ( i = 0; i < 6; i++ ) {
539 if ( elength [ i ] > maxlength ) {
540 maxlength = elength [ i ];
541 leIndex = ind [ i ];
542 for ( j = 0; j < 2; j++ ) {
543 side = ed_side [ ind [ i ] - 1 ] [ j ];
544 maxlen [ side ] = elength [ i ];
545 side_leIndex.at(side + 1) = ind [ i ];
546 }
547 } else {
548 for ( j = 0; j < 2; j++ ) {
549 side = ed_side [ ind [ i ] - 1 ] [ j ];
550 if ( elength [ i ] > maxlen [ side ] ) {
551 maxlen [ side ] = elength [ i ];
552 side_leIndex.at(side + 1) = ind [ i ];
553 }
554 }
555 }
556 }
557 }
558
559 return ( leIndex );
560}
561
562
563int
564Subdivision :: RS_Triangle :: giveEdgeIndex(int iNode, int jNode)
565{
566 /* returns zero, if triangle does not have iNode or jNode */
567 int in = 0, jn = 0;
568
569 int k;
570 for ( k = 1; k <= 3; k++ ) {
571 if ( nodes.at(k) == iNode ) {
572 in = k;
573 }
574
575 if ( nodes.at(k) == jNode ) {
576 jn = k;
577 }
578 }
579
580 if ( in == 0 || jn == 0 ) {
581 OOFEM_ERROR( "there is no edge connecting %d and %d on element %d",
582 iNode, jNode, this->giveNumber() );
583 }
584
585 if ( in < jn ) {
586 if ( jn == in + 1 ) {
587 return ( in );
588 }
589
590 return ( 3 );
591 } else {
592 if ( in == jn + 1 ) {
593 return ( jn );
594 }
595
596 return ( 3 );
597 }
598}
599
600
601int
602Subdivision :: RS_Tetra :: giveEdgeIndex(int iNode, int jNode)
603{
604 /* returns zero, if tetra does not have iNode or jNode */
605 int in = 0, jn = 0;
606
607 int k;
608 for ( k = 1; k <= 4; k++ ) {
609 if ( nodes.at(k) == iNode ) {
610 in = k;
611 }
612
613 if ( nodes.at(k) == jNode ) {
614 jn = k;
615 }
616 }
617
618 if ( in == 0 || jn == 0 ) {
619 OOFEM_ERROR( "there is no edge connecting %d and %d on element %d",
620 iNode, jNode, this->giveNumber() );
621 }
622
623 if ( in < jn ) {
624 if ( jn == 4 ) {
625 return ( in + 3 );
626 }
627
628 if ( jn == in + 1 ) {
629 return ( in );
630 }
631
632 return ( 3 );
633 } else {
634 if ( in == 4 ) {
635 return ( jn + 3 );
636 }
637
638 if ( in == jn + 1 ) {
639 return ( jn );
640 }
641
642 return ( 3 );
643 }
644}
645
646
647void
648Subdivision :: RS_Triangle :: bisect(std :: queue< int > &subdivqueue, std :: list< int > &sharedIrregularsQueue)
649{
650 /* this is symbolic bisection - no new elements are added, only irregular nodes are introduced */
651 int inode, jnode, iNode, jNode, iNum, eInd;
652 double density;
653 bool boundary = false;
654 FloatArray coords;
655 Subdivision :: RS_Element *elem;
656#ifdef __MPI_PARALLEL_MODE
657 Subdivision :: RS_SharedEdge *edge;
658#endif
659
660 if ( !irregular_nodes.at(leIndex) ) {
661 RS_IrregularNode *irregular;
662 // irregular on the longest edge does not exist
663 // introduce new irregular node on the longest edge
664 inode = leIndex;
665 jnode = ( inode < 3 ) ? inode + 1 : 1;
666
667 iNode = nodes.at(inode);
668 jNode = nodes.at(jnode);
669 // compute coordinates of new irregular
670 coords = * ( mesh->giveNode(iNode)->giveCoordinates() );
671 coords.add( * mesh->giveNode(jNode)->giveCoordinates() );
672 coords.times(0.5);
673 // compute required density of a new node
674 density = 0.5 * ( mesh->giveNode(iNode)->giveRequiredDensity() +
675 mesh->giveNode(jNode)->giveRequiredDensity() );
676 // create new irregular
677 iNum = mesh->giveNumberOfNodes() + 1;
678 irregular = new Subdivision :: RS_IrregularNode(iNum, mesh, 0, coords, density, boundary);
679 mesh->addNode(irregular);
680 // add irregular to receiver
681 this->irregular_nodes.at(leIndex) = iNum;
682
683#ifdef __OOFEG
684 #ifdef DRAW_IRREGULAR_NODES
685 irregular->drawGeometry();
686 #endif
687#endif
688
689#ifdef __MPI_PARALLEL_MODE
690#ifdef __VERBOSE_PARALLEL
691 OOFEM_LOG_INFO("[%d] RS_Triangle::bisecting %d nodes %d %d %d, leIndex %d, new irregular %d\n", mesh->giveSubdivision()->giveRank(), this->number, nodes.at(1), nodes.at(2), nodes.at(3), leIndex, iNum);
692#endif
693#endif
694
695#ifdef QUICK_HACK
696 if ( mesh->giveNode( nodes.at(1) )->isBoundary() && mesh->giveNode( nodes.at(2) )->isBoundary() && mesh->giveNode( nodes.at(3) )->isBoundary() ) {
697 OOFEM_ERROR( "quick hack not applicable due to element %d", this->giveNumber() );
698 }
699
700 if ( mesh->giveNode(iNode)->isBoundary() && mesh->giveNode(jNode)->isBoundary() ) {
701 boundary = true;
702 }
703
704#else
705 // check whether new node is boundary
706 if ( this->neghbours_base_elements.at(leIndex) ) {
707 Domain *dorig = mesh->giveSubdivision()->giveDomain();
708 // I rely on tha fact that nodes on intermaterial interface are marked as boundary
709 // however this might not be true
710 // therefore in smoothing the boundary flag is setuped again if not set boundary from here
711 if ( mesh->giveNode(iNode)->isBoundary() || mesh->giveNode(jNode)->isBoundary() ) {
712 if ( dorig->giveElement( this->giveTopParent() )->giveRegionNumber() != dorig->giveElement( mesh->giveElement( this->neghbours_base_elements.at(leIndex) )->giveTopParent() )->giveRegionNumber() ) {
713 boundary = true;
714 }
715 }
716 } else {
717 boundary = true;
718 }
719
720#endif
721
722 if ( boundary ) {
723 irregular->setBoundary(true);
724 }
725
726 if ( this->neghbours_base_elements.at(leIndex) ) {
727 // add irregular to neighbour
728 elem = mesh->giveElement( this->neghbours_base_elements.at(leIndex) );
729 eInd = elem->giveEdgeIndex(iNode, jNode);
730 elem->setIrregular(eInd, iNum);
731
732 if ( !elem->giveQueueFlag() ) {
733 // add neighbour to list of elements for subdivision
734 subdivqueue.push( this->neghbours_base_elements.at(leIndex) );
735 elem->setQueueFlag(true);
736 }
737 }
738
739#ifdef __MPI_PARALLEL_MODE
740 else {
741 // check if there are (potentionally) shared edges
742 if ( shared_edges.giveSize() ) {
743 // check if the edge is (really) shared
744 if ( shared_edges.at(leIndex) ) {
745 edge = mesh->giveEdge( shared_edges.at(leIndex) );
746
747 #ifdef DEBUG_CHECK
748 if ( !edge->givePartitions()->giveSize() ) {
749 OOFEM_ERROR( "unshared edge %d of element %d is marked as shared",
750 shared_edges.at(leIndex), this->giveNumber() );
751 }
752
753 #endif
754
755 // new node is on shared interpartition boundary
757 // partitions are inherited from shared edge
758 irregular->setPartitions( * ( edge->givePartitions() ) );
759 irregular->setEdgeNodes(iNode, jNode);
760 // put its number into queue of shared irregulars that is later used to inform remote partitions about this fact
761 sharedIrregularsQueue.push_back(iNum);
762 #ifdef __VERBOSE_PARALLEL
763 OOFEM_LOG_INFO("RS_Triangle::bisect: Shared irregular detected, number %d nodes %d %d [%d %d], elem %d\n", iNum, iNode, jNode, mesh->giveNode(iNode)->giveGlobalNumber(), mesh->giveNode(jNode)->giveGlobalNumber(), this->number);
764 #endif
765 }
766 }
767 }
768#endif
769 }
770
771 this->setQueueFlag(false);
772}
773
774
775void
776Subdivision :: RS_Tetra :: bisect(std :: queue< int > &subdivqueue, std :: list< int > &sharedIrregularsQueue)
777{
778 /* this is symbolic bisection - no new elements are added, only irregular nodes are introduced */
779 int i, j, inode, jnode, iNode, jNode, ngb, eIndex, eInd, reg, iNum, side, cnt = 0, elems;
780 // array ed_side contains face numbers NOT shared by the edge (indexing from 1)
781 int ed_side [ 6 ] [ 2 ] = { { 3, 4 }, { 4, 2 }, { 2, 3 }, { 1, 3 }, { 1, 4 }, { 1, 2 } }, ed [ 4 ] = {
782 0, 0, 0, 0
783 }, opp_ed [ 6 ] = {
784 6, 4, 5, 2, 3, 1
785 };
786 // array side_ed contains edge numbers bounding faces (indexing from 1)
787 int side_ed [ 4 ] [ 3 ] = { { 1, 2, 3 }, { 1, 5, 4 }, { 2, 6, 5 }, { 3, 4, 6 } };
788 double density;
789 bool shared, boundary, iboundary, jboundary, opposite = false;
790 Subdivision :: RS_Element *elem1, *elem2, *elem;
791 FloatArray coords;
792 Domain *dorig;
793 RS_IrregularNode *irregular;
794 const IntArray *iElems, *jElems;
795#ifdef __MPI_PARALLEL_MODE
796 Subdivision :: RS_SharedEdge *edge;
797#endif
798
799 dorig = mesh->giveSubdivision()->giveDomain();
800 reg = dorig->giveElement( this->giveTopParent() )->giveRegionNumber();
801
802 // first resolve whether there will be inserted irregular on the edge opposite to longest edge
803 // this will happen if the opposite edge is longest for a side not shared by the longest edge
804 // and simultaneously there is already an irregular on that side
805 if ( !irregular_nodes.at(opp_ed [ leIndex - 1 ]) ) {
806 for ( i = 0; i < 2; i++ ) {
807 // get side not incident to leIndex edge
808 side = ed_side [ leIndex - 1 ] [ i ];
809 // check whether the longest edge of that side is opposite edge
810 if ( side_leIndex.at(side) != opp_ed [ leIndex - 1 ] ) {
811 continue;
812 }
813
814 for ( j = 0; j < 3; j++ ) {
815 // check for irregulars on that side
816 if ( irregular_nodes.at(side_ed [ side - 1 ] [ j ]) ) {
817 opposite = true;
818 irregular_nodes.at(opp_ed [ leIndex - 1 ]) = -1; // fictitious irregular
819 break;
820 }
821 }
822
823 if ( opposite ) {
824 break;
825 }
826 }
827 }
828
829 // insert irregular on absolutely longest edge first;
830 // this controls the primary bisection;
831 // if there is an irregular (including a fictitious one) on side not shared by longest edge
832 // insert irregular on longest edge of that side;
833 ed [ cnt++ ] = leIndex;
834 for ( i = 0; i < 2; i++ ) {
835 // get side not incident to leIndex edge
836 side = ed_side [ leIndex - 1 ] [ i ];
837 for ( j = 0; j < 3; j++ ) {
838 // check for irregulars on that side
839 if ( irregular_nodes.at(side_ed [ side - 1 ] [ j ]) ) {
840 ed [ cnt++ ] = side_leIndex.at(side);
841 break;
842 }
843 }
844 }
845
846 // remove fictitious irregular
847 if ( opposite ) {
848 irregular_nodes.at(opp_ed [ leIndex - 1 ]) = 0;
849 }
850
851 // check for the case when longest edge of the sides not shared by the absolutely longest edge is the same
852 // (it is opposite to absolutely longest edge)
853 if ( cnt == 3 ) {
854 if ( ed [ 1 ] == ed [ 2 ] ) {
855 cnt = 2;
856#ifdef DEBUG_CHECK
857 if ( ed [ 1 ] != opp_ed [ leIndex - 1 ] ) {
858 OOFEM_ERROR( "unexpected situation on element %d", this->giveNumber() );
859 }
860
861#endif
862 }
863 }
864
865#ifdef QUICK_HACK
866 if ( mesh->giveNode( nodes.at(1) )->isBoundary() && mesh->giveNode( nodes.at(2) )->isBoundary() &&
867 mesh->giveNode( nodes.at(3) )->isBoundary() && mesh->giveNode( nodes.at(4) )->isBoundary() ) {
868 OOFEM_ERROR( "quick hack not applicable due to element %d", this->giveNumber() );
869 }
870
871#endif
872
873 // insert all relevant irregulars
874 for ( i = 0; i < cnt; i++ ) {
875 eIndex = ed [ i ];
876 if ( !irregular_nodes.at(eIndex) ) {
877 // irregular on this edge does not exist;
878 // introduce new irregular node on this edge on this element and on all local elements sharing that edge;
879 // if the edge is local, neigbours are processed;
880 // if the edge is shared, elements sharing simultaneously both end nodes are processed;
881 if ( eIndex <= 3 ) {
882 inode = eIndex;
883 jnode = ( eIndex < 3 ) ? inode + 1 : 1;
884 ngb = 1;
885 } else {
886 inode = eIndex - 3;
887 jnode = 4;
888 ngb = inode + 1;
889 }
890
891 iNode = nodes.at(inode);
892 jNode = nodes.at(jnode);
893 // compute coordinates of new irregular
894 coords = * ( mesh->giveNode(iNode)->giveCoordinates() );
895 coords.add( * mesh->giveNode(jNode)->giveCoordinates() );
896 coords.times(0.5);
897#ifdef HEADEDSTUD
898 double dist, rad, rate;
899 FloatArray *c;
900
901 c = mesh->giveNode(iNode)->giveCoordinates();
902 dist = c->at(1) * c->at(1) + c->at(3) * c->at(3);
903 if ( c->at(2) > 69.9999999 ) {
904 rad = 7.0;
905 } else if ( c->at(2) < 64.5000001 ) {
906 rad = 18.0;
907 } else {
908 rad = 18.0 - 11.0 / 5.5 * ( c->at(2) - 64.5 );
909 }
910
911 if ( fabs(dist - rad * rad) < 0.01 ) { // be very tolerant (geometry is not precise)
912 c = mesh->giveNode(jNode)->giveCoordinates();
913 dist = c->at(1) * c->at(1) + c->at(3) * c->at(3);
914 if ( c->at(2) > 69.9999999 ) {
915 rad = 7.0;
916 } else if ( c->at(2) < 64.5000001 ) {
917 rad = 18.0;
918 } else {
919 rad = 18.0 - 11.0 / 5.5 * ( c->at(2) - 64.5 );
920 }
921
922 if ( fabs(dist - rad * rad) < 0.01 ) { // be very tolerant (geometry is not precise)
923 dist = coords.at(1) * coords.at(1) + coords.at(3) * coords.at(3);
924 if ( coords.at(2) > 69.9999999 ) {
925 rad = 7.0;
926 } else if ( coords.at(2) < 64.5000001 ) {
927 rad = 18.0;
928 } else {
929 rad = 18.0 - 11.0 / 5.5 * ( coords.at(2) - 64.5 );
930 }
931
932 rate = rad / sqrt(dist);
933 coords.at(1) *= rate;
934 coords.at(3) *= rate;
935 }
936 }
937
938#endif
939 // compute required density of a new node
940 density = 0.5 * ( mesh->giveNode(iNode)->giveRequiredDensity() +
941 mesh->giveNode(jNode)->giveRequiredDensity() );
942 // create new irregular
943 iNum = mesh->giveNumberOfNodes() + 1;
944 irregular = new Subdivision :: RS_IrregularNode(iNum, mesh, 0, coords, density, false);
945 mesh->addNode(irregular);
946 // add irregular to receiver
947 this->irregular_nodes.at(eIndex) = iNum;
948
949#ifdef __OOFEG
950 #ifdef DRAW_IRREGULAR_NODES
951 irregular->drawGeometry();
952 #endif
953#endif
954
955#ifdef DEBUG_INFO
956 #ifdef __MPI_PARALLEL_MODE
957 // do not print global numbers of elements because they are not available (they are assigned at once after bisection);
958 // do not print global numbers of irregulars as these may not be available yet
959 OOFEM_LOG_INFO( "[%d] Irregular %d added on %d [%d] (edge %d, nodes %d %d [%d %d], nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
960 mesh->giveSubdivision()->giveRank(), iNum, this->number, this->giveGlobalNumber(), eIndex, iNode, jNode,
961 mesh->giveNode(iNode)->giveGlobalNumber(), mesh->giveNode(jNode)->giveGlobalNumber(),
962 nodes.at(1), nodes.at(2), nodes.at(3), nodes.at(4),
963 mesh->giveNode( nodes.at(1) )->giveGlobalNumber(), mesh->giveNode( nodes.at(2) )->giveGlobalNumber(),
964 mesh->giveNode( nodes.at(3) )->giveGlobalNumber(), mesh->giveNode( nodes.at(4) )->giveGlobalNumber(),
965 neghbours_base_elements.at(1), neghbours_base_elements.at(2),
966 neghbours_base_elements.at(3), neghbours_base_elements.at(4),
967 irregular_nodes.at(1), irregular_nodes.at(2), irregular_nodes.at(3),
968 irregular_nodes.at(4), irregular_nodes.at(5), irregular_nodes.at(6) );
969 #else
970 OOFEM_LOG_INFO( "Irregular %d added on %d (edge %d, nodes %d %d, nds %d %d %d %d, ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
971 iNum, this->number, eIndex, iNode, jNode,
972 nodes.at(1), nodes.at(2), nodes.at(3), nodes.at(4),
973 neghbours_base_elements.at(1), neghbours_base_elements.at(2),
974 neghbours_base_elements.at(3), neghbours_base_elements.at(4),
975 irregular_nodes.at(1), irregular_nodes.at(2), irregular_nodes.at(3),
976 irregular_nodes.at(4), irregular_nodes.at(5), irregular_nodes.at(6) );
977 #endif
978#endif
979
980 shared = boundary = false;
981
982#ifdef __MPI_PARALLEL_MODE
983 // check if there are (potentionally) shared edges
984 if ( shared_edges.giveSize() ) {
985 // check if the edge is (really) shared
986 if ( shared_edges.at(eIndex) ) {
987 edge = mesh->giveEdge( shared_edges.at(eIndex) );
988
989 #ifdef DEBUG_CHECK
990 if ( !edge->givePartitions()->giveSize() ) {
991 OOFEM_ERROR( "unshared edge %d of element %d is marked as shared",
992 shared_edges.at(eIndex), this->giveNumber() );
993 }
994
995 #endif
996
997 shared = boundary = true;
998 // new node is on shared interpartition boundary
1000 irregular->setPartitions( * ( edge->givePartitions() ) );
1001 irregular->setEdgeNodes(iNode, jNode);
1002 // put its number into queue of shared irregulars that is later used to inform remote partitions about this fact
1003 sharedIrregularsQueue.push_back(iNum);
1004 #ifdef __VERBOSE_PARALLEL
1005 OOFEM_LOG_INFO("RS_Tetra::bisect: Shared irregular detected, number %d nodes %d %d [%d %d], elem %d\n", iNum, iNode, jNode, mesh->giveNode(iNode)->giveGlobalNumber(), mesh->giveNode(jNode)->giveGlobalNumber(), this->number);
1006 #endif
1007
1008 iElems = mesh->giveNode(iNode)->giveConnectedElements();
1009 jElems = mesh->giveNode(jNode)->giveConnectedElements();
1010
1011 IntArray common;
1012 if ( iElems->giveSize() <= jElems->giveSize() ) {
1013 common.preallocate( iElems->giveSize() );
1014 } else {
1015 common.preallocate( jElems->giveSize() );
1016 }
1017
1018 // I do rely on the fact that the arrays are ordered !!!
1019 // I am using zero chunk because common is large enough
1020 elems = iElems->findCommonValuesSorted(* jElems, common, 0);
1021 #ifdef DEBUG_CHECK
1022 if ( !elems ) {
1023 OOFEM_ERROR( "shared edge %d is not shared by common elements",
1024 shared_edges.at(eIndex) );
1025 }
1026
1027 #endif
1028 // after subdivision there will be twice as much of connected local elements
1029 irregular->preallocateConnectedElements(elems * 2);
1030 // put the new node on appropriate edge of all local elements (except "this") sharing both nodes
1031 for ( j = 1; j <= elems; j++ ) {
1032 elem = mesh->giveElement( common.at(j) );
1033 if ( elem == this ) {
1034 continue;
1035 }
1036
1037 #ifdef DEBUG_CHECK
1038 if ( !elem->giveSharedEdges()->giveSize() ) {
1039 OOFEM_ERROR( "element %d incident to shared edge %d does not have shared edges",
1040 common.at(j), shared_edges.at(eIndex) );
1041 }
1042
1043 #endif
1044
1045 eInd = elem->giveEdgeIndex(iNode, jNode);
1046 elem->setIrregular(eInd, iNum);
1047
1048 if ( !elem->giveQueueFlag() ) {
1049 // add elem to list of elements for subdivision
1050 subdivqueue.push( elem->giveNumber() );
1051 elem->setQueueFlag(true);
1052 }
1053
1054 #ifdef DEBUG_INFO
1055 #ifdef __MPI_PARALLEL_MODE
1056 // do not print global numbers of elements because they are not available (they are assigned at once after bisection);
1057 // do not print global numbers of irregulars as these may not be available yet
1058 OOFEM_LOG_INFO( "[%d] Irregular %d added on %d [%d] (edge %d, nodes %d %d [%d %d], nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
1059 mesh->giveSubdivision()->giveRank(), iNum,
1060 elem->giveNumber(), this->giveGlobalNumber(), eInd, iNode, jNode,
1061 mesh->giveNode(iNode)->giveGlobalNumber(), mesh->giveNode(jNode)->giveGlobalNumber(),
1062 elem->giveNode(1), elem->giveNode(2), elem->giveNode(3), elem->giveNode(4),
1063 mesh->giveNode( elem->giveNode(1) )->giveGlobalNumber(),
1064 mesh->giveNode( elem->giveNode(2) )->giveGlobalNumber(),
1065 mesh->giveNode( elem->giveNode(3) )->giveGlobalNumber(),
1066 mesh->giveNode( elem->giveNode(4) )->giveGlobalNumber(),
1067 elem->giveNeighbor(1), elem->giveNeighbor(2), elem->giveNeighbor(3), elem->giveNeighbor(4),
1068 elem->giveIrregular(1), elem->giveIrregular(2), elem->giveIrregular(3),
1069 elem->giveIrregular(4), elem->giveIrregular(5), elem->giveIrregular(6) );
1070 #else
1071 OOFEM_LOG_INFO( "Irregular %d added on %d (edge %d, nodes %d %d, nds %d %d %d %d, ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
1072 iNum, elem->giveNumber(), eInd, iNode, jNode,
1073 elem->giveNode(1), elem->giveNode(2), elem->giveNode(3), elem->giveNode(4),
1074 elem->giveNeighbor(1), elem->giveNeighbor(2), elem->giveNeighbor(3), elem->giveNeighbor(4),
1075 elem->giveIrregular(1), elem->giveIrregular(2), elem->giveIrregular(3),
1076 elem->giveIrregular(4), elem->giveIrregular(5), elem->giveIrregular(6) );
1077 #endif
1078 #endif
1079 }
1080 }
1081 }
1082
1083#endif
1084
1085 if ( !shared ) {
1086 iboundary = mesh->giveNode(iNode)->isBoundary();
1087 jboundary = mesh->giveNode(jNode)->isBoundary();
1088#ifdef QUICK_HACK
1089 if ( iboundary == true && jboundary == true ) {
1090 boundary = true;
1091 }
1092
1093#endif
1094
1095 // traverse neighbours
1096 elem1 = this;
1097 elem2 = NULL;
1098 while ( elem1->giveNeighbor(ngb) ) {
1099 elem2 = mesh->giveElement( elem1->giveNeighbor(ngb) );
1100 if ( elem2 == this ) {
1101 break;
1102 }
1103
1104 eInd = elem2->giveEdgeIndex(iNode, jNode);
1105 elem2->setIrregular(eInd, iNum);
1106
1107 if ( !elem2->giveQueueFlag() ) {
1108 // add neighbour to list of elements for subdivision
1109 subdivqueue.push( elem2->giveNumber() );
1110 elem2->setQueueFlag(true);
1111 }
1112
1113#ifndef QUICK_HACK
1114 if ( !boundary ) {
1115 // I rely on the fact that nodes on intermaterial interface are marked as boundary
1116 // however this might not be true
1117 // therefore in smoothing the boundary flag is setuped again if not set boundary from here
1118 if ( iboundary == true || jboundary == true ) {
1119 if ( dorig->giveElement( elem2->giveTopParent() )->giveRegionNumber() != reg ) {
1120 boundary = true;
1121 }
1122 }
1123 }
1124
1125#endif
1126
1127#ifdef DEBUG_INFO
1128 #ifdef __MPI_PARALLEL_MODE
1129 // do not print global numbers of elements because they are not available (they are assigned at once after bisection);
1130 // do not print global numbers of irregulars as these may not be available yet
1131 OOFEM_LOG_INFO( "[%d] Irregular %d added on %d [%d] (edge %d, nodes %d %d [%d %d], nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
1132 mesh->giveSubdivision()->giveRank(), iNum,
1133 elem2->giveNumber(), this->giveGlobalNumber(), eInd, iNode, jNode,
1134 mesh->giveNode(iNode)->giveGlobalNumber(), mesh->giveNode(jNode)->giveGlobalNumber(),
1135 elem2->giveNode(1), elem2->giveNode(2), elem2->giveNode(3), elem2->giveNode(4),
1136 mesh->giveNode( elem2->giveNode(1) )->giveGlobalNumber(),
1137 mesh->giveNode( elem2->giveNode(2) )->giveGlobalNumber(),
1138 mesh->giveNode( elem2->giveNode(3) )->giveGlobalNumber(),
1139 mesh->giveNode( elem2->giveNode(4) )->giveGlobalNumber(),
1140 elem2->giveNeighbor(1), elem2->giveNeighbor(2), elem2->giveNeighbor(3), elem2->giveNeighbor(4),
1141 elem2->giveIrregular(1), elem2->giveIrregular(2), elem2->giveIrregular(3),
1142 elem2->giveIrregular(4), elem2->giveIrregular(5), elem2->giveIrregular(6) );
1143 #else
1144 OOFEM_LOG_INFO( "Irregular %d added on %d (edge %d, nodes %d %d, nds %d %d %d %d, ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
1145 iNum, elem2->giveNumber(), eInd, iNode, jNode,
1146 elem2->giveNode(1), elem2->giveNode(2), elem2->giveNode(3), elem2->giveNode(4),
1147 elem2->giveNeighbor(1), elem2->giveNeighbor(2), elem2->giveNeighbor(3), elem2->giveNeighbor(4),
1148 elem2->giveIrregular(1), elem2->giveIrregular(2), elem2->giveIrregular(3),
1149 elem2->giveIrregular(4), elem2->giveIrregular(5), elem2->giveIrregular(6) );
1150 #endif
1151#endif
1152
1153 if ( eInd <= 3 ) {
1154 if ( elem2->giveNeighbor(1) == elem1->giveNumber() ) {
1155 ngb = eInd + 1;
1156 } else {
1157 ngb = 1;
1158 }
1159 } else {
1160 if ( elem2->giveNeighbor(eInd - 2) == elem1->giveNumber() ) {
1161 ngb = ( eInd > 4 ) ? eInd - 3 : 4;
1162 } else {
1163 ngb = eInd - 2;
1164 }
1165 }
1166
1167 elem1 = elem2;
1168 }
1169
1170 if ( elem2 != this ) {
1171#ifdef DEBUG_CHECK
1172 #ifdef THREEPBT_3D
1173 if ( coords.at(1) > 0.000001 && coords.at(1) < 1999.99999 &&
1174 coords.at(2) > 0.000001 && coords.at(2) < 249.99999 &&
1175 coords.at(3) > 0.000001 && coords.at(3) < 499.99999 ) {
1176 if ( 987.5 - coords.at(1) > 0.000001 || coords.at(1) - 1012.5 > 0.000001 || 300.0 - coords.at(3) > 0.000001 ) {
1177 OOFEM_ERROR("Irregular %d [%d %d] not on boundary", iNum, iNode, jNode);
1178 }
1179 }
1180
1181 #endif
1182#endif
1183#ifndef QUICK_HACK
1184 boundary = true;
1185#endif
1186 // edge is on outer boundary
1187
1188 // I do rely on the fact that if the list of connected elements is not availale
1189 // then the node is on top level
1190 iElems = mesh->giveNode(iNode)->giveConnectedElements();
1191 if ( !iElems->giveSize() ) {
1192 mesh->giveNode(iNode)->buildTopLevelNodeConnectivity( mesh->giveSubdivision()->giveDomain()->giveConnectivityTable() );
1193 }
1194
1195 jElems = mesh->giveNode(jNode)->giveConnectedElements();
1196 if ( !jElems->giveSize() ) {
1197 mesh->giveNode(jNode)->buildTopLevelNodeConnectivity( mesh->giveSubdivision()->giveDomain()->giveConnectivityTable() );
1198 }
1199
1200 IntArray common;
1201 if ( iElems->giveSize() <= jElems->giveSize() ) {
1202 common.preallocate( iElems->giveSize() );
1203 } else {
1204 common.preallocate( jElems->giveSize() );
1205 }
1206
1207 // I do rely on the fact that the arrays are ordered !!!
1208 // I am using zero chunk because common is large enough
1209 elems = iElems->findCommonValuesSorted(* jElems, common, 0);
1210#ifdef DEBUG_CHECK
1211 if ( !elems ) {
1212 OOFEM_ERROR("local outer edge %d %d is not shared by common elements",
1213 iNode, jNode);
1214 }
1215
1216#endif
1217 // after subdivision there will be twice as much of connected local elements
1218 irregular->preallocateConnectedElements(elems * 2);
1219 irregular->setNumber(-iNum); // mark local unshared irregular for connectivity setup
1220 // put the new node on appropriate edge of all local elements sharing both nodes
1221 // (if not yet done during neighbour traversal)
1222 for ( j = 1; j <= elems; j++ ) {
1223 elem = mesh->giveElement( common.at(j) );
1224 if ( elem == this ) {
1225 continue;
1226 }
1227
1228 eInd = elem->giveEdgeIndex(iNode, jNode);
1229 if ( !elem->giveIrregular(eInd) ) {
1230 elem->setIrregular(eInd, iNum);
1231
1232#ifdef DEBUG_INFO
1233 #ifdef __MPI_PARALLEL_MODE
1234 // do not print global numbers of elements because they are not available (they are assigned at once after bisection);
1235 // do not print global numbers of irregulars as these may not be available yet
1236 OOFEM_LOG_INFO( "[%d] Irregular %d added on %d [%d] (edge %d, nodes %d %d [%d %d], nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
1237 mesh->giveSubdivision()->giveRank(), iNum,
1238 elem->giveNumber(), this->giveGlobalNumber(), eInd, iNode, jNode,
1239 mesh->giveNode(iNode)->giveGlobalNumber(), mesh->giveNode(jNode)->giveGlobalNumber(),
1240 elem->giveNode(1), elem->giveNode(2), elem->giveNode(3), elem->giveNode(4),
1241 mesh->giveNode( elem->giveNode(1) )->giveGlobalNumber(),
1242 mesh->giveNode( elem->giveNode(2) )->giveGlobalNumber(),
1243 mesh->giveNode( elem->giveNode(3) )->giveGlobalNumber(),
1244 mesh->giveNode( elem->giveNode(4) )->giveGlobalNumber(),
1245 elem->giveNeighbor(1), elem->giveNeighbor(2), elem->giveNeighbor(3), elem->giveNeighbor(4),
1246 elem->giveIrregular(1), elem->giveIrregular(2), elem->giveIrregular(3),
1247 elem->giveIrregular(4), elem->giveIrregular(5), elem->giveIrregular(6) );
1248 #else
1249 OOFEM_LOG_INFO( "Irregular %d added on %d (edge %d, nodes %d %d, nds %d %d %d %d, ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
1250 iNum, elem->giveNumber(), eInd, iNode, jNode,
1251 elem->giveNode(1), elem->giveNode(2), elem->giveNode(3), elem->giveNode(4),
1252 elem->giveNeighbor(1), elem->giveNeighbor(2), elem->giveNeighbor(3), elem->giveNeighbor(4),
1253 elem->giveIrregular(1), elem->giveIrregular(2), elem->giveIrregular(3),
1254 elem->giveIrregular(4), elem->giveIrregular(5), elem->giveIrregular(6) );
1255 #endif
1256#endif
1257
1258 if ( !elem->giveQueueFlag() ) {
1259 // add elem to list of elements for subdivision
1260 subdivqueue.push( elem->giveNumber() );
1261 elem->setQueueFlag(true);
1262 }
1263 }
1264 }
1265 }
1266 }
1267
1268 if ( boundary ) {
1269 // OOFEM_LOG_INFO("Irregular %d set boundary\n", abs(irregular->giveNumber()));
1270 irregular->setBoundary(true);
1271 }
1272 }
1273 }
1274
1275 this->setQueueFlag(false);
1276}
1277
1278
1279void
1280Subdivision :: RS_Triangle :: generate(std :: list< int > &sharedEdgesQueue)
1281{
1282#ifdef DEBUG_CHECK
1283 if ( this->queue_flag ) {
1284 OOFEM_ERROR("unexpected queue flag of %d ", this->number);
1285 }
1286
1287#endif
1288
1289 /* generates the children elements of already bisected element and adds them into mesh;
1290 * also children array of receiver is updated to contain children numbers */
1291 if ( irregular_nodes.containsOnlyZeroes() ) {
1292 // no subdivision of receiver required
1293 children.clear();
1294 } else {
1295 int i, ind, nIrregulars = 0;
1296 int childNum, iedge, jedge, kedge, inode, jnode, knode;
1297 IntArray _nodes(3);
1298 Subdivision :: RS_Triangle *child;
1299 Subdivision :: RS_Element *ngb;
1300#ifdef __MPI_PARALLEL_MODE
1301 bool ishared = false, jshared = false, kshared = false;
1302#endif
1303
1304 for ( i = 1; i <= irregular_nodes.giveSize(); i++ ) {
1305 if ( irregular_nodes.at(i) ) {
1306 nIrregulars++;
1307 }
1308 }
1309
1310 this->children.resize(nIrregulars + 1);
1311
1312 // leIndex determines primary edge to be subdivided
1313 /*
1314 * inode
1315 * o
1316 *
1317 *
1318 * kedge x x jedge
1319 *
1320 *
1321 * o x o
1322 * jnode iedge knode
1323 * =leIndex
1324 */
1325 iedge = leIndex;
1326 jedge = ( iedge < 3 ) ? iedge + 1 : 1;
1327 kedge = ( jedge < 3 ) ? jedge + 1 : 1;
1328
1329 inode = ( iedge > 1 ) ? iedge - 1 : 3;
1330 jnode = ( inode < 3 ) ? inode + 1 : 1;
1331 knode = ( jnode < 3 ) ? jnode + 1 : 1;
1332
1333#ifdef __MPI_PARALLEL_MODE
1334 if ( shared_edges.giveSize() ) {
1335 if ( shared_edges.at(iedge) ) {
1336 ishared = true;
1337 }
1338
1339 if ( shared_edges.at(jedge) ) {
1340 jshared = true;
1341 }
1342
1343 if ( shared_edges.at(kedge) ) {
1344 kshared = true;
1345 }
1346 }
1347
1348#endif
1349
1350 if ( irregular_nodes.at(iedge) && irregular_nodes.at(jedge) && irregular_nodes.at(kedge) ) {
1351 _nodes.at(1) = nodes.at(inode);
1352 _nodes.at(2) = irregular_nodes.at(kedge);
1353 _nodes.at(3) = irregular_nodes.at(iedge);
1354 childNum = mesh->giveNumberOfElements() + 1;
1355 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1356 mesh->addElement(child);
1357 children.at(1) = childNum;
1358 // set neigbour info
1359 child->setNeighbor( 1, -this->giveNeighbor(kedge) );
1360 child->setNeighbor(2, childNum + 2);
1361 child->setNeighbor(3, childNum + 1);
1362#ifdef __MPI_PARALLEL_MODE
1363 // set shared info
1364 if ( kshared ) {
1365 child->makeSharedEdges();
1366 child->setSharedEdge( 1, shared_edges.at(kedge) );
1367 }
1368
1369#endif
1370
1371 _nodes.at(1) = nodes.at(inode);
1372 _nodes.at(2) = irregular_nodes.at(iedge);
1373 _nodes.at(3) = irregular_nodes.at(jedge);
1374 childNum = mesh->giveNumberOfElements() + 1;
1375 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1376 mesh->addElement(child);
1377 children.at(2) = childNum;
1378 // set neigbour info
1379 child->setNeighbor(1, childNum - 1);
1380 child->setNeighbor(2, childNum + 2);
1381 child->setNeighbor( 3, -this->giveNeighbor(jedge) );
1382#ifdef __MPI_PARALLEL_MODE
1383 // set shared info
1384 if ( jshared ) {
1385 child->makeSharedEdges();
1386 child->setSharedEdge( 3, shared_edges.at(jedge) );
1387 }
1388
1389#endif
1390
1391 _nodes.at(1) = nodes.at(jnode);
1392 _nodes.at(2) = irregular_nodes.at(iedge);
1393 _nodes.at(3) = irregular_nodes.at(kedge);
1394 childNum = mesh->giveNumberOfElements() + 1;
1395 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1396 mesh->addElement(child);
1397 children.at(3) = childNum;
1398 // set neigbour info
1399 child->setNeighbor( 1, -this->giveNeighbor(iedge) );
1400 child->setNeighbor(2, childNum - 2);
1401 child->setNeighbor( 3, -this->giveNeighbor(kedge) );
1402#ifdef __MPI_PARALLEL_MODE
1403 // set shared info
1404 if ( ishared || kshared ) {
1405 child->makeSharedEdges();
1406 if ( ishared ) {
1407 child->setSharedEdge( 1, shared_edges.at(iedge) );
1408 }
1409
1410 if ( kshared ) {
1411 child->setSharedEdge( 3, shared_edges.at(kedge) );
1412 }
1413 }
1414
1415#endif
1416
1417 _nodes.at(1) = nodes.at(knode);
1418 _nodes.at(2) = irregular_nodes.at(jedge);
1419 _nodes.at(3) = irregular_nodes.at(iedge);
1420 childNum = mesh->giveNumberOfElements() + 1;
1421 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1422 mesh->addElement(child);
1423 children.at(4) = childNum;
1424 // set neigbour info
1425 child->setNeighbor( 1, -this->giveNeighbor(jedge) );
1426 child->setNeighbor(2, childNum - 2);
1427 child->setNeighbor( 3, -this->giveNeighbor(iedge) );
1428
1429#ifdef __MPI_PARALLEL_MODE
1430 // set shared info
1431 if ( ishared || jshared ) {
1432 child->makeSharedEdges();
1433 if ( ishared ) {
1434 child->setSharedEdge( 3, shared_edges.at(iedge) );
1435 }
1436
1437 if ( jshared ) {
1438 child->setSharedEdge( 1, shared_edges.at(jedge) );
1439 }
1440 }
1441
1442#endif
1443
1444#ifdef __MPI_PARALLEL_MODE
1445 // set connected elements
1446 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() == DofManager_shared ) {
1447 mesh->giveNode( nodes.at(inode) )->eraseConnectedElement( this->giveNumber() );
1448 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 2);
1449 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 3);
1450 }
1451
1452 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() == DofManager_shared ) {
1453 mesh->giveNode( nodes.at(jnode) )->eraseConnectedElement( this->giveNumber() );
1454 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum - 1);
1455 }
1456
1457 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() == DofManager_shared ) {
1458 mesh->giveNode( nodes.at(knode) )->eraseConnectedElement( this->giveNumber() );
1459 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum);
1460 }
1461
1462 if ( ishared ) {
1463 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum);
1464 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 1);
1465 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 2);
1466 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 3);
1467 }
1468
1469 if ( jshared ) {
1470 mesh->giveNode( irregular_nodes.at(jedge) )->insertConnectedElement(childNum);
1471 mesh->giveNode( irregular_nodes.at(jedge) )->insertConnectedElement(childNum - 2);
1472 }
1473
1474 if ( kshared ) {
1475 mesh->giveNode( irregular_nodes.at(kedge) )->insertConnectedElement(childNum - 1);
1476 mesh->giveNode( irregular_nodes.at(kedge) )->insertConnectedElement(childNum - 3);
1477 }
1478
1479#endif
1480 } else if ( irregular_nodes.at(iedge) && irregular_nodes.at(jedge) ) {
1481 _nodes.at(1) = nodes.at(inode);
1482 _nodes.at(2) = nodes.at(jnode);
1483 _nodes.at(3) = irregular_nodes.at(iedge);
1484 childNum = mesh->giveNumberOfElements() + 1;
1485 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1486 mesh->addElement(child);
1487 children.at(1) = childNum;
1488 // set neigbour info
1489 child->setNeighbor( 1, -this->giveNeighbor(kedge) );
1490 child->setNeighbor( 2, -this->giveNeighbor(iedge) );
1491 child->setNeighbor(3, childNum + 1);
1492#ifdef __MPI_PARALLEL_MODE
1493 // set shared info
1494 if ( ishared || kshared ) {
1495 child->makeSharedEdges();
1496 if ( ishared ) {
1497 child->setSharedEdge( 2, shared_edges.at(iedge) );
1498 }
1499
1500 if ( kshared ) {
1501 child->setSharedEdge( 1, shared_edges.at(kedge) );
1502 }
1503 }
1504
1505#endif
1506
1507 _nodes.at(1) = nodes.at(inode);
1508 _nodes.at(2) = irregular_nodes.at(iedge);
1509 _nodes.at(3) = irregular_nodes.at(jedge);
1510 childNum = mesh->giveNumberOfElements() + 1;
1511 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1512 mesh->addElement(child);
1513 children.at(2) = childNum;
1514 // set neigbour info
1515 child->setNeighbor(1, childNum - 1);
1516 child->setNeighbor(2, childNum + 1);
1517 child->setNeighbor( 3, -this->giveNeighbor(jedge) );
1518#ifdef __MPI_PARALLEL_MODE
1519 // set shared info
1520 if ( jshared ) {
1521 child->makeSharedEdges();
1522 child->setSharedEdge( 3, shared_edges.at(jedge) );
1523 }
1524
1525#endif
1526
1527 _nodes.at(1) = nodes.at(knode);
1528 _nodes.at(2) = irregular_nodes.at(jedge);
1529 _nodes.at(3) = irregular_nodes.at(iedge);
1530 childNum = mesh->giveNumberOfElements() + 1;
1531 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1532 mesh->addElement(child);
1533 children.at(3) = childNum;
1534 // set neigbour info
1535 child->setNeighbor( 1, -this->giveNeighbor(jedge) );
1536 child->setNeighbor(2, childNum - 1);
1537 child->setNeighbor( 3, -this->giveNeighbor(iedge) );
1538#ifdef __MPI_PARALLEL_MODE
1539 // set shared info
1540 if ( ishared || jshared ) {
1541 child->makeSharedEdges();
1542 if ( ishared ) {
1543 child->setSharedEdge( 3, shared_edges.at(iedge) );
1544 }
1545
1546 if ( jshared ) {
1547 child->setSharedEdge( 1, shared_edges.at(jedge) );
1548 }
1549 }
1550
1551#endif
1552
1553#ifdef __MPI_PARALLEL_MODE
1554 // set connected elements
1555 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() == DofManager_shared ) {
1556 mesh->giveNode( nodes.at(inode) )->eraseConnectedElement( this->giveNumber() );
1557 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 1);
1558 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 2);
1559 }
1560
1561 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() == DofManager_shared ) {
1562 mesh->giveNode( nodes.at(jnode) )->eraseConnectedElement( this->giveNumber() );
1563 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum - 2);
1564 }
1565
1566 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() == DofManager_shared ) {
1567 mesh->giveNode( nodes.at(knode) )->eraseConnectedElement( this->giveNumber() );
1568 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum);
1569 }
1570
1571 if ( ishared ) {
1572 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum);
1573 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 1);
1574 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 2);
1575 }
1576
1577 if ( jshared ) {
1578 mesh->giveNode( irregular_nodes.at(jedge) )->insertConnectedElement(childNum);
1579 mesh->giveNode( irregular_nodes.at(jedge) )->insertConnectedElement(childNum - 1);
1580 }
1581
1582#endif
1583 } else if ( irregular_nodes.at(iedge) && irregular_nodes.at(kedge) ) {
1584 _nodes.at(1) = nodes.at(inode);
1585 _nodes.at(2) = irregular_nodes.at(kedge);
1586 _nodes.at(3) = irregular_nodes.at(iedge);
1587 childNum = mesh->giveNumberOfElements() + 1;
1588 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1589 mesh->addElement(child);
1590 children.at(1) = childNum;
1591 // set neigbour info
1592 child->setNeighbor( 1, -this->giveNeighbor(kedge) );
1593 child->setNeighbor(2, childNum + 1);
1594 child->setNeighbor(3, childNum + 2);
1595#ifdef __MPI_PARALLEL_MODE
1596 // set shared info
1597 if ( kshared ) {
1598 child->makeSharedEdges();
1599 child->setSharedEdge( 1, shared_edges.at(kedge) );
1600 }
1601
1602#endif
1603
1604 _nodes.at(1) = nodes.at(jnode);
1605 _nodes.at(2) = irregular_nodes.at(iedge);
1606 _nodes.at(3) = irregular_nodes.at(kedge);
1607 childNum = mesh->giveNumberOfElements() + 1;
1608 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1609 mesh->addElement(child);
1610 children.at(2) = childNum;
1611 // set neigbour info
1612 child->setNeighbor( 1, -this->giveNeighbor(iedge) );
1613 child->setNeighbor(2, childNum - 1);
1614 child->setNeighbor( 3, -this->giveNeighbor(kedge) );
1615#ifdef __MPI_PARALLEL_MODE
1616 // set shared info
1617 if ( ishared || kshared ) {
1618 child->makeSharedEdges();
1619 if ( ishared ) {
1620 child->setSharedEdge( 1, shared_edges.at(iedge) );
1621 }
1622
1623 if ( kshared ) {
1624 child->setSharedEdge( 3, shared_edges.at(kedge) );
1625 }
1626 }
1627
1628#endif
1629
1630 _nodes.at(1) = nodes.at(inode);
1631 _nodes.at(2) = irregular_nodes.at(iedge);
1632 _nodes.at(3) = nodes.at(knode);
1633 childNum = mesh->giveNumberOfElements() + 1;
1634 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1635 mesh->addElement(child);
1636 children.at(3) = childNum;
1637 // set neigbour info
1638 child->setNeighbor(1, childNum - 2);
1639 child->setNeighbor( 2, -this->giveNeighbor(iedge) );
1640 child->setNeighbor( 3, -this->giveNeighbor(jedge) );
1641#ifdef __MPI_PARALLEL_MODE
1642 // set shared info
1643 if ( ishared || jshared ) {
1644 child->makeSharedEdges();
1645 if ( ishared ) {
1646 child->setSharedEdge( 2, shared_edges.at(iedge) );
1647 }
1648
1649 if ( jshared ) {
1650 child->setSharedEdge( 3, shared_edges.at(jedge) );
1651 }
1652 }
1653
1654#endif
1655
1656#ifdef __MPI_PARALLEL_MODE
1657 // set connected elements
1658 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() == DofManager_shared ) {
1659 mesh->giveNode( nodes.at(inode) )->eraseConnectedElement( this->giveNumber() );
1660 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum);
1661 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 2);
1662 }
1663
1664 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() == DofManager_shared ) {
1665 mesh->giveNode( nodes.at(jnode) )->eraseConnectedElement( this->giveNumber() );
1666 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum - 1);
1667 }
1668
1669 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() == DofManager_shared ) {
1670 mesh->giveNode( nodes.at(knode) )->eraseConnectedElement( this->giveNumber() );
1671 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum);
1672 }
1673
1674 if ( ishared ) {
1675 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum);
1676 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 1);
1677 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 2);
1678 }
1679
1680 if ( kshared ) {
1681 mesh->giveNode( irregular_nodes.at(kedge) )->insertConnectedElement(childNum - 1);
1682 mesh->giveNode( irregular_nodes.at(kedge) )->insertConnectedElement(childNum - 2);
1683 }
1684
1685#endif
1686 } else if ( irregular_nodes.at(iedge) ) {
1687 _nodes.at(1) = nodes.at(inode);
1688 _nodes.at(2) = nodes.at(jnode);
1689 _nodes.at(3) = irregular_nodes.at(iedge);
1690 childNum = mesh->giveNumberOfElements() + 1;
1691 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1692 mesh->addElement(child);
1693 children.at(1) = childNum;
1694 // set neigbour info
1695 child->setNeighbor( 1, -this->giveNeighbor(kedge) );
1696 child->setNeighbor( 2, -this->giveNeighbor(iedge) );
1697 child->setNeighbor(3, childNum + 1);
1698#ifdef __MPI_PARALLEL_MODE
1699 // set shared info
1700 if ( ishared || kshared ) {
1701 child->makeSharedEdges();
1702 if ( ishared ) {
1703 child->setSharedEdge( 2, shared_edges.at(iedge) );
1704 }
1705
1706 if ( kshared ) {
1707 child->setSharedEdge( 1, shared_edges.at(kedge) );
1708 }
1709 }
1710
1711#endif
1712
1713 _nodes.at(1) = nodes.at(inode);
1714 _nodes.at(2) = irregular_nodes.at(iedge);
1715 _nodes.at(3) = nodes.at(knode);
1716 childNum = mesh->giveNumberOfElements() + 1;
1717 child = new Subdivision :: RS_Triangle(childNum, mesh, this->number, _nodes); // number, parent, coords
1718 mesh->addElement(child);
1719 children.at(2) = childNum;
1720 // set neigbour info
1721 child->setNeighbor(1, childNum - 1);
1722 child->setNeighbor( 2, -this->giveNeighbor(iedge) );
1723 child->setNeighbor( 3, -this->giveNeighbor(jedge) );
1724#ifdef __MPI_PARALLEL_MODE
1725 // set shared info
1726 if ( ishared || jshared ) {
1727 child->makeSharedEdges();
1728 if ( ishared ) {
1729 child->setSharedEdge( 2, shared_edges.at(iedge) );
1730 }
1731
1732 if ( jshared ) {
1733 child->setSharedEdge( 3, shared_edges.at(jedge) );
1734 }
1735 }
1736
1737#endif
1738
1739#ifdef __MPI_PARALLEL_MODE
1740 // set connected elements
1741 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() == DofManager_shared ) {
1742 mesh->giveNode( nodes.at(inode) )->eraseConnectedElement( this->giveNumber() );
1743 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum);
1744 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 1);
1745 }
1746
1747 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() == DofManager_shared ) {
1748 mesh->giveNode( nodes.at(jnode) )->eraseConnectedElement( this->giveNumber() );
1749 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum - 1);
1750 }
1751
1752 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() == DofManager_shared ) {
1753 mesh->giveNode( nodes.at(knode) )->eraseConnectedElement( this->giveNumber() );
1754 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum);
1755 }
1756
1757 if ( ishared ) {
1758 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum);
1759 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 1);
1760 }
1761
1762#endif
1763 } else {
1764 OOFEM_ERROR("element %d internal data inconsistency", this->number);
1765 }
1766
1767 // if there is neighbor of "this" not designated for bisection
1768 // its neihgbor corresponding to "this" must be made negative to enforce update_neighbors
1769 for ( i = 1; i <= 3; i++ ) {
1770 if ( this->neghbours_base_elements.at(i) ) {
1771#ifdef DEBUG_CHECK
1772 if ( this->neghbours_base_elements.at(i) < 0 ) {
1773 OOFEM_ERROR("negative neighbor of %d not expected", this->number);
1774 }
1775
1776#endif
1777
1778 ngb = mesh->giveElement( this->neghbours_base_elements.at(i) );
1779 if ( !ngb->hasIrregulars() ) {
1780 ind = ngb->giveNeighbors()->findFirstIndexOf(this->number);
1781 if ( ind ) {
1782 ngb->setNeighbor(ind, -this->number);
1783 }
1784 }
1785 }
1786 }
1787 }
1788}
1789
1790
1791void
1792Subdivision :: RS_Tetra :: generate(std :: list< int > &sharedEdgesQueue)
1793{
1794#ifdef DEBUG_CHECK
1795 if ( this->queue_flag ) {
1796 OOFEM_ERROR("unexpected queue flag of %d ", this->number);
1797 }
1798
1799#endif
1800
1801 /* generates the children elements of already bisected element and adds them into mesh;
1802 * this is done recursively;
1803 * also children array of receiver is updated to contain children numbers */
1804
1805 if ( irregular_nodes.containsOnlyZeroes() ) {
1806 // no subdivision of receiver required
1807 children.clear();
1808 } else {
1809 int irregulars1 = 0, irregulars2 = 0;
1810 int childNum, iedge, jedge, kedge, iiedge, jjedge, kkedge, inode, jnode, knode, nnode, iside, jside, kside, nside;
1811 int i, ind, leIndex1 = 0, leIndex2 = 0;
1812 IntArray _nodes(4);
1813 Subdivision :: RS_Tetra *child;
1814 Subdivision :: RS_Element *ngb;
1815#ifdef __MPI_PARALLEL_MODE
1816 int eNum = this->mesh->giveNumberOfEdges();
1817 Subdivision :: RS_SharedEdge *_edge;
1818 bool ishared = false, jshared = false, kshared = false;
1819 bool iishared = false, jjshared = false, kkshared = false;
1820#endif
1821
1822 // leIndex determines primary edge to be subdivided
1823 // it is identified either with iedge or iiedge
1824 /*
1825 *
1826 * inode
1827 * o
1828 *
1829 * iiedge=leIndex(if>3)
1830 * x
1831 * inode, jnode, knode - base nodes
1832 * kedge x nnode x jedge nnode - top node
1833 * o iiedge, jjedge, kkedge - edges connecting base nodes with top node
1834 *
1835 * jjedge x x kkedge
1836 *
1837 * o x o
1838 * jnode iedge knode
1839 * =leIndex(if<=3)
1840 *
1841 * children keep all nodes in the same order except for that one which is replaced by irregular on leIndex edge !!!
1842 */
1843 if ( leIndex <= 3 ) {
1844 iedge = leIndex;
1845 } else {
1846 iedge = ( leIndex == 6 ) ? 1 : leIndex - 2;
1847 }
1848
1849 jedge = ( iedge < 3 ) ? iedge + 1 : 1;
1850 kedge = ( jedge < 3 ) ? jedge + 1 : 1;
1851
1852 inode = ( iedge > 1 ) ? iedge - 1 : 3;
1853 jnode = ( inode < 3 ) ? inode + 1 : 1;
1854 knode = ( jnode < 3 ) ? jnode + 1 : 1;
1855 nnode = 4;
1856
1857 iiedge = inode + 3;
1858 jjedge = jnode + 3;
1859 kkedge = knode + 3;
1860
1861 iside = iedge + 1;
1862 jside = jedge + 1;
1863 kside = kedge + 1;
1864 nside = 1;
1865
1866 this->children.resize(2);
1867
1868#ifdef __MPI_PARALLEL_MODE
1869 if ( shared_edges.giveSize() ) {
1870 if ( shared_edges.at(iedge) ) {
1871 ishared = true;
1872 }
1873
1874 if ( shared_edges.at(jedge) ) {
1875 jshared = true;
1876 }
1877
1878 if ( shared_edges.at(kedge) ) {
1879 kshared = true;
1880 }
1881
1882 if ( shared_edges.at(iiedge) ) {
1883 iishared = true;
1884 }
1885
1886 if ( shared_edges.at(jjedge) ) {
1887 jjshared = true;
1888 }
1889
1890 if ( shared_edges.at(kkedge) ) {
1891 kkshared = true;
1892 }
1893 }
1894
1895#endif
1896
1897 if ( leIndex <= 3 ) {
1898 // count number of irregulars on each child;
1899 // if there is one irregular only, the set leIndex is valid
1900 // otherwise it is corrected later
1901 if ( irregular_nodes.at(iiedge) ) {
1902 irregulars1++;
1903 irregulars2++;
1904 leIndex1 = leIndex2 = 4;
1905 }
1906
1907 if ( irregular_nodes.at(kedge) ) {
1908 irregulars1++;
1909 leIndex1 = 1;
1910 }
1911
1912 if ( irregular_nodes.at(jjedge) ) {
1913 irregulars1++;
1914 leIndex1 = 5;
1915 }
1916
1917 if ( irregular_nodes.at(jedge) ) {
1918 irregulars2++;
1919 leIndex2 = 3;
1920 }
1921
1922 if ( irregular_nodes.at(kkedge) ) {
1923 irregulars2++;
1924 leIndex2 = 6;
1925 }
1926
1927 if ( irregulars1 > 1 ) {
1928 // use parent information about the longest edge on kside
1929 leIndex1 = this->side_leIndex.at(kside);
1930
1931 if ( leIndex1 == jjedge ) {
1932 leIndex1 = 5;
1933 } else if ( leIndex1 == kedge ) {
1934 leIndex1 = 1;
1935 } else {
1936#ifdef DEBUG_CHECK
1937 if ( leIndex1 != iiedge ) {
1938 OOFEM_ERROR("side longest edge inconsistency on %d", this->number);
1939 }
1940
1941#endif
1942 leIndex1 = 4;
1943 }
1944 }
1945
1946 if ( irregulars2 > 1 ) {
1947 // use parent information about the longest edge on jside
1948 leIndex2 = this->side_leIndex.at(jside);
1949
1950 if ( leIndex2 == kkedge ) {
1951 leIndex2 = 6;
1952 } else if ( leIndex2 == jedge ) {
1953 leIndex2 = 3;
1954 } else {
1955#ifdef DEBUG_CHECK
1956 if ( leIndex2 != iiedge ) {
1957 OOFEM_ERROR("side longest edge inconsistency on %d", this->number);
1958 }
1959
1960#endif
1961 leIndex2 = 4;
1962 }
1963 }
1964
1965#ifdef __MPI_PARALLEL_MODE
1966 int i_shared_id = 0, n_shared_id = 0;
1967
1968 // check whether new edges are potentially shared
1969 if ( ishared ) {
1970 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() == DofManager_shared ) {
1971 if ( !this->giveNeighbor(nside) ) {
1972 _edge = new Subdivision :: RS_SharedEdge(this->mesh);
1973 _edge->setEdgeNodes( irregular_nodes.at(iedge), nodes.at(inode) );
1974
1975 this->mesh->addEdge(_edge);
1976 eNum++;
1977
1978 // get the tentative partitions
1979 // they must be confirmed via mutual communication
1980 IntArray partitions;
1981 if ( _edge->giveSharedPartitions(partitions) ) {
1982 i_shared_id = eNum;
1983 _edge->setPartitions(partitions);
1984 // put edge number into queue of shared edges to resolve remote partitions
1985 sharedEdgesQueue.push_back(eNum);
1986 }
1987 }
1988 }
1989
1990 if ( mesh->giveNode( nodes.at(nnode) )->giveParallelMode() == DofManager_shared ) {
1991 if ( !this->giveNeighbor(iside) ) {
1992 _edge = new Subdivision :: RS_SharedEdge(this->mesh);
1993 _edge->setEdgeNodes( irregular_nodes.at(iedge), nodes.at(nnode) );
1994
1995 this->mesh->addEdge(_edge);
1996 eNum++;
1997
1998 // get the tentative partitions
1999 // they must be confirmed via mutual communication
2000 IntArray partitions;
2001 if ( _edge->giveSharedPartitions(partitions) ) {
2002 n_shared_id = eNum;
2003 _edge->setPartitions(partitions);
2004 // put edge number into queue of shared edges to resolve remote partitions
2005 sharedEdgesQueue.push_back(eNum);
2006 }
2007 }
2008 }
2009 }
2010
2011#endif
2012
2013 _nodes.at(1) = nodes.at(inode);
2014 _nodes.at(2) = nodes.at(jnode);
2015 _nodes.at(3) = irregular_nodes.at(iedge);
2016 _nodes.at(4) = nodes.at(nnode);
2017 childNum = mesh->giveNumberOfElements() + 1;
2018 child = new Subdivision :: RS_Tetra(childNum, mesh, this->number, _nodes); // number, parent, coords
2019 mesh->addElement(child);
2020 children.at(1) = childNum;
2021
2022 // set neigbour info
2023 if ( irregulars1 ) {
2024 child->setNeighbor( 1, this->giveNeighbor(nside) );
2025 child->setNeighbor( 2, this->giveNeighbor(kside) );
2026 child->setNeighbor( 3, this->giveNeighbor(iside) );
2027
2028 child->setIrregular( 1, irregular_nodes.at(kedge) );
2029 child->setIrregular( 5, irregular_nodes.at(jjedge) );
2030 child->setIrregular( 4, irregular_nodes.at(iiedge) );
2031 } else {
2032 child->setNeighbor( 1, -this->giveNeighbor(nside) );
2033 child->setNeighbor( 2, -this->giveNeighbor(kside) );
2034 child->setNeighbor( 3, -this->giveNeighbor(iside) );
2035 }
2036
2037 // neihgbor4 of child1 is changed to negative during subdivision (if any) of child2
2038 child->setNeighbor(4, childNum + 1);
2039
2040#ifdef __MPI_PARALLEL_MODE
2041 // set shared info
2042 if ( ishared || kshared || iishared || jjshared ) {
2043 child->makeSharedEdges();
2044 if ( ishared ) {
2045 child->setSharedEdge( 2, shared_edges.at(iedge) );
2046 }
2047
2048 if ( kshared ) {
2049 child->setSharedEdge( 1, shared_edges.at(kedge) );
2050 }
2051
2052 if ( iishared ) {
2053 child->setSharedEdge( 4, shared_edges.at(iiedge) );
2054 }
2055
2056 if ( jjshared ) {
2057 child->setSharedEdge( 5, shared_edges.at(jjedge) );
2058 }
2059
2060 child->setSharedEdge(3, i_shared_id);
2061 child->setSharedEdge(6, n_shared_id);
2062 }
2063
2064#endif
2065
2066#ifdef DEBUG_INFO
2067 #ifdef __MPI_PARALLEL_MODE
2068 OOFEM_LOG_INFO("[%d] Child %d generated on parent %d [%d] (leIndex %d, nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d [%d %d %d %d %d %d])\n",
2069 mesh->giveSubdivision()->giveRank(), childNum,
2070 this->number, this->giveGlobalNumber(), this->leIndex,
2071 _nodes.at(1), _nodes.at(2), _nodes.at(3), _nodes.at(4),
2072 mesh->giveNode( _nodes.at(1) )->giveGlobalNumber(),
2073 mesh->giveNode( _nodes.at(2) )->giveGlobalNumber(),
2074 mesh->giveNode( _nodes.at(3) )->giveGlobalNumber(),
2075 mesh->giveNode( _nodes.at(4) )->giveGlobalNumber(),
2076 child->giveNeighbor(1), child->giveNeighbor(2), child->giveNeighbor(3), child->giveNeighbor(4),
2077 child->giveIrregular(1), child->giveIrregular(2), child->giveIrregular(3),
2078 child->giveIrregular(4), child->giveIrregular(5), child->giveIrregular(6),
2079 ( child->giveIrregular(1) ) ? mesh->giveNode( child->giveIrregular(1) )->giveGlobalNumber() : 0,
2080 ( child->giveIrregular(2) ) ? mesh->giveNode( child->giveIrregular(2) )->giveGlobalNumber() : 0,
2081 ( child->giveIrregular(3) ) ? mesh->giveNode( child->giveIrregular(3) )->giveGlobalNumber() : 0,
2082 ( child->giveIrregular(4) ) ? mesh->giveNode( child->giveIrregular(4) )->giveGlobalNumber() : 0,
2083 ( child->giveIrregular(5) ) ? mesh->giveNode( child->giveIrregular(5) )->giveGlobalNumber() : 0,
2084 ( child->giveIrregular(6) ) ? mesh->giveNode( child->giveIrregular(6) )->giveGlobalNumber() : 0);
2085 #else
2086 OOFEM_LOG_INFO( "Child %d generated on parent %d (leIndex %d, nds %d %d %d %d, ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
2087 childNum, this->number, this->leIndex, _nodes.at(1), _nodes.at(2), _nodes.at(3), _nodes.at(4),
2088 child->giveNeighbor(1), child->giveNeighbor(2), child->giveNeighbor(3), child->giveNeighbor(4),
2089 child->giveIrregular(1), child->giveIrregular(2), child->giveIrregular(3),
2090 child->giveIrregular(4), child->giveIrregular(5), child->giveIrregular(6) );
2091 #endif
2092#endif
2093
2094 _nodes.at(1) = nodes.at(inode);
2095 _nodes.at(2) = irregular_nodes.at(iedge);
2096 _nodes.at(3) = nodes.at(knode);
2097 _nodes.at(4) = nodes.at(nnode);
2098 childNum = mesh->giveNumberOfElements() + 1;
2099 child = new Subdivision :: RS_Tetra(childNum, mesh, this->number, _nodes); // number, parent, coords
2100 mesh->addElement(child);
2101 children.at(2) = childNum;
2102
2103 // set neigbour info
2104 if ( irregulars2 ) {
2105 child->setNeighbor( 1, this->giveNeighbor(nside) );
2106 child->setNeighbor( 3, this->giveNeighbor(iside) );
2107 child->setNeighbor( 4, this->giveNeighbor(jside) );
2108
2109 child->setIrregular( 3, irregular_nodes.at(jedge) );
2110 child->setIrregular( 6, irregular_nodes.at(kkedge) );
2111 child->setIrregular( 4, irregular_nodes.at(iiedge) );
2112 } else {
2113 child->setNeighbor( 1, -this->giveNeighbor(nside) );
2114 child->setNeighbor( 3, -this->giveNeighbor(iside) );
2115 child->setNeighbor( 4, -this->giveNeighbor(jside) );
2116 }
2117
2118 // neihgbor2 of child2 is changed to negative during subdivision (if any) of child1
2119 child->setNeighbor(2, childNum - 1);
2120#ifdef __MPI_PARALLEL_MODE
2121 // set shared info
2122 if ( ishared || jshared || iishared || kkshared ) {
2123 child->makeSharedEdges();
2124 if ( ishared ) {
2125 child->setSharedEdge( 2, shared_edges.at(iedge) );
2126 }
2127
2128 if ( jshared ) {
2129 child->setSharedEdge( 3, shared_edges.at(jedge) );
2130 }
2131
2132 if ( iishared ) {
2133 child->setSharedEdge( 4, shared_edges.at(iiedge) );
2134 }
2135
2136 if ( kkshared ) {
2137 child->setSharedEdge( 6, shared_edges.at(kkedge) );
2138 }
2139
2140 child->setSharedEdge(1, i_shared_id);
2141 child->setSharedEdge(5, n_shared_id);
2142 }
2143
2144#endif
2145
2146#ifdef __MPI_PARALLEL_MODE
2147 // set connected elements
2148 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() == DofManager_shared ) {
2149 mesh->giveNode( nodes.at(inode) )->eraseConnectedElement( this->giveNumber() );
2150 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum);
2151 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 1);
2152 }
2153
2154 if ( mesh->giveNode( nodes.at(nnode) )->giveParallelMode() == DofManager_shared ) {
2155 mesh->giveNode( nodes.at(nnode) )->eraseConnectedElement( this->giveNumber() );
2156 mesh->giveNode( nodes.at(nnode) )->insertConnectedElement(childNum);
2157 mesh->giveNode( nodes.at(nnode) )->insertConnectedElement(childNum - 1);
2158 }
2159
2160 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() == DofManager_shared ) {
2161 mesh->giveNode( nodes.at(jnode) )->eraseConnectedElement( this->giveNumber() );
2162 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum - 1);
2163 }
2164
2165 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() == DofManager_shared ) {
2166 mesh->giveNode( nodes.at(knode) )->eraseConnectedElement( this->giveNumber() );
2167 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum);
2168 }
2169
2170 if ( ishared ) {
2171 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum);
2172 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 1);
2173 }
2174
2175#endif
2176
2177#ifdef DEBUG_INFO
2178 #ifdef __MPI_PARALLEL_MODE
2179 OOFEM_LOG_INFO("[%d] Child %d generated on parent %d [%d] (leIndex %d, nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d [%d %d %d %d %d %d])\n",
2180 mesh->giveSubdivision()->giveRank(), childNum,
2181 this->number, this->giveGlobalNumber(), this->leIndex,
2182 _nodes.at(1), _nodes.at(2), _nodes.at(3), _nodes.at(4),
2183 mesh->giveNode( _nodes.at(1) )->giveGlobalNumber(),
2184 mesh->giveNode( _nodes.at(2) )->giveGlobalNumber(),
2185 mesh->giveNode( _nodes.at(3) )->giveGlobalNumber(),
2186 mesh->giveNode( _nodes.at(4) )->giveGlobalNumber(),
2187 child->giveNeighbor(1), child->giveNeighbor(2), child->giveNeighbor(3), child->giveNeighbor(4),
2188 child->giveIrregular(1), child->giveIrregular(2), child->giveIrregular(3),
2189 child->giveIrregular(4), child->giveIrregular(5), child->giveIrregular(6),
2190 ( child->giveIrregular(1) ) ? mesh->giveNode( child->giveIrregular(1) )->giveGlobalNumber() : 0,
2191 ( child->giveIrregular(2) ) ? mesh->giveNode( child->giveIrregular(2) )->giveGlobalNumber() : 0,
2192 ( child->giveIrregular(3) ) ? mesh->giveNode( child->giveIrregular(3) )->giveGlobalNumber() : 0,
2193 ( child->giveIrregular(4) ) ? mesh->giveNode( child->giveIrregular(4) )->giveGlobalNumber() : 0,
2194 ( child->giveIrregular(5) ) ? mesh->giveNode( child->giveIrregular(5) )->giveGlobalNumber() : 0,
2195 ( child->giveIrregular(6) ) ? mesh->giveNode( child->giveIrregular(6) )->giveGlobalNumber() : 0);
2196 #else
2197 OOFEM_LOG_INFO( "Child %d generated on parent %d (leIndex %d, nds %d %d %d %d, ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
2198 childNum, this->number, this->leIndex, _nodes.at(1), _nodes.at(2), _nodes.at(3), _nodes.at(4),
2199 child->giveNeighbor(1), child->giveNeighbor(2), child->giveNeighbor(3), child->giveNeighbor(4),
2200 child->giveIrregular(1), child->giveIrregular(2), child->giveIrregular(3),
2201 child->giveIrregular(4), child->giveIrregular(5), child->giveIrregular(6) );
2202 #endif
2203#endif
2204
2205 // set connected elements to nonshared nodes on outer boundary
2206#ifdef __MPI_PARALLEL_MODE
2207 if ( !ishared ) {
2208#endif
2209 if ( mesh->giveNode( irregular_nodes.at(iedge) )->giveNumber() < 0 ) { // check for marked local irregular
2210 // irregular node on outer boundary
2211 // insert connected elements
2212 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum);
2213 mesh->giveNode( irregular_nodes.at(iedge) )->insertConnectedElement(childNum - 1);
2214 }
2215
2216 // update connectivity of both end nodes of iedge if not shared
2217 // and ONLY if there is already list of connected elements
2218#ifdef __MPI_PARALLEL_MODE
2219 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() != DofManager_shared ) { // update already done
2220#endif
2221 if ( mesh->giveNode( nodes.at(jnode) )->giveConnectedElements()->giveSize() ) {
2222 mesh->giveNode( nodes.at(jnode) )->eraseConnectedElement( this->giveNumber() );
2223 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum - 1);
2224 }
2225
2226#ifdef __MPI_PARALLEL_MODE
2227 }
2228
2229#endif
2230#ifdef __MPI_PARALLEL_MODE
2231 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() != DofManager_shared ) { // update already done
2232#endif
2233 if ( mesh->giveNode( nodes.at(knode) )->giveConnectedElements()->giveSize() ) {
2234 mesh->giveNode( nodes.at(knode) )->eraseConnectedElement( this->giveNumber() );
2235 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum);
2236 }
2237
2238#ifdef __MPI_PARALLEL_MODE
2239 }
2240#endif
2241#ifdef __MPI_PARALLEL_MODE
2242 }
2243#endif
2244#ifdef __MPI_PARALLEL_MODE
2245 if ( !iishared ) {
2246#endif
2247 // update connectivity of both end nodes of iiedge if not shared
2248 // and ONLY if there is already list of connected elements
2249#ifdef __MPI_PARALLEL_MODE
2250 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() != DofManager_shared ) { // update already done
2251#endif
2252 if ( mesh->giveNode( nodes.at(inode) )->giveConnectedElements()->giveSize() ) {
2253 mesh->giveNode( nodes.at(inode) )->eraseConnectedElement( this->giveNumber() );
2254 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum);
2255 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 1);
2256 }
2257
2258#ifdef __MPI_PARALLEL_MODE
2259 }
2260#endif
2261#ifdef __MPI_PARALLEL_MODE
2262 if ( mesh->giveNode( nodes.at(nnode) )->giveParallelMode() != DofManager_shared ) { // update already done
2263#endif
2264 if ( mesh->giveNode( nodes.at(nnode) )->giveConnectedElements()->giveSize() ) {
2265 mesh->giveNode( nodes.at(nnode) )->eraseConnectedElement( this->giveNumber() );
2266 mesh->giveNode( nodes.at(nnode) )->insertConnectedElement(childNum);
2267 mesh->giveNode( nodes.at(nnode) )->insertConnectedElement(childNum - 1);
2268 }
2269
2270#ifdef __MPI_PARALLEL_MODE
2271 }
2272#endif
2273#ifdef __MPI_PARALLEL_MODE
2274 }
2275#endif
2276 } else {
2277 // count number of irregulars on each child;
2278 // if there is one irregular only, the set leIndex is valid
2279 // otherwise it is corrected later
2280 if ( irregular_nodes.at(iedge) ) {
2281 irregulars1++;
2282 irregulars2++;
2283 leIndex1 = leIndex2 = 2;
2284 }
2285
2286 if ( irregular_nodes.at(jedge) ) {
2287 irregulars1++;
2288 leIndex1 = 3;
2289 }
2290
2291 if ( irregular_nodes.at(kedge) ) {
2292 irregulars1++;
2293 leIndex1 = 1;
2294 }
2295
2296 if ( irregular_nodes.at(jjedge) ) {
2297 irregulars2++;
2298 leIndex2 = 5;
2299 }
2300
2301 if ( irregular_nodes.at(kkedge) ) {
2302 irregulars2++;
2303 leIndex2 = 6;
2304 }
2305
2306 if ( irregulars1 > 1 ) {
2307 // use parent information about the longest edge on nside
2308 leIndex1 = this->side_leIndex.at(nside);
2309
2310 if ( leIndex1 == jedge ) {
2311 leIndex1 = 3;
2312 } else if ( leIndex1 == kedge ) {
2313 leIndex1 = 1;
2314 } else {
2315#ifdef DEBUG_CHECK
2316 if ( leIndex1 != iedge ) {
2317 OOFEM_ERROR("side longest edge inconsistency on %d", this->number);
2318 }
2319
2320#endif
2321 leIndex1 = 2;
2322 }
2323 }
2324
2325 if ( irregulars2 > 1 ) {
2326 // use parent information about the longest edge on iside
2327 leIndex2 = this->side_leIndex.at(iside);
2328
2329 if ( leIndex2 == kkedge ) {
2330 leIndex2 = 6;
2331 } else if ( leIndex2 == jjedge ) {
2332 leIndex2 = 5;
2333 } else {
2334#ifdef DEBUG_CHECK
2335 if ( leIndex2 != iedge ) {
2336 OOFEM_ERROR("side longest edge inconsistency on %d", this->number);
2337 }
2338
2339#endif
2340 leIndex2 = 2;
2341 }
2342 }
2343
2344#ifdef __MPI_PARALLEL_MODE
2345 int j_shared_id = 0, k_shared_id = 0;
2346
2347 // check whether new edges are potentially shared
2348 if ( iishared ) {
2349 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() == DofManager_shared ) {
2350 if ( !this->giveNeighbor(kside) ) {
2351 _edge = new Subdivision :: RS_SharedEdge(this->mesh);
2352 _edge->setEdgeNodes( irregular_nodes.at(iiedge), nodes.at(jnode) );
2353
2354 this->mesh->addEdge(_edge);
2355 eNum++;
2356
2357 // get the tentative partitions
2358 // they must be confirmed via mutual communication
2359 IntArray partitions;
2360 if ( _edge->giveSharedPartitions(partitions) ) {
2361 j_shared_id = eNum;
2362 _edge->setPartitions(partitions);
2363 // put edge number into queue of shared edges to resolve remote partitions
2364 sharedEdgesQueue.push_back(eNum);
2365 }
2366 }
2367 }
2368
2369 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() == DofManager_shared ) {
2370 if ( !this->giveNeighbor(jside) ) {
2371 _edge = new Subdivision :: RS_SharedEdge(this->mesh);
2372 _edge->setEdgeNodes( irregular_nodes.at(iiedge), nodes.at(knode) );
2373
2374 this->mesh->addEdge(_edge);
2375 eNum++;
2376
2377 // get the tentative partitions
2378 // they must be confirmed via mutual communication
2379 IntArray partitions;
2380 if ( _edge->giveSharedPartitions(partitions) ) {
2381 k_shared_id = eNum;
2382 _edge->setPartitions(partitions);
2383 // put edge number into queue of shared edges to resolve remote partitions
2384 sharedEdgesQueue.push_back(eNum);
2385 }
2386 }
2387 }
2388 }
2389
2390#endif
2391
2392 _nodes.at(1) = nodes.at(inode);
2393 _nodes.at(2) = nodes.at(jnode);
2394 _nodes.at(3) = nodes.at(knode);
2395 _nodes.at(4) = irregular_nodes.at(iiedge);
2396 childNum = mesh->giveNumberOfElements() + 1;
2397 child = new Subdivision :: RS_Tetra(childNum, mesh, this->number, _nodes); // number, parent, coords
2398 mesh->addElement(child);
2399 children.at(1) = childNum;
2400 // set neigbour info
2401 if ( irregulars1 ) {
2402 child->setNeighbor( 1, this->giveNeighbor(nside) );
2403 child->setNeighbor( 2, this->giveNeighbor(kside) );
2404 child->setNeighbor( 4, this->giveNeighbor(jside) );
2405
2406 child->setIrregular( 1, irregular_nodes.at(kedge) );
2407 child->setIrregular( 3, irregular_nodes.at(jedge) );
2408 child->setIrregular( 2, irregular_nodes.at(iedge) );
2409 } else {
2410 child->setNeighbor( 1, -this->giveNeighbor(nside) );
2411 child->setNeighbor( 2, -this->giveNeighbor(kside) );
2412 child->setNeighbor( 4, -this->giveNeighbor(jside) );
2413 }
2414
2415 // neihgbor3 of child1 is changed to negative during subdivision (if any) of child2
2416 child->setNeighbor(3, childNum + 1);
2417#ifdef __MPI_PARALLEL_MODE
2418 // set shared info
2419 if ( ishared || jshared || kshared || iishared ) {
2420 child->makeSharedEdges();
2421 if ( ishared ) {
2422 child->setSharedEdge( 2, shared_edges.at(iedge) );
2423 }
2424
2425 if ( jshared ) {
2426 child->setSharedEdge( 3, shared_edges.at(jedge) );
2427 }
2428
2429 if ( kshared ) {
2430 child->setSharedEdge( 1, shared_edges.at(kedge) );
2431 }
2432
2433 if ( iishared ) {
2434 child->setSharedEdge( 4, shared_edges.at(iiedge) );
2435 }
2436
2437 child->setSharedEdge(5, j_shared_id);
2438 child->setSharedEdge(6, k_shared_id);
2439 }
2440
2441#endif
2442
2443#ifdef DEBUG_INFO
2444 #ifdef __MPI_PARALLEL_MODE
2445 OOFEM_LOG_INFO("[%d] Child %d generated on parent %d [%d] (leIndex %d, nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d [%d %d %d %d %d %d])\n",
2446 mesh->giveSubdivision()->giveRank(), childNum,
2447 this->number, this->giveGlobalNumber(), this->leIndex,
2448 _nodes.at(1), _nodes.at(2), _nodes.at(3), _nodes.at(4),
2449 mesh->giveNode( _nodes.at(1) )->giveGlobalNumber(),
2450 mesh->giveNode( _nodes.at(2) )->giveGlobalNumber(),
2451 mesh->giveNode( _nodes.at(3) )->giveGlobalNumber(),
2452 mesh->giveNode( _nodes.at(4) )->giveGlobalNumber(),
2453 child->giveNeighbor(1), child->giveNeighbor(2), child->giveNeighbor(3), child->giveNeighbor(4),
2454 child->giveIrregular(1), child->giveIrregular(2), child->giveIrregular(3),
2455 child->giveIrregular(4), child->giveIrregular(5), child->giveIrregular(6),
2456 ( child->giveIrregular(1) ) ? mesh->giveNode( child->giveIrregular(1) )->giveGlobalNumber() : 0,
2457 ( child->giveIrregular(2) ) ? mesh->giveNode( child->giveIrregular(2) )->giveGlobalNumber() : 0,
2458 ( child->giveIrregular(3) ) ? mesh->giveNode( child->giveIrregular(3) )->giveGlobalNumber() : 0,
2459 ( child->giveIrregular(4) ) ? mesh->giveNode( child->giveIrregular(4) )->giveGlobalNumber() : 0,
2460 ( child->giveIrregular(5) ) ? mesh->giveNode( child->giveIrregular(5) )->giveGlobalNumber() : 0,
2461 ( child->giveIrregular(6) ) ? mesh->giveNode( child->giveIrregular(6) )->giveGlobalNumber() : 0);
2462 #else
2463 OOFEM_LOG_INFO( "Child %d generated on parent %d (leIndex %d, nds %d %d %d %d, ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
2464 childNum, this->number, this->leIndex, _nodes.at(1), _nodes.at(2), _nodes.at(3), _nodes.at(4),
2465 child->giveNeighbor(1), child->giveNeighbor(2), child->giveNeighbor(3), child->giveNeighbor(4),
2466 child->giveIrregular(1), child->giveIrregular(2), child->giveIrregular(3),
2467 child->giveIrregular(4), child->giveIrregular(5), child->giveIrregular(6) );
2468 #endif
2469#endif
2470
2471 _nodes.at(1) = irregular_nodes.at(iiedge);
2472 _nodes.at(2) = nodes.at(jnode);
2473 _nodes.at(3) = nodes.at(knode);
2474 _nodes.at(4) = nodes.at(nnode);
2475 childNum = mesh->giveNumberOfElements() + 1;
2476 child = new Subdivision :: RS_Tetra(childNum, mesh, this->number, _nodes); // number, parent, coords
2477 mesh->addElement(child);
2478 children.at(2) = childNum;
2479
2480 // set neigbour info
2481 if ( irregulars2 ) {
2482 child->setNeighbor( 2, this->giveNeighbor(kside) );
2483 child->setNeighbor( 3, this->giveNeighbor(iside) );
2484 child->setNeighbor( 4, this->giveNeighbor(jside) );
2485
2486 child->setIrregular( 5, irregular_nodes.at(jjedge) );
2487 child->setIrregular( 6, irregular_nodes.at(kkedge) );
2488 child->setIrregular( 2, irregular_nodes.at(iedge) );
2489 } else {
2490 child->setNeighbor( 2, -this->giveNeighbor(kside) );
2491 child->setNeighbor( 3, -this->giveNeighbor(iside) );
2492 child->setNeighbor( 4, -this->giveNeighbor(jside) );
2493 }
2494
2495 // neihgbor1 of child2 is changed to negative during subdivision (if any) of child1
2496 child->setNeighbor(1, childNum - 1);
2497#ifdef __MPI_PARALLEL_MODE
2498 // set shared info
2499 if ( ishared || jjshared || kkshared || iishared ) {
2500 child->makeSharedEdges();
2501 if ( ishared ) {
2502 child->setSharedEdge( 2, shared_edges.at(iedge) );
2503 }
2504
2505 if ( jjshared ) {
2506 child->setSharedEdge( 5, shared_edges.at(jjedge) );
2507 }
2508
2509 if ( kkshared ) {
2510 child->setSharedEdge( 6, shared_edges.at(kkedge) );
2511 }
2512
2513 if ( iishared ) {
2514 child->setSharedEdge( 4, shared_edges.at(iiedge) );
2515 }
2516
2517 child->setSharedEdge(1, j_shared_id);
2518 child->setSharedEdge(3, k_shared_id);
2519 }
2520
2521#endif
2522
2523#ifdef __MPI_PARALLEL_MODE
2524 // set connected elements
2525 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() == DofManager_shared ) {
2526 mesh->giveNode( nodes.at(jnode) )->eraseConnectedElement( this->giveNumber() );
2527 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum);
2528 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum - 1);
2529 }
2530
2531 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() == DofManager_shared ) {
2532 mesh->giveNode( nodes.at(knode) )->eraseConnectedElement( this->giveNumber() );
2533 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum);
2534 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum - 1);
2535 }
2536
2537 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() == DofManager_shared ) {
2538 mesh->giveNode( nodes.at(inode) )->eraseConnectedElement( this->giveNumber() );
2539 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 1);
2540 }
2541
2542 if ( mesh->giveNode( nodes.at(nnode) )->giveParallelMode() == DofManager_shared ) {
2543 mesh->giveNode( nodes.at(nnode) )->eraseConnectedElement( this->giveNumber() );
2544 mesh->giveNode( nodes.at(nnode) )->insertConnectedElement(childNum);
2545 }
2546
2547 if ( iishared ) {
2548 mesh->giveNode( irregular_nodes.at(iiedge) )->insertConnectedElement(childNum);
2549 mesh->giveNode( irregular_nodes.at(iiedge) )->insertConnectedElement(childNum - 1);
2550 }
2551
2552#endif
2553
2554#ifdef DEBUG_INFO
2555 #ifdef __MPI_PARALLEL_MODE
2556 OOFEM_LOG_INFO("[%d] Child %d generated on parent %d [%d] (leIndex %d, nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d [%d %d %d %d %d %d])\n",
2557 mesh->giveSubdivision()->giveRank(), childNum,
2558 this->number, this->giveGlobalNumber(), this->leIndex,
2559 _nodes.at(1), _nodes.at(2), _nodes.at(3), _nodes.at(4),
2560 mesh->giveNode( _nodes.at(1) )->giveGlobalNumber(),
2561 mesh->giveNode( _nodes.at(2) )->giveGlobalNumber(),
2562 mesh->giveNode( _nodes.at(3) )->giveGlobalNumber(),
2563 mesh->giveNode( _nodes.at(4) )->giveGlobalNumber(),
2564 child->giveNeighbor(1), child->giveNeighbor(2), child->giveNeighbor(3), child->giveNeighbor(4),
2565 child->giveIrregular(1), child->giveIrregular(2), child->giveIrregular(3),
2566 child->giveIrregular(4), child->giveIrregular(5), child->giveIrregular(6),
2567 ( child->giveIrregular(1) ) ? mesh->giveNode( child->giveIrregular(1) )->giveGlobalNumber() : 0,
2568 ( child->giveIrregular(2) ) ? mesh->giveNode( child->giveIrregular(2) )->giveGlobalNumber() : 0,
2569 ( child->giveIrregular(3) ) ? mesh->giveNode( child->giveIrregular(3) )->giveGlobalNumber() : 0,
2570 ( child->giveIrregular(4) ) ? mesh->giveNode( child->giveIrregular(4) )->giveGlobalNumber() : 0,
2571 ( child->giveIrregular(5) ) ? mesh->giveNode( child->giveIrregular(5) )->giveGlobalNumber() : 0,
2572 ( child->giveIrregular(6) ) ? mesh->giveNode( child->giveIrregular(6) )->giveGlobalNumber() : 0);
2573 #else
2574 OOFEM_LOG_INFO( "Child %d generated on parent %d (leIndex %d, nds %d %d %d %d, ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
2575 childNum, this->number, this->leIndex, _nodes.at(1), _nodes.at(2), _nodes.at(3), _nodes.at(4),
2576 child->giveNeighbor(1), child->giveNeighbor(2), child->giveNeighbor(3), child->giveNeighbor(4),
2577 child->giveIrregular(1), child->giveIrregular(2), child->giveIrregular(3),
2578 child->giveIrregular(4), child->giveIrregular(5), child->giveIrregular(6) );
2579 #endif
2580#endif
2581
2582 // set connected elements to nonshared nodes on outer boundary
2583#ifdef __MPI_PARALLEL_MODE
2584 if ( !iishared ) {
2585#endif
2586 if ( mesh->giveNode( irregular_nodes.at(iiedge) )->giveNumber() < 0 ) { // check for marked local irregular
2587 // irregular node on outer boundary
2588 // insert connected elements
2589 mesh->giveNode( irregular_nodes.at(iiedge) )->insertConnectedElement(childNum);
2590 mesh->giveNode( irregular_nodes.at(iiedge) )->insertConnectedElement(childNum - 1);
2591 }
2592
2593 // update connectivity of both end nodes of iiedge if not shared
2594 // and ONLY if there is already list of connected elements
2595#ifdef __MPI_PARALLEL_MODE
2596 if ( mesh->giveNode( nodes.at(inode) )->giveParallelMode() != DofManager_shared ) { // update already done
2597#endif
2598 if ( mesh->giveNode( nodes.at(inode) )->giveConnectedElements()->giveSize() ) {
2599 mesh->giveNode( nodes.at(inode) )->eraseConnectedElement( this->giveNumber() );
2600 mesh->giveNode( nodes.at(inode) )->insertConnectedElement(childNum - 1);
2601 }
2602
2603#ifdef __MPI_PARALLEL_MODE
2604 }
2605#endif
2606#ifdef __MPI_PARALLEL_MODE
2607 if ( mesh->giveNode( nodes.at(nnode) )->giveParallelMode() != DofManager_shared ) { // update already done
2608#endif
2609 if ( mesh->giveNode( nodes.at(nnode) )->giveConnectedElements()->giveSize() ) {
2610 mesh->giveNode( nodes.at(nnode) )->eraseConnectedElement( this->giveNumber() );
2611 mesh->giveNode( nodes.at(nnode) )->insertConnectedElement(childNum);
2612 }
2613
2614#ifdef __MPI_PARALLEL_MODE
2615 }
2616#endif
2617#ifdef __MPI_PARALLEL_MODE
2618 }
2619#endif
2620#ifdef __MPI_PARALLEL_MODE
2621 if ( !ishared ) {
2622#endif
2623 // update connectivity of both end nodes of iedge if not shared
2624 // and ONLY if there is already list of connected elements
2625#ifdef __MPI_PARALLEL_MODE
2626 if ( mesh->giveNode( nodes.at(jnode) )->giveParallelMode() != DofManager_shared ) { // update already done
2627#endif
2628 if ( mesh->giveNode( nodes.at(jnode) )->giveConnectedElements()->giveSize() ) {
2629 mesh->giveNode( nodes.at(jnode) )->eraseConnectedElement( this->giveNumber() );
2630 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum);
2631 mesh->giveNode( nodes.at(jnode) )->insertConnectedElement(childNum - 1);
2632 }
2633
2634#ifdef __MPI_PARALLEL_MODE
2635 }
2636#endif
2637#ifdef __MPI_PARALLEL_MODE
2638 if ( mesh->giveNode( nodes.at(knode) )->giveParallelMode() != DofManager_shared ) { // update already done
2639#endif
2640 if ( mesh->giveNode( nodes.at(knode) )->giveConnectedElements()->giveSize() ) {
2641 mesh->giveNode( nodes.at(knode) )->eraseConnectedElement( this->giveNumber() );
2642 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum);
2643 mesh->giveNode( nodes.at(knode) )->insertConnectedElement(childNum - 1);
2644 }
2645
2646#ifdef __MPI_PARALLEL_MODE
2647 }
2648#endif
2649#ifdef __MPI_PARALLEL_MODE
2650 }
2651#endif
2652 }
2653
2654 if ( irregulars1 ) {
2655#ifdef DEBUG_CHECK
2656 if ( !mesh->giveElement( children.at(1) )->giveIrregular(leIndex1) ) {
2657 OOFEM_ERROR("leIndex incosistency for child 1 of %d", this->number);
2658 }
2659
2660#endif
2661 mesh->giveElement( children.at(1) )->setLeIndex(leIndex1);
2662 mesh->giveElement( children.at(1) )->generate(sharedEdgesQueue);
2663 }
2664
2665 if ( irregulars2 ) {
2666#ifdef DEBUG_CHECK
2667 if ( !mesh->giveElement( children.at(2) )->giveIrregular(leIndex2) ) {
2668 OOFEM_ERROR("leIndex incosistency for child 2 of %d", this->number);
2669 }
2670
2671#endif
2672 mesh->giveElement( children.at(2) )->setLeIndex(leIndex2);
2673 mesh->giveElement( children.at(2) )->generate(sharedEdgesQueue);
2674 }
2675
2676 // if there is neighbor of "this" (local or remote) not designated for bisection
2677 // its neihgbor corresponding to "this" must be made negative to enforce update_neighbors
2678 for ( i = 1; i <= 4; i++ ) {
2679 if ( this->neghbours_base_elements.at(i) ) {
2680#ifdef DEBUG_CHECK
2681 if ( this->neghbours_base_elements.at(i) < 0 ) {
2682 OOFEM_ERROR("negative neighbor of %d not expected", this->number);
2683 }
2684
2685#endif
2686
2687 ngb = mesh->giveElement( this->neghbours_base_elements.at(i) );
2688 if ( !ngb->hasIrregulars() ) {
2689 ind = ngb->giveNeighbors()->findFirstIndexOf(this->number);
2690 if ( ind ) {
2691 ngb->setNeighbor(ind, -this->number);
2692 }
2693 }
2694 }
2695 }
2696 }
2697}
2698
2699
2700
2701void
2702Subdivision :: RS_Triangle :: update_neighbours()
2703{
2704 bool found;
2705 int i, iside, parentNeighbor;
2706 const IntArray *ca;
2707
2708 /*
2709 * neghbours_base_elements pre-set in generate using this rule:
2710 * value > 0 .. real neighbour known, value equals to real neighbor on new mesh
2711 * value = 0 .. boundary
2712 * value < 0 .. neighbour set to parent element, actual neighbour has to be determined from parent children
2713 * or if no child exists then to parent new counterpart.
2714 */
2715
2716 for ( iside = 1; iside <= 3; iside++ ) {
2717 if ( this->neghbours_base_elements.at(iside) < 0 ) {
2718 parentNeighbor = -this->neghbours_base_elements.at(iside);
2719 // test if parentNeighbor has been subdivided
2720 if ( mesh->giveElement(parentNeighbor)->hasIrregulars() ) { // HUHU replace by !isTerminal
2721 // old neighbour bisected -> we loop over its children to find an appropriate new neighbor
2722 ca = mesh->giveElement(parentNeighbor)->giveChildren();
2723 found = false;
2724 for ( i = 1; i <= ca->giveSize(); i++ ) {
2725 if ( this->isNeighborOf( mesh->giveElement( ca->at(i) ) ) ) {
2726 this->neghbours_base_elements.at(iside) = ca->at(i);
2727 found = true;
2728 break;
2729 }
2730 }
2731
2732 if ( !found ) {
2733 OOFEM_ERROR("update_neighbours failed for element %d", this->number);
2734 }
2735 } else {
2736 // parent neighbour remains actual neighbour
2737 this->neghbours_base_elements.at(iside) = parentNeighbor;
2738 }
2739 } else if ( this->neghbours_base_elements.at(iside) > 0 ) {
2740 // neighbor element already set
2741 }
2742 } // end loop over element sides
2743}
2744
2745
2746void
2747Subdivision :: RS_Tetra :: update_neighbours()
2748{
2749 bool found;
2750 int i, j, k, iside, parentNeighbor;
2751 const IntArray *ca1, *ca2, *ca3;
2752
2753 /*
2754 * neghbours_base_elements pre-set in generate using this rule:
2755 * value > 0 .. real neighbour known, value equals to real neighbor on new mesh
2756 * value = 0 .. boundary
2757 * value < 0 .. neighbour set to parent element, actual neighbour has to be determined from terminal children of parent
2758 * or if no child exists then to parent new counterpart.
2759 */
2760
2761 for ( iside = 1; iside <= 4; iside++ ) {
2762 if ( this->neghbours_base_elements.at(iside) < 0 ) {
2763 parentNeighbor = -this->neghbours_base_elements.at(iside);
2764 // test if parentNeighbor has been subdivided
2765 if ( mesh->giveElement(parentNeighbor)->hasIrregulars() ) { // HUHU replace by !isTerminal
2766 // old neighbour bisected -> we loop over its terminal children to find an appropriate new neighbor;
2767 // there may be at maximum 3 levels of parent tetra subdivision
2768 ca1 = mesh->giveElement(parentNeighbor)->giveChildren();
2769 found = false;
2770 for ( i = 1; i <= ca1->giveSize(); i++ ) {
2771 if ( mesh->giveElement( ca1->at(i) )->isTerminal() ) {
2772 if ( this->isNeighborOf( mesh->giveElement( ca1->at(i) ) ) ) {
2773 this->neghbours_base_elements.at(iside) = ca1->at(i);
2774 found = true;
2775 break;
2776 }
2777 } else {
2778 ca2 = mesh->giveElement( ca1->at(i) )->giveChildren();
2779 for ( j = 1; j <= ca2->giveSize(); j++ ) {
2780 if ( mesh->giveElement( ca2->at(j) )->isTerminal() ) {
2781 if ( this->isNeighborOf( mesh->giveElement( ca2->at(j) ) ) ) {
2782 this->neghbours_base_elements.at(iside) = ca2->at(j);
2783 found = true;
2784 break;
2785 }
2786 } else {
2787 ca3 = mesh->giveElement( ca2->at(j) )->giveChildren();
2788 for ( k = 1; k <= ca3->giveSize(); k++ ) {
2789 if ( mesh->giveElement( ca3->at(k) )->isTerminal() ) {
2790 if ( this->isNeighborOf( mesh->giveElement( ca3->at(k) ) ) ) {
2791 this->neghbours_base_elements.at(iside) = ca3->at(k);
2792 found = true;
2793 break;
2794 }
2795 }
2796
2797#ifdef DEBUG_CHECK
2798 else {
2799 OOFEM_ERROR("too many subdivision levels for element %d", this->number);
2800 }
2801#endif
2802 }
2803 }
2804
2805 if ( found ) {
2806 break;
2807 }
2808 }
2809 }
2810
2811 if ( found ) {
2812 break;
2813 }
2814 }
2815
2816 if ( !found ) {
2817 OOFEM_ERROR("failed for element %d (side %d, elem %d)",
2818 this->number, iside, parentNeighbor);
2819 }
2820 } else {
2821 // parent neighbour remains actual neighbour
2822 this->neghbours_base_elements.at(iside) = parentNeighbor;
2823 }
2824 } else if ( this->neghbours_base_elements.at(iside) > 0 ) {
2825 // neighbor element already set
2826 }
2827 } // end loop over element side faces
2828
2829#ifdef DEBUG_CHECK
2830 // check updated neighbors
2831 IntArray snodes1, snodes2;
2832 RS_Element *ngb;
2833 for ( i = 1; i <= 4; i++ ) {
2834 if ( this->neghbours_base_elements.at(i) ) {
2835 if ( this->neghbours_base_elements.at(i) > 0 ) {
2836 this->giveSideNodes(i, snodes1);
2837 ngb = mesh->giveElement( this->neghbours_base_elements.at(i) );
2838 if ( ngb->giveNumber() < 0 ) {
2839 OOFEM_ERROR("neighbour %d of %d is temporary",
2840 this->neghbours_base_elements.at(i), this->number);
2841 }
2842
2843 if ( !ngb->isTerminal() ) {
2844 OOFEM_ERROR("neighbour %d of %d not terminal",
2845 this->neghbours_base_elements.at(i), this->number);
2846 }
2847
2848 if ( ngb->giveNumber() < this->number ) {
2849 // ngb has been already processed
2850 j = ngb->giveNeighbors()->findFirstIndexOf(this->number);
2851 if ( j ) {
2852 ngb->giveSideNodes(j, snodes2);
2853 for ( k = 1; k <= 3; k++ ) {
2854 if ( snodes2.findFirstIndexOf( snodes1.at(k) ) ) {
2855 continue;
2856 }
2857
2858 OOFEM_ERROR( "element %d is not neighbor (%d) of element %d",
2859 this->number, i, this->neghbours_base_elements.at(i) );
2860 }
2861 } else {
2862 OOFEM_ERROR( "element %d is not neighbor (%d) of element %d",
2863 this->number, i, this->neghbours_base_elements.at(i) );
2864 }
2865 } else {
2866 // ngb has not been yet processed ==> I cannot check particular side of ngb
2867 for ( k = 1; k <= 3; k++ ) {
2868 if ( ngb->giveNodes()->findFirstIndexOf( snodes1.at(k) ) ) {
2869 continue;
2870 }
2871
2872 OOFEM_ERROR( "element %d is not neighbor of element %d",
2873 this->number, this->neghbours_base_elements.at(i) );
2874 }
2875 }
2876 } else {
2877 OOFEM_ERROR("negative neighbour %d of %d not expected",
2878 this->neghbours_base_elements.at(i), this->number);
2879 }
2880 }
2881 }
2882
2883#endif
2884}
2885
2886
2887bool
2888Subdivision :: RS_Triangle :: isNeighborOf(Subdivision :: RS_Element *elem)
2889{
2890 // Simplified implementation, considering only one element type - triangles
2891 int i, _c = 0;
2892 for ( i = 1; i <= 3; i++ ) {
2893 _c += elem->containsNode( this->nodes.at(i) );
2894 }
2895
2896 return ( _c == 2 );
2897}
2898
2899
2900bool
2901Subdivision :: RS_Tetra :: isNeighborOf(Subdivision :: RS_Element *elem)
2902{
2903 // Simplified implementation, considering only one element type - tetras
2904 int i, _c = 0;
2905 for ( i = 1; i <= 4; i++ ) {
2906 _c += elem->containsNode( this->nodes.at(i) );
2907 }
2908
2909 return ( _c == 3 );
2910}
2911
2912
2913void
2914Subdivision :: RS_Triangle :: giveSideNodes(int iside, IntArray &snodes)
2915{
2916 int inode, jnode;
2917
2918 inode = iside;
2919 jnode = ( iside < 3 ) ? iside + 1 : 1;
2920
2921 snodes.resize(2);
2922 snodes.at(1) = nodes.at(inode);
2923 snodes.at(2) = nodes.at(jnode);
2924}
2925
2926
2927void
2928Subdivision :: RS_Tetra :: giveSideNodes(int iside, IntArray &snodes)
2929{
2930 int inode, jnode, knode;
2931
2932 if ( iside == 1 ) {
2933 inode = 1;
2934 jnode = 2;
2935 knode = 3;
2936 } else {
2937 inode = iside - 1;
2938 jnode = ( iside < 4 ) ? iside : 1;
2939 knode = 4;
2940 }
2941
2942 snodes.resize(3);
2943 snodes.at(1) = nodes.at(inode);
2944 snodes.at(2) = nodes.at(jnode);
2945 snodes.at(3) = nodes.at(knode);
2946}
2947
2948
2949
2950double
2951Subdivision :: RS_Triangle :: giveDensity()
2952{
2953 double x1, x2, x3, y1, y2, y3;
2954 x1 = mesh->giveNode( nodes.at(1) )->giveCoordinate(1);
2955 x2 = mesh->giveNode( nodes.at(2) )->giveCoordinate(1);
2956 x3 = mesh->giveNode( nodes.at(3) )->giveCoordinate(1);
2957
2958 y1 = mesh->giveNode( nodes.at(1) )->giveCoordinate(2);
2959 y2 = mesh->giveNode( nodes.at(2) )->giveCoordinate(2);
2960 y3 = mesh->giveNode( nodes.at(3) )->giveCoordinate(2);
2961
2962 return sqrt( fabs( 0.5 * ( x2 * y3 + x1 * y2 + y1 * x3 - x2 * y1 - x3 * y2 - x1 * y3 ) ) );
2963}
2964
2965
2966double
2967Subdivision :: RS_Tetra :: giveDensity()
2968{
2969 double x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4;
2970 double dx1, dx2, dx3, dy1, dy2, dy3, dz1, dz2, dz3;
2971 double vol, d;
2972 x1 = mesh->giveNode( nodes.at(1) )->giveCoordinate(1);
2973 x2 = mesh->giveNode( nodes.at(2) )->giveCoordinate(1);
2974 x3 = mesh->giveNode( nodes.at(3) )->giveCoordinate(1);
2975 x4 = mesh->giveNode( nodes.at(4) )->giveCoordinate(1);
2976
2977 y1 = mesh->giveNode( nodes.at(1) )->giveCoordinate(2);
2978 y2 = mesh->giveNode( nodes.at(2) )->giveCoordinate(2);
2979 y3 = mesh->giveNode( nodes.at(3) )->giveCoordinate(2);
2980 y4 = mesh->giveNode( nodes.at(4) )->giveCoordinate(2);
2981
2982 z1 = mesh->giveNode( nodes.at(1) )->giveCoordinate(3);
2983 z2 = mesh->giveNode( nodes.at(2) )->giveCoordinate(3);
2984 z3 = mesh->giveNode( nodes.at(3) )->giveCoordinate(3);
2985 z4 = mesh->giveNode( nodes.at(4) )->giveCoordinate(3);
2986
2987 dx1 = x2 - x1;
2988 dy1 = y2 - y1;
2989 dz1 = z2 - z1;
2990 dx2 = x3 - x1;
2991 dy2 = y3 - y1;
2992 dz2 = z3 - z1;
2993 dx3 = x4 - x1;
2994 dy3 = y4 - y1;
2995 dz3 = z4 - z1;
2996
2997 vol = ( dx3 * ( dy1 * dz2 - dz1 * dy2 ) + dy3 * ( dz1 * dx2 - dx1 * dz2 ) + dz3 * ( dx1 * dy2 - dy1 * dx2 ) ) / 6.0;
2998 d = exp(log(vol) / 3.0);
2999
3000 return d;
3001}
3002
3003
3004void
3005Subdivision :: RS_Triangle :: importConnectivity(ConnectivityTable *ct)
3006{
3007 IntArray me(1), conn;
3008 int iNode, jNode, el, i;
3009
3010 neghbours_base_elements.resize(3);
3011 neghbours_base_elements.zero(); // initialized to have no neighbour
3012
3013#if 0 // old version
3014 me.at(1) = this->number;
3015 ct->giveElementNeighbourList(conn, me);
3016
3017 int iside;
3018 for ( iside = 1; iside <= 3; iside++ ) {
3019 iNode = nodes.at(iside);
3020 jNode = nodes.at( ( iside == 3 ) ? 1 : iside + 1 );
3021
3022 // select right neighbour
3023 for ( i = 1; i <= conn.giveSize(); i++ ) {
3024 el = conn.at(i);
3025 if ( el == this->number ) {
3026 continue;
3027 }
3028
3029 #ifdef __MPI_PARALLEL_MODE
3030 if ( mesh->giveElement(el)->giveParallelMode() != Element_local ) {
3031 continue;
3032 }
3033
3034 #endif
3035 if ( mesh->giveElement(el)->containsNode(iNode) &&
3036 mesh->giveElement(el)->containsNode(jNode) ) {
3037 neghbours_base_elements.at(iside) = el;
3038 break;
3039 }
3040 }
3041 }
3042
3043#endif
3044
3045 me.at(1) = nodes.at(3);
3046 ct->giveNodeNeighbourList(conn, me);
3047 iNode = nodes.at(1);
3048 jNode = nodes.at(2);
3049
3050 // select right neighbour
3051 for ( i = 1; i <= conn.giveSize(); i++ ) {
3052 el = conn.at(i);
3053 if ( el == this->number ) {
3054 continue;
3055 }
3056
3057#ifdef __MPI_PARALLEL_MODE
3058 if ( mesh->giveElement(el)->giveParallelMode() != Element_local ) {
3059 continue;
3060 }
3061
3062#endif
3063
3064 if ( mesh->giveElement(el)->containsNode(iNode) ) {
3065 neghbours_base_elements.at(3) = el;
3066 break;
3067 }
3068 }
3069
3070 for ( i = 1; i <= conn.giveSize(); i++ ) {
3071 el = conn.at(i);
3072 if ( el == this->number ) {
3073 continue;
3074 }
3075
3076#ifdef __MPI_PARALLEL_MODE
3077 if ( mesh->giveElement(el)->giveParallelMode() != Element_local ) {
3078 continue;
3079 }
3080
3081#endif
3082
3083 if ( mesh->giveElement(el)->containsNode(jNode) ) {
3084 neghbours_base_elements.at(2) = el;
3085 break;
3086 }
3087 }
3088
3089 me.at(1) = iNode;
3090 ct->giveNodeNeighbourList(conn, me);
3091
3092 // select right neighbour
3093 for ( i = 1; i <= conn.giveSize(); i++ ) {
3094 el = conn.at(i);
3095 if ( el == this->number ) {
3096 continue;
3097 }
3098
3099#ifdef __MPI_PARALLEL_MODE
3100 if ( mesh->giveElement(el)->giveParallelMode() != Element_local ) {
3101 continue;
3102 }
3103
3104#endif
3105
3106 if ( mesh->giveElement(el)->containsNode(jNode) ) {
3107 neghbours_base_elements.at(1) = el;
3108 break;
3109 }
3110 }
3111}
3112
3113
3114void
3115Subdivision :: RS_Tetra :: importConnectivity(ConnectivityTable *ct)
3116{
3117 IntArray me(1), conn;
3118 int iNode, jNode, kNode, el, i;
3119
3120 neghbours_base_elements.resize(4);
3121 neghbours_base_elements.zero(); // initialized to have no neighbour
3122
3123#if 0 // old version
3124 me.at(1) = this->number;
3125 ct->giveElementNeighbourList(conn, me);
3126
3127 iNode = nodes.at(1);
3128 jNode = nodes.at(2);
3129 kNode = nodes.at(3);
3130
3131 // select right base neighbour
3132 for ( i = 1; i <= conn.giveSize(); i++ ) {
3133 el = conn.at(i);
3134 if ( el == this->number ) {
3135 continue;
3136 }
3137
3138 #ifdef __MPI_PARALLEL_MODE
3139 if ( mesh->giveElement(el)->giveParallelMode() != Element_local ) {
3140 continue;
3141 }
3142
3143 #endif
3144 if ( mesh->giveElement(el)->containsNode(iNode) &&
3145 mesh->giveElement(el)->containsNode(jNode) &&
3146 mesh->giveElement(el)->containsNode(kNode) ) {
3147 neghbours_base_elements.at(1) = el;
3148 break;
3149 }
3150 }
3151
3152 kNode = nodes.at(4);
3153 int iside;
3154 for ( iside = 1; iside <= 3; iside++ ) {
3155 iNode = nodes.at(iside);
3156 jNode = nodes.at( ( iside == 3 ) ? 1 : iside + 1 );
3157
3158 // select right side neighbour
3159 for ( i = 1; i <= conn.giveSize(); i++ ) {
3160 el = conn.at(i);
3161 if ( el == this->number ) {
3162 continue;
3163 }
3164
3165 #ifdef __MPI_PARALLEL_MODE
3166 if ( mesh->giveElement(el)->giveParallelMode() != Element_local ) {
3167 continue;
3168 }
3169
3170 #endif
3171 if ( mesh->giveElement(el)->containsNode(iNode) &&
3172 mesh->giveElement(el)->containsNode(jNode) &&
3173 mesh->giveElement(el)->containsNode(kNode) ) {
3174 neghbours_base_elements.at(iside + 1) = el;
3175 break;
3176 }
3177 }
3178 }
3179
3180#endif
3181
3182 bool has_i, has_j, has_k;
3183
3184 me.at(1) = nodes.at(4);
3185 ct->giveNodeNeighbourList(conn, me);
3186 iNode = nodes.at(1);
3187 jNode = nodes.at(2);
3188 kNode = nodes.at(3);
3189
3190 // select right neighbour
3191 for ( i = 1; i <= conn.giveSize(); i++ ) {
3192 el = conn.at(i);
3193 if ( el == this->number ) {
3194 continue;
3195 }
3196
3197#ifdef __MPI_PARALLEL_MODE
3198 if ( mesh->giveElement(el)->giveParallelMode() != Element_local ) {
3199 continue;
3200 }
3201
3202#endif
3203
3204 has_i = mesh->giveElement(el)->containsNode(iNode);
3205 has_j = mesh->giveElement(el)->containsNode(jNode);
3206 has_k = mesh->giveElement(el)->containsNode(kNode);
3207
3208 if ( has_i && has_j ) {
3209 neghbours_base_elements.at(2) = el;
3210 }
3211
3212 if ( has_j && has_k ) {
3213 neghbours_base_elements.at(3) = el;
3214 }
3215
3216 if ( has_k && has_i ) {
3217 neghbours_base_elements.at(4) = el;
3218 }
3219 }
3220
3221 me.at(1) = iNode;
3222 ct->giveNodeNeighbourList(conn, me);
3223
3224 // select right neighbour
3225 for ( i = 1; i <= conn.giveSize(); i++ ) {
3226 el = conn.at(i);
3227 if ( el == this->number ) {
3228 continue;
3229 }
3230
3231#ifdef __MPI_PARALLEL_MODE
3232 if ( mesh->giveElement(el)->giveParallelMode() != Element_local ) {
3233 continue;
3234 }
3235
3236#endif
3237
3238 if ( mesh->giveElement(el)->containsNode(jNode) &&
3239 mesh->giveElement(el)->containsNode(kNode) ) {
3240 neghbours_base_elements.at(1) = el;
3241 break;
3242 }
3243 }
3244
3245 /*
3246 * #ifdef DEBUG_INFO
3247 * OOFEM_LOG_INFO("Elem %d connectivity imported (nds %d %d %d %d ngbs %d %d %d %d)\n", this->number,
3248 * nodes.at(1), nodes.at(2), nodes.at(3), nodes.at(4),
3249 * neghbours_base_elements.at(1), neghbours_base_elements.at(2),
3250 * neghbours_base_elements.at(3), neghbours_base_elements.at(4));
3251 ******#endif
3252 */
3253}
3254
3255
3256#ifdef __OOFEG
3257void
3258Subdivision :: RS_Node :: drawGeometry()
3259//
3260// draws graphics representation of receiver
3261//
3262{
3263 GraphicObj *go;
3264 EPixel color;
3265 BOOLEAN suc;
3266 const char *colors[] = {
3267 "orange", "black"
3268 };
3269
3270 WCRec p [ 1 ]; /* point */
3271 p [ 0 ].x = ( FPNum ) this->giveCoordinate(1);
3272 p [ 0 ].y = ( FPNum ) this->giveCoordinate(2);
3273 p [ 0 ].z = ( FPNum ) this->giveCoordinate(3);
3274
3275 EASValsSetMType(FILLED_CIRCLE_MARKER);
3276 color = ColorGetPixelFromString(const_cast< char * >(colors [ 0 ]), & suc);
3277 EASValsSetColor(color);
3278 //EASValsSetColor( gc.getNodeColor() );
3279 EASValsSetLayer(OOFEG_RAW_GEOMETRY_LAYER);
3280 EASValsSetMSize(8);
3281 go = CreateMarker3D(p);
3282 EGWithMaskChangeAttributes(COLOR_MASK | LAYER_MASK | MTYPE_MASK | MSIZE_MASK, go);
3283 EMAddGraphicsToModel(ESIModel(), go);
3284
3285 char num [ 6 ];
3286 color = ColorGetPixelFromString(const_cast< char * >(colors [ 1 ]), & suc);
3287 EASValsSetColor(color);
3288 //EASValsSetColor( gc.getNodeColor() );
3289 EASValsSetLayer(OOFEG_RAW_GEOMETRY_LAYER);
3290 p [ 0 ].x = ( FPNum ) this->giveCoordinate(1);
3291 p [ 0 ].y = ( FPNum ) this->giveCoordinate(2);
3292 p [ 0 ].z = ( FPNum ) this->giveCoordinate(3);
3293 sprintf(num, "%d", this->number);
3294 go = CreateAnnText3D(p, num);
3295 EGWithMaskChangeAttributes(COLOR_MASK | LAYER_MASK, go);
3296 EMAddGraphicsToModel(ESIModel(), go);
3297}
3298
3299
3300void
3301Subdivision :: RS_Triangle :: drawGeometry()
3302{
3303 WCRec p [ 3 ];
3304 GraphicObj *go;
3305 EPixel color;
3306 BOOLEAN suc;
3307 const char *colors[] = {
3308 "DodgerBlue", "black"
3309 };
3310
3311 EASValsSetLineWidth(OOFEG_RAW_GEOMETRY_WIDTH);
3312 color = ColorGetPixelFromString(const_cast< char * >(colors [ 0 ]), & suc);
3313 EASValsSetColor(color);
3314 color = ColorGetPixelFromString(const_cast< char * >(colors [ 1 ]), & suc);
3315 EASValsSetEdgeColor(color);
3316 //EASValsSetColor( gc.getElementColor() );
3317 //EASValsSetEdgeColor( gc.getElementEdgeColor() );
3318 EASValsSetEdgeFlag(true);
3319 EASValsSetLayer(OOFEG_RAW_GEOMETRY_LAYER);
3320 // EASValsSetShrink(0.8);
3321 p [ 0 ].x = ( FPNum ) mesh->giveNode( nodes.at(1) )->giveCoordinate(1);
3322 p [ 0 ].y = ( FPNum ) mesh->giveNode( nodes.at(1) )->giveCoordinate(2);
3323 p [ 0 ].z = 0.;
3324 p [ 1 ].x = ( FPNum ) mesh->giveNode( nodes.at(2) )->giveCoordinate(1);
3325 p [ 1 ].y = ( FPNum ) mesh->giveNode( nodes.at(2) )->giveCoordinate(2);
3326 p [ 1 ].z = 0.;
3327 p [ 2 ].x = ( FPNum ) mesh->giveNode( nodes.at(3) )->giveCoordinate(1);
3328 p [ 2 ].y = ( FPNum ) mesh->giveNode( nodes.at(3) )->giveCoordinate(2);
3329 p [ 2 ].z = 0.;
3330
3331 go = CreateTriangle3D(p);
3332 //EGWithMaskChangeAttributes(WIDTH_MASK | COLOR_MASK | SHRINK_MASK | EDGE_COLOR_MASK | EDGE_FLAG_MASK | LAYER_MASK, go);
3333 EGWithMaskChangeAttributes(WIDTH_MASK | COLOR_MASK | EDGE_COLOR_MASK | EDGE_FLAG_MASK | LAYER_MASK, go);
3334 EGAttachObject(go, ( EObjectP ) this);
3335 EMAddGraphicsToModel(ESIModel(), go);
3336}
3337
3338
3339void
3340Subdivision :: RS_Tetra :: drawGeometry()
3341{
3342 WCRec p [ 4 ];
3343 GraphicObj *go;
3344 EPixel color;
3345 BOOLEAN suc;
3346 const char *colors[] = {
3347 "DodgerBlue", "black"
3348 };
3349
3350 EASValsSetLineWidth(OOFEG_RAW_GEOMETRY_WIDTH);
3351 color = ColorGetPixelFromString(const_cast< char * >(colors [ 0 ]), & suc);
3352 EASValsSetColor(color);
3353 color = ColorGetPixelFromString(const_cast< char * >(colors [ 1 ]), & suc);
3354 EASValsSetEdgeColor(color);
3355 //EASValsSetColor( gc.getElementColor() );
3356 //EASValsSetEdgeColor( gc.getElementEdgeColor() );
3357 EASValsSetEdgeFlag(true);
3358 EASValsSetLayer(OOFEG_RAW_GEOMETRY_LAYER);
3359 EASValsSetFillStyle(FILL_SOLID);
3360 //EASValsSetShrink(0.8);
3361 p [ 0 ].x = ( FPNum ) mesh->giveNode( nodes.at(1) )->giveCoordinate(1);
3362 p [ 0 ].y = ( FPNum ) mesh->giveNode( nodes.at(1) )->giveCoordinate(2);
3363 p [ 0 ].z = ( FPNum ) mesh->giveNode( nodes.at(1) )->giveCoordinate(3);
3364 p [ 1 ].x = ( FPNum ) mesh->giveNode( nodes.at(2) )->giveCoordinate(1);
3365 p [ 1 ].y = ( FPNum ) mesh->giveNode( nodes.at(2) )->giveCoordinate(2);
3366 p [ 1 ].z = ( FPNum ) mesh->giveNode( nodes.at(2) )->giveCoordinate(3);
3367 p [ 2 ].x = ( FPNum ) mesh->giveNode( nodes.at(3) )->giveCoordinate(1);
3368 p [ 2 ].y = ( FPNum ) mesh->giveNode( nodes.at(3) )->giveCoordinate(2);
3369 p [ 2 ].z = ( FPNum ) mesh->giveNode( nodes.at(3) )->giveCoordinate(3);
3370 p [ 3 ].x = ( FPNum ) mesh->giveNode( nodes.at(4) )->giveCoordinate(1);
3371 p [ 3 ].y = ( FPNum ) mesh->giveNode( nodes.at(4) )->giveCoordinate(2);
3372 p [ 3 ].z = ( FPNum ) mesh->giveNode( nodes.at(4) )->giveCoordinate(3);
3373
3374 go = CreateTetra(p);
3375 //EGWithMaskChangeAttributes(WIDTH_MASK | COLOR_MASK | SHRINK_MASK | EDGE_COLOR_MASK | EDGE_FLAG_MASK | LAYER_MASK | FILL_MASK, go);
3376 EGWithMaskChangeAttributes(WIDTH_MASK | COLOR_MASK | EDGE_COLOR_MASK | EDGE_FLAG_MASK | LAYER_MASK | FILL_MASK, go);
3377 EGAttachObject(go, ( EObjectP ) this);
3378 EMAddGraphicsToModel(ESIModel(), go);
3379}
3380#endif
3381
3382
3383MesherInterface :: returnCode
3384Subdivision :: createMesh(TimeStep *tStep, int domainNumber, int domainSerNum, Domain **dNew)
3385{
3386 // import data from old domain
3387 int parent, nnodes = domain->giveNumberOfDofManagers(), nelems = domain->giveNumberOfElements();
3388 IntArray enodes;
3389 Subdivision :: RS_Node *_node;
3390 Subdivision :: RS_Element *_element;
3391 Timer timer;
3392
3393 timer.startTimer();
3394
3395 if ( this->mesh ) {
3396 delete mesh;
3397 }
3398
3399 mesh = new Subdivision :: RS_Mesh(this);
3400
3401 // import nodes
3402 // all nodes (including remote which are not needed) are imported to ensure consistency between
3403 // node number (in the mesh) and its parent number (in the domain) because the domain is used to import connectivities
3404 for ( int i = 1; i <= nnodes; i++ ) {
3405 _node = new Subdivision :: RS_Node( i, mesh, i, domain->giveNode ( i )->giveCoordinates(),
3406 domain->giveErrorEstimator ( )->giveRemeshingCrit ( )->giveRequiredDofManDensity ( i, tStep ),
3407 domain->giveNode ( i )->isBoundary() );
3408 _node->setGlobalNumber( domain->giveNode(i)->giveGlobalNumber() );
3409#ifdef __MPI_PARALLEL_MODE
3410 _node->setParallelMode( domain->giveNode(i)->giveParallelMode() );
3411 _node->setPartitions( * domain->giveNode(i)->givePartitionList() );
3412#endif
3413 this->mesh->addNode(_node);
3414 }
3415
3416 // import elements
3417 // all elements (including remote which are not needed) are imported to ensure consistency between
3418 // element number (in the mesh) and its parent number (in the domain) because the domain is used to import connectivities
3419 for ( int i = 1; i <= nelems; i++ ) {
3420 if ( domain->giveElement(i)->giveGeometryType() == EGT_triangle_1 ) {
3421 enodes.resize(3);
3422 for ( int j = 1; j <= 3; j++ ) {
3423 enodes.at(j) = domain->giveElement(i)->giveDofManagerNumber(j);
3424 }
3425
3426 _element = new Subdivision :: RS_Triangle(i, mesh, i, enodes);
3427 } else if ( domain->giveElement(i)->giveGeometryType() == EGT_tetra_1 ) {
3428 enodes.resize(4);
3429 for ( int j = 1; j <= 4; j++ ) {
3430 enodes.at(j) = domain->giveElement(i)->giveDofManagerNumber(j);
3431 }
3432
3433 _element = new Subdivision :: RS_Tetra(i, mesh, i, enodes);
3434 } else {
3435 OOFEM_ERROR("Unsupported element geometry (element %d)", i);
3436 }
3437 _element->setGlobalNumber( domain->giveElement(i)->giveGlobalNumber() );
3438#ifdef __MPI_PARALLEL_MODE
3439 _element->setParallelMode( domain->giveElement(i)->giveParallelMode() );
3440#endif
3441 this->mesh->addElement(_element);
3442
3443 }
3444
3445 // import connectivities for local elements only
3446 for ( int i = 1; i <= nelems; i++ ) {
3447#ifdef __MPI_PARALLEL_MODE
3448 if ( this->mesh->giveElement(i)->giveParallelMode() != Element_local ) {
3449 continue;
3450 }
3451
3452#endif
3453 this->mesh->giveElement(i)->importConnectivity( domain->giveConnectivityTable() );
3454 }
3455
3456#ifdef __MPI_PARALLEL_MODE
3457 // import connectivities for shared nodes only
3458 // build global shared node map (for top level only)
3459 this->mesh->initGlobalSharedNodeMap();
3460 for ( int i = 1; i <= nnodes; i++ ) {
3461 _node = this->mesh->giveNode(i);
3462 if ( _node->giveParallelMode() != DofManager_shared ) {
3463 continue;
3464 }
3465
3466 _node->importConnectivity( domain->giveConnectivityTable() );
3467 this->mesh->insertGlobalSharedNodeMap(_node);
3468 }
3469
3470 // build array of shared edges (for top level only)
3471 // this can be done after connectivity is available for all shared nodes
3472 for ( int i = 1; i <= nnodes; i++ ) {
3473 _node = this->mesh->giveNode(i);
3474 if ( _node->giveParallelMode() != DofManager_shared ) {
3475 continue;
3476 }
3477
3478 _node->numberSharedEdges();
3479 }
3480
3481 // initiate queue for shared edge exchange
3482 for ( int i = 1; i <= mesh->giveNumberOfEdges(); i++ ) {
3483 if ( mesh->giveEdge(i)->givePartitions()->giveSize() ) {
3484 sharedEdgesQueue.push_back(i);
3485 }
3486 }
3487
3488 // exchange shared edges (on top level)
3489 this->exchangeSharedEdges();
3490#endif
3491
3492#ifdef __OOFEG
3493 #ifdef DRAW_MESH_BEFORE_BISECTION
3494 nelems = mesh->giveNumberOfElements();
3495 for ( int i = 1; i <= nelems; i++ ) {
3496 #ifdef __MPI_PARALLEL_MODE
3497 if ( this->mesh->giveElement(i)->giveParallelMode() != Element_local ) {
3498 continue;
3499 }
3500
3501 #endif
3502 mesh->giveElement(i)->drawGeometry();
3503 }
3504
3505 ESIEventLoop(YES, "Before bisection; Press Ctrl-p to continue");
3506 #endif
3507#endif
3508
3509 // bisect mesh
3510 this->bisectMesh();
3511 // smooth mesh
3512 if ( smoothingFlag ) {
3513 // smooth only if there are new irregulars;
3514 // this is reasonable only if the smoothing is done locally !!!
3515 if ( nnodes != mesh->giveNumberOfNodes() ) {
3516 this->smoothMesh();
3517 }
3518 }
3519
3520#ifdef __OOFEG
3521 #ifdef DRAW_MESH_AFTER_BISECTION
3522 nelems = mesh->giveNumberOfElements();
3523 for ( int i = 1; i <= nelems; i++ ) {
3524 if ( !mesh->giveElement(i)->isTerminal() ) {
3525 continue;
3526 }
3527
3528 #ifdef __MPI_PARALLEL_MODE
3529 if ( this->mesh->giveElement(i)->giveParallelMode() != Element_local ) {
3530 continue;
3531 }
3532
3533 #endif
3534 mesh->giveElement(i)->drawGeometry();
3535 }
3536
3537 ESIEventLoop(YES, (char*) "After bisection; Press Ctrl-p to continue");
3538 #endif
3539#endif
3540
3541 Dof *dof;
3542 DofManager *parentNodePtr;
3543 std :: string name;
3544
3545 // create new mesh (missing param for new mesh!)
3546 nnodes = mesh->giveNumberOfNodes();
3547 ( * dNew ) = new Domain( 2, domain->giveSerialNumber() + 1, domain->giveEngngModel() );
3548 ( * dNew )->setDomainType( domain->giveDomainType() );
3549
3550 // copy dof managers
3551 ( * dNew )->resizeDofManagers(nnodes);
3552 const IntArray dofIDArrayPtr = domain->giveDefaultNodeDofIDArry();
3553 for ( int inode = 1; inode <= nnodes; inode++ ) {
3554 std::unique_ptr<DofManager> newNode;
3555 parent = mesh->giveNode(inode)->giveParent();
3556 if ( parent ) {
3557 parentNodePtr = domain->giveNode(parent);
3558 // inherit all data from parent (bc, ic, load, etc.)
3559 newNode = classFactory.createDofManager(parentNodePtr->giveInputRecordName(), inode, * dNew);
3560 auto node = newNode.get();
3561 node->setNumberOfDofs(0);
3562 node->setLoadArray( * parentNodePtr->giveLoadArray() );
3563 // create individual DOFs
3564 for ( Dof *idofPtr: *parentNodePtr ) {
3565 if ( idofPtr->isPrimaryDof() ) {
3566 dof = new MasterDof( node, idofPtr->giveBcId(), idofPtr->giveIcId(), idofPtr->giveDofID() );
3567 } else {
3568 SimpleSlaveDof *simpleSlaveDofPtr = dynamic_cast< SimpleSlaveDof * >(idofPtr);
3569 if ( simpleSlaveDofPtr ) {
3570 dof = new SimpleSlaveDof( node, simpleSlaveDofPtr->giveMasterDofManagerNum(), idofPtr->giveDofID() );
3571 } else {
3572 OOFEM_ERROR("unsupported DOF type");
3573 }
3574 }
3575 node->appendDof(dof);
3576 }
3577
3578 node->setGlobalNumber( parentNodePtr->giveGlobalNumber() );
3579#ifdef __MPI_PARALLEL_MODE
3580 node->setParallelMode( parentNodePtr->giveParallelMode() );
3581 node->setPartitionList( parentNodePtr->givePartitionList() );
3582#endif
3583 } else {
3584 // newly created node (irregular)
3585 newNode = std::make_unique<Node>(inode, *dNew);
3586 auto node = newNode.get();
3587 //create new node with default DOFs
3588 int ndofs = dofIDArrayPtr.giveSize();
3589 node->setNumberOfDofs(0);
3590
3591 // create individual DOFs
3592 for ( int idof = 1; idof <= ndofs; idof++ ) {
3593#ifdef NM
3594 dof = nullptr;
3595 FloatArray *coords = mesh->giveNode(inode)->giveCoordinates();
3596 if ( !dof ) {
3597 if ( fabs(coords->at(1) - 200.0) < 0.000001 ) {
3598 if ( coords->at(2) > -0.000001 && coords->at(2) < 97.500001 ) {
3599 dof = new MasterDof( node, 1, 0, dofIDArrayPtr.at ( idof ) );
3600 }
3601 }
3602 }
3603
3604 if ( !dof ) {
3605 if ( fabs( coords->at(2) ) < 0.000001 ) {
3606 dof = new MasterDof( node, 1, 0, dofIDArrayPtr.at ( idof ) );
3607 }
3608 }
3609
3610 if ( !dof ) {
3611 if ( fabs( coords->at(1) ) < 0.000001 ) {
3612 if ( coords->at(2) > 102.4999999 && coords->at(2) < 199.9999999 ) {
3613 dof = new SimpleSlaveDof( node, 5, ( DofID ) dofIDArrayPtr.at ( idof ) ); // HUHU
3614 }
3615 }
3616 }
3617
3618 if ( !dof ) {
3619 if ( fabs(coords->at(2) - 200.0) < 0.000001 ) {
3620 if ( coords->at(1) > 0.000001 && coords->at(1) < 200.000001 ) {
3621 dof = new SimpleSlaveDof( node, 6, ( DofID ) dofIDArrayPtr.at ( idof ) ); // HUHU
3622 }
3623 }
3624 }
3625
3626 if ( !dof ) {
3627 dof = new MasterDof( node, 0, 0, dofIDArrayPtr.at ( idof ) );
3628 }
3629
3630#else
3631 #ifdef BRAZIL_2D
3632 dof = nullptr;
3633 FloatArray *coords = mesh->giveNode(inode)->giveCoordinates();
3634 if ( !dof ) {
3635 if ( fabs( coords->at(1) ) < 0.000001 ) {
3636 if ( coords->at(2) > 0.000001 ) {
3637 if ( idof == 1 ) {
3638 dof = new MasterDof( node, 1, 0, dofIDArrayPtr.at ( idof ) );
3639 }
3640 }
3641 }
3642 }
3643
3644 if ( !dof ) {
3645 if ( fabs( coords->at(2) ) < 0.000001 ) {
3646 if ( coords->at(1) > 0.000001 ) {
3647 if ( idof == 2 ) {
3648 dof = new MasterDof( node, 1, 0, dofIDArrayPtr.at ( idof ) );
3649 }
3650 }
3651 }
3652 }
3653
3654 if ( !dof ) {
3655 dof = new MasterDof( node, 0, 0, dofIDArrayPtr.at ( idof ) );
3656 }
3657
3658 #else
3659 #ifdef THREEPBT_3D
3660 dof = nullptr;
3661 FloatArray *coords = mesh->giveNode(inode)->giveCoordinates();
3662 if ( !dof ) {
3663 if ( fabs( coords->at(1) ) < 0.000001 ) {
3664 if ( coords->at(2) > 0.000001 ) {
3665 if ( coords->at(3) > 499.999999 ) {
3666 if ( idof == 1 || idof == 3 ) {
3667 dof = new MasterDof( node, 1, 0, dofIDArrayPtr.at ( idof ) );
3668 }
3669 }
3670 }
3671 }
3672 }
3673
3674 if ( !dof ) {
3675 if ( coords->at(1) > 1999.999999 ) {
3676 if ( coords->at(2) > 0.000001 ) {
3677 if ( coords->at(3) > 499.999999 ) {
3678 if ( idof == 3 ) {
3679 dof = new MasterDof( node, 1, 0, dofIDArrayPtr.at ( idof ) );
3680 }
3681 }
3682 }
3683 }
3684 }
3685
3686 if ( !dof ) {
3687 dof = new MasterDof( node, 0, 0, dofIDArrayPtr.at ( idof ) );
3688 }
3689
3690 #else
3691 #ifdef HEADEDSTUD
3692 double dist, rad;
3693 FloatArray *coords = mesh->giveNode(inode)->giveCoordinates();
3694
3695 dof = nullptr;
3696 if ( !dof ) {
3697 dist = coords->at(1) * coords->at(1) + coords->at(3) * coords->at(3);
3698 if ( coords->at(2) < 88.000001 ) {
3699 if ( coords->at(2) > 70.000001 ) {
3700 if ( fabs(dist - 7.0 * 7.0) < 0.01 ) { // be very tolerant (geometry is not precise)
3701 if ( idof == 1 || idof == 3 ) {
3702 dof = new MasterDof( node, 1, 0, ( DofIDItem ) dofIDArrayPtr.at ( idof ) );
3703 }
3704 }
3705 } else if ( coords->at(2) > 67.9999999 ) {
3706 rad = 18.0 - 11.0 / 5.5 * ( coords->at(2) - 64.5 );
3707 if ( fabs(dist - rad * rad) < 0.01 ) { // be very tolerant (geometry is not precise)
3708 if ( idof == 1 || idof == 3 ) {
3709 dof = new MasterDof( node, 1, 0, ( DofIDItem ) dofIDArrayPtr.at ( idof ) );
3710 }
3711
3712 if ( idof == 2 ) {
3713 dof = new MasterDof( node, 2, 0, ( DofIDItem ) dofIDArrayPtr.at ( idof ) );
3714 OOFEM_LOG_INFO("Subdivision: Conrolled Node %d", inode);
3715 }
3716 }
3717 }
3718 }
3719 }
3720
3721 if ( !dof ) {
3722 if ( coords->at(1) > 299.999999 || coords->at(3) > 299.999999 ) {
3723 dof = new MasterDof( node, 1, 0, ( DofIDItem ) dofIDArrayPtr.at ( idof ) );
3724 }
3725 }
3726
3727 if ( !dof ) {
3728 if ( coords->at(1) < 0.00000001 ) {
3729 if ( idof == 1 ) {
3730 dof = new MasterDof( node, 1, 0, ( DofIDItem ) dofIDArrayPtr.at ( idof ) );
3731 }
3732 }
3733 }
3734
3735 if ( !dof ) {
3736 dof = new MasterDof( node, 0, 0, ( DofIDItem ) dofIDArrayPtr.at ( idof ) );
3737 }
3738
3739 #else
3740 dof = new MasterDof( node, 0, 0, dofIDArrayPtr.at ( idof ) );
3741 #endif
3742 #endif
3743 #endif
3744#endif
3745 node->appendDof(dof);
3746 }
3747
3748 node->setGlobalNumber( mesh->giveNode(inode)->giveGlobalNumber() );
3749#ifdef __MPI_PARALLEL_MODE
3750 node->setParallelMode( mesh->giveNode(inode)->giveParallelMode() );
3751 node->setPartitionList( mesh->giveNode(inode)->givePartitions() );
3752#endif
3753 }
3754
3755 // set node coordinates
3756 static_cast< Node * >(newNode.get())->setCoordinates( * mesh->giveNode(inode)->giveCoordinates() );
3757 newNode->setBoundaryFlag( mesh->giveNode(inode)->isBoundary() );
3758 ( * dNew )->setDofManager(inode, std::move(newNode));
3759 } // end creating dof managers
3760
3761 // create elements
3762 // count number of local terminal elements first
3763 int nterminals = 0;
3764 nelems = mesh->giveNumberOfElements();
3765 for ( int ielem = 1; ielem <= nelems; ielem++ ) {
3766#ifdef __MPI_PARALLEL_MODE
3767 if ( mesh->giveElement(ielem)->giveParallelMode() != Element_local ) {
3768 continue;
3769 }
3770
3771#endif
3772 if ( mesh->giveElement(ielem)->isTerminal() ) {
3773 nterminals++;
3774 }
3775 }
3776
3777#ifdef __MPI_PARALLEL_MODE
3778 IntArray parentElemMap(nterminals);
3779#endif
3780 ( * dNew )->resizeElements(nterminals);
3781 int eNum = 0;
3782 for ( int ielem = 1; ielem <= nelems; ielem++ ) {
3783#ifdef __MPI_PARALLEL_MODE
3784 if ( mesh->giveElement(ielem)->giveParallelMode() != Element_local ) {
3785 continue;
3786 }
3787
3788#endif
3789 if ( !mesh->giveElement(ielem)->isTerminal() ) {
3790 continue;
3791 }
3792
3793 eNum++;
3794 parent = mesh->giveElement(ielem)->giveTopParent();
3795#ifdef __MPI_PARALLEL_MODE
3796 parentElemMap.at(eNum) = parent;
3797#endif
3798 if ( parent ) {
3799 // Copy most of the existing parent element:
3800 DynamicInputRecord ir( *domain->giveElement ( parent ) );
3801 ir.setField(* mesh->giveElement(ielem)->giveNodes(), Element::IPK_Element_nodes.getNameCStr());
3802 ir.giveRecordKeywordField(name);
3803 auto elem = classFactory.createElement(name.c_str(), eNum, * dNew);
3804 elem->initializeFrom(ir,1);
3805 elem->setGlobalNumber( mesh->giveElement(ielem)->giveGlobalNumber() );
3806#ifdef __MPI_PARALLEL_MODE
3807 //ir.setRecordKeywordNumber( mesh->giveElement(ielem)->giveGlobalNumber() );
3808 // not subdivided elements inherit globNum, subdivided give -1
3809 // local elements have array partitions empty !
3810#endif
3811 ( * dNew )->setElement(eNum, std::move(elem));
3812 } else {
3813 OOFEM_ERROR("parent element missing");
3814 }
3815 } // end loop over elements
3816
3817 // create the rest of the model description (BCs, CrossSections, Materials, etc)
3818 // cross sections
3819 int ncrosssect = domain->giveNumberOfCrossSectionModels();
3820 ( * dNew )->resizeCrossSectionModels(ncrosssect);
3821 for ( int i = 1; i <= ncrosssect; i++ ) {
3822 DynamicInputRecord ir( *domain->giveCrossSection ( i ) );
3823 ir.giveRecordKeywordField(name);
3824
3825 auto crossSection = classFactory.createCrossSection(name.c_str(), i, * dNew);
3826 crossSection->initializeFrom(ir);
3827 ( * dNew )->setCrossSection(i, std::move(crossSection));
3828 }
3829
3830 // materials
3831 int nmat = domain->giveNumberOfMaterialModels();
3832 ( * dNew )->resizeMaterials(nmat);
3833 for ( int i = 1; i <= nmat; i++ ) {
3834 DynamicInputRecord ir( *domain->giveMaterial ( i ) );
3835 ir.giveRecordKeywordField(name);
3836
3837 auto mat = classFactory.createMaterial(name.c_str(), i, * dNew);
3838 mat->initializeFrom(ir);
3839 ( * dNew )->setMaterial(i, std::move(mat));
3840 }
3841
3842 // barriers
3843 int nbarriers = domain->giveNumberOfNonlocalBarriers();
3844 ( * dNew )->resizeNonlocalBarriers(nbarriers);
3845 for ( int i = 1; i <= nbarriers; i++ ) {
3846 DynamicInputRecord ir( *domain->giveNonlocalBarrier ( i ) );
3847 ir.giveRecordKeywordField(name);
3848
3849 auto barrier = classFactory.createNonlocalBarrier(name.c_str(), i, * dNew);
3850 barrier->initializeFrom(ir);
3851 ( * dNew )->setNonlocalBarrier(i, std::move(barrier));
3852 }
3853
3854 // boundary conditions
3855 int nbc = domain->giveNumberOfBoundaryConditions();
3856 ( * dNew )->resizeBoundaryConditions(nbc);
3857 for ( int i = 1; i <= nbc; i++ ) {
3858 DynamicInputRecord ir( *domain->giveBc ( i ) );
3859 ir.giveRecordKeywordField(name);
3860
3861 auto bc = classFactory.createBoundaryCondition(name.c_str(), i, * dNew);
3862 bc->initializeFrom(ir);
3863 ( * dNew )->setBoundaryCondition(i, std::move(bc));
3864 }
3865
3866 // initial conditions
3867 int nic = domain->giveNumberOfInitialConditions();
3868 ( * dNew )->resizeInitialConditions(nic);
3869 for ( int i = 1; i <= nic; i++ ) {
3870 DynamicInputRecord ir( *domain->giveIc ( i ) );
3871
3872 auto ic = std::make_unique<InitialCondition>(i, *dNew);
3873 ic->initializeFrom(ir);
3874 ( * dNew )->setInitialCondition(i, std::move(ic));
3875 }
3876
3877 // load time functions
3878 int nfunc = domain->giveNumberOfFunctions();
3879 ( * dNew )->resizeFunctions(nfunc);
3880 for ( int i = 1; i <= nfunc; i++ ) {
3881 DynamicInputRecord ir( *domain->giveFunction ( i ) );
3882 ir.giveRecordKeywordField(name);
3883
3884 auto func = classFactory.createFunction(name.c_str(), i, * dNew);
3885 func->initializeFrom(ir);
3886 ( * dNew )->setFunction(i, std::move(func));
3887 }
3888
3889 // sets
3890 int nset = domain->giveNumberOfSets();
3891 ( * dNew )->resizeSets(nset);
3892 for ( int i = 1; i <= nset; i++ ) {
3893 DynamicInputRecord ir( *domain->giveSet ( i ) );
3894 ir.giveRecordKeywordField(name);
3895
3896 auto set = std::make_unique<Set>(i, * dNew);
3897 set->initializeFrom(ir);
3898 ( * dNew )->setSet(i, std::move(set));
3899 }
3900
3901 // post initialize components
3902 ( * dNew )->postInitialize();
3903
3904 // copy output manager settings
3905 ( * dNew )->giveOutputManager()->beCopyOf( domain->giveOutputManager() );
3906
3907 timer.stopTimer();
3908#ifdef __MPI_PARALLEL_MODE
3909 OOFEM_LOG_INFO( "[%d] Subdivision: created new mesh (%d nodes and %d elements) in %.2fs\n",
3910 ( * dNew )->giveEngngModel()->giveRank(), nnodes, eNum, timer.getUtime() );
3911#else
3912 OOFEM_LOG_INFO( "Subdivision: created new mesh (%d nodes and %d elements) in %.2fs\n",
3913 nnodes, eNum, timer.getUtime() );
3914#endif
3915
3916
3917
3918
3919#ifdef __MPI_PARALLEL_MODE
3920 #ifdef __VERBOSE_PARALLEL
3921 nnodes = ( * dNew )->giveNumberOfDofManagers();
3922 for ( int inode = 1; inode <= nnodes; inode++ ) {
3923 if ( ( * dNew )->giveDofManager(inode)->giveParallelMode() == DofManager_shared ) {
3924 //OOFEM_LOG_INFO ("[%d] Shared Node %d[%d]\n", this->giveRank(), inode, (*dNew)->giveDofManager(inode)->giveGlobalNumber());
3925 }
3926 }
3927
3928 #endif
3929
3930 // we need to assign global numbers to newly generated elements
3931 this->assignGlobalNumbersToElements(* dNew);
3932
3933 bool nonloc = false;
3934 nmat = ( * dNew )->giveNumberOfMaterialModels();
3935 for ( int im = 1; im <= nmat; im++ ) {
3936 if ( ( * dNew )->giveMaterial(im)->giveInterface(NonlocalMaterialExtensionInterfaceType) ) {
3937 nonloc = true;
3938 }
3939 }
3940
3941 if ( nonloc ) {
3942 exchangeRemoteElements(* dNew, parentElemMap);
3943 }
3944
3945 ( * dNew )->commitTransactions( ( * dNew )->giveTransactionManager() );
3946
3947 // print some statistics
3948 if (0) {
3949 for (int in=1; in<=(*dNew)->giveNumberOfDofManagers(); in++) {
3951 (*dNew)->giveDofManager(in)->giveInputRecord(ir);
3952 OOFEM_LOG_INFO("[%d]:[%d]:%s\n", this->giveRank(), (*dNew)->giveDofManager(in)->giveGlobalNumber(), ir.giveRecordAsString().c_str());
3953 }
3954 IntArray nodes;
3955 for (int in=1; in<=(*dNew)->giveNumberOfElements(); in++) {
3957 (*dNew)->giveElement(in)->giveInputRecord(ir);
3958 nodes = (*dNew)->giveElement(in)->giveDofManArray();
3959 // translate local node numbers to globnums
3960 for (int ii=1; ii<=nodes.giveSize(); ii++)
3961 nodes.at(ii) = (*dNew)->giveNode(nodes.at(ii))->giveGlobalNumber();
3962 ir.setField(nodes, "gnodes");
3963 OOFEM_LOG_INFO("[%d]:[%d]:%s\n", this->giveRank(), (*dNew)->giveElement(in)->giveGlobalNumber(), ir.giveRecordAsString().c_str());
3964 }
3965 }
3966 nelems = ( * dNew )->giveNumberOfElements();
3967 int localVals [ 2 ], globalVals [ 2 ];
3968 localVals [ 0 ] = 0;
3969 for ( int ielem = 1; ielem <= nelems; ielem++ ) {
3970 if ( ( * dNew )->giveElement(ielem)->giveParallelMode() == Element_local ) {
3971 localVals [ 0 ]++;
3972 }
3973 }
3974
3975 nnodes = ( * dNew )->giveNumberOfDofManagers();
3976 localVals [ 1 ] = 0;
3977 for ( int inode = 1; inode <= nnodes; inode++ ) {
3978 if ( ( * dNew )->giveDofManager(inode)->isLocal() ) {
3979 localVals [ 1 ]++;
3980 }
3981 }
3982
3983 MPI_Reduce(localVals, globalVals, 2, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
3984 if ( this->giveRank() == 0 ) {
3985 OOFEM_LOG_INFO("Subdivision: new mesh info: %d nodes, %d elements in total\n", globalVals [ 1 ], globalVals [ 0 ]);
3986 }
3987#else
3988 // we need to assign global numbers to newly generated elements
3989 this->assignGlobalNumbersToElements(* dNew);
3990#endif
3991
3992 return MI_OK;
3993}
3994
3995
3996void
3997Subdivision :: bisectMesh()
3998{
3999 [[maybe_unused]] int ie, nelems = mesh->giveNumberOfElements(), nelems_old = 0, terminal_local_elems = nelems;
4000 int nnodes = mesh->giveNumberOfNodes(), nnodes_old;
4001 double iedensity, rdensity;
4002 int repeat = 1, loop = 0, max_loop = 0; // max_loop != 0 use only for debugging
4003 RS_Element *elem;
4004 RS_Node *node;
4005 //std::queue<int> subdivqueue;
4006#ifdef __MPI_PARALLEL_MODE
4007 int remote_elems = 0;
4008 int myrank = this->giveRank();
4009 int problem_size = this->giveNumberOfProcesses();
4010 int value;
4011 int *partitionsIrregulars = new int[ problem_size ];
4012#endif
4013
4014 // get the max globnum on the mesh
4015 // determine max global number of local nodes
4016 int maxlocalglobal = 0, maxglobalnumber;
4017 for ( int in = 1; in <= nnodes; in++ ) {
4018 maxlocalglobal = max( maxlocalglobal, mesh->giveNode(in)->giveGlobalNumber() );
4019 }
4020#ifdef __MPI_PARALLEL_MODE
4021 // determine max global number on all partitions
4022 MPI_Allreduce(& maxlocalglobal, & maxglobalnumber, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
4023#else
4024 maxglobalnumber=maxlocalglobal;
4025#endif
4026
4027
4028 // repeat bisection until no new element is created
4029 while ( repeat && ( loop < max_loop || max_loop == 0 ) ) {
4030
4031
4032 nnodes_old = nnodes;
4033#ifdef __MPI_PARALLEL_MODE
4034 OOFEM_LOG_INFO("[%d] Subdivision::bisectMesh: entering bisection loop %d\n", myrank, ++loop);
4035#else
4036 OOFEM_LOG_INFO("Subdivision::bisectMesh: entering bisection loop %d\n", ++loop);
4037#endif
4038 repeat = 0;
4039 // process only newly created elements in pass 2 and more
4040 for ( ie = nelems_old + 1; ie <= nelems; ie++ ) {
4041 elem = mesh->giveElement(ie);
4042#ifdef __MPI_PARALLEL_MODE
4043 // skip bisection of remote elements (in first pass only (nelems_old = 0));
4044 // in pass 2 and more there should be no remote elements because
4045 // only newly created elements are processed
4046 if ( nelems_old == 0 ) {
4047 if ( elem->giveParallelMode() == Element_remote ) {
4048 remote_elems++;
4049 terminal_local_elems--;
4050 continue;
4051 }
4052 }
4053
4054#endif
4055 if ( !elem->isTerminal() ) {
4056 continue;
4057 }
4058
4059#ifdef __MPI_PARALLEL_MODE
4060 // bisect local elements only
4061 if ( elem->giveParallelMode() != Element_local ) {
4062 continue;
4063 }
4064
4065#endif
4066
4067#ifdef DEBUG_CHECK
4068 if ( elem->giveQueueFlag() ) {
4069 OOFEM_ERROR("unexpected queue flag of %d ", ie);
4070 }
4071
4072#endif
4073
4074 iedensity = elem->giveDensity();
4075 rdensity = elem->giveRequiredDensity();
4076
4077 // first select all candidates for local bisection based on required mesh density
4078
4079 if ( rdensity < iedensity ) {
4080 subdivqueue.push(ie);
4081 elem->setQueueFlag(true);
4082
4083
4084
4085#ifndef __MPI_PARALLEL_MODE
4086 repeat = 1; // force repetition in seqeuntial run
4087#endif
4088 /*
4089 * #ifdef __MPI_PARALLEL_MODE
4090 * OOFEM_LOG_INFO("[%d] Subdivision: scheduling element %d[%d] for bisection, dens=%lf rdens=%lf\n", myrank, ie, elem->giveGlobalNumber(), iedensity, rdensity);
4091 ******#else
4092 * OOFEM_LOG_INFO("Subdivision: scheduling element %d for bisection, dens=%lf rdens=%lf\n", ie, iedensity, rdensity);
4093 ******#endif
4094 */
4095 }
4096 }
4097
4098#ifdef DEBUG_INFO
4099 #ifdef __MPI_PARALLEL_MODE
4100 OOFEM_LOG_INFO("[%d] (with %d nodes and %d elems)\n", myrank, nnodes_old, terminal_local_elems + remote_elems);
4101 #else
4102 OOFEM_LOG_INFO("(with %d nodes and %d elems)\n", nnodes_old, terminal_local_elems);
4103 #endif
4104#endif
4105
4106#ifdef __MPI_PARALLEL_MODE
4107 for ( value = 0; value == 0; value = exchangeSharedIrregulars() ) {
4108#endif
4109 // loop over subdivision queue to bisect all local elements there
4110 while ( !subdivqueue.empty() ) {
4111 elem = mesh->giveElement( subdivqueue.front() );
4112#ifdef DEBUG_CHECK
4113 #ifdef __MPI_PARALLEL_MODE
4114 if ( elem->giveParallelMode() != Element_local ) {
4115 OOFEM_ERROR( "nonlocal element %d not expected for bisection", elem->giveNumber() );
4116 }
4117
4118 #endif
4119#endif
4120 elem->evaluateLongestEdge();
4122 subdivqueue.pop();
4123 }
4124
4125#ifdef __MPI_PARALLEL_MODE
4126 // in parallel communicate with neighbours the irregular nodes on shared bondary
4127 }
4128
4129#endif
4130
4131 int in;
4132 nnodes = mesh->giveNumberOfNodes();
4133
4134#ifndef __MPI_PARALLEL_MODE
4135 int myrank = 0;
4136#endif
4137 // assign global numbers to newly introduced irregulars while
4138 // keeping global numbering of existing (master) nodes
4139 // idea: first determine the max globnum already assigned
4140 // and start global numbering of new nodes from this value up
4141
4142 // determine number of local irregulars
4143 // this is needed to determine offsets on each partition to start global numbering
4144 // the numbering of irregulars starts on rank 0 partition by numbering subseqeuntly all its irregulars
4145 // then we proceed with rank 1, etc.
4146 // the shared irregulars receive their number from partition with the lowest rank.
4147
4148 // count local irregulars that receive their global number from this partition
4149 int localIrregulars = 0;
4150 for ( in = nnodes_old+1; in <= nnodes; in++ ) {
4151 if ( this->isNodeLocalIrregular(mesh->giveNode(in), myrank) && ( mesh->giveNode(in)->giveGlobalNumber() == 0 ) ) {
4152 localIrregulars++;
4153 }
4154 }
4155
4156#ifdef __MPI_PARALLEL_MODE
4157 #ifdef __VERBOSE_PARALLEL
4158 OOFEM_LOG_INFO("[%d] Subdivision::bisectMesh: number of new local irregulars is %d\n", myrank, localIrregulars);
4159 #endif
4160 int localOffset = 0;
4161 int irank, gnum, globalIrregulars = 0;
4162 // gather number of local irregulars from all partitions
4163 MPI_Allgather(& localIrregulars, 1, MPI_INT, partitionsIrregulars, 1, MPI_INT, MPI_COMM_WORLD);
4164 // compute local offset
4165 for ( irank = 0; irank < myrank; irank++ ) {
4166 localOffset += partitionsIrregulars [ irank ];
4167 }
4168 // start to assign global numbers to local irregulars
4169 int availGlobNum = maxglobalnumber + localOffset;
4170 for ( in = nnodes_old+1; in <= nnodes; in++ ) {
4171 node = mesh->giveNode(in);
4172 if ( this->isNodeLocalIrregular(node, myrank) && ( node->giveGlobalNumber() == 0 ) ) {
4173 // set negative globnum to mark newly assigned nodes with globnum to participate in shared globnum data exchange
4174 node->setGlobalNumber( -( ++availGlobNum ) );
4175 #ifdef __VERBOSE_PARALLEL
4176 //OOFEM_LOG_INFO ("[%d] %d --> [%d]\n", myrank, in, availGlobNum);
4177 #endif
4178 }
4179 }
4180#else
4181 int localOffset=0;
4182 // start to assign global numbers to local irregulars
4183 int availGlobNum = maxglobalnumber+localOffset;
4184 for ( in = nnodes_old+1; in <= nnodes; in++ ) {
4185 node = mesh->giveNode(in);
4186 node->setGlobalNumber( ( ++availGlobNum ) );
4187 }
4188
4189#endif
4190
4191#ifdef __MPI_PARALLEL_MODE
4192 // finally, communicate global numbers assigned to shared irregulars
4194 for ( in = nnodes_old+1; in <= nnodes; in++ ) {
4195 node = mesh->giveNode(in);
4196 gnum = node->giveGlobalNumber();
4197 if ( gnum < 0 ) {
4198 // turn all globnums to positive
4199 node->setGlobalNumber(-gnum);
4200 // update global shared node map (for refined level)
4201 // this must be done after globnum is made positive
4202 this->mesh->insertGlobalSharedNodeMap(node);
4203 } else if ( gnum == 0 ) {
4204 OOFEM_ERROR("rank [%d] zero globnum identified on node %d", myrank, in);
4205 }
4206 }
4207
4208 // update max globnum
4209 for ( irank = 0; irank < problem_size; irank++ ) {
4210 globalIrregulars += partitionsIrregulars [ irank ];
4211 }
4212
4213 if ( globalIrregulars ) {
4214 maxglobalnumber += globalIrregulars;
4215 // exchange shared edges
4216 // this must be done after globnums are assigned to new shared irregulars
4217 /* BP
4218 this->exchangeSharedEdges();
4219 repeat = 1; // force repetition in parallel run
4220 */
4221 }
4222
4223#else
4224 maxglobalnumber+=localIrregulars;
4225#endif
4226
4227 // symbolic bisection is finished;
4228 // now we need to create new mesh;
4229 // also there is a need to update element connectivities
4230 for ( ie = 1; ie <= nelems; ie++ ) {
4231 elem = mesh->giveElement(ie);
4232 if ( !elem->isTerminal() ) {
4233 continue;
4234 }
4235
4236#ifdef __MPI_PARALLEL_MODE
4237 if ( elem->giveParallelMode() != Element_local ) {
4238 continue;
4239 }
4240
4241#endif
4243 }
4244
4245#ifdef __MPI_PARALLEL_MODE
4246 if ( globalIrregulars ) {
4247 // exchange shared edges
4248 // this must be done after globnums are assigned to new shared irregulars
4249 this->exchangeSharedEdges();
4250 repeat = 1; // force repetition in parallel run
4251 }
4252#endif
4253 // unmark local unshared irregulars marked for connectivity setup
4254 // important this may be not done before generate !!!
4255 for ( in = nnodes_old+1; in <= nnodes; in++ ) {
4256 if ( mesh->giveNode(in)->giveNumber() < 0 ) {
4257 mesh->giveNode(in)->setNumber( -mesh->giveNode(in)->giveNumber() );
4258 }
4259 }
4260
4261 nelems_old = nelems;
4262 nelems = mesh->giveNumberOfElements();
4263 terminal_local_elems = 0;
4264 for ( ie = 1; ie <= nelems; ie++ ) {
4265 elem = mesh->giveElement(ie);
4266 if ( !elem->isTerminal() ) {
4267 continue;
4268 }
4269
4270#ifdef __MPI_PARALLEL_MODE
4271 if ( elem->giveParallelMode() != Element_local ) {
4272 continue;
4273 }
4274
4275#endif
4276 elem->update_neighbours();
4277 terminal_local_elems++;
4278 }
4279
4280#if 0
4281 #ifdef __MPI_PARALLEL_MODE
4282 int global_repeat = 0;
4283
4284 // determine whether any partition needs additional bisection pass
4285 MPI_Allreduce(& repeat, & global_repeat, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD);
4286 repeat = global_repeat;
4287 #endif
4288#endif
4289
4290#ifdef __OOFEG
4291 #ifdef DRAW_MESH_AFTER_EACH_BISECTION_LEVEL
4292 for ( ie = 1; ie <= nelems; ie++ ) {
4293 if ( !mesh->giveElement(ie)->isTerminal() ) {
4294 continue;
4295 }
4296
4297 mesh->giveElement(ie)->drawGeometry();
4298 }
4299
4300 ESIEventLoop( YES, const_cast< char * >("Subdivision Bisection; Press Ctrl-p to continue") );
4301 #endif
4302#endif
4303 } // end bisection loop
4304#ifdef __MPI_PARALLEL_MODE
4305 if (partitionsIrregulars) {
4306 delete[] partitionsIrregulars;
4307 }
4308#endif
4309}
4310
4311
4312void
4313Subdivision :: smoothMesh()
4314{
4315 int nnodes, nelems, i, j, in, ie;
4316 int pos, number, reg, nd, cycles = 6;
4317 IntArray snodes;
4318 FloatArray *coords;
4319 RS_Element *elem;
4320 //bool fixed;
4321 IntArray node_num_elems, node_con_elems;
4322 IntArray node_num_nodes, node_con_nodes;
4323
4324#ifdef DEBUG_SMOOTHING
4325 char buffer [ 1024 ];
4326 int len;
4327#endif
4328#ifdef __MPI_PARALLEL_MODE
4329 OOFEM_LOG_INFO( "[%d] Subdivision::smoothMesh\n", this->giveRank() );
4330#else
4331 OOFEM_LOG_INFO("Subdivision::smoothMesh\n");
4332#endif
4333 nnodes = mesh->giveNumberOfNodes();
4334 nelems = mesh->giveNumberOfElements();
4335
4336 // count number of elements incident to nodes
4337 node_num_elems.resize(nnodes + 1);
4338 node_num_elems.zero();
4339
4340 for ( ie = 1; ie <= nelems; ie++ ) {
4341 elem = mesh->giveElement(ie);
4342 if ( !elem->isTerminal() ) {
4343 continue;
4344 }
4345
4346#ifdef __MPI_PARALLEL_MODE
4347 if ( elem->giveParallelMode() != Element_local ) {
4348 continue;
4349 }
4350
4351#endif
4352
4353 for ( i = 1; i <= elem->giveNodes()->giveSize(); i++ ) {
4354 node_num_elems.at( elem->giveNode(i) )++;
4355 }
4356 }
4357
4358 // recalculate the number of elements to current addresses
4359 pos = 1;
4360 for ( in = 1; in <= nnodes; in++ ) {
4361 number = node_num_elems.at(in);
4362 node_num_elems.at(in) = pos;
4363 pos += number;
4364 }
4365
4366 node_num_elems.at(nnodes + 1) = pos;
4367 node_con_elems.resize(pos);
4368
4369 // store element numbers incident to nodes
4370 for ( ie = 1; ie <= nelems; ie++ ) {
4371 elem = mesh->giveElement(ie);
4372 if ( !elem->isTerminal() ) {
4373 continue;
4374 }
4375
4376#ifdef __MPI_PARALLEL_MODE
4377 if ( elem->giveParallelMode() != Element_local ) {
4378 continue;
4379 }
4380
4381#endif
4382
4383 for ( i = 1; i <= elem->giveNodes()->giveSize(); i++ ) {
4384 node_con_elems.at(node_num_elems.at( elem->giveNode(i) )++) = ie;
4385 }
4386 }
4387
4388 // recalculate the addresses to address of the first element
4389 pos = 1;
4390 for ( in = 1; in <= nnodes; in++ ) {
4391 number = node_num_elems.at(in) - pos;
4392 node_num_elems.at(in) = pos;
4393 pos += number;
4394 }
4395
4396#ifdef DEBUG_SMOOTHING
4397 #ifdef __MPI_PARALLEL_MODE
4398 OOFEM_LOG_INFO( "[%d] Subdivision::smoothMesh: connectivity node_id: elem_ids\n", this->giveRank() );
4399 #else
4400 OOFEM_LOG_INFO("Subdivision::smoothMesh: connectivity node_id: elem_ids\n");
4401 #endif
4402 for ( in = 1; in <= nnodes; in++ ) {
4403 len = 0;
4404 for ( i = node_num_elems.at(in); i < node_num_elems.at(in + 1); i++ ) {
4405 sprintf( buffer + len, " %d", node_con_elems.at(i) );
4406 len = strlen(buffer);
4407 if ( len >= 1024 ) {
4408 OOFEM_ERROR("too small buffer");
4409 }
4410 }
4411
4412 OOFEM_LOG_INFO("%d:%s\n", in, buffer);
4413 }
4414
4415#endif
4416
4417 // count number of nodes incident to nodes
4418 node_num_nodes.resize(nnodes + 1);
4419 node_num_nodes.zero();
4420
4421 for ( in = 1; in <= nnodes; in++ ) {
4422 for ( i = node_num_elems.at(in); i < node_num_elems.at(in + 1); i++ ) {
4423 elem = mesh->giveElement( node_con_elems.at(i) );
4424 for ( j = 1; j <= elem->giveNodes()->giveSize(); j++ ) {
4425 nd = elem->giveNode(j);
4426 if ( nd != in && mesh->giveNode(nd)->giveNumber() > 0 ) {
4427 mesh->giveNode(nd)->setNumber(-nd); // mark connected node
4428 node_num_nodes.at(in)++;
4429 }
4430 }
4431 }
4432
4433 // unmark connected nodes
4434 for ( i = node_num_elems.at(in); i < node_num_elems.at(in + 1); i++ ) {
4435 elem = mesh->giveElement( node_con_elems.at(i) );
4436 for ( j = 1; j <= elem->giveNodes()->giveSize(); j++ ) {
4437 nd = elem->giveNode(j);
4438 mesh->giveNode(nd)->setNumber(nd);
4439 }
4440 }
4441 }
4442
4443 // recalculate the number of nodes to current addresses
4444 pos = 1;
4445 for ( in = 1; in <= nnodes; in++ ) {
4446 number = node_num_nodes.at(in);
4447 node_num_nodes.at(in) = pos;
4448 pos += number;
4449 }
4450
4451 node_num_nodes.at(nnodes + 1) = pos;
4452 node_con_nodes.resize(pos);
4453
4454 // store nodes incident to nodes
4455 for ( in = 1; in <= nnodes; in++ ) {
4456 for ( i = node_num_elems.at(in); i < node_num_elems.at(in + 1); i++ ) {
4457 elem = mesh->giveElement( node_con_elems.at(i) );
4458 for ( j = 1; j <= elem->giveNodes()->giveSize(); j++ ) {
4459 nd = elem->giveNode(j);
4460 if ( nd != in && mesh->giveNode(nd)->giveNumber() > 0 ) {
4461 mesh->giveNode(nd)->setNumber(-nd); // mark connected node
4462 node_con_nodes.at(node_num_nodes.at(in)++) = nd;
4463 }
4464 }
4465 }
4466
4467 // unmark connected nodes
4468 for ( i = node_num_elems.at(in); i < node_num_elems.at(in + 1); i++ ) {
4469 elem = mesh->giveElement( node_con_elems.at(i) );
4470 for ( j = 1; j <= elem->giveNodes()->giveSize(); j++ ) {
4471 nd = elem->giveNode(j);
4472 mesh->giveNode(nd)->setNumber(nd);
4473 }
4474 }
4475 }
4476
4477 // recalculate the addresses to address of the first node
4478 pos = 1;
4479 for ( in = 1; in <= nnodes; in++ ) {
4480 number = node_num_nodes.at(in) - pos;
4481 node_num_nodes.at(in) = pos;
4482 pos += number;
4483 }
4484
4485#ifdef DEBUG_SMOOTHING
4486 #ifdef __MPI_PARALLEL_MODE
4487 OOFEM_LOG_INFO( "[%d] Subdivision::smoothMesh: connectivity node_id: node_ids\n", this->giveRank() );
4488 #else
4489 OOFEM_LOG_INFO("Subdivision::smoothMesh: connectivity node_id: node_ids\n");
4490 #endif
4491 for ( in = 1; in <= nnodes; in++ ) {
4492 len = 0;
4493 for ( i = node_num_nodes.at(in); i < node_num_nodes.at(in + 1); i++ ) {
4494 sprintf( buffer + len, " %d", node_con_nodes.at(i) );
4495 len = strlen(buffer);
4496 if ( len >= 1024 ) {
4497 OOFEM_ERROR("too small buffer");
4498 }
4499 }
4500
4501 OOFEM_LOG_INFO("%d:%s\n", in, buffer);
4502 }
4503
4504#endif
4505
4506 // identify fixed nodes which should not be subjected to smoothing;
4507 // these are nodes on boundary (geometrical or material);
4508 // note that some of these node may be already marked as boundary if this flag was available on input
4509 // or when processed during bisection or when processed (and assigned) during previous smoothing;
4510 // the last case is applicable only if node's method storeYourself packs the boundary flag;
4511 bool fixed;
4512 for ( in = 1; in <= nnodes; in++ ) {
4513 if ( mesh->giveNode(in)->isBoundary() ) {
4514 continue; // skip boundary node
4515 }
4516
4517 if ( node_num_elems.at(in) == node_num_elems.at(in + 1) ) {
4518 continue; // skip isolated node
4519 }
4520
4521 fixed = false;
4522 elem = mesh->giveElement( node_con_elems.at( node_num_elems.at(in) ) );
4523 // check for geometrical boundary
4524 for ( j = 1; j <= elem->giveNeighbors()->giveSize(); j++ ) {
4525 if ( elem->giveNeighbor(j) == 0 ) {
4526 elem->giveSideNodes(j, snodes);
4527 if ( snodes.findFirstIndexOf(in) != 0 ) {
4528 mesh->giveNode(in)->setNumber(-in); // mark fixed node on geometrical boundary
4529 fixed = true;
4530 break;
4531 }
4532 }
4533 }
4534
4535 if ( !fixed ) {
4536 reg = domain->giveElement( elem->giveTopParent() )->giveRegionNumber();
4537 for ( i = node_num_elems.at(in) + 1; i < node_num_elems.at(in + 1); i++ ) {
4538 elem = mesh->giveElement( node_con_elems.at(i) );
4539 // check for material boundary
4540 if ( domain->giveElement( elem->giveTopParent() )->giveRegionNumber() != reg ) {
4541 mesh->giveNode(in)->setNumber(-in); //mark fixed node on material boundary
4542 fixed = true;
4543 break;
4544 }
4545
4546 // check for geometrical boundary
4547 for ( j = 1; j <= elem->giveNeighbors()->giveSize(); j++ ) {
4548 if ( elem->giveNeighbor(j) == 0 ) {
4549 elem->giveSideNodes(j, snodes);
4550 if ( snodes.findFirstIndexOf(in) != 0 ) {
4551 mesh->giveNode(in)->setNumber(-in); //mark fixed node on geometrical boundary
4552 fixed = true;
4553 break;
4554 }
4555 }
4556 }
4557
4558 if ( fixed ) {
4559 break;
4560 }
4561 }
4562 }
4563 }
4564
4565#ifdef QUICK_HACK
4566 int jn;
4567 IntArray orderedNodes;
4568 Subdivision :: RS_CompareNodePositions cmp(mesh);
4569 orderedNodes.resize(nnodes);
4570 for ( jn = 1; jn <= nnodes; jn++ ) {
4571 orderedNodes.at(jn) = jn;
4572 }
4573
4574 sort(orderedNodes, cmp);
4575#endif
4576
4577 while ( cycles-- ) {
4578#ifdef QUICK_HACK
4579 for ( jn = 1; jn <= nnodes; jn++ ) {
4580 in = orderedNodes.at(jn);
4581#else
4582 for ( in = 1; in <= nnodes; in++ ) {
4583#endif
4584#ifdef __MPI_PARALLEL_MODE
4585 if ( ( mesh->giveNode(in)->giveParallelMode() == DofManager_shared ) ||
4586 ( mesh->giveNode(in)->giveParallelMode() == DofManager_null ) ) {
4587 continue; // skip shared and remote node
4588 }
4589
4590#endif
4591 if ( mesh->giveNode(in)->giveNumber() < 0 ) {
4592 continue; // skip fixed node
4593 }
4594
4595 if ( mesh->giveNode(in)->isBoundary() ) {
4596 continue; // skip boundary node
4597 }
4598
4599 coords = mesh->giveNode(in)->giveCoordinates();
4600
4601#ifdef DEBUG_CHECK
4602 if ( coords ) {
4603 int count = 0;
4604 coords->zero();
4605 for ( i = node_num_nodes.at(in); i < node_num_nodes.at(in + 1); i++ ) {
4606 if ( mesh->giveNode( node_con_nodes.at(i) ) ) {
4607 if ( mesh->giveNode( node_con_nodes.at(i) )->giveCoordinates() ) {
4608 coords->add( *(mesh->giveNode( node_con_nodes.at(i))->giveCoordinates()));
4609 count++;
4610 } else {
4611 OOFEM_ERROR("node %d without coordinates", in);
4612 }
4613 } else {
4614 OOFEM_ERROR("undefined node %d", in);
4615 }
4616 }
4617
4618 if ( !count ) {
4619 OOFEM_ERROR("node %d without connectivity", in);
4620 }
4621
4622 coords->times( 1.0 / ( node_num_nodes.at(in + 1) - node_num_nodes.at(in) ) );
4623 } else {
4624 OOFEM_ERROR("node %d without coordinates", in);
4625 }
4626
4627#else
4628 coords->zero();
4629 for ( i = node_num_nodes.at(in); i < node_num_nodes.at(in + 1); i++ ) {
4630 coords->add( * mesh->giveNode( node_con_nodes.at(i) )->giveCoordinates() );
4631 }
4632
4633 coords->times( 1.0 / ( node_num_nodes.at(in + 1) - node_num_nodes.at(in) ) );
4634#endif
4635 }
4636 }
4637
4638 // unmark fixed nodes and marked them as boundary
4639 for ( in = 1; in <= nnodes; in++ ) {
4640 if ( mesh->giveNode(in)->giveNumber() < 0 ) {
4641 mesh->giveNode(in)->setNumber(in);
4642
4643#ifndef QUICK_HACK
4644 // it is not clear what boundary flag may cause
4645 // therefore it is not set in current version
4646 //mesh->giveNode(in)->setBoundary(true);
4647#endif
4648 }
4649 }
4650}
4651
4652
4653bool
4654Subdivision :: isNodeLocalIrregular(Subdivision :: RS_Node *node, int myrank)
4655{
4656#ifdef __MPI_PARALLEL_MODE
4657 if ( node->isIrregular() ) {
4658 if ( node->giveParallelMode() == DofManager_local ) {
4659 return true;
4660 } else if ( node->giveParallelMode() == DofManager_shared ) {
4661 int i, minpart, npart;
4662 const IntArray *partitions = node->givePartitions();
4663 npart = partitions->giveSize();
4664 minpart = myrank;
4665 for ( i = 1; i <= npart; i++ ) {
4666 minpart = min( minpart, partitions->at(i) );
4667 }
4668
4669 if ( minpart == myrank ) {
4670 return true;
4671 } else {
4672 return false;
4673 }
4674 } else {
4675 return false;
4676 }
4677 } else {
4678 return false;
4679 }
4680#else
4681 return node->isIrregular();
4682#endif
4683}
4684
4685void
4686Subdivision :: assignGlobalNumbersToElements(Domain *d)
4687{
4688
4689#ifdef __MPI_PARALLEL_MODE
4690
4691 int problem_size = this->giveNumberOfProcesses();
4692 int myrank = this->giveRank();
4693 int i, nelems, numberOfLocalElementsToNumber = 0;
4694 int *partitionNumberOfElements = new int[ problem_size ];
4695 int localMaxGlobnum = 0, globalMaxGlobnum;
4696
4697 // idea: first determine the number of local elements waiting for new global id
4698 // and also determine max global number assigned up to now
4699 nelems = d->giveNumberOfElements();
4700 for ( i = 1; i <= nelems; i++ ) {
4701 localMaxGlobnum = max( localMaxGlobnum, d->giveElement(i)->giveGlobalNumber() );
4702 #ifdef DEBUG_CHECK
4703 if ( d->giveElement(i)->giveParallelMode() == Element_remote ) {
4704 OOFEM_ERROR("unexpected remote element %d ", i);
4705 }
4706
4707 #endif
4708 if ( d->giveElement(i)->giveGlobalNumber() <= 0 ) {
4709 numberOfLocalElementsToNumber++;
4710 }
4711 }
4712
4713 // determine number of elements across all partitions
4714 MPI_Allgather(& numberOfLocalElementsToNumber, 1, MPI_INT,
4715 partitionNumberOfElements, 1, MPI_INT, MPI_COMM_WORLD);
4716 MPI_Allreduce(& localMaxGlobnum, & globalMaxGlobnum, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
4717 #ifdef __VERBOSE_PARALLEL
4718 OOFEM_LOG_INFO("[%d] Subdivision::assignGlobalNumbersToElements: max globnum %d, new elements %d\n", myrank, globalMaxGlobnum, numberOfLocalElementsToNumber);
4719 #endif
4720
4721 // compute local offset
4722 int startOffset = globalMaxGlobnum, availGlobNum;
4723 for ( i = 0; i < myrank; i++ ) {
4724 startOffset += partitionNumberOfElements [ i ];
4725 }
4726
4727 // lets assign global numbers on each partition to local elements
4728 availGlobNum = startOffset;
4729 for ( i = 1; i <= nelems; i++ ) {
4730 if ( d->giveElement(i)->giveGlobalNumber() <= 0 ) {
4731 d->giveElement(i)->setGlobalNumber(++availGlobNum);
4732 }
4733 }
4734
4735 #ifdef __VERBOSE_PARALLEL
4736 /*
4737 * for (i=1; i<=nelems; i++) {
4738 * OOFEM_LOG_INFO ("[%d] Element %d[%d]\n", myrank, i,d->giveElement(i)->giveGlobalNumber());
4739 * }
4740 */
4741 #endif
4742
4743 if (partitionNumberOfElements) {
4744 delete[] partitionNumberOfElements;
4745 }
4746
4747#else // local case
4748
4749 [[maybe_unused]] int numberOfLocalElementsToNumber = 0;
4750 int localMaxGlobnum = 0;
4751
4752 // idea: first determine the number of local elements waiting for new global id
4753 // and also determine max global number assigned up to now
4754 for ( auto &elem : d->giveElements() ) {
4755 localMaxGlobnum = max( localMaxGlobnum, elem->giveGlobalNumber() );
4756 if ( elem->giveGlobalNumber() <= 0 ) {
4757 numberOfLocalElementsToNumber++;
4758 }
4759 }
4760
4761 // compute local offset
4762 int startOffset = localMaxGlobnum, availGlobNum;
4763
4764 // lets assign global numbers on each partition to local elements
4765 availGlobNum = startOffset;
4766 for ( auto &elem : d->giveElements() ) {
4767 if ( elem->giveGlobalNumber() <= 0 ) {
4768 elem->setGlobalNumber(++availGlobNum);
4769 }
4770 }
4771
4772#endif
4773
4774}
4775
4776
4777
4778#ifdef __MPI_PARALLEL_MODE
4779bool
4780Subdivision :: exchangeSharedIrregulars()
4781{
4782 // loop over local sharedIrregularsQueue
4783 int globalSharedIrregularsQueueEmpty, localSharedIrregularsQueueEmpty = this->sharedIrregularsQueue.empty();
4784 #ifdef __VERBOSE_PARALLEL
4785 OOFEM_LOG_INFO("[%d] Subdivision :: exchangeSharedIrregulars: localSharedIrregularsQueueEmpty %d\n",
4786 this->giveRank(), localSharedIrregularsQueueEmpty);
4787 #endif
4788 MPI_Allreduce(& localSharedIrregularsQueueEmpty, & globalSharedIrregularsQueueEmpty, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD);
4789 #ifdef __VERBOSE_PARALLEL
4790 OOFEM_LOG_INFO("[%d] Subdivision :: exchangeSharedIrregulars: globalSharedIrregularsQueueEmpty %d\n",
4791 this->giveRank(), globalSharedIrregularsQueueEmpty);
4792 #endif
4793 if ( globalSharedIrregularsQueueEmpty ) {
4794 return true;
4795 } else {
4796 #ifdef __VERBOSE_PARALLEL
4797 OOFEM_LOG_INFO( "[%d] Subdivision :: exchangeSharedIrregulars: started\n", this->giveRank() );
4798 #endif
4799
4800 // there are some shared irregulars -> data exchange
4802 Communicator com(domain->giveEngngModel(), &cb, this->giveRank(), this->giveNumberOfProcesses(), CommMode_Dynamic);
4803
4804 com.packAllData(this, this, & Subdivision :: packSharedIrregulars);
4806 com.unpackAllData(this, this, & Subdivision :: unpackSharedIrregulars);
4807 com.finishExchange();
4808 this->sharedIrregularsQueue.clear();
4809
4810 return false;
4811 }
4812}
4813
4814
4815int
4816Subdivision :: packSharedIrregulars(Subdivision *s, ProcessCommunicator &pc)
4817{
4818 int rproc = pc.giveRank();
4819 int myrank = this->giveRank();
4820 IntArray edgeInfo(2);
4821
4822 if ( rproc == myrank ) {
4823 return 1; // skip local partition
4824 }
4825
4826 // query process communicator to use
4828 for ( int pi : sharedIrregularsQueue ) {
4829 const IntArray *sharedPartitions = this->mesh->giveNode(pi)->givePartitions();
4830 if ( sharedPartitions->contains(rproc) ) {
4831 // the info about new local shared irregular node needs to be sent to remote partition
4832 // the new irregular on remote partition is identified using two nodes (glonums) defining
4833 // an edge on which irregular node is introduced
4834 int iNode, jNode;
4835 static_cast< RS_IrregularNode * >( this->mesh->giveNode(pi) )->giveEdgeNodes(iNode, jNode);
4836 edgeInfo.at(1) = this->mesh->giveNode(iNode)->giveGlobalNumber();
4837 edgeInfo.at(2) = this->mesh->giveNode(jNode)->giveGlobalNumber();
4839 edgeInfo.storeYourself(*pcbuff);
4840 #ifdef __VERBOSE_PARALLEL
4841 OOFEM_LOG_INFO("[%d] Subdivision::packSharedIrregulars: packing shared node %d [%d %d] for %d\n",
4842 myrank, pi, edgeInfo.at(1), edgeInfo.at(2), rproc);
4843 #endif
4844 }
4845 }
4846
4847 pcbuff->write(SUBDIVISION_END_DATA);
4848
4849 return 1;
4850}
4851
4852int
4853Subdivision :: unpackSharedIrregulars(Subdivision *s, ProcessCommunicator &pc)
4854{
4855 int myrank = this->giveRank();
4856 int ie, _type, iNum, iproc = pc.giveRank();
4857 int iNode, jNode, elems;
4858 double density;
4859 IntArray edgeInfo(2);
4860 const IntArray *iElems, *jElems;
4861 FloatArray coords;
4862 Subdivision :: RS_SharedEdge *edge;
4863 Subdivision :: RS_Element *elem;
4864 Subdivision :: RS_IrregularNode *irregular;
4865 int eIndex;
4866
4867 if ( iproc == myrank ) {
4868 return 1; // skip local partition
4869 }
4870
4871 // query process communicator to use
4873
4874 pcbuff->read(_type);
4875 // unpack dofman data
4876 while ( _type != SUBDIVISION_END_DATA ) {
4877 if ( _type == SUBDIVISION_SHARED_IRREGULAR_REC_TAG ) {
4878 edgeInfo.restoreYourself(*pcbuff);
4879 #ifdef __VERBOSE_PARALLEL
4880 OOFEM_LOG_INFO("[%d] Subdivision::unpackSharedIrregulars: received shared node record [%d %d] from %d ...\n",
4881 myrank, edgeInfo.at(1), edgeInfo.at(2), iproc);
4882 #endif
4883
4884 iNode = mesh->sharedNodeGlobal2Local( edgeInfo.at(1) );
4885 jNode = mesh->sharedNodeGlobal2Local( edgeInfo.at(2) );
4886
4887 // get elements incident simultaneiusly to iNode and jNode
4888 iElems = mesh->giveNode(iNode)->giveConnectedElements();
4889 jElems = mesh->giveNode(jNode)->giveConnectedElements();
4890
4891 IntArray common;
4892 if ( iElems->giveSize() <= jElems->giveSize() ) {
4893 common.preallocate( iElems->giveSize() );
4894 } else {
4895 common.preallocate( jElems->giveSize() );
4896 }
4897
4898 // I do rely on the fact that the arrays are ordered !!!
4899 // I am using zero chunk because array common is large enough
4900 elems = iElems->findCommonValuesSorted(* jElems, common, 0);
4901#if 0
4902 if ( !elems) {
4903 // get type of the next record
4904 pcbuff->read(_type);
4905 continue;
4906 }
4907#else
4908 if ( !elems ) {
4909 OOFEM_ERROR("[%d] no element found sharing nodes %d[%d] and %d[%d]",
4910 myrank, iNode, edgeInfo.at(1), jNode, edgeInfo.at(2));
4911 }
4912#endif
4913 // check on the first element whether irregular exists
4914 elem = mesh->giveElement( common.at(1) );
4915 eIndex = elem->giveEdgeIndex(iNode, jNode);
4916 #ifdef DEBUG_CHECK
4917 if ( !elem->giveSharedEdges()->giveSize() ) {
4918 OOFEM_ERROR("element %d sharing nodes %d %d has no shared edges",
4919 elem->giveNumber(), iNode, jNode);
4920 }
4921
4922 if ( !elem->giveSharedEdge(eIndex) ) {
4923 OOFEM_ERROR("element %d sharing nodes %d and %d has no shared edge %d",
4924 elem->giveNumber(), iNode, jNode, eIndex);
4925 }
4926
4927 #endif
4928 if ( elem->giveIrregular(eIndex) ) {
4929 // irregular already exists
4930 #ifdef __VERBOSE_PARALLEL
4931 OOFEM_LOG_INFO( "...already exists as %d on element %d\n", elem->giveIrregular(eIndex), elem->giveNumber() );
4932 #endif
4933 } else {
4934 // irregular does not exist:
4935 // compute coordinates of new irregular
4936 coords = * ( mesh->giveNode(iNode)->giveCoordinates() );
4937 coords.add( * mesh->giveNode(jNode)->giveCoordinates() );
4938 coords.times(0.5);
4939 #ifdef HEADEDSTUD
4940 double dist, rad, rate;
4941 FloatArray *c;
4942
4943 c = mesh->giveNode(iNode)->giveCoordinates();
4944 dist = c->at(1) * c->at(1) + c->at(3) * c->at(3);
4945 if ( c->at(2) > 69.9999999 ) {
4946 rad = 7.0;
4947 } else if ( c->at(2) < 64.5000001 ) {
4948 rad = 18.0;
4949 } else {
4950 rad = 18.0 - 11.0 / 5.5 * ( c->at(2) - 64.5 );
4951 }
4952
4953 if ( fabs(dist - rad * rad) < 0.01 ) { // be very tolerant (geometry is not precise)
4954 c = mesh->giveNode(jNode)->giveCoordinates();
4955 dist = c->at(1) * c->at(1) + c->at(3) * c->at(3);
4956 if ( c->at(2) > 69.9999999 ) {
4957 rad = 7.0;
4958 } else if ( c->at(2) < 64.5000001 ) {
4959 rad = 18.0;
4960 } else {
4961 rad = 18.0 - 11.0 / 5.5 * ( c->at(2) - 64.5 );
4962 }
4963
4964 if ( fabs(dist - rad * rad) < 0.01 ) { // be very tolerant (geometry is not precise)
4965 dist = coords.at(1) * coords.at(1) + coords.at(3) * coords.at(3);
4966 if ( coords.at(2) > 69.9999999 ) {
4967 rad = 7.0;
4968 } else if ( coords.at(2) < 64.5000001 ) {
4969 rad = 18.0;
4970 } else {
4971 rad = 18.0 - 11.0 / 5.5 * ( coords.at(2) - 64.5 );
4972 }
4973
4974 rate = rad / sqrt(dist);
4975 coords.at(1) *= rate;
4976 coords.at(3) *= rate;
4977 }
4978 }
4979
4980 #endif
4981 // compute required density of a new node
4982 density = 0.5 * ( mesh->giveNode(iNode)->giveRequiredDensity() +
4983 mesh->giveNode(jNode)->giveRequiredDensity() );
4984 // create new irregular to receiver
4985 iNum = mesh->giveNumberOfNodes() + 1;
4986 irregular = new Subdivision :: RS_IrregularNode(iNum, mesh, 0, coords, density, true);
4987 irregular->setParallelMode(DofManager_shared);
4988 irregular->setEdgeNodes(iNode, jNode);
4989 mesh->addNode(irregular);
4990
4991 #ifdef __OOFEG
4992 #ifdef DRAW_IRREGULAR_NODES
4993 irregular->drawGeometry();
4994 #endif
4995 #endif
4996
4997 // partitions are inherited from shared edge
4998 edge = mesh->giveEdge( elem->giveSharedEdge(eIndex) );
4999 irregular->setPartitions( * ( edge->givePartitions() ) );
5000 // add irregular to all relevant elements
5001 for ( ie = 1; ie <= common.giveSize(); ie++ ) {
5002 elem = mesh->giveElement( common.at(ie) );
5003 eIndex = elem->giveEdgeIndex(iNode, jNode);
5004 #ifdef DEBUG_CHECK
5005 if ( !elem->giveSharedEdges()->giveSize() ) {
5006 OOFEM_ERROR("element %d sharing nodes %d %d has no shared edges",
5007 elem->giveNumber(), iNode, jNode);
5008 }
5009
5010 if ( !elem->giveSharedEdge(eIndex) ) {
5011 OOFEM_ERROR("element %d sharing nodes %d and %d has no shared edge %d",
5012 elem->giveNumber(), iNode, jNode, eIndex);
5013 }
5014
5015 if ( elem->giveIrregular(eIndex) ) {
5016 OOFEM_ERROR("element %d sharing nodes %d %d already has irregular",
5017 elem->giveNumber(), iNode, jNode);
5018 }
5019
5020 #endif
5021 elem->setIrregular(eIndex, iNum);
5022 if ( !elem->giveQueueFlag() ) {
5023 // schedule elem for bisection
5024 subdivqueue.push( elem->giveNumber() );
5025 elem->setQueueFlag(true);
5026 }
5027
5028 #ifdef __VERBOSE_PARALLEL
5029 OOFEM_LOG_INFO( "...added as %d on element %d\n", iNum, elem->giveNumber() );
5030 #endif
5031 #ifdef DEBUG_INFO
5032 if ( domain->giveElement( elem->giveTopParent() )->giveGeometryType() == EGT_tetra_1 ) {
5033 // do not print global numbers of elements because they are not available (they are assigned at once after bisection);
5034 // do not print global numbers of irregulars as these may not be available yet
5035 OOFEM_LOG_INFO( "[%d] Shared irregular %d added on %d (edge %d, nodes %d %d [%d %d], nds %d %d %d %d [%d %d %d %d], ngbs %d %d %d %d, irr %d %d %d %d %d %d)\n",
5036 myrank, iNum,
5037 elem->giveNumber(), eIndex, iNode, jNode,
5038 mesh->giveNode(iNode)->giveGlobalNumber(), mesh->giveNode(jNode)->giveGlobalNumber(),
5039 elem->giveNode(1), elem->giveNode(2), elem->giveNode(3), elem->giveNode(4),
5040 mesh->giveNode( elem->giveNode(1) )->giveGlobalNumber(),
5041 mesh->giveNode( elem->giveNode(2) )->giveGlobalNumber(),
5042 mesh->giveNode( elem->giveNode(3) )->giveGlobalNumber(),
5043 mesh->giveNode( elem->giveNode(4) )->giveGlobalNumber(),
5044 elem->giveNeighbor(1), elem->giveNeighbor(2), elem->giveNeighbor(3), elem->giveNeighbor(4),
5045 elem->giveIrregular(1), elem->giveIrregular(2), elem->giveIrregular(3),
5046 elem->giveIrregular(4), elem->giveIrregular(5), elem->giveIrregular(6) );
5047 }
5048
5049 #endif
5050 }
5051 }
5052 } else {
5053 OOFEM_ERROR("unknown tag received");
5054 }
5055
5056 // get type of the next record
5057 pcbuff->read(_type);
5058 }
5059
5060 return 1;
5061}
5062
5063void
5064Subdivision :: assignGlobalNumbersToSharedIrregulars()
5065{
5066 // there are some shared irregulars -> data exchange
5068 Communicator com(domain->giveEngngModel(), &cb, this->giveRank(),
5069 this->giveNumberOfProcesses(), CommMode_Dynamic);
5070
5071 com.packAllData(this, this, & Subdivision :: packIrregularSharedGlobnums);
5073 com.unpackAllData(this, this, & Subdivision :: unpackIrregularSharedGlobnums);
5074 com.finishExchange();
5075}
5076
5077int
5078Subdivision :: packIrregularSharedGlobnums(Subdivision *s, ProcessCommunicator &pc)
5079{
5080 int rproc = pc.giveRank();
5081 int in, iNode, jNode, nnodes = mesh->giveNumberOfNodes();
5082 int myrank = this->giveRank();
5083 IntArray edgeInfo(3);
5084 const IntArray *sharedPartitions;
5085
5086 if ( rproc == myrank ) {
5087 return 1; // skip local partition
5088 }
5089
5090 // query process communicator to use
5092 for ( in = 1; in <= nnodes; in++ ) {
5093 if ( this->isNodeLocalSharedIrregular(mesh->giveNode(in), myrank) && ( mesh->giveNode(in)->giveGlobalNumber() < 0 ) ) {
5094 sharedPartitions = this->mesh->giveNode(in)->givePartitions();
5095 if ( sharedPartitions->contains(rproc) ) {
5096 // the info about new local shared irregular node needs to be sent to remote partition
5097 // the new irregular on remote partition is identified using two nodes defining
5098 // an edge on which irregular node is introduced
5099 ( ( RS_IrregularNode * ) this->mesh->giveNode(in) )->giveEdgeNodes(iNode, jNode);
5100 edgeInfo.at(1) = this->mesh->giveNode(iNode)->giveGlobalNumber();
5101 edgeInfo.at(2) = this->mesh->giveNode(jNode)->giveGlobalNumber();
5102 edgeInfo.at(3) = this->mesh->giveNode(in)->giveGlobalNumber(); // keep negative
5103 #ifdef __VERBOSE_PARALLEL
5104 OOFEM_LOG_INFO("[%d] packIrregularSharedGlobnums: sending %d [%d] - [%d %d] to %d\n",
5105 myrank, in, -edgeInfo.at(3), edgeInfo.at(1), edgeInfo.at(2), rproc);
5106 #endif
5107 pcbuff->write(SUBDIVISION_SHARED_IRREGULAR_REC_TAG); // KOKO asi zbytecne
5108 edgeInfo.storeYourself(*pcbuff);
5109 }
5110 }
5111 }
5112
5113 pcbuff->write(SUBDIVISION_END_DATA);
5114
5115 return 1;
5116}
5117
5118
5119int
5120Subdivision :: unpackIrregularSharedGlobnums(Subdivision *s, ProcessCommunicator &pc)
5121{
5122 int myrank = this->giveRank();
5123 int _type, iproc = pc.giveRank();
5124 int iNode, jNode, iNum, elems;
5125 IntArray edgeInfo(3);
5126 const IntArray *iElems, *jElems;
5127 RS_Element *elem;
5128 RS_Node *node;
5129 int eIndex;
5130
5131 if ( iproc == myrank ) {
5132 return 1; // skip local partition
5133 }
5134
5135 // query process communicator to use
5137
5138 pcbuff->read(_type);
5139 // unpack dofman data
5140 while ( _type != SUBDIVISION_END_DATA ) {
5141 if ( _type == SUBDIVISION_SHARED_IRREGULAR_REC_TAG ) { // KOKO asi zbytecne
5142 edgeInfo.restoreYourself(*pcbuff);
5143
5144 iNode = mesh->sharedNodeGlobal2Local( edgeInfo.at(1) );
5145 jNode = mesh->sharedNodeGlobal2Local( edgeInfo.at(2) );
5146
5147 // get elements incident simultaneiusly to iNode and jNode
5148 iElems = mesh->giveNode(iNode)->giveConnectedElements();
5149 jElems = mesh->giveNode(jNode)->giveConnectedElements();
5150
5151 IntArray common;
5152 if ( iElems->giveSize() <= jElems->giveSize() ) {
5153 common.preallocate( iElems->giveSize() );
5154 } else {
5155 common.preallocate( jElems->giveSize() );
5156 }
5157
5158 // I do rely on the fact that the arrays are ordered !!!
5159 // I am using zero chunk because array common is large enough
5160 elems = iElems->findCommonValuesSorted(* jElems, common, 0);
5161#if 0
5162 if ( !elems ) {
5163 pcbuff->read(_type);
5164 continue;
5165 }
5166#else
5167 if ( !elems ) {
5168 OOFEM_ERROR("no element found sharing nodes %d and %d",
5169 iNode, jNode);
5170 }
5171#endif
5172
5173 // assign globnum to appropriate edge on the first element
5174 elem = mesh->giveElement( common.at(1) );
5175 eIndex = elem->giveEdgeIndex(iNode, jNode);
5176 iNum = elem->giveIrregular(eIndex);
5177 #ifdef DEBUG_CHECK
5178 if ( !elem->giveSharedEdges()->giveSize() ) {
5179 OOFEM_ERROR("element %d sharing nodes %d %d has no shared edges",
5180 elem->giveNumber(), iNode, jNode);
5181 }
5182
5183 if ( !elem->giveSharedEdge(eIndex) ) {
5184 OOFEM_ERROR("element %d sharing nodes %d and %d has no shared edge %d",
5185 elem->giveNumber(), iNode, jNode, eIndex);
5186 }
5187
5188 if ( !iNum ) {
5189 OOFEM_ERROR("element %d sharing nodes %d %d does not have irregular",
5190 elem->giveNumber(), iNode, jNode);
5191 }
5192
5193 #endif
5194 node = mesh->giveNode(iNum);
5195 node->setGlobalNumber( edgeInfo.at(3) ); // keep negative
5196 // update global shared node map (for refined level)
5197 this->mesh->insertGlobalSharedNodeMap(node);
5198
5199 #ifdef __VERBOSE_PARALLEL
5200 OOFEM_LOG_INFO("[%d] Subdivision::unpackIrregularSharedGlobnums: received %d [%d] - [%d %d] from %d\n",
5201 myrank, iNum, -edgeInfo.at(3), edgeInfo.at(1), edgeInfo.at(2), iproc);
5202 #endif
5203 } else {
5204 OOFEM_ERROR("unknown tag received");
5205 }
5206
5207 pcbuff->read(_type);
5208 }
5209
5210 return 1;
5211}
5212
5213bool
5214Subdivision :: isNodeLocalSharedIrregular(Subdivision :: RS_Node *node, int myrank)
5215{
5216 if ( node->isIrregular() ) {
5217 if ( node->giveParallelMode() == DofManager_shared ) {
5218 int i, minpart, npart;
5219 const IntArray *partitions = node->givePartitions();
5220 npart = partitions->giveSize();
5221 minpart = myrank;
5222 for ( i = 1; i <= npart; i++ ) {
5223 minpart = min( minpart, partitions->at(i) );
5224 }
5225
5226 if ( minpart == myrank ) {
5227 return true;
5228 } else {
5229 return false;
5230 }
5231 } else {
5232 return false;
5233 }
5234 } else {
5235 return false;
5236 }
5237}
5238
5239
5240
5241
5242
5243int
5244Subdivision :: giveRank()
5245{
5246 return this->domain->giveEngngModel()->giveRank();
5247}
5248
5249int
5250Subdivision :: giveNumberOfProcesses()
5251{
5252 return this->domain->giveEngngModel()->giveNumberOfProcesses();
5253}
5254
5255
5256/*
5257 * Idea is to rebuild the remote elements from scratch after subdivision
5258 * Reason is that sbdivision in mot cases followed by smoothing,
5259 * so that it becomes difficult to reconstruct the remot elements from old remote elements
5260 *
5261 * the algorith should be summarized as follows:
5262 * 1. For each remote partition:
5263 * For each node (INODE) shared with remote partition:
5264 * Add all elements sharing INODE into the queue:
5265 * For each element in the queue:
5266 * Mark element as remote
5267 * For each node (JNODE) of this element:
5268 * Compute its distance from INODE
5269 * If less than nonlocal radius:
5270 * Add all elements sharing JNODE to queue
5271 *
5272 * This is an aproximate algrithm, that works correctly for reasonably shaped grids,
5273 * for grids with badly shaped elements, some interactions can be neglected, due to the fact
5274 * that real distances between intagration points are not considered directly.
5275 *
5276 * This algorithm failes if the mirror zone propagates to partition not adjacent to current partition.
5277 * Therefore the algorithm has been abandaned and replaced by that which mirrors children
5278 * of all originally mirrored elements;
5279 * If the smoothing is applied this is also only approximate algorithm, as the mesh movement
5280 * may casuse that some new elements being not child of origanally mirrored elements are shifted
5281 * into the mirrored band !!!
5282 */
5283void
5284Subdivision :: exchangeRemoteElements(Domain *d, IntArray &parentMap)
5285{
5286 int nproc = this->giveNumberOfProcesses(), myrank = this->giveRank();
5287 CommunicatorBuff cb(nproc, CBT_dynamic);
5288 Communicator com(d->giveEngngModel(), &cb, myrank, nproc, CommMode_Dynamic);
5289
5290 // move existing dofmans and elements, that will be local on current partition,
5291 // into local map
5293 s.d = d;
5294 s.parentElemMap = & parentMap;
5295 com.packAllData(this, & s, & Subdivision :: packRemoteElements);
5297
5298 // remove existing remote elements and null nodes
5299 int nelem = d->giveNumberOfElements();
5300 int nnodes = d->giveNumberOfDofManagers();
5302 for ( int i = 1; i <= nnodes; i++ ) {
5304 dtm->addDofManTransaction(DomainTransactionManager :: DTT_Remove, d->giveDofManager(i)->giveGlobalNumber(), NULL);
5305 }
5306 }
5307
5308 for ( int i = 1; i <= nelem; i++ ) {
5309 if ( d->giveElement(i)->giveParallelMode() == Element_remote ) {
5310 dtm->addElementTransaction(DomainTransactionManager :: DTT_Remove, d->giveElement(i)->giveGlobalNumber(), NULL);
5311 }
5312 }
5313
5314 // receive remote data
5315 com.unpackAllData(this, d, & Subdivision :: unpackRemoteElements);
5316 com.finishExchange();
5317}
5318
5319int
5320Subdivision :: packRemoteElements(RS_packRemoteElemsStruct *s, ProcessCommunicator &pc)
5321{
5322 Domain *d = s->d;
5323 int rproc = pc.giveRank();
5324 int myrank = this->giveRank();
5325 std :: queue< int >elemCandidates;
5326 std :: set< int >remoteElements, processedElements, nodesToSend;
5327
5328 if ( rproc == myrank ) {
5329 return 1; // skip local partition
5330 }
5331
5332 EngngModel *emodel = d->giveEngngModel();
5333 // comMap refers to original (parent) elements
5334 const IntArray &comMap = emodel->giveProblemCommunicator(EngngModel :: PC_nonlocal)->giveProcessCommunicator(rproc)->giveToSendMap();
5335 #ifdef __OOFEG
5336 #ifdef DRAW_REMOTE_ELEMENTS
5338 EPixel geocolor = gc.getElementColor();
5339 gc.setElementColor( gc.getActiveCrackColor() );
5340 #endif
5341 #endif
5342 for ( int i = 1; i <= d->giveNumberOfElements(); i++ ) {
5343 // remote parent skipped - parentElemMap has zero value for them
5344 if ( comMap.contains( s->parentElemMap->at(i) ) ) {
5345 remoteElements.insert(i);
5346 #ifdef __OOFEG
5347 #ifdef DRAW_REMOTE_ELEMENTS
5348 TimeStep *tStep = emodel->giveCurrentStep();
5349 d->giveElement(i)->drawRawGeometry(gc, tStep);
5350 #endif
5351 #endif
5352 }
5353 }
5354
5355 #ifdef __OOFEG
5356 #ifdef DRAW_REMOTE_ELEMENTS
5357 ESIEventLoop(YES, "Remote element packing ; Press Ctrl-p to continue");
5358 gc.setElementColor(geocolor);
5359 #endif
5360 #endif
5361
5362 // now the list of elements to became remote on given remote partition is in remoteElements set
5363
5364 // need to pack elements definition and corresponding nodes!
5365 /*
5366 * mark shecheduled nodes:
5367 * loop over elements in remoteElements set and add all their nodes (except those that are shared)
5368 */
5369 for ( int elNum: remoteElements ) {
5370 Element *relemPtr = d->giveElement(elNum);
5371 int nn = relemPtr->giveNumberOfNodes();
5372 for ( int in = 1; in <= nn; in++ ) {
5373 int inode = relemPtr->giveDofManagerNumber(in);
5374 if ( ( d->giveDofManager(inode)->giveParallelMode() == DofManager_local ) ||
5375 ( ( d->giveDofManager(inode)->giveParallelMode() == DofManager_shared ) && ( !d->giveDofManager(inode)->givePartitionList()->contains(rproc) ) ) ) {
5376 // nodesToSend is set, therefore duplicity is avoided
5377 nodesToSend.insert(inode);
5378 }
5379 }
5380 }
5381
5382 //-----------------end here-------------------
5383
5384 // query process communicator to use
5386 // send nodes that define remote_elements gometry
5387 for ( int nodeNum: nodesToSend ) {
5388 DofManager *inodePtr = d->giveDofManager(nodeNum);
5389
5390 pcbuff->write( inodePtr->giveInputRecordName() );
5391 pcbuff->write( inodePtr->giveGlobalNumber() );
5392 inodePtr->saveContext(*pcbuff, CM_Definition);
5393 }
5394
5395 // pack end-of-element-record
5396 pcbuff->write("");
5397
5398 // send elements
5399 for ( int elNum: remoteElements ) {
5400 Element *elemPtr = d->giveElement(elNum);
5401 // pack local element (node numbers shuld be global ones!!!)
5402 // pack type
5403 pcbuff->write( elemPtr->giveInputRecordName() );
5404 // nodal numbers shuld be packed as global !!
5405 elemPtr->saveContext(*pcbuff, CM_Definition | CM_DefinitionGlobal);
5406 //OOFEM_LOG_INFO ("[%d] Sending Remote elem %d[%d] to rank %d\n", myrank,*si, elemPtr->giveGlobalNumber(), rproc );
5407 }
5408
5409 // pack end-of-element-record
5410 pcbuff->write("");
5411
5412 return 1;
5413}
5414
5415
5416int
5417Subdivision :: unpackRemoteElements(Domain *d, ProcessCommunicator &pc)
5418{
5419 int myrank = d->giveEngngModel()->giveRank();
5420 int iproc = pc.giveRank();
5421 int _globnum;
5422 std :: string _type;
5424
5425 if ( iproc == myrank ) {
5426 return 1; // skip local partition
5427 }
5428
5429 // query process communicator to use
5431
5432 // unpack dofman data
5433 do {
5434 pcbuff->read(_type);
5435 if ( _type.size() == 0 ) {
5436 break;
5437 }
5438
5439 // receiving new local dofManager
5440 pcbuff->read(_globnum);
5441
5442 DofManager *dofman;
5443 bool _newentry = false;
5444 if ( ( dofman = dtm->giveDofManager(_globnum) ) == NULL ) {
5445 // data not available -> create a new one
5446 _newentry = true;
5447 dofman = classFactory.createDofManager(_type.c_str(), 0, d).release();
5448 }
5449
5450 dofman->setGlobalNumber(_globnum);
5451 // unpack dofman state (this is the local dofman, not available on remote)
5452 dofman->restoreContext(*pcbuff, CM_Definition);
5454 // add transaction if new entry allocated; otherwise existing one has been modified via returned dofman
5455 if ( _newentry ) {
5456 dtm->addDofManTransaction(DomainTransactionManager :: DTT_ADD, _globnum, dofman);
5457 }
5458 } while ( 1 );
5459
5460 IntArray elemPartitions(1);
5461 elemPartitions.at(1) = iproc;
5462 int nrecv = 0;
5463
5464 do {
5465 pcbuff->read(_type);
5466 if ( _type.size() == 0 ) {
5467 break;
5468 }
5469
5470 Element *elem = classFactory.createElement(_type.c_str(), 0, d).release();
5473 elem->setPartitionList(elemPartitions);
5474 dtm->addElementTransaction(DomainTransactionManager :: DTT_ADD, elem->giveGlobalNumber(), elem);
5475 nrecv++;
5476 //OOFEM_LOG_INFO ("[%d] Received Remote elem [%d] from rank %d\n", myrank, elem->giveGlobalNumber(), iproc );
5477 //recvElemList.push_back(elem);
5478 } while ( 1 );
5479
5480 return 1;
5481}
5482
5483
5484
5485
5486/* CAUTION: the exchange can be done only for not subdivided edges !
5487 * subdivided edges inherit partitions from parent edge (in ::generate) */
5488
5489void
5490Subdivision :: exchangeSharedEdges()
5491{
5492 int iNode, jNode, elems;
5493 Subdivision :: RS_SharedEdge *edge;
5494 Subdivision :: RS_Element *elem;
5495 const IntArray *iElems, *jElems;
5496
5497 // loop over local sharedEdgessQueue
5498 int globalSharedEdgesQueueEmpty, localSharedEdgesQueueEmpty = this->sharedEdgesQueue.empty();
5499 #ifdef __VERBOSE_PARALLEL
5500 OOFEM_LOG_INFO("[%d] Subdivision :: exchangeSharedEdges: localSharedEdgesQueueEmpty %d\n",
5501 this->giveRank(), localSharedEdgesQueueEmpty);
5502 #endif
5503 MPI_Allreduce(& localSharedEdgesQueueEmpty, & globalSharedEdgesQueueEmpty, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD);
5504 #ifdef __VERBOSE_PARALLEL
5505 OOFEM_LOG_INFO("[%d] Subdivision :: exchangeSharedEdges: globalSharedEdgesQueueEmpty %d\n",
5506 this->giveRank(), globalSharedEdgesQueueEmpty);
5507 #endif
5508 if ( !globalSharedEdgesQueueEmpty ) {
5509 #ifdef __VERBOSE_PARALLEL
5510 OOFEM_LOG_INFO( "[%d] Subdivision :: exchangeSharedEdges: started\n", this->giveRank() );
5511 #endif
5512
5513 // there are some shared edges -> data exchange
5514
5516 Communicator com(domain->giveEngngModel(), &cb, this->giveRank(), this->giveNumberOfProcesses(), CommMode_Dynamic);
5517
5518 com.packAllData(this, this, & Subdivision :: packSharedEdges);
5519
5520 // remove all tentative partitions on queued shared edges after packing relevant data
5521 for ( int pi : sharedEdgesQueue ) {
5522 edge = mesh->giveEdge(pi);
5523 edge->removePartitions();
5524 }
5525
5527 com.unpackAllData(this, this, & Subdivision :: unpackSharedEdges);
5528 com.finishExchange();
5529
5530 // unmark unshared edges from elements after unpacking data and before clearing the queue
5531 for ( int pi : sharedEdgesQueue ) {
5532
5533 edge = mesh->giveEdge(pi);
5534 if ( edge->givePartitions()->giveSize() ) {
5535 continue;
5536 }
5537
5538 edge->giveEdgeNodes(iNode, jNode);
5539 #ifdef __VERBOSE_PARALLEL
5540 //OOFEM_LOG_INFO("edge %d %d [%d %d] not shared\n", iNode, jNode,
5541 //mesh->giveNode(iNode)->giveGlobalNumber(), mesh->giveNode(jNode)->giveGlobalNumber());
5542 #endif
5543 iElems = mesh->giveNode(iNode)->giveConnectedElements();
5544 jElems = mesh->giveNode(jNode)->giveConnectedElements();
5545
5546 IntArray common;
5547 if ( iElems->giveSize() <= jElems->giveSize() ) {
5548 common.preallocate( iElems->giveSize() );
5549 } else {
5550 common.preallocate( jElems->giveSize() );
5551 }
5552
5553 // I do rely on the fact that the arrays are ordered !!!
5554 // I am using zero chunk because array common is large enough
5555 elems = iElems->findCommonValuesSorted(* jElems, common, 0);
5556 #ifdef DEBUG_CHECK
5557 if ( !elems ) {
5558 OOFEM_ERROR("no element found sharing nodes %d and %d corresponding to edge %d",
5559 iNode, jNode, pi);
5560 }
5561
5562 #endif
5563 for ( int i = 1; i <= elems; i++ ) {
5564 elem = mesh->giveElement( common.at(i) );
5565 #ifdef DEBUG_CHECK
5566 if ( !elem->giveSharedEdges()->giveSize() ) {
5567 OOFEM_ERROR("element %d sharing nodes %d %d has no shared edges",
5568 elem->giveNumber(), iNode, jNode);
5569 }
5570
5571 #endif
5572 elem->setSharedEdge(elem->giveEdgeIndex(iNode, jNode), 0);
5573 }
5574 }
5575
5576 this->sharedEdgesQueue.clear();
5577 }
5578}
5579
5580
5581
5582int
5583Subdivision :: packSharedEdges(Subdivision *s, ProcessCommunicator &pc)
5584{
5585 int rproc = pc.giveRank();
5586 int myrank = this->giveRank();
5587 IntArray edgeInfo(2);
5588
5589 if ( rproc == myrank ) {
5590 return 1; // skip local partition
5591 }
5592
5593 // query process communicator to use
5595 for ( int pi : sharedEdgesQueue ) {
5596
5597 const IntArray *sharedPartitions = this->mesh->giveEdge(pi)->givePartitions();
5598 if ( sharedPartitions->contains(rproc) ) {
5599 int iNode, jNode;
5600 this->mesh->giveEdge(pi)->giveEdgeNodes(iNode, jNode);
5601 edgeInfo.at(1) = this->mesh->giveNode(iNode)->giveGlobalNumber();
5602 edgeInfo.at(2) = this->mesh->giveNode(jNode)->giveGlobalNumber();
5603 #ifdef __VERBOSE_PARALLEL
5604 OOFEM_LOG_INFO("[%d] Subdivision::packSharedEdges: sending [%d %d] to %d\n", myrank, edgeInfo.at(1), edgeInfo.at(2), rproc);
5605 #endif
5606 pcbuff->write(SUBDIVISION_SHARED_EDGE_REC_TAG); // KOKO zbytecne
5607 edgeInfo.storeYourself(*pcbuff);
5608 }
5609 }
5610
5611 pcbuff->write(SUBDIVISION_END_DATA);
5612
5613 return 1;
5614}
5615
5616
5617int
5618Subdivision :: unpackSharedEdges(Subdivision *s, ProcessCommunicator &pc)
5619{
5620 int myrank = this->giveRank();
5621 int _type, iproc = pc.giveRank();
5622 int iNode, jNode, elems;
5623 IntArray edgeInfo(2);
5624 const IntArray *iElems, *jElems;
5625 Subdivision :: RS_SharedEdge *edge;
5626 Subdivision :: RS_Element *elem;
5627 int eIndex;
5628
5629 if ( iproc == myrank ) {
5630 return 1; // skip local partition
5631 }
5632
5633 // query process communicator to use
5635
5636 pcbuff->read(_type);
5637 // unpack dofman data
5638 while ( _type != SUBDIVISION_END_DATA ) {
5639 if ( _type == SUBDIVISION_SHARED_EDGE_REC_TAG ) { // KOKO zbytecne
5640 edgeInfo.restoreYourself(*pcbuff);
5641
5642 #ifdef __VERBOSE_PARALLEL
5643 OOFEM_LOG_INFO("[%d] Subdivision::unpackSharedEdges: receiving [%d %d] from %d\n",
5644 myrank, edgeInfo.at(1), edgeInfo.at(2), iproc);
5645 #endif
5646
5647 iNode = mesh->sharedNodeGlobal2Local( edgeInfo.at(1) );
5648 jNode = mesh->sharedNodeGlobal2Local( edgeInfo.at(2) );
5649
5650 if (!(iNode && jNode)) {
5651 pcbuff->read(_type);
5652 continue;
5653 }
5654
5655 // get elements incident simultaneiusly to iNode and jNode
5656 iElems = mesh->giveNode(iNode)->giveConnectedElements();
5657 jElems = mesh->giveNode(jNode)->giveConnectedElements();
5658
5659 IntArray common;
5660 if ( iElems->giveSize() <= jElems->giveSize() ) {
5661 common.preallocate( iElems->giveSize() );
5662 } else {
5663 common.preallocate( jElems->giveSize() );
5664 }
5665
5666 // I do rely on the fact that the arrays are ordered !!!
5667 // I am using zero chunk because array common is large enough
5668 elems = iElems->findCommonValuesSorted(* jElems, common, 0);
5669 if ( elems ) {
5670 // find the relevant edge on the first element
5671 elem = mesh->giveElement( common.at(1) );
5672 eIndex = elem->giveEdgeIndex(iNode, jNode);
5673 #ifdef DEBUG_CHECK
5674 if ( !elem->giveSharedEdges()->giveSize() ) {
5675 OOFEM_ERROR("element %d sharing nodes %d %d has no shared edges",
5676 elem->giveNumber(), iNode, jNode);
5677 }
5678
5679 if ( !elem->giveSharedEdge(eIndex) ) {
5680 OOFEM_ERROR("element %d sharing nodes %d and %d has no shared edge %d",
5681 elem->giveNumber(), iNode, jNode, eIndex);
5682 }
5683
5684 #endif
5685 edge = mesh->giveEdge( elem->giveSharedEdge(eIndex) );
5686 // use zero chunk; the array is large enough from tentative set of partitions
5687 edge->addPartition(iproc, 0);
5688
5689 #ifdef __VERBOSE_PARALLEL
5690 OOFEM_LOG_INFO( "[%d] Partition %d added to shared edge %d (%d %d) [%d %d]\n",
5691 myrank, iproc, elem->giveSharedEdge(eIndex), iNode, jNode, edgeInfo.at(1), edgeInfo.at(2) );
5692 #endif
5693 }
5694 } else {
5695 OOFEM_ERROR("unknown tag received");
5696 }
5697
5698 pcbuff->read(_type);
5699 }
5700
5701 return 1;
5702}
5703
5704
5705void
5706Subdivision :: RS_Mesh :: insertGlobalSharedNodeMap(Subdivision :: RS_Node *node)
5707{
5708 sharedNodeMap [ node->giveGlobalNumber() ] = node;
5709}
5710
5711
5712int
5713Subdivision :: RS_Mesh :: sharedNodeGlobal2Local(int _globnum)
5714{
5715 if ( sharedNodeMap.find(_globnum) != sharedNodeMap.end() ) {
5716 // node is already available -> update only
5717 return ( sharedNodeMap [ _globnum ]->giveNumber() );
5718 } else {
5719 return 0;
5720 }
5721}
5722
5723#endif
5724
5725
5726
5727int
5728Subdivision :: RS_CompareNodePositions :: operator() (int i, int j)
5729{
5730 double icoord = m->giveNode(i)->giveCoordinates()->at(1);
5731 double jcoord = m->giveNode(j)->giveCoordinates()->at(1);
5732
5733 if ( icoord < jcoord ) {
5734 return -1;
5735 }
5736
5737 if ( icoord > jcoord ) {
5738 return 1;
5739 }
5740
5741 icoord = m->giveNode(i)->giveCoordinates()->at(2);
5742 jcoord = m->giveNode(j)->giveCoordinates()->at(2);
5743
5744 if ( icoord < jcoord ) {
5745 return -1;
5746 }
5747
5748 if ( icoord > jcoord ) {
5749 return 1;
5750 }
5751
5752 icoord = m->giveNode(i)->giveCoordinates()->at(3);
5753 jcoord = m->giveNode(j)->giveCoordinates()->at(3);
5754
5755 if ( icoord < jcoord ) {
5756 return -1;
5757 }
5758
5759 if ( icoord > jcoord ) {
5760 return 1;
5761 }
5762
5763 return 0;
5764}
5765} // end namespace oofem
#define REGISTER_Mesher(class, type)
int unpackAllData(T *ptr, int(T ::*unpackFunc)(ProcessCommunicator &))
ProcessCommunicator * giveProcessCommunicator(int i)
int initExchange(int tag)
int packAllData(T *ptr, int(T ::*packFunc)(ProcessCommunicator &))
void giveElementNeighbourList(IntArray &answer, const IntArray &elemList)
void giveNodeNeighbourList(IntArray &answer, IntArray &nodeList)
int giveGlobalNumber() const
Definition dofmanager.h:515
const char * giveInputRecordName() const override
Definition dofmanager.h:558
void saveContext(DataStream &stream, ContextMode mode) override
Definition dofmanager.C:540
void restoreContext(DataStream &stream, ContextMode mode) override
Definition dofmanager.C:595
const IntArray * givePartitionList()
Definition dofmanager.h:533
IntArray * giveLoadArray()
Definition dofmanager.C:90
void setGlobalNumber(int newNumber)
Definition dofmanager.h:521
dofManagerParallelMode giveParallelMode() const
Definition dofmanager.h:526
void setParallelMode(dofManagerParallelMode _mode)
Definition dofmanager.h:528
int addDofManTransaction(DomainTransactionType, int, DofManager *)
int addElementTransaction(DomainTransactionType, int, Element *)
DomainTransactionManager * giveTransactionManager()
Definition domain.C:1697
int giveNumberOfElements() const
Returns number of elements in domain.
Definition domain.h:463
int giveNumberOfDofManagers() const
Returns number of dof managers in domain.
Definition domain.h:461
DofManager * giveDofManager(int n)
Definition domain.C:317
Element * giveElement(int n)
Definition domain.C:165
EngngModel * giveEngngModel()
Definition domain.C:419
std ::vector< std ::unique_ptr< Element > > & giveElements()
Definition domain.h:294
void giveRecordKeywordField(std ::string &answer, int &value) override
Reads the record id field (type of record) and its corresponding number.
std::string giveRecordAsString() const override
Returns string representation of record in OOFEMs text format.
void setField(int item, InputFieldType id)
int giveGlobalNumber() const
Definition element.h:1129
virtual void drawRawGeometry(oofegGraphicContext &gc, TimeStep *tStep)
Definition element.h:1075
static ParamKey IPK_Element_nodes
Definition element.h:200
virtual int giveNumberOfNodes() const
Definition element.h:703
void saveContext(DataStream &stream, ContextMode mode) override
Definition element.C:923
elementParallelMode giveParallelMode() const
Definition element.h:1139
void restoreContext(DataStream &stream, ContextMode mode) override
Definition element.C:999
void setGlobalNumber(int num)
Definition element.h:1134
int giveDofManagerNumber(int i) const
Definition element.h:609
void setParallelMode(elementParallelMode _mode)
Sets parallel mode of element.
Definition element.h:1141
void setPartitionList(IntArray &pl)
Definition element.h:1182
int giveRegionNumber()
Definition element.C:546
virtual TimeStep * giveCurrentStep(bool force=false)
Definition engngm.h:717
int giveRank() const
Returns domain rank in a group of collaborating processes (0..groupSize-1).
Definition engngm.h:1154
ProblemCommunicator * giveProblemCommunicator(EngngModelCommType t)
Definition engngm.h:625
virtual const char * giveInputRecordName() const =0
double & at(Index i)
Definition floatarray.h:202
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void add(const FloatArray &src)
Definition floatarray.C:218
void times(double s)
Definition floatarray.C:834
void followedBy(const IntArray &b, int allocChunk=0)
Definition intarray.C:94
int findCommonValuesSorted(const IntArray &iarray, IntArray &common, int allocChunk=0) const
Definition intarray.C:332
void resize(int n)
Definition intarray.C:73
contextIOResultType restoreYourself(DataStream &stream)
Definition intarray.C:254
bool contains(int value) const
Definition intarray.h:292
void preallocate(int futureSize)
Definition intarray.C:79
void zero()
Sets all component to zero.
Definition intarray.C:52
contextIOResultType storeYourself(DataStream &stream) const
Definition intarray.C:238
int findFirstIndexOf(int value) const
Definition intarray.C:280
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
void setCoordinates(FloatArray coords)
Definition node.h:117
int read(int *data, std::size_t count) override
Reads count integer values into array pointed by data.
Definition processcomm.h:94
int write(const int *data, std::size_t count) override
Writes count integer values from array pointed by data.
Definition processcomm.h:86
ProcessCommunicatorBuff * giveProcessCommunicatorBuff()
Returns communication buffer.
const IntArray & giveToSendMap()
int giveMasterDofManagerNum() const
Returns Master Dof Manager Number.
const IntArray * giveNodes()
const IntArray * giveSharedEdges()
virtual int giveEdgeIndex(int iNode, int jNode)=0
elementParallelMode giveParallelMode() const
RS_Element(int number, Subdivision ::RS_Mesh *m, int parent, IntArray &nodes)
bool isTerminal()
Returns true if receiver is terminal (not further subdivided).
virtual double giveRequiredDensity()
const IntArray * giveChildren()
void buildTopLevelNodeConnectivity(Subdivision ::RS_Node *node)
const IntArray * giveNeighbors()
virtual void bisect(std ::queue< int > &subdivqueue, std ::list< int > &sharedIrregularsQueue)
virtual void generate(std ::list< int > &sharedEdgesQueue)
virtual void giveSideNodes(int iside, IntArray &snodes)=0
std ::map< int, Subdivision ::RS_Node * > sharedNodeMap
Global shared node map (index is global shared node number).
void preallocateConnectedElements(int size)
void setParallelMode(dofManagerParallelMode _mode)
void setPartitions(IntArray _p)
const IntArray * giveConnectedElements()
void giveSideNodes(int iside, IntArray &snodes) override
int giveEdgeIndex(int iNode, int jNode) override
void makeSharedEdges() override
bool isNeighborOf(Subdivision ::RS_Element *elem) override
bool isNeighborOf(Subdivision ::RS_Element *elem) override
int giveEdgeIndex(int iNode, int jNode) override
void assignGlobalNumbersToSharedIrregulars()
std ::queue< int > subdivqueue
std ::list< int > sharedEdgesQueue
bool exchangeSharedIrregulars()
bool isNodeLocalIrregular(Subdivision ::RS_Node *node, int myrank)
void assignGlobalNumbersToElements(Domain *d)
void exchangeRemoteElements(Domain *d, IntArray &)
Subdivision(Domain *d)
Constructor.
bool isNodeLocalSharedIrregular(Subdivision ::RS_Node *node, int myrank)
Returns true if receiver is irregular, shared node locally maintatined.
std ::list< int > sharedIrregularsQueue
double getUtime()
Returns total user time elapsed in seconds.
Definition timer.C:105
void startTimer()
Definition timer.C:69
void stopTimer()
Definition timer.C:77
#define CM_DefinitionGlobal
Definition contextmode.h:48
#define CM_Definition
Definition contextmode.h:47
#define OOFEM_ERROR(...)
Definition error.h:79
#define OOFEM_LOG_INFO(...)
Definition logger.h:143
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
@ Element_remote
Element in active domain is only mirror of some remote element.
Definition element.h:89
@ Element_local
Element is local, there are no contributions from other domains to this element.
Definition element.h:88
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
@ DofManager_local
Definition dofmanager.h:67
@ DofManager_shared
Definition dofmanager.h:68
@ DofManager_null
Definition dofmanager.h:74
@ CBT_dynamic
ClassFactory & classFactory
@ NonlocalMaterialExtensionInterfaceType
void sort(IntArray &arry, operation op)
Definition intarray.h:423
double distance_square(const FloatArray &x, const FloatArray &y)
oofem::oofegGraphicContext gc[OOFEG_LAST_LAYER]
#define OOFEG_RAW_GEOMETRY_WIDTH
#define OOFEG_RAW_GEOMETRY_LAYER
#define SUBDIVISION_END_DATA
Definition subdivision.h:56
#define SUBDIVISION_SHARED_IRREGULAR_REC_TAG
Definition subdivision.h:55
#define SHARED_IRREGULAR_DATA_TAG
Definition subdivision.h:54
#define SUBDIVISION_SHARED_EDGE_REC_TAG
Definition subdivision.h:59
#define SUBDIVISION_MIGRATE_REMOTE_ELEMENTS_TAG
Definition subdivision.h:57
#define SHARED_EDGE_DATA_TAG
Definition subdivision.h:58

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011