Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmergrid/src/egparallel.c
5224 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 binary,int *parthalo,
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,*sidesinpart;
3832
int maxneededtimes,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,singleprec;
3838
3839
FILE *out,*outfiles[MAXPARTITIONS+1];
3840
int sumelementsinpart,sumownnodes,sumsharednodes,sumsidesinpart;
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
singleprec = FALSE;
3874
if(binary == 2) singleprec = TRUE;
3875
3876
elempart = data->elempart;
3877
ownerpart = data->nodepart;
3878
noelements = data->noelements;
3879
noknots = data->noknots;
3880
3881
minelemtype = 101;
3882
maxelemtype = GetMaxElementType(data);
3883
halobulkelems = 0;
3884
3885
needednodes = Ivector(1,partitions);
3886
neededtwice = Ivector(1,partitions);
3887
sharednodes = Ivector(1,partitions);
3888
ownnodes = Ivector(1,partitions);
3889
sidetypes = Ivector(minelemtype,maxelemtype);
3890
bulktypes = Imatrix(1,partitions,minelemtype,maxelemtype);
3891
bcnodedummy = Ivector(1,noknots);
3892
3893
/* Order the nodes so that the different partitions have a continuous interval of nodes.
3894
This information is used only just before the saving of node indexes in each instance.
3895
This feature was coded for collaboration with Hypre library that assumes this. */
3896
reorder = parthypre;
3897
if(reorder) {
3898
order = Ivector(1,noknots);
3899
k = 0;
3900
for(j=1;j<=partitions;j++)
3901
for(i=1; i <= noknots; i++)
3902
if(ownerpart[i] == j) {
3903
k++;
3904
order[i] = k;
3905
}
3906
invorder = Ivector(1,noknots);
3907
for(i=1;i<=noknots;i++)
3908
invorder[order[i]] = i;
3909
if(info) printf("Created continuous parallel ordering\n");
3910
}
3911
3912
/* Mark the nodes that are on some boundary in order to create boundary halos */
3913
bcnode = Ivector(1,noknots);
3914
for(i=1;i<=noknots;i++)
3915
bcnode[i] = FALSE;
3916
for(j=0;j < MAXBOUNDARIES;j++) {
3917
if(!bound[j].created) continue;
3918
for(i=1; i <= bound[j].nosides; i++) {
3919
GetBoundaryElement(i,&bound[j],data,sideind,&sideelemtype);
3920
nodesd1 = sideelemtype%100;
3921
for(l=0;l<nodesd1;l++)
3922
bcnode[sideind[l]] = 1;
3923
}
3924
}
3925
nobcnodes = 0;
3926
for(i=1;i<=noknots;i++) {
3927
if( bcnode[i] == 1) nobcnodes += 1;
3928
}
3929
if(info) printf("Number of boundary nodes at the boundary: %d\n",nobcnodes);
3930
3931
3932
for(i=1;i<=noknots;i++)
3933
bcnodedummy[i] = 0;
3934
for(i=1;i<=noelements;i++) {
3935
k = data->material[i];
3936
elemtype = data->elementtypes[i];
3937
nodesd2 = elemtype%100;
3938
3939
for(j=0;j < nodesd2;j++) {
3940
ind = data->topology[i][j];
3941
if( bcnode[ind] == 1) continue;
3942
if( bcnodedummy[ind] ) {
3943
if( bcnodedummy[ind] != k ) bcnode[ind] = 2;
3944
} else {
3945
bcnodedummy[ind] = k;
3946
}
3947
}
3948
}
3949
nobcnodes = 0;
3950
for(i=1;i<=noknots;i++) {
3951
if( bcnode[i] == 2) nobcnodes += 1;
3952
}
3953
if(info) printf("Number of additional interface nodes: %d\n",nobcnodes);
3954
3955
3956
sprintf(directoryname,"%s",prefix);
3957
sprintf(subdirectoryname,"%s.%d","partitioning",partitions);
3958
3959
3960
#ifdef MINGW32
3961
mkdir(directoryname);
3962
#else
3963
fail = mkdir(directoryname,0750);
3964
#endif
3965
if(info && !fail) printf("Created mesh directory: %s\n",directoryname);
3966
fail = chdir(directoryname);
3967
#ifdef MINGW32
3968
fail = mkdir(subdirectoryname);
3969
#else
3970
fail = mkdir(subdirectoryname,0750);
3971
#endif
3972
if(fail) {
3973
if(info) printf("Reusing existing subdirectory: %s\n",subdirectoryname);
3974
if(nooverwrite) {
3975
printf("Mesh seems to already exist, writing is cancelled!\n");
3976
return(0);
3977
}
3978
}
3979
else {
3980
if(info) printf("Created subdirectory: %s\n",subdirectoryname);
3981
}
3982
cdstat = chdir(subdirectoryname);
3983
3984
3985
3986
if(info) printf("Saving mesh in parallel ElmerSolver format to directory %s/%s.\n",
3987
directoryname,subdirectoryname);
3988
3989
filesetsize = MAXPARTITIONS;
3990
if(partitions > filesetsize)
3991
if(info) printf("Saving %d partitions in maximum sets of %d\n",partitions,filesetsize);
3992
3993
elementsinpart = Ivector(1,partitions);
3994
sidesinpart = Ivector(1,partitions);
3995
elementhalo = Ivector(1,partitions);
3996
for(i=1;i<=partitions;i++)
3997
elementsinpart[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
if(binary)
4025
sprintf(filename,"%s.%d.%s","part",part,"elements.bin");
4026
else
4027
sprintf(filename,"%s.%d.%s","part",part,"elements");
4028
nofile = part - partstart + 1;
4029
outfiles[nofile] = fopen(filename,"w");
4030
}
4031
4032
for(i=1;i<=noelements;i++) {
4033
part = elempart[i];
4034
4035
elemtype = data->elementtypes[i];
4036
nodesd2 = elemtype%100;
4037
4038
if(part >= partstart && part <= partfin) {
4039
nofile = part - partstart + 1;
4040
bulktypes[part][elemtype] += 1;
4041
elementsinpart[part] += 1;
4042
4043
if(binary) {
4044
fwrite(&i,sizeof(int),1,outfiles[nofile]);
4045
k=-1; fwrite(&k,sizeof(int),1,outfiles[nofile]);
4046
fwrite(&data->material[i],sizeof(int),1,outfiles[nofile]);
4047
fwrite(&elemtype,sizeof(int),1,outfiles[nofile]);
4048
fwrite(&data->topology[i][0],sizeof(int),nodesd2,outfiles[nofile]);
4049
}
4050
else {
4051
fprintf(outfiles[nofile],"%d %d %d ",i,data->material[i],elemtype);
4052
for(j=0;j < nodesd2;j++) {
4053
ind = data->topology[i][j];
4054
if(reorder) ind = order[ind];
4055
fprintf(outfiles[nofile],"%d ",ind);
4056
}
4057
fprintf(outfiles[nofile],"\n");
4058
}
4059
}
4060
4061
4062
if(!anyparthalo) continue;
4063
halocopies = 0;
4064
4065
4066
4067
for( halomode = 1; halomode <= 4; halomode++) {
4068
4069
if(!parthalo[halomode]) continue;
4070
4071
4072
/* This creates a simple halo when the elements have been partitioned such
4073
that they are in number of "subparts" intervals of z coordinate. */
4074
if( halomode == 3 ) {
4075
if( part <= subparts ) {
4076
int leftright;
4077
for(leftright=-1;leftright <=1;leftright += 2) {
4078
part2 = part+leftright;
4079
if( part2 < 1 || part2 > subparts ) continue;
4080
elementhalo[part2] = i;
4081
halocopies += 1;
4082
}
4083
}
4084
}
4085
4086
/* For the following halos we study the shared and boundary nodes. */
4087
otherpart = 0;
4088
hasbcnodes = FALSE;
4089
for(j=0;j < nodesd2;j++) {
4090
ind = data->topology[i][j];
4091
if(neededtimes[ind] > 1) otherpart++;
4092
if(bcnode[ind]) hasbcnodes = TRUE;
4093
}
4094
4095
/* Classical halo needed by discontinuous Galerkin.
4096
Elements that are attached by joined face element are added to halo */
4097
if( halomode == 1 && otherpart ) {
4098
/* If the saving of halo is requested check it for elements which have at least
4099
two nodes in shared partitions. First make this quick test. */
4100
4101
elemsides = elemtype / 100;
4102
if(elemsides == 8) {
4103
immersed = (otherpart >= 4);
4104
elemsides = 6;
4105
}
4106
else if(elemsides == 7) {
4107
immersed = (otherpart >= 3);
4108
elemsides = 5;
4109
}
4110
else if(elemsides == 6) {
4111
immersed = (otherpart >= 3);
4112
elemsides = 5;
4113
}
4114
else if(elemsides == 5) {
4115
immersed = (otherpart >= 3);
4116
elemsides = 4;
4117
}
4118
else {
4119
immersed = (otherpart >= 2);
4120
}
4121
4122
if( immersed ) {
4123
4124
/* In order for the halo to be present the element should have a boundary
4125
fully immersed in the other partition. This test takes more time. */
4126
4127
for(side=0;side<elemsides;side++) {
4128
4129
GetElementSide(i,side,1,data,&sideind[0],&sideelemtype);
4130
4131
/* Because every node must be on the boundary use the 1st index as the
4132
first test */
4133
for(l=1;l<=neededtimes[sideind[0]];l++) {
4134
part2 = data->partitiontable[l][sideind[0]];
4135
4136
/* We did already save this in partition part */
4137
if(part2 == part) continue;
4138
if(elementhalo[part2] == i) continue;
4139
if(part2 < partstart || part2 > partfin) continue;
4140
4141
/* Now check that also the other nodes on the face are at the interface */
4142
sidehits = 1;
4143
for(k=1;k<sideelemtype%100;k++) {
4144
for(l2=1;l2<=neededtimes[sideind[k]];l2++) {
4145
part3 = data->partitiontable[l2][sideind[k]];
4146
if(part2 == part3) sidehits++;
4147
}
4148
}
4149
if( sidehits < sideelemtype % 100 ) continue;
4150
4151
if(0) printf("Adding halo for partition %d and element %d\n",part2,i);
4152
4153
/* Remember that this element is saved for this partition */
4154
elementhalo[part2] = i;
4155
halocopies += 1;
4156
}
4157
}
4158
}
4159
}
4160
4161
/* This creates a halo that includes all elements attached to boundary or interface nodes */
4162
if( halomode == 2 && hasbcnodes ) {
4163
for(j=0;j < nodesd2;j++) {
4164
ind = data->topology[i][j];
4165
4166
/* If the node is not on the boundary then cycle */
4167
if( !bcnode[ind] ) continue;
4168
4169
/* Check to which partitions this element is associated with */
4170
for(k=1;k<=neededtimes[ind];k++) {
4171
part2 = data->partitiontable[k][ind];
4172
4173
/* This element is already saved to its primary partition */
4174
if( part == part2 ) continue;
4175
if( elementhalo[part2] == i) continue;
4176
if( part2 < partstart || part2 > partfin ) continue;
4177
4178
if(0) printf("Adding bc halo for partition %d and element %d\n",part2,i);
4179
4180
/* Remember that this element is saved for this partition */
4181
elementhalo[part2] = i;
4182
halocopies += 1;
4183
}
4184
}
4185
}
4186
4187
/* This greedy routine makes the halo even if there is just one node in the shared boundary.
4188
Currently not active. */
4189
if( halomode == 4 && otherpart ) {
4190
for(j=0;j < nodesd2;j++) {
4191
ind = data->topology[i][j];
4192
if(neededtimes[ind] == 1) continue;
4193
4194
for(l=1;l<=neededtimes[ind];l++) {
4195
part2 = data->partitiontable[l][ind];
4196
4197
/* We did already save this in partition part */
4198
if(part2 == part) continue;
4199
if( elementhalo[part2] == i) continue;
4200
if(part2 < partstart || part2 > partfin) continue;
4201
4202
/* Remember that this element is saved for this partition */
4203
elementhalo[part2] = i;
4204
halocopies += 1;
4205
}
4206
}
4207
}
4208
}
4209
4210
4211
if( halocopies ) {
4212
halobulkelems += halocopies;
4213
4214
for(part2=partstart; part2 <= partfin; part2++) {
4215
if( part == part2) continue;
4216
if( elementhalo[part2] != i ) continue;
4217
4218
nofile2 = part2 - partstart + 1;
4219
4220
if(binary) {
4221
fwrite(&i,sizeof(int),1,outfiles[nofile2]);
4222
fwrite(&part,sizeof(int),1,outfiles[nofile2]);
4223
fwrite(&data->material[i],sizeof(int),1,outfiles[nofile2]);
4224
fwrite(&elemtype,sizeof(int),1,outfiles[nofile2]);
4225
for(j=0;j < nodesd2;j++) {
4226
ind = data->topology[i][j];
4227
if(reorder) ind = order[ind];
4228
fwrite(&ind,sizeof(int),1,outfiles[nofile2]);
4229
}
4230
} else {
4231
fprintf(outfiles[nofile2],"%d/%d %d %d ",i,part,data->material[i],elemtype);
4232
for(j=0;j < nodesd2;j++) {
4233
ind = data->topology[i][j];
4234
if(reorder) ind = order[ind];
4235
fprintf(outfiles[nofile2],"%d ",ind);
4236
}
4237
fprintf(outfiles[nofile2],"\n");
4238
}
4239
4240
4241
bulktypes[part2][elemtype] += 1;
4242
elementsinpart[part2] += 1;
4243
4244
/* Add the halo on-the-fly to the partitiontable of the nodes */
4245
for(j=0;j < nodesd2;j++) {
4246
ind = data->topology[i][j];
4247
hit = FALSE;
4248
for(k=1;k<=maxneededtimes;k++) {
4249
part3 = data->partitiontable[k][ind];
4250
if(part3 == part2) hit = TRUE;
4251
if(!part3) break;
4252
}
4253
if(!hit) {
4254
if(k <= maxneededtimes) {
4255
data->partitiontable[k][ind] = part2;
4256
}
4257
else {
4258
maxneededtimes++;
4259
if(0) printf("Allocating new column %d in partitiontable\n",k);
4260
data->partitiontable[k] = Ivector(1,noknots);
4261
for(m=1;m<=noknots;m++)
4262
data->partitiontable[k][m] = 0;
4263
data->partitiontable[k][ind] = part2;
4264
}
4265
}
4266
}
4267
}
4268
} /* halocopies */
4269
4270
} /* noelements */
4271
4272
if( anyparthalo ) {
4273
if(info) printf("There are %d bulk elements in the halo.\n",halobulkelems);
4274
}
4275
4276
4277
for(part=partstart;part<=partfin;part++) {
4278
nofile = part - partstart + 1;
4279
fclose(outfiles[nofile]);
4280
}
4281
if(partfin < partitions) {
4282
partstart = partfin + 1;
4283
partfin = MIN( partfin + filesetsize, partitions);
4284
goto next_elements_set;
4285
}
4286
/* part.n.elements saved */
4287
4288
4289
/* The partitiontable has been changed to include the halo elements. The need for saving the
4290
halo nodes may be checked by looking whether the number of how many partitions needs
4291
the element has changed. */
4292
if(anyparthalo) {
4293
int halonodes;
4294
neededtimes2 = Ivector(1,noknots);
4295
halonodes = 0;
4296
4297
k = 0;
4298
l = 0;
4299
for(i=1;i<=noknots;i++) {
4300
neededtimes2[i] = 0;
4301
for(j=1;j<=maxneededtimes;j++)
4302
if(data->partitiontable[j][i]) {
4303
neededtimes2[i] += 1;
4304
k++;
4305
}
4306
halonodes += neededtimes2[i] - neededtimes[i];
4307
l += neededtimes[i];
4308
}
4309
if(data->maxpartitiontable < maxneededtimes) {
4310
data->maxpartitiontable = maxneededtimes;
4311
if(info) printf("With the halos nodes belong to %d partitions in maximum\n",maxneededtimes);
4312
}
4313
if(info) printf("There are %d additional shared nodes resulting from the halo.\n",halonodes);
4314
}
4315
else {
4316
neededtimes2 = neededtimes;
4317
}
4318
4319
/* The output format is the same for all partitions */
4320
if(data->dim == 2)
4321
sprintf(outstyle,"%%d %%d %%.%dg %%.%dg 0.0\n",decimals,decimals);
4322
else
4323
sprintf(outstyle,"%%d %%d %%.%dg %%.%dg %%.%dg\n",decimals,decimals,decimals);
4324
4325
if(info) printf("Saving mesh for %d partitions\n",partitions);
4326
4327
4328
/*********** part.n.nodes *********************/
4329
4330
partstart = 1;
4331
partfin = MIN( partitions, filesetsize);
4332
4333
for(i=1;i<=partitions;i++) {
4334
needednodes[i] = 0;
4335
neededtwice[i] = 0;
4336
sharednodes[i] = 0;
4337
ownnodes[i] = 0;
4338
}
4339
4340
next_nodes_set:
4341
4342
for(part=partstart;part<=partfin;part++) {
4343
if(binary) {
4344
if(singleprec)
4345
sprintf(filename,"%s.%d.%s","part",part,"nodes.sbin");
4346
else
4347
sprintf(filename,"%s.%d.%s","part",part,"nodes.bin");
4348
} else {
4349
sprintf(filename,"%s.%d.%s","part",part,"nodes");
4350
}
4351
nofile = part - partstart + 1;
4352
outfiles[nofile] = fopen(filename,"w");
4353
}
4354
4355
for(l=1; l <= noknots; l++) {
4356
i = l;
4357
if(reorder) i=invorder[l];
4358
4359
/* for(j=1;j<=neededtimes2[i];j++) { */
4360
for(j=1;j<=maxneededtimes;j++) {
4361
4362
k = data->partitiontable[j][i];
4363
if(!k) break;
4364
4365
if(k < partstart || k > partfin) continue;
4366
nofile = k - partstart + 1;
4367
4368
ind = i;
4369
if(reorder) ind=order[i];
4370
4371
4372
if(binary) {
4373
double coords[3];
4374
float scoords[3];
4375
4376
fwrite(&ind,sizeof(int),1,out);
4377
/* Note that in binary format we don't save the obsolite "-1". */
4378
if(singleprec) {
4379
/* We save the coordinates in single precidion format */
4380
scoords[0] = data->x[i];
4381
scoords[1] = data->y[i];
4382
scoords[2] = data->z[i];
4383
fwrite(scoords,sizeof(float),3,outfiles[nofile]);
4384
} else {
4385
coords[0] = data->x[i];
4386
coords[1] = data->y[i];
4387
coords[2] = data->z[i];
4388
fwrite(coords,sizeof(double),3,outfiles[nofile]);
4389
}
4390
} else {
4391
if(data->dim == 2)
4392
fprintf(outfiles[nofile],outstyle,ind,-1,data->x[i],data->y[i]);
4393
else if(data->dim == 3)
4394
fprintf(outfiles[nofile],outstyle,ind,-1,data->x[i],data->y[i],data->z[i]);
4395
}
4396
4397
needednodes[k] += 1;
4398
if(k == ownerpart[i])
4399
ownnodes[k] += 1;
4400
else
4401
sharednodes[k] += 1;
4402
}
4403
}
4404
4405
for(part=partstart;part<=partfin;part++) {
4406
nofile = part - partstart + 1;
4407
fclose(outfiles[nofile]);
4408
}
4409
if(partfin < partitions) {
4410
partstart = partfin + 1;
4411
partfin = MIN( partfin + filesetsize, partitions);
4412
goto next_nodes_set;
4413
}
4414
/* part.n.nodes saved */
4415
4416
4417
/*********** part.n.shared *********************/
4418
4419
partstart = 1;
4420
partfin = MIN( partitions, filesetsize );
4421
4422
next_shared_set:
4423
4424
for(part=partstart;part<=partfin;part++) {
4425
sprintf(filename,"%s.%d.%s","part",part,"shared");
4426
nofile = part - partstart + 1;
4427
outfiles[nofile] = fopen(filename,"w");
4428
}
4429
4430
for(l=1; l <= noknots; l++) {
4431
i = l;
4432
if(reorder) i = invorder[l];
4433
4434
if(neededtimes2[i] <= 1) continue;
4435
4436
for(j=1;j<=neededtimes2[i];j++) {
4437
k = data->partitiontable[j][i];
4438
4439
/* if( parthalo[2] && neededtimes[i] == 1 && ownerpart[i] == k ) continue; */
4440
4441
if(k < partstart || k > partfin) continue;
4442
nofile = k - partstart + 1;
4443
4444
ind = i;
4445
if(reorder) ind = order[i];
4446
neededtwice[k] += 1;
4447
4448
/* if( parthalo[2] ) {
4449
fprintf(outfiles[nofile],"%d %d %d",ind,MAX(1,neededtimes[i]),ownerpart[i]);
4450
for(m=1;m<=neededtimes[i];m++)
4451
if(data->partitiontable[m][i] != ownerpart[i]) fprintf(outfiles[nofile]," %d",data->partitiontable[m][i]);
4452
fprintf(outfiles[nofile],"\n");
4453
}
4454
else { */
4455
fprintf(outfiles[nofile],"%d %d %d",ind,neededtimes2[i],ownerpart[i]);
4456
for(m=1;m<=neededtimes2[i];m++)
4457
if(data->partitiontable[m][i] != ownerpart[i]) fprintf(outfiles[nofile]," %d",data->partitiontable[m][i]);
4458
fprintf(outfiles[nofile],"\n");
4459
/* } */
4460
}
4461
}
4462
4463
for(part=partstart;part<=partfin;part++) {
4464
nofile = part - partstart + 1;
4465
fclose(outfiles[nofile]);
4466
}
4467
if(partfin < partitions) {
4468
partstart = partfin + 1;
4469
partfin = MIN( partfin + filesetsize, partitions);
4470
goto next_shared_set;
4471
}
4472
/* part.n.shared saved */
4473
4474
4475
4476
4477
4478
/*********** part.n.boundary *********************/
4479
/* This is still done in partition loop as the subroutines are quite complicated */
4480
discont = FALSE;
4481
splitsides = 0;
4482
4483
maxnosides = 0;
4484
for(j=0;j < MAXBOUNDARIES;j++)
4485
maxnosides = MAX( maxnosides, bound[j].nosides );
4486
4487
halobcs = 0;
4488
for(part=1;part<=partitions;part++) {
4489
int bcneeded2,closeparent,closeparent2,haloelem,saveelem;
4490
4491
if(binary)
4492
sprintf(filename,"%s.%d.%s","part",part,"boundary.bin");
4493
else
4494
sprintf(filename,"%s.%d.%s","part",part,"boundary");
4495
out = fopen(filename,"w");
4496
4497
for(i=minelemtype;i<=maxelemtype;i++)
4498
sidetypes[i] = 0;
4499
4500
sumsides = 0;
4501
totsides = 0;
4502
4503
/* Loop over boundaries and boundary elements therein. */
4504
for(j=0;j < MAXBOUNDARIES;j++) {
4505
4506
if(!bound[j].created) continue;
4507
if(bound[j].nosides == 0 ) continue;
4508
4509
/* Normal boundary conditions */
4510
for(i=1; i <= bound[j].nosides; i++) {
4511
4512
GetBoundaryElement(i,&bound[j],data,sideind,&sideelemtype);
4513
4514
bctype = bound[j].types[i];
4515
nodesd1 = sideelemtype%100;
4516
4517
parent = bound[j].parent[i];
4518
parent2 = bound[j].parent2[i];
4519
4520
totsides++;
4521
4522
/* Check whether the side is such that it belongs to the domain.
4523
Then it will be always saved - no matter of the halos. */
4524
trueparent = trueparent2 = FALSE;
4525
if( parent ) trueparent = (elempart[parent] == part);
4526
if( parent2 ) trueparent2 = (elempart[parent2] == part);
4527
4528
saveelem = FALSE;
4529
part2 = 0;
4530
4531
if(trueparent || trueparent2) {
4532
/* Either parent must be associated with this partition, otherwise do not save this (except for halo nodes) */
4533
if( parent && !trueparent ) {
4534
splitsides++;
4535
/* For halo elements also the 2nd true parent exists by construction. */
4536
if(!parthalo[1] && !parthalo[2] && !parthalo[4]) parent = 0;
4537
}
4538
else if( parent2 && !trueparent2 ) {
4539
splitsides++;
4540
if(!parthalo[1] && !parthalo[2] && !parthalo[4]) parent2 = 0;
4541
}
4542
saveelem = TRUE;
4543
}
4544
4545
/* If boundary element is not saved by default then study different halos.
4546
First look for the extruded halo and offset +/-1 in partition index. */
4547
if(!saveelem && parthalo[3] && part <= subparts ) {
4548
int leftright;
4549
for(leftright=-1;leftright <=1;leftright += 2) {
4550
part2 = part+leftright;
4551
if( part2 < 1 || part2 > subparts ) continue;
4552
if( parent ) trueparent = (elempart[parent] == part2);
4553
if( parent2 ) trueparent2 = (elempart[parent2] == part2);
4554
4555
/* If other parent is not true parent then set the parent to zero because it is not
4556
in this partition. */
4557
if(trueparent || trueparent2) {
4558
if( parent && !trueparent )
4559
parent = 0;
4560
else if( parent2 && !trueparent2 )
4561
parent2 = 0;
4562
saveelem = TRUE;
4563
break;
4564
}
4565
}
4566
if(saveelem) halobcs += 1;
4567
}
4568
4569
/* These halo strategies save elements even with just one hit on the original partition
4570
since the aggressive halos ensure that all necessary bulk elements are saved. */
4571
if(!saveelem && (parthalo[2] || parthalo[4]) ) {
4572
bcneeded = 0;
4573
for(l=0;l<nodesd1;l++) {
4574
ind = sideind[l];
4575
for(k=1;k<=neededtimes[ind];k++)
4576
if(part == data->partitiontable[k][ind]) bcneeded++;
4577
}
4578
saveelem = bcneeded;
4579
if(saveelem) halobcs +=1;
4580
}
4581
4582
/* If we have nothing to save then just continue to next boundary element. */
4583
if(!saveelem) continue;
4584
4585
sumsides++;
4586
sidetypes[sideelemtype] += 1;
4587
4588
if(binary) {
4589
k = part2;
4590
if(k==0) k=-1;
4591
4592
fwrite(&totsides,sizeof(int),1,out);
4593
fwrite(&k,sizeof(int),1,out);
4594
fwrite(&bctype,sizeof(int),1,out);
4595
fwrite(&parent,sizeof(int),1,out);
4596
fwrite(&parent2,sizeof(int),1,out);
4597
fwrite(&sideelemtype,sizeof(int),1,out);
4598
4599
for(l=0;l<nodesd1;l++) {
4600
k = sideind[l];
4601
if(reorder) k = order[k];
4602
fwrite(&k,sizeof(int),1,out);
4603
}
4604
4605
} else {
4606
if( part2 )
4607
fprintf(out,"%d/%d %d %d %d %d", totsides,part2,bctype,parent,parent2,sideelemtype);
4608
else
4609
fprintf(out,"%d %d %d %d %d", totsides,bctype,parent,parent2,sideelemtype);
4610
4611
for(l=0;l<nodesd1;l++) {
4612
k = sideind[l];
4613
if(reorder) k = order[k];
4614
fprintf(out," %d",k);
4615
}
4616
fprintf(out,"\n");
4617
}
4618
}
4619
}
4620
4621
/* The discontinuous stuff is more or less obsolete as these things can now be made also
4622
within ElmerSolver. */
4623
/* The second side for discontinuous boundary conditions.
4624
Note that this has not been treated for orphan control. */
4625
for(j=0;j < MAXBOUNDARIES;j++) {
4626
if(!bound[j].created) continue;
4627
for(i=1; i <= bound[j].nosides; i++) {
4628
if(bound[j].ediscont)
4629
discont = bound[j].discont[i];
4630
else
4631
discont = FALSE;
4632
4633
if(!bound[j].parent2[i] || !discont) continue;
4634
4635
GetElementSide(bound[j].parent2[i],bound[j].side2[i],-bound[j].normal[i],
4636
data,sideind,&sideelemtype);
4637
nodesd1 = sideelemtype%100;
4638
totsides++;
4639
4640
bcneeded = 0;
4641
for(l=0;l<nodesd1;l++) {
4642
ind = sideind[l];
4643
for(k=1;k<=neededtimes[ind];k++)
4644
if(part == data->partitiontable[k][ind]) bcneeded++;
4645
}
4646
if(bcneeded < nodesd1) continue;
4647
4648
4649
trueparent = (elempart[bound[j].parent2[i]] == part);
4650
if(!trueparent) continue;
4651
4652
sumsides++;
4653
sidetypes[sideelemtype] += 1;
4654
4655
4656
if(binary) {
4657
k = -1;
4658
4659
fwrite(&totsides,sizeof(int),1,out);
4660
fwrite(&k,sizeof(int),1,out);
4661
fwrite(&bound[j].types[i],sizeof(int),1,out);
4662
fwrite(&bound[j].parent2[i],sizeof(int),1,out);
4663
fwrite(&bound[j].parent[i],sizeof(int),1,out);
4664
fwrite(&sideelemtype,sizeof(int),1,out);
4665
4666
for(l=0;l<nodesd1;l++) {
4667
k = sideind[l];
4668
if(reorder) k = order[k];
4669
fwrite(&k,sizeof(int),1,out);
4670
}
4671
}
4672
else {
4673
fprintf(out,"%d %d %d %d %d",
4674
totsides,bound[j].types[i],bound[j].parent2[i],bound[j].parent[i],sideelemtype);
4675
4676
for(l=0;l<nodesd1;l++) {
4677
k = sideind[l];
4678
if(reorder) k = order[k];
4679
fprintf(out," %d",k);
4680
}
4681
fprintf(out,"\n");
4682
}
4683
}
4684
}
4685
sidesinpart[part] = sumsides;
4686
4687
4688
fclose(out);
4689
/*********** end of part.n.boundary *********************/
4690
4691
4692
4693
4694
/*********** start of part.n.header *********************/
4695
tottypes = 0;
4696
for(i=minelemtype;i<=maxelemtype;i++) {
4697
if(bulktypes[part][i]) tottypes++;
4698
if(sidetypes[i]) tottypes++;
4699
}
4700
4701
sprintf(filename,"%s.%d.%s","part",part,"header");
4702
out = fopen(filename,"w");
4703
fprintf(out,"%-6d %-6d %-6d\n",
4704
needednodes[part],elementsinpart[part],sumsides);
4705
4706
fprintf(out,"%-6d\n",tottypes);
4707
for(i=minelemtype;i<=maxelemtype;i++)
4708
if(bulktypes[part][i])
4709
fprintf(out,"%-6d %-6d\n",i,bulktypes[part][i]);
4710
4711
for(i=minelemtype;i<=maxelemtype;i++)
4712
if(sidetypes[i])
4713
fprintf(out,"%-6d %-6d\n",i,sidetypes[i]);
4714
4715
fprintf(out,"%-6d %-6d\n",neededtwice[part],0);
4716
fclose(out);
4717
4718
if(info) {
4719
if( part == 1 ) {
4720
printf(" %-5s %-10s %-10s %-8s %-8s\n",
4721
"part","elements","nodes","shared","bc elems");
4722
}
4723
printf(" %-5d %-10d %-10d %-8d %-8d\n",
4724
part,elementsinpart[part],ownnodes[part],sharednodes[part],sidesinpart[part]);
4725
}
4726
}
4727
/*********** end of part.n.header *********************/
4728
4729
4730
sumelementsinpart = sumownnodes = sumsharednodes = sumsidesinpart = 0;
4731
for(i=1;i<=partitions;i++) {
4732
sumelementsinpart += elementsinpart[i];
4733
sumownnodes += ownnodes[i];
4734
sumsharednodes += sharednodes[i];
4735
sumsidesinpart += sidesinpart[i];
4736
}
4737
n = partitions;
4738
printf("----------------------------------------------------------------------------------------------\n");
4739
printf(" ave %-10.1f %-10.1f %-8.1f %-8.1f\n",
4740
1.0*sumelementsinpart/n,1.0*sumownnodes/n,1.0*sumsharednodes/n,
4741
1.0*sumsidesinpart/n);
4742
4743
if( info && halobcs ) {
4744
printf("Number of boundary elements associated with halo: %d\n",halobcs);
4745
}
4746
4747
4748
4749
if(splitsides && !anyparthalo) {
4750
printf("************************* Warning ****************************\n");
4751
printf("Number or boundary elements split at between parents: %d\n",splitsides);
4752
printf("This could be a problem for internal jump conditions\n");
4753
printf("You could try to use '-halobc' flag as remedy with ElmerSolver.\n");
4754
printf("**************************************************************\n");
4755
}
4756
4757
if(anyparthalo) free_Ivector(neededtimes2,1,noknots);
4758
4759
cdstat = chdir("..");
4760
cdstat = chdir("..");
4761
4762
if(reorder) free_Ivector(order,1,noknots);
4763
free_Ivector(needednodes,1,partitions);
4764
free_Ivector(neededtwice,1,partitions);
4765
free_Ivector(sharednodes,1,partitions);
4766
free_Ivector(ownnodes,1,partitions);
4767
free_Ivector(sidetypes,minelemtype,maxelemtype);
4768
free_Imatrix(bulktypes,1,partitions,minelemtype,maxelemtype);
4769
4770
if(info) printf("Writing of partitioned mesh finished\n");
4771
4772
return(0);
4773
}
4774
4775
4776
#if USE_METIS
4777
int ReorderElementsMetis(struct FemType *data,int info)
4778
/* Calls the fill reduction ordering algorithm of Metis library. */
4779
{
4780
int i,j,k,nn,totcon,maxcon,con,options[8];
4781
int noelements,noknots,nonodes;
4782
int *xadj,*adjncy,numflag,*iperm=NULL,*perm=NULL,**newtopology;
4783
Real *newx,*newy,*newz = NULL;
4784
4785
noelements = data->noelements;
4786
noknots = data->noknots;
4787
4788
if(info) printf("Reordering %d knots and %d elements using Metis reordering routine.\n",
4789
noknots,noelements);
4790
perm = NULL;
4791
i = CalculateIndexwidth(data,FALSE,perm);
4792
if(info) printf("Indexwidth of the original node order is %d.\n",i);
4793
4794
4795
CreateNodalGraph(data,TRUE,info);
4796
maxcon = data->nodalmaxconnections;
4797
4798
totcon = 0;
4799
for(i=1;i<=noknots;i++) {
4800
for(j=0;j<maxcon;j++) {
4801
con = data->nodalgraph[j][i];
4802
if(con) totcon++;
4803
}
4804
}
4805
if(info) printf("There are %d connections altogether\n",totcon);
4806
4807
xadj = Ivector(0,noknots);
4808
adjncy = Ivector(0,totcon-1);
4809
for(i=0;i<totcon;i++)
4810
adjncy[i] = 0;
4811
4812
totcon = 0;
4813
for(i=1;i<=noknots;i++) {
4814
xadj[i-1] = totcon;
4815
for(j=0;j<maxcon;j++) {
4816
con = data->nodalgraph[j][i];
4817
if(con) {
4818
adjncy[totcon] = con-1;
4819
totcon++;
4820
}
4821
}
4822
}
4823
xadj[noknots] = totcon;
4824
4825
nn = noknots;
4826
numflag = 0;
4827
for(i=0;i<8;i++) options[i] = 0;
4828
perm = Ivector(0,noknots-1);
4829
iperm = Ivector(0,noknots-1);
4830
4831
if(info) printf("Starting Metis reordering routine.\n");
4832
4833
METIS_NodeND(&nn,xadj,adjncy,&numflag,&options[0],perm,iperm);
4834
4835
if(info) printf("Finished Metis reordering routine.\n");
4836
4837
if(info) printf("Moving knots to new positions\n");
4838
newx = Rvector(1,data->noknots);
4839
newy = Rvector(1,data->noknots);
4840
newz = Rvector(1,data->noknots);
4841
4842
for(i=1;i<=data->noknots;i++) {
4843
newx[i] = data->x[perm[i-1]+1];
4844
newy[i] = data->y[perm[i-1]+1];
4845
newz[i] = data->z[perm[i-1]+1];
4846
}
4847
4848
free_Rvector(data->x,1,data->noknots);
4849
free_Rvector(data->y,1,data->noknots);
4850
free_Rvector(data->z,1,data->noknots);
4851
4852
data->x = newx;
4853
data->y = newy;
4854
data->z = newz;
4855
4856
4857
if(info) printf("Changing the element topology\n");
4858
4859
newtopology = Imatrix(1,noelements,0,data->maxnodes-1);
4860
4861
for(j=1;j<=noelements;j++) {
4862
nonodes = data->elementtypes[j]%100;
4863
for(i=0;i<nonodes;i++) {
4864
k = data->topology[j][i];
4865
newtopology[j][i] = iperm[k-1]+1;
4866
}
4867
}
4868
free_Imatrix(data->topology,1,noelements,0,data->maxnodes-1);
4869
data->topology = newtopology;
4870
4871
i = CalculateIndexwidth(data,FALSE,perm);
4872
if(info) printf("Indexwidth of the new node order is %d.\n",i);
4873
4874
if(0) printf("Deallocating vectors needed for reordering.\n");
4875
free_Ivector(iperm,0,noknots-1);
4876
free_Ivector(perm,0,noknots-1);
4877
4878
return(0);
4879
}
4880
#endif
4881
4882