Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/netgen/libsrc/meshing/improve3.cpp
3206 views
1
#include <mystdlib.h>
2
3
#include "meshing.hpp"
4
5
#ifdef SOLIDGEOM
6
#include <csg.hpp>
7
#endif
8
#include <opti.hpp>
9
10
namespace netgen
11
{
12
13
/*
14
Combine two points to one.
15
Set new point into the center, if both are
16
inner points.
17
Connect inner point to boundary point, if one
18
point is inner point.
19
*/
20
21
void MeshOptimize3d :: CombineImprove (Mesh & mesh,
22
OPTIMIZEGOAL goal)
23
{
24
int np = mesh.GetNP();
25
int ne = mesh.GetNE();
26
27
TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np);
28
ARRAY<ElementIndex> hasonepi, hasbothpi;
29
30
ARRAY<double> oneperr;
31
ARRAY<double> elerrs (ne);
32
33
PrintMessage (3, "CombineImprove");
34
(*testout) << "Start CombineImprove" << "\n";
35
36
// mesh.CalcSurfacesOfNode ();
37
const char * savetask = multithread.task;
38
multithread.task = "Combine Improve";
39
40
41
double totalbad = 0;
42
for (ElementIndex ei = 0; ei < ne; ei++)
43
{
44
double elerr = CalcBad (mesh.Points(), mesh[ei], 0);
45
totalbad += elerr;
46
elerrs[ei] = elerr;
47
}
48
49
if (goal == OPT_QUALITY)
50
{
51
totalbad = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
52
(*testout) << "Total badness = " << totalbad << endl;
53
PrintMessage (5, "Total badness = ", totalbad);
54
}
55
56
for (ElementIndex ei = 0; ei < ne; ei++)
57
if (!mesh[ei].IsDeleted())
58
for (int j = 0; j < mesh[ei].GetNP(); j++)
59
elementsonnode.Add (mesh[ei][j], ei);
60
61
INDEX_2_HASHTABLE<int> edgetested (np+1);
62
63
int cnt = 0;
64
65
for (ElementIndex ei = 0; ei < ne; ei++)
66
{
67
if (multithread.terminate)
68
break;
69
70
multithread.percent = 100.0 * (ei+1) / ne;
71
72
if (mesh.ElementType(ei) == FIXEDELEMENT)
73
continue;
74
75
for (int j = 0; j < 6; j++)
76
{
77
Element & elemi = mesh[ei];
78
if (elemi.IsDeleted()) continue;
79
80
static const int tetedges[6][2] =
81
{ { 0, 1 }, { 0, 2 }, { 0, 3 },
82
{ 1, 2 }, { 1, 3 }, { 2, 3 } };
83
84
PointIndex pi1 = elemi[tetedges[j][0]];
85
PointIndex pi2 = elemi[tetedges[j][1]];
86
87
if (pi2 < pi1) Swap (pi1, pi2);
88
89
INDEX_2 si2 (pi1, pi2);
90
si2.Sort();
91
92
if (edgetested.Used (si2)) continue;
93
edgetested.Set (si2, 1);
94
95
96
// hasonepoint.SetSize(0);
97
// hasbothpoints.SetSize(0);
98
hasonepi.SetSize(0);
99
hasbothpi.SetSize(0);
100
101
FlatArray<ElementIndex> row1 = elementsonnode[pi1];
102
for (int k = 0; k < row1.Size(); k++)
103
{
104
Element & elem = mesh[row1[k]];
105
if (elem.IsDeleted()) continue;
106
107
if (elem[0] == pi2 || elem[1] == pi2 ||
108
elem[2] == pi2 || elem[3] == pi2)
109
{
110
hasbothpi.Append (row1[k]);
111
}
112
else
113
{
114
hasonepi.Append (row1[k]);
115
}
116
}
117
118
FlatArray<ElementIndex> row2 = elementsonnode[pi2];
119
for (int k = 0; k < row2.Size(); k++)
120
{
121
Element & elem = mesh[row2[k]];
122
if (elem.IsDeleted()) continue;
123
124
if (elem[0] == pi1 || elem[1] == pi1 ||
125
elem[2] == pi1 || elem[3] == pi1)
126
;
127
else
128
{
129
hasonepi.Append (row2[k]);
130
}
131
}
132
133
double bad1 = 0;
134
for (int k = 0; k < hasonepi.Size(); k++)
135
bad1 += elerrs[hasonepi[k]];
136
for (int k = 0; k < hasbothpi.Size(); k++)
137
bad1 += elerrs[hasbothpi[k]];
138
139
MeshPoint p1 = mesh[pi1];
140
MeshPoint p2 = mesh[pi2];
141
142
143
// if (mesh.PointType(pi2) != INNERPOINT)
144
if (p2.Type() != INNERPOINT)
145
continue;
146
147
MeshPoint pnew;
148
// if (mesh.PointType(pi1) != INNERPOINT)
149
if (p1.Type() != INNERPOINT)
150
pnew = p1;
151
else
152
pnew = Center (p1, p2);
153
154
mesh[pi1] = pnew;
155
mesh[pi2] = pnew;
156
157
oneperr.SetSize (hasonepi.Size());
158
159
double bad2 = 0;
160
for (int k = 0; k < hasonepi.Size(); k++)
161
{
162
const Element & elem = mesh[hasonepi[k]];
163
double err = CalcTetBadness (mesh[elem[0]], mesh[elem[1]],
164
mesh[elem[2]], mesh[elem[3]], 0);
165
bad2 += err;
166
oneperr[k] = err;
167
}
168
169
mesh[pi1] = p1;
170
mesh[pi2] = p2;
171
172
// if (mesh.PointType(pi1) != INNERPOINT)
173
if (p1.Type() != INNERPOINT)
174
{
175
for (int k = 0; k < hasonepi.Size(); k++)
176
{
177
Element & elem = mesh[hasonepi[k]];
178
int l;
179
for (l = 0; l < 4; l++)
180
if (elem[l] == pi2)
181
{
182
elem[l] = pi1;
183
break;
184
}
185
186
elem.flags.illegal_valid = 0;
187
if (!mesh.LegalTet(elem))
188
bad2 += 1e4;
189
190
if (l < 4)
191
{
192
elem.flags.illegal_valid = 0;
193
elem[l] = pi2;
194
}
195
}
196
}
197
198
if (bad2 / hasonepi.Size() <
199
bad1 / (hasonepi.Size()+hasbothpi.Size()))
200
{
201
mesh[pi1] = pnew;
202
cnt++;
203
204
FlatArray<ElementIndex> row = elementsonnode[pi2];
205
for (int k = 0; k < row.Size(); k++)
206
{
207
Element & elem = mesh[row[k]];
208
if (elem.IsDeleted()) continue;
209
210
elementsonnode.Add (pi1, row[k]);
211
for (int l = 0; l < elem.GetNP(); l++)
212
if (elem[l] == pi2)
213
elem[l] = pi1;
214
215
elem.flags.illegal_valid = 0;
216
if (!mesh.LegalTet (elem))
217
(*testout) << "illegal tet " << elementsonnode[pi2][k] << endl;
218
}
219
220
for (int k = 0; k < hasonepi.Size(); k++)
221
elerrs[hasonepi[k]] = oneperr[k];
222
223
for (int k = 0; k < hasbothpi.Size(); k++)
224
{
225
mesh[hasbothpi[k]].flags.illegal_valid = 0;
226
mesh[hasbothpi[k]].Delete();
227
}
228
}
229
}
230
}
231
232
mesh.Compress();
233
mesh.MarkIllegalElements();
234
235
PrintMessage (5, cnt, " elements combined");
236
(*testout) << "CombineImprove done" << "\n";
237
238
totalbad = 0;
239
for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
240
totalbad += CalcBad (mesh.Points(), mesh[ei], 0);
241
242
if (goal == OPT_QUALITY)
243
{
244
totalbad = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
245
(*testout) << "Total badness = " << totalbad << endl;
246
247
int cntill = 0;
248
for (ElementIndex ei = 0; ei < ne; ei++)
249
if (!mesh.LegalTet (mesh[ei]))
250
cntill++;
251
252
PrintMessage (5, cntill, " illegal tets");
253
}
254
multithread.task = savetask;
255
}
256
257
258
259
260
261
/*
262
Mesh improvement by edge splitting.
263
If mesh quality is improved by inserting a node into an inner edge,
264
the edge is split into two parts.
265
*/
266
void MeshOptimize3d :: SplitImprove (Mesh & mesh,
267
OPTIMIZEGOAL goal)
268
{
269
int j, k, l;
270
Point3d p1, p2, pnew;
271
272
ElementIndex ei;
273
SurfaceElementIndex sei;
274
PointIndex pi1, pi2;
275
276
double bad1, bad2, badmax, badlimit;
277
278
279
int cnt = 0;
280
int np = mesh.GetNP();
281
int ne = mesh.GetNE();
282
283
TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np);
284
ARRAY<ElementIndex> hasbothpoints;
285
286
BitArray origpoint(np), boundp(np);
287
origpoint.Set();
288
289
ARRAY<double> elerrs(ne);
290
BitArray illegaltet(ne);
291
illegaltet.Clear();
292
293
const char * savetask = multithread.task;
294
multithread.task = "Split Improve";
295
296
297
PrintMessage (3, "SplitImprove");
298
(*testout) << "start SplitImprove" << "\n";
299
300
ARRAY<INDEX_3> locfaces;
301
302
INDEX_2_HASHTABLE<int> edgetested (np);
303
304
bad1 = 0;
305
badmax = 0;
306
for (ei = 0; ei < ne; ei++)
307
{
308
elerrs[ei] = CalcBad (mesh.Points(), mesh[ei], 0);
309
bad1 += elerrs[ei];
310
if (elerrs[ei] > badmax) badmax = elerrs[ei];
311
}
312
313
PrintMessage (5, "badmax = ", badmax);
314
badlimit = 0.5 * badmax;
315
316
317
boundp.Clear();
318
for (sei = 0; sei < mesh.GetNSE(); sei++)
319
for (j = 0; j < 3; j++)
320
boundp.Set (mesh[sei][j]);
321
322
if (goal == OPT_QUALITY)
323
{
324
bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
325
(*testout) << "Total badness = " << bad1 << endl;
326
}
327
328
for (ei = 0; ei < ne; ei++)
329
for (j = 0; j < mesh[ei].GetNP(); j++)
330
elementsonnode.Add (mesh[ei][j], ei);
331
332
333
mesh.MarkIllegalElements();
334
if (goal == OPT_QUALITY || goal == OPT_LEGAL)
335
{
336
int cntill = 0;
337
for (ei = 0; ei < ne; ei++)
338
{
339
// if (!LegalTet (volelements.Get(i)))
340
if (mesh[ei].flags.illegal)
341
{
342
cntill++;
343
illegaltet.Set (ei+1);
344
}
345
}
346
// (*mycout) << cntill << " illegal tets" << endl;
347
}
348
349
350
for (ei = 0; ei < ne; ei++)
351
{
352
if (multithread.terminate)
353
break;
354
355
multithread.percent = 100.0 * (ei+1) / ne;
356
357
bool ltestmode = 0;
358
359
360
if (elerrs[ei] < badlimit && !illegaltet.Test(ei+1)) continue;
361
362
if ((goal == OPT_LEGAL) &&
363
!illegaltet.Test(ei+1) &&
364
CalcBad (mesh.Points(), mesh[ei], 0) < 1e3)
365
continue;
366
367
368
Element & elem = mesh[ei];
369
370
if (ltestmode)
371
{
372
(*testout) << "test el " << ei << endl;
373
for (j = 0; j < 4; j++)
374
(*testout) << elem[j] << " ";
375
(*testout) << endl;
376
}
377
378
379
for (j = 0; j < 6; j++)
380
{
381
382
static const int tetedges[6][2] =
383
{ { 0, 1 }, { 0, 2 }, { 0, 3 },
384
{ 1, 2 }, { 1, 3 }, { 2, 3 } };
385
386
pi1 = elem[tetedges[j][0]];
387
pi2 = elem[tetedges[j][1]];
388
389
if (pi2 < pi1) Swap (pi1, pi2);
390
if (pi2 > elementsonnode.Size()) continue;
391
392
if (!origpoint.Test(pi1) || !origpoint.Test(pi2))
393
continue;
394
395
396
INDEX_2 i2(pi1, pi2);
397
i2.Sort();
398
399
if (mesh.BoundaryEdge (pi1, pi2)) continue;
400
401
if (edgetested.Used (i2) && !illegaltet.Test(ei+1)) continue;
402
edgetested.Set (i2, 1);
403
404
hasbothpoints.SetSize (0);
405
for (k = 1; k <= elementsonnode.EntrySize(pi1); k++)
406
{
407
bool has1 = 0, has2 = 0;
408
409
ElementIndex elnr = elementsonnode.Get(pi1, k);
410
Element & el = mesh[elnr];
411
412
for (l = 0; l < el.GetNP(); l++)
413
{
414
if (el[l] == pi1) has1 = 1;
415
if (el[l] == pi2) has2 = 1;
416
}
417
if (has1 && has2)
418
{ // only once
419
for (l = 0; l < hasbothpoints.Size(); l++)
420
if (hasbothpoints[l] == elnr)
421
has1 = 0;
422
423
if (has1)
424
hasbothpoints.Append (elnr);
425
}
426
}
427
428
bad1 = 0;
429
for (k = 0; k < hasbothpoints.Size(); k++)
430
bad1 += CalcBad (mesh.Points(), mesh[hasbothpoints[k]], 0);
431
432
433
bool puretet = 1;
434
for (k = 0; k < hasbothpoints.Size(); k++)
435
if (mesh[hasbothpoints[k]].GetType() != TET)
436
puretet = 0;
437
if (!puretet) continue;
438
439
p1 = mesh[pi1];
440
p2 = mesh[pi2];
441
442
/*
443
pnew = Center (p1, p2);
444
445
points.Elem(pi1) = pnew;
446
bad2 = 0;
447
for (k = 1; k <= hasbothpoints.Size(); k++)
448
bad2 += CalcBad (points,
449
volelements.Get(hasbothpoints.Get(k)), 0);
450
451
points.Elem(pi1) = p1;
452
points.Elem(pi2) = pnew;
453
454
for (k = 1; k <= hasbothpoints.Size(); k++)
455
bad2 += CalcBad (points,
456
volelements.Get(hasbothpoints.Get(k)), 0);
457
points.Elem(pi2) = p2;
458
*/
459
460
461
locfaces.SetSize (0);
462
for (k = 0; k < hasbothpoints.Size(); k++)
463
{
464
const Element & el = mesh[hasbothpoints[k]];
465
466
for (l = 0; l < 4; l++)
467
if (el[l] == pi1 || el[l] == pi2)
468
{
469
INDEX_3 i3;
470
Element2d face;
471
el.GetFace (l+1, face);
472
for (int kk = 1; kk <= 3; kk++)
473
i3.I(kk) = face.PNum(kk);
474
locfaces.Append (i3);
475
}
476
}
477
478
PointFunction1 pf (mesh.Points(), locfaces, -1);
479
OptiParameters par;
480
par.maxit_linsearch = 50;
481
par.maxit_bfgs = 20;
482
483
pnew = Center (p1, p2);
484
Vector px(3);
485
px.Elem(1) = pnew.X();
486
px.Elem(2) = pnew.Y();
487
px.Elem(3) = pnew.Z();
488
489
if (elerrs[ei] > 0.1 * badmax)
490
BFGS (px, pf, par);
491
492
bad2 = pf.Func (px);
493
494
pnew.X() = px.Get(1);
495
pnew.Y() = px.Get(2);
496
pnew.Z() = px.Get(3);
497
498
499
int hpinew = mesh.AddPoint (pnew);
500
// ptyps.Append (INNERPOINT);
501
502
for (k = 0; k < hasbothpoints.Size(); k++)
503
{
504
Element & oldel = mesh[hasbothpoints[k]];
505
Element newel1 = oldel;
506
Element newel2 = oldel;
507
508
oldel.flags.illegal_valid = 0;
509
newel1.flags.illegal_valid = 0;
510
newel2.flags.illegal_valid = 0;
511
512
for (l = 0; l < 4; l++)
513
{
514
if (newel1[l] == pi2) newel1[l] = hpinew;
515
if (newel2[l] == pi1) newel2[l] = hpinew;
516
}
517
518
if (!mesh.LegalTet (oldel)) bad1 += 1e6;
519
if (!mesh.LegalTet (newel1)) bad2 += 1e6;
520
if (!mesh.LegalTet (newel2)) bad2 += 1e6;
521
}
522
523
// mesh.PointTypes().DeleteLast();
524
mesh.Points().DeleteLast();
525
526
if (bad2 < bad1)
527
/* (bad1 > 1e4 && boundp.Test(pi1) && boundp.Test(pi2)) */
528
{
529
cnt++;
530
531
PointIndex pinew = mesh.AddPoint (pnew);
532
533
for (k = 0; k < hasbothpoints.Size(); k++)
534
{
535
Element & oldel = mesh[hasbothpoints[k]];
536
Element newel = oldel;
537
538
newel.flags.illegal_valid = 0;
539
oldel.flags.illegal_valid = 0;
540
541
for (l = 0; l < 4; l++)
542
{
543
origpoint.Clear (oldel[l]);
544
545
if (oldel[l] == pi2) oldel[l] = pinew;
546
if (newel[l] == pi1) newel[l] = pinew;
547
}
548
mesh.AddVolumeElement (newel);
549
}
550
551
j = 10;
552
}
553
}
554
}
555
556
557
mesh.Compress();
558
PrintMessage (5, cnt, " splits performed");
559
560
(*testout) << "Splitt - Improve done" << "\n";
561
562
if (goal == OPT_QUALITY)
563
{
564
bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
565
(*testout) << "Total badness = " << bad1 << endl;
566
567
int cntill = 0;
568
ne = mesh.GetNE();
569
for (ei = 0; ei < ne; ei++)
570
{
571
if (!mesh.LegalTet (mesh[ei]))
572
cntill++;
573
}
574
// cout << cntill << " illegal tets" << endl;
575
}
576
577
multithread.task = savetask;
578
}
579
580
581
582
583
584
void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal,
585
const BitArray * working_elements)
586
{
587
int j, k, l;
588
589
ElementIndex ei;
590
SurfaceElementIndex sei;
591
592
PointIndex pi1(0), pi2(0), pi3(0), pi4(0), pi5(0), pi6(0);
593
int cnt = 0;
594
595
Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET);
596
Element el1(TET), el2(TET), el3(TET), el4(TET);
597
Element el1b(TET), el2b(TET), el3b(TET), el4b(TET);
598
599
double bad1, bad2, bad3;
600
601
int np = mesh.GetNP();
602
int ne = mesh.GetNE();
603
//int nse = mesh.GetNSE();
604
605
// contains at least all elements at node
606
TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np);
607
608
ARRAY<ElementIndex> hasbothpoints;
609
610
PrintMessage (3, "SwapImprove ");
611
(*testout) << "\n" << "Start SwapImprove" << endl;
612
613
const char * savetask = multithread.task;
614
multithread.task = "Swap Improve";
615
616
// mesh.CalcSurfacesOfNode ();
617
/*
618
for (i = 1; i <= GetNE(); i++)
619
if (volelements.Get(i).PNum(1))
620
if (!LegalTet (volelements.Get(i)))
621
{
622
cout << "detected illegal tet, 1" << endl;
623
(*testout) << "detected illegal tet1: " << i << endl;
624
}
625
*/
626
627
628
INDEX_3_HASHTABLE<int> faces(mesh.GetNOpenElements()/3 + 2);
629
if (goal == OPT_CONFORM)
630
{
631
for (int i = 1; i <= mesh.GetNOpenElements(); i++)
632
{
633
const Element2d & hel = mesh.OpenElement(i);
634
INDEX_3 face(hel[0], hel[1], hel[2]);
635
face.Sort();
636
faces.Set (face, 1);
637
}
638
}
639
640
// Calculate total badness
641
if (goal == OPT_QUALITY)
642
{
643
bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
644
(*testout) << "Total badness = " << bad1 << endl;
645
}
646
647
// find elements on node
648
for (ei = 0; ei < ne; ei++)
649
for (j = 0; j < mesh[ei].GetNP(); j++)
650
elementsonnode.Add (mesh[ei][j], ei);
651
652
/*
653
BitArray illegaltet(GetNE());
654
MarkIllegalElements();
655
if (goal == OPT_QUALITY || goal == OPT_LEGAL)
656
{
657
int cntill = 0;
658
for (i = 1; i <= GetNE(); i++)
659
{
660
// if (!LegalTet (volelements.Get(i)))
661
if (VolumeElement(i).flags.illegal)
662
{
663
cntill++;
664
illegaltet.Set (i);
665
}
666
}
667
// (*mycout) << cntill << " illegal tets" << endl;
668
}
669
*/
670
671
INDEX_2_HASHTABLE<int> edgeused(2 * ne + 5);
672
673
for (ei = 0; ei < ne; ei++)
674
{
675
if (multithread.terminate)
676
break;
677
678
multithread.percent = 100.0 * (ei+1) / ne;
679
680
if ((mesh.ElementType(ei)) == FIXEDELEMENT)
681
continue;
682
683
if(working_elements &&
684
ei < working_elements->Size() &&
685
!working_elements->Test(ei))
686
continue;
687
688
if (mesh[ei].IsDeleted())
689
continue;
690
691
if ((goal == OPT_LEGAL) &&
692
mesh.LegalTet (mesh[ei]) &&
693
CalcBad (mesh.Points(), mesh[ei], 0) < 1e3)
694
continue;
695
696
// int onlybedges = 1;
697
698
for (j = 0; j < 6; j++)
699
{
700
// loop over edges
701
702
const Element & elemi = mesh[ei];
703
if (elemi.IsDeleted()) continue;
704
705
706
// (*testout) << "check element " << elemi << endl;
707
708
int mattyp = elemi.GetIndex();
709
710
static const int tetedges[6][2] =
711
{ { 0, 1 }, { 0, 2 }, { 0, 3 },
712
{ 1, 2 }, { 1, 3 }, { 2, 3 } };
713
714
pi1 = elemi[tetedges[j][0]];
715
pi2 = elemi[tetedges[j][1]];
716
717
718
if (pi2 < pi1) Swap (pi1, pi2);
719
720
if (mesh.BoundaryEdge (pi1, pi2)) continue;
721
722
723
INDEX_2 i2 (pi1, pi2);
724
i2.Sort();
725
if (edgeused.Used(i2)) continue;
726
edgeused.Set (i2, 1);
727
728
hasbothpoints.SetSize (0);
729
for (k = 0; k < elementsonnode[pi1].Size(); k++)
730
{
731
bool has1 = 0, has2 = 0;
732
ElementIndex elnr = elementsonnode[pi1][k];
733
const Element & elem = mesh[elnr];
734
735
if (elem.IsDeleted()) continue;
736
737
for (l = 0; l < elem.GetNP(); l++)
738
{
739
if (elem[l] == pi1) has1 = 1;
740
if (elem[l] == pi2) has2 = 1;
741
}
742
743
if (has1 && has2)
744
{ // only once
745
for (l = 0; l < hasbothpoints.Size(); l++)
746
if (hasbothpoints[l] == elnr)
747
has1 = 0;
748
749
if (has1)
750
hasbothpoints.Append (elnr);
751
}
752
}
753
754
bool puretet = 1;
755
for (k = 0; k < hasbothpoints.Size(); k++)
756
if (mesh[hasbothpoints[k]].GetType () != TET)
757
puretet = 0;
758
if (!puretet)
759
continue;
760
761
int nsuround = hasbothpoints.Size();
762
763
if ( nsuround == 3 )
764
{
765
Element & elem = mesh[hasbothpoints[0]];
766
for (l = 0; l < 4; l++)
767
if (elem[l] != pi1 && elem[l] != pi2)
768
{
769
pi4 = pi3;
770
pi3 = elem[l];
771
}
772
773
el31[0] = pi1;
774
el31[1] = pi2;
775
el31[2] = pi3;
776
el31[3] = pi4;
777
el31.SetIndex (mattyp);
778
779
if (WrongOrientation (mesh.Points(), el31))
780
{
781
Swap (pi3, pi4);
782
el31[2] = pi3;
783
el31[3] = pi4;
784
}
785
786
pi5 = 0;
787
for (k = 1; k < 3; k++)
788
{
789
const Element & elemk = mesh[hasbothpoints[k]];
790
bool has1 = 0;
791
for (l = 0; l < 4; l++)
792
if (elemk[l] == pi4)
793
has1 = 1;
794
if (has1)
795
{
796
for (l = 0; l < 4; l++)
797
if (elemk[l] != pi1 && elemk[l] != pi2 && elemk[l] != pi4)
798
pi5 = elemk[l];
799
}
800
}
801
802
if(pi5 == 0)
803
throw NgException("Illegal state observed in SwapImprove");
804
805
806
807
el32[0] = pi1;
808
el32[1] = pi2;
809
el32[2] = pi4;
810
el32[3] = pi5;
811
el32.SetIndex (mattyp);
812
813
el33[0] = pi1;
814
el33[1] = pi2;
815
el33[2] = pi5;
816
el33[3] = pi3;
817
el33.SetIndex (mattyp);
818
819
elementsonnode.Add (pi4, hasbothpoints[1]);
820
elementsonnode.Add (pi3, hasbothpoints[2]);
821
822
bad1 = CalcBad (mesh.Points(), el31, 0) +
823
CalcBad (mesh.Points(), el32, 0) +
824
CalcBad (mesh.Points(), el33, 0);
825
826
el31.flags.illegal_valid = 0;
827
el32.flags.illegal_valid = 0;
828
el33.flags.illegal_valid = 0;
829
830
if (!mesh.LegalTet(el31) ||
831
!mesh.LegalTet(el32) ||
832
!mesh.LegalTet(el33))
833
bad1 += 1e4;
834
835
el21[0] = pi3;
836
el21[1] = pi4;
837
el21[2] = pi5;
838
el21[3] = pi2;
839
el21.SetIndex (mattyp);
840
841
el22[0] = pi5;
842
el22[1] = pi4;
843
el22[2] = pi3;
844
el22[3] = pi1;
845
el22.SetIndex (mattyp);
846
847
bad2 = CalcBad (mesh.Points(), el21, 0) +
848
CalcBad (mesh.Points(), el22, 0);
849
850
el21.flags.illegal_valid = 0;
851
el22.flags.illegal_valid = 0;
852
853
if (!mesh.LegalTet(el21) ||
854
!mesh.LegalTet(el22))
855
bad2 += 1e4;
856
857
858
if (goal == OPT_CONFORM && bad2 < 1e4)
859
{
860
INDEX_3 face(pi3, pi4, pi5);
861
face.Sort();
862
if (faces.Used(face))
863
{
864
// (*testout) << "3->2 swap, could improve conformity, bad1 = " << bad1
865
// << ", bad2 = " << bad2 << endl;
866
if (bad2 < 1e4)
867
bad1 = 2 * bad2;
868
}
869
/*
870
else
871
{
872
INDEX_2 hi1(pi3, pi4);
873
hi1.Sort();
874
INDEX_2 hi2(pi3, pi5);
875
hi2.Sort();
876
INDEX_2 hi3(pi4, pi5);
877
hi3.Sort();
878
879
if (boundaryedges->Used (hi1) ||
880
boundaryedges->Used (hi2) ||
881
boundaryedges->Used (hi3) )
882
bad1 = 2 * bad2;
883
}
884
*/
885
}
886
887
if (bad2 < bad1)
888
{
889
// (*mycout) << "3->2 " << flush;
890
// (*testout) << "3->2 conversion" << endl;
891
cnt++;
892
893
894
/*
895
(*testout) << "3->2 swap, old els = " << endl
896
<< mesh[hasbothpoints[0]] << endl
897
<< mesh[hasbothpoints[1]] << endl
898
<< mesh[hasbothpoints[2]] << endl
899
<< "new els = " << endl
900
<< el21 << endl
901
<< el22 << endl;
902
*/
903
904
el21.flags.illegal_valid = 0;
905
el22.flags.illegal_valid = 0;
906
mesh[hasbothpoints[0]] = el21;
907
mesh[hasbothpoints[1]] = el22;
908
for (l = 0; l < 4; l++)
909
mesh[hasbothpoints[2]][l] = 0;
910
mesh[hasbothpoints[2]].Delete();
911
912
for (k = 0; k < 2; k++)
913
for (l = 0; l < 4; l++)
914
elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
915
}
916
}
917
918
919
if (nsuround == 4)
920
{
921
const Element & elem1 = mesh[hasbothpoints[0]];
922
for (l = 0; l < 4; l++)
923
if (elem1[l] != pi1 && elem1[l] != pi2)
924
{
925
pi4 = pi3;
926
pi3 = elem1[l];
927
}
928
929
el1[0] = pi1; el1[1] = pi2;
930
el1[2] = pi3; el1[3] = pi4;
931
el1.SetIndex (mattyp);
932
933
if (WrongOrientation (mesh.Points(), el1))
934
{
935
Swap (pi3, pi4);
936
el1[2] = pi3;
937
el1[3] = pi4;
938
}
939
940
pi5 = 0;
941
for (k = 1; k < 4; k++)
942
{
943
const Element & elem = mesh[hasbothpoints[k]];
944
bool has1 = 0;
945
for (l = 0; l < 4; l++)
946
if (elem[l] == pi4)
947
has1 = 1;
948
if (has1)
949
{
950
for (l = 0; l < 4; l++)
951
if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi4)
952
pi5 = elem[l];
953
}
954
}
955
956
pi6 = 0;
957
for (k = 1; k < 4; k++)
958
{
959
const Element & elem = mesh[hasbothpoints[k]];
960
bool has1 = 0;
961
for (l = 0; l < 4; l++)
962
if (elem[l] == pi3)
963
has1 = 1;
964
if (has1)
965
{
966
for (l = 0; l < 4; l++)
967
if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi3)
968
pi6 = elem[l];
969
}
970
}
971
972
/*
973
INDEX_2 i22(pi3, pi5);
974
i22.Sort();
975
INDEX_2 i23(pi4, pi6);
976
i23.Sort();
977
*/
978
979
el1[0] = pi1; el1[1] = pi2;
980
el1[2] = pi3; el1[3] = pi4;
981
el1.SetIndex (mattyp);
982
983
el2[0] = pi1; el2[1] = pi2;
984
el2[2] = pi4; el2[3] = pi5;
985
el2.SetIndex (mattyp);
986
987
el3[0] = pi1; el3[1] = pi2;
988
el3[2] = pi5; el3[3] = pi6;
989
el3.SetIndex (mattyp);
990
991
el4[0] = pi1; el4[1] = pi2;
992
el4[2] = pi6; el4[3] = pi3;
993
el4.SetIndex (mattyp);
994
995
// elementsonnode.Add (pi4, hasbothpoints.Elem(2));
996
// elementsonnode.Add (pi3, hasbothpoints.Elem(3));
997
998
bad1 = CalcBad (mesh.Points(), el1, 0) +
999
CalcBad (mesh.Points(), el2, 0) +
1000
CalcBad (mesh.Points(), el3, 0) +
1001
CalcBad (mesh.Points(), el4, 0);
1002
1003
1004
el1.flags.illegal_valid = 0;
1005
el2.flags.illegal_valid = 0;
1006
el3.flags.illegal_valid = 0;
1007
el4.flags.illegal_valid = 0;
1008
1009
1010
if (goal != OPT_CONFORM)
1011
{
1012
if (!mesh.LegalTet(el1) ||
1013
!mesh.LegalTet(el2) ||
1014
!mesh.LegalTet(el3) ||
1015
!mesh.LegalTet(el4))
1016
bad1 += 1e4;
1017
}
1018
1019
el1[0] = pi3; el1[1] = pi5;
1020
el1[2] = pi2; el1[3] = pi4;
1021
el1.SetIndex (mattyp);
1022
1023
el2[0] = pi3; el2[1] = pi5;
1024
el2[2] = pi4; el2[3] = pi1;
1025
el2.SetIndex (mattyp);
1026
1027
el3[0] = pi3; el3[1] = pi5;
1028
el3[2] = pi1; el3[3] = pi6;
1029
el3.SetIndex (mattyp);
1030
1031
el4[0] = pi3; el4[1] = pi5;
1032
el4[2] = pi6; el4[3] = pi2;
1033
el4.SetIndex (mattyp);
1034
1035
bad2 = CalcBad (mesh.Points(), el1, 0) +
1036
CalcBad (mesh.Points(), el2, 0) +
1037
CalcBad (mesh.Points(), el3, 0) +
1038
CalcBad (mesh.Points(), el4, 0);
1039
1040
el1.flags.illegal_valid = 0;
1041
el2.flags.illegal_valid = 0;
1042
el3.flags.illegal_valid = 0;
1043
el4.flags.illegal_valid = 0;
1044
1045
if (goal != OPT_CONFORM)
1046
{
1047
if (!mesh.LegalTet(el1) ||
1048
!mesh.LegalTet(el2) ||
1049
!mesh.LegalTet(el3) ||
1050
!mesh.LegalTet(el4))
1051
bad2 += 1e4;
1052
}
1053
1054
1055
el1b[0] = pi4; el1b[1] = pi6;
1056
el1b[2] = pi3; el1b[3] = pi2;
1057
el1b.SetIndex (mattyp);
1058
1059
el2b[0] = pi4; el2b[1] = pi6;
1060
el2b[2] = pi2; el2b[3] = pi5;
1061
el2b.SetIndex (mattyp);
1062
1063
el3b[0] = pi4; el3b[1] = pi6;
1064
el3b[2] = pi5; el3b[3] = pi1;
1065
el3b.SetIndex (mattyp);
1066
1067
el4b[0] = pi4; el4b[1] = pi6;
1068
el4b[2] = pi1; el4b[3] = pi3;
1069
el4b.SetIndex (mattyp);
1070
1071
bad3 = CalcBad (mesh.Points(), el1b, 0) +
1072
CalcBad (mesh.Points(), el2b, 0) +
1073
CalcBad (mesh.Points(), el3b, 0) +
1074
CalcBad (mesh.Points(), el4b, 0);
1075
1076
el1b.flags.illegal_valid = 0;
1077
el2b.flags.illegal_valid = 0;
1078
el3b.flags.illegal_valid = 0;
1079
el4b.flags.illegal_valid = 0;
1080
1081
if (goal != OPT_CONFORM)
1082
{
1083
if (!mesh.LegalTet(el1b) ||
1084
!mesh.LegalTet(el2b) ||
1085
!mesh.LegalTet(el3b) ||
1086
!mesh.LegalTet(el4b))
1087
bad3 += 1e4;
1088
}
1089
1090
1091
/*
1092
int swap2 = (bad2 < bad1) && (bad2 < bad3);
1093
int swap3 = !swap2 && (bad3 < bad1);
1094
1095
if ( ((bad2 < 10 * bad1) ||
1096
(bad2 < 1e6)) && mesh.BoundaryEdge (pi3, pi5))
1097
swap2 = 1;
1098
else if ( ((bad3 < 10 * bad1) ||
1099
(bad3 < 1e6)) && mesh.BoundaryEdge (pi4, pi6))
1100
{
1101
swap3 = 1;
1102
swap2 = 0;
1103
}
1104
*/
1105
bool swap2, swap3;
1106
1107
if (goal != OPT_CONFORM)
1108
{
1109
swap2 = (bad2 < bad1) && (bad2 < bad3);
1110
swap3 = !swap2 && (bad3 < bad1);
1111
}
1112
else
1113
{
1114
if (mesh.BoundaryEdge (pi3, pi5)) bad2 /= 1e6;
1115
if (mesh.BoundaryEdge (pi4, pi6)) bad3 /= 1e6;
1116
1117
swap2 = (bad2 < bad1) && (bad2 < bad3);
1118
swap3 = !swap2 && (bad3 < bad1);
1119
}
1120
1121
1122
if (swap2 || swap3)
1123
{
1124
// (*mycout) << "4->4 " << flush;
1125
cnt++;
1126
// (*testout) << "4->4 conversion" << "\n";
1127
/*
1128
(*testout) << "bad1 = " << bad1
1129
<< " bad2 = " << bad2
1130
<< " bad3 = " << bad3 << "\n";
1131
1132
(*testout) << "Points: " << pi1 << " " << pi2 << " " << pi3
1133
<< " " << pi4 << " " << pi5 << " " << pi6 << "\n";
1134
(*testout) << "Elements: "
1135
<< hasbothpoints.Get(1) << " "
1136
<< hasbothpoints.Get(2) << " "
1137
<< hasbothpoints.Get(3) << " "
1138
<< hasbothpoints.Get(4) << " " << "\n";
1139
*/
1140
1141
/*
1142
{
1143
int i1, j1;
1144
for (i1 = 1; i1 <= 4; i1++)
1145
{
1146
for (j1 = 1; j1 <= 4; j1++)
1147
(*testout) << volelements.Get(hasbothpoints.Get(i1)).PNum(j1)
1148
<< " ";
1149
(*testout) << "\n";
1150
}
1151
}
1152
*/
1153
}
1154
1155
1156
if (swap2)
1157
{
1158
// (*mycout) << "bad1 = " << bad1 << " bad2 = " << bad2 << "\n";
1159
1160
1161
/*
1162
(*testout) << "4->4 swap A, old els = " << endl
1163
<< mesh[hasbothpoints[0]] << endl
1164
<< mesh[hasbothpoints[1]] << endl
1165
<< mesh[hasbothpoints[2]] << endl
1166
<< mesh[hasbothpoints[3]] << endl
1167
<< "new els = " << endl
1168
<< el1 << endl
1169
<< el2 << endl
1170
<< el3 << endl
1171
<< el4 << endl;
1172
*/
1173
1174
1175
1176
el1.flags.illegal_valid = 0;
1177
el2.flags.illegal_valid = 0;
1178
el3.flags.illegal_valid = 0;
1179
el4.flags.illegal_valid = 0;
1180
1181
mesh[hasbothpoints[0]] = el1;
1182
mesh[hasbothpoints[1]] = el2;
1183
mesh[hasbothpoints[2]] = el3;
1184
mesh[hasbothpoints[3]] = el4;
1185
1186
for (k = 0; k < 4; k++)
1187
for (l = 0; l < 4; l++)
1188
elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
1189
}
1190
else if (swap3)
1191
{
1192
// (*mycout) << "bad1 = " << bad1 << " bad3 = " << bad3 << "\n";
1193
el1b.flags.illegal_valid = 0;
1194
el2b.flags.illegal_valid = 0;
1195
el3b.flags.illegal_valid = 0;
1196
el4b.flags.illegal_valid = 0;
1197
1198
1199
/*
1200
(*testout) << "4->4 swap A, old els = " << endl
1201
<< mesh[hasbothpoints[0]] << endl
1202
<< mesh[hasbothpoints[1]] << endl
1203
<< mesh[hasbothpoints[2]] << endl
1204
<< mesh[hasbothpoints[3]] << endl
1205
<< "new els = " << endl
1206
<< el1b << endl
1207
<< el2b << endl
1208
<< el3b << endl
1209
<< el4b << endl;
1210
*/
1211
1212
1213
mesh[hasbothpoints[0]] = el1b;
1214
mesh[hasbothpoints[1]] = el2b;
1215
mesh[hasbothpoints[2]] = el3b;
1216
mesh[hasbothpoints[3]] = el4b;
1217
1218
1219
for (k = 0; k < 4; k++)
1220
for (l = 0; l < 4; l++)
1221
elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
1222
}
1223
}
1224
1225
if (nsuround >= 5)
1226
{
1227
Element hel(TET);
1228
1229
ArrayMem<PointIndex, 50> suroundpts(nsuround);
1230
ArrayMem<char, 50> tetused(nsuround);
1231
1232
Element & elem = mesh[hasbothpoints[0]];
1233
1234
for (l = 0; l < 4; l++)
1235
if (elem[l] != pi1 && elem[l] != pi2)
1236
{
1237
pi4 = pi3;
1238
pi3 = elem[l];
1239
}
1240
1241
hel[0] = pi1;
1242
hel[1] = pi2;
1243
hel[2] = pi3;
1244
hel[3] = pi4;
1245
hel.SetIndex (mattyp);
1246
1247
if (WrongOrientation (mesh.Points(), hel))
1248
{
1249
Swap (pi3, pi4);
1250
hel[2] = pi3;
1251
hel[3] = pi4;
1252
}
1253
1254
1255
// suroundpts.SetSize (nsuround);
1256
suroundpts[0] = pi3;
1257
suroundpts[1] = pi4;
1258
1259
tetused = 0;
1260
tetused[0] = 1;
1261
1262
for (l = 2; l < nsuround; l++)
1263
{
1264
int oldpi = suroundpts[l-1];
1265
int newpi = 0;
1266
1267
for (k = 0; k < nsuround && !newpi; k++)
1268
if (!tetused[k])
1269
{
1270
const Element & nel = mesh[hasbothpoints[k]];
1271
1272
for (int k2 = 0; k2 < 4 && !newpi; k2++)
1273
if (nel[k2] == oldpi)
1274
{
1275
newpi =
1276
nel[0] + nel[1] + nel[2] + nel[3]
1277
- pi1 - pi2 - oldpi;
1278
1279
tetused[k] = 1;
1280
suroundpts[l] = newpi;
1281
}
1282
}
1283
}
1284
1285
1286
bad1 = 0;
1287
for (k = 0; k < nsuround; k++)
1288
{
1289
hel[0] = pi1;
1290
hel[1] = pi2;
1291
hel[2] = suroundpts[k];
1292
hel[3] = suroundpts[(k+1) % nsuround];
1293
hel.SetIndex (mattyp);
1294
1295
bad1 += CalcBad (mesh.Points(), hel, 0);
1296
}
1297
1298
// (*testout) << "nsuround = " << nsuround << " bad1 = " << bad1 << endl;
1299
1300
1301
int bestl = -1;
1302
int confface = -1;
1303
int confedge = -1;
1304
double badopt = bad1;
1305
1306
for (l = 0; l < nsuround; l++)
1307
{
1308
bad2 = 0;
1309
1310
for (k = l+1; k <= nsuround + l - 2; k++)
1311
{
1312
hel[0] = suroundpts[l];
1313
hel[1] = suroundpts[k % nsuround];
1314
hel[2] = suroundpts[(k+1) % nsuround];
1315
hel[3] = pi2;
1316
1317
bad2 += CalcBad (mesh.Points(), hel, 0);
1318
hel.flags.illegal_valid = 0;
1319
if (!mesh.LegalTet(hel)) bad2 += 1e4;
1320
1321
hel[2] = suroundpts[k % nsuround];
1322
hel[1] = suroundpts[(k+1) % nsuround];
1323
hel[3] = pi1;
1324
1325
bad2 += CalcBad (mesh.Points(), hel, 0);
1326
1327
hel.flags.illegal_valid = 0;
1328
if (!mesh.LegalTet(hel)) bad2 += 1e4;
1329
}
1330
// (*testout) << "bad2," << l << " = " << bad2 << endl;
1331
1332
if ( bad2 < badopt )
1333
{
1334
bestl = l;
1335
badopt = bad2;
1336
}
1337
1338
1339
if (goal == OPT_CONFORM)
1340
// (bad2 <= 100 * bad1 || bad2 <= 1e6))
1341
{
1342
bool nottoobad =
1343
(bad2 <= bad1) ||
1344
(bad2 <= 100 * bad1 && bad2 <= 1e18) ||
1345
(bad2 <= 1e8);
1346
1347
for (k = l+1; k <= nsuround + l - 2; k++)
1348
{
1349
INDEX_3 hi3(suroundpts[l],
1350
suroundpts[k % nsuround],
1351
suroundpts[(k+1) % nsuround]);
1352
hi3.Sort();
1353
if (faces.Used(hi3))
1354
{
1355
// (*testout) << "could improve face conformity, bad1 = " << bad1
1356
// << ", bad 2 = " << bad2 << ", nottoobad = " << nottoobad << endl;
1357
if (nottoobad)
1358
confface = l;
1359
}
1360
}
1361
1362
for (k = l+2; k <= nsuround+l-2; k++)
1363
{
1364
if (mesh.BoundaryEdge (suroundpts[l],
1365
suroundpts[k % nsuround]))
1366
{
1367
/*
1368
*testout << "could improve edge conformity, bad1 = " << bad1
1369
<< ", bad 2 = " << bad2 << ", nottoobad = " << nottoobad << endl;
1370
*/
1371
if (nottoobad)
1372
confedge = l;
1373
}
1374
}
1375
}
1376
}
1377
1378
if (confedge != -1)
1379
bestl = confedge;
1380
if (confface != -1)
1381
bestl = confface;
1382
1383
if (bestl != -1)
1384
{
1385
// (*mycout) << nsuround << "->" << 2 * (nsuround-2) << " " << flush;
1386
cnt++;
1387
1388
for (k = bestl+1; k <= nsuround + bestl - 2; k++)
1389
{
1390
int k1;
1391
1392
hel[0] = suroundpts[bestl];
1393
hel[1] = suroundpts[k % nsuround];
1394
hel[2] = suroundpts[(k+1) % nsuround];
1395
hel[3] = pi2;
1396
hel.flags.illegal_valid = 0;
1397
1398
/*
1399
(*testout) << nsuround << "-swap, new el,top = "
1400
<< hel << endl;
1401
*/
1402
mesh.AddVolumeElement (hel);
1403
1404
for (k1 = 0; k1 < 4; k1++)
1405
elementsonnode.Add (hel[k1], mesh.GetNE()-1);
1406
1407
1408
hel[2] = suroundpts[k % nsuround];
1409
hel[1] = suroundpts[(k+1) % nsuround];
1410
hel[3] = pi1;
1411
1412
/*
1413
(*testout) << nsuround << "-swap, new el,bot = "
1414
<< hel << endl;
1415
*/
1416
1417
mesh.AddVolumeElement (hel);
1418
1419
for (k1 = 0; k1 < 4; k1++)
1420
elementsonnode.Add (hel[k1], mesh.GetNE()-1);
1421
}
1422
1423
for (k = 0; k < nsuround; k++)
1424
{
1425
Element & rel = mesh[hasbothpoints[k]];
1426
/*
1427
(*testout) << nsuround << "-swap, old el = "
1428
<< rel << endl;
1429
*/
1430
rel.Delete();
1431
for (int k1 = 0; k1 < 4; k1++)
1432
rel[k1] = 0;
1433
1434
}
1435
}
1436
}
1437
}
1438
1439
/*
1440
if (onlybedges)
1441
{
1442
(*testout) << "bad tet: "
1443
<< volelements.Get(i)[0]
1444
<< volelements.Get(i)[1]
1445
<< volelements.Get(i)[2]
1446
<< volelements.Get(i)[3] << "\n";
1447
1448
if (!mesh.LegalTet (volelements.Get(i)))
1449
cerr << "Illegal tet" << "\n";
1450
}
1451
*/
1452
}
1453
// (*mycout) << endl;
1454
1455
/*
1456
cout << "edgeused: ";
1457
edgeused.PrintMemInfo(cout);
1458
*/
1459
PrintMessage (5, cnt, " swaps performed");
1460
1461
1462
1463
1464
1465
mesh.Compress ();
1466
1467
/*
1468
if (goal == OPT_QUALITY)
1469
{
1470
bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
1471
// (*testout) << "Total badness = " << bad1 << endl;
1472
}
1473
*/
1474
1475
/*
1476
for (i = 1; i <= GetNE(); i++)
1477
if (volelements.Get(i)[0])
1478
if (!mesh.LegalTet (volelements.Get(i)))
1479
{
1480
cout << "detected illegal tet, 2" << endl;
1481
(*testout) << "detected illegal tet1: " << i << endl;
1482
}
1483
*/
1484
1485
multithread.task = savetask;
1486
}
1487
1488
1489
1490
1491
1492
1493
void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal,
1494
const BitArray * working_elements,
1495
const ARRAY< ARRAY<int,PointIndex::BASE>* > * idmaps)
1496
{
1497
ARRAY< ARRAY<int,PointIndex::BASE>* > locidmaps;
1498
const ARRAY< ARRAY<int,PointIndex::BASE>* > * used_idmaps;
1499
1500
if(idmaps)
1501
used_idmaps = idmaps;
1502
else
1503
{
1504
used_idmaps = &locidmaps;
1505
1506
for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
1507
{
1508
if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
1509
{
1510
locidmaps.Append(new ARRAY<int,PointIndex::BASE>);
1511
mesh.GetIdentifications().GetMap(i,*locidmaps.Last(),true);
1512
}
1513
}
1514
}
1515
1516
ElementIndex ei;
1517
SurfaceElementIndex sei;
1518
1519
PointIndex pi1, pi2, pi3, pi4, pi5, pi6;
1520
PointIndex pi1other, pi2other;
1521
int cnt = 0;
1522
1523
//double bad1, bad2, bad3, sbad;
1524
double bad1, sbad;
1525
double h;
1526
1527
int np = mesh.GetNP();
1528
int ne = mesh.GetNE();
1529
int nse = mesh.GetNSE();
1530
1531
int mattype, othermattype;
1532
1533
1534
// contains at least all elements at node
1535
TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np);
1536
TABLE<SurfaceElementIndex,PointIndex::BASE> surfaceelementsonnode(np);
1537
TABLE<int,PointIndex::BASE> surfaceindicesonnode(np);
1538
1539
ARRAY<ElementIndex> hasbothpoints;
1540
ARRAY<ElementIndex> hasbothpointsother;
1541
1542
PrintMessage (3, "SwapImproveSurface ");
1543
(*testout) << "\n" << "Start SwapImproveSurface" << endl;
1544
1545
const char * savetask = multithread.task;
1546
multithread.task = "Swap Improve Surface";
1547
1548
1549
1550
// find elements on node
1551
for (ei = 0; ei < ne; ei++)
1552
for (int j = 0; j < mesh[ei].GetNP(); j++)
1553
elementsonnode.Add (mesh[ei][j], ei);
1554
1555
for (sei = 0; sei < nse; sei++)
1556
for(int j=0; j<mesh[sei].GetNP(); j++)
1557
{
1558
surfaceelementsonnode.Add(mesh[sei][j], sei);
1559
if(!surfaceindicesonnode[mesh[sei][j]].Contains(mesh[sei].GetIndex()))
1560
surfaceindicesonnode.Add(mesh[sei][j],mesh[sei].GetIndex());
1561
}
1562
1563
bool periodic;
1564
int idnum(-1);
1565
1566
INDEX_2_HASHTABLE<int> edgeused(2 * ne + 5);
1567
1568
for (ei = 0; ei < ne; ei++)
1569
{
1570
if (multithread.terminate)
1571
break;
1572
1573
multithread.percent = 100.0 * (ei+1) / ne;
1574
1575
if (mesh.ElementType(ei) == FIXEDELEMENT)
1576
continue;
1577
1578
if(working_elements &&
1579
ei < working_elements->Size() &&
1580
!working_elements->Test(ei))
1581
continue;
1582
1583
if (mesh[ei].IsDeleted())
1584
continue;
1585
1586
if ((goal == OPT_LEGAL) &&
1587
mesh.LegalTet (mesh[ei]) &&
1588
CalcBad (mesh.Points(), mesh[ei], 0) < 1e3)
1589
continue;
1590
1591
const Element & elemi = mesh[ei];
1592
//Element elemi = mesh[ei];
1593
if (elemi.IsDeleted()) continue;
1594
1595
1596
mattype = elemi.GetIndex();
1597
1598
bool swapped = false;
1599
1600
for (int j = 0; !swapped && j < 6; j++)
1601
{
1602
// loop over edges
1603
1604
1605
static const int tetedges[6][2] =
1606
{ { 0, 1 }, { 0, 2 }, { 0, 3 },
1607
{ 1, 2 }, { 1, 3 }, { 2, 3 } };
1608
1609
pi1 = elemi[tetedges[j][0]];
1610
pi2 = elemi[tetedges[j][1]];
1611
1612
1613
if (pi2 < pi1)
1614
Swap (pi1, pi2);
1615
1616
1617
bool found = false;
1618
for(int k=0; !found && k<used_idmaps->Size(); k++)
1619
{
1620
if(pi2 < (*used_idmaps)[k]->Size() + PointIndex::BASE)
1621
{
1622
pi1other = (*(*used_idmaps)[k])[pi1];
1623
pi2other = (*(*used_idmaps)[k])[pi2];
1624
found = (pi1other != 0 && pi2other != 0 && pi1other != pi1 && pi2other != pi2);
1625
if(found)
1626
idnum = k;
1627
}
1628
}
1629
if(found)
1630
periodic = true;
1631
else
1632
{
1633
periodic = false;
1634
pi1other = pi1; pi2other = pi2;
1635
}
1636
1637
1638
1639
if (!mesh.BoundaryEdge (pi1, pi2) ||
1640
mesh.IsSegment(pi1, pi2)) continue;
1641
1642
othermattype = -1;
1643
1644
1645
INDEX_2 i2 (pi1, pi2);
1646
i2.Sort();
1647
if (edgeused.Used(i2)) continue;
1648
edgeused.Set (i2, 1);
1649
if(periodic)
1650
{
1651
i2.I1() = pi1other;
1652
i2.I2() = pi2other;
1653
i2.Sort();
1654
edgeused.Set(i2,1);
1655
}
1656
1657
1658
hasbothpoints.SetSize (0);
1659
hasbothpointsother.SetSize (0);
1660
for (int k = 0; k < elementsonnode[pi1].Size(); k++)
1661
{
1662
bool has1 = false, has2 = false;
1663
ElementIndex elnr = elementsonnode[pi1][k];
1664
const Element & elem = mesh[elnr];
1665
1666
if (elem.IsDeleted()) continue;
1667
1668
for (int l = 0; l < elem.GetNP(); l++)
1669
{
1670
if (elem[l] == pi1) has1 = true;
1671
if (elem[l] == pi2) has2 = true;
1672
}
1673
1674
if (has1 && has2)
1675
{
1676
if(othermattype == -1 && elem.GetIndex() != mattype)
1677
othermattype = elem.GetIndex();
1678
1679
if(elem.GetIndex() == mattype)
1680
{
1681
// only once
1682
for (int l = 0; l < hasbothpoints.Size(); l++)
1683
if (hasbothpoints[l] == elnr)
1684
has1 = 0;
1685
1686
if (has1)
1687
hasbothpoints.Append (elnr);
1688
}
1689
else if(elem.GetIndex() == othermattype)
1690
{
1691
// only once
1692
for (int l = 0; l < hasbothpointsother.Size(); l++)
1693
if (hasbothpointsother[l] == elnr)
1694
has1 = 0;
1695
1696
if (has1)
1697
hasbothpointsother.Append (elnr);
1698
}
1699
else
1700
{
1701
cout << "problem with domain indices" << endl;
1702
(*testout) << "problem: mattype = " << mattype << ", othermattype = " << othermattype
1703
<< " elem " << elem << " mt " << elem.GetIndex() << endl
1704
<< " pi1 " << pi1 << " pi2 " << pi2 << endl;
1705
(*testout) << "hasbothpoints:" << endl;
1706
for(int ii=0; ii < hasbothpoints.Size(); ii++)
1707
(*testout) << mesh[hasbothpoints[ii]] << endl;
1708
(*testout) << "hasbothpointsother:" << endl;
1709
for(int ii=0; ii < hasbothpointsother.Size(); ii++)
1710
(*testout) << mesh[hasbothpointsother[ii]] << endl;
1711
}
1712
}
1713
}
1714
1715
if(hasbothpointsother.Size() > 0 && periodic)
1716
throw NgException("SwapImproveSurface: Assumption about interface/periodicity wrong!");
1717
1718
if(periodic)
1719
{
1720
for (int k = 0; k < elementsonnode[pi1other].Size(); k++)
1721
{
1722
bool has1 = false, has2 = false;
1723
ElementIndex elnr = elementsonnode[pi1other][k];
1724
const Element & elem = mesh[elnr];
1725
1726
if (elem.IsDeleted()) continue;
1727
1728
for (int l = 0; l < elem.GetNP(); l++)
1729
{
1730
if (elem[l] == pi1other) has1 = true;
1731
if (elem[l] == pi2other) has2 = true;
1732
}
1733
1734
if (has1 && has2)
1735
{
1736
if(othermattype == -1)
1737
othermattype = elem.GetIndex();
1738
1739
// only once
1740
for (int l = 0; l < hasbothpointsother.Size(); l++)
1741
if (hasbothpointsother[l] == elnr)
1742
has1 = 0;
1743
1744
if (has1)
1745
hasbothpointsother.Append (elnr);
1746
}
1747
}
1748
}
1749
1750
1751
//for(k=0; k<hasbothpoints.Size(); k++)
1752
// (*testout) << "hasbothpoints["<<k<<"]: " << mesh[hasbothpoints[k]] << endl;
1753
1754
1755
SurfaceElementIndex sel1=-1,sel2=-1;
1756
SurfaceElementIndex sel1other=-1,sel2other=-1;
1757
for(int k = 0; k < surfaceelementsonnode[pi1].Size(); k++)
1758
{
1759
bool has1 = false, has2 = false;
1760
SurfaceElementIndex elnr = surfaceelementsonnode[pi1][k];
1761
const Element2d & elem = mesh[elnr];
1762
1763
if (elem.IsDeleted()) continue;
1764
1765
for (int l = 0; l < elem.GetNP(); l++)
1766
{
1767
if (elem[l] == pi1) has1 = true;
1768
if (elem[l] == pi2) has2 = true;
1769
}
1770
1771
if(has1 && has2 && elnr != sel2)
1772
{
1773
sel1 = sel2;
1774
sel2 = elnr;
1775
}
1776
}
1777
1778
if(periodic)
1779
{
1780
for(int k = 0; k < surfaceelementsonnode[pi1other].Size(); k++)
1781
{
1782
bool has1 = false, has2 = false;
1783
SurfaceElementIndex elnr = surfaceelementsonnode[pi1other][k];
1784
const Element2d & elem = mesh[elnr];
1785
1786
if (elem.IsDeleted()) continue;
1787
1788
for (int l = 0; l < elem.GetNP(); l++)
1789
{
1790
if (elem[l] == pi1other) has1 = true;
1791
if (elem[l] == pi2other) has2 = true;
1792
}
1793
1794
if(has1 && has2 && elnr != sel2other)
1795
{
1796
sel1other = sel2other;
1797
sel2other = elnr;
1798
}
1799
}
1800
}
1801
else
1802
{
1803
sel1other = sel1; sel2other = sel2;
1804
}
1805
1806
//(*testout) << "sel1 " << sel1 << " sel2 " << sel2 << " el " << mesh[sel1] << " resp. " << mesh[sel2] << endl;
1807
1808
PointIndex sp1(0), sp2(0);
1809
PointIndex sp1other, sp2other;
1810
for(int l=0; l<mesh[sel1].GetNP(); l++)
1811
if(mesh[sel1][l] != pi1 && mesh[sel1][l] != pi2)
1812
sp1 = mesh[sel1][l];
1813
for(int l=0; l<mesh[sel2].GetNP(); l++)
1814
if(mesh[sel2][l] != pi1 && mesh[sel2][l] != pi2)
1815
sp2 = mesh[sel2][l];
1816
1817
if(periodic)
1818
{
1819
sp1other = (*(*used_idmaps)[idnum])[sp1];
1820
sp2other = (*(*used_idmaps)[idnum])[sp2];
1821
1822
bool change = false;
1823
for(int l=0; !change && l<mesh[sel1other].GetNP(); l++)
1824
change = (sp2other == mesh[sel1other][l]);
1825
1826
if(change)
1827
{
1828
SurfaceElementIndex aux = sel1other;
1829
sel1other = sel2other;
1830
sel2other = aux;
1831
}
1832
1833
}
1834
else
1835
{
1836
sp1other = sp1; sp2other = sp2;
1837
}
1838
1839
Vec<3> v1 = mesh[sp1]-mesh[pi1],
1840
v2 = mesh[sp2]-mesh[pi1],
1841
v3 = mesh[sp1]-mesh[pi2],
1842
v4 = mesh[sp2]-mesh[pi2];
1843
double vol = 0.5*(Cross(v1,v2).Length() + Cross(v3,v4).Length());
1844
h = sqrt(vol);
1845
h = 0;
1846
1847
sbad = CalcTriangleBadness (mesh[pi1],mesh[pi2],mesh[sp1],0,0) +
1848
CalcTriangleBadness (mesh[pi2],mesh[pi1],mesh[sp2],0,0);
1849
1850
1851
1852
bool puretet = true;
1853
for (int k = 0; puretet && k < hasbothpoints.Size(); k++)
1854
if (mesh[hasbothpoints[k]].GetType () != TET)
1855
puretet = false;
1856
for (int k = 0; puretet && k < hasbothpointsother.Size(); k++)
1857
if (mesh[hasbothpointsother[k]].GetType () != TET)
1858
puretet = false;
1859
if (!puretet)
1860
continue;
1861
1862
int nsuround = hasbothpoints.Size();
1863
int nsuroundother = hasbothpointsother.Size();
1864
1865
ARRAY < int > outerpoints(nsuround+1);
1866
outerpoints[0] = sp1;
1867
1868
for(int i=0; i<nsuround; i++)
1869
{
1870
bool done = false;
1871
for(int jj=i; !done && jj<hasbothpoints.Size(); jj++)
1872
{
1873
for(int k=0; !done && k<4; k++)
1874
if(mesh[hasbothpoints[jj]][k] == outerpoints[i])
1875
{
1876
done = true;
1877
for(int l=0; l<4; l++)
1878
if(mesh[hasbothpoints[jj]][l] != pi1 &&
1879
mesh[hasbothpoints[jj]][l] != pi2 &&
1880
mesh[hasbothpoints[jj]][l] != outerpoints[i])
1881
outerpoints[i+1] = mesh[hasbothpoints[jj]][l];
1882
}
1883
if(done)
1884
{
1885
ElementIndex aux = hasbothpoints[i];
1886
hasbothpoints[i] = hasbothpoints[jj];
1887
hasbothpoints[jj] = aux;
1888
}
1889
}
1890
}
1891
if(outerpoints[nsuround] != sp2)
1892
{
1893
cerr << "OJE OJE OJE" << endl;
1894
(*testout) << "OJE OJE OJE" << endl;
1895
(*testout) << "hasbothpoints: " << endl;
1896
for(int ii=0; ii < hasbothpoints.Size(); ii++)
1897
{
1898
(*testout) << mesh[hasbothpoints[ii]] << endl;
1899
for(int jj=0; jj<mesh[hasbothpoints[ii]].GetNP(); jj++)
1900
if(mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] > 0)
1901
(*testout) << mesh[hasbothpoints[ii]][jj] << " between "
1902
<< mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] << " and "
1903
<< mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][1] << endl;
1904
}
1905
(*testout) << "outerpoints: " << outerpoints << endl;
1906
(*testout) << "sel1 " << mesh[sel1] << endl
1907
<< "sel2 " << mesh[sel2] << endl;
1908
for(int ii=0; ii<3; ii++)
1909
{
1910
if(mesh.mlbetweennodes[mesh[sel1][ii]][0] > 0)
1911
(*testout) << mesh[sel1][ii] << " between "
1912
<< mesh.mlbetweennodes[mesh[sel1][ii]][0] << " and "
1913
<< mesh.mlbetweennodes[mesh[sel1][ii]][1] << endl;
1914
if(mesh.mlbetweennodes[mesh[sel2][ii]][0] > 0)
1915
(*testout) << mesh[sel2][ii] << " between "
1916
<< mesh.mlbetweennodes[mesh[sel2][ii]][0] << " and "
1917
<< mesh.mlbetweennodes[mesh[sel2][ii]][1] << endl;
1918
}
1919
}
1920
1921
1922
ARRAY < int > outerpointsother;
1923
1924
if(nsuroundother > 0)
1925
{
1926
outerpointsother.SetSize(nsuroundother+1);
1927
outerpointsother[0] = sp2other;
1928
}
1929
1930
for(int i=0; i<nsuroundother; i++)
1931
{
1932
bool done = false;
1933
for(int jj=i; !done && jj<hasbothpointsother.Size(); jj++)
1934
{
1935
for(int k=0; !done && k<4; k++)
1936
if(mesh[hasbothpointsother[jj]][k] == outerpointsother[i])
1937
{
1938
done = true;
1939
for(int l=0; l<4; l++)
1940
if(mesh[hasbothpointsother[jj]][l] != pi1other &&
1941
mesh[hasbothpointsother[jj]][l] != pi2other &&
1942
mesh[hasbothpointsother[jj]][l] != outerpointsother[i])
1943
outerpointsother[i+1] = mesh[hasbothpointsother[jj]][l];
1944
}
1945
if(done)
1946
{
1947
ElementIndex aux = hasbothpointsother[i];
1948
hasbothpointsother[i] = hasbothpointsother[jj];
1949
hasbothpointsother[jj] = aux;
1950
}
1951
}
1952
}
1953
if(nsuroundother > 0 && outerpointsother[nsuroundother] != sp1other)
1954
{
1955
cerr << "OJE OJE OJE (other)" << endl;
1956
(*testout) << "OJE OJE OJE (other)" << endl;
1957
(*testout) << "pi1 " << pi1 << " pi2 " << pi2 << " sp1 " << sp1 << " sp2 " << sp2 << endl;
1958
(*testout) << "hasbothpoints: " << endl;
1959
for(int ii=0; ii < hasbothpoints.Size(); ii++)
1960
{
1961
(*testout) << mesh[hasbothpoints[ii]] << endl;
1962
for(int jj=0; jj<mesh[hasbothpoints[ii]].GetNP(); jj++)
1963
if(mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] > 0)
1964
(*testout) << mesh[hasbothpoints[ii]][jj] << " between "
1965
<< mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] << " and "
1966
<< mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][1] << endl;
1967
}
1968
(*testout) << "outerpoints: " << outerpoints << endl;
1969
(*testout) << "sel1 " << mesh[sel1] << endl
1970
<< "sel2 " << mesh[sel2] << endl;
1971
for(int ii=0; ii<3; ii++)
1972
{
1973
if(mesh.mlbetweennodes[mesh[sel1][ii]][0] > 0)
1974
(*testout) << mesh[sel1][ii] << " between "
1975
<< mesh.mlbetweennodes[mesh[sel1][ii]][0] << " and "
1976
<< mesh.mlbetweennodes[mesh[sel1][ii]][1] << endl;
1977
if(mesh.mlbetweennodes[mesh[sel2][ii]][0] > 0)
1978
(*testout) << mesh[sel2][ii] << " between "
1979
<< mesh.mlbetweennodes[mesh[sel2][ii]][0] << " and "
1980
<< mesh.mlbetweennodes[mesh[sel2][ii]][1] << endl;
1981
}
1982
1983
(*testout) << "pi1other " << pi1other << " pi2other " << pi2other << " sp1other " << sp1other << " sp2other " << sp2other << endl;
1984
(*testout) << "hasbothpointsother: " << endl;
1985
for(int ii=0; ii < hasbothpointsother.Size(); ii++)
1986
{
1987
(*testout) << mesh[hasbothpointsother[ii]] << endl;
1988
for(int jj=0; jj<mesh[hasbothpointsother[ii]].GetNP(); jj++)
1989
if(mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][0] > 0)
1990
(*testout) << mesh[hasbothpointsother[ii]][jj] << " between "
1991
<< mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][0] << " and "
1992
<< mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][1] << endl;
1993
}
1994
(*testout) << "outerpoints: " << outerpointsother << endl;
1995
(*testout) << "sel1other " << mesh[sel1other] << endl
1996
<< "sel2other " << mesh[sel2other] << endl;
1997
for(int ii=0; ii<3; ii++)
1998
{
1999
if(mesh.mlbetweennodes[mesh[sel1other][ii]][0] > 0)
2000
(*testout) << mesh[sel1other][ii] << " between "
2001
<< mesh.mlbetweennodes[mesh[sel1other][ii]][0] << " and "
2002
<< mesh.mlbetweennodes[mesh[sel1other][ii]][1] << endl;
2003
if(mesh.mlbetweennodes[mesh[sel2other][ii]][0] > 0)
2004
(*testout) << mesh[sel2other][ii] << " between "
2005
<< mesh.mlbetweennodes[mesh[sel2other][ii]][0] << " and "
2006
<< mesh.mlbetweennodes[mesh[sel2other][ii]][1] << endl;
2007
}
2008
}
2009
2010
bad1=0;
2011
for(int i=0; i<hasbothpoints.Size(); i++)
2012
bad1 += CalcBad(mesh.Points(), mesh[hasbothpoints[i]],h);
2013
for(int i=0; i<hasbothpointsother.Size(); i++)
2014
bad1 += CalcBad(mesh.Points(), mesh[hasbothpointsother[i]],h);
2015
bad1 /= double(hasbothpoints.Size() + hasbothpointsother.Size());
2016
2017
2018
int startpoints,startpointsother;
2019
2020
2021
if(outerpoints.Size() == 3)
2022
startpoints = 1;
2023
else if(outerpoints.Size() == 4)
2024
startpoints = 2;
2025
else
2026
startpoints = outerpoints.Size();
2027
2028
if(outerpointsother.Size() == 3)
2029
startpointsother = 1;
2030
else if(outerpointsother.Size() == 4)
2031
startpointsother = 2;
2032
else
2033
startpointsother = outerpointsother.Size();
2034
2035
2036
ARRAY < ARRAY < Element* > * > newelts(startpoints);
2037
ARRAY < ARRAY < Element* > * > neweltsother(startpointsother);
2038
2039
double minbad = 1e50, minbadother = 1e50, currbad;
2040
int minpos = -1, minposother = -1;
2041
2042
//(*testout) << "pi1 " << pi1 << " pi2 " << pi2 << " outerpoints " << outerpoints << endl;
2043
2044
for(int i=0; i<startpoints; i++)
2045
{
2046
newelts[i] = new ARRAY <Element*>(2*(nsuround-1));
2047
2048
for(int jj=0; jj<nsuround-1; jj++)
2049
{
2050
(*newelts[i])[2*jj] = new Element(TET);
2051
(*newelts[i])[2*jj+1] = new Element(TET);
2052
Element & newel1 = *((*newelts[i])[2*jj]);
2053
Element & newel2 = *((*newelts[i])[2*jj+1]);
2054
2055
newel1[0] = pi1;
2056
newel1[1] = outerpoints[i];
2057
newel1[2] = outerpoints[(i+jj+1)%outerpoints.Size()];
2058
newel1[3] = outerpoints[(i+jj+2)%outerpoints.Size()];
2059
2060
newel2[0] = pi2;
2061
newel2[1] = outerpoints[i];
2062
newel2[2] = outerpoints[(i+jj+2)%outerpoints.Size()];
2063
newel2[3] = outerpoints[(i+jj+1)%outerpoints.Size()];
2064
2065
2066
//(*testout) << "j " << j << " newel1 " << newel1[0] << " "<< newel1[1] << " "<< newel1[2] << " "<< newel1[3] << endl
2067
// << " newel2 " << newel2[0] << " "<< newel2[1] << " "<< newel2[2] << " "<< newel2[3] << endl;
2068
2069
newel1.SetIndex(mattype);
2070
newel2.SetIndex(mattype);
2071
2072
}
2073
2074
bool wrongorientation = true;
2075
for(int jj = 0; wrongorientation && jj<newelts[i]->Size(); jj++)
2076
wrongorientation = wrongorientation && WrongOrientation(mesh.Points(), *(*newelts[i])[jj]);
2077
2078
currbad = 0;
2079
2080
for(int jj=0; jj<newelts[i]->Size(); jj++)
2081
{
2082
if(wrongorientation)
2083
Swap((*(*newelts[i])[jj])[2],(*(*newelts[i])[jj])[3]);
2084
2085
2086
// not two new faces on same surface
2087
ARRAY<int> face_index;
2088
for(int k = 0; k<surfaceindicesonnode[(*(*newelts[i])[jj])[0]].Size(); k++)
2089
face_index.Append(surfaceindicesonnode[(*(*newelts[i])[jj])[0]][k]);
2090
2091
for(int k=1; k<4; k++)
2092
{
2093
for(int l=0; l<face_index.Size(); l++)
2094
{
2095
if(face_index[l] != -1 &&
2096
!(surfaceindicesonnode[(*(*newelts[i])[jj])[k]].Contains(face_index[l])))
2097
face_index[l] = -1;
2098
}
2099
2100
}
2101
2102
for(int k=0; k<face_index.Size(); k++)
2103
if(face_index[k] != -1)
2104
currbad += 1e12;
2105
2106
2107
currbad += CalcBad(mesh.Points(),*(*newelts[i])[jj],h);
2108
2109
2110
}
2111
2112
//currbad /= double(newelts[i]->Size());
2113
2114
2115
2116
if(currbad < minbad)
2117
{
2118
minbad = currbad;
2119
minpos = i;
2120
}
2121
2122
}
2123
2124
if(startpointsother == 0)
2125
minbadother = 0;
2126
2127
for(int i=0; i<startpointsother; i++)
2128
{
2129
neweltsother[i] = new ARRAY <Element*>(2*(nsuroundother));
2130
2131
for(int jj=0; jj<nsuroundother; jj++)
2132
{
2133
(*neweltsother[i])[2*jj] = new Element(TET);
2134
(*neweltsother[i])[2*jj+1] = new Element(TET);
2135
Element & newel1 = *((*neweltsother[i])[2*jj]);
2136
Element & newel2 = *((*neweltsother[i])[2*jj+1]);
2137
2138
newel1[0] = pi1other;
2139
newel1[1] = outerpointsother[i];
2140
newel1[2] = outerpointsother[(i+jj+1)%outerpointsother.Size()];
2141
newel1[3] = outerpointsother[(i+jj+2)%outerpointsother.Size()];
2142
2143
newel2[0] = pi2other;
2144
newel2[1] = outerpointsother[i];
2145
newel2[2] = outerpointsother[(i+jj+2)%outerpointsother.Size()];
2146
newel2[3] = outerpointsother[(i+jj+1)%outerpointsother.Size()];
2147
2148
2149
//(*testout) << "j " << j << " newel1 " << newel1[0] << " "<< newel1[1] << " "<< newel1[2] << " "<< newel1[3] << endl
2150
// << " newel2 " << newel2[0] << " "<< newel2[1] << " "<< newel2[2] << " "<< newel2[3] << endl;
2151
2152
newel1.SetIndex(othermattype);
2153
newel2.SetIndex(othermattype);
2154
2155
}
2156
2157
bool wrongorientation = true;
2158
for(int jj = 0; wrongorientation && jj<neweltsother[i]->Size(); jj++)
2159
wrongorientation = wrongorientation && WrongOrientation(mesh.Points(), *(*neweltsother[i])[jj]);
2160
2161
currbad = 0;
2162
2163
for(int jj=0; jj<neweltsother[i]->Size(); jj++)
2164
{
2165
if(wrongorientation)
2166
Swap((*(*neweltsother[i])[jj])[2],(*(*neweltsother[i])[jj])[3]);
2167
2168
currbad += CalcBad(mesh.Points(),*(*neweltsother[i])[jj],h);
2169
}
2170
2171
//currbad /= double(neweltsother[i]->Size());
2172
2173
2174
2175
if(currbad < minbadother)
2176
{
2177
minbadother = currbad;
2178
minposother = i;
2179
}
2180
2181
}
2182
2183
//(*testout) << "minbad " << minbad << " bad1 " << bad1 << endl;
2184
2185
2186
double sbadnew = CalcTriangleBadness (mesh[pi1],mesh[sp2],mesh[sp1],0,0) +
2187
CalcTriangleBadness (mesh[pi2],mesh[sp1],mesh[sp2],0,0);
2188
2189
2190
int denom = newelts[minpos]->Size();
2191
if(minposother >= 0)
2192
denom += neweltsother[minposother]->Size();
2193
2194
2195
if((minbad+minbadother)/double(denom) < bad1 &&
2196
sbadnew < sbad)
2197
{
2198
cnt++;
2199
2200
swapped = true;
2201
2202
2203
int start1 = -1;
2204
for(int l=0; l<3; l++)
2205
if(mesh[sel1][l] == pi1)
2206
start1 = l;
2207
if(mesh[sel1][(start1+1)%3] == pi2)
2208
{
2209
mesh[sel1][0] = pi1;
2210
mesh[sel1][1] = sp2;
2211
mesh[sel1][2] = sp1;
2212
mesh[sel2][0] = pi2;
2213
mesh[sel2][1] = sp1;
2214
mesh[sel2][2] = sp2;
2215
}
2216
else
2217
{
2218
mesh[sel1][0] = pi2;
2219
mesh[sel1][1] = sp2;
2220
mesh[sel1][2] = sp1;
2221
mesh[sel2][0] = pi1;
2222
mesh[sel2][1] = sp1;
2223
mesh[sel2][2] = sp2;
2224
}
2225
//(*testout) << "changed surface element " << sel1 << " to " << mesh[sel1] << ", " << sel2 << " to " << mesh[sel2] << endl;
2226
2227
for(int l=0; l<3; l++)
2228
{
2229
surfaceelementsonnode.Add(mesh[sel1][l],sel1);
2230
surfaceelementsonnode.Add(mesh[sel2][l],sel2);
2231
}
2232
2233
2234
2235
if(periodic)
2236
{
2237
start1 = -1;
2238
for(int l=0; l<3; l++)
2239
if(mesh[sel1other][l] == pi1other)
2240
start1 = l;
2241
2242
2243
2244
//(*testout) << "changed surface elements " << mesh[sel1other] << " and " << mesh[sel2other] << endl;
2245
if(mesh[sel1other][(start1+1)%3] == pi2other)
2246
{
2247
mesh[sel1other][0] = pi1other;
2248
mesh[sel1other][1] = sp2other;
2249
mesh[sel1other][2] = sp1other;
2250
mesh[sel2other][0] = pi2other;
2251
mesh[sel2other][1] = sp1other;
2252
mesh[sel2other][2] = sp2other;
2253
//(*testout) << " with rule 1" << endl;
2254
}
2255
else
2256
{
2257
mesh[sel1other][0] = pi2other;
2258
mesh[sel1other][1] = sp2other;
2259
mesh[sel1other][2] = sp1other;
2260
mesh[sel2other][0] = pi1other;
2261
mesh[sel2other][1] = sp1other;
2262
mesh[sel2other][2] = sp2other;
2263
//(*testout) << " with rule 2" << endl;
2264
}
2265
//(*testout) << " to " << mesh[sel1other] << " and " << mesh[sel2other] << endl;
2266
2267
//(*testout) << " and surface element " << sel1other << " to " << mesh[sel1other] << ", " << sel2other << " to " << mesh[sel2other] << endl;
2268
2269
for(int l=0; l<3; l++)
2270
{
2271
surfaceelementsonnode.Add(mesh[sel1other][l],sel1other);
2272
surfaceelementsonnode.Add(mesh[sel2other][l],sel2other);
2273
}
2274
}
2275
2276
2277
2278
2279
for(int i=0; i<hasbothpoints.Size(); i++)
2280
{
2281
mesh[hasbothpoints[i]] = *(*newelts[minpos])[i];
2282
2283
for(int l=0; l<4; l++)
2284
elementsonnode.Add((*(*newelts[minpos])[i])[l],hasbothpoints[i]);
2285
}
2286
2287
for(int i=hasbothpoints.Size(); i<(*newelts[minpos]).Size(); i++)
2288
{
2289
ElementIndex ni = mesh.AddVolumeElement(*(*newelts[minpos])[i]);
2290
2291
for(int l=0; l<4; l++)
2292
elementsonnode.Add((*(*newelts[minpos])[i])[l],ni);
2293
}
2294
2295
if(hasbothpointsother.Size() > 0)
2296
{
2297
for(int i=0; i<hasbothpointsother.Size(); i++)
2298
{
2299
mesh[hasbothpointsother[i]] = *(*neweltsother[minposother])[i];
2300
for(int l=0; l<4; l++)
2301
elementsonnode.Add((*(*neweltsother[minposother])[i])[l],hasbothpointsother[i]);
2302
}
2303
2304
for(int i=hasbothpointsother.Size(); i<(*neweltsother[minposother]).Size(); i++)
2305
{
2306
ElementIndex ni = mesh.AddVolumeElement(*(*neweltsother[minposother])[i]);
2307
for(int l=0; l<4; l++)
2308
elementsonnode.Add((*(*neweltsother[minposother])[i])[l],ni);
2309
}
2310
}
2311
2312
2313
2314
}
2315
2316
for(int i=0; i<newelts.Size(); i++)
2317
{
2318
for(int jj=0; jj<newelts[i]->Size(); jj++)
2319
delete (*newelts[i])[jj];
2320
delete newelts[i];
2321
}
2322
2323
for(int i=0; i<neweltsother.Size(); i++)
2324
{
2325
for(int jj=0; jj<neweltsother[i]->Size(); jj++)
2326
delete (*neweltsother[i])[jj];
2327
delete neweltsother[i];
2328
}
2329
2330
}
2331
}
2332
2333
PrintMessage (5, cnt, " swaps performed");
2334
2335
2336
for(int i=0; i<locidmaps.Size(); i++)
2337
delete locidmaps[i];
2338
2339
2340
mesh.Compress ();
2341
2342
multithread.task = savetask;
2343
}
2344
2345
2346
2347
2348
2349
2350
2351
2352
/*
2353
2 -> 3 conversion
2354
*/
2355
2356
2357
2358
void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal)
2359
{
2360
int j, k, l;
2361
ElementIndex ei, eli1, eli2, elnr;
2362
SurfaceElementIndex sei;
2363
PointIndex pi1(0), pi2(0), pi3(0), pi4(0), pi5(0);
2364
2365
int cnt = 0;
2366
2367
Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET);
2368
2369
double bad1, bad2;
2370
2371
int np = mesh.GetNP();
2372
int ne = mesh.GetNE();
2373
int nse = mesh.GetNSE();
2374
2375
if (goal == OPT_CONFORM) return;
2376
2377
// contains at least all elements at node
2378
TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np);
2379
TABLE<SurfaceElementIndex, PointIndex::BASE> belementsonnode(np);
2380
2381
PrintMessage (3, "SwapImprove2 ");
2382
(*testout) << "\n" << "Start SwapImprove2" << "\n";
2383
// TestOk();
2384
2385
2386
2387
/*
2388
CalcSurfacesOfNode ();
2389
for (i = 1; i <= GetNE(); i++)
2390
if (volelements.Get(i)[0])
2391
if (!mesh.LegalTet (volelements.Get(i)))
2392
{
2393
cout << "detected illegal tet, 1" << endl;
2394
(*testout) << "detected illegal tet1: " << i << endl;
2395
}
2396
*/
2397
2398
2399
// Calculate total badness
2400
2401
bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
2402
(*testout) << "Total badness = " << bad1 << endl;
2403
// cout << "tot bad = " << bad1 << endl;
2404
2405
// find elements on node
2406
2407
for (ei = 0; ei < ne; ei++)
2408
for (j = 0; j < mesh[ei].GetNP(); j++)
2409
elementsonnode.Add (mesh[ei][j], ei);
2410
2411
for (sei = 0; sei < nse; sei++)
2412
for (j = 0; j < 3; j++)
2413
belementsonnode.Add (mesh[sei][j], sei);
2414
2415
for (eli1 = 0; eli1 < ne; eli1++)
2416
{
2417
if (multithread.terminate)
2418
break;
2419
2420
if (mesh.ElementType (eli1) == FIXEDELEMENT)
2421
continue;
2422
2423
if (mesh[eli1].GetType() != TET)
2424
continue;
2425
2426
if ((goal == OPT_LEGAL) &&
2427
mesh.LegalTet (mesh[eli1]) &&
2428
CalcBad (mesh.Points(), mesh[eli1], 0) < 1e3)
2429
continue;
2430
2431
// cout << "eli = " << eli1 << endl;
2432
// (*testout) << "swapimp2, eli = " << eli1 << "; el = " << mesh[eli1] << endl;
2433
2434
for (j = 0; j < 4; j++)
2435
{
2436
// loop over faces
2437
2438
Element & elem = mesh[eli1];
2439
// if (elem[0] < PointIndex::BASE) continue;
2440
if (elem.IsDeleted()) continue;
2441
2442
int mattyp = elem.GetIndex();
2443
2444
switch (j)
2445
{
2446
case 0:
2447
pi1 = elem.PNum(1); pi2 = elem.PNum(2);
2448
pi3 = elem.PNum(3); pi4 = elem.PNum(4);
2449
break;
2450
case 1:
2451
pi1 = elem.PNum(1); pi2 = elem.PNum(4);
2452
pi3 = elem.PNum(2); pi4 = elem.PNum(3);
2453
break;
2454
case 2:
2455
pi1 = elem.PNum(1); pi2 = elem.PNum(3);
2456
pi3 = elem.PNum(4); pi4 = elem.PNum(2);
2457
break;
2458
case 3:
2459
pi1 = elem.PNum(2); pi2 = elem.PNum(4);
2460
pi3 = elem.PNum(3); pi4 = elem.PNum(1);
2461
break;
2462
}
2463
2464
2465
bool bface = 0;
2466
for (k = 0; k < belementsonnode[pi1].Size(); k++)
2467
{
2468
const Element2d & bel =
2469
mesh[belementsonnode[pi1][k]];
2470
2471
bool bface1 = 1;
2472
for (l = 0; l < 3; l++)
2473
if (bel[l] != pi1 && bel[l] != pi2 && bel[l] != pi3)
2474
{
2475
bface1 = 0;
2476
break;
2477
}
2478
2479
if (bface1)
2480
{
2481
bface = 1;
2482
break;
2483
}
2484
}
2485
2486
if (bface) continue;
2487
2488
2489
FlatArray<ElementIndex> row = elementsonnode[pi1];
2490
for (k = 0; k < row.Size(); k++)
2491
{
2492
eli2 = row[k];
2493
2494
// cout << "\rei1 = " << eli1 << ", pi1 = " << pi1 << ", k = " << k << ", ei2 = " << eli2
2495
// << ", getne = " << mesh.GetNE();
2496
2497
if ( eli1 != eli2 )
2498
{
2499
Element & elem2 = mesh[eli2];
2500
if (elem2.IsDeleted()) continue;
2501
if (elem2.GetType() != TET)
2502
continue;
2503
2504
int comnodes=0;
2505
for (l = 1; l <= 4; l++)
2506
if (elem2.PNum(l) == pi1 || elem2.PNum(l) == pi2 ||
2507
elem2.PNum(l) == pi3)
2508
{
2509
comnodes++;
2510
}
2511
else
2512
{
2513
pi5 = elem2.PNum(l);
2514
}
2515
2516
if (comnodes == 3)
2517
{
2518
bad1 = CalcBad (mesh.Points(), elem, 0) +
2519
CalcBad (mesh.Points(), elem2, 0);
2520
2521
if (!mesh.LegalTet(elem) ||
2522
!mesh.LegalTet(elem2))
2523
bad1 += 1e4;
2524
2525
2526
el31.PNum(1) = pi1;
2527
el31.PNum(2) = pi2;
2528
el31.PNum(3) = pi5;
2529
el31.PNum(4) = pi4;
2530
el31.SetIndex (mattyp);
2531
2532
el32.PNum(1) = pi2;
2533
el32.PNum(2) = pi3;
2534
el32.PNum(3) = pi5;
2535
el32.PNum(4) = pi4;
2536
el32.SetIndex (mattyp);
2537
2538
el33.PNum(1) = pi3;
2539
el33.PNum(2) = pi1;
2540
el33.PNum(3) = pi5;
2541
el33.PNum(4) = pi4;
2542
el33.SetIndex (mattyp);
2543
2544
bad2 = CalcBad (mesh.Points(), el31, 0) +
2545
CalcBad (mesh.Points(), el32, 0) +
2546
CalcBad (mesh.Points(), el33, 0);
2547
2548
2549
el31.flags.illegal_valid = 0;
2550
el32.flags.illegal_valid = 0;
2551
el33.flags.illegal_valid = 0;
2552
2553
if (!mesh.LegalTet(el31) ||
2554
!mesh.LegalTet(el32) ||
2555
!mesh.LegalTet(el33))
2556
bad2 += 1e4;
2557
2558
2559
bool do_swap = (bad2 < bad1);
2560
2561
if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) &&
2562
mesh.BoundaryEdge (pi4, pi5))
2563
do_swap = 1;
2564
2565
if (do_swap)
2566
{
2567
// cout << "do swap, eli1 = " << eli1 << "; eli2 = " << eli2 << endl;
2568
// (*mycout) << "2->3 " << flush;
2569
cnt++;
2570
2571
el31.flags.illegal_valid = 0;
2572
el32.flags.illegal_valid = 0;
2573
el33.flags.illegal_valid = 0;
2574
2575
mesh[eli1] = el31;
2576
mesh[eli2] = el32;
2577
2578
ElementIndex neli =
2579
mesh.AddVolumeElement (el33);
2580
2581
/*
2582
if (!LegalTet(el31) || !LegalTet(el32) ||
2583
!LegalTet(el33))
2584
{
2585
cout << "Swap to illegal tets !!!" << endl;
2586
}
2587
*/
2588
// cout << "neli = " << neli << endl;
2589
for (l = 0; l < 4; l++)
2590
{
2591
elementsonnode.Add (el31[l], eli1);
2592
elementsonnode.Add (el32[l], eli2);
2593
elementsonnode.Add (el33[l], neli);
2594
}
2595
2596
break;
2597
}
2598
}
2599
}
2600
}
2601
}
2602
}
2603
2604
2605
PrintMessage (5, cnt, " swaps performed");
2606
2607
2608
2609
/*
2610
CalcSurfacesOfNode ();
2611
for (i = 1; i <= GetNE(); i++)
2612
if (volelements.Get(i).PNum(1))
2613
if (!LegalTet (volelements.Get(i)))
2614
{
2615
cout << "detected illegal tet, 2" << endl;
2616
(*testout) << "detected illegal tet2: " << i << endl;
2617
}
2618
*/
2619
2620
2621
bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
2622
(*testout) << "Total badness = " << bad1 << endl;
2623
(*testout) << "swapimprove2 done" << "\n";
2624
// (*mycout) << "Vol = " << CalcVolume (points, volelements) << "\n";
2625
}
2626
2627
2628
/*
2629
void Mesh :: SwapImprove2 (OPTIMIZEGOAL goal)
2630
{
2631
int i, j;
2632
int eli1, eli2;
2633
int mattyp;
2634
2635
Element el31(4), el32(4), el33(4);
2636
double bad1, bad2;
2637
2638
2639
INDEX_3_HASHTABLE<INDEX_2> elsonface (GetNE());
2640
2641
(*mycout) << "SwapImprove2 " << endl;
2642
(*testout) << "\n" << "Start SwapImprove2" << "\n";
2643
2644
// Calculate total badness
2645
2646
if (goal == OPT_QUALITY)
2647
{
2648
double bad1 = CalcTotalBad (points, volelements);
2649
(*testout) << "Total badness = " << bad1 << endl;
2650
}
2651
2652
// find elements on node
2653
2654
2655
Element2d face;
2656
for (i = 1; i <= GetNE(); i++)
2657
if ( (i > eltyps.Size()) || (eltyps.Get(i) != FIXEDELEMENT) )
2658
{
2659
const Element & el = VolumeElement(i);
2660
if (!el.PNum(1)) continue;
2661
2662
for (j = 1; j <= 4; j++)
2663
{
2664
el.GetFace (j, face);
2665
INDEX_3 i3 (face.PNum(1), face.PNum(2), face.PNum(3));
2666
i3.Sort();
2667
2668
2669
int bnr, posnr;
2670
if (!elsonface.PositionCreate (i3, bnr, posnr))
2671
{
2672
INDEX_2 i2;
2673
elsonface.GetData (bnr, posnr, i3, i2);
2674
i2.I2() = i;
2675
elsonface.SetData (bnr, posnr, i3, i2);
2676
}
2677
else
2678
{
2679
INDEX_2 i2 (i, 0);
2680
elsonface.SetData (bnr, posnr, i3, i2);
2681
}
2682
2683
// if (elsonface.Used (i3))
2684
// {
2685
// INDEX_2 i2 = elsonface.Get(i3);
2686
// i2.I2() = i;
2687
// elsonface.Set (i3, i2);
2688
// }
2689
// else
2690
// {
2691
// INDEX_2 i2 (i, 0);
2692
// elsonface.Set (i3, i2);
2693
// }
2694
2695
}
2696
}
2697
2698
BitArray original(GetNE());
2699
original.Set();
2700
2701
for (i = 1; i <= GetNSE(); i++)
2702
{
2703
const Element2d & sface = SurfaceElement(i);
2704
INDEX_3 i3 (sface.PNum(1), sface.PNum(2), sface.PNum(3));
2705
i3.Sort();
2706
INDEX_2 i2(0,0);
2707
elsonface.Set (i3, i2);
2708
}
2709
2710
2711
for (i = 1; i <= elsonface.GetNBags(); i++)
2712
for (j = 1; j <= elsonface.GetBagSize(i); j++)
2713
{
2714
INDEX_3 i3;
2715
INDEX_2 i2;
2716
elsonface.GetData (i, j, i3, i2);
2717
2718
2719
int eli1 = i2.I1();
2720
int eli2 = i2.I2();
2721
2722
if (eli1 && eli2 && original.Test(eli1) && original.Test(eli2) )
2723
{
2724
Element & elem = volelements.Elem(eli1);
2725
Element & elem2 = volelements.Elem(eli2);
2726
2727
int pi1 = i3.I1();
2728
int pi2 = i3.I2();
2729
int pi3 = i3.I3();
2730
2731
int pi4 = elem.PNum(1) + elem.PNum(2) + elem.PNum(3) + elem.PNum(4) - pi1 - pi2 - pi3;
2732
int pi5 = elem2.PNum(1) + elem2.PNum(2) + elem2.PNum(3) + elem2.PNum(4) - pi1 - pi2 - pi3;
2733
2734
2735
2736
2737
2738
2739
el31.PNum(1) = pi1;
2740
el31.PNum(2) = pi2;
2741
el31.PNum(3) = pi3;
2742
el31.PNum(4) = pi4;
2743
el31.SetIndex (mattyp);
2744
2745
if (WrongOrientation (points, el31))
2746
swap (pi1, pi2);
2747
2748
2749
bad1 = CalcBad (points, elem, 0) +
2750
CalcBad (points, elem2, 0);
2751
2752
// if (!LegalTet(elem) || !LegalTet(elem2))
2753
// bad1 += 1e4;
2754
2755
2756
el31.PNum(1) = pi1;
2757
el31.PNum(2) = pi2;
2758
el31.PNum(3) = pi5;
2759
el31.PNum(4) = pi4;
2760
el31.SetIndex (mattyp);
2761
2762
el32.PNum(1) = pi2;
2763
el32.PNum(2) = pi3;
2764
el32.PNum(3) = pi5;
2765
el32.PNum(4) = pi4;
2766
el32.SetIndex (mattyp);
2767
2768
el33.PNum(1) = pi3;
2769
el33.PNum(2) = pi1;
2770
el33.PNum(3) = pi5;
2771
el33.PNum(4) = pi4;
2772
el33.SetIndex (mattyp);
2773
2774
bad2 = CalcBad (points, el31, 0) +
2775
CalcBad (points, el32, 0) +
2776
CalcBad (points, el33, 0);
2777
2778
// if (!LegalTet(el31) || !LegalTet(el32) ||
2779
// !LegalTet(el33))
2780
// bad2 += 1e4;
2781
2782
2783
int swap = (bad2 < bad1);
2784
2785
INDEX_2 hi2b(pi4, pi5);
2786
hi2b.Sort();
2787
2788
if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) &&
2789
boundaryedges->Used (hi2b) )
2790
swap = 1;
2791
2792
if (swap)
2793
{
2794
(*mycout) << "2->3 " << flush;
2795
2796
volelements.Elem(eli1) = el31;
2797
volelements.Elem(eli2) = el32;
2798
volelements.Append (el33);
2799
2800
original.Clear (eli1);
2801
original.Clear (eli2);
2802
}
2803
}
2804
}
2805
2806
(*mycout) << endl;
2807
2808
if (goal == OPT_QUALITY)
2809
{
2810
bad1 = CalcTotalBad (points, volelements);
2811
(*testout) << "Total badness = " << bad1 << endl;
2812
}
2813
2814
// FindOpenElements ();
2815
2816
(*testout) << "swapimprove2 done" << "\n";
2817
}
2818
2819
*/
2820
}
2821
2822