Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmergrid/src/egparallel.c
3196 views
1
/*
2
ElmerGrid - A simple mesh generation and manipulation utility
3
Copyright (C) 1995- , CSC - IT Center for Science Ltd.
4
5
Author: Peter Raback
6
Email: [email protected]
7
Address: CSC - IT Center for Science Ltd.
8
Keilaranta 14
9
02101 Espoo, Finland
10
11
This program is free software; you can redistribute it and/or
12
modify it under the terms of the GNU General Public License
13
as published by the Free Software Foundation; either version 2
14
of the License, or (at your option) any later version.
15
16
This program is distributed in the hope that it will be useful,
17
but WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
GNU General Public License for more details.
20
21
You should have received a copy of the GNU General Public License
22
along with this program; if not, write to the Free Software
23
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
*/
25
26
/* -------------------------------: egparallel.c :----------------------------
27
This module includes routines related to parallel file format of Elmer suite.
28
*/
29
30
#include <stdio.h>
31
#include <unistd.h>
32
#include <stddef.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <math.h>
36
37
#if HAVE_UNISTD_H
38
#include <unistd.h>
39
#endif
40
41
#include <stdarg.h>
42
#include <sys/stat.h>
43
#include <sys/types.h>
44
45
#include "egutils.h"
46
#include "egdef.h"
47
#include "egtypes.h"
48
#include "egmesh.h"
49
#include "egparallel.h"
50
#include "../config.h"
51
52
#if USE_METIS
53
#include "metis-5.1.0/include/metis.h"
54
#endif
55
56
57
int FuseSolutionElmerPartitioned(char *prefix,char *outfile,int decimals,int parts,
58
int minstep, int maxstep, int dstep, int info)
59
{
60
#define LONGLINE 2048
61
int *noknots,*noelements,novctrs,elemcode;
62
int totknots,totelements,sumknots,sumelements;
63
int timesteps,i,j,k,l,step;
64
int ind[MAXNODESD3];
65
int nofiles,activestep;
66
Real *res, x, y, z;
67
FILE *in[MAXPARTITIONS+1],*intest,*out;
68
char line[LONGLINE],filename[MAXFILESIZE],text[MAXNAMESIZE],outstyle[MAXFILESIZE];
69
char *cp, *charend;
70
71
if(minstep || maxstep || dstep) {
72
if(info) printf("Saving results in the interval from %d to %d with step %d\n",minstep,maxstep,dstep);
73
}
74
75
for(i=0;;i++) {
76
sprintf(filename,"%s.ep.%d",prefix,i);
77
if ((intest = fopen(filename,"r")) == NULL) break;
78
if(i<=MAXPARTITIONS) in[i] = intest;
79
}
80
if(i > MAXPARTITIONS) {
81
printf("**********************************************************\n");
82
printf("Only data for %d partitions is fused (%d)\n",MAXPARTITIONS,i);
83
printf("**********************************************************\n");
84
i = MAXPARTITIONS;
85
}
86
nofiles = i;
87
88
if(nofiles < 2) {
89
printf("Opening of partitioned data from file %s wasn't successful!\n",
90
filename);
91
return(2);
92
} else {
93
if(parts > 0) nofiles = MIN(parts,nofiles);
94
if(info) printf("Loading Elmer results from %d partitions.\n",nofiles);
95
}
96
97
if(minstep || maxstep || dstep) {
98
if(info) printf("Saving results in the interval from %d to %d with step %d\n",minstep,maxstep,dstep);
99
}
100
101
noknots = Ivector(0,nofiles-1);
102
noelements = Ivector(0,nofiles-1);
103
104
sumknots = 0;
105
sumelements = 0;
106
107
for(i=0;i<nofiles;i++) {
108
charend = fgets(line,LONGLINE,in[i]);
109
if(i==0) {
110
cp = line;
111
noknots[i] = next_int(&cp);
112
noelements[i] = next_int(&cp);
113
novctrs = next_int(&cp);
114
timesteps = next_int(&cp);
115
}
116
else {
117
sscanf(line,"%d %d",&noknots[i],&noelements[i]);
118
}
119
sumknots += noknots[i];
120
sumelements += noelements[i];
121
}
122
totknots = sumknots;
123
totelements = sumelements;
124
if(novctrs) res = Rvector(1,novctrs);
125
126
if(info) printf("There are %d nodes, %d elements and %d vectors.\n",totknots,sumelements,novctrs);
127
128
129
AddExtension(outfile,filename,"ep");
130
if(info) printf("Saving ElmerPost data to %s.\n",filename);
131
out = fopen(filename,"w");
132
if(out == NULL) {
133
printf("opening of file was not successful\n");
134
return(3);
135
}
136
137
i = timesteps;
138
if(minstep || maxstep || dstep) {
139
if ( dstep>1 ) {
140
i = 0;
141
for(step = minstep; step <= maxstep; step++)
142
if((step-minstep)%dstep==0) i++;
143
} else i=maxstep-minstep+1;
144
}
145
fprintf(out,"%d %d %d %d %s %s",totknots,totelements,novctrs+1,i,"scalar: Partition",cp);
146
147
if(info) printf("Reading and writing %d coordinates.\n",totknots);
148
sprintf(outstyle,"%%.%dg %%.%dg %%.%dg\n",decimals,decimals,decimals);
149
150
for(j=0; j < nofiles; j++) {
151
for(i=1; i <= noknots[j]; i++) {
152
do {
153
charend = fgets(line,LONGLINE,in[j]);
154
} while(line[0] == '#');
155
156
sscanf(line,"%le %le %le",&x,&y,&z);
157
fprintf(out,outstyle,x,y,z);
158
}
159
}
160
161
if(info) printf("Reading and writing %d element topologies.\n",totelements);
162
sumknots = 0;
163
164
for(j=0; j < nofiles; j++) {
165
for(i=1; i <= noelements[j]; i++) {
166
do {
167
charend = fgets(line,LONGLINE,in[j]);
168
} while (line[0] == '#');
169
170
sscanf(line,"%s",text);
171
cp = strstr(line," ");
172
173
elemcode = next_int(&cp);
174
175
for(k=0;k< elemcode%100 ;k++) {
176
/* Dirty trick for long lines */
177
l = strspn(cp," ");
178
if( l == 0) {
179
charend = fgets(line,LONGLINE,in[j]);
180
cp = line;
181
}
182
ind[k] = next_int(&cp);
183
}
184
if(elemcode == 102) elemcode = 101;
185
186
fprintf(out,"%s %d",text,elemcode);
187
for(k=0;k < elemcode%100 ;k++)
188
fprintf(out," %d",ind[k]+sumknots);
189
fprintf(out,"\n");
190
}
191
sumknots += noknots[j];
192
}
193
194
if(info) printf("Reading and writing %d degrees of freedom.\n",novctrs);
195
if(!novctrs) goto skip;
196
197
sprintf(outstyle,"%%.%dg ",decimals);
198
199
activestep = FALSE;
200
if(maxstep) timesteps = MIN(timesteps, maxstep);
201
202
for(step = 1; step <= timesteps; step++) {
203
204
if (step>=minstep) {
205
if ( dstep>0 ) {
206
activestep=((step-minstep)%dstep==0);
207
} else activestep=TRUE;
208
}
209
210
for(k=0;k<nofiles;k++)
211
for(i=1; i <= noknots[k]; i++) {
212
do {
213
charend = fgets(line,LONGLINE,in[k]);
214
if (activestep) {
215
if(k==0 && strstr(line,"#time")) {
216
fprintf(out,"%s",line);
217
fprintf(stderr,"%s",line);
218
}
219
}
220
}
221
while (line[0] == '#');
222
223
if(activestep) {
224
cp = line;
225
for(j=1;j <= novctrs;j++)
226
res[j] = next_real(&cp);
227
228
fprintf(out,"%d ",k+1);
229
for(j=1;j <= novctrs;j++)
230
fprintf(out,outstyle,res[j]);
231
fprintf(out,"\n");
232
}
233
234
}
235
}
236
237
238
skip:
239
for(i=0;i<nofiles;i++)
240
fclose(in[i]);
241
fclose(out);
242
243
if(info) printf("Successfully fused partitioned Elmer results\n");
244
245
return(0);
246
}
247
248
249
250
251
static int CreatePartitionTable(struct FemType *data,int info)
252
{
253
int i,j,k,m,noelements,noknots,partitions,nonodes,periodic;
254
int maxneededtimes,sharings,part,ind,hit,notinany,debug;
255
int *indxper;
256
257
printf("Creating a table showing all parenting partitions of nodes.\n");
258
259
if(data->maxpartitiontable) {
260
printf("The partition table already exists!\n");
261
smallerror("Partition table not done");
262
return(0);
263
}
264
265
partitions = data->nopartitions;
266
if( partitions <= 1 ) {
267
bigerror("Cannot do partition table for less than two partitions");
268
}
269
270
271
noelements = data->noelements;
272
periodic = data->periodicexist;
273
noknots = data->noknots;
274
if(periodic) indxper = data->periodic;
275
276
maxneededtimes = 0;
277
sharings = 0;
278
279
/* Make the partition list taking into account periodicity */
280
for(i=1;i<=noelements;i++) {
281
part = data->elempart[i];
282
nonodes = data->elementtypes[i] % 100;
283
284
for(j=0;j < nonodes;j++) {
285
ind = data->topology[i][j];
286
if(periodic) ind = indxper[ind];
287
288
debug = FALSE;
289
if(debug) printf("ind=%d i=%d j=%d part=%d\n",ind,i,j,part);
290
291
hit = 0;
292
for(k=1;k<=maxneededtimes;k++) {
293
if(data->partitiontable[k][ind] == 0) hit = k;
294
if(data->partitiontable[k][ind] == part) hit = -k;
295
if(hit) break;
296
}
297
if( hit > 0) {
298
data->partitiontable[hit][ind] = part;
299
if(hit == 2) sharings++;
300
}
301
else if(hit == 0) {
302
maxneededtimes++;
303
data->partitiontable[maxneededtimes] = Ivector(1,noknots);
304
for(m=1;m<=noknots;m++)
305
data->partitiontable[maxneededtimes][m] = 0;
306
data->partitiontable[maxneededtimes][ind] = part;
307
if(maxneededtimes == 2) sharings++;
308
}
309
if(debug) printf("hit = %d\n",hit);
310
}
311
}
312
313
314
/* Make the partitiontable such that the owner node is the first one in the list */
315
notinany = 0;
316
for(i=1;i<=noknots;i++) {
317
318
/* Skip the periodic nodes and take care of them later */
319
if(periodic)
320
if(i != indxper[i]) continue;
321
322
hit = FALSE;
323
for(k=1;k<=maxneededtimes;k++) {
324
if(!data->partitiontable[k][i]) break;
325
if(data->partitiontable[k][i] == data->nodepart[i]) {
326
hit = k;
327
break;
328
}
329
}
330
if( hit > 1 ) {
331
data->partitiontable[hit][i] = data->partitiontable[1][i];
332
data->partitiontable[1][i] = data->nodepart[i];
333
}
334
else if(!hit) {
335
if(0) {
336
printf("Node %d in partition %d not in the table!\n",i,data->nodepart[i]);
337
if(periodic) printf("indexper: %d\n",indxper[i]);
338
}
339
340
notinany++;
341
data->nodepart[i] = data->partitiontable[1][i];
342
}
343
}
344
345
346
/* For periodic counterparts copy the table and ownership */
347
if(periodic) {
348
for(i=1;i<=noknots;i++) {
349
ind = indxper[i];
350
if(ind == i) continue;
351
for(k=1;k<=maxneededtimes;k++) {
352
if( !data->partitiontable[k][ind] ) break;
353
data->partitiontable[k][i] = data->partitiontable[k][ind];
354
}
355
data->nodepart[i] = data->nodepart[ind];
356
}
357
}
358
359
360
if(info) {
361
printf("Nodes belong to %d partitions in maximum\n",maxneededtimes);
362
printf("There are %d shared nodes which is %.2f %% of all nodes.\n",
363
sharings,(100.*sharings)/noknots);
364
printf("The initial owner was not any of the elements for %d nodes\n",notinany);
365
}
366
367
368
if(0) for(i=1;i<=noknots;i++) {
369
if(data->partitiontable[maxneededtimes][i]) {
370
printf("node %d parts: ",i);
371
for(k=1;k<=maxneededtimes;k++)
372
printf("%d ",data->partitiontable[k][i]);
373
printf("\n");
374
}
375
}
376
377
data->maxpartitiontable = maxneededtimes;
378
data->partitiontableexists = TRUE;
379
return(0);
380
}
381
382
383
384
static int PartitionElementsByNodes(struct FemType *data,int info)
385
/* Given nodal partitioning determine the elemental partitioning.
386
This is usually suboptimal, it is preferable to do the other way around. */
387
{
388
int i,j,noelements,nopartitions,part,maxpart,maxpart2,minpart;
389
int *elempart,*nodepart,*nodesinpart,*cuminpart,**knows,**cumknows,set;
390
391
if(!data->partitionexist) return(1);
392
393
noelements = data->noelements;
394
nopartitions = data->nopartitions;
395
elempart = data->elempart;
396
nodepart = data->nodepart;
397
398
nodesinpart = Ivector(1,nopartitions);
399
cuminpart = Ivector(1,nopartitions);
400
for(j=1;j<=nopartitions;j++)
401
cuminpart[j] = 0;
402
403
knows = Imatrix(1,nopartitions,1,nopartitions);
404
cumknows = Imatrix(1,nopartitions,1,nopartitions);
405
for(i=1;i<=nopartitions;i++)
406
for(j=1;j<=nopartitions;j++)
407
knows[i][j] = cumknows[i][j] = 0;
408
409
set = FALSE;
410
411
omstart:
412
413
/* In the first round count the equally joined elements and
414
on the second round split them equally using cumulative numbering */
415
416
for(i=1;i<=noelements;i++) {
417
for(j=1;j<=nopartitions;j++)
418
nodesinpart[j] = 0;
419
for(j=0;j<data->elementtypes[i] % 100;j++) {
420
part = nodepart[data->topology[i][j]];
421
nodesinpart[part] += 1;
422
}
423
maxpart = maxpart2 = 1;
424
for(j=1;j<=nopartitions;j++)
425
if(nodesinpart[j] > nodesinpart[maxpart]) maxpart = j;
426
if(maxpart == 1) maxpart2 = 2;
427
for(j=1;j<=nopartitions;j++) {
428
if(j == maxpart) continue;
429
if(nodesinpart[j] > nodesinpart[maxpart2]) maxpart2 = j;
430
}
431
432
if(nodesinpart[maxpart] > nodesinpart[maxpart2]) {
433
if(set)
434
elempart[i] = maxpart;
435
else
436
cuminpart[maxpart] += 1;
437
}
438
else {
439
if(set) {
440
cumknows[maxpart][maxpart2] += 1;
441
if( cumknows[maxpart][maxpart2] > knows[maxpart][maxpart2] / 2) {
442
elempart[i] = maxpart2;
443
cuminpart[maxpart2] += 1;
444
}
445
else {
446
elempart[i] = maxpart;
447
cuminpart[maxpart] += 1;
448
}
449
}
450
else
451
knows[maxpart][maxpart2] += 1;
452
}
453
}
454
455
if(!set) {
456
set = TRUE;
457
goto omstart;
458
}
459
460
minpart = maxpart = cuminpart[1];
461
for(j=1;j<=nopartitions;j++) {
462
minpart = MIN( minpart, cuminpart[j]);
463
maxpart = MAX( maxpart, cuminpart[j]);
464
}
465
466
if(info) {
467
printf("Set the element partitions by the dominating nodal partition\n");
468
printf("There are from %d to %d elements in the %d partitions.\n",minpart,maxpart,nopartitions);
469
}
470
471
free_Ivector(nodesinpart,1,nopartitions);
472
free_Ivector(cuminpart,1,nopartitions);
473
free_Imatrix(knows,1,nopartitions,1,nopartitions);
474
free_Imatrix(cumknows,1,nopartitions,1,nopartitions);
475
476
return(0);
477
}
478
479
480
static int PartitionNodesByElements(struct FemType *data,int info)
481
/* Given the elemental partitioning set the nodal ownership.
482
This is optimal for Elmer since the elemental partitioning is primary. */
483
{
484
int i,j,k,noknots,nopartitions,part,minpart,maxpart;
485
int maxpart2,*cuminpart,**knows,**cumknows,set;
486
int *elempart,*nodepart,*nodesinpart;
487
int *invrow,*invcol;
488
489
if(!data->partitionexist) return(1);
490
491
CreateInverseTopology(data, info);
492
493
invrow = data->invtopo.rows;
494
invcol = data->invtopo.cols;
495
496
noknots = data->noknots;
497
nopartitions = data->nopartitions;
498
elempart = data->elempart;
499
nodepart = data->nodepart;
500
501
if(info) printf("Number of nodal partitions: %d\n",nopartitions);
502
503
nodesinpart = Ivector(1,nopartitions);
504
cuminpart = Ivector(1,nopartitions);
505
for(j=1;j<=nopartitions;j++)
506
cuminpart[j] = 0;
507
508
knows = Imatrix(1,nopartitions,1,nopartitions);
509
cumknows = Imatrix(1,nopartitions,1,nopartitions);
510
for(i=1;i<=nopartitions;i++)
511
for(j=1;j<=nopartitions;j++)
512
knows[i][j] = cumknows[i][j] = 0;
513
514
set = FALSE;
515
516
omstart:
517
518
for(i=1;i<=noknots;i++) {
519
520
for(j=1;j<=nopartitions;j++)
521
nodesinpart[j] = 0;
522
523
/* Tag the number of owner partitions */
524
for(j=invrow[i-1];j<invrow[i];j++) {
525
k = invcol[j]+1;
526
part = elempart[k];
527
if( part > 0 ) nodesinpart[part] += 1;
528
}
529
530
/* Find the partition with maximum number of hits */
531
maxpart = maxpart2 = 0;
532
for(j=1;j<=nopartitions;j++)
533
if(nodesinpart[j] > 0 ) {
534
if(!maxpart) {
535
maxpart = j;
536
}
537
else if(nodesinpart[j] > nodesinpart[maxpart]) {
538
maxpart = j;
539
}
540
}
541
542
/* Find the partition with 2nd largest number of hits */
543
for(j=1;j<=nopartitions;j++)
544
if(nodesinpart[j] > 0 ) {
545
if(j == maxpart) continue;
546
if(!maxpart2) {
547
maxpart2 = j;
548
}
549
else if(nodesinpart[j] > nodesinpart[maxpart2]) {
550
maxpart2 = j;
551
}
552
}
553
554
/* If there is a clear dominator use that */
555
if(!maxpart && !maxpart2)
556
printf("Node is not included in any partition: %d\n",i);
557
else if(!maxpart2) {
558
nodepart[i] = maxpart;
559
cuminpart[maxpart] += 1;
560
}
561
else
562
if(nodesinpart[maxpart] > nodesinpart[maxpart2]) {
563
if(set)
564
nodepart[i] = maxpart;
565
else
566
cuminpart[maxpart] += 1;
567
}
568
569
/* Otherwise make a half and half split between the major owners */
570
else {
571
if(set) {
572
cumknows[maxpart][maxpart2] += 1;
573
if( cumknows[maxpart][maxpart2] > knows[maxpart][maxpart2] / 2) {
574
nodepart[i] = maxpart2;
575
cuminpart[maxpart2] += 1;
576
}
577
else {
578
nodepart[i] = maxpart;
579
cuminpart[maxpart] += 1;
580
}
581
}
582
else {
583
knows[maxpart][maxpart2] += 1;
584
}
585
}
586
}
587
588
if(!set) {
589
set = TRUE;
590
goto omstart;
591
}
592
593
minpart = maxpart = cuminpart[1];
594
for(j=1;j<=nopartitions;j++) {
595
minpart = MIN( minpart, cuminpart[j]);
596
maxpart = MAX( maxpart, cuminpart[j]);
597
}
598
599
if(info) {
600
printf("Set the node partitions by the dominating element partition.\n");
601
printf("There are from %d to %d nodes in the %d partitions.\n",minpart,maxpart,nopartitions);
602
}
603
604
free_Ivector(nodesinpart,1,nopartitions);
605
free_Ivector(cuminpart,1,nopartitions);
606
free_Imatrix(knows,1,nopartitions,1,nopartitions);
607
free_Imatrix(cumknows,1,nopartitions,1,nopartitions);
608
609
return(0);
610
}
611
612
613
614
int PartitionSimpleElements(struct FemType *data,struct ElmergridType *eg,struct BoundaryType *bound,
615
int dimpart[],int dimper[],int partorder, Real corder[],
616
Real parttol, int info)
617
/* Partition elements recursively in major directions.
618
This may be the optimal method of partitioning for simple geometries. */
619
{
620
int i,j,k,l,kprev,ind,minpart,maxpart;
621
int noknots,noelements,nonodes,elemsinpart,periodic;
622
int partitions1,partitions2,partitions3,partitions;
623
int vpartitions1,vpartitions2,vpartitions3,vpartitions;
624
int noelements0,noelements1,noparts0;
625
int *indx,*nopart,*inpart,*elemconnect;
626
Real *arrange;
627
Real x,y,z,cx,cy,cz;
628
629
if(info) printf("PartitionSimpleElements\n");
630
631
noelements = data->noelements;
632
noknots = data->noknots;
633
634
partitions1 = dimpart[0];
635
partitions2 = dimpart[1];
636
partitions3 = dimpart[2];
637
if(data->dim < 3) partitions3 = 1;
638
partitions = partitions1 * partitions2 * partitions3;
639
640
if(partitions1 < 2 && partitions2 < 2 && partitions3 < 2 && !eg->connect) {
641
printf("Some of the divisions must be larger than one: %d %d %d\n",
642
partitions1, partitions2, partitions3 );
643
bigerror("Partitioning not performed");
644
}
645
646
if(partitions >= noelements) {
647
printf("There must be fever partitions than elements (%d vs %d)!\n",
648
partitions,noelements);
649
bigerror("Partitioning not performed");
650
}
651
652
if( eg->partbcz > 1 || eg->partbcr )
653
PartitionConnectedElements1D(data,bound,eg,info);
654
else if( eg->partbcmetis > 1 )
655
PartitionConnectedElementsMetis(data,bound,eg,eg->partbcmetis,3,info);
656
else if( eg->connect )
657
PartitionConnectedElementsStraight(data,bound,eg,info);
658
659
660
if( data->nodeconnectexist )
661
ExtendBoundaryPartitioning(data,bound,eg->partbclayers,info);
662
663
if(!data->partitionexist) {
664
data->partitionexist = TRUE;
665
data->elempart = Ivector(1,noelements);
666
data->nodepart = Ivector(1,noknots);
667
data->nopartitions = partitions;
668
}
669
inpart = data->elempart;
670
671
vpartitions1 = partitions1;
672
vpartitions2 = partitions2;
673
vpartitions3 = partitions3;
674
675
if(0) printf("connect: %d %d\n",data->elemconnectexist,data->nodeconnectexist);
676
677
noparts0 = 0;
678
noelements0 = 0;
679
if( data->elemconnectexist || data->nodeconnectexist) {
680
elemconnect = data->elemconnect;
681
noparts0 = 0;
682
for(i=1;i<=data->noelements;i++) {
683
if( elemconnect[i] ) noelements0 = noelements0 + 1;
684
noparts0 = MAX( noparts0, elemconnect[i] );
685
}
686
if(info) printf("There are %d initial partitions in the connected mesh\n",noparts0);
687
if(info) printf("There are %d initial elements in the connected mesh\n",noelements0);
688
}
689
noelements1 = noelements - noelements0;
690
691
vpartitions1 = partitions1;
692
vpartitions2 = partitions2;
693
vpartitions3 = partitions3;
694
695
periodic = dimper[0] || dimper[1] || dimper[2];
696
if(periodic) {
697
if(dimper[0] && partitions1 > 1) vpartitions1 *= 2;
698
if(dimper[1] && partitions2 > 1) vpartitions2 *= 2;
699
if(dimper[2] && partitions3 > 1) vpartitions3 *= 2;
700
}
701
vpartitions = vpartitions1 * vpartitions2 * vpartitions3;
702
nopart = Ivector(1,vpartitions+noparts0);
703
704
if( vpartitions == 1 && data->elemconnectexist ) {
705
if(info) printf("Only one regular partitions requested, skipping 2nd part of hybrid partitioning\n");
706
for(j=1;j<=noelements;j++) {
707
if( elemconnect[j] > 0 )
708
inpart[j] = elemconnect[j];
709
else
710
inpart[j] = noparts0 + 1;
711
}
712
partitions = noparts0 + 1;
713
data->nopartitions = partitions;
714
goto skippart;
715
}
716
717
718
719
if(info) printf("Making a simple partitioning for %d elements in %d-dimensions.\n",
720
noelements1,data->dim);
721
722
arrange = Rvector(1,noelements);
723
indx = Ivector(1,noelements);
724
725
if(partorder) {
726
cx = corder[0];
727
cy = corder[1];
728
cz = corder[2];
729
}
730
else {
731
cx = 1.0;
732
cy = 0.0001;
733
cz = cy*cy;
734
}
735
z = 0.0;
736
737
for(i=1;i<=noelements;i++)
738
inpart[i] = 1;
739
740
if(vpartitions1 > 1) {
741
742
if(info) printf("Ordering 1st direction with (%.3lg*x + %.3lg*y + %.3lg*z)\n",cx,cy,cz);
743
744
for(j=1;j<=noelements;j++) {
745
if( data->elemconnectexist ) {
746
if( elemconnect[j] > 0 ) {
747
arrange[j] = 1.0e9;
748
continue;
749
}
750
}
751
nonodes = data->elementtypes[j]%100;
752
x = y = z = 0.0;
753
for(i=0;i<nonodes;i++) {
754
k = data->topology[j][i];
755
x += data->x[k];
756
y += data->y[k];
757
z += data->z[k];
758
}
759
arrange[j] = (cx*x + cy*y + cz*z) / nonodes;
760
}
761
762
SortIndex(noelements,arrange,indx);
763
764
for(i=1;i<=noelements1;i++) {
765
ind = indx[i];
766
k = (i*vpartitions1-1)/noelements1+1;
767
inpart[ind] = k;
768
}
769
}
770
771
772
/* Partition in the 2nd direction taking into account the 1st direction */
773
if(vpartitions2 > 1) {
774
if(info) printf("Ordering in the 2nd direction.\n");
775
776
for(j=1;j<=noelements;j++) {
777
if( data->elemconnectexist ) {
778
if( elemconnect[j] > 0 ) {
779
arrange[j] = 1.0e9;
780
continue;
781
}
782
}
783
nonodes = data->elementtypes[j]%100;
784
x = y = z = 0.0;
785
for(i=0;i<nonodes;i++) {
786
k = data->topology[j][i];
787
x += data->x[k];
788
y += data->y[k];
789
z += data->z[k];
790
}
791
arrange[j] = (-cy*x + cx*y + cz*z) / nonodes;
792
}
793
SortIndex(noelements,arrange,indx);
794
795
for(i=1;i<=vpartitions;i++)
796
nopart[i] = 0;
797
798
elemsinpart = noelements1 / (vpartitions1*vpartitions2);
799
for(i=1;i<=noelements1;i++) {
800
j = 0;
801
ind = indx[i];
802
do {
803
j++;
804
k = (inpart[ind]-1) * vpartitions2 + j;
805
}
806
while(nopart[k] >= elemsinpart && j < vpartitions2);
807
808
nopart[k] += 1;
809
inpart[ind] = (inpart[ind]-1)*vpartitions2 + j;
810
}
811
}
812
813
/* Partition in the 3rd direction taking into account the 1st and 2nd direction */
814
if(vpartitions3 > 1) {
815
if(info) printf("Ordering in the 3rd direction.\n");
816
817
for(j=1;j<=noelements;j++) {
818
if( data->elemconnectexist ) {
819
if( elemconnect[j] > 0 ) {
820
arrange[j] = 1.0e9;
821
continue;
822
}
823
}
824
825
nonodes = data->elementtypes[j]%100;
826
x = y = z = 0.0;
827
for(i=0;i<nonodes;i++) {
828
k = data->topology[j][i];
829
x += data->x[k];
830
y += data->y[k];
831
z += data->z[k];
832
}
833
arrange[j] = (-cz*x - cy*y + cx*z) / nonodes;
834
}
835
836
SortIndex(noelements,arrange,indx);
837
838
for(i=1;i<=vpartitions;i++)
839
nopart[i] = 0;
840
841
elemsinpart = noelements1 / (vpartitions1*vpartitions2*vpartitions3);
842
for(i=1;i<=noelements1;i++) {
843
j = 0;
844
ind = indx[i];
845
do {
846
j++;
847
k = (inpart[ind]-1)*vpartitions3 + j;
848
}
849
while(nopart[k] >= elemsinpart && j < vpartitions3);
850
851
nopart[k] += 1;
852
inpart[ind] = (inpart[ind]-1)*vpartitions3 + j;
853
}
854
}
855
856
/* This piece of code may be used to assign "strides" back to same partition.
857
After performing the geometric partitioning we revisit whether elements
858
are too close to each other and yet in different partition in the chosen measure.
859
For example, if chosen measure has the smallest coefficient in z-direction then
860
a suitable value will revert elements to being on the same stride. */
861
if(parttol > 1.0e-20 ) {
862
if(0) {
863
printf("Original partition counts:\n");
864
for(i=1;i<=partitions;i++)
865
printf("nopart[%d] = %d\n",i,nopart[i]);
866
}
867
868
for(j=1;j<=noelements;j++) {
869
if( data->elemconnectexist ) {
870
if( elemconnect[j] > 0 ) {
871
arrange[j] = 1.0e9;
872
continue;
873
}
874
}
875
nonodes = data->elementtypes[j]%100;
876
x = y = z = 0.0;
877
for(i=0;i<nonodes;i++) {
878
k = data->topology[j][i];
879
x += data->x[k];
880
y += data->y[k];
881
z += data->z[k];
882
}
883
arrange[j] = (cx*x + cy*y + cz*z) / nonodes;
884
}
885
SortIndex(noelements,arrange,indx);
886
887
kprev = inpart[indx[1]];
888
l = 0;
889
for(i=2;i<=noelements1;i++) {
890
ind = indx[i];
891
k = inpart[ind];
892
if(k != kprev ) {
893
if(fabs(arrange[i]-arrange[i-1]) < parttol ) {
894
nopart[k] -= 1;
895
nopart[kprev] += 1;
896
inpart[ind] = kprev;
897
k = kprev;
898
if(0) printf("arrange %d %d %d %d %.6lg %.6lg\n",i,ind,k,kprev,arrange[i],arrange[i-1]);
899
l++;
900
}
901
}
902
kprev = k;
903
}
904
if(0) {
905
printf("Updated partition counts:\n");
906
for(i=1;i<=partitions;i++)
907
printf("nopart[%d] = %d\n",i,nopart[i]);
908
}
909
if(info) printf("Number of partition changes due to tolerance: %d\n",l);
910
}
911
912
913
free_Rvector(arrange,1,noelements);
914
free_Ivector(indx,1,noelements);
915
916
917
if( data->elemconnectexist ) {
918
for(j=1;j<=noelements;j++) {
919
if( elemconnect[j] > 0 )
920
inpart[j] = elemconnect[j];
921
else
922
inpart[j] = inpart[j] + noparts0;
923
}
924
partitions = partitions + noparts0;
925
data->nopartitions = partitions;
926
}
927
928
929
/* For periodic systems the number of virtual partitions is larger. Now map the mesh so that the
930
1st and last partition for each direction will be joined */
931
if(periodic) {
932
int *partmap;
933
int p1,p2,p3,q1,q2,q3;
934
int P,Q;
935
936
if(data->elemconnectexist ) {
937
bigerror("Cannot use connect flag with periodic systems\n");
938
}
939
940
p1=p2=p3=1;
941
partmap = Ivector(1,vpartitions);
942
for(i=1;i<=vpartitions;i++)
943
partmap[i] = 0;
944
for(p1=1;p1<=vpartitions1;p1++) {
945
q1 = p1;
946
if(dimper[0] && vpartitions1 > 1) {
947
if(q1==vpartitions1) q1 = 0;
948
q1 = q1/2 + 1;
949
}
950
for(p2=1;p2<=vpartitions2;p2++) {
951
q2 = p2;
952
if(dimper[1] && vpartitions2 > 1) {
953
if(q2==vpartitions2) q2 = 0;
954
q2 = q2/2 + 1;
955
}
956
for(p3=1;p3<=vpartitions3;p3++) {
957
q3 = p3;
958
if(dimper[2] && vpartitions3 > 1) {
959
if(q3==vpartitions3) q3 = 0;
960
q3 = q3/2 + 1;
961
}
962
963
P = vpartitions3 * vpartitions2 * (p1 - 1) + vpartitions3 * (p2-1) + p3;
964
Q = partitions3 * partitions2 * (q1 - 1) + partitions3 * (q2-1) + q3;
965
966
partmap[P] = Q;
967
}
968
}
969
}
970
for(i=1;i<=noelements;i++)
971
inpart[i] = partmap[inpart[i]];
972
free_Ivector(partmap,1,vpartitions);
973
}
974
975
skippart:
976
977
for(i=1;i<=partitions;i++)
978
nopart[i] = 0;
979
for(i=1;i<=noelements;i++)
980
nopart[inpart[i]] += 1;
981
982
minpart = maxpart = nopart[1];
983
for(i=1;i<=partitions;i++) {
984
minpart = MIN( nopart[i], minpart );
985
maxpart = MAX( nopart[i], maxpart );
986
}
987
988
free_Ivector(nopart,1,vpartitions);
989
PartitionNodesByElements(data,info);
990
991
if(info) printf("Successfully made a partitioning with %d to %d elements.\n",minpart,maxpart);
992
993
return(0);
994
}
995
996
997
int PartitionSimpleElementsNonRecursive(struct FemType *data,int dimpart[],int dimper[],
998
int info)
999
/* This is similar to the previous except the partitioning is not recursive.
1000
This kind of partitioning is optimal for uniform grids with blockwise structure.
1001
An example would be L-type geometry where 3/4 of potential partitions would be active. */
1002
{
1003
int i,j,k,minpart,maxpart;
1004
int noknots, noelements,nonodes,periodic;
1005
int partitions1,partitions2,partitions3,partitions;
1006
int IndX,IndY,IndZ;
1007
int *nopart,*inpart;
1008
Real x,y,z,MaxX,MinX,MaxY,MinY,MaxZ,MinZ;
1009
1010
partitions1 = dimpart[0];
1011
partitions2 = dimpart[1];
1012
partitions3 = dimpart[2];
1013
if(data->dim < 3) partitions3 = 1;
1014
partitions = partitions1 * partitions2 * partitions3;
1015
1016
if(partitions1 < 2 && partitions2 < 2 && partitions3 < 2) {
1017
printf("Some of the divisions must be larger than one: %d %d %d\n",
1018
partitions1, partitions2, partitions3 );
1019
bigerror("Partitioning not performed");
1020
}
1021
1022
if(!data->partitionexist) {
1023
data->partitionexist = TRUE;
1024
data->elempart = Ivector(1,data->noelements);
1025
data->nodepart = Ivector(1,data->noknots);
1026
data->nopartitions = partitions;
1027
}
1028
inpart = data->elempart;
1029
noelements = data->noelements;
1030
noknots = data->noknots;
1031
1032
periodic = dimper[0] || dimper[1] || dimper[2];
1033
if(periodic) {
1034
printf("Implement periodicity for this partitioning routine!\n");
1035
}
1036
1037
if(info) {
1038
printf("Making a simple partitioning for %d elements in %d-dimensions.\n",
1039
noelements,data->dim);
1040
printf("There can be at maximum %d partitions\n",partitions);
1041
}
1042
1043
nopart = Ivector(1,partitions);
1044
for(i=1;i<=partitions;i++)
1045
nopart[i] = 0;
1046
1047
z = 0.0;
1048
IndZ = 1;
1049
for(i=1;i<=noelements;i++)
1050
inpart[i] = 0;
1051
1052
MaxX = MinX = data->x[1];
1053
MaxY = MinY = data->y[1];
1054
MaxZ = MinZ = data->z[1];
1055
1056
for(i=1;i<=noknots;i++) {
1057
x = data->x[i];
1058
y = data->y[i];
1059
z = data->z[i];
1060
1061
MaxX = MAX( MaxX, x);
1062
MinX = MIN( MinX, x);
1063
MaxY = MAX( MaxY, y);
1064
MinY = MIN( MinY, y);
1065
MaxZ = MAX( MaxZ, z);
1066
MinZ = MIN( MinZ, z);
1067
}
1068
if( info ) {
1069
printf("Range in x-direction: %12.5le %12.5le\n",MinX,MaxX);
1070
printf("Range in y-direction: %12.5le %12.5le\n",MinY,MaxY);
1071
printf("Range in z-direction: %12.5le %12.5le\n",MinZ,MaxZ);
1072
}
1073
1074
for(j=1;j<=noelements;j++) {
1075
nonodes = data->elementtypes[j]%100;
1076
x = y = z = 0.0;
1077
for(i=0;i<nonodes;i++) {
1078
k = data->topology[j][i];
1079
x += data->x[k];
1080
y += data->y[k];
1081
z += data->z[k];
1082
}
1083
x = x / nonodes;
1084
y = y / nonodes;
1085
z = z / nonodes;
1086
1087
IndX = ceil( partitions1 * ( x - MinX ) / ( MaxX - MinX ) );
1088
IndY = ceil( partitions2 * ( y - MinY ) / ( MaxY - MinY ) );
1089
if( data->dim == 3 ) {
1090
IndZ = ceil( partitions3 * ( z - MinZ ) / ( MaxZ - MinZ ) );
1091
}
1092
k = (IndZ-1) * partitions1 * partitions2 +
1093
(IndY-1) * partitions1 + IndX;
1094
1095
inpart[j] = k;
1096
nopart[k] += 1;
1097
}
1098
1099
maxpart = 0;
1100
minpart = noelements;
1101
j = 0;
1102
if( info ) printf("Renumbering the partitions (showing only 64):\n");
1103
for(i=1;i<=partitions;i++) {
1104
k = nopart[i];
1105
if( k ) {
1106
maxpart = MAX( k, maxpart );
1107
minpart = MIN( k, minpart );
1108
j += 1;
1109
nopart[i] = j;
1110
if( info && j<=64) printf("%d -> %d\n",i,j);
1111
}
1112
}
1113
if(info) printf("There are %d active partitions out of %d possible ones\n",j,partitions);
1114
1115
data->nopartitions = j;
1116
1117
for(i=1;i<=noelements;i++) {
1118
j = inpart[i];
1119
inpart[i] = nopart[j];
1120
}
1121
1122
free_Ivector(nopart,1,partitions);
1123
1124
PartitionNodesByElements(data,info);
1125
1126
if(info) printf("Successfully made a partitioning with %d to %d elements.\n",minpart,maxpart);
1127
1128
return(0);
1129
}
1130
1131
1132
#define MAXCATEGORY 500
1133
int PartitionSimpleElementsRotational(struct FemType *data,int dimpart[],int dimper[],
1134
int info) {
1135
int i,j,k,minpart,maxpart,dim,hit;
1136
int noknots, noelements,nonodes,periodic;
1137
int partitions1,partitions2,partitions3,partitions;
1138
int IndR,IndF,IndZ,connect;
1139
int *nopart,*inpart,*cumf,*cumr,*cumz = NULL,*elemconnect = NULL;
1140
Real x,y,z,r,f,MaxR,MinR,MaxF,MinF,MaxZ,MinZ;
1141
1142
dim = data->dim;
1143
partitions1 = dimpart[0];
1144
partitions2 = dimpart[1];
1145
partitions3 = dimpart[2];
1146
if(dim < 3) partitions3 = 1;
1147
partitions = partitions1 * partitions2 * partitions3;
1148
1149
/* See if there are connected elements */
1150
connect = FALSE;
1151
if(data->nodeconnectexist) {
1152
SetConnectedElements(data,info);
1153
connect = TRUE;
1154
elemconnect = data->elemconnect;
1155
partitions = partitions + partitions3;
1156
}
1157
1158
if(partitions1 < 2 && partitions2 < 2 && partitions3 < 2) {
1159
printf("Some of the divisions must be larger than one: %d %d %d\n",
1160
partitions1, partitions2, partitions3 );
1161
bigerror("Partitioning not performed");
1162
}
1163
1164
if(!data->partitionexist) {
1165
data->partitionexist = TRUE;
1166
data->elempart = Ivector(1,data->noelements);
1167
data->nodepart = Ivector(1,data->noknots);
1168
data->nopartitions = partitions;
1169
}
1170
inpart = data->elempart;
1171
noelements = data->noelements;
1172
noknots = data->noknots;
1173
1174
periodic = dimper[0] || dimper[1] || dimper[2];
1175
if(periodic) {
1176
printf("Implement periodicity for this partitioning routine!\n");
1177
}
1178
1179
if(info) {
1180
printf("Making a simple rotational partitioning for %d elements in %d-dimensions.\n",
1181
noelements,data->dim);
1182
printf("There can be at maximum %d partitions\n",partitions);
1183
}
1184
1185
nopart = Ivector(1,partitions);
1186
for(i=1;i<=partitions;i++)
1187
nopart[i] = 0;
1188
1189
z = 0.0;
1190
IndZ = 1;
1191
for(i=1;i<=noelements;i++)
1192
inpart[i] = 0;
1193
1194
x = data->x[1];
1195
y = data->y[1];
1196
z = data->z[1];
1197
1198
r = sqrt(x*x+y*y);
1199
f = 180 * atan2(y,x)/FM_PI;
1200
if( f < 0.0 ) f = f + 360.0;
1201
MaxR = MinR = r;
1202
MaxF = MinF = f;
1203
MaxZ = MinZ = z;
1204
1205
for(i=1;i<=noknots;i++) {
1206
x = data->x[i];
1207
y = data->y[i];
1208
z = data->z[i];
1209
1210
r = sqrt(x*x+y*y);
1211
f = 180 * atan2(y,x)/FM_PI;
1212
if( f < 0.0 ) f = f + 360.0;
1213
1214
MaxR = MAX( MaxR, r);
1215
MinR = MIN( MinR, r);
1216
MaxF = MAX( MaxF, f);
1217
MinF = MIN( MinF, f);
1218
MaxZ = MAX( MaxZ, z);
1219
MinZ = MIN( MinZ, z);
1220
}
1221
1222
if( info ) {
1223
printf("Range in r-direction: %12.5le %12.5le\n",MinR,MaxR);
1224
printf("Range in f-direction: %12.5le %12.5le\n",MinF,MaxF);
1225
printf("Range in z-direction: %12.5le %12.5le\n",MinZ,MaxZ);
1226
}
1227
if( MaxF - MinF > 180.0 ) {
1228
MaxF = 360.0;
1229
MinF = 0.0;
1230
}
1231
1232
/* Zero is the 1st value so that recursive algos can be used. */
1233
cumr = Ivector(0,MAXCATEGORY);
1234
cumf = Ivector(0,MAXCATEGORY);
1235
if(dim==3) cumz = Ivector(0,MAXCATEGORY);
1236
1237
for(i=0;i<=MAXCATEGORY;i++) {
1238
cumf[i] = cumr[i] = 0;
1239
if( dim == 3) cumz[i] = 0;
1240
}
1241
1242
for(j=1;j<=noelements;j++) {
1243
nonodes = data->elementtypes[j]%100;
1244
x = y = z = 0.0;
1245
for(i=0;i<nonodes;i++) {
1246
k = data->topology[j][i];
1247
x += data->x[k];
1248
y += data->y[k];
1249
z += data->z[k];
1250
}
1251
x = x / nonodes;
1252
y = y / nonodes;
1253
z = z / nonodes;
1254
1255
r = sqrt(x*x+y*y);
1256
f = 180 * atan2(y,x)/FM_PI;
1257
if( f < 0.0 ) f = f + 360.0;
1258
1259
IndR = ceil( MAXCATEGORY * ( r - MinR ) / ( MaxR - MinR ) );
1260
IndF = ceil( MAXCATEGORY * ( f - MinF ) / ( MaxF - MinF ) );
1261
if(dim==3) IndZ = ceil( MAXCATEGORY * ( z - MinZ ) / ( MaxZ - MinZ ) );
1262
1263
if( IndR < 1 || IndR > MAXCATEGORY ) {
1264
printf("IndR out of bounds : %d\n",IndR );
1265
IndR = MIN( MAX( IndR, 1 ), MAXCATEGORY );
1266
}
1267
if( IndF < 1 || IndF > MAXCATEGORY ) {
1268
printf("IndF out of bounds : %d\n",IndF );
1269
IndF = MIN( MAX( IndF, 1 ), MAXCATEGORY );
1270
}
1271
if( dim == 3 ) {
1272
if( IndZ < 1 || IndZ > MAXCATEGORY ) {
1273
printf("IndZ out of bounds : %d\n",IndZ );
1274
IndZ = MIN( MAX( IndZ, 1 ), MAXCATEGORY );
1275
}
1276
cumz[IndZ] += 1;
1277
}
1278
if( connect && elemconnect[j] < 0 ) continue;
1279
1280
cumr[IndR] += 1;
1281
cumf[IndF] += 1;
1282
}
1283
1284
/* Count the cumulative numbers */
1285
for(i=1;i<=MAXCATEGORY;i++) {
1286
cumr[i] = cumr[i] + cumr[i-1];
1287
cumf[i] = cumf[i] + cumf[i-1];
1288
if(dim==3) cumz[i] = cumz[i] + cumz[i-1];
1289
}
1290
1291
j = noelements - data->elemconnectexist;
1292
for(i=1;i<=MAXCATEGORY;i++) {
1293
cumr[i] = ceil( 1.0 * partitions1 * cumr[i] / noelements );
1294
cumf[i] = ceil( 1.0 * partitions2 * cumf[i] / j );
1295
if(dim==3) cumz[i] = ceil( 1.0 * partitions3 * cumz[i] / j );
1296
}
1297
1298
1299
for(j=1;j<=noelements;j++) {
1300
nonodes = data->elementtypes[j]%100;
1301
x = y = z = 0.0;
1302
for(i=0;i<nonodes;i++) {
1303
k = data->topology[j][i];
1304
x += data->x[k];
1305
y += data->y[k];
1306
z += data->z[k];
1307
}
1308
x = x / nonodes;
1309
y = y / nonodes;
1310
z = z / nonodes;
1311
1312
r = sqrt(x*x+y*y);
1313
f = 180 * atan2(y,x)/FM_PI;
1314
if( f < 0.0 ) f = f + 360.0;
1315
1316
IndR = ceil( MAXCATEGORY * ( r - MinR ) / ( MaxR - MinR ) );
1317
IndF = ceil( MAXCATEGORY * ( f - MinF ) / ( MaxF - MinF ) );
1318
if(dim==3) IndZ = ceil( MAXCATEGORY * ( z - MinZ ) / ( MaxZ - MinZ ) );
1319
1320
IndR = MIN( MAX( IndR, 1 ), MAXCATEGORY );
1321
IndF = MIN( MAX( IndF, 1 ), MAXCATEGORY );
1322
if(dim==3) IndZ = MIN( MAX( IndZ, 1 ), MAXCATEGORY );
1323
1324
IndR = cumr[IndR];
1325
IndF = cumf[IndF];
1326
if(dim==3) {
1327
IndZ = cumz[IndZ];
1328
}
1329
else {
1330
IndZ = 1;
1331
}
1332
1333
k = (IndZ-1) * partitions1 * partitions2 +
1334
(IndF-1) * partitions1 + IndR;
1335
if( connect ) {
1336
if( elemconnect[j] < 0 )
1337
k = IndZ;
1338
else
1339
k += 1;
1340
}
1341
inpart[j] = k;
1342
nopart[k] += 1;
1343
}
1344
1345
maxpart = 0;
1346
minpart = noelements;
1347
j = 0;
1348
1349
/* Check whether some partition was not used */
1350
hit = FALSE;
1351
for(i=1;i<=partitions;i++)
1352
if(!nopart[i]) hit = TRUE;
1353
1354
if( hit ) {
1355
if( info ) printf("Renumbering the partitions (showing only 64):\n");
1356
for(i=1;i<=partitions;i++) {
1357
k = nopart[i];
1358
if( k ) {
1359
maxpart = MAX( k, maxpart );
1360
minpart = MIN( k, minpart );
1361
j += 1;
1362
nopart[i] = j;
1363
if( info && i!=j && j<=64) printf("%d -> %d %d\n",i,j,k);
1364
}
1365
}
1366
if(info) printf("There are %d active partitions out of %d possible ones\n",j,partitions);
1367
data->nopartitions = j;
1368
1369
for(i=1;i<=noelements;i++) {
1370
j = inpart[i];
1371
inpart[i] = nopart[j];
1372
}
1373
}
1374
else {
1375
if(info) printf("All possible %d out of %d partitions are active\n",j,partitions);
1376
data->nopartitions = partitions;
1377
}
1378
1379
1380
free_Ivector(nopart,1,partitions);
1381
free_Ivector( cumr,0,MAXCATEGORY);
1382
free_Ivector( cumf,0,MAXCATEGORY);
1383
if(dim==3) free_Ivector( cumz,0,MAXCATEGORY);
1384
1385
PartitionNodesByElements(data,info);
1386
1387
if(info) printf("Successfully made a partitioning with %d to %d elements.\n",minpart,maxpart);
1388
1389
return(0);
1390
}
1391
1392
1393
1394
int PartitionConnectedElementsStraight(struct FemType *data,struct BoundaryType *bound,
1395
struct ElmergridType *eg, int info) {
1396
int i,j,k,l,dim,allocated,debug,partz,hit,bctype;
1397
int noknots, noelements,bcelem,bc,maxbcelem;
1398
int IndZ,noconnect,totpartelems,sideelemtype,sidenodes,sidehits,nohits;
1399
int *cumz,*elemconnect,*partelems,*nodeconnect;
1400
int sideind[MAXNODESD2];
1401
Real z,MaxZ,MinZ;
1402
1403
1404
debug = FALSE;
1405
1406
if(info) {
1407
printf("Link the connected set directly to the partition\n");
1408
}
1409
1410
if(!data->nodeconnectexist) {
1411
printf("There are no connected boundary nodes?\n");
1412
return(1);
1413
}
1414
nodeconnect = data->nodeconnect;
1415
noknots = data->noknots;
1416
noelements = data->noelements;
1417
totpartelems = 0;
1418
1419
bcelem = 0;
1420
data->elemconnect = Ivector(1,noelements);
1421
elemconnect = data->elemconnect;
1422
for(i=1;i<=noelements;i++) elemconnect[i] = 0;
1423
1424
for(bc=0;bc<MAXBOUNDARIES;bc++) {
1425
if(bound[bc].created == FALSE) continue;
1426
if(bound[bc].nosides == 0) continue;
1427
1428
for(i=1;i<=bound[bc].nosides;i++) {
1429
1430
GetElementSide(bound[bc].parent[i],bound[bc].side[i],bound[bc].normal[i],
1431
data,sideind,&sideelemtype);
1432
1433
sidenodes = sideelemtype % 100;
1434
1435
hit = FALSE;
1436
1437
for(k=1;k<=eg->connect;k++) {
1438
bctype = eg->connectbounds[k-1];
1439
hit = (bound[bc].types[i] == bctype);
1440
if(hit) break;
1441
}
1442
if(!hit) continue;
1443
bcelem += 1;
1444
1445
k = bound[bc].parent[i];
1446
l = bound[bc].parent2[i];
1447
if(k) {
1448
if(!elemconnect[k]) {
1449
elemconnect[k] = 1;
1450
totpartelems += 1;
1451
}
1452
}
1453
if(l) {
1454
if(!elemconnect[l]) {
1455
elemconnect[l] = 1;
1456
totpartelems += 1;
1457
}
1458
}
1459
}
1460
}
1461
1462
data->elemconnectexist = totpartelems;
1463
1464
if(info) printf("Number of constrained boundary elements = %d\n",bcelem);
1465
if(info) printf("Number of constrained bulk elements = %d\n",totpartelems);
1466
if(info) printf("Successfully made connected elements to a partition\n");
1467
1468
return(0);
1469
}
1470
1471
1472
1473
int PartitionConnectedElements1D(struct FemType *data,struct BoundaryType *bound,
1474
struct ElmergridType *eg, int info) {
1475
int i,j,k,l,dim,allocated,debug,partz,partr,parts,hit,bctype;
1476
int noknots, noelements,bcelem,bc,maxbcelem;
1477
int IndZ,noconnect,totpartelems,sideelemtype,sidenodes,sidehits,nohits;
1478
int *cumz,*elemconnect,*partelems,*nodeconnect;
1479
int sideind[MAXNODESD2];
1480
Real val,z,MaxZ,MinZ;
1481
1482
1483
debug = FALSE;
1484
1485
partz = eg->partbcz;
1486
partr = eg->partbcr;
1487
1488
if( partz == 0 && partr == 0) return(0);
1489
1490
parts = MAX( partz, partr );
1491
1492
if(info) {
1493
if( partz )
1494
printf("Making a simple 1D partitioning in z for the connected elements only\n");
1495
else
1496
printf("Making a simple 1D partitioning in r for the connected elements only\n");
1497
}
1498
1499
if(!data->nodeconnectexist) {
1500
printf("There are no connected boundary nodes?\n");
1501
return(1);
1502
}
1503
nodeconnect = data->nodeconnect;
1504
1505
dim = data->dim;
1506
if( dim < 3 ) {
1507
printf("PartitionConnectedElements1D is only applicable in 3D\n");
1508
return(2);
1509
}
1510
1511
noknots = data->noknots;
1512
noelements = data->noelements;
1513
totpartelems = 0;
1514
1515
/* Because we don't want to change the code too much use 'z' for the
1516
coordinate also in the radial case. */
1517
if( partr )
1518
z = sqrt( data->x[1] * data->z[1] + data->y[1] * data->y[1]);
1519
else
1520
z = data->z[1];
1521
MaxZ = MinZ = z;
1522
1523
for(i=1;i<=noknots;i++) {
1524
if( partr )
1525
z = sqrt( data->x[i] * data->x[i] + data->y[i] * data->y[i]);
1526
else
1527
z = data->z[i];
1528
MaxZ = MAX( MaxZ, z);
1529
MinZ = MIN( MinZ, z);
1530
}
1531
1532
if( info ) {
1533
printf("Range in coordinate extent: %12.5le %12.5le\n",MinZ,MaxZ);
1534
}
1535
1536
/* Zero is the 1st value so that recursive algos can be used. */
1537
cumz = Ivector(0,MAXCATEGORY);
1538
for(i=0;i<=MAXCATEGORY;i++)
1539
cumz[i] = 0;
1540
1541
allocated = FALSE;
1542
bcelem = 0;
1543
1544
omstart:
1545
1546
for(bc=0;bc<MAXBOUNDARIES;bc++) {
1547
if(bound[bc].created == FALSE) continue;
1548
if(bound[bc].nosides == 0) continue;
1549
1550
for(i=1;i<=bound[bc].nosides;i++) {
1551
1552
GetElementSide(bound[bc].parent[i],bound[bc].side[i],bound[bc].normal[i],
1553
data,sideind,&sideelemtype);
1554
1555
sidenodes = sideelemtype % 100;
1556
hit = FALSE;
1557
1558
for(k=1;k<=eg->connect;k++) {
1559
bctype = eg->connectbounds[k-1];
1560
if( bctype > 0 ) {
1561
if(bound[bc].types[i] == bctype) hit = TRUE;
1562
}
1563
else if( bctype == -1 ) {
1564
if( bound[bc].parent[i] ) hit = TRUE;
1565
}
1566
else if( bctype == -2 ) {
1567
if( bound[bc].parent[i] && bound[bc].parent2[i] ) hit = TRUE;
1568
}
1569
else if( bctype == -3 ) {
1570
if( bound[bc].parent[i] && !bound[bc].parent2[i] ) hit = TRUE;
1571
}
1572
if(hit) break;
1573
}
1574
if(!hit) continue;
1575
1576
z = 0.0;
1577
for(j=0;j<sidenodes;j++) {
1578
k = sideind[j];
1579
if( partr )
1580
val = sqrt( data->x[k]*data->x[k] + data->y[k]*data->y[k]);
1581
else
1582
val = data->z[k];
1583
z += val;
1584
}
1585
1586
z = z / sidenodes;
1587
IndZ = ceil( MAXCATEGORY * ( z - MinZ ) / ( MaxZ - MinZ ) );
1588
1589
/* To be on the safe side */
1590
IndZ = MIN( MAX( IndZ, 1 ), MAXCATEGORY );
1591
1592
1593
if(allocated) {
1594
IndZ = cumz[IndZ];
1595
if(0) partelems[IndZ] += 1;
1596
1597
/* Also set the connected elements if available */
1598
k = bound[bc].parent[i];
1599
l = bound[bc].parent2[i];
1600
1601
if(k) {
1602
elemconnect[k] = IndZ;
1603
totpartelems += 1;
1604
}
1605
if(l) {
1606
elemconnect[l] = IndZ;
1607
totpartelems += 1;
1608
}
1609
}
1610
else {
1611
bcelem += 1;
1612
cumz[IndZ] += 1;
1613
}
1614
}
1615
}
1616
1617
if( !allocated ) {
1618
maxbcelem = bcelem;
1619
if( debug ) {
1620
printf("Number of constrained boundary elements = %d\n",bcelem);
1621
printf("Differential categories (showing only 20 active ones from %d)\n",MAXCATEGORY);
1622
k = 0;
1623
for(j=0;j<=MAXCATEGORY;j++) {
1624
if( cumz[j] > 0 ) {
1625
k++;
1626
printf("%d : %d\n",j,cumz[j]);
1627
if( k == 20 ) break;
1628
}
1629
}
1630
}
1631
1632
/* Count the cumulative numbers and map them to number of partitions */
1633
for(i=1;i<=MAXCATEGORY;i++)
1634
cumz[i] = cumz[i] + cumz[i-1];
1635
1636
if( debug ) {
1637
printf("Cumulative categories\n");
1638
for(j=0;j<=MAXCATEGORY;j++) {
1639
printf("%d : %d\n",j,cumz[j]);
1640
}
1641
}
1642
1643
noconnect = bcelem;
1644
for(i=1;i<=MAXCATEGORY;i++)
1645
cumz[i] = ceil( 1.0 * parts * cumz[i] / noconnect );
1646
1647
if( debug ) {
1648
printf("Partition categories\n");
1649
for(j=0;j<=MAXCATEGORY;j++) {
1650
printf("%d : %d\n",j,cumz[j]);
1651
}
1652
}
1653
1654
data->elemconnect = Ivector(1,noelements);
1655
elemconnect = data->elemconnect;
1656
1657
for(i=1;i<=noelements;i++) elemconnect[i] = 0;
1658
1659
allocated = TRUE;
1660
if(info) printf("Allocated and now setting the entries\n");
1661
goto omstart;
1662
}
1663
1664
data->elemconnectexist = totpartelems;
1665
free_Ivector( cumz,0,MAXCATEGORY);
1666
1667
if(info) printf("Successfully made a partitioning 1D with %d elements\n",totpartelems);
1668
1669
return(0);
1670
}
1671
1672
1673
#if USE_METIS
1674
static int SetMetisOptions(idx_t *options, struct ElmergridType *eg,int info) {
1675
1676
if(info) printf("Setting default Metis options!\n");
1677
METIS_SetDefaultOptions(options);
1678
1679
if(info) printf("Setting user defined Metis options!\n");
1680
options[METIS_OPTION_NUMBERING] = 0;
1681
options[METIS_OPTION_DBGLVL] = 3;
1682
options[METIS_OPTION_CTYPE] = METIS_CTYPE_SHEM;
1683
options[METIS_OPTION_IPTYPE] = METIS_IPTYPE_GROW;
1684
options[METIS_OPTION_RTYPE] = METIS_RTYPE_GREEDY;
1685
1686
if( eg->metis_contig ) options[METIS_OPTION_CONTIG] = 1;
1687
if( eg->metis_seed ) options[METIS_OPTION_SEED] = eg->metis_seed;
1688
if( eg->metis_ncuts > 1) options[METIS_OPTION_NCUTS] = eg->metis_ncuts;
1689
if( eg->metis_volcut) options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
1690
if( eg->metis_minconn) options[METIS_OPTION_MINCONN] = 1;
1691
}
1692
1693
1694
int PartitionConnectedElementsMetis(struct FemType *data,struct BoundaryType *bound,
1695
struct ElmergridType *eg, int nparts,int metisopt,int info) {
1696
int i,j,k,l,n,m,dim;
1697
int noknots,noelements,sidenodes,ind,nohits,totpartelems;
1698
int dualmaxcon,invmaxcon,totcon,step,bc,bcelem,bcelem2,hit,set;
1699
int noconnect,minpartelems,maxpartelems,sideelemtype,con,maxbcelem;
1700
int *elemconnect,*partelems,*nodeperm,*neededby;
1701
int *bcdualgraph[MAXCONNECTIONS],*bcinvtopo[MAXCONNECTIONS];
1702
int sideind[MAXNODESD1];
1703
int nn;
1704
idx_t options[METIS_NOPTIONS];
1705
int *xadj,*adjncy,*vwgt,*adjwgt,wgtflag,*npart;
1706
int numflag,edgecut,ncon;
1707
int *nodepart;
1708
1709
1710
if(info) {
1711
printf("Making a Metis partitioning for the connected BC elements only\n");
1712
}
1713
1714
if(!data->nodeconnectexist) {
1715
printf("There are no connected elements\n");
1716
return(1);
1717
}
1718
1719
SetMetisOptions(options,eg,info);
1720
1721
dim = data->dim;
1722
noknots = data->noknots;
1723
noelements = data->noelements;
1724
1725
/* Count the connected nodes and set the permutation */
1726
noconnect = 0;
1727
for(i=1;i<=noknots;i++)
1728
if( data->nodeconnect[i] ) noconnect++;
1729
if( noconnect == 0 ) {
1730
printf("There are really no connected nodes?\n");
1731
return(2);
1732
}
1733
if(info) printf("Number of connected nodes is %d\n",noconnect);
1734
1735
/* Permute the nodes so that they only include the connected nodes. */
1736
nodeperm = Ivector(1,noknots);
1737
for(i=1;i<=noknots;i++) nodeperm[i] = 0;
1738
noconnect = 0;
1739
for(i=1;i<=noknots;i++)
1740
if( data->nodeconnect[i] ) {
1741
noconnect++;
1742
nodeperm[i] = noconnect;
1743
}
1744
if(info) printf("Permuted the connected nodes\n");
1745
1746
/* Cycle over the boundary elements
1747
1) First cycle create a table showing the elements sharing a node
1748
2) Second cycle create a table showing the element-to-element connections */
1749
1750
invmaxcon = 0;
1751
dualmaxcon = 0;
1752
totcon = 0;
1753
1754
neededby = Ivector(1,noconnect);
1755
for(i=1;i<=noconnect;i++) neededby[i] = 0;
1756
1757
for(step=1;step<=2;step++) {
1758
1759
bcelem = 0;
1760
for(bc=0;bc<MAXBOUNDARIES;bc++) {
1761
if(bound[bc].created == FALSE) continue;
1762
if(bound[bc].nosides == 0) continue;
1763
1764
for(i=1;i<=bound[bc].nosides;i++) {
1765
1766
GetBoundaryElement(i,&bound[bc],data,sideind,&sideelemtype);
1767
/* GetElementSide(bound[bc].parent[i],bound[bc].side[i],bound[bc].normal[i],
1768
data,sideind,&sideelemtype); */
1769
sidenodes = sideelemtype % 100;
1770
nohits = 0;
1771
1772
for(j=0;j<sidenodes;j++)
1773
if( nodeperm[sideind[j]] ) nohits++;
1774
if( nohits < sidenodes ) continue;
1775
bcelem++;
1776
1777
for(j=0;j<sidenodes;j++) {
1778
ind = nodeperm[sideind[j]];
1779
1780
/* Create table that shows all the elements sharing a node. */
1781
if( step == 1 ) {
1782
neededby[ind] += 1;
1783
k = neededby[ind];
1784
1785
if(k > invmaxcon) {
1786
invmaxcon++;
1787
bcinvtopo[invmaxcon] = Ivector(1,noconnect);
1788
if(0) printf("allocating invtopo %d %d\n",invmaxcon,noconnect);
1789
for(m=1;m<=noconnect;m++)
1790
bcinvtopo[invmaxcon][m] = 0;
1791
}
1792
bcinvtopo[k][ind] = bcelem;
1793
}
1794
else if( step == 2 ) {
1795
/* Now create a table that shows how elements are connected to other elements,
1796
this is the dual graph. */
1797
for(k=1;k<=invmaxcon;k++) {
1798
bcelem2 = bcinvtopo[k][ind];
1799
1800
if( bcelem2 == 0 ) break;
1801
if( bcelem2 == bcelem ) continue;
1802
1803
hit = FALSE;
1804
for(l=1;l<=dualmaxcon;l++) {
1805
if(bcdualgraph[l][bcelem] == bcelem2) hit = TRUE;
1806
if(bcdualgraph[l][bcelem] == 0) break;
1807
}
1808
if(!hit) {
1809
if(l > dualmaxcon) {
1810
dualmaxcon++;
1811
if( l >= MAXCONNECTIONS ) {
1812
printf("Number of connections %d vs. static limit %d\n",l,MAXCONNECTIONS-1);
1813
bigerror("Maximum of connections in dual graph larger than the static limit!");
1814
}
1815
if(0) printf("allocating dual topo %d %d\n",dualmaxcon,maxbcelem);
1816
bcdualgraph[dualmaxcon] = Ivector(1,maxbcelem);
1817
for(m=1;m<=maxbcelem;m++)
1818
bcdualgraph[dualmaxcon][m] = 0;
1819
}
1820
bcdualgraph[l][bcelem] = bcelem2;
1821
totcon++;
1822
}
1823
}
1824
}
1825
}
1826
}
1827
}
1828
maxbcelem = bcelem;
1829
}
1830
1831
if(info) {
1832
printf("There are %d connected boundary elements.\n",maxbcelem);
1833
printf("There are %d connections altogether in the dual graph.\n",totcon);
1834
}
1835
1836
/* Create the sparse matrix format graph for Metis */
1837
xadj = Ivector(0,maxbcelem);
1838
adjncy = Ivector(0,totcon-1);
1839
for(i=0;i<totcon;i++)
1840
adjncy[i] = 0;
1841
1842
totcon = 0;
1843
for(i=1;i<=maxbcelem;i++) {
1844
xadj[i-1] = totcon;
1845
for(j=1;j<=dualmaxcon;j++) {
1846
con = bcdualgraph[j][i];
1847
if(con) {
1848
adjncy[totcon] = con-1;
1849
totcon++;
1850
if(0) printf("con: %d %d %d\n",i,totcon,con);
1851
}
1852
}
1853
}
1854
xadj[maxbcelem] = totcon;
1855
1856
/* Deallocate the temporal graphs */
1857
free_Ivector( neededby, 1, noconnect );
1858
for(i=1;i<=invmaxcon;i++)
1859
free_Ivector(bcinvtopo[i],1,noconnect);
1860
for(i=1;i<=dualmaxcon;i++)
1861
free_Ivector(bcdualgraph[i],1,maxbcelem);
1862
1863
/* Parameters for Metis */
1864
numflag = 0;
1865
nn = maxbcelem;
1866
npart = Ivector(0,nn-1);
1867
wgtflag = 0;
1868
1869
/* Optional weights */
1870
vwgt = NULL;
1871
adjwgt = NULL;
1872
1873
if(metisopt == 2) {
1874
if(info) printf("Starting graph partitioning METIS_PartGraphRecursive.\n");
1875
METIS_PartGraphRecursive(&nn,&ncon,xadj,adjncy,vwgt,&wgtflag,adjwgt,
1876
&nparts,NULL,NULL,options,&edgecut,npart);
1877
}
1878
else if(metisopt == 3 || metisopt == 4) {
1879
if(info) printf("Starting graph partitioning METIS_PartGraphKway.\n");
1880
ncon = 0;
1881
wgtflag = 0;
1882
METIS_PartGraphKway(&nn,&ncon,xadj,adjncy,vwgt,&wgtflag,adjwgt,
1883
&nparts,NULL,NULL,options,&edgecut,npart);
1884
}
1885
else {
1886
printf("Unknown Metis option %d\n",metisopt);
1887
}
1888
if(0) printf("Finished Metis routine for boundary partitioning\n");
1889
1890
1891
free_Ivector(xadj, 0,maxbcelem);
1892
free_Ivector(adjncy, 0,totcon-1);
1893
1894
1895
data->elemconnect = Ivector(1,noelements);
1896
elemconnect = data->elemconnect;
1897
for(i=1;i<=noelements;i++) elemconnect[i] = 0;
1898
1899
/* Set the bulk element partitions by following the boundary elements.
1900
Also set the nodal partitions to apply majority rule later on. */
1901
bcelem = 0;
1902
totpartelems = 0;
1903
for(bc=0;bc<MAXBOUNDARIES;bc++) {
1904
if(bound[bc].created == FALSE) continue;
1905
if(bound[bc].nosides == 0) continue;
1906
1907
for(i=1;i<=bound[bc].nosides;i++) {
1908
1909
GetBoundaryElement(i,&bound[bc],data,sideind,&sideelemtype);
1910
/* GetElementSide(bound[bc].parent[i],bound[bc].side[i],bound[bc].normal[i],
1911
data,sideind,&sideelemtype); */
1912
sidenodes = sideelemtype % 100;
1913
nohits = 0;
1914
for(j=0;j<sidenodes;j++)
1915
if( nodeperm[sideind[j]] ) nohits++;
1916
if( nohits < sidenodes ) continue;
1917
1918
/* Always set the connected element to a negative value as this information is used
1919
in a dirty way later on. */
1920
k = bound[bc].parent[i];
1921
l = bound[bc].parent2[i];
1922
1923
if(0) printf("kl = %d %d %d %d %d\n",k,l,bcelem,npart[bcelem]+1,elemconnect[k]);
1924
1925
/* Have the addition here since npart has indexes [0,nn-1]. */
1926
if(k) {
1927
elemconnect[k] = npart[bcelem]+1;
1928
totpartelems += 1;
1929
}
1930
if(l) {
1931
elemconnect[l] = npart[bcelem]+1;
1932
totpartelems += 1;
1933
}
1934
bcelem++;
1935
}
1936
}
1937
1938
free_Ivector( nodeperm, 1, noknots );
1939
free_Ivector( npart, 0, nn-1 );
1940
1941
data->elemconnectexist = totpartelems;
1942
if(info) printf("Successfully created boundary partitioning for %d bulk elements\n",totpartelems);
1943
1944
return(0);
1945
}
1946
#endif
1947
1948
1949
int ExtendBoundaryPartitioning(struct FemType *data,struct BoundaryType *bound,
1950
int elemlayers,int info)
1951
{
1952
int i,j,k,l,m,n,nonodes,noknots,noelements,totpartelems,nparts,set;
1953
int minpartelems,maxpartelems,refcount,refpart,part;
1954
int *partelems,*elemconnect;
1955
int *invrow,*invcol;
1956
1957
printf("Extending boundary partitioning by majority rule\n");
1958
1959
CreateInverseTopology(data, info);
1960
invrow = data->invtopo.rows;
1961
invcol = data->invtopo.cols;
1962
1963
noelements = data->noelements;
1964
noknots = data->noknots;
1965
1966
if( !data->elemconnectexist ) {
1967
printf("Initial partitioning does not exist!\n");
1968
return(1);
1969
}
1970
elemconnect = data->elemconnect;
1971
1972
nparts = 0;
1973
for(i=1;i<=data->noelements;i++)
1974
nparts = MAX( nparts, elemconnect[i] );
1975
1976
partelems = Ivector(1,nparts);
1977
for(i=1;i<=nparts;i++)
1978
partelems[i] = 0;
1979
1980
totpartelems = 0;
1981
for(i=1;i<=noelements;i++) {
1982
j = elemconnect[i];
1983
if(j) {
1984
partelems[j] += 1;
1985
totpartelems +=1;
1986
}
1987
}
1988
1989
if(info) printf("Initial partitioning with %d elements:\n",totpartelems);
1990
minpartelems = maxpartelems = partelems[1];
1991
for(j=1;j<=nparts;j++) {
1992
minpartelems = MIN( minpartelems, partelems[j] );
1993
maxpartelems = MAX( maxpartelems, partelems[j] );
1994
}
1995
printf("Initial partitioning has %d to %d elements in partition\n",minpartelems,maxpartelems);
1996
1997
1998
/* Counter to find the dominating element */
1999
for(i=1;i<=nparts;i++)
2000
partelems[i] = 0;
2001
2002
/* Apply majority rule to set the remaining bulk elements that
2003
share nodes on the connected boundary. */
2004
for(m=1;m<=elemlayers;m++) {
2005
n = 0;
2006
for(j=1;j<=noelements;j++) {
2007
2008
/* This element is already set */
2009
if( elemconnect[j] > 0 ) continue;
2010
2011
set = FALSE;
2012
nonodes = data->elementtypes[j] % 100;
2013
for(i=0;i<nonodes;i++) {
2014
k = data->topology[j][i];
2015
for(l=invrow[k-1];l<invrow[k];l++) {
2016
part = elemconnect[invcol[l]+1];
2017
if( part > 0 ) {
2018
set = TRUE;
2019
partelems[part] += 1;
2020
}
2021
}
2022
}
2023
/* No hits, cannot set */
2024
if(!set) continue;
2025
2026
refcount = 0;
2027
for(i=0;i<nonodes;i++) {
2028
k = data->topology[j][i];
2029
for(l=invrow[k-1];l<invrow[k];l++) {
2030
part = elemconnect[invcol[l]+1];
2031
if(part > 0 ) {
2032
if( partelems[part] > refcount ) {
2033
refcount = partelems[part];
2034
refpart = part;
2035
}
2036
partelems[part] = 0;
2037
}
2038
}
2039
}
2040
2041
if(0) printf("setting: %d %d %d\n",j,refpart,refcount);
2042
2043
/* Set negative entry first so that this is not used within this loop */
2044
elemconnect[j] = -refpart;
2045
n++;
2046
}
2047
2048
/* Revert to positive indexes at the end */
2049
for(j=1;j<=noelements;j++)
2050
elemconnect[j] = abs( elemconnect[j] );
2051
2052
if(info) printf("Setting partition for %d elements in layer %d\n",n,m);
2053
if( n == 0 ) {
2054
printf("No elements set in the layer, breaking loop %d!\n",m);
2055
break;
2056
}
2057
}
2058
2059
2060
/* Compute the division to partitions */
2061
for(i=1;i<=nparts;i++)
2062
partelems[i] = 0;
2063
2064
totpartelems = 0;
2065
for(i=1;i<=noelements;i++) {
2066
j = elemconnect[i];
2067
if(j) {
2068
partelems[j] += 1;
2069
totpartelems += 1;
2070
}
2071
}
2072
2073
if(info) printf("Extended partitioning of %d elements:\n",totpartelems);
2074
minpartelems = maxpartelems = partelems[1];
2075
for(j=1;j<=nparts;j++) {
2076
minpartelems = MIN( minpartelems, partelems[j] );
2077
maxpartelems = MAX( maxpartelems, partelems[j] );
2078
if(0) printf("Part: %d %d\n",j,partelems[j]);
2079
}
2080
if(info) printf("Extended partitioning has %d to %d elements in partition\n",minpartelems,maxpartelems);
2081
2082
data->elemconnectexist = totpartelems;
2083
free_Ivector( partelems, 1, nparts );
2084
2085
if(info) printf("Successfully extended the partitioning by %d layers\n",elemlayers);
2086
2087
return(0);
2088
}
2089
2090
2091
2092
2093
2094
int PartitionSimpleNodes(struct FemType *data,int dimpart[],int dimper[],
2095
int partorder, Real corder[],Real parttol,int info)
2096
/* Do simple partitioning going for the nodes. Then using the the majority rule
2097
define the elemental partitioning. This is suboptimal for Elmer because the
2098
elemental ordering is primary in Elmer. */
2099
{
2100
int i,j,k,k0,kprev,l,ind,minpart,maxpart;
2101
int noknots, noelements,elemsinpart,periodic;
2102
int partitions1,partitions2,partitions3,partitions;
2103
int vpartitions1,vpartitions2,vpartitions3,vpartitions,hit;
2104
int *indx,*nopart,*nodepart;
2105
Real *arrange;
2106
Real x,y,z,cx,cy,cz;
2107
2108
partitions1 = dimpart[0];
2109
partitions2 = dimpart[1];
2110
partitions3 = dimpart[2];
2111
if(data->dim < 3) partitions3 = 1;
2112
partitions = partitions1 * partitions2 * partitions3;
2113
2114
if(partitions1 < 2 && partitions2 < 2 && partitions3 < 2) {
2115
printf("Some of the divisions must be larger than one: %d %d %d\n",
2116
partitions1, partitions2, partitions3 );
2117
bigerror("Partitioning not performed");
2118
}
2119
2120
if(partitions >= data->noelements) {
2121
printf("There must be fever partitions than elements (%d vs %d)!\n",
2122
partitions,data->noelements);
2123
bigerror("Partitioning not performed");
2124
}
2125
2126
if(!data->partitionexist) {
2127
data->partitionexist = TRUE;
2128
data->elempart = Ivector(1,data->noelements);
2129
data->nodepart = Ivector(1,data->noknots);
2130
data->nopartitions = partitions;
2131
}
2132
nodepart = data->nodepart;
2133
2134
vpartitions1 = partitions1;
2135
vpartitions2 = partitions2;
2136
vpartitions3 = partitions3;
2137
periodic = dimper[0] || dimper[1] || dimper[2];
2138
if(periodic) {
2139
if(dimper[0] && partitions1 > 1) vpartitions1 *= 2;
2140
if(dimper[1] && partitions2 > 1) vpartitions2 *= 2;
2141
if(dimper[2] && partitions3 > 1) vpartitions3 *= 2;
2142
}
2143
vpartitions = vpartitions1 * vpartitions2 * vpartitions3;
2144
2145
nopart = Ivector(1,vpartitions);
2146
noelements = data->noelements;
2147
noknots = data->noknots;
2148
2149
if(info) printf("Making a simple partitioning for %d nodes in %d-dimensions.\n",
2150
noknots,data->dim);
2151
2152
arrange = Rvector(1,noknots);
2153
indx = Ivector(1,noknots);
2154
2155
if(partorder) {
2156
cx = corder[0];
2157
cy = corder[1];
2158
cz = corder[2];
2159
}
2160
else {
2161
cx = 1.0;
2162
cy = 0.0001;
2163
cz = cy*cy;
2164
}
2165
2166
z = 0.0;
2167
2168
for(i=1;i<=noknots;i++)
2169
nodepart[i] = 1;
2170
2171
if(vpartitions1 > 1) {
2172
if(info) printf("Ordering 1st direction with (%.3lg*x + %.3lg*y + %.3lg*z)\n",cx,cy,cz);
2173
for(j=1;j<=noknots;j++) {
2174
x = data->x[j];
2175
y = data->y[j];
2176
z = data->z[j];
2177
arrange[j] = cx*x + cy*y + cz*z;
2178
}
2179
SortIndex(noknots,arrange,indx);
2180
2181
for(i=1;i<=noknots;i++) {
2182
ind = indx[i];
2183
k = (i*vpartitions1-1)/noknots+1;
2184
nodepart[ind] = k;
2185
}
2186
}
2187
2188
/* Partition in the 2nd direction taking into account the 1st direction */
2189
if(vpartitions2 > 1) {
2190
if(info) printf("Ordering in the 2nd direction.\n");
2191
for(j=1;j<=noknots;j++) {
2192
x = data->x[j];
2193
y = data->y[j];
2194
z = data->z[j];
2195
arrange[j] = -cy*x + cx*y + cz*z;
2196
}
2197
SortIndex(noknots,arrange,indx);
2198
2199
for(i=1;i<=vpartitions;i++)
2200
nopart[i] = 0;
2201
2202
elemsinpart = noknots / (vpartitions1*vpartitions2);
2203
j = 1;
2204
for(i=1;i<=noknots;i++) {
2205
ind = indx[i];
2206
k0 = (nodepart[ind]-1) * vpartitions2;
2207
for(l=1;l<=vpartitions2;l++) {
2208
hit = FALSE;
2209
if( j < vpartitions ) {
2210
if( nopart[k0+j] >= elemsinpart ) {
2211
j += 1;
2212
hit = TRUE;
2213
}
2214
}
2215
if( j > 1 ) {
2216
if( nopart[k0+j-1] < elemsinpart ) {
2217
j -= 1;
2218
hit = TRUE;
2219
}
2220
}
2221
if( !hit ) break;
2222
}
2223
k = k0 + j;
2224
nopart[k] += 1;
2225
nodepart[ind] = k;
2226
}
2227
}
2228
2229
/* Partition in the 3rd direction taking into account the 1st and 2nd direction */
2230
if(vpartitions3 > 1) {
2231
if(info) printf("Ordering in the 3rd direction.\n");
2232
for(j=1;j<=noknots;j++) {
2233
x = data->x[j];
2234
y = data->y[j];
2235
z = data->z[j];
2236
arrange[j] = -cz*x - cy*y + cx*z;
2237
}
2238
SortIndex(noknots,arrange,indx);
2239
2240
for(i=1;i<=vpartitions;i++)
2241
nopart[i] = 0;
2242
2243
elemsinpart = noknots / (vpartitions1*vpartitions2*vpartitions3);
2244
j = 1;
2245
for(i=1;i<=noknots;i++) {
2246
ind = indx[i];
2247
k0 = (nodepart[ind]-1)*vpartitions3;
2248
2249
for(l=1;l<=vpartitions;l++) {
2250
hit = FALSE;
2251
if( j < vpartitions3 ) {
2252
if( nopart[k0+j] >= elemsinpart ) {
2253
j += 1;
2254
hit = TRUE;
2255
}
2256
}
2257
if( j > 1 ) {
2258
if( nopart[k0+j-1] < elemsinpart ) {
2259
j -= 1;
2260
hit = TRUE;
2261
}
2262
}
2263
if( !hit ) break;
2264
}
2265
k = k0 + j;
2266
nopart[k] += 1;
2267
nodepart[ind] = k;
2268
}
2269
}
2270
2271
2272
/* This piece of code may be used to assign "strides" back to same partition. */
2273
if(parttol > 1.0e-20 ) {
2274
if(0) {
2275
printf("Original partition counts:\n");
2276
for(i=1;i<=partitions;i++)
2277
printf("nopart[%d] = %d\n",i,nopart[i]);
2278
}
2279
2280
for(j=1;j<=noknots;j++) {
2281
x = data->x[j];
2282
y = data->y[j];
2283
z = data->z[j];
2284
arrange[j] = cx*x + cy*y + cz*z;
2285
}
2286
SortIndex(noknots,arrange,indx);
2287
2288
kprev = nodepart[indx[1]];
2289
l = 0;
2290
for(i=2;i<=noknots;i++) {
2291
ind = indx[i];
2292
k = nodepart[ind];
2293
if(k != kprev ) {
2294
if(fabs(arrange[i]-arrange[i-1]) < parttol ) {
2295
nopart[k] -= 1;
2296
nopart[kprev] += 1;
2297
nodepart[ind] = kprev;
2298
k = kprev;
2299
if(0) printf("arrange %d %d %d %d %.6lg %.6lg\n",i,ind,k,kprev,arrange[i],arrange[i-1]);
2300
l++;
2301
}
2302
}
2303
kprev = k;
2304
}
2305
if(0) {
2306
printf("Updated partition counts:\n");
2307
for(i=1;i<=partitions;i++)
2308
printf("nopart[%d] = %d\n",i,nopart[i]);
2309
}
2310
if(info) printf("Number of partition changes due to tolerance: %d\n",l);
2311
}
2312
2313
2314
/* For periodic systems the number of virtual partitions is larger. Now map the mesh so that the
2315
1st and last partition for each direction will be joined */
2316
if(periodic) {
2317
int *partmap;
2318
int p1,p2,p3,q1,q2,q3;
2319
int P,Q;
2320
p1=p2=p3=1;
2321
partmap = Ivector(1,vpartitions);
2322
for(i=1;i<=vpartitions;i++)
2323
partmap[i] = 0;
2324
for(p1=1;p1<=vpartitions1;p1++) {
2325
q1 = p1;
2326
if(dimper[0] && vpartitions1 > 1) {
2327
if(q1==vpartitions1) q1 = 0;
2328
q1 = q1/2 + 1;
2329
}
2330
for(p2=1;p2<=vpartitions2;p2++) {
2331
q2 = p2;
2332
if(dimper[1] && vpartitions2 > 1) {
2333
if(q2==vpartitions2) q2 = 0;
2334
q2 = q2/2 + 1;
2335
}
2336
for(p3=1;p3<=vpartitions3;p3++) {
2337
q3 = p3;
2338
if(dimper[2] && vpartitions3 > 1) {
2339
if(q3==vpartitions3) q3 = 0;
2340
q3 = q3/2 + 1;
2341
}
2342
2343
P = vpartitions3 * vpartitions2 * (p1 - 1) + vpartitions3 * (p2-1) + p3;
2344
Q = partitions3 * partitions2 * (q1 - 1) + partitions3 * (q2-1) + q3;
2345
2346
partmap[P] = Q;
2347
}
2348
}
2349
}
2350
for(i=1;i<=noknots;i++)
2351
nodepart[i] = partmap[nodepart[i]];
2352
free_Ivector(partmap,1,vpartitions);
2353
}
2354
2355
2356
for(i=1;i<=partitions;i++)
2357
nopart[i] = 0;
2358
for(i=1;i<=noknots;i++)
2359
nopart[nodepart[i]] += 1;
2360
2361
minpart = maxpart = nopart[1];
2362
for(i=1;i<=partitions;i++) {
2363
minpart = MIN( nopart[i], minpart );
2364
maxpart = MAX( nopart[i], maxpart );
2365
}
2366
2367
free_Rvector(arrange,1,noelements);
2368
free_Ivector(nopart,1,partitions);
2369
free_Ivector(indx,1,noelements);
2370
2371
PartitionElementsByNodes(data,info);
2372
2373
if(info) printf("Successfully made a partitioning with %d to %d nodes.\n",minpart,maxpart);
2374
2375
return(0);
2376
}
2377
2378
2379
static int LinearNodes(int elemtype)
2380
{
2381
int elemfamily,nonodes;
2382
int fam2nodemap[] = {0, 1, 2, 3, 4, 4, 5, 6, 8 };
2383
2384
elemfamily = elemtype / 100;
2385
nonodes = fam2nodemap[elemfamily];
2386
2387
return(nonodes);
2388
}
2389
2390
2391
int PartitionMetisMesh(struct FemType *data,struct ElmergridType *eg,
2392
int partitions,int dual,int info)
2393
/* Perform partitioning using Metis. This uses the elemental routines of Metis that assume that
2394
there exists only one elementtype. If this condition is not met then this routine cannot be
2395
used. If the elements are higher order nodal elements then use only the linear basis. */
2396
{
2397
int i,j,k,periodic, noelements, noknots, sides, highorder;
2398
int nodesd2, etype, numflag,mintype,maxtype,elemtype,minnodes,ninv;
2399
int *neededby,*indxper,*inpart;
2400
idx_t *metistopo,*eptr,*npart,*epart;
2401
idx_t ne,nn,ncommon,edgecut,nparts;
2402
idx_t options[METIS_NOPTIONS];
2403
2404
2405
SetMetisOptions(options,eg,info);
2406
2407
if(info) printf("Making a Metis partitioning for %d elements in %d-dimensions.\n",
2408
data->noelements,data->dim);
2409
2410
noelements = data->noelements;
2411
noknots = data->noknots;
2412
2413
for(i=1;i<=noelements;i++) {
2414
elemtype = data->elementtypes[i];
2415
nodesd2 = LinearNodes( elemtype );
2416
if(i == 1 ) {
2417
mintype = maxtype = elemtype;
2418
minnodes = nodesd2;
2419
} else {
2420
mintype = MIN( mintype, elemtype );
2421
maxtype = MAX( maxtype, elemtype );
2422
minnodes = MIN( minnodes, nodesd2 );
2423
}
2424
}
2425
2426
if(info) {
2427
if(mintype == maxtype ) {
2428
printf("All elements are of type %d\n",mintype);
2429
}
2430
else {
2431
printf("Minimum element type is %d\n",mintype);
2432
printf("Maximum element type is %d\n",maxtype);
2433
}
2434
}
2435
2436
if( minnodes >= 8) {
2437
ncommon = 4;
2438
}
2439
else if(minnodes > 4 ) {
2440
ncommon = 3;
2441
}
2442
else {
2443
ncommon = 2;
2444
}
2445
if(info) {
2446
printf("Minimum number of linear nodes in elements %d\n",minnodes);
2447
printf("Requiring number of nodes in dual graph %d\n",ncommon);
2448
}
2449
2450
if(!data->partitionexist) {
2451
data->partitionexist = TRUE;
2452
data->elempart = Ivector(1,data->noelements);
2453
data->nodepart = Ivector(1,data->noknots);
2454
data->nopartitions = partitions;
2455
}
2456
inpart = data->elempart;
2457
2458
/* Are there periodic boundaries. This information is used to join the boundaries. */
2459
periodic = data->periodicexist;
2460
if(periodic) {
2461
if(info) printf("There seems to be periodic boundaries\n");
2462
indxper = data->periodic;
2463
}
2464
2465
ne = noelements;
2466
nn = noknots;
2467
2468
neededby = Ivector(1,noknots);
2469
2470
numflag = 0;
2471
nparts = partitions;
2472
2473
/* Mark the nodes that are needed */
2474
k = 0;
2475
for(i=1;i<=noknots;i++)
2476
neededby[i] = 0;
2477
if(periodic) {
2478
for(i=1;i<=noelements;i++) {
2479
nodesd2 = LinearNodes( data->elementtypes[i] );
2480
for(j=0;j<nodesd2;j++) {
2481
neededby[indxper[data->topology[i][j]]] = 1;
2482
k += 1;
2483
}
2484
}
2485
}
2486
else {
2487
for(i=1;i<=noelements;i++) {
2488
nodesd2 = LinearNodes( data->elementtypes[i] );
2489
for(j=0;j<nodesd2;j++) {
2490
neededby[data->topology[i][j]] = 1;
2491
k += 1;
2492
}
2493
}
2494
}
2495
2496
j = 0;
2497
for(i=1;i<=noknots;i++)
2498
if(neededby[i])
2499
neededby[i] = ++j;
2500
2501
nn = j;
2502
if(info) {
2503
if(nn == noknots)
2504
printf("Using all %d possible nodes in the Metis graph\n",nn);
2505
else
2506
printf("Using %d nodes of %d possible nodes in the Metis graph\n",nn,noknots);
2507
printf("Allocating mesh topology of size %d\n",k);
2508
}
2509
2510
eptr = Ivector(0,noelements);
2511
metistopo = Ivector(0,k-1);
2512
2513
k = 0;
2514
eptr[0] = k;
2515
if(periodic) {
2516
for(i=1;i<=noelements;i++) {
2517
nodesd2 = LinearNodes( data->elementtypes[i] );
2518
for(j=0;j<nodesd2;j++) {
2519
metistopo[k] = neededby[indxper[data->topology[i][j]]]-1;
2520
k += 1;
2521
}
2522
eptr[i] = k;
2523
}
2524
}
2525
else if(nn < noknots) {
2526
for(i=1;i<=noelements;i++) {
2527
nodesd2 = LinearNodes( data->elementtypes[i] );
2528
for(j=0;j<nodesd2;j++) {
2529
metistopo[k] = neededby[data->topology[i][j]]-1;
2530
k += 1;
2531
}
2532
eptr[i] = k;
2533
}
2534
}
2535
else {
2536
for(i=1;i<=noelements;i++) {
2537
nodesd2 = LinearNodes( data->elementtypes[i] );
2538
for(j=0;j<nodesd2;j++) {
2539
metistopo[k] = data->topology[i][j]-1;
2540
k += 1;
2541
}
2542
eptr[i] = k;
2543
}
2544
}
2545
2546
npart = Ivector(0,nn-1);
2547
for(i=0;i<nn;i++) npart[i] = 0;
2548
2549
epart = Ivector(0,ne-1);
2550
for(i=0;i<ne;i++) epart[i] = 0;
2551
2552
if(dual) {
2553
if(info) printf("Starting graph partitioning METIS_PartMeshDual.\n");
2554
METIS_PartMeshDual(&ne,&nn,eptr,metistopo,NULL,NULL,&ncommon,
2555
&nparts,NULL,options,&edgecut,epart,npart);
2556
if(info) printf("Finished graph partitioning METIS_PartMeshDual.\n");
2557
}
2558
else {
2559
if(info) printf("Starting graph partitioning METIS_PartMeshNodal.\n");
2560
METIS_PartMeshNodal(&ne,&nn,eptr,metistopo,NULL,NULL,
2561
&nparts,NULL,options,&edgecut,epart,npart);
2562
if(info) printf("Finished graph partitioning METIS_PartMeshNodal.\n");
2563
}
2564
2565
/* Set the partition given by Metis for each element. */
2566
ninv = 0;
2567
for(i=1;i<=noelements;i++) {
2568
inpart[i] = epart[i-1]+1;
2569
if(inpart[i] < 1 || inpart[i] > partitions) {
2570
if(ninv < 10 ) printf("Invalid partition %d for element %d\n",inpart[i],i);
2571
ninv++;
2572
}
2573
}
2574
if(ninv) {
2575
printf("Number of invalid element partitions by Metis %d\n",ninv);
2576
bigerror("Cannot continue with invalid partitioning!");
2577
}
2578
2579
if( highorder ) {
2580
PartitionNodesByElements(data,info);
2581
}
2582
else {
2583
if(info) printf("Set the partition given by Metis for each node\n");
2584
for(i=1;i<=noknots;i++) {
2585
if(periodic)
2586
j = neededby[indxper[i]];
2587
else if(nn < noknots)
2588
j = neededby[i];
2589
else
2590
j = i;
2591
if(!j) printf("Cannot set partitioning for node %d\n",i);
2592
data->nodepart[i] = npart[j-1]+1;
2593
if(data->nodepart[i] < 1 || data->nodepart[i] > partitions) {
2594
if(ninv < 10) printf("Invalid partition %d for node %d\n",data->nodepart[i],i);
2595
ninv++;
2596
}
2597
}
2598
if(ninv) {
2599
printf("Number of invalid node partitions by Metis %d\n",ninv);
2600
bigerror("Cannot continue with invalid partitioning!");
2601
}
2602
}
2603
2604
free_Ivector(neededby,1,noknots);
2605
free_Ivector(metistopo,0,k-1);
2606
free_Ivector(epart,0,noelements-1);
2607
free_Ivector(npart,0,nn-1);
2608
free_Ivector(eptr,0,noelements+1);
2609
2610
if(info) printf("Successfully made a Metis partition using the element mesh.\n");
2611
2612
return(0);
2613
}
2614
2615
2616
2617
#if USE_METIS
2618
int PartitionMetisGraph(struct FemType *data,struct BoundaryType *bound,
2619
struct ElmergridType *eg,int partitions,int metisopt,
2620
int dual,int info)
2621
/* Perform partitioning using Metis. One may use either the direct or the dual
2622
graph. The direct graph means that the nodes are first partitioned and the
2623
elements follow. The dual graph means that the elements are partitioned and
2624
the ownership of the nodes will follow. The latter is optimal for Elmer. */
2625
{
2626
int i,j,k,noelements,noknots,errstat;
2627
int nn,ncon,con,maxcon,totcon;
2628
int *xadj,*adjncy,*vwgt,*adjwgt,wgtflag,*npart,**graph;
2629
int numflag,nparts,edgecut,maxconset;
2630
struct CRSType *dualgraph;
2631
idx_t options[METIS_NOPTIONS];
2632
2633
if(info) printf("Making a Metis partitioning for %d nodes in %d-dimensions.\n",
2634
data->noknots,data->dim);
2635
if(partitions < 2 ) {
2636
bigerror("There should be at least two partitions for partitioning!");
2637
}
2638
2639
noknots = data->noknots;
2640
noelements = data->noelements;
2641
maxconset = 0;
2642
2643
if(data->periodicexist && dual ) {
2644
printf("Dual graph not implemented for periodic system!\n");
2645
printf("Enforcing nodal graph for partitioning\n");
2646
dual = FALSE;
2647
}
2648
2649
SetMetisOptions(options,eg,info);
2650
2651
nparts = partitions;
2652
if( dual ) {
2653
if( eg->partbcz > 1 || eg->partbcr )
2654
PartitionConnectedElements1D(data,bound,eg,info);
2655
else if( eg->partbcmetis > 1 )
2656
PartitionConnectedElementsMetis(data,bound,eg,eg->partbcmetis,metisopt,info);
2657
else if( eg->connect ) {
2658
PartitionConnectedElementsStraight(data,bound,eg,info);
2659
}
2660
2661
if( data->nodeconnectexist ) {
2662
errstat = ExtendBoundaryPartitioning(data,bound,eg->partbclayers,info);
2663
if( errstat ) bigerror("Extend boundary partitioning returned error!");
2664
}
2665
2666
/* Find the number of partitions already used for connected elements */
2667
if( data->elemconnectexist ) {
2668
maxconset = 0;
2669
for(i=1;i<=noelements;i++)
2670
maxconset = MAX( maxconset, data->elemconnect[i] );
2671
nparts -= maxconset;
2672
}
2673
2674
if( nparts == 1 ) {
2675
if(info) printf("Just one partition left, skipping 2nd part of hybrid partitioning!\n");
2676
goto skippart;
2677
}
2678
2679
CreateDualGraph(data,TRUE,info);
2680
2681
/* Create the sparse matrix format graph for Metis */
2682
dualgraph = &data->dualgraph;
2683
2684
nn = dualgraph->rowsize;
2685
xadj = dualgraph->rows;
2686
adjncy = dualgraph->cols;
2687
totcon = dualgraph->colsize;
2688
}
2689
else {
2690
CreateNodalGraph(data,TRUE,info);
2691
maxcon = data->nodalmaxconnections;
2692
nn = noknots;
2693
graph = data->nodalgraph;
2694
2695
/* Compute total number of connections in graph */
2696
totcon = 0;
2697
for(i=1;i<=nn;i++) {
2698
for(j=0;j<maxcon;j++) {
2699
con = graph[j][i];
2700
if(con) totcon++;
2701
}
2702
}
2703
2704
/* Create the sparse matrix format graph for Metis */
2705
xadj = Ivector(0,nn);
2706
adjncy = Ivector(0,totcon-1);
2707
for(i=0;i<totcon;i++)
2708
adjncy[i] = 0;
2709
2710
totcon = 0;
2711
for(i=1;i<=nn;i++) {
2712
xadj[i-1] = totcon;
2713
for(j=0;j<maxcon;j++) {
2714
con = graph[j][i];
2715
if(con) {
2716
adjncy[totcon] = con-1;
2717
totcon++;
2718
}
2719
}
2720
}
2721
xadj[nn] = totcon;
2722
}
2723
2724
if(info) printf("There are %d connections altogether in the graph.\n",totcon);
2725
2726
/* Parameters for Metis */
2727
numflag = 0;
2728
npart = Ivector(0,nn-1);
2729
wgtflag = 0;
2730
ncon = 1;
2731
2732
/* Optional weights */
2733
vwgt = NULL;
2734
adjwgt = NULL;
2735
2736
if( !dual ) {
2737
/* Create weights if needed */
2738
if(data->periodicexist || eg->connect) {
2739
if(info) printf("Creating weight for %d connections.\n",totcon);
2740
wgtflag = 1;
2741
adjwgt = Ivector(0,totcon-1);
2742
for(i=0;i<totcon;i++)
2743
adjwgt[i] = 1;
2744
2745
if(metisopt != 3) {
2746
printf("For weighted partitioning Metis subroutine METIS_PartGraphKway is enforced\n");
2747
metisopt = 3;
2748
}
2749
}
2750
2751
/* Make the periodic connections stronger */
2752
if(data->periodicexist) {
2753
if(info) printf("Setting periodic connections to dominate %d\n",totcon);
2754
for(i=0;i<noknots;i++) {
2755
j = data->periodic[i+1]-1;
2756
if(j == i) continue;
2757
for(k=xadj[i];k<xadj[i+1];k++)
2758
if(adjncy[k] == j) adjwgt[k] = maxcon;
2759
}
2760
}
2761
2762
/* Make the constraint connections stronger */
2763
if(eg->connect) {
2764
int maxweight;
2765
int con,bc,bctype,sideelemtype,sidenodes;
2766
int j2,ind,ind2;
2767
int sideind[MAXNODESD1];
2768
2769
maxweight = noknots+noelements;
2770
printf("Adding weight of %d for constrained nodes\n",maxweight);
2771
2772
for(con=1;con<=eg->connect;con++) {
2773
bctype = eg->connectbounds[con-1];
2774
2775
for(bc=0;bc<MAXBOUNDARIES;bc++) {
2776
if(bound[bc].created == FALSE) continue;
2777
if(bound[bc].nosides == 0) continue;
2778
2779
for(i=1;i<=bound[bc].nosides;i++) {
2780
if(bound[bc].types[i] != bctype) continue;
2781
2782
GetBoundaryElement(i,&bound[bc],data,sideind,&sideelemtype);
2783
/* GetElementSide(bound[bc].parent[i],bound[bc].side[i],bound[bc].normal[i],
2784
data,sideind,&sideelemtype); */
2785
2786
sidenodes = sideelemtype%100;
2787
2788
for(j=0;j<sidenodes;j++) {
2789
for(j2=0;j2<sidenodes;j2++) {
2790
if(j==j2) continue;
2791
2792
ind = sideind[j]-1;
2793
ind2 = sideind[j2]-1;
2794
2795
for(k=xadj[ind];k<xadj[ind+1];k++)
2796
if(adjncy[k] == ind2) adjwgt[k] = maxweight;
2797
}
2798
}
2799
}
2800
}
2801
}
2802
}
2803
} /* !dual */
2804
2805
if(metisopt == 2) {
2806
if(info) printf("Starting graph partitioning METIS_PartGraphRecursive.\n");
2807
METIS_PartGraphRecursive(&nn,&ncon,xadj,adjncy,vwgt,&wgtflag,adjwgt,
2808
&nparts,NULL,NULL,options,&edgecut,npart);
2809
}
2810
else if( metisopt == 3 || metisopt == 4 ) {
2811
ncon = 1;
2812
wgtflag = 0;
2813
if(info) printf("Starting graph partitioning METIS_PartGraphKway.\n");
2814
METIS_PartGraphKway(&nn, /* number of vertices in the graph */
2815
&ncon, /* number of balancing constraints */
2816
xadj, adjncy, /* the adjacency structure of the graph */
2817
vwgt, /* weights of the vertices */
2818
&wgtflag, /* size of the vertices for computing communication */
2819
adjwgt, /* weight of the edges */
2820
&nparts, /* number of partitions */
2821
NULL, /* weights for each partition and constraint */
2822
NULL, /* allowed load imbalance */
2823
options, /* array of options */
2824
&edgecut, /* the total communication volume */
2825
npart); /* partition vector of the graph */
2826
}
2827
else {
2828
printf("Unknown Metis option %d\n",metisopt);
2829
}
2830
2831
if(info) printf("Finished Metis graph partitioning call.\n");
2832
2833
2834
free_Ivector(adjncy,0,totcon-1);
2835
free_Ivector(xadj,0,nn);
2836
if(wgtflag == 1) free_Ivector(adjwgt,0,totcon-1);
2837
2838
skippart:
2839
2840
if(!data->partitionexist) {
2841
data->partitionexist = TRUE;
2842
data->elempart = Ivector(1,noelements);
2843
data->nodepart = Ivector(1,noknots);
2844
data->nopartitions = partitions;
2845
}
2846
2847
/* Set the partition given by Metis for each node. */
2848
if( dual ) {
2849
if( data->elemconnectexist ) {
2850
for(i=1;i<=noelements;i++) {
2851
j = data->elemconnect[i];
2852
if( nparts == 1 ) {
2853
if(j)
2854
data->elempart[i] = j;
2855
else
2856
data->elempart[i] = maxconset+1;
2857
} else {
2858
if(j < 0)
2859
data->elempart[i] = -j;
2860
else
2861
data->elempart[i] = npart[j-1]+1+maxconset;
2862
}
2863
}
2864
}
2865
else {
2866
for(i=1;i<=nn;i++)
2867
data->elempart[i] = npart[i-1]+1;
2868
}
2869
PartitionNodesByElements(data,info);
2870
}
2871
else {
2872
for(i=1;i<=nn;i++)
2873
data->nodepart[i] = npart[i-1]+1;
2874
PartitionElementsByNodes(data,info);
2875
2876
/* Finally check that the constraint is really honored */
2877
if(!eg->connect) {
2878
int con,bc,bctype,sideelemtype,sidenodes,par;
2879
int ind,sideind[MAXNODESD1];
2880
int *sidehits,sidepartitions;
2881
2882
printf("Checking connection integrity\n");
2883
sidehits = Ivector(1,partitions);
2884
2885
for(con=1;con<=eg->connect;con++) {
2886
bctype = eg->connectbounds[con-1];
2887
2888
for(i=1;i<=partitions;i++)
2889
sidehits[i] = 0;
2890
2891
for(bc=0;bc<MAXBOUNDARIES;bc++) {
2892
if(bound[bc].created == FALSE) continue;
2893
if(bound[bc].nosides == 0) continue;
2894
2895
for(i=1;i<=bound[bc].nosides;i++) {
2896
if(bound[bc].types[i] != bctype) continue;
2897
2898
if(1)
2899
GetBoundaryElement(i,&bound[bc],data,sideind,&sideelemtype);
2900
else
2901
GetElementSide(bound[bc].parent[i],bound[bc].side[i],bound[bc].normal[i],
2902
data,sideind,&sideelemtype);
2903
sidenodes = sideelemtype%100;
2904
2905
for(j=0;j<sidenodes;j++) {
2906
ind = sideind[j];
2907
par = data->nodepart[ind];
2908
sidehits[par] += 1;
2909
}
2910
}
2911
}
2912
2913
sidepartitions = 0;
2914
for(i=1;i<=partitions;i++)
2915
if( sidehits[i] ) sidepartitions += 1;
2916
2917
if(sidepartitions != 1) {
2918
printf("PartitionMetisGraph: side %d belongs to %d partitions\n",bctype,sidepartitions);
2919
bigerror("Parallel constraints might not be set!");
2920
}
2921
}
2922
}
2923
}
2924
2925
if( nparts > 1 ) {
2926
free_Ivector(npart,0,nn-1);
2927
}
2928
2929
if(info) {
2930
if( dual )
2931
printf("Successfully made a Metis partition using the dual graph.\n");
2932
else
2933
printf("Successfully made a Metis partition using the nodal graph.\n");
2934
}
2935
2936
return(0);
2937
}
2938
2939
#endif
2940
2941
2942
static void CheckPartitioning(struct FemType *data,int info)
2943
{
2944
int i,j,k,partitions,part,part2,noknots,noelements,mini,maxi,sumi,hit,ind,nodesd2,elemtype;
2945
int *elempart, *nodepart,*elemsinpart,*nodesinpart,*sharedinpart;
2946
2947
noknots = data->noknots;
2948
noelements = data->noelements;
2949
partitions = data->nopartitions;
2950
elemsinpart = Ivector(1,partitions);
2951
nodesinpart = Ivector(1,partitions);
2952
sharedinpart = Ivector(1,partitions);
2953
for(i=1;i<=partitions;i++)
2954
elemsinpart[i] = nodesinpart[i] = sharedinpart[i] = 0;
2955
2956
if(info) printf("Checking for partitioning\n");
2957
2958
/* Check that division of elements */
2959
elempart = data->elempart;
2960
j=0;
2961
for(i=1;i<=data->noelements;i++) {
2962
part = elempart[i];
2963
if(part < 1 || part > partitions)
2964
j++;
2965
else
2966
elemsinpart[part] += 1;
2967
}
2968
if(j) {
2969
printf("Bad initial partitioning: %d elements do not belong anywhere!\n",j);
2970
bigerror("Can't continue with broken partitioning");
2971
}
2972
2973
/* Check the division of nodes */
2974
nodepart = data->nodepart;
2975
j=0;
2976
for(i=1;i<=data->noknots;i++) {
2977
part = nodepart[i];
2978
if(part < 1 || part > partitions)
2979
j++;
2980
else
2981
nodesinpart[part] += 1;
2982
}
2983
2984
if(j) {
2985
printf("Bad initial partitioning: %d nodes do not belong anywhere!\n",j);
2986
bigerror("Can't continue with broken partitioning");
2987
}
2988
2989
if(data->partitiontableexists) {
2990
for(i=1;i<=noknots;i++) {
2991
part = nodepart[i];
2992
for(j=1;j<=data->maxpartitiontable;j++) {
2993
part2 = data->partitiontable[j][i];
2994
if(!part2) break;
2995
if(part != part2) sharedinpart[part2] += 1;
2996
}
2997
}
2998
}
2999
3000
if(info) {
3001
printf("Information on partition bandwidth\n");
3002
if(partitions <= 10) {
3003
printf("Distribution of elements, nodes and shared nodes\n");
3004
printf(" %-10s %-10s %-10s %-10s\n","partition","elements","nodes","shared");
3005
for(i=1;i<=partitions;i++)
3006
printf(" %-10d %-10d %-10d %-10d\n",i,elemsinpart[i],nodesinpart[i],sharedinpart[i]);
3007
}
3008
else {
3009
mini = maxi = elemsinpart[1];
3010
for(i=1;i<=partitions;i++) {
3011
mini = MIN( elemsinpart[i], mini);
3012
maxi = MAX( elemsinpart[i], maxi);
3013
}
3014
printf("Average %d elements with range %d in partition\n",noelements/partitions,maxi-mini);
3015
3016
mini = maxi = nodesinpart[1];
3017
for(i=1;i<=partitions;i++) {
3018
mini = MIN( nodesinpart[i], mini);
3019
maxi = MAX( nodesinpart[i], maxi);
3020
}
3021
printf("Average %d nodes with range %d in partition\n",noknots/partitions,maxi-mini);
3022
3023
sumi = 0;
3024
mini = maxi = sharedinpart[1];
3025
for(i=1;i<=partitions;i++) {
3026
mini = MIN( sharedinpart[i], mini);
3027
maxi = MAX( sharedinpart[i], maxi);
3028
sumi += sharedinpart[i];
3029
}
3030
printf("Average %d shared nodes with range %d in partition\n",sumi/partitions,maxi-mini);
3031
}
3032
}
3033
3034
if(!data->maxpartitiontable) return;
3035
3036
if(0) printf("Checking that each node in elements belongs to nodes\n");
3037
for(i=1;i<=data->noelements;i++) {
3038
part = elempart[i];
3039
elemtype = data->elementtypes[i];
3040
nodesd2 = elemtype % 100;
3041
3042
for(j=0;j < nodesd2;j++) {
3043
ind = data->topology[i][j];
3044
3045
hit = FALSE;
3046
part2 = 0;
3047
for(k=1;k<=data->maxpartitiontable;k++) {
3048
part2 = data->partitiontable[k][ind];
3049
if( part == part2 ) hit = TRUE;
3050
if(hit && !part) break;
3051
}
3052
if(!hit) {
3053
printf("******** Warning *******\n");
3054
printf("Node %d in element %d does not belong to partition %d (%d)\n",ind,i,part,part2);
3055
printf("elemtype = %d nodesd2 = %d\n",elemtype,nodesd2);
3056
for(k=0;k < nodesd2;k++)
3057
printf("ind[%d] = %d\n",k,data->topology[i][k]);
3058
}
3059
}
3060
}
3061
3062
if(0) printf("Checking that each node in partition is shown in partition list\n");
3063
for(i=1;i<=data->noknots;i++) {
3064
part = nodepart[i];
3065
3066
hit = FALSE;
3067
for(j=1;j<=data->maxpartitiontable;j++) {
3068
part2 = data->partitiontable[j][i];
3069
if( part == part2 ) hit = TRUE;
3070
if(hit && !part) break;
3071
}
3072
if(!hit) {
3073
printf("***** Node %d in partition %d is not in partition list\n",i,part);
3074
}
3075
}
3076
}
3077
3078
3079
int OptimizePartitioningAtBoundary(struct FemType *data,struct BoundaryType *bound,int info)
3080
{
3081
int i,j,k,l,boundaryelems,ind,hit1,hit2,fix1,fix2;
3082
int dompart,part1,part2,newmam,mam1,mam2,nodesd2;
3083
int *alteredparent;
3084
3085
if(!data->partitionexist) {
3086
printf("OptimizePartitioningAtBoundary: this should be called only after partitioning\n");
3087
bigerror("Optimization not performed!");
3088
}
3089
3090
if(info) printf("Optimizing the partitioning at boundaries.\n");
3091
3092
/* Memorize the original parent */
3093
alteredparent = Ivector(1,data->noelements);
3094
for(i=1;i<=data->noelements;i++)
3095
alteredparent[i] = data->elempart[i];
3096
3097
3098
/* Set the secondary parent to be a parent also because we want all
3099
internal BCs to be within the same partition.
3100
Also set the nodes of the altered elements to be in the desired partition. */
3101
k = 0;
3102
do {
3103
k++;
3104
boundaryelems = 0;
3105
3106
for(j=0;j < MAXBOUNDARIES;j++) {
3107
if(!bound[j].created) continue;
3108
for(i=1; i <= bound[j].nosides; i++) {
3109
if(bound[j].ediscont)
3110
if(bound[j].discont[i]) continue;
3111
3112
mam1 = bound[j].parent[i];
3113
mam2 = abs(bound[j].parent2[i]);
3114
if(!mam1 || !mam2) continue;
3115
3116
part1 = data->elempart[mam1];
3117
part2 = data->elempart[mam2];
3118
if(part1 == part2) continue;
3119
3120
/* Check if both nodes are enforced to be fixed */
3121
if( data->elemconnectexist ) {
3122
fix1 = ( data->elemconnect[mam1] < 0 );
3123
fix2 = ( data->elemconnect[mam2] < 0 );
3124
if( fix1 && fix2 ) continue;
3125
}
3126
else {
3127
fix1 = fix2 = 0;
3128
}
3129
3130
/* The first iterations check which parents is ruling
3131
thereafter choose pragmatically the other to overcome
3132
oscillating solutions. */
3133
if(fix1 || fix2 ) {
3134
}
3135
if(k < 5) {
3136
hit1 = hit2 = 0;
3137
nodesd2 = data->elementtypes[mam1] % 100;
3138
for(l=0;l < nodesd2;l++) {
3139
ind = data->topology[mam1][l];
3140
if(data->nodepart[ind] == part1) hit1++;
3141
if(data->nodepart[ind] == part2) hit2++;
3142
}
3143
nodesd2 = data->elementtypes[mam2] % 100;
3144
for(l=0;l < nodesd2;l++) {
3145
ind = data->topology[mam2][l];
3146
if(data->nodepart[ind] == part1) hit1++;
3147
if(data->nodepart[ind] == part2) hit2++;
3148
}
3149
fix1 = ( hit1 >= hit2 );
3150
fix2 = !fix1;
3151
}
3152
else {
3153
fix1 = TRUE;
3154
fix2 = FALSE;
3155
}
3156
3157
/* Make the more ruling parent dominate the whole boundary */
3158
if(fix1) {
3159
dompart = part1;
3160
newmam = mam2;
3161
}
3162
else {
3163
dompart = part2;
3164
newmam = mam1;
3165
}
3166
3167
data->elempart[newmam] = dompart;
3168
boundaryelems++;
3169
3170
/* Move the ownership of all nodes to the leading partition */
3171
if(0) {
3172
nodesd2 = data->elementtypes[newmam] % 100;
3173
for(l=0;l < nodesd2;l++) {
3174
ind = data->topology[newmam][l];
3175
data->nodepart[ind] = dompart;
3176
}
3177
}
3178
else if(0) {
3179
nodesd2 = data->elementtypes[mam1] % 100;
3180
for(l=0;l < nodesd2;l++) {
3181
ind = data->topology[mam1][l];
3182
data->nodepart[ind] = dompart;
3183
}
3184
nodesd2 = data->elementtypes[mam2] % 100;
3185
for(l=0;l < nodesd2;l++) {
3186
ind = data->topology[mam2][l];
3187
data->nodepart[ind] = dompart;
3188
}
3189
}
3190
3191
}
3192
}
3193
if(info && boundaryelems)
3194
printf("Round %d: %d bulk elements with BCs removed from interface.\n",
3195
k,boundaryelems);
3196
} while(boundaryelems && k < 10);
3197
3198
3199
j = 0;
3200
for(i=1;i<=data->noelements;i++) {
3201
if(alteredparent[i] == data->elempart[i])
3202
alteredparent[i] = 0;
3203
else
3204
j++;
3205
}
3206
free_Ivector(alteredparent,1,data->noelements);
3207
if(info) printf("Ownership of %d parents was changed at BCs\n",j);
3208
3209
3210
3211
/* Remove the negative secondary parents that were only used to optimize the partitioning */
3212
for(j=0;j < MAXBOUNDARIES;j++) {
3213
if(!bound[j].created) continue;
3214
for(i=1; i <= bound[j].nosides; i++)
3215
bound[j].parent2[i] = MAX(0, bound[j].parent2[i]);
3216
}
3217
3218
if(0) printf("The partitioning at discontinuous gaps was optimized.\n");
3219
return(0);
3220
}
3221
3222
3223
static void Levelize(int n,int level,int *maxlevel,int *levels,int *rows,int *cols,int *done)
3224
{
3225
int j,k;
3226
3227
levels[n] = level;
3228
done[n] = TRUE;
3229
*maxlevel = MAX( *maxlevel,level );
3230
3231
for( j=rows[n]; j<rows[n+1]; j++ ) {
3232
k = cols[j];
3233
if ( !done[k] ) Levelize(k,level+1,maxlevel,levels,rows,cols,done);
3234
}
3235
}
3236
3237
3238
static int RenumberCuthillMckee( int nrows, int *rows, int *cols, int *iperm )
3239
{
3240
int i,j,k,n,startn,mindegree,maxlevel,newroot,bw_bef,bw_aft;
3241
int *level,*degree,*done;
3242
3243
done = Ivector(0,nrows-1);
3244
level = Ivector(0,nrows-1);
3245
degree = Ivector(0,nrows-1);
3246
3247
bw_bef = 0;
3248
for(i=0; i<nrows; i++ )
3249
{
3250
for( j=rows[i]; j<rows[i+1]; j++ )
3251
bw_bef = MAX( bw_bef, ABS(cols[j]-i)+1 );
3252
degree[i] = rows[i+1]-rows[i];
3253
}
3254
printf( "RenumberCuthillMckee: Bandwidth before: %d\n", bw_bef );
3255
3256
startn = 0;
3257
mindegree = degree[startn];
3258
for( i=0; i<nrows; i++ ) {
3259
if ( degree[i] < mindegree ) {
3260
startn = i;
3261
mindegree = degree[i];
3262
}
3263
level[i] = 0;
3264
}
3265
3266
maxlevel = 0;
3267
for( i=0; i<nrows; i++ ) done[i]=FALSE;
3268
3269
Levelize( startn,0,&maxlevel,level,rows,cols,done );
3270
3271
newroot = TRUE;
3272
while(newroot) {
3273
newroot = FALSE;
3274
mindegree = degree[startn];
3275
k = startn;
3276
3277
for( i=0; i<nrows; i++ ) {
3278
if ( level[i] == maxlevel ) {
3279
if ( degree[i] < mindegree ) {
3280
k = i;
3281
mindegree = degree[i];
3282
}
3283
}
3284
}
3285
3286
if ( k != startn ) {
3287
j = maxlevel;
3288
maxlevel = 0;
3289
for(i=0; i<nrows; i++ ) done[i]=FALSE;
3290
3291
Levelize( k,0,&maxlevel,level,rows,cols,done );
3292
3293
if ( j > maxlevel ) {
3294
newroot = TRUE;
3295
startn = j;
3296
}
3297
}
3298
}
3299
3300
for(i=0; i<nrows; i++ ) done[i]=-1,iperm[i]=-1;
3301
3302
done[0]=startn;
3303
iperm[startn]=0;
3304
i=1;
3305
3306
for( j=0; j<nrows; j++ ) {
3307
if ( done[j]<0 ) {
3308
for( k=0; k<nrows; k++ ) {
3309
if ( iperm[k]<0 ) {
3310
done[i]=k;
3311
iperm[k]=i;
3312
i++;
3313
break;
3314
}
3315
}
3316
}
3317
3318
for( k=rows[done[j]]; k<rows[done[j]+1]; k++) {
3319
n = cols[k];
3320
if ( iperm[n]<0 ) {
3321
done[i] = n;
3322
iperm[n] = i;
3323
i++;
3324
}
3325
}
3326
}
3327
3328
for( i=0; i<nrows; i++ )
3329
iperm[done[i]] = nrows-1-i;
3330
3331
bw_aft = 0;
3332
for(i=0; i<nrows; i++ )
3333
for( j=rows[i]; j<rows[i+1]; j++ )
3334
bw_aft = MAX( bw_aft, ABS(iperm[cols[j]]-iperm[i])+1 );
3335
3336
printf( "RenumberCuthillMckee: Bandwidth after: %d\n", bw_aft );
3337
3338
free_Ivector(level,0,nrows-1);
3339
free_Ivector(done,0,nrows-1);
3340
free_Ivector(degree,0,nrows-1);
3341
3342
return bw_aft < bw_bef;
3343
}
3344
3345
3346
3347
static void RenumberPartitions(struct FemType *data,int info)
3348
/* Minimize bandwidth of partition indexing. This could be favourable if the
3349
communication between neighbouring partitions is faster than between
3350
partitions with larger partition index. Probably there is not much
3351
difference for normal hardware configurations. */
3352
{
3353
int i,j,k,l,m,hit,con,totcon,noelements,noknots,partitions;
3354
int maxneededtimes,totneededtimes;
3355
int part,part1,part2,bw_reduced;
3356
int *nodepart,*elempart;
3357
int *perm;
3358
int *xadj,*adjncy;
3359
int *partparttable[MAXCONNECTIONS];
3360
3361
3362
if(info) printf("Renumbering partitions to minimize bandwidth.\n");
3363
3364
partitions = data->nopartitions;
3365
noelements = data->noelements;
3366
noknots = data->noknots;
3367
maxneededtimes = data->maxpartitiontable;
3368
3369
3370
/* Make the partition-partition list from the node-partition list */
3371
totneededtimes = 0;
3372
totcon = 0;
3373
for(i=1;i<=noknots;i++) {
3374
if(data->partitiontable[2][i] == 0) continue;
3375
for(j=1;j<=maxneededtimes;j++) {
3376
part1 = data->partitiontable[j][i];
3377
if(!part1) break;
3378
3379
for(k=1;k<=maxneededtimes;k++) {
3380
if(k==j) continue;
3381
part2 = data->partitiontable[k][i];
3382
if(!part2) break;
3383
3384
hit = 0;
3385
for(l=1;l<=totneededtimes;l++) {
3386
if(partparttable[l][part1] == part2) {
3387
hit = -1;
3388
break;
3389
}
3390
else if(partparttable[l][part1] == 0) {
3391
totcon++;
3392
partparttable[l][part1] = part2;
3393
hit = 1;
3394
break;
3395
}
3396
}
3397
if(!hit) {
3398
totneededtimes++;
3399
partparttable[totneededtimes] = Ivector(1,partitions);
3400
for(m=1;m<=partitions;m++)
3401
partparttable[totneededtimes][m] = 0;
3402
partparttable[totneededtimes][part1] = part2;
3403
totcon++;
3404
}
3405
}
3406
}
3407
}
3408
3409
if(info) {
3410
printf("There are %d connections altogether\n",totcon);
3411
printf("There are %.3f connections between partitions in average\n",1.0*totcon/partitions);
3412
}
3413
3414
3415
xadj = Ivector(0,partitions);
3416
adjncy = Ivector(0,totcon-1);
3417
for(i=0;i<totcon;i++)
3418
adjncy[i] = 0;
3419
3420
totcon = 0;
3421
for(i=1;i<=partitions;i++) {
3422
xadj[i-1] = totcon;
3423
for(j=1;j<=totneededtimes;j++) {
3424
con = partparttable[j][i];
3425
if(!con) continue;
3426
adjncy[totcon] = con-1;
3427
totcon++;
3428
}
3429
}
3430
xadj[partitions] = totcon;
3431
3432
perm = Ivector(0,partitions-1);
3433
bw_reduced = RenumberCuthillMckee( partitions, xadj, adjncy, perm );
3434
3435
3436
/* Print the new order of partitions */
3437
if(0 && info) {
3438
printf( "Partition order after Cuthill-McKee bandwidth optimization: \n" );
3439
for(i=0;i<partitions;i++)
3440
printf("old=%d new=%d\n",i,perm[i] );
3441
}
3442
3443
/* Use the renumbering or not */
3444
if(bw_reduced) {
3445
if(info) printf("Successful ordering: moving partitions to new positions\n");
3446
nodepart = data->nodepart;
3447
elempart = data->elempart;
3448
for(i=1;i<=noelements;i++)
3449
elempart[i] = perm[elempart[i]-1]+1;
3450
for(i=1;i<=noknots;i++)
3451
nodepart[i] = perm[nodepart[i]-1]+1;
3452
for(i=1;i<=noknots;i++) {
3453
for(j=1;j<=maxneededtimes;j++) {
3454
part = data->partitiontable[j][i];
3455
if(!part) break;
3456
data->partitiontable[j][i] = perm[part-1]+1;
3457
}
3458
}
3459
}
3460
3461
for(i=1;i<=totneededtimes;i++)
3462
free_Ivector(partparttable[i],1,partitions);
3463
free_Ivector(xadj,0,partitions);
3464
free_Ivector(adjncy,0,totcon-1);
3465
3466
3467
}
3468
3469
3470
static int CheckSharedDeviation(int *neededvector,int partitions,int info)
3471
{
3472
int i,minshared,maxshared,dshared;
3473
Real sumshared, sumshared2, varshared, needed, det, ave;
3474
3475
sumshared = sumshared2 = 0.0;
3476
minshared = maxshared = neededvector[1];
3477
for(i=1;i<=partitions;i++) {
3478
needed = 1.0 * neededvector[i];
3479
sumshared += needed;
3480
sumshared2 += (needed * needed);
3481
maxshared = MAX(maxshared, neededvector[i]);
3482
minshared = MIN(minshared, neededvector[i]);
3483
}
3484
3485
dshared = maxshared - minshared;
3486
3487
if(info) {
3488
ave = sumshared / partitions;
3489
det = 1.0*sumshared2 / partitions - 1.0*(sumshared/partitions)*(sumshared / partitions);
3490
varshared = sqrt( det );
3491
3492
printf("Average number of elements in partition %.3le\n",ave);
3493
printf("Maximum deviation in ownership %d\n",dshared);
3494
printf("Average deviation in ownership %.3le\n",varshared);
3495
printf("Average relative deviation %.2lf %%\n",100.0*varshared/ave);
3496
}
3497
3498
return(dshared);
3499
}
3500
3501
3502
3503
3504
int OptimizePartitioning(struct FemType *data,struct BoundaryType *bound,int noopt,
3505
int partbw, int info)
3506
/* Optimize partitioning of elements so that each partition has as closely as possible the
3507
desired amount of elements. Also, ir requested, check that there are no odd couplings within
3508
elements that are not directly present at the given partition. It is a bit unclear
3509
to which extent these checks are needed in the current Elmer version. */
3510
{
3511
int i,j,k,l,n,m,noelements,partitions,ind,hit;
3512
int noknots,dshared,dshared0;
3513
int *elempart,*nodepart,sharings,maxshared;
3514
int nodesd2,maxneededtimes,*probnodes=NULL,optimize;
3515
int *neededvector;
3516
int somethingdone = 0;
3517
int *elemparts = NULL,*invelemparts = NULL;
3518
int **knows = NULL;
3519
3520
if(!data->partitionexist) {
3521
printf("OptimizePartitioning: this should be called only after partitioning\n");
3522
bigerror("Optimization not performed!");
3523
}
3524
3525
noknots = data->noknots;
3526
noelements = data->noelements;
3527
partitions = data->nopartitions;
3528
if(info) printf("Optimizing for %d partitions\n", partitions);
3529
3530
elempart = data->elempart;
3531
nodepart = data->nodepart;
3532
maxshared = 0;
3533
3534
if( partitions < 2 ) {
3535
printf("OptimizePartitioning: does not make sense for %d partitions\n",partitions);
3536
bigerror("Optimization not performed!");
3537
}
3538
3539
/* Create a table showing to which partitions nodes belong to */
3540
CreatePartitionTable(data,info);
3541
maxneededtimes = data->maxpartitiontable;
3542
3543
/* Renumber the bandwidth of partition-partition connections */
3544
if(partbw) RenumberPartitions(data,info);
3545
3546
/* Check partitioning after table is created for the first time */
3547
printf("Checking partitioning before optimization\n");
3548
CheckPartitioning(data,info);
3549
3550
/* Calculate how many nodes is owned by each partition */
3551
neededvector = Ivector(1,partitions);
3552
for(i=1;i<=partitions;i++)
3553
neededvector[i] = 0;
3554
for(i=1;i<=noknots;i++)
3555
neededvector[nodepart[i]] += 1;
3556
3557
if(!noopt) {
3558
optimize = 1;
3559
probnodes = Ivector(1,noknots);
3560
for(i=1;i<=noknots;i++)
3561
probnodes[i] = 0;
3562
printf("Applying aggressive optimization for load balancing\n");
3563
}
3564
else {
3565
optimize = 1;
3566
}
3567
3568
optimizeownership:
3569
3570
dshared = CheckSharedDeviation(neededvector,partitions,info);
3571
3572
if(!noopt) {
3573
3574
/* Distribute the shared nodes as evenly as possible. */
3575
3576
int nochanges, maxrounds, dtarget;
3577
3578
maxrounds = 5;
3579
dtarget = 3;
3580
nochanges = 0;
3581
3582
for(n=1;n<=maxrounds;n++) {
3583
nochanges = 0;
3584
3585
for(i=1;i<=noknots;i++) {
3586
ind = i;
3587
3588
/* owner partition may only be changed it there a are two of them */
3589
k = data->partitiontable[2][ind];
3590
if(!k) continue;
3591
3592
/* only apply the switch to cases with exactly two partitions
3593
to avoid the nasty multiply coupled nodes. */
3594
if(maxneededtimes > 2)
3595
if(data->partitiontable[3][ind]) continue;
3596
3597
/* Do not change the ownership of nodes that cause topological problems */
3598
if(probnodes[ind]) continue;
3599
3600
j = data->partitiontable[1][ind];
3601
3602
/* Switch the owner to the smaller owner group if possible */
3603
if(abs(neededvector[j] - neededvector[k]) < dtarget ) continue;
3604
3605
if(neededvector[j] < neededvector[k] && nodepart[ind] == k) {
3606
nochanges++;
3607
neededvector[j] += 1;
3608
neededvector[k] -= 1;
3609
nodepart[ind] = j;
3610
}
3611
else if(neededvector[k] < neededvector[j] && nodepart[ind] == j) {
3612
nochanges++;
3613
neededvector[k] += 1;
3614
neededvector[j] -= 1;
3615
nodepart[ind] = k;
3616
}
3617
}
3618
if(info && nochanges) printf("Changed the ownership of %d nodes\n",nochanges);
3619
3620
dshared0 = dshared;
3621
dshared = CheckSharedDeviation(neededvector,partitions,info);
3622
3623
if(dshared >= dshared0) break;
3624
somethingdone = somethingdone + nochanges;
3625
}
3626
}
3627
3628
3629
/* optimizesharing: */
3630
3631
if(info) printf("Checking for problematic sharings\n");
3632
m = 0;
3633
3634
if(partitions > 2) {
3635
if(info) printf("Optimizing sharing for %d partitions\n", partitions);
3636
3637
do {
3638
3639
int i1,i2,e1,e2,owners;
3640
3641
m++;
3642
sharings = 0;
3643
i1 = i2 = 0;
3644
e1 = e2 = 0;
3645
3646
/* There cannot be more partitions sharing a node than there are
3647
node in the elements. Elementtype 827 has 27 nodes. */
3648
maxshared = 27;
3649
if(m == 1 && optimize == 1) {
3650
elemparts = Ivector(1,partitions);
3651
invelemparts = Ivector(1,maxshared);
3652
knows = Imatrix(1,maxshared,1,maxshared);
3653
}
3654
3655
for(j=1;j<=partitions;j++)
3656
elemparts[j] = 0;
3657
3658
for(j=1;j<=maxshared;j++)
3659
invelemparts[j] = 0;
3660
3661
for(j=1;j<=maxshared;j++)
3662
for(k=1;k<=maxshared;k++)
3663
knows[j][k] = 0;
3664
3665
for(i=1;i<=noelements;i++) {
3666
int ownpart;
3667
3668
owners = 0;
3669
nodesd2 = data->elementtypes[i] % 100;
3670
ownpart = FALSE;
3671
3672
/* Check the number of owners in an element */
3673
for(j=0;j < nodesd2;j++) {
3674
ind = data->topology[i][j];
3675
k = nodepart[ind];
3676
3677
/* Mark if the element partition is one of the owners */
3678
if( k == elempart[i]) ownpart = TRUE;
3679
if(!elemparts[k]) {
3680
owners++;
3681
elemparts[k] = owners;
3682
invelemparts[owners] = k;
3683
}
3684
}
3685
3686
/* One strange owner is still ok. */
3687
if(owners - ownpart <= 1) {
3688
/* Nullify the elemparts vector */
3689
for(j=1;j<=owners;j++) {
3690
k = invelemparts[j];
3691
elemparts[k] = 0;
3692
}
3693
continue;
3694
}
3695
3696
/* Check which of the partitions are related by a common node */
3697
for(j=0;j < nodesd2;j++) {
3698
ind = data->topology[i][j];
3699
for(l=1;l<=maxneededtimes;l++) {
3700
e1 = data->partitiontable[l][ind];
3701
if(!e1) break;
3702
e1 = elemparts[e1];
3703
if(!e1) continue;
3704
for(k=l+1;k<=maxneededtimes;k++) {
3705
e2 = data->partitiontable[k][ind];
3706
if(!e2) break;
3707
e2 = elemparts[e2];
3708
if(!e2) continue;
3709
knows[e1][e2] = knows[e2][e1] = TRUE;
3710
}
3711
}
3712
}
3713
3714
/* Check if there are more complex relations:
3715
i.e. two partitions are joined at an element but not at the same node. */
3716
hit = FALSE;
3717
for(j=1;j<=owners;j++)
3718
for(k=j+1;k<=owners;k++) {
3719
if(!knows[j][k]) {
3720
hit += 1;
3721
i1 = invelemparts[j];
3722
i2 = invelemparts[k];
3723
}
3724
}
3725
/* Nullify the elemparts vector */
3726
for(j=1;j<=owners;j++) {
3727
k = invelemparts[j];
3728
elemparts[k] = 0;
3729
}
3730
3731
/* Nullify the knows matrix */
3732
for(j=1;j <= owners;j++)
3733
for(k=1;k <= owners;k++)
3734
knows[j][k] = FALSE;
3735
3736
if(hit) {
3737
e1 = e2 = 0;
3738
3739
if(info) {
3740
if( hit + m > 2 ) printf("Partitions %d and %d in element %d (%d owners) oddly related %d times\n",
3741
i1,i2,i,owners,hit);
3742
}
3743
3744
/* Count the number of nodes with wrong parents */
3745
for(j=0;j < nodesd2;j++) {
3746
ind = data->topology[i][j];
3747
for(l=1;l<=maxneededtimes;l++) {
3748
k = data->partitiontable[l][ind];
3749
if(k == 0) break;
3750
if(k == i1) e1++;
3751
if(k == i2) e2++;
3752
}
3753
}
3754
3755
/* Change the owner of those with less sharings */
3756
for(j=0;j < nodesd2;j++) {
3757
ind = data->topology[i][j];
3758
k = nodepart[ind];
3759
if((k == i1 && e1 < e2) || (k == i2 && e1 >= e2)) {
3760
if(!noopt) probnodes[ind] += 1;
3761
nodepart[ind] = elempart[i];
3762
neededvector[elempart[i]] += 1;
3763
neededvector[k] -= 1;
3764
}
3765
}
3766
sharings++;
3767
}
3768
}
3769
3770
somethingdone += sharings;
3771
if(info && sharings) printf("Changed the ownership of %d nodes\n",sharings);
3772
3773
} while (sharings > 0 && m < 3);
3774
3775
if(info) {
3776
if(sharings)
3777
printf("%d problematic sharings may still exist\n",sharings);
3778
else
3779
printf("There shouldn't be any problematic sharings, knock, knock...\n");
3780
}
3781
}
3782
3783
/* This seems to work also iteratively */
3784
if(!noopt && m+n > 10 && optimize < 50) {
3785
optimize++;
3786
printf("Performing ownership optimization round %d\n",optimize);
3787
goto optimizeownership;
3788
}
3789
3790
free_Ivector(neededvector,1,partitions);
3791
3792
if(!noopt) {
3793
free_Ivector(probnodes,1,noknots);
3794
if(partitions > 2) {
3795
free_Ivector(elemparts,1,partitions);
3796
free_Ivector(invelemparts,1,maxshared);
3797
free_Imatrix(knows,1,maxshared,1,maxshared);
3798
}
3799
}
3800
3801
3802
if(somethingdone) {
3803
if( info ) {
3804
printf("The partitioning was optimized: %d\n",somethingdone);
3805
printf("Checking partitioning after optimization\n");
3806
}
3807
CheckPartitioning(data,info);
3808
}
3809
else {
3810
if(info) printf("Partitioning was not altered\n");
3811
}
3812
3813
return(0);
3814
}
3815
3816
3817
int SaveElmerInputPartitioned(struct FemType *data,struct BoundaryType *bound,
3818
char *prefix,int decimals,int *parthalo,int indirect,
3819
int parthypre,int subparts,int nooverwrite, int info)
3820
/* Saves the mesh in a form that may be used as input
3821
in Elmer calculations in parallel platforms.
3822
*/
3823
{
3824
int noknots,noelements,sumsides,partitions,hit,found,parent,parent2,maxnosides;
3825
int nodesd2,nodesd1,discont,maxelemtype,minelemtype,sidehits,elemsides,side,bctype;
3826
int part,otherpart,part2,part3,elemtype,sideelemtype,*needednodes,*neededtwice;
3827
int **bulktypes,*sidetypes,tottypes,splitsides;
3828
int i,j,k,l,l2,l3,m,n,ind,ind2,sideind[MAXNODESD1],elemhit[MAXNODESD2];
3829
char filename[MAXFILESIZE],outstyle[MAXFILESIZE];
3830
char directoryname[MAXFILESIZE],subdirectoryname[MAXFILESIZE];
3831
int *neededtimes,*elempart,*elementsinpart,*indirectinpart,*sidesinpart;
3832
int maxneededtimes,indirecttype,bcneeded,trueparent,trueparent2,*ownerpart;
3833
int *sharednodes,*ownnodes,reorder,*order=NULL,*invorder=NULL;
3834
int *bcnode,*bcnodedummy,*elementhalo,*neededtimes2;
3835
int partstart,partfin,filesetsize,nofile,nofile2,nobcnodes,hasbcnodes,halomode;
3836
int halobulkelems,halobcs,savethis,fail=0,cdstat,immersed,halocopies,anyparthalo;
3837
int totsides;
3838
3839
FILE *out,*outfiles[MAXPARTITIONS+1];
3840
int sumelementsinpart,sumownnodes,sumsharednodes,sumsidesinpart,sumindirect;
3841
3842
3843
3844
if(info) {
3845
printf("Saving Elmer mesh in partitioned format\n");
3846
if( subparts ) printf("There are %d subpartitions\n",subparts);
3847
}
3848
3849
if(!data->created) {
3850
printf("You tried to save points that were never created.\n");
3851
bigerror("No Elmer mesh files saved!");
3852
}
3853
3854
partitions = data->nopartitions;
3855
if(!partitions) {
3856
printf("Tried to save partitioned format without partitions!\n");
3857
bigerror("No Elmer mesh files saved!");
3858
}
3859
3860
anyparthalo = FALSE;
3861
for(i=0;i<MAXHALOMODES;i++) {
3862
if( parthalo[i] ) {
3863
printf("Saving halo elements mode active: %d\n",i);
3864
anyparthalo = TRUE;
3865
}
3866
}
3867
3868
if( subparts < 1 && parthalo[3] ) {
3869
printf("There can be no layer halo since there are no layers!\n");
3870
bigerror("No Elmer mesh files saved!");
3871
}
3872
3873
3874
elempart = data->elempart;
3875
ownerpart = data->nodepart;
3876
noelements = data->noelements;
3877
noknots = data->noknots;
3878
3879
minelemtype = 101;
3880
maxelemtype = GetMaxElementType(data);
3881
indirecttype = 0;
3882
halobulkelems = 0;
3883
3884
needednodes = Ivector(1,partitions);
3885
neededtwice = Ivector(1,partitions);
3886
sharednodes = Ivector(1,partitions);
3887
ownnodes = Ivector(1,partitions);
3888
sidetypes = Ivector(minelemtype,maxelemtype);
3889
bulktypes = Imatrix(1,partitions,minelemtype,maxelemtype);
3890
bcnodedummy = Ivector(1,noknots);
3891
3892
/* Order the nodes so that the different partitions have a continuous interval of nodes.
3893
This information is used only just before the saving of node indexes in each instance.
3894
This feature was coded for collaboration with Hypre library that assumes this. */
3895
reorder = parthypre;
3896
if(reorder) {
3897
order = Ivector(1,noknots);
3898
k = 0;
3899
for(j=1;j<=partitions;j++)
3900
for(i=1; i <= noknots; i++)
3901
if(ownerpart[i] == j) {
3902
k++;
3903
order[i] = k;
3904
}
3905
invorder = Ivector(1,noknots);
3906
for(i=1;i<=noknots;i++)
3907
invorder[order[i]] = i;
3908
if(info) printf("Created continuous parallel ordering\n");
3909
}
3910
3911
/* Mark the nodes that are on some boundary in order to create boundary halos */
3912
bcnode = Ivector(1,noknots);
3913
for(i=1;i<=noknots;i++)
3914
bcnode[i] = FALSE;
3915
for(j=0;j < MAXBOUNDARIES;j++) {
3916
if(!bound[j].created) continue;
3917
for(i=1; i <= bound[j].nosides; i++) {
3918
GetBoundaryElement(i,&bound[j],data,sideind,&sideelemtype);
3919
nodesd1 = sideelemtype%100;
3920
for(l=0;l<nodesd1;l++)
3921
bcnode[sideind[l]] = 1;
3922
}
3923
}
3924
nobcnodes = 0;
3925
for(i=1;i<=noknots;i++) {
3926
if( bcnode[i] == 1) nobcnodes += 1;
3927
}
3928
if(info) printf("Number of boundary nodes at the boundary: %d\n",nobcnodes);
3929
3930
3931
for(i=1;i<=noknots;i++)
3932
bcnodedummy[i] = 0;
3933
for(i=1;i<=noelements;i++) {
3934
k = data->material[i];
3935
elemtype = data->elementtypes[i];
3936
nodesd2 = elemtype%100;
3937
3938
for(j=0;j < nodesd2;j++) {
3939
ind = data->topology[i][j];
3940
if( bcnode[ind] == 1) continue;
3941
if( bcnodedummy[ind] ) {
3942
if( bcnodedummy[ind] != k ) bcnode[ind] = 2;
3943
} else {
3944
bcnodedummy[ind] = k;
3945
}
3946
}
3947
}
3948
nobcnodes = 0;
3949
for(i=1;i<=noknots;i++) {
3950
if( bcnode[i] == 2) nobcnodes += 1;
3951
}
3952
if(info) printf("Number of additional interface nodes: %d\n",nobcnodes);
3953
3954
3955
sprintf(directoryname,"%s",prefix);
3956
sprintf(subdirectoryname,"%s.%d","partitioning",partitions);
3957
3958
3959
#ifdef MINGW32
3960
mkdir(directoryname);
3961
#else
3962
fail = mkdir(directoryname,0750);
3963
#endif
3964
if(info && !fail) printf("Created mesh directory: %s\n",directoryname);
3965
fail = chdir(directoryname);
3966
#ifdef MINGW32
3967
fail = mkdir(subdirectoryname);
3968
#else
3969
fail = mkdir(subdirectoryname,0750);
3970
#endif
3971
if(fail) {
3972
if(info) printf("Reusing existing subdirectory: %s\n",subdirectoryname);
3973
if(nooverwrite) {
3974
printf("Mesh seems to already exist, writing is cancelled!\n");
3975
return(0);
3976
}
3977
}
3978
else {
3979
if(info) printf("Created subdirectory: %s\n",subdirectoryname);
3980
}
3981
cdstat = chdir(subdirectoryname);
3982
3983
3984
3985
if(info) printf("Saving mesh in parallel ElmerSolver format to directory %s/%s.\n",
3986
directoryname,subdirectoryname);
3987
3988
filesetsize = MAXPARTITIONS;
3989
if(partitions > filesetsize)
3990
if(info) printf("Saving %d partitions in maximum sets of %d\n",partitions,filesetsize);
3991
3992
elementsinpart = Ivector(1,partitions);
3993
indirectinpart = Ivector(1,partitions);
3994
sidesinpart = Ivector(1,partitions);
3995
elementhalo = Ivector(1,partitions);
3996
for(i=1;i<=partitions;i++)
3997
elementsinpart[i] = indirectinpart[i] = sidesinpart[i] = elementhalo[i] = 0;
3998
3999
for(j=1;j<=partitions;j++)
4000
for(i=minelemtype;i<=maxelemtype;i++)
4001
bulktypes[j][i] = 0;
4002
4003
/* Compute how many times a node may be needed at maximum */
4004
maxneededtimes = data->maxpartitiontable;
4005
neededtimes = Ivector(1,noknots);
4006
for(i=1;i<=noknots;i++) {
4007
neededtimes[i] = 0;
4008
for(j=1;j<=maxneededtimes;j++)
4009
if(data->partitiontable[j][i]) neededtimes[i] += 1;
4010
}
4011
if(info) printf("Nodes belong to %d partitions in maximum\n",maxneededtimes);
4012
4013
4014
/*********** part.n.elements *********************/
4015
/* Save elements in all partitions and where they are needed */
4016
4017
4018
partstart = 1;
4019
partfin = MIN( partitions, filesetsize );
4020
4021
next_elements_set:
4022
4023
for(part=partstart;part<=partfin;part++) {
4024
sprintf(filename,"%s.%d.%s","part",part,"elements");
4025
nofile = part - partstart + 1;
4026
outfiles[nofile] = fopen(filename,"w");
4027
}
4028
4029
for(i=1;i<=noelements;i++) {
4030
part = elempart[i];
4031
4032
elemtype = data->elementtypes[i];
4033
nodesd2 = elemtype%100;
4034
4035
if(part >= partstart && part <= partfin) {
4036
nofile = part - partstart + 1;
4037
bulktypes[part][elemtype] += 1;
4038
elementsinpart[part] += 1;
4039
4040
fprintf(outfiles[nofile],"%d %d %d ",i,data->material[i],elemtype);
4041
4042
for(j=0;j < nodesd2;j++) {
4043
ind = data->topology[i][j];
4044
if(reorder) ind = order[ind];
4045
fprintf(outfiles[nofile],"%d ",ind);
4046
}
4047
fprintf(outfiles[nofile],"\n");
4048
}
4049
4050
4051
if(!anyparthalo) continue;
4052
halocopies = 0;
4053
4054
4055
4056
for( halomode = 1; halomode <= 4; halomode++) {
4057
4058
if(!parthalo[halomode]) continue;
4059
4060
4061
/* This creates a simple halo when the elements have been partitioned such
4062
that they are in number of "subparts" intervals of z coordinate. */
4063
if( halomode == 3 ) {
4064
if( part <= subparts ) {
4065
int leftright;
4066
for(leftright=-1;leftright <=1;leftright += 2) {
4067
part2 = part+leftright;
4068
if( part2 < 1 || part2 > subparts ) continue;
4069
elementhalo[part2] = i;
4070
halocopies += 1;
4071
}
4072
}
4073
}
4074
4075
/* For the following halos we study the shared and boundary nodes. */
4076
otherpart = 0;
4077
hasbcnodes = FALSE;
4078
for(j=0;j < nodesd2;j++) {
4079
ind = data->topology[i][j];
4080
if(neededtimes[ind] > 1) otherpart++;
4081
if(bcnode[ind]) hasbcnodes = TRUE;
4082
}
4083
4084
/* Classical halo needed by discontinuous Galerkin.
4085
Elements that are attached by joined face element are added to halo */
4086
if( halomode == 1 && otherpart ) {
4087
/* If the saving of halo is requested check it for elements which have at least
4088
two nodes in shared partitions. First make this quick test. */
4089
4090
elemsides = elemtype / 100;
4091
if(elemsides == 8) {
4092
immersed = (otherpart >= 4);
4093
elemsides = 6;
4094
}
4095
else if(elemsides == 7) {
4096
immersed = (otherpart >= 3);
4097
elemsides = 5;
4098
}
4099
else if(elemsides == 6) {
4100
immersed = (otherpart >= 3);
4101
elemsides = 5;
4102
}
4103
else if(elemsides == 5) {
4104
immersed = (otherpart >= 3);
4105
elemsides = 4;
4106
}
4107
else {
4108
immersed = (otherpart >= 2);
4109
}
4110
4111
if( immersed ) {
4112
4113
/* In order for the halo to be present the element should have a boundary
4114
fully immersed in the other partition. This test takes more time. */
4115
4116
for(side=0;side<elemsides;side++) {
4117
4118
GetElementSide(i,side,1,data,&sideind[0],&sideelemtype);
4119
4120
/* Because every node must be on the boundary use the 1st index as the
4121
first test */
4122
for(l=1;l<=neededtimes[sideind[0]];l++) {
4123
part2 = data->partitiontable[l][sideind[0]];
4124
4125
/* We did already save this in partition part */
4126
if(part2 == part) continue;
4127
if(elementhalo[part2] == i) continue;
4128
if(part2 < partstart || part2 > partfin) continue;
4129
4130
/* Now check that also the other nodes on the face are at the interface */
4131
sidehits = 1;
4132
for(k=1;k<sideelemtype%100;k++) {
4133
for(l2=1;l2<=neededtimes[sideind[k]];l2++) {
4134
part3 = data->partitiontable[l2][sideind[k]];
4135
if(part2 == part3) sidehits++;
4136
}
4137
}
4138
if( sidehits < sideelemtype % 100 ) continue;
4139
4140
if(0) printf("Adding halo for partition %d and element %d\n",part2,i);
4141
4142
/* Remember that this element is saved for this partition */
4143
elementhalo[part2] = i;
4144
halocopies += 1;
4145
}
4146
}
4147
}
4148
}
4149
4150
/* This creates a halo that includes all elements attached to boundary or interface nodes */
4151
if( halomode == 2 && hasbcnodes ) {
4152
for(j=0;j < nodesd2;j++) {
4153
ind = data->topology[i][j];
4154
4155
/* If the node is not on the boundary then cycle */
4156
if( !bcnode[ind] ) continue;
4157
4158
/* Check to which partitions this element is associated with */
4159
for(k=1;k<=neededtimes[ind];k++) {
4160
part2 = data->partitiontable[k][ind];
4161
4162
/* This element is already saved to its primary partition */
4163
if( part == part2 ) continue;
4164
if( elementhalo[part2] == i) continue;
4165
if( part2 < partstart || part2 > partfin ) continue;
4166
4167
if(0) printf("Adding bc halo for partition %d and element %d\n",part2,i);
4168
4169
/* Remember that this element is saved for this partition */
4170
elementhalo[part2] = i;
4171
halocopies += 1;
4172
}
4173
}
4174
}
4175
4176
/* This greedy routine makes the halo even if there is just one node in the shared boundary.
4177
Currently not active. */
4178
if( halomode == 4 && otherpart ) {
4179
for(j=0;j < nodesd2;j++) {
4180
ind = data->topology[i][j];
4181
if(neededtimes[ind] == 1) continue;
4182
4183
for(l=1;l<=neededtimes[ind];l++) {
4184
part2 = data->partitiontable[l][ind];
4185
4186
/* We did already save this in partition part */
4187
if(part2 == part) continue;
4188
if( elementhalo[part2] == i) continue;
4189
if(part2 < partstart || part2 > partfin) continue;
4190
4191
/* Remember that this element is saved for this partition */
4192
elementhalo[part2] = i;
4193
halocopies += 1;
4194
}
4195
}
4196
}
4197
}
4198
4199
4200
if( halocopies ) {
4201
halobulkelems += halocopies;
4202
4203
for(part2=partstart; part2 <= partfin; part2++) {
4204
if( part == part2) continue;
4205
if( elementhalo[part2] != i ) continue;
4206
4207
nofile2 = part2 - partstart + 1;
4208
fprintf(outfiles[nofile2],"%d/%d %d %d ",i,part,data->material[i],elemtype);
4209
4210
for(j=0;j < nodesd2;j++) {
4211
ind = data->topology[i][j];
4212
if(reorder) ind = order[ind];
4213
fprintf(outfiles[nofile2],"%d ",ind);
4214
}
4215
fprintf(outfiles[nofile2],"\n");
4216
4217
bulktypes[part2][elemtype] += 1;
4218
elementsinpart[part2] += 1;
4219
4220
/* Add the halo on-the-fly to the partitiontable of the nodes */
4221
for(j=0;j < nodesd2;j++) {
4222
ind = data->topology[i][j];
4223
hit = FALSE;
4224
for(k=1;k<=maxneededtimes;k++) {
4225
part3 = data->partitiontable[k][ind];
4226
if(part3 == part2) hit = TRUE;
4227
if(!part3) break;
4228
}
4229
if(!hit) {
4230
if(k <= maxneededtimes) {
4231
data->partitiontable[k][ind] = part2;
4232
}
4233
else {
4234
maxneededtimes++;
4235
if(0) printf("Allocating new column %d in partitiontable\n",k);
4236
data->partitiontable[k] = Ivector(1,noknots);
4237
for(m=1;m<=noknots;m++)
4238
data->partitiontable[k][m] = 0;
4239
data->partitiontable[k][ind] = part2;
4240
}
4241
}
4242
}
4243
}
4244
} /* halocopies */
4245
4246
} /* noelements */
4247
4248
if( anyparthalo ) {
4249
if(info) printf("There are %d bulk elements in the halo.\n",halobulkelems);
4250
}
4251
4252
4253
for(part=partstart;part<=partfin;part++) {
4254
nofile = part - partstart + 1;
4255
fclose(outfiles[nofile]);
4256
}
4257
if(partfin < partitions) {
4258
partstart = partfin + 1;
4259
partfin = MIN( partfin + filesetsize, partitions);
4260
goto next_elements_set;
4261
}
4262
/* part.n.elements saved */
4263
4264
4265
/* The partitiontable has been changed to include the halo elements. The need for saving the
4266
halo nodes may be checked by looking whether the number of how many partitions needs
4267
the element has changed. */
4268
if(anyparthalo) {
4269
int halonodes;
4270
neededtimes2 = Ivector(1,noknots);
4271
halonodes = 0;
4272
4273
k = 0;
4274
l = 0;
4275
for(i=1;i<=noknots;i++) {
4276
neededtimes2[i] = 0;
4277
for(j=1;j<=maxneededtimes;j++)
4278
if(data->partitiontable[j][i]) {
4279
neededtimes2[i] += 1;
4280
k++;
4281
}
4282
halonodes += neededtimes2[i] - neededtimes[i];
4283
l += neededtimes[i];
4284
}
4285
if(data->maxpartitiontable < maxneededtimes) {
4286
data->maxpartitiontable = maxneededtimes;
4287
if(info) printf("With the halos nodes belong to %d partitions in maximum\n",maxneededtimes);
4288
}
4289
if(info) printf("There are %d additional shared nodes resulting from the halo.\n",halonodes);
4290
}
4291
else {
4292
neededtimes2 = neededtimes;
4293
}
4294
4295
/* Define new BC numbers for indirect connections. These should not be mixed with
4296
existing BCs as they only serve the purpose of automatically creating the matrix structure. */
4297
if(indirect) {
4298
indirecttype = 0;
4299
for(j=0;j < MAXBOUNDARIES;j++)
4300
for(i=1; i <= bound[j].nosides; i++)
4301
if(bound[j].types[i] > indirecttype) indirecttype = bound[j].types[i];
4302
indirecttype++;
4303
if(info) printf("Indirect connections given index %d and elementtype 102.\n",indirecttype);
4304
}
4305
4306
/* The output format is the same for all partitions */
4307
if(data->dim == 2)
4308
sprintf(outstyle,"%%d %%d %%.%dg %%.%dg 0.0\n",decimals,decimals);
4309
else
4310
sprintf(outstyle,"%%d %%d %%.%dg %%.%dg %%.%dg\n",decimals,decimals,decimals);
4311
4312
if(info) printf("Saving mesh for %d partitions\n",partitions);
4313
4314
4315
/*********** part.n.nodes *********************/
4316
4317
partstart = 1;
4318
partfin = MIN( partitions, filesetsize);
4319
4320
for(i=1;i<=partitions;i++) {
4321
needednodes[i] = 0;
4322
neededtwice[i] = 0;
4323
sharednodes[i] = 0;
4324
ownnodes[i] = 0;
4325
}
4326
4327
next_nodes_set:
4328
4329
for(part=partstart;part<=partfin;part++) {
4330
sprintf(filename,"%s.%d.%s","part",part,"nodes");
4331
nofile = part - partstart + 1;
4332
outfiles[nofile] = fopen(filename,"w");
4333
}
4334
4335
for(l=1; l <= noknots; l++) {
4336
i = l;
4337
if(reorder) i=invorder[l];
4338
4339
/* for(j=1;j<=neededtimes2[i];j++) { */
4340
for(j=1;j<=maxneededtimes;j++) {
4341
4342
k = data->partitiontable[j][i];
4343
if(!k) break;
4344
4345
if(k < partstart || k > partfin) continue;
4346
nofile = k - partstart + 1;
4347
4348
ind = i;
4349
if(reorder) ind=order[i];
4350
4351
if(data->dim == 2)
4352
fprintf(outfiles[nofile],outstyle,ind,-1,data->x[i],data->y[i]);
4353
else if(data->dim == 3)
4354
fprintf(outfiles[nofile],outstyle,ind,-1,data->x[i],data->y[i],data->z[i]);
4355
4356
needednodes[k] += 1;
4357
if(k == ownerpart[i])
4358
ownnodes[k] += 1;
4359
else
4360
sharednodes[k] += 1;
4361
}
4362
}
4363
4364
for(part=partstart;part<=partfin;part++) {
4365
nofile = part - partstart + 1;
4366
fclose(outfiles[nofile]);
4367
}
4368
if(partfin < partitions) {
4369
partstart = partfin + 1;
4370
partfin = MIN( partfin + filesetsize, partitions);
4371
goto next_nodes_set;
4372
}
4373
/* part.n.nodes saved */
4374
4375
4376
/*********** part.n.shared *********************/
4377
4378
partstart = 1;
4379
partfin = MIN( partitions, filesetsize );
4380
4381
next_shared_set:
4382
4383
for(part=partstart;part<=partfin;part++) {
4384
sprintf(filename,"%s.%d.%s","part",part,"shared");
4385
nofile = part - partstart + 1;
4386
outfiles[nofile] = fopen(filename,"w");
4387
}
4388
4389
for(l=1; l <= noknots; l++) {
4390
i = l;
4391
if(reorder) i = invorder[l];
4392
4393
if(neededtimes2[i] <= 1) continue;
4394
4395
for(j=1;j<=neededtimes2[i];j++) {
4396
k = data->partitiontable[j][i];
4397
4398
/* if( parthalo[2] && neededtimes[i] == 1 && ownerpart[i] == k ) continue; */
4399
4400
if(k < partstart || k > partfin) continue;
4401
nofile = k - partstart + 1;
4402
4403
ind = i;
4404
if(reorder) ind = order[i];
4405
neededtwice[k] += 1;
4406
4407
/* if( parthalo[2] ) {
4408
fprintf(outfiles[nofile],"%d %d %d",ind,MAX(1,neededtimes[i]),ownerpart[i]);
4409
for(m=1;m<=neededtimes[i];m++)
4410
if(data->partitiontable[m][i] != ownerpart[i]) fprintf(outfiles[nofile]," %d",data->partitiontable[m][i]);
4411
fprintf(outfiles[nofile],"\n");
4412
}
4413
else { */
4414
fprintf(outfiles[nofile],"%d %d %d",ind,neededtimes2[i],ownerpart[i]);
4415
for(m=1;m<=neededtimes2[i];m++)
4416
if(data->partitiontable[m][i] != ownerpart[i]) fprintf(outfiles[nofile]," %d",data->partitiontable[m][i]);
4417
fprintf(outfiles[nofile],"\n");
4418
/* } */
4419
}
4420
}
4421
4422
for(part=partstart;part<=partfin;part++) {
4423
nofile = part - partstart + 1;
4424
fclose(outfiles[nofile]);
4425
}
4426
if(partfin < partitions) {
4427
partstart = partfin + 1;
4428
partfin = MIN( partfin + filesetsize, partitions);
4429
goto next_shared_set;
4430
}
4431
/* part.n.shared saved */
4432
4433
4434
4435
4436
4437
/*********** part.n.boundary *********************/
4438
/* This is still done in partition loop as the subroutines are quite complicated */
4439
discont = FALSE;
4440
splitsides = 0;
4441
4442
maxnosides = 0;
4443
for(j=0;j < MAXBOUNDARIES;j++)
4444
maxnosides = MAX( maxnosides, bound[j].nosides );
4445
4446
halobcs = 0;
4447
for(part=1;part<=partitions;part++) {
4448
int bcneeded2,closeparent,closeparent2,haloelem,saveelem;
4449
4450
sprintf(filename,"%s.%d.%s","part",part,"boundary");
4451
out = fopen(filename,"w");
4452
4453
for(i=minelemtype;i<=maxelemtype;i++)
4454
sidetypes[i] = 0;
4455
4456
sumsides = 0;
4457
totsides = 0;
4458
4459
/* Loop over boundaries and boundary elements therein. */
4460
for(j=0;j < MAXBOUNDARIES;j++) {
4461
4462
if(!bound[j].created) continue;
4463
if(bound[j].nosides == 0 ) continue;
4464
4465
/* Normal boundary conditions */
4466
for(i=1; i <= bound[j].nosides; i++) {
4467
4468
GetBoundaryElement(i,&bound[j],data,sideind,&sideelemtype);
4469
4470
bctype = bound[j].types[i];
4471
nodesd1 = sideelemtype%100;
4472
4473
parent = bound[j].parent[i];
4474
parent2 = bound[j].parent2[i];
4475
4476
totsides++;
4477
4478
/* Check whether the side is such that it belongs to the domain.
4479
Then it will be always saved - no matter of the halos. */
4480
trueparent = trueparent2 = FALSE;
4481
if( parent ) trueparent = (elempart[parent] == part);
4482
if( parent2 ) trueparent2 = (elempart[parent2] == part);
4483
4484
saveelem = FALSE;
4485
part2 = 0;
4486
4487
if(trueparent || trueparent2) {
4488
/* Either parent must be associated with this partition, otherwise do not save this (except for halo nodes) */
4489
if( parent && !trueparent ) {
4490
splitsides++;
4491
/* For halo elements also the 2nd true parent exists by construction. */
4492
if(!parthalo[1] && !parthalo[2] && !parthalo[4]) parent = 0;
4493
}
4494
else if( parent2 && !trueparent2 ) {
4495
splitsides++;
4496
if(!parthalo[1] && !parthalo[2] && !parthalo[4]) parent2 = 0;
4497
}
4498
saveelem = TRUE;
4499
}
4500
4501
/* If boundary element is not saved by default then study different halos.
4502
First look for the extruded halo and offset +/-1 in partition index. */
4503
if(!saveelem && parthalo[3] && part <= subparts ) {
4504
int leftright;
4505
for(leftright=-1;leftright <=1;leftright += 2) {
4506
part2 = part+leftright;
4507
if( part2 < 1 || part2 > subparts ) continue;
4508
if( parent ) trueparent = (elempart[parent] == part2);
4509
if( parent2 ) trueparent2 = (elempart[parent2] == part2);
4510
4511
/* If other parent is not true parent then set the parent to zero because it is not
4512
in this partition. */
4513
if(trueparent || trueparent2) {
4514
if( parent && !trueparent )
4515
parent = 0;
4516
else if( parent2 && !trueparent2 )
4517
parent2 = 0;
4518
saveelem = TRUE;
4519
break;
4520
}
4521
}
4522
if(saveelem) halobcs += 1;
4523
}
4524
4525
/* These halo strategies save elements even with just one hit on the original partition
4526
since the aggressive halos ensure that all necessary bulk elements are saved. */
4527
if(!saveelem && (parthalo[2] || parthalo[4]) ) {
4528
bcneeded = 0;
4529
for(l=0;l<nodesd1;l++) {
4530
ind = sideind[l];
4531
for(k=1;k<=neededtimes[ind];k++)
4532
if(part == data->partitiontable[k][ind]) bcneeded++;
4533
}
4534
saveelem = bcneeded;
4535
if(saveelem) halobcs +=1;
4536
}
4537
4538
/* If we have nothing to save then just continue to next boundary element. */
4539
if(!saveelem) continue;
4540
4541
sumsides++;
4542
sidetypes[sideelemtype] += 1;
4543
4544
if( part2 )
4545
fprintf(out,"%d/%d %d %d %d %d", totsides,part2,bctype,parent,parent2,sideelemtype);
4546
else
4547
fprintf(out,"%d %d %d %d %d", totsides,bctype,parent,parent2,sideelemtype);
4548
4549
if(reorder) {
4550
for(l=0;l<nodesd1;l++)
4551
fprintf(out," %d",order[sideind[l]]);
4552
} else {
4553
for(l=0;l<nodesd1;l++)
4554
fprintf(out," %d",sideind[l]);
4555
}
4556
fprintf(out,"\n");
4557
}
4558
}
4559
4560
/* The discontinuous stuff is more or less obsolete as these things can now be made also
4561
within ElmerSolver. */
4562
/* The second side for discontinuous boundary conditions.
4563
Note that this has not been treated for orphan control. */
4564
for(j=0;j < MAXBOUNDARIES;j++) {
4565
if(!bound[j].created) continue;
4566
for(i=1; i <= bound[j].nosides; i++) {
4567
if(bound[j].ediscont)
4568
discont = bound[j].discont[i];
4569
else
4570
discont = FALSE;
4571
4572
if(!bound[j].parent2[i] || !discont) continue;
4573
4574
GetElementSide(bound[j].parent2[i],bound[j].side2[i],-bound[j].normal[i],
4575
data,sideind,&sideelemtype);
4576
nodesd1 = sideelemtype%100;
4577
totsides++;
4578
4579
bcneeded = 0;
4580
for(l=0;l<nodesd1;l++) {
4581
ind = sideind[l];
4582
for(k=1;k<=neededtimes[ind];k++)
4583
if(part == data->partitiontable[k][ind]) bcneeded++;
4584
}
4585
if(bcneeded < nodesd1) continue;
4586
4587
4588
trueparent = (elempart[bound[j].parent2[i]] == part);
4589
if(!trueparent) continue;
4590
4591
sumsides++;
4592
fprintf(out,"%d %d %d %d ",
4593
totsides,bound[j].types[i],bound[j].parent2[i],bound[j].parent[i]);
4594
4595
fprintf(out,"%d ",sideelemtype);
4596
sidetypes[sideelemtype] += 1;
4597
if(reorder) {
4598
for(l=0;l<nodesd1;l++)
4599
fprintf(out,"%d ",order[sideind[l]]);
4600
}
4601
else {
4602
for(l=0;l<nodesd1;l++)
4603
fprintf(out,"%d ",sideind[l]);
4604
}
4605
fprintf(out,"\n");
4606
}
4607
}
4608
sidesinpart[part] = sumsides;
4609
4610
4611
/* Boundary nodes that express indirect couplings between different partitions.
4612
This makes it possible for ElmerSolver to create a matrix connection that
4613
is known to exist. */
4614
4615
if (indirect) {
4616
int maxsides,nodesides,maxnodeconnections,connectednodes,m;
4617
int **nodepairs=NULL,*nodeconnections,**indpairs;
4618
4619
nodeconnections = bcnodedummy;
4620
l = 0;
4621
maxsides = 0;
4622
nodesides = 0;
4623
4624
findindirect:
4625
4626
/* First calculate the maximum number of additional sides */
4627
for(i=1;i<=noelements;i++) {
4628
4629
/* owner partition cannot cause an indirect coupling */
4630
if(elempart[i] == part) continue;
4631
4632
elemtype = data->elementtypes[i];
4633
nodesd2 = elemtype%100;
4634
4635
/* Check how many nodes still belong to this partition,
4636
if more than one there may be indirect coupling. */
4637
for(j=0;j < nodesd2;j++) {
4638
elemhit[j] = FALSE;
4639
ind = data->topology[i][j];
4640
for(k=1;k<=neededtimes[ind];k++)
4641
if(part == data->partitiontable[k][ind]) elemhit[j] = TRUE;
4642
}
4643
bcneeded = 0;
4644
for(j=0;j < nodesd2;j++)
4645
if(elemhit[j]) bcneeded++;
4646
if(bcneeded <= 1) continue;
4647
4648
if(l == 0) {
4649
maxsides += (bcneeded-1)*bcneeded/2;
4650
}
4651
else {
4652
for(j=0;j < nodesd2;j++) {
4653
for(k=j+1;k < nodesd2;k++) {
4654
if(elemhit[j] && elemhit[k]) {
4655
nodesides += 1;
4656
4657
/* The minimum index always first */
4658
if(data->topology[i][j] <= data->topology[i][k]) {
4659
nodepairs[nodesides][1] = data->topology[i][j];
4660
nodepairs[nodesides][2] = data->topology[i][k];
4661
}
4662
else {
4663
nodepairs[nodesides][1] = data->topology[i][k];
4664
nodepairs[nodesides][2] = data->topology[i][j];
4665
}
4666
}
4667
}
4668
}
4669
}
4670
}
4671
4672
/* After first round allocate enough space to memorize all indirect non-element couplings. */
4673
if(l == 0) {
4674
nodepairs = Imatrix(1,maxsides,1,2);
4675
for(i=1;i<=maxsides;i++)
4676
nodepairs[i][1] = nodepairs[i][2] = 0;
4677
l++;
4678
goto findindirect;
4679
}
4680
if(0) printf("Number of non-element connections is %d\n",nodesides);
4681
4682
4683
for(i=1;i<=noknots;i++)
4684
nodeconnections[i] = 0;
4685
4686
for(i=1;i<=nodesides;i++)
4687
nodeconnections[nodepairs[i][1]] += 1;
4688
4689
maxnodeconnections = 0;
4690
for(i=1;i<=noknots;i++)
4691
maxnodeconnections = MAX(maxnodeconnections, nodeconnections[i]);
4692
if(0) printf("Maximum number of node-to-node connections %d\n",maxnodeconnections);
4693
4694
connectednodes = 0;
4695
for(i=1;i<=noknots;i++) {
4696
if(nodeconnections[i] > 0) {
4697
connectednodes++;
4698
nodeconnections[i] = connectednodes;
4699
}
4700
}
4701
if(0) printf("Number of nodes with non-element connections %d\n",connectednodes);
4702
4703
indpairs = Imatrix(1,connectednodes,1,maxnodeconnections);
4704
for(i=1;i<=connectednodes;i++)
4705
for(j=1;j<=maxnodeconnections;j++)
4706
indpairs[i][j] = 0;
4707
4708
for(i=1;i<=nodesides;i++) {
4709
ind = nodeconnections[nodepairs[i][1]];
4710
for(j=1;j<=maxnodeconnections;j++) {
4711
if(indpairs[ind][j] == 0) {
4712
indpairs[ind][j] = i;
4713
break;
4714
}
4715
}
4716
}
4717
4718
/* Remove duplicate connections */
4719
l = 0;
4720
for(i=1;i<=connectednodes;i++) {
4721
for(j=1;j<=maxnodeconnections;j++)
4722
for(k=j+1;k<=maxnodeconnections;k++) {
4723
ind = indpairs[i][j];
4724
ind2 = indpairs[i][k];
4725
if(!ind || !ind2) continue;
4726
4727
if(!nodepairs[ind][1] || !nodepairs[ind][2]) continue;
4728
4729
if(nodepairs[ind][2] == nodepairs[ind2][2]) {
4730
nodepairs[ind2][1] = nodepairs[ind2][2] = 0;
4731
l++;
4732
}
4733
}
4734
}
4735
if(0) printf("Removed %d duplicate connections\n",l);
4736
4737
4738
/* Remove connections that already exist */
4739
m = 0;
4740
for(i=1;i<=noelements;i++) {
4741
if(elempart[i] != part) continue;
4742
4743
elemtype = data->elementtypes[i];
4744
nodesd2 = elemtype%100;
4745
4746
for(j=0;j < nodesd2;j++) {
4747
ind = nodeconnections[data->topology[i][j]];
4748
if(!ind) continue;
4749
4750
for(k=0;k < nodesd2;k++) {
4751
if(j==k) continue;
4752
4753
for(l=1;l<=maxnodeconnections;l++) {
4754
ind2 = indpairs[ind][l];
4755
if(!ind2) break;
4756
4757
if(nodepairs[ind2][1] == data->topology[i][j] && nodepairs[ind2][2] == data->topology[i][k]) {
4758
nodepairs[ind2][1] = nodepairs[ind2][2] = 0;
4759
m++;
4760
}
4761
}
4762
}
4763
}
4764
}
4765
if(0) printf("Removed %d connections that already exists in other elements\n",m);
4766
4767
for(i=1; i <= nodesides; i++) {
4768
ind = nodepairs[i][1];
4769
ind2 = nodepairs[i][2];
4770
if(!ind || !ind2) continue;
4771
sumsides++;
4772
4773
sideelemtype = 102;
4774
if(reorder) {
4775
fprintf(out,"%d %d %d %d %d %d %d\n",
4776
sumsides,indirecttype,0,0,sideelemtype,order[ind],order[ind2]);
4777
} else {
4778
fprintf(out,"%d %d %d %d %d %d %d\n",
4779
sumsides,indirecttype,0,0,sideelemtype,ind,ind2);
4780
}
4781
sidetypes[sideelemtype] += 1;
4782
indirectinpart[part] += 1;
4783
}
4784
4785
/* Finally free some extra space that was allocated */
4786
free_Imatrix(indpairs,1,connectednodes,1,maxnodeconnections);
4787
free_Imatrix(nodepairs,1,maxsides,1,2);
4788
}
4789
/* End of indirect couplings */
4790
4791
4792
fclose(out);
4793
/*********** end of part.n.boundary *********************/
4794
4795
4796
4797
4798
/*********** start of part.n.header *********************/
4799
tottypes = 0;
4800
for(i=minelemtype;i<=maxelemtype;i++) {
4801
if(bulktypes[part][i]) tottypes++;
4802
if(sidetypes[i]) tottypes++;
4803
}
4804
4805
sprintf(filename,"%s.%d.%s","part",part,"header");
4806
out = fopen(filename,"w");
4807
fprintf(out,"%-6d %-6d %-6d\n",
4808
needednodes[part],elementsinpart[part],sumsides);
4809
4810
fprintf(out,"%-6d\n",tottypes);
4811
for(i=minelemtype;i<=maxelemtype;i++)
4812
if(bulktypes[part][i])
4813
fprintf(out,"%-6d %-6d\n",i,bulktypes[part][i]);
4814
4815
for(i=minelemtype;i<=maxelemtype;i++)
4816
if(sidetypes[i])
4817
fprintf(out,"%-6d %-6d\n",i,sidetypes[i]);
4818
4819
fprintf(out,"%-6d %-6d\n",neededtwice[part],0);
4820
fclose(out);
4821
4822
if(info) {
4823
if( indirect ) {
4824
if(part == 1) {
4825
printf(" %-5s %-10s %-10s %-8s %-8s %-8s\n",
4826
"part","elements","nodes","shared","bc elems","indirect");
4827
}
4828
printf(" %-5d %-10d %-10d %-8d %-8d %-8d\n",
4829
part,elementsinpart[part],ownnodes[part],sharednodes[part],sidesinpart[part],
4830
indirectinpart[part]);
4831
}
4832
else {
4833
if( part == 1 ) {
4834
printf(" %-5s %-10s %-10s %-8s %-8s\n",
4835
"part","elements","nodes","shared","bc elems");
4836
}
4837
printf(" %-5d %-10d %-10d %-8d %-8d\n",
4838
part,elementsinpart[part],ownnodes[part],sharednodes[part],sidesinpart[part]);
4839
}
4840
}
4841
}
4842
/*********** end of part.n.header *********************/
4843
4844
4845
sumelementsinpart = sumownnodes = sumsharednodes = sumsidesinpart = sumindirect = 0;
4846
for(i=1;i<=partitions;i++) {
4847
sumelementsinpart += elementsinpart[i];
4848
sumownnodes += ownnodes[i];
4849
sumsharednodes += sharednodes[i];
4850
sumsidesinpart += sidesinpart[i];
4851
sumindirect += indirectinpart[i];
4852
}
4853
n = partitions;
4854
printf("----------------------------------------------------------------------------------------------\n");
4855
printf(" ave %-10.1f %-10.1f %-8.1f %-8.1f %-8.1f\n",
4856
1.0*sumelementsinpart/n,1.0*sumownnodes/n,1.0*sumsharednodes/n,
4857
1.0*sumsidesinpart/n,1.0*sumindirect/n);
4858
4859
if( info && halobcs ) {
4860
printf("Number of boundary elements associated with halo: %d\n",halobcs);
4861
}
4862
4863
4864
#if 0
4865
{
4866
int noparents[2][100];
4867
4868
for(j=0;j<2;j++)
4869
for(i=0;i<100;i++)
4870
noparents[j][i] = 0;
4871
4872
for(j=0;j < MAXBOUNDARIES;j++) {
4873
if(bound[j].nosides == 0 ) continue;
4874
for(i=1; i <= bound[j].nosides; i++) {
4875
GetBoundaryElement(i,&bound[j],data,sideind,&sideelemtype);
4876
parent = bound[j].parent[i];
4877
parent2 = bound[j].parent2[i];
4878
bctype = bound[j].types[i];
4879
4880
k = 0;
4881
if(parent) k++;
4882
if(parent2) k++;
4883
4884
noparents[k][bctype] += 1;
4885
}
4886
}
4887
4888
printf("Number of BC parents\n");
4889
for(i=0;i<100;i++) {
4890
k = 0;
4891
for(j=0;j<2;j++)
4892
k = k + noparents[j][i];
4893
if( k ) {
4894
printf("BC %d: %d %d %d\n",i,noparents[0][i],noparents[1][i],noparents[2][i]);
4895
}
4896
}
4897
}
4898
#endif
4899
4900
4901
4902
if(splitsides && !anyparthalo) {
4903
printf("************************* Warning ****************************\n");
4904
printf("Number or boundary elements split at between parents: %d\n",splitsides);
4905
printf("This could be a problem for internal jump conditions\n");
4906
printf("You could try to use '-halobc' flag as remedy with ElmerSolver.\n");
4907
printf("**************************************************************\n");
4908
}
4909
4910
if(anyparthalo) free_Ivector(neededtimes2,1,noknots);
4911
4912
cdstat = chdir("..");
4913
cdstat = chdir("..");
4914
4915
if(reorder) free_Ivector(order,1,noknots);
4916
free_Ivector(needednodes,1,partitions);
4917
free_Ivector(neededtwice,1,partitions);
4918
free_Ivector(sharednodes,1,partitions);
4919
free_Ivector(ownnodes,1,partitions);
4920
free_Ivector(sidetypes,minelemtype,maxelemtype);
4921
free_Imatrix(bulktypes,1,partitions,minelemtype,maxelemtype);
4922
4923
if(info) printf("Writing of partitioned mesh finished\n");
4924
4925
return(0);
4926
}
4927
4928
4929
#if USE_METIS
4930
int ReorderElementsMetis(struct FemType *data,int info)
4931
/* Calls the fill reduction ordering algorithm of Metis library. */
4932
{
4933
int i,j,k,nn,totcon,maxcon,con,options[8];
4934
int noelements,noknots,nonodes;
4935
int *xadj,*adjncy,numflag,*iperm=NULL,*perm=NULL,**newtopology;
4936
Real *newx,*newy,*newz = NULL;
4937
4938
noelements = data->noelements;
4939
noknots = data->noknots;
4940
4941
if(info) printf("Reordering %d knots and %d elements using Metis reordering routine.\n",
4942
noknots,noelements);
4943
perm = NULL;
4944
i = CalculateIndexwidth(data,FALSE,perm);
4945
if(info) printf("Indexwidth of the original node order is %d.\n",i);
4946
4947
4948
CreateNodalGraph(data,TRUE,info);
4949
maxcon = data->nodalmaxconnections;
4950
4951
totcon = 0;
4952
for(i=1;i<=noknots;i++) {
4953
for(j=0;j<maxcon;j++) {
4954
con = data->nodalgraph[j][i];
4955
if(con) totcon++;
4956
}
4957
}
4958
if(info) printf("There are %d connections altogether\n",totcon);
4959
4960
xadj = Ivector(0,noknots);
4961
adjncy = Ivector(0,totcon-1);
4962
for(i=0;i<totcon;i++)
4963
adjncy[i] = 0;
4964
4965
totcon = 0;
4966
for(i=1;i<=noknots;i++) {
4967
xadj[i-1] = totcon;
4968
for(j=0;j<maxcon;j++) {
4969
con = data->nodalgraph[j][i];
4970
if(con) {
4971
adjncy[totcon] = con-1;
4972
totcon++;
4973
}
4974
}
4975
}
4976
xadj[noknots] = totcon;
4977
4978
nn = noknots;
4979
numflag = 0;
4980
for(i=0;i<8;i++) options[i] = 0;
4981
perm = Ivector(0,noknots-1);
4982
iperm = Ivector(0,noknots-1);
4983
4984
if(info) printf("Starting Metis reordering routine.\n");
4985
4986
METIS_NodeND(&nn,xadj,adjncy,&numflag,&options[0],perm,iperm);
4987
4988
if(info) printf("Finished Metis reordering routine.\n");
4989
4990
if(info) printf("Moving knots to new positions\n");
4991
newx = Rvector(1,data->noknots);
4992
newy = Rvector(1,data->noknots);
4993
newz = Rvector(1,data->noknots);
4994
4995
for(i=1;i<=data->noknots;i++) {
4996
newx[i] = data->x[perm[i-1]+1];
4997
newy[i] = data->y[perm[i-1]+1];
4998
newz[i] = data->z[perm[i-1]+1];
4999
}
5000
5001
free_Rvector(data->x,1,data->noknots);
5002
free_Rvector(data->y,1,data->noknots);
5003
free_Rvector(data->z,1,data->noknots);
5004
5005
data->x = newx;
5006
data->y = newy;
5007
data->z = newz;
5008
5009
5010
if(info) printf("Changing the element topology\n");
5011
5012
newtopology = Imatrix(1,noelements,0,data->maxnodes-1);
5013
5014
for(j=1;j<=noelements;j++) {
5015
nonodes = data->elementtypes[j]%100;
5016
for(i=0;i<nonodes;i++) {
5017
k = data->topology[j][i];
5018
newtopology[j][i] = iperm[k-1]+1;
5019
}
5020
}
5021
free_Imatrix(data->topology,1,noelements,0,data->maxnodes-1);
5022
data->topology = newtopology;
5023
5024
i = CalculateIndexwidth(data,FALSE,perm);
5025
if(info) printf("Indexwidth of the new node order is %d.\n",i);
5026
5027
if(0) printf("Deallocating vectors needed for reordering.\n");
5028
free_Ivector(iperm,0,noknots-1);
5029
free_Ivector(perm,0,noknots-1);
5030
5031
return(0);
5032
}
5033
#endif
5034
5035