Path: blob/devel/ElmerGUI/Application/src/sifgenerator.cpp
3203 views
/*****************************************************************************1* *2* Elmer, A Finite Element Software for Multiphysical Problems *3* *4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *5* *6* This program is free software; you can redistribute it and/or *7* modify it under the terms of the GNU General Public License *8* as published by the Free Software Foundation; either version 2 *9* of the License, or (at your option) any later version. *10* *11* This program is distributed in the hope that it will be useful, *12* but WITHOUT ANY WARRANTY; without even the implied warranty of *13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *14* GNU General Public License for more details. *15* *16* You should have received a copy of the GNU General Public License *17* along with this program (in file fem/GPL-2); if not, write to the *18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *19* Boston, MA 02110-1301, USA. *20* *21*****************************************************************************/2223/*****************************************************************************24* *25* ElmerGUI sifgenerator *26* *27*****************************************************************************28* *29* Authors: Mikko Lyly, Juha Ruokolainen and Peter R�back *30* Email: [email protected] *31* Web: http://www.csc.fi/elmer *32* Address: CSC - IT Center for Science Ltd. *33* Keilaranta 14 *34* 02101 Espoo, Finland *35* *36* Original Date: 15 Mar 2008 *37* *38*****************************************************************************/3940#include "sifgenerator.h"41#include <iostream>42#include <QDebug>43#if WITH_QT644#include <QJSEngine>45#else46#include <QScriptEngine>47#endif4849using namespace std;5051SifGenerator::SifGenerator()52{53}5455SifGenerator::~SifGenerator()56{57}5859void SifGenerator::setMesh(mesh_t* m)60{61this->mesh = m;62}6364void SifGenerator::setTextEdit(QTextEdit* textEdit)65{66this->te = textEdit;67}6869void SifGenerator::setDim(int n)70{71this->dim = n;72}7374void SifGenerator::setCdim(int n)75{76this->cdim = n;77}7879void SifGenerator::setElmerDefs(QDomDocument* d)80{81this->elmerDefs = d;82}8384void SifGenerator::setGeneralSetup(GeneralSetup* g)85{86this->generalSetup = g;87}8889void SifGenerator::setEquationEditor(const QVector<DynamicEditor*>& d)90{91this->equationEditor = d;92}9394void SifGenerator::setMaterialEditor(const QVector<DynamicEditor*>& d)95{96this->materialEditor = d;97}9899void SifGenerator::setBodyForceEditor(const QVector<DynamicEditor*>& d)100{101this->bodyForceEditor = d;102}103104void SifGenerator::setInitialConditionEditor(const QVector<DynamicEditor*>& d)105{106this->initialConditionEditor = d;107}108109void SifGenerator::setBoundaryConditionEditor(const QVector<DynamicEditor*>& d)110{111this->boundaryConditionEditor = d;112}113114void SifGenerator::setSolverParameterEditor(const QVector<SolverParameterEditor*>& s)115{116this->solverParameterEditor = s;117}118119void SifGenerator::setBoundaryPropertyEditor(const QVector<BoundaryPropertyEditor*>& b)120{121this->boundaryPropertyEditor = b;122}123124void SifGenerator::setBodyPropertyEditor(const QVector<BodyPropertyEditor*>& b)125{126this->bodyPropertyEditor = b;127}128129void SifGenerator::setMeshControl(MeshControl* m)130{131this->meshControl = m;132}133134void SifGenerator::setLimit(Limit* l)135{136this->limit = l;137}138139// Make Header-block:140//-----------------------------------------------------------------------------141void SifGenerator::makeHeaderBlock()142{143Ui::setupDialog ui = generalSetup->ui;144145te->append("Header");146147if(ui.checkKeywordsWarn->isChecked())148te->append(" CHECK KEYWORDS Warn");149150QString qs1 = ui.meshDBEdit1->text().trimmed();151QString qs2 = ui.meshDBEdit2->text().trimmed();152QString qs3 = ui.includePathEdit->text().trimmed();153QString qs4 = ui.resultsDirectoryEdit->text().trimmed();154QString qs5 = ui.headerFreeTextEdit->toPlainText();155156te->append(" Mesh DB \"" + qs1 + "\" \"" + qs2 + "\"");157te->append(" Include Path \"" + qs3 + "\"");158te->append(" Results Directory \"" + qs4 + "\"");159160if(!qs5.isEmpty())161te->append(qs5);162163te->append("End\n");164}165166// Make Simulation-block:167//-----------------------------------------------------------------------------168void SifGenerator::makeSimulationBlock()169{170Ui::setupDialog ui = generalSetup->ui;171172te->append("Simulation");173174addSifLine(" Max Output Level = ",175ui.maxOutputLevelCombo->currentText().trimmed());176addSifLine(" Coordinate System = ",177ui.coordinateSystemCombo->currentText().trimmed());178addSifLine(" Coordinate Mapping(3) = ",179ui.coordinateMappingEdit->text().trimmed());180addSifLine(" Simulation Type = ",181ui.simulationTypeCombo->currentText().trimmed());182addSifLine(" Steady State Max Iterations = ",183ui.steadyStateMaxIterEdit->text().trimmed());184//Modify Output intervals size according to the number of values entered185QString qs = ui.outputIntervalsEdit->text().simplified();186addSifLine(" Output Intervals(" + QString::number(qs.count(' ') + 1) + ") = ", qs);187188if( ui.simulationTypeCombo->currentText().trimmed() != "Steady state") {189//Modify Timestep intervals size according to the number of values entered190qs = ui.timeStepIntervalsEdit->text().simplified();191addSifLine(" Timestep intervals(" + QString::number(qs.count(' ') + 1) + ") = ", qs);192if( ui.simulationTypeCombo->currentText().trimmed() == "Transient") {193//Modify Timestep Sizes size according to the number of values entered194qs = ui.timestepSizesEdit->text().simplified();195addSifLine(" Timestep Sizes(" + QString::number(qs.count(' ') + 1) + ") = ", qs);196addSifLine(" Timestepping Method = ",197ui.timesteppingMethodCombo->currentText().trimmed());198addSifLine(" BDF Order = ",199ui.bdfOrderCombo->currentText().trimmed());200}201}202203addSifLine(" Coordinate Scaling = ",204ui.coordinateScalingEdit->text().trimmed());205addSifLine(" Angular Frequency = ",206ui.angularFrequencyEdit->text().trimmed());207208addSifLine(" Solver Input File = ",209ui.solverInputFileEdit->text().trimmed());210addSifLine(" Post File = ",211ui.postFileEdit->text().trimmed());212213if(ui.calculateMeshPiecesCheck->isChecked())214te->append(" Calculate Mesh Pieces = True");215addSifLine(" Desired Mesh Pieces = ",216ui.desiredMeshPiecesEdit->text().trimmed());217218qs = ui.simulationFreeTextEdit->toPlainText();219220if(!qs.isEmpty())221te->append(qs);222223te->append("End\n");224}225226// Make Constants-block:227//-----------------------------------------------------------------------------228void SifGenerator::makeConstantsBlock()229{230Ui::setupDialog ui = generalSetup->ui;231232te->append("Constants");233234addSifLine(" Gravity(4) = ",235ui.gravityEdit->text().trimmed());236addSifLine(" Stefan Boltzmann = ",237ui.stefanBoltzmannEdit->text().trimmed());238addSifLine(" Permittivity of Vacuum = ",239ui.vacuumPermittivityEdit->text().trimmed());240addSifLine(" Permeability of Vacuum = ",241ui.vacuumPermeabilityEdit->text().trimmed());242addSifLine(" Boltzmann Constant = ",243ui.boltzmannEdit->text().trimmed());244addSifLine(" Unit Charge = ",245ui.unitChargeEdit->text().trimmed());246247QString qs = ui.constantsFreeTextEdit->toPlainText();248249if(!qs.isEmpty())250te->append(qs);251252te->append("End\n");253}254255256// Make Body-blocks:257//-----------------------------------------------------------------------------258void SifGenerator::makeBodyBlocks()259{260int i;261262int sifIndex = 0, maxOriginalIndex=-1;263264for(int index = 0; index < bodyMap.count(); index++) {265266if(index >= bodyPropertyEditor.size()) {267cout << "SifGenerator: Body index out of bounds" << endl;268continue;269}270271BodyPropertyEditor *bodyEdit = bodyPropertyEditor[index];272273if(!bodyEdit)274continue;275276int originalIndex = bodyMap.key(index);277maxOriginalIndex = max(maxOriginalIndex, originalIndex );278279if(bodyEdit->touched) {280te->append("Body " + QString::number(++sifIndex));281282te->append(" Target Bodies(1) = " + QString::number(originalIndex));283284if ( bodyEdit->ui.nameEdit->text().trimmed() == "" )285te->append(" Name = \"Body " + QString::number(sifIndex) + "\"");286else287te->append(" Name = \"" + bodyEdit->ui.nameEdit->text().trimmed() + "\"");288289i = bodyEdit->ui.equationCombo->currentIndex();290if(i > 0)291te->append(" Equation = " + QString::number(i));292293i = bodyEdit->ui.materialCombo->currentIndex();294if(i > 0)295te->append(" Material = " + QString::number(i));296297i = bodyEdit->ui.bodyForceCombo->currentIndex();298if(i > 0)299te->append(" Body Force = " + QString::number(i));300301i = bodyEdit->ui.initialConditionCombo->currentIndex();302if(i > 0)303te->append(" Initial condition = " + QString::number(i));304305te->append("End\n");306}307}308309for( int index = 0; index < boundaryPropertyEditor.size(); index++ )310{311if(!boundaryPropertyEditor[index])312continue;313314BodyPropertyEditor *bodyEdit = boundaryPropertyEditor[index]->bodyProperties;315316if(!bodyEdit)317continue;318319if(bodyEdit && bodyEdit->touched ) {320te->append("Body " + QString::number(++sifIndex));321322boundaryPropertyEditor[index]->bodyID = ++maxOriginalIndex;323324te->append(" Target Bodies(1) = " + QString::number(maxOriginalIndex));325326if ( bodyEdit->ui.nameEdit->text().trimmed() == "" )327te->append(" Name = \"Body " + QString::number(sifIndex) + "\"");328else329te->append(" Name = \"" + bodyEdit->ui.nameEdit->text().trimmed() + "\"");330331i = bodyEdit->ui.equationCombo->currentIndex();332if(i > 0)333te->append(" Equation = " + QString::number(i));334335i = bodyEdit->ui.materialCombo->currentIndex();336if(i > 0)337te->append(" Material = " + QString::number(i));338339i = bodyEdit->ui.bodyForceCombo->currentIndex();340if(i > 0)341te->append(" Body Force = " + QString::number(i));342343i = bodyEdit->ui.initialConditionCombo->currentIndex();344if(i > 0)345te->append(" Initial condition = " + QString::number(i));346347te->append("End\n");348}349}350}351352353int SifGenerator::findHashValue(DynamicEditor *de, const QString &sname, const QString &name)354{355for(int i = 0; i < de->hash.count(); i++) {356hash_entry_t entry = de->hash.values().at(i);357358QWidget *widget = entry.widget;359if (widget->isEnabled()) {360QString key = de->hash.keys().at(i);361QStringList keySplitted = key.split("/");362QString solverName = keySplitted.at(1).trimmed();363QString labelName = keySplitted.at(3).trimmed();364365QDomElement elem = entry.elem;366if ( solverName==sname && labelName==name &&367elem.attribute("Widget","")=="Edit" ) {368QLineEdit *line = static_cast<QLineEdit*>(widget);369QString str = line->text().trimmed();370if ( str.isEmpty() ) return 0;371return str.toInt();372}373}374}375return 0;376}377378// Make Equation/Solver -blocks:379//-----------------------------------------------------------------------------380void SifGenerator::makeEquationBlocks()381{382// Enumerate solvers && write solver blocks:383//-------------------------------------------384QMap<QString, int> numberForSolver;385numberForSolver.clear();386387int solverNumber = 0;388389for(int index = 0; index < equationEditor.size(); index++) {390DynamicEditor *eqEditor = equationEditor[index];391392if(eqEditor->menuAction != NULL) {393for(int i = 0; i < eqEditor->hash.count(); i++) {394hash_entry_t entry = eqEditor->hash.values().at(i);395396QWidget *widget = entry.widget;397if (widget->isEnabled()) {398QDomElement elem = entry.elem;399400QString key = eqEditor->hash.keys().at(i);401QStringList keySplitted = key.split("/");402QString labelName = keySplitted.at(3).trimmed();403QString solverName = keySplitted.at(1).trimmed();404405if(labelName=="Active" && elem.attribute("Widget", "")=="CheckBox") {406QCheckBox *checkBox = static_cast<QCheckBox*>(widget);407if(checkBox->isChecked()) {408if(!numberForSolver.contains(solverName)) {409int pri = findHashValue( eqEditor, solverName, "Priority");410numberForSolver.insert(solverName, pri);411}412}413}414}415}416}417}418419// Sort and enumerate solvers according to their priority:420//---------------------------------------------------------421#if WITH_QT6422vector<QPair<int, QString> > tmpList;423424foreach(const QString &key, numberForSolver.keys()) {425int value = numberForSolver.value(key);426tmpList.push_back(qMakePair(value, key));427}428429sort(tmpList.begin(), tmpList.end());430#else431QList<QPair<int, QString> > tmpList;432433foreach(const QString &key, numberForSolver.keys()) {434int value = numberForSolver.value(key);435tmpList << qMakePair(value, key);436}437438qSort(tmpList);439#endif440441numberForSolver.clear();442443#if WITH_QT6444int n = tmpList.size();445#else446int n = tmpList.count();447#endif448449for(int i = 0; i < n; i++) {450const QPair<int, QString> &pair = tmpList[i];451const QString &key = pair.second;452numberForSolver.insert(key, n-i);453}454455// Generate solver blocks:456//-------------------------457QMap<int, int> handled;458459for(int index = 0; index < equationEditor.size(); index++) {460DynamicEditor *eqEditor = equationEditor[index];461if(eqEditor->menuAction != NULL) {462for(int i = 0; i < eqEditor->hash.count(); i++) {463hash_entry_t entry = eqEditor->hash.values().at(i);464465QWidget *widget = entry.widget;466if (widget->isEnabled()) {467QString key = eqEditor->hash.keys().at(i);468QStringList keySplitted = key.split("/");469QString solverName = keySplitted.at(1).trimmed();470QString labelName = keySplitted.at(3).trimmed();471QDomElement elem = entry.elem;472473if(labelName=="Active" && elem.attribute("Widget", "")=="CheckBox") {474QCheckBox *checkBox = static_cast<QCheckBox*>(widget);475if(checkBox->isChecked()) {476solverNumber = numberForSolver.value(solverName);477if((solverNumber>0) && (handled[solverNumber]==0)) {478handled[solverNumber] = 1;479te->append("Solver " + QString::number(solverNumber));480te->append(" Equation = " + solverName);481makeSolverBlocks(solverName);482te->append("End");483te->append("");484}485}486}487}488}489}490}491492// Generate equation blocks:493//---------------------------494QMap<int, bool> solverActive;495496int sifIndex = 0;497for(int index = 0; index < equationEditor.size(); index++) {498DynamicEditor *eqEditor = equationEditor[index];499500if(eqEditor->menuAction != NULL) {501te->append("Equation " + QString::number(++sifIndex));502503QString name = eqEditor->nameEdit->text().trimmed();504te->append(" Name = \"" + name + "\"");505506QString solverString = "";507int nofSolvers = 0;508509for( int i=0; i < solverParameterEditor.size(); i++ )510solverActive[i] = false;511512for(int i = 0; i < eqEditor->hash.count(); i++) {513hash_entry_t entry = eqEditor->hash.values().at(i);514QWidget *widget = entry.widget;515516if(widget->isEnabled()) {517QDomElement elem = entry.elem;518QString key = eqEditor->hash.keys().at(i);519QStringList keySplitted = key.split("/");520QString solverName = keySplitted.at(1).trimmed();521QString labelName = keySplitted.at(3).trimmed();522523// solver active?524if((labelName == "Active") && (elem.attribute("Widget", "") == "CheckBox")) {525QCheckBox *checkBox = static_cast<QCheckBox*>(widget);526if(checkBox->isChecked()) {527nofSolvers++;528solverNumber = numberForSolver.value(solverName);529solverActive[solverNumber] = true;530solverString += " " + QString::number(solverNumber);531}532}533}534}535536for(int i = 0; i < eqEditor->hash.count(); i++) {537hash_entry_t entry = eqEditor->hash.values().at(i);538QWidget *widget = entry.widget;539540if(widget->isEnabled()) {541QDomElement elem = entry.elem;542QString key = eqEditor->hash.keys().at(i);543QStringList keySplitted = key.split("/");544QString solverName = keySplitted.at(1).trimmed();545QString labelName = keySplitted.at(3).trimmed();546547solverNumber = numberForSolver.value(solverName);548if ( !solverActive[solverNumber] ) continue;549550if((elem.attribute("Widget", "") == "CheckBox") &&551(labelName != "Active"))552handleCheckBox(elem, widget);553554if(elem.attribute("Widget", "") == "Edit" &&555labelName != "Priority")556handleLineEdit(elem, widget);557558if(elem.attribute("Widget", "") == "Combo")559handleComboBox(elem, widget);560561if(elem.attribute("Widget", "") == "TextEdit")562handleTextEdit(elem, widget);563}564}565566if(nofSolvers > 0)567te->append(" Active Solvers("568+ QString::number(nofSolvers)569+ ") =" + solverString);570571te->append("End\n");572}573}574}575576//-------------------------------------------------------------------------577void SifGenerator::makeSolverBlocks(const QString &solverName)578{579SolverParameterEditor *spe, *tmp;580Ui::solverParameterEditor ui;581582bool found = false;583int current=-1;584585for(int i = 0; i < solverParameterEditor.size(); i++) {586spe = solverParameterEditor[i];587588if(!spe)589continue;590591QString currentName = spe->solverName.trimmed();592if(currentName == solverName) {593found = true;594current = i;595break;596}597}598599if(!found) {600tmp = new SolverParameterEditor;601} else {602tmp = spe;603}604605if ( !tmp->generalOptions ) {606tmp->generalOptions = new DynamicEditor;607tmp->generalOptions->setupTabs(elmerDefs, "Solver", current );608}609610bool hasMatrix = parseSolverSpecificTab(tmp->generalOptions, solverName);611612ui = tmp->ui;613614// Parse the exec solver also for non-PDE solvers615parseExecSolverTab(ui);616617if(hasMatrix) {618parseNumericalTechniquesTab(ui);619parseSteadyStateTab(ui);620parseNonlinearSystemTab(ui);621parseLinearSystemTab(ui);622parseParallelTab(ui);623// todo: add adaptivity & multigrid624}625626if(!found)627{628delete tmp->generalOptions;629delete tmp;630}631}632633// Make Material-blocks:634//-----------------------------------------------------------------------------635void SifGenerator::makeMaterialBlocks()636{637int sifIndex = 0;638639for(int index = 0; index < materialEditor.size(); index++) {640DynamicEditor *matEditor = materialEditor[index];641642if(matEditor->menuAction != NULL) {643te->append("Material " + QString::number(++sifIndex));644645QString name = matEditor->nameEdit->text().trimmed();646te->append(" Name = \"" + name + "\"");647648for(int i = 0; i < matEditor->hash.count(); i++) {649hash_entry_t entry = matEditor->hash.values().at(i);650651QWidget *widget = entry.widget;652653QDomElement elem;654655if ( widget->isEnabled() ) {656elem = entry.elem;657658if(elem.attribute("Widget", "") == "CheckBox")659handleCheckBox(elem, widget);660661if(elem.attribute("Widget", "") == "Edit")662handleLineEdit(elem, widget);663664if(elem.attribute("Widget", "") == "Combo")665handleComboBox(elem, widget);666667if(elem.attribute("Widget", "") == "TextEdit")668handleTextEdit(elem, widget);669}670}671te->append("End\n");672}673}674}675676677// Make body force blocks:678//-----------------------------------------------------------------------------679void SifGenerator::makeBodyForceBlocks()680{681int sifIndex = 0;682683for(int index = 0; index < bodyForceEditor.size(); index++) {684DynamicEditor *bfEdit = bodyForceEditor[index];685686if(bfEdit->menuAction != NULL) {687te->append("Body Force " + QString::number(++sifIndex));688689QString name = bfEdit->nameEdit->text().trimmed();690te->append(" Name = \"" + name + "\"");691692for(int i = 0; i < bfEdit->hash.count(); i++) {693hash_entry_t entry = bfEdit->hash.values().at(i);694695QWidget *widget = entry.widget;696697if ( widget->isEnabled() ) {698QDomElement elem = entry.elem;699700if(elem.attribute("Widget", "") == "CheckBox")701handleCheckBox(elem, widget);702703if(elem.attribute("Widget", "") == "Edit")704handleLineEdit(elem, widget);705706if(elem.attribute("Widget", "") == "Combo")707handleComboBox(elem, widget);708709if(elem.attribute("Widget", "") == "TextEdit")710handleTextEdit(elem, widget);711}712}713te->append("End\n");714}715}716}717718719// Make initial condition blocks:720//-----------------------------------------------------------------------------721void SifGenerator::makeInitialConditionBlocks()722{723int sifIndex = 0;724725for(int index = 0; index < initialConditionEditor.size(); index++) {726DynamicEditor *icEdit = initialConditionEditor[index];727728if(icEdit->menuAction != NULL) {729te->append("Initial Condition " + QString::number(++sifIndex));730731QString name = icEdit->nameEdit->text().trimmed();732te->append(" Name = \"" + name + "\"");733734for(int i = 0; i < icEdit->hash.count(); i++) {735hash_entry_t entry = icEdit->hash.values().at(i);736737QWidget *widget = entry.widget;738739if ( widget->isEnabled() ) {740QDomElement elem = entry.elem;741742if(elem.attribute("Widget", "") == "CheckBox")743handleCheckBox(elem, widget);744745if(elem.attribute("Widget", "") == "Edit")746handleLineEdit(elem, widget);747748if(elem.attribute("Widget", "") == "Combo")749handleComboBox(elem, widget);750751if(elem.attribute("Widget", "") == "TextEdit")752handleTextEdit(elem, widget);753}754}755te->append("End\n");756}757}758}759760761762// Make boundary blocks:763//-----------------------------------------------------------------------------764void SifGenerator::makeBoundaryBlocks()765{766int sifIndex = 0;767int bcnum = 0;768int diff = 0;769QMap<int, int> boundaryBC;770#if WITH_QT6771QMultiMap<QString, int> boundaryList; /*(Boundary condition, edge) value pairs */772#else773QMap<QString, int> boundaryList; /*(Boundary condition, edge) value pairs */774#endif775QList<QString> boundaryConditions; /* List of different boundary conditions */776QList<int> boundaryEdges; /* List of edges relating to some specific boundary condition */777QString tmp;778779boundaryBC.clear();780boundaryList.clear();781boundaryConditions.clear();782boundaryEdges.clear();783tmp.clear();784785//Find the available boundary conditions786for (int index = 0; index < boundaryConditionEditor.count(); index++) {787DynamicEditor *bc = boundaryConditionEditor[index];788boundaryConditions.append(bc->nameEdit->text().trimmed());789}790791//Find the boundary conditions and edges related to them.792for (int index = 0; index < boundaryConditions.count(); index++) {793for(int k = 0; k < boundaryMap.count(); k++) {794BoundaryPropertyEditor *bEdit = boundaryPropertyEditor[k];795if(bEdit->touched) {796boundaryBC[index] = ++sifIndex;797int originalIndex = boundaryMap.key(k);798const QString bcname = bEdit->ui.boundaryConditionCombo->currentText().trimmed();799if (boundaryConditions.value(index) == bcname)800#if WITH_QT6801boundaryList.insert(bcname, originalIndex);802#else803boundaryList.insertMulti(bcname, originalIndex);804#endif805}806}807}808//qDebug() << "boundaryMap: " << boundaryMap;809//qDebug() << "boundaryList: " << boundaryList;810qDebug() << "boundaryConditions: " << boundaryConditions;811812//Arrange and sort boundary conditions813for(int index = 0; index < boundaryConditions.count(); index++) {814tmp.clear();815boundaryEdges.clear();816const QString name = boundaryConditions[index];817BoundaryPropertyEditor *bEdit = boundaryPropertyEditor[index];818DynamicEditor *bc = boundaryConditionEditor[index];819820if(boundaryList.contains(name)) {821bcnum++;822te->append("Boundary Condition " + QString::number(bcnum));823if(boundaryConditions.count() > 1) {824#if WITH_QT6825QMultiMap <QString,int>::ConstIterator l = boundaryList.find(boundaryConditions[index]);826#else827QMap <QString,int>::ConstIterator l = boundaryList.find(boundaryConditions[index]);828#endif829while (l != boundaryList.end() && l.key()==boundaryConditions[index]){830boundaryEdges.append(l.value());831l++;832}833while ((l--) != boundaryList.begin() && l.key()==boundaryConditions[index]){834tmp.append(QString::number(l.value()));835tmp.append(" ");836}837}838if(boundaryConditions.count() <= 1) {839#if WITH_QT6840QMultiMap <QString,int>::ConstIterator l = boundaryList.begin();841#else842QMap <QString,int>::ConstIterator l = boundaryList.begin();843#endif844while (l != boundaryList.end()) {845boundaryEdges.append(l.value());846l++;847}848while ((l--) != boundaryList.begin()){849tmp.append(QString::number(l.value()));850tmp.append(" ");851}852}853854te->append(" Target Boundaries("855+ QString::number(boundaryEdges.count())856+ ") = " + tmp);857858if ( bEdit->bodyProperties ) {859te->append(" Body id = " + QString::number(bEdit->bodyID) );860}861862te->append(" Name = \"" + name + "\"");863864// check which one of the dynamic editors has "name" typed in nameEdit:865for(int j = 0; j < boundaryConditionEditor.size(); j++) {866DynamicEditor *bc = boundaryConditionEditor[j];867if(bc->menuAction != NULL) {868if(bc->nameEdit->text().trimmed() == name && !name.isNull()) {869870// go through the hash of this dynamic editor:871//--------------------------------------------872for(int i = 0; i < bc->hash.count(); i++) {873hash_entry_t entry = bc->hash.values().at(i);874875QWidget *widget = entry.widget;876877QDomElement elem;878if ( widget->isEnabled() ) {879elem = entry.elem;880881if(elem.attribute("Widget", "") == "CheckBox")882handleCheckBox(elem, widget);883884if(elem.attribute("Widget", "") == "Edit")885handleBCLineEdit(elem, widget, boundaryBC);886887if(elem.attribute("Widget", "") == "Combo")888handleComboBox(elem, widget);889890if(elem.attribute("Widget", "") == "TextEdit")891handleTextEdit(elem, widget);892}893}894}895}896}897te->append("End\n");898}899}900}901902// Parse "Solver specific tab"903//-----------------------------------------------------------------------------904bool SifGenerator::parseSolverSpecificTab(DynamicEditor *solEditor, const QString &solverName)905{906// Returns true if there is a matrix involved. otherwise returns false.907if ( !solEditor ) return false;908909bool hasMatrix = true;910911#if WITH_QT6912QJSEngine engine;913914QJSValue dim_QSV = QJSValue(dim);915engine.globalObject().setProperty( "dim", dim_QSV );916917QJSValue cdim_QSV = QJSValue(cdim);918engine.globalObject().setProperty( "cdim", cdim_QSV );919#else920QScriptEngine engine;921922QScriptValue dim_QSV = QScriptValue(&engine,dim);923engine.globalObject().setProperty( "dim", dim_QSV );924925QScriptValue cdim_QSV = QScriptValue(&engine,cdim);926engine.globalObject().setProperty( "cdim", cdim_QSV );927#endif928929for(int i = 0; i < solEditor->hash.count(); i++) {930hash_entry_t entry = solEditor->hash.values().at(i);931932QString key = solEditor->hash.keys().at(i);933QStringList keySplitted = key.split("/");934QString tabName = keySplitted.at(1).trimmed();935QString labelName = keySplitted.at(3).trimmed();936937if ( tabName != solverName ) continue;938939// Has matrix?940if(labelName == "No Matrix Equation") {941if(entry.elem.attribute("Widget", "") == "CheckBox") {942QCheckBox *cb = static_cast<QCheckBox*>(entry.widget);943hasMatrix = !cb->isChecked();944}945}946947// variable names handled separately...948// ------------------------------------949if ( labelName=="Variable" || labelName.mid(0,17)=="Exported Variable" ) {950if( entry.elem.attribute("Widget", "") != "Edit") continue;951952QLineEdit *l = static_cast<QLineEdit*>(entry.widget);953QString varName = l->text().simplified();954955if ( varName == "" ) continue;956957int dofs=1;958QStringList dofsplit = varName.split("[");959if ( dofsplit.count()>1 ) {960varName = dofsplit.at(0).trimmed() + "[";961QString dof = dofsplit.at(1).trimmed();962dof = dof.split("]").at(0).trimmed();963964dofsplit = dof.split(":");965QString subVarName = dofsplit.at(0).trimmed();966for( int i=1; i<dofsplit.count(); i++)967{968dof = dofsplit.at(i).trimmed();969970QStringList subDofSplit = dof.split(" ");971QString subDof = subDofSplit.at(0).trimmed();972973#if WITH_QT6974dofs = engine.evaluate(subDof).toInt();975#else976dofs = engine.evaluate(subDof).toInt32();977#endif978if (i>1) varName = varName + " ";979varName = varName + subVarName + ":" + QString::number(dofs);980981if ( subDofSplit.count() > 1 ) {982subVarName = subDofSplit.at(1).trimmed();983if ( subDofSplit.count() > 2 ) {984subVarName = subVarName + " " + subDofSplit.at(2);985}986}987}988varName = varName + "]";989addSifLine( " " + labelName + " = ", varName );990} else {991dofsplit = varName.split("(");992if ( dofsplit.count()>1 ) {993varName = dofsplit.at(0).trimmed();994QString dof = dofsplit.at(1).trimmed();995dofsplit = dof.split(")");996dof = dofsplit.at(0).trimmed();997998#if WITH_QT6999dofs = engine.evaluate(dof).toInt();1000#else1001dofs = engine.evaluate(dof).toInt32();1002#endif10031004}1005// Don't write the the trivial dof==1 case as this leaves possibility to define the number of1006// dofs internally within the solver.1007if ( dofs <= 1 ) {1008addSifLine( " "+labelName+" = ", varName );1009dofs = 1;1010}1011else {1012addSifLine( " "+labelName+" = -dofs ", QString::number(dofs) + " " + varName );1013}1014}1015continue;1016}10171018QWidget *widget = entry.widget;10191020QDomElement elem;1021if ( widget->isEnabled() ) {1022elem = entry.elem;10231024if(elem.attribute("Widget", "") == "CheckBox")1025handleCheckBox(elem, widget);10261027if(elem.attribute("Widget", "") == "Edit")1028handleLineEdit(elem, widget);10291030if(elem.attribute("Widget", "") == "Combo")1031handleComboBox(elem, widget);10321033if(elem.attribute("Widget", "") == "TextEdit")1034handleTextEdit(elem, widget);1035}1036}10371038return hasMatrix;1039}10401041// Parse "Exec Solver" tab from ui to sif:1042//-----------------------------------------------------------------------------1043void SifGenerator::parseExecSolverTab(Ui::solverParameterEditor ui)1044{1045if(ui.execAlways->isChecked())1046te->append(" Exec Solver = Always");10471048if(ui.execBeforeSimulation->isChecked())1049te->append(" Exec Solver = Before Simulation");10501051if(ui.execAfterSimulation->isChecked())1052te->append(" Exec Solver = After Simulation");10531054if(ui.execBeforeTimestep->isChecked())1055te->append(" Exec Solver = Before Timestep");10561057if(ui.execAfterTimestep->isChecked())1058te->append(" Exec Solver = After Timestep");10591060if(ui.execBeforeSaving->isChecked())1061te->append(" Exec Solver = Before Saving");10621063if(ui.execAfterSaving->isChecked())1064te->append(" Exec Solver = After Saving");10651066if(ui.execNever->isChecked())1067te->append(" Exec Solver = Never");1068}10691070// Parse "Numerical Techniques" tab from ui to sif:1071//-----------------------------------------------------------------------------1072void SifGenerator::parseNumericalTechniquesTab(Ui::solverParameterEditor ui)1073{1074if(ui.lumpedMassCheck->isChecked())1075addSifLineBool(" Lumped Mass Matrix = ", ui.lumpedMassCheck->isChecked());10761077addSifLineBool(" Stabilize = ", ui.stabilizeCheck->isChecked());10781079if(ui.bubblesCheck->isChecked())1080addSifLineBool(" Bubbles = ", ui.bubblesCheck->isChecked());10811082addSifLineBool(" Optimize Bandwidth = ", ui.optimizeBandwidthCheck->isChecked());1083}108410851086// Parse "Steady state" tab from ui to sif:1087//-----------------------------------------------------------------------------1088void SifGenerator::parseSteadyStateTab(Ui::solverParameterEditor ui)1089{1090if(ui.steadyStateConvergenceToleranceEdit->text() == "") {1091cout << "Steady state convergence tolerance is undefined - aborting" << endl;1092return;1093}10941095addSifLine(" Steady State Convergence Tolerance = ",1096ui.steadyStateConvergenceToleranceEdit->text());10971098if( ui.steadyStateConvergenceMeasureCombo->currentText().trimmed() != "Norm")1099addSifLine(" Steady State Convergence Measure = ",1100ui.steadyStateConvergenceMeasureCombo->currentText().trimmed());1101}110211031104// Parse "Nonlinear system" tab from ui to sif:1105//-----------------------------------------------------------------------------1106void SifGenerator::parseNonlinearSystemTab(Ui::solverParameterEditor ui)1107{1108addSifLine(" Nonlinear System Convergence Tolerance = ",1109ui.nonlinSystemConvergenceToleranceEdit->text());11101111addSifLine(" Nonlinear System Max Iterations = ",1112ui.nonlinSystemMaxIterationEdit->text());11131114addSifLine(" Nonlinear System Newton After Iterations = ",1115ui.nonlinSystemNewtonAfterIterEdit->text());11161117addSifLine(" Nonlinear System Newton After Tolerance = ",1118ui.nonlinSystemNewtonAfterTolEdit->text());11191120addSifLine(" Nonlinear System Relaxation Factor = ",1121ui.nonlinSystemRelaxationFactorEdit->text());11221123if( ui.nonlinSystemConvergenceMeasureCombo->currentText().trimmed() != "Norm")1124addSifLine(" Nonlinear System Convergence Measure = ",1125ui.nonlinSystemConvergenceMeasureCombo->currentText().trimmed());11261127}112811291130// Parse "Parallel" tab from ui to sif:1131//-----------------------------------------------------------------------------1132void SifGenerator::parseParallelTab(Ui::solverParameterEditor ui)1133{1134if(ui.useHypre->isChecked()) {1135addSifLine(" Linear System Use HYPRE = ", "True");11361137if(ui.useParasails->isChecked()) {1138addSifLine(" Linear System Preconditioning = ", "ParaSails");11391140addSifLine(" ParaSails Threshold = ",1141ui.thresholdEdit->text().trimmed());11421143addSifLine(" ParaSails Filter = ",1144ui.filterEdit->text().trimmed());11451146addSifLine(" ParaSails MaxLevel = ",1147ui.maxLevelEdit->text().trimmed());11481149addSifLine(" ParaSails Symmetry = ",1150ui.symmetryEdit->text().trimmed());1151}11521153if(ui.useBoomerAMG->isChecked()) {1154addSifLine(" Linear System Preconditioning = ", "BoomerAMG");11551156addSifLine(" BoomerAMG Relax Type = ",1157QString::number(ui.boomerRelaxation->currentIndex()));11581159addSifLine(" BoomerAMG Coarsen Type = ",1160QString::number(ui.boomerCoarsening->currentIndex()));11611162addSifLine(" BoomerAMG Num Sweeps = ",1163ui.boomerSweeps->text().trimmed());11641165addSifLine(" BoomerAMG Max Levels = ",1166ui.boomerMaxLevels->text().trimmed());11671168addSifLine(" BoomerAMG Interpolation = ",1169QString::number(ui.boomerInterpolation->currentIndex()));11701171addSifLine(" BoomerAMG Smooth Type = ",1172QString::number(ui.boomerSmoother->currentIndex()));11731174addSifLine(" BoomerAMG Cycle Type = ",1175QString::number(ui.boomerCycle->currentIndex()));11761177}1178}1179}118011811182// Parse "Linear system" tab from ui to sif:1183//-----------------------------------------------------------------------------1184void SifGenerator::parseLinearSystemTab(Ui::solverParameterEditor ui)1185{1186bool hyprePreconditioning1187= ui.useParasails->isChecked() | ui.useBoomerAMG->isChecked();11881189if(ui.linearSystemSolverDirect->isChecked()) {11901191addSifLine(" Linear System Solver = ", "Direct");11921193addSifLine(" Linear System Direct Method = ",1194ui.linearSystemDirectMethod->currentText());11951196} else if(ui.linearSystemSolverIterative->isChecked()) {11971198addSifLine(" Linear System Solver = ", "Iterative");11991200addSifLine(" Linear System Iterative Method = ",1201ui.linearSystemIterativeMethod->currentText());12021203addSifLine(" Linear System Max Iterations = ",1204ui.linearSystemMaxIterationsEdit->text());12051206addSifLine(" Linear System Convergence Tolerance = ",1207ui.linearSystemConvergenceToleranceEdit->text());12081209addSifLine(" BiCGstabl polynomial degree = ",1210ui.linearSystemBiCGstablPolDeg->text());12111212if(!hyprePreconditioning)1213addSifLine(" Linear System Preconditioning = ",1214ui.linearSystemPreconditioning->currentText());12151216addSifLine(" Linear System ILUT Tolerance = ",1217ui.linearSystemILUTToleranceEdit->text());12181219addSifLineBool(" Linear System Abort Not Converged = ",1220ui.linearSystemAbortWhenNotConvergedCheck->isChecked());12211222addSifLine(" Linear System Residual Output = ",1223ui.linearSystemResiduaOutputEdit->text());12241225addSifLine(" Linear System Precondition Recompute = ",1226ui.linearSystemPreconditionRecomputeEdit->text());12271228} else if(ui.linearSystemSolverMultigrid->isChecked()) {12291230addSifLine(" Linear System Solver = ", "Multigrid");12311232// TODO: rest of the less common params etc.1233}1234}12351236//------------------------------------------------------------------------1237//1238// COMMON UTILITY FUNCTIONS1239//1240//------------------------------------------------------------------------12411242void SifGenerator::addSifLine(const QString &var, const QString &val)1243{1244if(val != "")1245te->append(var + val);1246}12471248void SifGenerator::addSifLineBool(const QString &var, bool val)1249{1250if(val == true)1251te->append(var + "True");1252else1253te->append(var + "False");1254}125512561257void SifGenerator::handleBCLineEdit(const QDomElement &elem, QWidget *widget, const QMap<int, int> &boundaryBC)1258{1259QString name = elem.firstChildElement("SifName").text().trimmed();1260if( name == "" )1261name= elem.firstChildElement("Name").text().trimmed();12621263QLineEdit *lineEdit = static_cast<QLineEdit*>(widget);1264QString value = lineEdit->text().trimmed();12651266if ( name=="Periodic BC" && value != "" )1267{1268int val = value.toInt();1269val = boundaryMap.value(val);1270value=QString::number(boundaryBC[val]);1271}12721273addSifLine(" " + name + " = ", value);1274}12751276void SifGenerator::handleLineEdit(const QDomElement &elem, QWidget *widget)1277{1278QString name = elem.firstChildElement("SifName").text().trimmed();1279if( name == "" )1280name= elem.firstChildElement("Name").text().trimmed();12811282QLineEdit *lineEdit = static_cast<QLineEdit*>(widget);1283QString value = lineEdit->text().trimmed();12841285// Adjust array parameters, i.e.:1286// eliminate the first '=' in "Save Coordinates = (2,3) = 1.2 2.3 3.4 4.5 5.6 6.7"1287#if WITH_QT5 || WITH_QT61288QRegularExpression qre("^\\s*\\(\\s*[1-9]+[0-9]*\\s*(,\\s*[1-9]+[0-9]*\\s*)*\\)\\s*=");1289QRegularExpressionMatch match = qre.match(value);1290if(match.hasMatch()){1291addSifLine(" " + name, value);1292cout << " [SifGenerator] array parameter adjusted: '"1293<< name.toLatin1().constData() << " = " << value.toLatin1().constData() << "' to '"1294<< name.toLatin1().constData() << value.toLatin1().constData() << "'" << endl;1295}else{1296addSifLine(" " + name + " = ", value);1297}1298#else1299QRegExp qre("^\\s*\\(\\s*[1-9]+[0-9]*\\s*(,\\s*[1-9]+[0-9]*\\s*)*\\)\\s*=");1300int index = qre.indexIn(value);1301if(index >= 0) {1302addSifLine(" " + name, value);1303cout << " [SifGenerator] array parameter adjusted: '"1304<< name.toAscii().constData() << " = " << value.toAscii().constData() << "' to '"1305<< name.toAscii().constData() << value.toAscii().constData() << "'" << endl;1306}else{1307addSifLine(" " + name + " = ", value);1308}1309#endif1310}13111312void SifGenerator::handleTextEdit(const QDomElement &elem, QWidget *widget)1313{1314QTextEdit *textEdit = static_cast<QTextEdit*>(widget);1315QString value = textEdit->toPlainText();1316if(!value.isEmpty()) te->append(value);1317}13181319void SifGenerator::handleComboBox(const QDomElement &elem, QWidget *widget)1320{1321QString name = elem.firstChildElement("SifName").text().trimmed();1322if( name == "" )1323name= elem.firstChildElement("Name").text().trimmed();13241325QComboBox *comboBox = static_cast<QComboBox*>(widget);1326QString value = comboBox->currentText().trimmed();13271328if(value != "None")1329addSifLine(" " + name + " = ", value);1330}13311332void SifGenerator::handleCheckBox(const QDomElement &elem, QWidget *widget)1333{1334QString name = elem.firstChildElement("SifName").text().trimmed();1335if( name == "" )1336name = elem.firstChildElement("Name").text().trimmed();13371338QString def_val = elem.firstChildElement("DefaultValue").text().trimmed();1339if ( def_val == "" )1340def_val = "False";13411342QCheckBox *checkBox = static_cast<QCheckBox*>(widget);13431344if(checkBox->isChecked()) {1345if ( def_val != "True" )1346te->append(" " + name + " = True");1347} else {1348if ( def_val != "False" )1349te->append(" " + name + " = False");1350}1351}135213531354