Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/Application/src/sifgenerator.cpp
3203 views
1
/*****************************************************************************
2
* *
3
* Elmer, A Finite Element Software for Multiphysical Problems *
4
* *
5
* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *
6
* *
7
* This program is free software; you can redistribute it and/or *
8
* modify it under the terms of the GNU General Public License *
9
* as published by the Free Software Foundation; either version 2 *
10
* of the License, or (at your option) any later version. *
11
* *
12
* This program is distributed in the hope that it will be useful, *
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15
* GNU General Public License for more details. *
16
* *
17
* You should have received a copy of the GNU General Public License *
18
* along with this program (in file fem/GPL-2); if not, write to the *
19
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
20
* Boston, MA 02110-1301, USA. *
21
* *
22
*****************************************************************************/
23
24
/*****************************************************************************
25
* *
26
* ElmerGUI sifgenerator *
27
* *
28
*****************************************************************************
29
* *
30
* Authors: Mikko Lyly, Juha Ruokolainen and Peter R�back *
31
* Email: [email protected] *
32
* Web: http://www.csc.fi/elmer *
33
* Address: CSC - IT Center for Science Ltd. *
34
* Keilaranta 14 *
35
* 02101 Espoo, Finland *
36
* *
37
* Original Date: 15 Mar 2008 *
38
* *
39
*****************************************************************************/
40
41
#include "sifgenerator.h"
42
#include <iostream>
43
#include <QDebug>
44
#if WITH_QT6
45
#include <QJSEngine>
46
#else
47
#include <QScriptEngine>
48
#endif
49
50
using namespace std;
51
52
SifGenerator::SifGenerator()
53
{
54
}
55
56
SifGenerator::~SifGenerator()
57
{
58
}
59
60
void SifGenerator::setMesh(mesh_t* m)
61
{
62
this->mesh = m;
63
}
64
65
void SifGenerator::setTextEdit(QTextEdit* textEdit)
66
{
67
this->te = textEdit;
68
}
69
70
void SifGenerator::setDim(int n)
71
{
72
this->dim = n;
73
}
74
75
void SifGenerator::setCdim(int n)
76
{
77
this->cdim = n;
78
}
79
80
void SifGenerator::setElmerDefs(QDomDocument* d)
81
{
82
this->elmerDefs = d;
83
}
84
85
void SifGenerator::setGeneralSetup(GeneralSetup* g)
86
{
87
this->generalSetup = g;
88
}
89
90
void SifGenerator::setEquationEditor(const QVector<DynamicEditor*>& d)
91
{
92
this->equationEditor = d;
93
}
94
95
void SifGenerator::setMaterialEditor(const QVector<DynamicEditor*>& d)
96
{
97
this->materialEditor = d;
98
}
99
100
void SifGenerator::setBodyForceEditor(const QVector<DynamicEditor*>& d)
101
{
102
this->bodyForceEditor = d;
103
}
104
105
void SifGenerator::setInitialConditionEditor(const QVector<DynamicEditor*>& d)
106
{
107
this->initialConditionEditor = d;
108
}
109
110
void SifGenerator::setBoundaryConditionEditor(const QVector<DynamicEditor*>& d)
111
{
112
this->boundaryConditionEditor = d;
113
}
114
115
void SifGenerator::setSolverParameterEditor(const QVector<SolverParameterEditor*>& s)
116
{
117
this->solverParameterEditor = s;
118
}
119
120
void SifGenerator::setBoundaryPropertyEditor(const QVector<BoundaryPropertyEditor*>& b)
121
{
122
this->boundaryPropertyEditor = b;
123
}
124
125
void SifGenerator::setBodyPropertyEditor(const QVector<BodyPropertyEditor*>& b)
126
{
127
this->bodyPropertyEditor = b;
128
}
129
130
void SifGenerator::setMeshControl(MeshControl* m)
131
{
132
this->meshControl = m;
133
}
134
135
void SifGenerator::setLimit(Limit* l)
136
{
137
this->limit = l;
138
}
139
140
// Make Header-block:
141
//-----------------------------------------------------------------------------
142
void SifGenerator::makeHeaderBlock()
143
{
144
Ui::setupDialog ui = generalSetup->ui;
145
146
te->append("Header");
147
148
if(ui.checkKeywordsWarn->isChecked())
149
te->append(" CHECK KEYWORDS Warn");
150
151
QString qs1 = ui.meshDBEdit1->text().trimmed();
152
QString qs2 = ui.meshDBEdit2->text().trimmed();
153
QString qs3 = ui.includePathEdit->text().trimmed();
154
QString qs4 = ui.resultsDirectoryEdit->text().trimmed();
155
QString qs5 = ui.headerFreeTextEdit->toPlainText();
156
157
te->append(" Mesh DB \"" + qs1 + "\" \"" + qs2 + "\"");
158
te->append(" Include Path \"" + qs3 + "\"");
159
te->append(" Results Directory \"" + qs4 + "\"");
160
161
if(!qs5.isEmpty())
162
te->append(qs5);
163
164
te->append("End\n");
165
}
166
167
// Make Simulation-block:
168
//-----------------------------------------------------------------------------
169
void SifGenerator::makeSimulationBlock()
170
{
171
Ui::setupDialog ui = generalSetup->ui;
172
173
te->append("Simulation");
174
175
addSifLine(" Max Output Level = ",
176
ui.maxOutputLevelCombo->currentText().trimmed());
177
addSifLine(" Coordinate System = ",
178
ui.coordinateSystemCombo->currentText().trimmed());
179
addSifLine(" Coordinate Mapping(3) = ",
180
ui.coordinateMappingEdit->text().trimmed());
181
addSifLine(" Simulation Type = ",
182
ui.simulationTypeCombo->currentText().trimmed());
183
addSifLine(" Steady State Max Iterations = ",
184
ui.steadyStateMaxIterEdit->text().trimmed());
185
//Modify Output intervals size according to the number of values entered
186
QString qs = ui.outputIntervalsEdit->text().simplified();
187
addSifLine(" Output Intervals(" + QString::number(qs.count(' ') + 1) + ") = ", qs);
188
189
if( ui.simulationTypeCombo->currentText().trimmed() != "Steady state") {
190
//Modify Timestep intervals size according to the number of values entered
191
qs = ui.timeStepIntervalsEdit->text().simplified();
192
addSifLine(" Timestep intervals(" + QString::number(qs.count(' ') + 1) + ") = ", qs);
193
if( ui.simulationTypeCombo->currentText().trimmed() == "Transient") {
194
//Modify Timestep Sizes size according to the number of values entered
195
qs = ui.timestepSizesEdit->text().simplified();
196
addSifLine(" Timestep Sizes(" + QString::number(qs.count(' ') + 1) + ") = ", qs);
197
addSifLine(" Timestepping Method = ",
198
ui.timesteppingMethodCombo->currentText().trimmed());
199
addSifLine(" BDF Order = ",
200
ui.bdfOrderCombo->currentText().trimmed());
201
}
202
}
203
204
addSifLine(" Coordinate Scaling = ",
205
ui.coordinateScalingEdit->text().trimmed());
206
addSifLine(" Angular Frequency = ",
207
ui.angularFrequencyEdit->text().trimmed());
208
209
addSifLine(" Solver Input File = ",
210
ui.solverInputFileEdit->text().trimmed());
211
addSifLine(" Post File = ",
212
ui.postFileEdit->text().trimmed());
213
214
if(ui.calculateMeshPiecesCheck->isChecked())
215
te->append(" Calculate Mesh Pieces = True");
216
addSifLine(" Desired Mesh Pieces = ",
217
ui.desiredMeshPiecesEdit->text().trimmed());
218
219
qs = ui.simulationFreeTextEdit->toPlainText();
220
221
if(!qs.isEmpty())
222
te->append(qs);
223
224
te->append("End\n");
225
}
226
227
// Make Constants-block:
228
//-----------------------------------------------------------------------------
229
void SifGenerator::makeConstantsBlock()
230
{
231
Ui::setupDialog ui = generalSetup->ui;
232
233
te->append("Constants");
234
235
addSifLine(" Gravity(4) = ",
236
ui.gravityEdit->text().trimmed());
237
addSifLine(" Stefan Boltzmann = ",
238
ui.stefanBoltzmannEdit->text().trimmed());
239
addSifLine(" Permittivity of Vacuum = ",
240
ui.vacuumPermittivityEdit->text().trimmed());
241
addSifLine(" Permeability of Vacuum = ",
242
ui.vacuumPermeabilityEdit->text().trimmed());
243
addSifLine(" Boltzmann Constant = ",
244
ui.boltzmannEdit->text().trimmed());
245
addSifLine(" Unit Charge = ",
246
ui.unitChargeEdit->text().trimmed());
247
248
QString qs = ui.constantsFreeTextEdit->toPlainText();
249
250
if(!qs.isEmpty())
251
te->append(qs);
252
253
te->append("End\n");
254
}
255
256
257
// Make Body-blocks:
258
//-----------------------------------------------------------------------------
259
void SifGenerator::makeBodyBlocks()
260
{
261
int i;
262
263
int sifIndex = 0, maxOriginalIndex=-1;
264
265
for(int index = 0; index < bodyMap.count(); index++) {
266
267
if(index >= bodyPropertyEditor.size()) {
268
cout << "SifGenerator: Body index out of bounds" << endl;
269
continue;
270
}
271
272
BodyPropertyEditor *bodyEdit = bodyPropertyEditor[index];
273
274
if(!bodyEdit)
275
continue;
276
277
int originalIndex = bodyMap.key(index);
278
maxOriginalIndex = max(maxOriginalIndex, originalIndex );
279
280
if(bodyEdit->touched) {
281
te->append("Body " + QString::number(++sifIndex));
282
283
te->append(" Target Bodies(1) = " + QString::number(originalIndex));
284
285
if ( bodyEdit->ui.nameEdit->text().trimmed() == "" )
286
te->append(" Name = \"Body " + QString::number(sifIndex) + "\"");
287
else
288
te->append(" Name = \"" + bodyEdit->ui.nameEdit->text().trimmed() + "\"");
289
290
i = bodyEdit->ui.equationCombo->currentIndex();
291
if(i > 0)
292
te->append(" Equation = " + QString::number(i));
293
294
i = bodyEdit->ui.materialCombo->currentIndex();
295
if(i > 0)
296
te->append(" Material = " + QString::number(i));
297
298
i = bodyEdit->ui.bodyForceCombo->currentIndex();
299
if(i > 0)
300
te->append(" Body Force = " + QString::number(i));
301
302
i = bodyEdit->ui.initialConditionCombo->currentIndex();
303
if(i > 0)
304
te->append(" Initial condition = " + QString::number(i));
305
306
te->append("End\n");
307
}
308
}
309
310
for( int index = 0; index < boundaryPropertyEditor.size(); index++ )
311
{
312
if(!boundaryPropertyEditor[index])
313
continue;
314
315
BodyPropertyEditor *bodyEdit = boundaryPropertyEditor[index]->bodyProperties;
316
317
if(!bodyEdit)
318
continue;
319
320
if(bodyEdit && bodyEdit->touched ) {
321
te->append("Body " + QString::number(++sifIndex));
322
323
boundaryPropertyEditor[index]->bodyID = ++maxOriginalIndex;
324
325
te->append(" Target Bodies(1) = " + QString::number(maxOriginalIndex));
326
327
if ( bodyEdit->ui.nameEdit->text().trimmed() == "" )
328
te->append(" Name = \"Body " + QString::number(sifIndex) + "\"");
329
else
330
te->append(" Name = \"" + bodyEdit->ui.nameEdit->text().trimmed() + "\"");
331
332
i = bodyEdit->ui.equationCombo->currentIndex();
333
if(i > 0)
334
te->append(" Equation = " + QString::number(i));
335
336
i = bodyEdit->ui.materialCombo->currentIndex();
337
if(i > 0)
338
te->append(" Material = " + QString::number(i));
339
340
i = bodyEdit->ui.bodyForceCombo->currentIndex();
341
if(i > 0)
342
te->append(" Body Force = " + QString::number(i));
343
344
i = bodyEdit->ui.initialConditionCombo->currentIndex();
345
if(i > 0)
346
te->append(" Initial condition = " + QString::number(i));
347
348
te->append("End\n");
349
}
350
}
351
}
352
353
354
int SifGenerator::findHashValue(DynamicEditor *de, const QString &sname, const QString &name)
355
{
356
for(int i = 0; i < de->hash.count(); i++) {
357
hash_entry_t entry = de->hash.values().at(i);
358
359
QWidget *widget = entry.widget;
360
if (widget->isEnabled()) {
361
QString key = de->hash.keys().at(i);
362
QStringList keySplitted = key.split("/");
363
QString solverName = keySplitted.at(1).trimmed();
364
QString labelName = keySplitted.at(3).trimmed();
365
366
QDomElement elem = entry.elem;
367
if ( solverName==sname && labelName==name &&
368
elem.attribute("Widget","")=="Edit" ) {
369
QLineEdit *line = static_cast<QLineEdit*>(widget);
370
QString str = line->text().trimmed();
371
if ( str.isEmpty() ) return 0;
372
return str.toInt();
373
}
374
}
375
}
376
return 0;
377
}
378
379
// Make Equation/Solver -blocks:
380
//-----------------------------------------------------------------------------
381
void SifGenerator::makeEquationBlocks()
382
{
383
// Enumerate solvers && write solver blocks:
384
//-------------------------------------------
385
QMap<QString, int> numberForSolver;
386
numberForSolver.clear();
387
388
int solverNumber = 0;
389
390
for(int index = 0; index < equationEditor.size(); index++) {
391
DynamicEditor *eqEditor = equationEditor[index];
392
393
if(eqEditor->menuAction != NULL) {
394
for(int i = 0; i < eqEditor->hash.count(); i++) {
395
hash_entry_t entry = eqEditor->hash.values().at(i);
396
397
QWidget *widget = entry.widget;
398
if (widget->isEnabled()) {
399
QDomElement elem = entry.elem;
400
401
QString key = eqEditor->hash.keys().at(i);
402
QStringList keySplitted = key.split("/");
403
QString labelName = keySplitted.at(3).trimmed();
404
QString solverName = keySplitted.at(1).trimmed();
405
406
if(labelName=="Active" && elem.attribute("Widget", "")=="CheckBox") {
407
QCheckBox *checkBox = static_cast<QCheckBox*>(widget);
408
if(checkBox->isChecked()) {
409
if(!numberForSolver.contains(solverName)) {
410
int pri = findHashValue( eqEditor, solverName, "Priority");
411
numberForSolver.insert(solverName, pri);
412
}
413
}
414
}
415
}
416
}
417
}
418
}
419
420
// Sort and enumerate solvers according to their priority:
421
//---------------------------------------------------------
422
#if WITH_QT6
423
vector<QPair<int, QString> > tmpList;
424
425
foreach(const QString &key, numberForSolver.keys()) {
426
int value = numberForSolver.value(key);
427
tmpList.push_back(qMakePair(value, key));
428
}
429
430
sort(tmpList.begin(), tmpList.end());
431
#else
432
QList<QPair<int, QString> > tmpList;
433
434
foreach(const QString &key, numberForSolver.keys()) {
435
int value = numberForSolver.value(key);
436
tmpList << qMakePair(value, key);
437
}
438
439
qSort(tmpList);
440
#endif
441
442
numberForSolver.clear();
443
444
#if WITH_QT6
445
int n = tmpList.size();
446
#else
447
int n = tmpList.count();
448
#endif
449
450
for(int i = 0; i < n; i++) {
451
const QPair<int, QString> &pair = tmpList[i];
452
const QString &key = pair.second;
453
numberForSolver.insert(key, n-i);
454
}
455
456
// Generate solver blocks:
457
//-------------------------
458
QMap<int, int> handled;
459
460
for(int index = 0; index < equationEditor.size(); index++) {
461
DynamicEditor *eqEditor = equationEditor[index];
462
if(eqEditor->menuAction != NULL) {
463
for(int i = 0; i < eqEditor->hash.count(); i++) {
464
hash_entry_t entry = eqEditor->hash.values().at(i);
465
466
QWidget *widget = entry.widget;
467
if (widget->isEnabled()) {
468
QString key = eqEditor->hash.keys().at(i);
469
QStringList keySplitted = key.split("/");
470
QString solverName = keySplitted.at(1).trimmed();
471
QString labelName = keySplitted.at(3).trimmed();
472
QDomElement elem = entry.elem;
473
474
if(labelName=="Active" && elem.attribute("Widget", "")=="CheckBox") {
475
QCheckBox *checkBox = static_cast<QCheckBox*>(widget);
476
if(checkBox->isChecked()) {
477
solverNumber = numberForSolver.value(solverName);
478
if((solverNumber>0) && (handled[solverNumber]==0)) {
479
handled[solverNumber] = 1;
480
te->append("Solver " + QString::number(solverNumber));
481
te->append(" Equation = " + solverName);
482
makeSolverBlocks(solverName);
483
te->append("End");
484
te->append("");
485
}
486
}
487
}
488
}
489
}
490
}
491
}
492
493
// Generate equation blocks:
494
//---------------------------
495
QMap<int, bool> solverActive;
496
497
int sifIndex = 0;
498
for(int index = 0; index < equationEditor.size(); index++) {
499
DynamicEditor *eqEditor = equationEditor[index];
500
501
if(eqEditor->menuAction != NULL) {
502
te->append("Equation " + QString::number(++sifIndex));
503
504
QString name = eqEditor->nameEdit->text().trimmed();
505
te->append(" Name = \"" + name + "\"");
506
507
QString solverString = "";
508
int nofSolvers = 0;
509
510
for( int i=0; i < solverParameterEditor.size(); i++ )
511
solverActive[i] = false;
512
513
for(int i = 0; i < eqEditor->hash.count(); i++) {
514
hash_entry_t entry = eqEditor->hash.values().at(i);
515
QWidget *widget = entry.widget;
516
517
if(widget->isEnabled()) {
518
QDomElement elem = entry.elem;
519
QString key = eqEditor->hash.keys().at(i);
520
QStringList keySplitted = key.split("/");
521
QString solverName = keySplitted.at(1).trimmed();
522
QString labelName = keySplitted.at(3).trimmed();
523
524
// solver active?
525
if((labelName == "Active") && (elem.attribute("Widget", "") == "CheckBox")) {
526
QCheckBox *checkBox = static_cast<QCheckBox*>(widget);
527
if(checkBox->isChecked()) {
528
nofSolvers++;
529
solverNumber = numberForSolver.value(solverName);
530
solverActive[solverNumber] = true;
531
solverString += " " + QString::number(solverNumber);
532
}
533
}
534
}
535
}
536
537
for(int i = 0; i < eqEditor->hash.count(); i++) {
538
hash_entry_t entry = eqEditor->hash.values().at(i);
539
QWidget *widget = entry.widget;
540
541
if(widget->isEnabled()) {
542
QDomElement elem = entry.elem;
543
QString key = eqEditor->hash.keys().at(i);
544
QStringList keySplitted = key.split("/");
545
QString solverName = keySplitted.at(1).trimmed();
546
QString labelName = keySplitted.at(3).trimmed();
547
548
solverNumber = numberForSolver.value(solverName);
549
if ( !solverActive[solverNumber] ) continue;
550
551
if((elem.attribute("Widget", "") == "CheckBox") &&
552
(labelName != "Active"))
553
handleCheckBox(elem, widget);
554
555
if(elem.attribute("Widget", "") == "Edit" &&
556
labelName != "Priority")
557
handleLineEdit(elem, widget);
558
559
if(elem.attribute("Widget", "") == "Combo")
560
handleComboBox(elem, widget);
561
562
if(elem.attribute("Widget", "") == "TextEdit")
563
handleTextEdit(elem, widget);
564
}
565
}
566
567
if(nofSolvers > 0)
568
te->append(" Active Solvers("
569
+ QString::number(nofSolvers)
570
+ ") =" + solverString);
571
572
te->append("End\n");
573
}
574
}
575
}
576
577
//-------------------------------------------------------------------------
578
void SifGenerator::makeSolverBlocks(const QString &solverName)
579
{
580
SolverParameterEditor *spe, *tmp;
581
Ui::solverParameterEditor ui;
582
583
bool found = false;
584
int current=-1;
585
586
for(int i = 0; i < solverParameterEditor.size(); i++) {
587
spe = solverParameterEditor[i];
588
589
if(!spe)
590
continue;
591
592
QString currentName = spe->solverName.trimmed();
593
if(currentName == solverName) {
594
found = true;
595
current = i;
596
break;
597
}
598
}
599
600
if(!found) {
601
tmp = new SolverParameterEditor;
602
} else {
603
tmp = spe;
604
}
605
606
if ( !tmp->generalOptions ) {
607
tmp->generalOptions = new DynamicEditor;
608
tmp->generalOptions->setupTabs(elmerDefs, "Solver", current );
609
}
610
611
bool hasMatrix = parseSolverSpecificTab(tmp->generalOptions, solverName);
612
613
ui = tmp->ui;
614
615
// Parse the exec solver also for non-PDE solvers
616
parseExecSolverTab(ui);
617
618
if(hasMatrix) {
619
parseNumericalTechniquesTab(ui);
620
parseSteadyStateTab(ui);
621
parseNonlinearSystemTab(ui);
622
parseLinearSystemTab(ui);
623
parseParallelTab(ui);
624
// todo: add adaptivity & multigrid
625
}
626
627
if(!found)
628
{
629
delete tmp->generalOptions;
630
delete tmp;
631
}
632
}
633
634
// Make Material-blocks:
635
//-----------------------------------------------------------------------------
636
void SifGenerator::makeMaterialBlocks()
637
{
638
int sifIndex = 0;
639
640
for(int index = 0; index < materialEditor.size(); index++) {
641
DynamicEditor *matEditor = materialEditor[index];
642
643
if(matEditor->menuAction != NULL) {
644
te->append("Material " + QString::number(++sifIndex));
645
646
QString name = matEditor->nameEdit->text().trimmed();
647
te->append(" Name = \"" + name + "\"");
648
649
for(int i = 0; i < matEditor->hash.count(); i++) {
650
hash_entry_t entry = matEditor->hash.values().at(i);
651
652
QWidget *widget = entry.widget;
653
654
QDomElement elem;
655
656
if ( widget->isEnabled() ) {
657
elem = entry.elem;
658
659
if(elem.attribute("Widget", "") == "CheckBox")
660
handleCheckBox(elem, widget);
661
662
if(elem.attribute("Widget", "") == "Edit")
663
handleLineEdit(elem, widget);
664
665
if(elem.attribute("Widget", "") == "Combo")
666
handleComboBox(elem, widget);
667
668
if(elem.attribute("Widget", "") == "TextEdit")
669
handleTextEdit(elem, widget);
670
}
671
}
672
te->append("End\n");
673
}
674
}
675
}
676
677
678
// Make body force blocks:
679
//-----------------------------------------------------------------------------
680
void SifGenerator::makeBodyForceBlocks()
681
{
682
int sifIndex = 0;
683
684
for(int index = 0; index < bodyForceEditor.size(); index++) {
685
DynamicEditor *bfEdit = bodyForceEditor[index];
686
687
if(bfEdit->menuAction != NULL) {
688
te->append("Body Force " + QString::number(++sifIndex));
689
690
QString name = bfEdit->nameEdit->text().trimmed();
691
te->append(" Name = \"" + name + "\"");
692
693
for(int i = 0; i < bfEdit->hash.count(); i++) {
694
hash_entry_t entry = bfEdit->hash.values().at(i);
695
696
QWidget *widget = entry.widget;
697
698
if ( widget->isEnabled() ) {
699
QDomElement elem = entry.elem;
700
701
if(elem.attribute("Widget", "") == "CheckBox")
702
handleCheckBox(elem, widget);
703
704
if(elem.attribute("Widget", "") == "Edit")
705
handleLineEdit(elem, widget);
706
707
if(elem.attribute("Widget", "") == "Combo")
708
handleComboBox(elem, widget);
709
710
if(elem.attribute("Widget", "") == "TextEdit")
711
handleTextEdit(elem, widget);
712
}
713
}
714
te->append("End\n");
715
}
716
}
717
}
718
719
720
// Make initial condition blocks:
721
//-----------------------------------------------------------------------------
722
void SifGenerator::makeInitialConditionBlocks()
723
{
724
int sifIndex = 0;
725
726
for(int index = 0; index < initialConditionEditor.size(); index++) {
727
DynamicEditor *icEdit = initialConditionEditor[index];
728
729
if(icEdit->menuAction != NULL) {
730
te->append("Initial Condition " + QString::number(++sifIndex));
731
732
QString name = icEdit->nameEdit->text().trimmed();
733
te->append(" Name = \"" + name + "\"");
734
735
for(int i = 0; i < icEdit->hash.count(); i++) {
736
hash_entry_t entry = icEdit->hash.values().at(i);
737
738
QWidget *widget = entry.widget;
739
740
if ( widget->isEnabled() ) {
741
QDomElement elem = entry.elem;
742
743
if(elem.attribute("Widget", "") == "CheckBox")
744
handleCheckBox(elem, widget);
745
746
if(elem.attribute("Widget", "") == "Edit")
747
handleLineEdit(elem, widget);
748
749
if(elem.attribute("Widget", "") == "Combo")
750
handleComboBox(elem, widget);
751
752
if(elem.attribute("Widget", "") == "TextEdit")
753
handleTextEdit(elem, widget);
754
}
755
}
756
te->append("End\n");
757
}
758
}
759
}
760
761
762
763
// Make boundary blocks:
764
//-----------------------------------------------------------------------------
765
void SifGenerator::makeBoundaryBlocks()
766
{
767
int sifIndex = 0;
768
int bcnum = 0;
769
int diff = 0;
770
QMap<int, int> boundaryBC;
771
#if WITH_QT6
772
QMultiMap<QString, int> boundaryList; /*(Boundary condition, edge) value pairs */
773
#else
774
QMap<QString, int> boundaryList; /*(Boundary condition, edge) value pairs */
775
#endif
776
QList<QString> boundaryConditions; /* List of different boundary conditions */
777
QList<int> boundaryEdges; /* List of edges relating to some specific boundary condition */
778
QString tmp;
779
780
boundaryBC.clear();
781
boundaryList.clear();
782
boundaryConditions.clear();
783
boundaryEdges.clear();
784
tmp.clear();
785
786
//Find the available boundary conditions
787
for (int index = 0; index < boundaryConditionEditor.count(); index++) {
788
DynamicEditor *bc = boundaryConditionEditor[index];
789
boundaryConditions.append(bc->nameEdit->text().trimmed());
790
}
791
792
//Find the boundary conditions and edges related to them.
793
for (int index = 0; index < boundaryConditions.count(); index++) {
794
for(int k = 0; k < boundaryMap.count(); k++) {
795
BoundaryPropertyEditor *bEdit = boundaryPropertyEditor[k];
796
if(bEdit->touched) {
797
boundaryBC[index] = ++sifIndex;
798
int originalIndex = boundaryMap.key(k);
799
const QString bcname = bEdit->ui.boundaryConditionCombo->currentText().trimmed();
800
if (boundaryConditions.value(index) == bcname)
801
#if WITH_QT6
802
boundaryList.insert(bcname, originalIndex);
803
#else
804
boundaryList.insertMulti(bcname, originalIndex);
805
#endif
806
}
807
}
808
}
809
//qDebug() << "boundaryMap: " << boundaryMap;
810
//qDebug() << "boundaryList: " << boundaryList;
811
qDebug() << "boundaryConditions: " << boundaryConditions;
812
813
//Arrange and sort boundary conditions
814
for(int index = 0; index < boundaryConditions.count(); index++) {
815
tmp.clear();
816
boundaryEdges.clear();
817
const QString name = boundaryConditions[index];
818
BoundaryPropertyEditor *bEdit = boundaryPropertyEditor[index];
819
DynamicEditor *bc = boundaryConditionEditor[index];
820
821
if(boundaryList.contains(name)) {
822
bcnum++;
823
te->append("Boundary Condition " + QString::number(bcnum));
824
if(boundaryConditions.count() > 1) {
825
#if WITH_QT6
826
QMultiMap <QString,int>::ConstIterator l = boundaryList.find(boundaryConditions[index]);
827
#else
828
QMap <QString,int>::ConstIterator l = boundaryList.find(boundaryConditions[index]);
829
#endif
830
while (l != boundaryList.end() && l.key()==boundaryConditions[index]){
831
boundaryEdges.append(l.value());
832
l++;
833
}
834
while ((l--) != boundaryList.begin() && l.key()==boundaryConditions[index]){
835
tmp.append(QString::number(l.value()));
836
tmp.append(" ");
837
}
838
}
839
if(boundaryConditions.count() <= 1) {
840
#if WITH_QT6
841
QMultiMap <QString,int>::ConstIterator l = boundaryList.begin();
842
#else
843
QMap <QString,int>::ConstIterator l = boundaryList.begin();
844
#endif
845
while (l != boundaryList.end()) {
846
boundaryEdges.append(l.value());
847
l++;
848
}
849
while ((l--) != boundaryList.begin()){
850
tmp.append(QString::number(l.value()));
851
tmp.append(" ");
852
}
853
}
854
855
te->append(" Target Boundaries("
856
+ QString::number(boundaryEdges.count())
857
+ ") = " + tmp);
858
859
if ( bEdit->bodyProperties ) {
860
te->append(" Body id = " + QString::number(bEdit->bodyID) );
861
}
862
863
te->append(" Name = \"" + name + "\"");
864
865
// check which one of the dynamic editors has "name" typed in nameEdit:
866
for(int j = 0; j < boundaryConditionEditor.size(); j++) {
867
DynamicEditor *bc = boundaryConditionEditor[j];
868
if(bc->menuAction != NULL) {
869
if(bc->nameEdit->text().trimmed() == name && !name.isNull()) {
870
871
// go through the hash of this dynamic editor:
872
//--------------------------------------------
873
for(int i = 0; i < bc->hash.count(); i++) {
874
hash_entry_t entry = bc->hash.values().at(i);
875
876
QWidget *widget = entry.widget;
877
878
QDomElement elem;
879
if ( widget->isEnabled() ) {
880
elem = entry.elem;
881
882
if(elem.attribute("Widget", "") == "CheckBox")
883
handleCheckBox(elem, widget);
884
885
if(elem.attribute("Widget", "") == "Edit")
886
handleBCLineEdit(elem, widget, boundaryBC);
887
888
if(elem.attribute("Widget", "") == "Combo")
889
handleComboBox(elem, widget);
890
891
if(elem.attribute("Widget", "") == "TextEdit")
892
handleTextEdit(elem, widget);
893
}
894
}
895
}
896
}
897
}
898
te->append("End\n");
899
}
900
}
901
}
902
903
// Parse "Solver specific tab"
904
//-----------------------------------------------------------------------------
905
bool SifGenerator::parseSolverSpecificTab(DynamicEditor *solEditor, const QString &solverName)
906
{
907
// Returns true if there is a matrix involved. otherwise returns false.
908
if ( !solEditor ) return false;
909
910
bool hasMatrix = true;
911
912
#if WITH_QT6
913
QJSEngine engine;
914
915
QJSValue dim_QSV = QJSValue(dim);
916
engine.globalObject().setProperty( "dim", dim_QSV );
917
918
QJSValue cdim_QSV = QJSValue(cdim);
919
engine.globalObject().setProperty( "cdim", cdim_QSV );
920
#else
921
QScriptEngine engine;
922
923
QScriptValue dim_QSV = QScriptValue(&engine,dim);
924
engine.globalObject().setProperty( "dim", dim_QSV );
925
926
QScriptValue cdim_QSV = QScriptValue(&engine,cdim);
927
engine.globalObject().setProperty( "cdim", cdim_QSV );
928
#endif
929
930
for(int i = 0; i < solEditor->hash.count(); i++) {
931
hash_entry_t entry = solEditor->hash.values().at(i);
932
933
QString key = solEditor->hash.keys().at(i);
934
QStringList keySplitted = key.split("/");
935
QString tabName = keySplitted.at(1).trimmed();
936
QString labelName = keySplitted.at(3).trimmed();
937
938
if ( tabName != solverName ) continue;
939
940
// Has matrix?
941
if(labelName == "No Matrix Equation") {
942
if(entry.elem.attribute("Widget", "") == "CheckBox") {
943
QCheckBox *cb = static_cast<QCheckBox*>(entry.widget);
944
hasMatrix = !cb->isChecked();
945
}
946
}
947
948
// variable names handled separately...
949
// ------------------------------------
950
if ( labelName=="Variable" || labelName.mid(0,17)=="Exported Variable" ) {
951
if( entry.elem.attribute("Widget", "") != "Edit") continue;
952
953
QLineEdit *l = static_cast<QLineEdit*>(entry.widget);
954
QString varName = l->text().simplified();
955
956
if ( varName == "" ) continue;
957
958
int dofs=1;
959
QStringList dofsplit = varName.split("[");
960
if ( dofsplit.count()>1 ) {
961
varName = dofsplit.at(0).trimmed() + "[";
962
QString dof = dofsplit.at(1).trimmed();
963
dof = dof.split("]").at(0).trimmed();
964
965
dofsplit = dof.split(":");
966
QString subVarName = dofsplit.at(0).trimmed();
967
for( int i=1; i<dofsplit.count(); i++)
968
{
969
dof = dofsplit.at(i).trimmed();
970
971
QStringList subDofSplit = dof.split(" ");
972
QString subDof = subDofSplit.at(0).trimmed();
973
974
#if WITH_QT6
975
dofs = engine.evaluate(subDof).toInt();
976
#else
977
dofs = engine.evaluate(subDof).toInt32();
978
#endif
979
if (i>1) varName = varName + " ";
980
varName = varName + subVarName + ":" + QString::number(dofs);
981
982
if ( subDofSplit.count() > 1 ) {
983
subVarName = subDofSplit.at(1).trimmed();
984
if ( subDofSplit.count() > 2 ) {
985
subVarName = subVarName + " " + subDofSplit.at(2);
986
}
987
}
988
}
989
varName = varName + "]";
990
addSifLine( " " + labelName + " = ", varName );
991
} else {
992
dofsplit = varName.split("(");
993
if ( dofsplit.count()>1 ) {
994
varName = dofsplit.at(0).trimmed();
995
QString dof = dofsplit.at(1).trimmed();
996
dofsplit = dof.split(")");
997
dof = dofsplit.at(0).trimmed();
998
999
#if WITH_QT6
1000
dofs = engine.evaluate(dof).toInt();
1001
#else
1002
dofs = engine.evaluate(dof).toInt32();
1003
#endif
1004
1005
}
1006
// Don't write the the trivial dof==1 case as this leaves possibility to define the number of
1007
// dofs internally within the solver.
1008
if ( dofs <= 1 ) {
1009
addSifLine( " "+labelName+" = ", varName );
1010
dofs = 1;
1011
}
1012
else {
1013
addSifLine( " "+labelName+" = -dofs ", QString::number(dofs) + " " + varName );
1014
}
1015
}
1016
continue;
1017
}
1018
1019
QWidget *widget = entry.widget;
1020
1021
QDomElement elem;
1022
if ( widget->isEnabled() ) {
1023
elem = entry.elem;
1024
1025
if(elem.attribute("Widget", "") == "CheckBox")
1026
handleCheckBox(elem, widget);
1027
1028
if(elem.attribute("Widget", "") == "Edit")
1029
handleLineEdit(elem, widget);
1030
1031
if(elem.attribute("Widget", "") == "Combo")
1032
handleComboBox(elem, widget);
1033
1034
if(elem.attribute("Widget", "") == "TextEdit")
1035
handleTextEdit(elem, widget);
1036
}
1037
}
1038
1039
return hasMatrix;
1040
}
1041
1042
// Parse "Exec Solver" tab from ui to sif:
1043
//-----------------------------------------------------------------------------
1044
void SifGenerator::parseExecSolverTab(Ui::solverParameterEditor ui)
1045
{
1046
if(ui.execAlways->isChecked())
1047
te->append(" Exec Solver = Always");
1048
1049
if(ui.execBeforeSimulation->isChecked())
1050
te->append(" Exec Solver = Before Simulation");
1051
1052
if(ui.execAfterSimulation->isChecked())
1053
te->append(" Exec Solver = After Simulation");
1054
1055
if(ui.execBeforeTimestep->isChecked())
1056
te->append(" Exec Solver = Before Timestep");
1057
1058
if(ui.execAfterTimestep->isChecked())
1059
te->append(" Exec Solver = After Timestep");
1060
1061
if(ui.execBeforeSaving->isChecked())
1062
te->append(" Exec Solver = Before Saving");
1063
1064
if(ui.execAfterSaving->isChecked())
1065
te->append(" Exec Solver = After Saving");
1066
1067
if(ui.execNever->isChecked())
1068
te->append(" Exec Solver = Never");
1069
}
1070
1071
// Parse "Numerical Techniques" tab from ui to sif:
1072
//-----------------------------------------------------------------------------
1073
void SifGenerator::parseNumericalTechniquesTab(Ui::solverParameterEditor ui)
1074
{
1075
if(ui.lumpedMassCheck->isChecked())
1076
addSifLineBool(" Lumped Mass Matrix = ", ui.lumpedMassCheck->isChecked());
1077
1078
addSifLineBool(" Stabilize = ", ui.stabilizeCheck->isChecked());
1079
1080
if(ui.bubblesCheck->isChecked())
1081
addSifLineBool(" Bubbles = ", ui.bubblesCheck->isChecked());
1082
1083
addSifLineBool(" Optimize Bandwidth = ", ui.optimizeBandwidthCheck->isChecked());
1084
}
1085
1086
1087
// Parse "Steady state" tab from ui to sif:
1088
//-----------------------------------------------------------------------------
1089
void SifGenerator::parseSteadyStateTab(Ui::solverParameterEditor ui)
1090
{
1091
if(ui.steadyStateConvergenceToleranceEdit->text() == "") {
1092
cout << "Steady state convergence tolerance is undefined - aborting" << endl;
1093
return;
1094
}
1095
1096
addSifLine(" Steady State Convergence Tolerance = ",
1097
ui.steadyStateConvergenceToleranceEdit->text());
1098
1099
if( ui.steadyStateConvergenceMeasureCombo->currentText().trimmed() != "Norm")
1100
addSifLine(" Steady State Convergence Measure = ",
1101
ui.steadyStateConvergenceMeasureCombo->currentText().trimmed());
1102
}
1103
1104
1105
// Parse "Nonlinear system" tab from ui to sif:
1106
//-----------------------------------------------------------------------------
1107
void SifGenerator::parseNonlinearSystemTab(Ui::solverParameterEditor ui)
1108
{
1109
addSifLine(" Nonlinear System Convergence Tolerance = ",
1110
ui.nonlinSystemConvergenceToleranceEdit->text());
1111
1112
addSifLine(" Nonlinear System Max Iterations = ",
1113
ui.nonlinSystemMaxIterationEdit->text());
1114
1115
addSifLine(" Nonlinear System Newton After Iterations = ",
1116
ui.nonlinSystemNewtonAfterIterEdit->text());
1117
1118
addSifLine(" Nonlinear System Newton After Tolerance = ",
1119
ui.nonlinSystemNewtonAfterTolEdit->text());
1120
1121
addSifLine(" Nonlinear System Relaxation Factor = ",
1122
ui.nonlinSystemRelaxationFactorEdit->text());
1123
1124
if( ui.nonlinSystemConvergenceMeasureCombo->currentText().trimmed() != "Norm")
1125
addSifLine(" Nonlinear System Convergence Measure = ",
1126
ui.nonlinSystemConvergenceMeasureCombo->currentText().trimmed());
1127
1128
}
1129
1130
1131
// Parse "Parallel" tab from ui to sif:
1132
//-----------------------------------------------------------------------------
1133
void SifGenerator::parseParallelTab(Ui::solverParameterEditor ui)
1134
{
1135
if(ui.useHypre->isChecked()) {
1136
addSifLine(" Linear System Use HYPRE = ", "True");
1137
1138
if(ui.useParasails->isChecked()) {
1139
addSifLine(" Linear System Preconditioning = ", "ParaSails");
1140
1141
addSifLine(" ParaSails Threshold = ",
1142
ui.thresholdEdit->text().trimmed());
1143
1144
addSifLine(" ParaSails Filter = ",
1145
ui.filterEdit->text().trimmed());
1146
1147
addSifLine(" ParaSails MaxLevel = ",
1148
ui.maxLevelEdit->text().trimmed());
1149
1150
addSifLine(" ParaSails Symmetry = ",
1151
ui.symmetryEdit->text().trimmed());
1152
}
1153
1154
if(ui.useBoomerAMG->isChecked()) {
1155
addSifLine(" Linear System Preconditioning = ", "BoomerAMG");
1156
1157
addSifLine(" BoomerAMG Relax Type = ",
1158
QString::number(ui.boomerRelaxation->currentIndex()));
1159
1160
addSifLine(" BoomerAMG Coarsen Type = ",
1161
QString::number(ui.boomerCoarsening->currentIndex()));
1162
1163
addSifLine(" BoomerAMG Num Sweeps = ",
1164
ui.boomerSweeps->text().trimmed());
1165
1166
addSifLine(" BoomerAMG Max Levels = ",
1167
ui.boomerMaxLevels->text().trimmed());
1168
1169
addSifLine(" BoomerAMG Interpolation = ",
1170
QString::number(ui.boomerInterpolation->currentIndex()));
1171
1172
addSifLine(" BoomerAMG Smooth Type = ",
1173
QString::number(ui.boomerSmoother->currentIndex()));
1174
1175
addSifLine(" BoomerAMG Cycle Type = ",
1176
QString::number(ui.boomerCycle->currentIndex()));
1177
1178
}
1179
}
1180
}
1181
1182
1183
// Parse "Linear system" tab from ui to sif:
1184
//-----------------------------------------------------------------------------
1185
void SifGenerator::parseLinearSystemTab(Ui::solverParameterEditor ui)
1186
{
1187
bool hyprePreconditioning
1188
= ui.useParasails->isChecked() | ui.useBoomerAMG->isChecked();
1189
1190
if(ui.linearSystemSolverDirect->isChecked()) {
1191
1192
addSifLine(" Linear System Solver = ", "Direct");
1193
1194
addSifLine(" Linear System Direct Method = ",
1195
ui.linearSystemDirectMethod->currentText());
1196
1197
} else if(ui.linearSystemSolverIterative->isChecked()) {
1198
1199
addSifLine(" Linear System Solver = ", "Iterative");
1200
1201
addSifLine(" Linear System Iterative Method = ",
1202
ui.linearSystemIterativeMethod->currentText());
1203
1204
addSifLine(" Linear System Max Iterations = ",
1205
ui.linearSystemMaxIterationsEdit->text());
1206
1207
addSifLine(" Linear System Convergence Tolerance = ",
1208
ui.linearSystemConvergenceToleranceEdit->text());
1209
1210
addSifLine(" BiCGstabl polynomial degree = ",
1211
ui.linearSystemBiCGstablPolDeg->text());
1212
1213
if(!hyprePreconditioning)
1214
addSifLine(" Linear System Preconditioning = ",
1215
ui.linearSystemPreconditioning->currentText());
1216
1217
addSifLine(" Linear System ILUT Tolerance = ",
1218
ui.linearSystemILUTToleranceEdit->text());
1219
1220
addSifLineBool(" Linear System Abort Not Converged = ",
1221
ui.linearSystemAbortWhenNotConvergedCheck->isChecked());
1222
1223
addSifLine(" Linear System Residual Output = ",
1224
ui.linearSystemResiduaOutputEdit->text());
1225
1226
addSifLine(" Linear System Precondition Recompute = ",
1227
ui.linearSystemPreconditionRecomputeEdit->text());
1228
1229
} else if(ui.linearSystemSolverMultigrid->isChecked()) {
1230
1231
addSifLine(" Linear System Solver = ", "Multigrid");
1232
1233
// TODO: rest of the less common params etc.
1234
}
1235
}
1236
1237
//------------------------------------------------------------------------
1238
//
1239
// COMMON UTILITY FUNCTIONS
1240
//
1241
//------------------------------------------------------------------------
1242
1243
void SifGenerator::addSifLine(const QString &var, const QString &val)
1244
{
1245
if(val != "")
1246
te->append(var + val);
1247
}
1248
1249
void SifGenerator::addSifLineBool(const QString &var, bool val)
1250
{
1251
if(val == true)
1252
te->append(var + "True");
1253
else
1254
te->append(var + "False");
1255
}
1256
1257
1258
void SifGenerator::handleBCLineEdit(const QDomElement &elem, QWidget *widget, const QMap<int, int> &boundaryBC)
1259
{
1260
QString name = elem.firstChildElement("SifName").text().trimmed();
1261
if( name == "" )
1262
name= elem.firstChildElement("Name").text().trimmed();
1263
1264
QLineEdit *lineEdit = static_cast<QLineEdit*>(widget);
1265
QString value = lineEdit->text().trimmed();
1266
1267
if ( name=="Periodic BC" && value != "" )
1268
{
1269
int val = value.toInt();
1270
val = boundaryMap.value(val);
1271
value=QString::number(boundaryBC[val]);
1272
}
1273
1274
addSifLine(" " + name + " = ", value);
1275
}
1276
1277
void SifGenerator::handleLineEdit(const QDomElement &elem, QWidget *widget)
1278
{
1279
QString name = elem.firstChildElement("SifName").text().trimmed();
1280
if( name == "" )
1281
name= elem.firstChildElement("Name").text().trimmed();
1282
1283
QLineEdit *lineEdit = static_cast<QLineEdit*>(widget);
1284
QString value = lineEdit->text().trimmed();
1285
1286
// Adjust array parameters, i.e.:
1287
// eliminate the first '=' in "Save Coordinates = (2,3) = 1.2 2.3 3.4 4.5 5.6 6.7"
1288
#if WITH_QT5 || WITH_QT6
1289
QRegularExpression qre("^\\s*\\(\\s*[1-9]+[0-9]*\\s*(,\\s*[1-9]+[0-9]*\\s*)*\\)\\s*=");
1290
QRegularExpressionMatch match = qre.match(value);
1291
if(match.hasMatch()){
1292
addSifLine(" " + name, value);
1293
cout << " [SifGenerator] array parameter adjusted: '"
1294
<< name.toLatin1().constData() << " = " << value.toLatin1().constData() << "' to '"
1295
<< name.toLatin1().constData() << value.toLatin1().constData() << "'" << endl;
1296
}else{
1297
addSifLine(" " + name + " = ", value);
1298
}
1299
#else
1300
QRegExp qre("^\\s*\\(\\s*[1-9]+[0-9]*\\s*(,\\s*[1-9]+[0-9]*\\s*)*\\)\\s*=");
1301
int index = qre.indexIn(value);
1302
if(index >= 0) {
1303
addSifLine(" " + name, value);
1304
cout << " [SifGenerator] array parameter adjusted: '"
1305
<< name.toAscii().constData() << " = " << value.toAscii().constData() << "' to '"
1306
<< name.toAscii().constData() << value.toAscii().constData() << "'" << endl;
1307
}else{
1308
addSifLine(" " + name + " = ", value);
1309
}
1310
#endif
1311
}
1312
1313
void SifGenerator::handleTextEdit(const QDomElement &elem, QWidget *widget)
1314
{
1315
QTextEdit *textEdit = static_cast<QTextEdit*>(widget);
1316
QString value = textEdit->toPlainText();
1317
if(!value.isEmpty()) te->append(value);
1318
}
1319
1320
void SifGenerator::handleComboBox(const QDomElement &elem, QWidget *widget)
1321
{
1322
QString name = elem.firstChildElement("SifName").text().trimmed();
1323
if( name == "" )
1324
name= elem.firstChildElement("Name").text().trimmed();
1325
1326
QComboBox *comboBox = static_cast<QComboBox*>(widget);
1327
QString value = comboBox->currentText().trimmed();
1328
1329
if(value != "None")
1330
addSifLine(" " + name + " = ", value);
1331
}
1332
1333
void SifGenerator::handleCheckBox(const QDomElement &elem, QWidget *widget)
1334
{
1335
QString name = elem.firstChildElement("SifName").text().trimmed();
1336
if( name == "" )
1337
name = elem.firstChildElement("Name").text().trimmed();
1338
1339
QString def_val = elem.firstChildElement("DefaultValue").text().trimmed();
1340
if ( def_val == "" )
1341
def_val = "False";
1342
1343
QCheckBox *checkBox = static_cast<QCheckBox*>(widget);
1344
1345
if(checkBox->isChecked()) {
1346
if ( def_val != "True" )
1347
te->append(" " + name + " = True");
1348
} else {
1349
if ( def_val != "False" )
1350
te->append(" " + name + " = False");
1351
}
1352
}
1353
1354