1# -*- coding: utf-8 -*-
2
3#-------------------------------------------------------------------------------
4
5# This file is part of Code_Saturne, a general-purpose CFD tool.
6#
7# Copyright (C) 1998-2021 EDF S.A.
8#
9# This program is free software; you can redistribute it and/or modify it under
10# the terms of the GNU General Public License as published by the Free Software
11# Foundation; either version 2 of the License, or (at your option) any later
12# version.
13#
14# This program is distributed in the hope that it will be useful, but WITHOUT
15# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17# details.
18#
19# You should have received a copy of the GNU General Public License along with
20# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
21# Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23#-------------------------------------------------------------------------------
24
25"""
26This module defines the turbulence model data management.
27
28This module contains the following classes:
29- TurbulenceAdvancedOptionsDialogView
30- TurbulenceView
31"""
32
33#-------------------------------------------------------------------------------
34# Library modules import
35#-------------------------------------------------------------------------------
36
37import sys, logging
38
39#-------------------------------------------------------------------------------
40# Third-party modules
41#-------------------------------------------------------------------------------
42
43from code_saturne.Base.QtCore    import *
44from code_saturne.Base.QtGui     import *
45from code_saturne.Base.QtWidgets import *
46
47#-------------------------------------------------------------------------------
48# Application modules import
49#-------------------------------------------------------------------------------
50
51from code_saturne.model.Common import GuiParam
52from code_saturne.Base.QtPage import ComboModel, DoubleValidator, from_qvariant
53from code_saturne.Pages.TurbulenceForm import Ui_TurbulenceForm
54from code_saturne.Pages.TurbulenceAdvancedOptionsDialogForm import Ui_TurbulenceAdvancedOptionsDialogForm
55from code_saturne.model.TurbulenceModel import TurbulenceModel
56
57#-------------------------------------------------------------------------------
58# log config
59#-------------------------------------------------------------------------------
60
61logging.basicConfig()
62log = logging.getLogger("TurbulenceView")
63log.setLevel(GuiParam.DEBUG)
64
65#-------------------------------------------------------------------------------
66# Advanced dialog
67#-------------------------------------------------------------------------------
68
69class TurbulenceAdvancedOptionsDialogView(QDialog, Ui_TurbulenceAdvancedOptionsDialogForm):
70    """
71    Advanced dialog
72    """
73    def __init__(self, parent, case, default):
74        """
75        Constructor
76        """
77        QDialog.__init__(self, parent)
78
79        Ui_TurbulenceAdvancedOptionsDialogForm.__init__(self)
80        self.setupUi(self)
81
82        self.case = case
83        self.case.undoStopGlobal()
84
85        self.labelTurbDiff.hide()
86        self.comboBoxTurbDiff.hide()
87        self.turbDiff = None
88
89        self.default = default
90        self.result  = self.default.copy()
91
92        if default['model'] in ('k-epsilon', 'k-epsilon-PL'):
93            title = self.tr("Options for k-epsilon model")
94        elif default['model'] in ('Rij-epsilon', 'Rij-SSG', 'Rij-EBRSM'):
95            title = self.tr("Options for Rij-epsilon model")
96
97            self.labelTurbDiff.show()
98            self.comboBoxTurbDiff.show()
99            self.turbDiff = ComboModel(self.comboBoxTurbDiff, 2, 1)
100            self.turbDiff.addItem(self.tr("Scalar diffusivity (Shir model)"), 'shir')
101            self.turbDiff.addItem(self.tr("Tensorial diffusivity (Daly and Harlow model)"), 'daly_harlow')
102
103            # Initialization of turb diff model
104            self.turbDiff.setItem(str_model=str(self.result['turb_diff']))
105
106        elif default['model'] == 'k-omega-SST':
107            title = self.tr("Options for k-omega-SST model")
108        elif default['model'] == 'v2f-BL-v2/k':
109            title = self.tr("Options for v2f-BL-v2/k model")
110        elif default['model'] == 'Spalart-Allmaras':
111            title = self.tr("Options for Spalart-Allmaras model")
112
113        self.setWindowTitle(title)
114
115        self.checkBoxGravity.setEnabled(True)
116        self.comboBoxWallFunctions.setEnabled(True)
117
118        if default['model'] == 'Rij-EBRSM':
119            # Combo - piecewise laws (iwallf=2,3) unavailable through the GUI
120            self.wallFunctions = ComboModel(self.comboBoxWallFunctions, 2, 1)
121            self.wallFunctions.addItem(self.tr("No wall function"), '0')
122            self.wallFunctions.addItem(self.tr("2-scale model (all y+)"), '7')
123
124            # Initialization of wall function model
125            self.wallFunctions.setItem(str_model=str(self.result['wall_function']))
126
127        elif default['model'] == 'v2f-BL-v2/k':
128            self.wallFunctions = ComboModel(self.comboBoxWallFunctions, 1, 1)
129            self.wallFunctions.addItem(self.tr("No wall function"), '0')
130            self.comboBoxWallFunctions.setEnabled(False)
131        elif default['model'] == 'Spalart-Allmaras':
132            self.wallFunctions = ComboModel(self.comboBoxWallFunctions, 1, 1)
133            self.wallFunctions.addItem(self.tr("One scale model (log law)"), '2')
134            self.comboBoxWallFunctions.setEnabled(False)
135        elif default['model'] == 'k-omega-SST':
136            # Combo - power law (iwallf=1) unavailable through the GUI
137            self.wallFunctions = ComboModel(self.comboBoxWallFunctions, 5, 1)
138            self.wallFunctions.addItem(self.tr("No wall function"), '0')
139            self.wallFunctions.addItem(self.tr("1-scale model (log law)"), '2')
140            self.wallFunctions.addItem(self.tr("2-scale model (log law)"), '3')
141            self.wallFunctions.addItem(self.tr("2-scale model (all y+)"), '7')
142            self.wallFunctions.addItem(self.tr("Scalable 2-scale model (log law)"), '4')
143
144            # Initialization of wall function model
145            self.wallFunctions.setItem(str_model=str(self.result['wall_function']))
146        else:
147            # Combo - power law (iwallf=1) unavailable through the GUI
148            self.wallFunctions = ComboModel(self.comboBoxWallFunctions, 4, 1)
149            self.wallFunctions.addItem(self.tr("No wall function"), '0')
150            self.wallFunctions.addItem(self.tr("1-scale model (log law)"), '2')
151            self.wallFunctions.addItem(self.tr("2-scale model (log law)"), '3')
152            self.wallFunctions.addItem(self.tr("Scalable 2-scale model (log law)"), '4')
153
154            # Initialization of wall function model
155            self.wallFunctions.setItem(str_model=str(self.result['wall_function']))
156
157        # Initialization gravity terms
158        if self.result['gravity_terms'] == 'on':
159            self.checkBoxGravity.setChecked(True)
160        else:
161            self.checkBoxGravity.setChecked(False)
162
163        self.case.undoStartGlobal()
164
165
166    def get_result(self):
167        """
168        Method to get the result
169        """
170        return self.result
171
172
173    def accept(self):
174        """
175        Method called when user clicks 'OK'
176        """
177        if self.checkBoxGravity.isChecked():
178            self.result['gravity_terms'] = "on"
179        else:
180            self.result['gravity_terms'] = "off"
181        self.result['wall_function'] = \
182          int(self.wallFunctions.dicoV2M[str(self.comboBoxWallFunctions.currentText())])
183        if self.turbDiff:
184            self.result['turb_diff'] = self.turbDiff.dicoV2M[str(self.comboBoxTurbDiff.currentText())]
185
186        QDialog.accept(self)
187
188
189    def reject(self):
190        """
191        Method called when user clicks 'Cancel'
192        """
193        QDialog.reject(self)
194
195
196#-------------------------------------------------------------------------------
197# Main view class
198#-------------------------------------------------------------------------------
199
200class TurbulenceView(QWidget, Ui_TurbulenceForm):
201    """
202    Class to open Turbulence Page.
203    """
204    def __init__(self, parent=None, case=None):
205        """
206        Constructor
207        """
208        QWidget.__init__(self, parent)
209
210        Ui_TurbulenceForm.__init__(self)
211        self.setupUi(self)
212
213        self.case = case
214        self.case.undoStopGlobal()
215        self.model = TurbulenceModel(self.case)
216
217        # Combo model
218
219        self.modelTurbModel = ComboModel(self.comboBoxTurbModel,10,1)
220
221        self.modelTurbModel.addItem(self.tr("No model (i.e. laminar flow)"), "off")
222
223        # RANS - Algebraic
224        self.modelTurbModel.addItemGroup(self.tr("RANS - Algebraic"))
225        self.modelTurbModel.addItem(self.tr("Mixing length"), "mixing_length", groupName="RANS - Algebraic")
226
227        # RANS - 1st order
228        self.modelTurbModel.addItemGroup(self.tr("RANS - 1st order"))
229
230        e = {"k-epsilon-PL": "k-\u03B5 Linear Production",
231             "v2f-BL-v2/k": "v\u00B2-f BL-v\u00B2/k",
232             "k-omega-SST": "k-\u03C9 SST",
233             "Spalart-Allmaras": "Spalart-Allmaras"}
234
235        if QT_API == "PYQT4":
236            e["k-epsilon-PL"] = "k-epsilon Linear Production"
237            e["v2f-BL-v2/k"] = "v2f BL-v2/k"
238            e["k-omega-SST"] = "k-omega SST"
239
240        for k in ("k-epsilon-PL", "v2f-BL-v2/k",
241                  "k-omega-SST", "Spalart-Allmaras"):
242            self.modelTurbModel.addItem(self.tr(e[k]), k,
243                                        groupName="RANS - 1st order")
244
245        # RANS - 2nd order
246        self.modelTurbModel.addItemGroup(self.tr("RANS - 2nd order"))
247
248        e = {"Rij-SSG": "R\u1D62\u2C7C-\u03B5 SSG",
249             "Rij-EBRSM": "R\u1D62\u2C7C-\u03B5 EBRSM"}
250
251        if QT_API == "PYQT4":
252            e["Rij-SSG"] = "Rij-SSG"
253            e["Rij-EBRSM"] = "Rij-EBRSM"
254
255        for k in ("Rij-SSG", "Rij-EBRSM"):
256            self.modelTurbModel.addItem(self.tr(e[k]), k,
257                                        groupName="RANS - 2nd order")
258
259        # LES
260        self.modelTurbModel.addItemGroup(self.tr("LES"))
261
262        self.modelTurbModel.addItem(self.tr("Smagorinsky"),
263                                    "LES_Smagorinsky",
264                                    groupName="LES")
265        self.modelTurbModel.addItem(self.tr("Standard dynamic model"),
266                                    "LES_dynamique",
267                                    groupName="LES")
268        self.modelTurbModel.addItem(self.tr("WALE"),
269                                    "LES_WALE",
270                                    groupName="LES")
271
272        # Others
273        self.modelTurbModel.addItemGroup(self.tr(""))
274        self.modelTurbModel.addItemGroup(self.tr("Others"))
275
276        e = {"Rij-epsilon": "R\u1D62\u2C7C-\u03B5 LRR",
277             "k-epsilon": "k-\u03B5"}
278
279        if QT_API == "PYQT4":
280            e["Rij-epsilon"] = "Rij-LRR"
281            e["k-epsilon"] = "k-epsilon"
282
283        for k in ("Rij-epsilon", "k-epsilon"):
284            self.modelTurbModel.addItem(self.tr(e[k]), k,
285                                        groupName="Others")
286
287        self.modelLength = ComboModel(self.comboBoxLength,2,1)
288        self.modelLength.addItem(self.tr("Automatic"), 'automatic')
289        self.modelLength.addItem(self.tr("Prescribed"), 'prescribed')
290        self.comboBoxLength.setSizeAdjustPolicy(QComboBox.AdjustToContents)
291
292        # Connections
293
294        self.comboBoxTurbModel.activated[str].connect(self.slotTurbulenceModel)
295        self.pushButtonAdvanced.clicked.connect(self.slotAdvancedOptions)
296        self.lineEditLength.textChanged[str].connect(self.slotLengthScale)
297
298        self.lineEditV0.textChanged[str].connect(self.slotVelocity)
299        self.comboBoxLength.activated[str].connect(self.slotLengthChoice)
300        self.lineEditL0.textChanged[str].connect(self.slotLength)
301
302        # Frames display
303
304        self.frameAdvanced.hide()
305        self.frameLength.hide()
306
307        # Validators
308
309        validator = DoubleValidator(self.lineEditLength, min=0.0)
310        validator.setExclusiveMin(True)
311        self.lineEditLength.setValidator(validator)
312
313        validatorV0 = DoubleValidator(self.lineEditV0, min=0.0)
314        self.lineEditV0.setValidator(validatorV0)
315
316        validatorL0 = DoubleValidator(self.lineEditL0, min=0.0)
317        self.lineEditL0.setValidator(validatorL0)
318
319        # Update the turbulence models list with the calculation features
320
321        for turb in self.model.turbulenceModels():
322            if turb not in self.model.turbulenceModelsList():
323                self.modelTurbModel.disableItem(str_model=turb)
324
325        # Select the turbulence model
326
327        model = self.model.getTurbulenceModel()
328        self.modelTurbModel.setItem(str_model=model)
329        self.__initializeView()
330
331        # Length scale
332
333        l_scale = self.model.getLengthScale()
334        self.lineEditLength.setText(str(l_scale))
335
336        # Initialization
337
338        v = self.model.getVelocity()
339        self.lineEditV0.setText(str(v))
340
341        init_length_choice = self.model.getLengthChoice()
342        self.modelLength.setItem(str_model=init_length_choice)
343        if init_length_choice == 'automatic':
344            self.lineEditL0.setText(str())
345            self.lineEditL0.hide()
346            self.labelUnitL0.hide()
347        else:
348            self.lineEditL0.show()
349            self.labelUnitL0.show()
350            l = self.model.getLength()
351            self.lineEditL0.setText(str(l))
352
353        self.case.undoStartGlobal()
354
355
356    def __initializeView(self):
357        """
358        Private Method.
359        initalize view for a turbulence model
360        """
361        model = self.model.getTurbulenceModel()
362
363        self.frameAdvanced.hide()
364        self.frameLength.hide()
365        self.groupBoxReferenceValues.hide()
366
367        if model not in ('off', 'mixing_length', 'LES_Smagorinsky', 'LES_dynamique', 'LES_WALE'):
368            self.groupBoxReferenceValues.show()
369
370        if model == 'mixing_length':
371            self.frameLength.show()
372            self.frameAdvanced.hide()
373            self.model.getLengthScale()
374        elif model not in ('off', 'LES_Smagorinsky', 'LES_dynamique', 'LES_WALE', 'Spalart-Allmaras'):
375            self.frameLength.hide()
376            self.frameAdvanced.show()
377
378        if model in ('off', 'LES_Smagorinsky', 'LES_dynamique', 'LES_WALE', 'Spalart-Allmaras'):
379            self.line.hide()
380        else:
381            self.line.show()
382
383
384    @pyqtSlot(str)
385    def slotLengthScale(self, text):
386        """
387        Private slot.
388        Input XLOMLG.
389        """
390        if self.lineEditLength.validator().state == QValidator.Acceptable:
391            l_scale = from_qvariant(text, float)
392            self.model.setLengthScale(l_scale)
393
394
395    @pyqtSlot(str)
396    def slotTurbulenceModel(self, text):
397        """
398        Private slot.
399        Input ITURB.
400        """
401        model = self.modelTurbModel.dicoV2M[str(text)]
402        self.model.setTurbulenceModel(model)
403        self.__initializeView()
404
405    @pyqtSlot(str)
406    def slotVelocity(self,  text):
407        """
408        Private slot.
409        Input reference velocity.
410        """
411        if self.lineEditV0.validator().state == QValidator.Acceptable:
412            v = from_qvariant(text, float)
413            self.model.setVelocity(v)
414
415
416    @pyqtSlot(str)
417    def slotLengthChoice(self,text):
418        """
419        Private slot.
420        Input mode for reference length.
421        """
422        choice = self.modelLength.dicoV2M[str(text)]
423        self.model.setLengthChoice(choice)
424        if choice == 'automatic':
425            self.lineEditL0.setText(str())
426            self.lineEditL0.hide()
427            self.labelUnitL0.hide()
428        else:
429            self.lineEditL0.show()
430            self.labelUnitL0.show()
431            value = self.model.getLength()
432            self.lineEditL0.setText(str(value))
433        log.debug("slotlengthchoice-> %s" % choice)
434
435
436    @pyqtSlot(str)
437    def slotLength(self,  text):
438        """
439        Private slot.
440        Input reference length.
441        """
442        if self.lineEditL0.validator().state == QValidator.Acceptable:
443            l = from_qvariant(text, float)
444            self.model.setLength(l)
445
446
447    @pyqtSlot()
448    def slotAdvancedOptions(self):
449        """
450        Private slot.
451        Ask one popup for advanced specifications
452        """
453        default = {}
454        default['model']         = self.model.getTurbulenceModel()
455        default['wall_function'] = self.model.getWallFunction()
456        default['turb_diff']     = self.model.getTurbDiffModel()
457        default['gravity_terms'] = self.model.getGravity()
458        log.debug("slotAdvancedOptions -> %s" % str(default))
459
460        dialog = TurbulenceAdvancedOptionsDialogView(self, self.case, default)
461        if dialog.exec_():
462            result = dialog.get_result()
463            log.debug("slotAdvancedOptions -> %s" % str(result))
464            self.model.setTurbulenceModel(result['model'])
465            self.model.setWallFunction(result['wall_function'])
466            self.model.setTurbDiffModel(result['turb_diff'])
467            self.model.setGravity(result['gravity_terms'])
468
469
470#-------------------------------------------------------------------------------
471# End
472#-------------------------------------------------------------------------------
473