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#-------------------------------------------------------------------------------
26# Library modules import
27#-------------------------------------------------------------------------------
28
29import string
30import unittest
31
32#-------------------------------------------------------------------------------
33# Application modules import
34#-------------------------------------------------------------------------------
35
36from code_saturne.model.XMLvariables import Model, Variables
37from code_saturne.model.XMLmodel     import ModelTest
38from code_saturne.model.XMLengine import *
39from code_saturne.model.TurbulenceNeptuneModel import TurbulenceModelsDescription
40
41class NumericalParamEquatModel(Model):
42
43    """
44    This class manages the turbulence objects in the XML file
45    """
46
47    def __init__(self, case) :
48        """
49        Constuctor.
50        """
51        #
52        # XML file parameters
53        self.case            = case
54        self.XMLThermo       = self.case.xmlGetNode('thermophysical_models')
55        self.XMLNodeVariable = self.XMLThermo.xmlGetNode('variables')
56        self.XMLClosure      = self.case.xmlGetNode('closure_modeling')
57        self.XMLTurbulence   = self.XMLClosure.xmlInitNode('turbulence')
58        self.XMLTurbVariable = self.XMLTurbulence.xmlInitNode('variables')
59        self.XMLAddScalar    = self.case.xmlInitNode('additional_scalars')
60        self.XMLScalar       = self.XMLAddScalar.xmlInitNode('scalars')
61        self.XMLnonCond      = self.XMLThermo.xmlInitNode('non_condensable_list')
62
63        self.imgra_model = ['iterative_handling', \
64                            'sweep_linear', \
65                            'sweep_linear_ext_neigh', \
66                            'least_square_linear', \
67                            'least_square_linear_ext_neigh', \
68                            'iterative_handling_weighted', \
69                            'least_square_linear_weighted', \
70                            'least_square_linear_ext_neigh_weighted']
71
72
73    def defaultValues(self) :
74        default = {}
75
76        default['max_iter_number']                  = 10000
77        default['solver_precision']                 = 1e-5
78        default['solver_precision_alpha']           = 1e-8
79        default['solver_precision_enthal']          = 1e-7
80        default['slope_test']                       = 'on'
81        default['flux_reconstruction']              = 'off'
82        default['order_scheme']                     = 'solu'
83        default['order_scheme_pressure_turbulence'] = 'upwind'
84        default['solver']                           = 'automatic'
85        default['gradient_reconstruction']          = 'sweep_linear_ext_neigh'
86        return default
87
88
89    def getVariableList(self) :
90        """
91        return list of variables
92        """
93        list = []
94        from code_saturne.model.MainFieldsModel import MainFieldsModel
95        for node in self.XMLNodeVariable.xmlGetNodeList('variable') :
96            if self._isPressure(node) != 1 :
97                # control to add enthalpy only if solved!!!
98                if self._isEnthalpy(node) == 1 :
99                    field = node['field_id']
100                    if MainFieldsModel(self.case).getEnergyResolution(field) == "on":
101                        list.append(node['label'])
102                else:
103                    list.append(node['label'])
104
105        if self.XMLTurbVariable != None:
106            for node in self.XMLTurbVariable.xmlGetNodeList('variable') :
107                list.append(node['label'])
108
109        for node in self.XMLScalar.xmlGetNodeList('variable') :
110            list.append(node['label'])
111
112        for node in self.XMLnonCond.xmlGetNodeList('variable') :
113            list.append(node['label'])
114
115        del MainFieldsModel
116        return list
117
118
119    def _isPressure(self, node) :
120        """
121        Return : 1 if name of node is 'pressure', 0 if not
122        """
123        if node and node['name'] == 'pressure':
124            return 1
125        else:
126            return 0
127
128
129    def _isTurbulenceVariable(self, node) :
130        """
131        Return : 1 if name of node is a turbulence variable, 0 if not
132        """
133        if node and node['name'] in TurbulenceModelsDescription.turbulenceVariables['all'] :
134            return 1
135        else:
136            return 0
137
138
139    def _isAlpha(self, node) :
140        """
141        Return : 1 if name of node is 'alpha', 0 if not
142        """
143        if node and node['name'] == 'volume_fraction':
144            return 1
145        else:
146            return 0
147
148
149    def _isEnthalpy(self, node):
150        """
151        Return : 1 if name of node is 'enthalpy', 0 if not
152        """
153        if node and node['name'] == 'enthalpy':
154            return 1
155        else:
156            return 0
157
158
159    def _getSchemeLabelNode(self, label):
160        """ Private method: return node called with label'label' for scheme nodes"""
161        for node in self.XMLNodeVariable.xmlGetNodeList('variable') :
162            if node['label'] == label:
163                if node['label'] == 'Pressure':
164                    raise ValueError("This method does not run with pressure")
165                else:
166                    return node
167        for node in self.XMLTurbVariable.xmlGetNodeList('variable') :
168            if node['label'] == label:
169                return node
170
171        for node in self.XMLScalar.xmlGetNodeList('variable') :
172            if node['label'] == label:
173                return node
174
175        for node in self.XMLnonCond.xmlGetNodeList('variable') :
176            if node['label'] == label:
177                return node
178
179        raise ValueError("This label does not exist: " + label)
180
181
182    @Variables.undoGlobal
183    def setSchemeModel(self, label, value) :
184        """
185        Put value of order scheme for variable or scalar labelled label
186        only if it 's different of default value
187        """
188        self.isInList(value, ('upwind', 'centered', 'solu'))
189        node = self._getSchemeLabelNode(label)
190        defval = self.defaultValues()['order_scheme']
191        if (self._isTurbulenceVariable(node)) :
192            defval = self.defaultValues()['order_scheme_pressure_turbulence']
193
194        if value == defval :
195            node.xmlRemoveChild('scheme')
196        else:
197            n = node.xmlInitNode('scheme')
198            n['choice'] = value
199
200        if value == "upwind":
201            self.setSlopeTestStatus(label, "off")
202        else:
203            self.setSlopeTestStatus(label, "on")
204
205
206    @Variables.noUndo
207    def getSchemeModel(self, label) :
208        """
209        Return value of order scheme for variable labelled label
210        """
211        node = self._getSchemeLabelNode(label)
212        value = self.defaultValues()['order_scheme']
213        if (self._isTurbulenceVariable(node)) :
214            value = self.defaultValues()['order_scheme_pressure_turbulence']
215        n = node.xmlGetNode('scheme')
216        if n:
217            value = n['choice']
218        return value
219
220
221    @Variables.undoLocal
222    def setSlopeTestStatus(self, label, status) :
223        """
224        Put status of slope test for variable labelled label
225        """
226        self.isOnOff(status)
227        node = self._getSchemeLabelNode(label)
228        if status == self.defaultValues()['slope_test']:
229            node.xmlRemoveChild('slope_test')
230        else:
231            n = node.xmlInitNode('slope_test')
232            n['status'] = status
233
234
235    @Variables.noUndo
236    def getSlopeTestStatus(self, label) :
237        """
238        Return value of slope test for variable labelled label
239        """
240        node = self._getSchemeLabelNode(label)
241        value = self.defaultValues()['slope_test']
242        n = node.xmlGetNode('slope_test')
243        if n:
244            value = n['status']
245        return value
246
247
248    @Variables.undoLocal
249    def setSolverModel(self, label, value) :
250        """
251        Put value of solver for variable or scalar labelled label
252        """
253        self.isInList(value, ('automatic', 'jacobi', 'pcg', 'cgstab', 'jacobi_saturne', 'pcg_saturne', 'bicgstab_saturne', 'bicgstab2_saturne', 'gmres_saturne', 'gauss_seidel_saturne', 'sym_gauss_seidel_saturne', 'pcr3_saturne'))
254        node = self._getSchemeLabelNode(label)
255        default = self.defaultValues()['solver']
256        if value == default:
257            node.xmlRemoveChild('solver')
258        else:
259            n = node.xmlInitNode('solver')
260            n['choice'] = value
261
262
263    @Variables.noUndo
264    def getSolverModel(self, label) :
265        """
266        Return value of solver for variable labelled label
267        """
268        node = self._getSchemeLabelNode(label)
269        value = self.defaultValues()['solver']
270        n = node.xmlGetNode('solver')
271        if n:
272            value = n['choice']
273        return value
274
275
276    @Variables.undoLocal
277    def setSolverPrecision(self, label, value) :
278        """
279        Put value of solveur precision for variable labelled label
280        """
281        self.isPositiveFloat(value)
282        node = self._getSchemeLabelNode(label)
283        default = self.defaultValues()['solver_precision']
284        if self._isAlpha(node):
285            default = self.defaultValues()['solver_precision_alpha']
286        elif self._isEnthalpy(node):
287            default = self.defaultValues()['solver_precision_enthal']
288
289        if value != default:
290            node.xmlSetData('solver_precision', value)
291        else:
292            node.xmlRemoveChild('solver_precision')
293
294
295    @Variables.noUndo
296    def getSolverPrecision(self, label) :
297        """
298        Return value of solveur precision for variable labelled label
299        """
300        node = self._getSchemeLabelNode(label)
301
302        default = self.defaultValues()['solver_precision']
303        if self._isAlpha(node):
304            default = self.defaultValues()['solver_precision_alpha']
305        elif self._isEnthalpy(node):
306            default = self.defaultValues()['solver_precision_enthal']
307
308        value = node.xmlGetDouble('solver_precision')
309        if value == None:
310            value = default
311        return value
312
313
314    @Variables.undoLocal
315    def setMaximumIteration(self, label, value) :
316        """
317        Put number of maximum iterations for variable labelled label
318        """
319        self.isInt(value)
320        node = self._getSchemeLabelNode(label)
321        default = self.defaultValues()['max_iter_number']
322        if value != default :
323            node.xmlSetData('max_iter_number', value)
324        else:
325            node.xmlRemoveChild('max_iter_number')
326
327
328    @Variables.noUndo
329    def getMaximumIteration(self, label) :
330        """
331        Return number of maximum iterations for variable labelled label
332        """
333        node = self._getSchemeLabelNode(label)
334        value = node.xmlGetInt('max_iter_number')
335        if value == None:
336            value = self.defaultValues()['max_iter_number']
337        return value
338
339
340    def getPressureNodefields(self):
341        for node in self.XMLNodeVariable.xmlGetNodeList('variable') :
342            if node['label'] == 'Pressure':
343                return node
344
345#-------------------------------------------------------------------------------
346# DefineUsersScalars test case
347#-------------------------------------------------------------------------------
348
349class NumericalParamEquatTestCase(ModelTest):
350    """
351    """
352    def checkNumericalParamEquatInstantiation(self):
353        """Check whether the NumericalParamEquationModel class could be instantiated"""
354        model = None
355        model = NumericalParamEquatModel(self.case)
356        assert model != None, 'Could not instantiate NumericalParamEquationModel'
357
358
359    def checkGetVariableList(self):
360        """Check whether the NumericalParamEquationModel class could get the VariableList"""
361        from code_saturne.model.MainFieldsModel import MainFieldsModel
362        MainFieldsModel(self.case).addField()
363        mdl = NumericalParamEquatModel(self.case)
364        assert mdl.getVariableList() == ['enthalpy1', 'alpha1', 'U1', 'V1', 'W1'],\
365            'Could not get VariableList'
366
367
368    def checkGetandSetSchemeModel(self):
369        """Check whether the NumericalParamEquationModel class could be set and get SchemeModel"""
370        from code_saturne.model.MainFieldsModel import MainFieldsModel
371        MainFieldsModel(self.case).addField()
372        mdl = NumericalParamEquatModel(self.case)
373        mdl.setSchemeModel('pressure','solu')
374        doc = '''<variable field_id="none" label="Pressure" name="pressure">
375                         <listing_printing status="on"/>
376                         <postprocessing_recording status="on"/>
377                         <scheme choice="solu"/>
378                 </variable>'''
379        assert mdl.getPressureNodefields() == self.xmlNodeFromString(doc),\
380            'Could not set SchemeModel'
381        assert mdl.getSchemeModel('Pressure') == 'solu',\
382            'Could not get SchemeModel'
383
384
385    def checkGetandSetSlopeTestStatus(self):
386        """Check whether the NumericalParamEquationModel class could be set and get SlopeTestStatus"""
387        from code_saturne.model.MainFieldsModel import MainFieldsModel
388        MainFieldsModel(self.case).addField()
389        mdl = NumericalParamEquatModel(self.case)
390        mdl.setSlopeTestStatus('Pressure','off')
391        doc = '''<variable field_id="none" label="Pressure" name="pressure">
392                         <listing_printing status="on"/>
393                         <postprocessing_recording status="on"/>
394                         <slope_test status="off"/>
395                 </variable>'''
396        assert mdl.getPressureNodefields() == self.xmlNodeFromString(doc),\
397            'Could not set SlopeTestStatus'
398        assert mdl.getSlopeTestStatus('Pressure') == 'off',\
399            'Could not get SlopeTestStatus'
400
401
402    def checkGetandSetSolverModel(self):
403        """Check whether the NumericalParamEquationModel class could be set and get SolverModel"""
404        from code_saturne.model.MainFieldsModel import MainFieldsModel
405        MainFieldsModel(self.case).addField()
406        mdl = NumericalParamEquatModel(self.case)
407        mdl.setSolverModel('Pressure','jacobi')
408        doc = '''<variable field_id="none" label="Pressure" name="pressure">
409                         <listing_printing status="on"/>
410                         <postprocessing_recording status="on"/>
411                         <solver choice="jacobi"/>
412                 </variable>'''
413        assert mdl.getPressureNodefields() == self.xmlNodeFromString(doc),\
414            'Could not set SolverModel'
415        assert mdl.getSolverModel('Pressure') == 'jacobi',\
416            'Could not get SolverModel'
417
418
419    def checkGetandSetSolverPrecision(self):
420        """Check whether the NumericalParamEquationModel class could be set and get SolverPrecision"""
421        from code_saturne.model.MainFieldsModel import MainFieldsModel
422        MainFieldsModel(self.case).addField()
423        mdl = NumericalParamEquatModel(self.case)
424        mdl.setSolverPrecision('Pressure',56.23)
425        doc = '''<variable field_id="none" label="Pressure" name="pressure">
426                         <listing_printing status="on"/>
427                         <postprocessing_recording status="on"/>
428                         <solver_precision>
429                                 56.23
430                         </solver_precision>
431                 </variable>'''
432        assert mdl.getPressureNodefields() == self.xmlNodeFromString(doc),\
433            'Could not set SolverPrecision'
434        assert mdl.getSolverPrecision('Pressure') == 56.23,\
435            'Could not get SolverPrecision'
436
437
438    def checkGetandSetMaximumIteration(self):
439        """Check whether the NumericalParamEquationModel class could be set and get MaximumIteration"""
440        from code_saturne.model.MainFieldsModel import MainFieldsModel
441        MainFieldsModel(self.case).addField()
442        mdl = NumericalParamEquatModel(self.case)
443        mdl.setMaximumIteration('Pressure',18)
444        doc = '''<variable field_id="none" label="Pressure" name="pressure">
445                         <listing_printing status="on"/>
446                         <postprocessing_recording status="on"/>
447                         <max_iter_number>
448                                 18
449                         </max_iter_number>
450                 </variable>'''
451        assert mdl.getPressureNodefields() == self.xmlNodeFromString(doc),\
452            'Could not set MaximumIteration'
453        assert mdl.getMaximumIteration('Pressure') == 18,\
454            'Could not get MaximumIteration'
455
456
457def suite():
458    testSuite = unittest.makeSuite(NumericalParamEquatTestCase, "check")
459    return testSuite
460
461
462def runTest():
463    print("NumericalParamEquatTestCase")
464    runner = unittest.TextTestRunner()
465    runner.run(suite())
466