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