1
2# -*- coding: utf-8 -*-
3
4#-------------------------------------------------------------------------------
5
6# This file is part of Code_Saturne, a general-purpose CFD tool.
7#
8# Copyright (C) 1998-2021 EDF S.A.
9#
10# This program is free software; you can redistribute it and/or modify it under
11# the terms of the GNU General Public License as published by the Free Software
12# Foundation; either version 2 of the License, or (at your option) any later
13# version.
14#
15# This program is distributed in the hope that it will be useful, but WITHOUT
16# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18# details.
19#
20# You should have received a copy of the GNU General Public License along with
21# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22# Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
24#-------------------------------------------------------------------------------
25
26"""
27This module defines the 1D profile management page.
28
29This module defines the following classes:
30- ProfilesModel
31- ProfilesTestCase
32"""
33
34#-------------------------------------------------------------------------------
35# Library modules import
36#-------------------------------------------------------------------------------
37
38import os, sys, types, unittest
39
40#-------------------------------------------------------------------------------
41# Application modules import
42#-------------------------------------------------------------------------------
43
44from code_saturne.model.Common import *
45from code_saturne.model.XMLmodel import XMLmodel, ModelTest
46from code_saturne.model.XMLvariables import Model, Variables
47from code_saturne.model.OutputVolumicVariablesModel import OutputVolumicVariablesModel
48
49#-------------------------------------------------------------------------------
50# Model class
51#-------------------------------------------------------------------------------
52
53class ProfilesModel(Model):
54    """
55    1D profile management.
56    """
57    def __init__(self, case):
58        """
59        Constructor.
60        """
61        self.case = case
62        self.node_anal      = self.case.xmlInitNode('analysis_control')
63        self.node_prof      = self.node_anal.xmlInitNode('profiles')
64        self.node_model     = self.case.xmlInitNode('thermophysical_models')
65        self.node_model_vp  = self.node_model.xmlInitNode('velocity_pressure')
66        self.node_var_vp    = self.node_model_vp.xmlGetNodeList('variable')
67        self.node_pro_vp    = self.node_model_vp.xmlGetNodeList('property')
68
69        self.__var_prop_list = self.getVariablesAndVolumeProperties()
70        self.__var_prop_list_compat = self.dicoLabel2Name_compat.keys()
71
72
73    def __defaultValues(self):
74        """
75        Private method.
76        Returns a dictionnary with default values.
77        """
78        value = {}
79        value['nfreq']         = -1
80        value['formula']       =  "x = 0;\ny = s;\nz = 0;\n"
81        value['points']        =  200
82        value['label']         =  "profile"
83        value['choice']        =  "frequency"
84        value['frequency']     =  1
85        value['format']        =  "CSV"
86        value['snap_mode']     =  "snap_to_center"
87        value['interpolation'] =  "no"
88
89        return value
90
91
92    @Variables.noUndo
93    def getVariablesAndVolumeProperties(self):
94        """
95        Creates a dictionnary to connect name and label from
96        variables and properties.
97        """
98        mdl = OutputVolumicVariablesModel(self.case)
99
100        self.dicoLabel2Name = mdl.getVolumeFieldsLabel2Name(time_averages=True)
101        self.dicoLabel2Name_compat = mdl.getVolumeFieldsLabel2Name(time_averages=True,
102                                                                   get_components=True)
103
104
105        return list(self.dicoLabel2Name.keys())
106
107
108    @Variables.undoGlobal
109    def addProfile(self):
110        """
111        Public method.
112        Add a new profile and return a default label
113        """
114        label = self.__defaultValues()['label']
115        def_label = label + str(len(self.getProfilesLabelsList()) + 1)
116
117        # define default label
118        if def_label in self.getProfilesLabelsList():
119            i = 2
120            while def_label in self.getProfilesLabelsList():
121                def_label = label + str(len(self.getProfilesLabelsList()) + i)
122                i = i + 1
123
124        node = self.node_prof.xmlInitNode('profile', label = def_label)
125
126        return def_label
127
128
129    @Variables.undoLocal
130    def setFormula(self, label, str):
131        """
132        Public method.
133        Get coordinates for profile named I{label}
134        """
135        self.isInList(label, self.getProfilesLabelsList())
136        node = self.node_prof.xmlGetNode('profile', label = label)
137        node.xmlSetData('formula', str)
138
139
140    def getFormula(self, label):
141        """
142        Private method.
143        Gets coordinates for profile named I{label}.
144        """
145        self.isInList(label, self.getProfilesLabelsList())
146        node = self.node_prof.xmlGetNode('profile', label = label)
147        return node.xmlGetString('formula')
148
149
150    @Variables.undoLocal
151    def setNbPoint(self, label, NbPoint):
152        """
153        Public method.
154        Get coordinates for profile named I{label}
155        """
156        self.isInt(NbPoint)
157        self.isInList(label, self.getProfilesLabelsList())
158        node = self.node_prof.xmlGetNode('profile', label = label)
159        node.xmlSetData('points', NbPoint)
160
161
162    def getNbPoint(self, label):
163        """
164        Private method.
165        Gets coordinates for profile named I{label}.
166        """
167        self.isInList(label, self.getProfilesLabelsList())
168        node = self.node_prof.xmlGetNode('profile', label = label)
169        return node.xmlGetInt('points')
170
171
172    @Variables.undoLocal
173    def setSnapMode(self, label, mode):
174        """
175        """
176        node = self.node_prof.xmlGetNode('profile', label=label)
177        if mode == self.__defaultValues()['snap_mode']:
178            node.xmlRemoveChild('snap_mode')
179        else:
180            node.xmlSetData('snap_mode', mode)
181
182
183    @Variables.noUndo
184    def getSnapMode(self, label):
185        """
186        """
187        node = self.node_prof.xmlGetNode('profile', label = label)
188        mode = node.xmlGetString('snap_mode')
189        if not mode:
190            mode = self.__defaultValues()['snap_mode']
191        return mode
192
193
194    @Variables.undoLocal
195    def setProfileInterpolation(self, label, state):
196        """
197        """
198        node = self.node_prof.xmlGetNode('profile', label = label)
199        if state == self.__defaultValues()["interpolation"]:
200            node.xmlRemoveChild('interpolation')
201        else:
202            node.xmlSetData('interpolation', state)
203
204
205    @Variables.noUndo
206    def getProfileInterpolation(self, label):
207        """
208        """
209        node = self.node_prof.xmlGetNode('profile', label = label)
210        state = node.xmlGetString('interpolation')
211        if not state:
212            state = self.__defaultValues()["interpolation"]
213
214        return state
215
216
217    @Variables.noUndo
218    def getProfilesLabelsList(self):
219        """
220        Public method.
221        Returns the profiles labels list.
222        """
223        lst = []
224        for node in self.node_prof.xmlGetNodeList('profile'):
225            label = node['label']
226            lst.append(label)
227        return lst
228
229
230    @Variables.undoLocal
231    def setOutputType(self, label, choice):
232        """
233        Public method.
234        """
235        self.isInList(label, self.getProfilesLabelsList())
236        self.isInList(choice, ["end", "frequency", "time_value"])
237        node = self.node_prof.xmlGetNode('profile', label = label)
238        node.xmlSetData('output_type', choice)
239
240
241    @Variables.undoLocal
242    def setOutputFrequency(self, label, freq):
243        """
244        Public method.
245        """
246        self.isInList(label, self.getProfilesLabelsList())
247        node = self.node_prof.xmlGetNode('profile', label = label)
248        node.xmlSetData('output_frequency', freq)
249
250
251    @Variables.noUndo
252    def getOutputFrequency(self, label):
253        """
254        Public method.
255        """
256        self.isInList(label, self.getProfilesLabelsList())
257        node = self.node_prof.xmlGetNode('profile', label = label)
258        return node.xmlGetDouble('output_frequency')
259
260
261    @Variables.undoLocal
262    def setLabel(self, old_label, label):
263        """
264        Public method.
265        """
266        self.isInList(old_label, self.getProfilesLabelsList())
267        node = self.node_prof.xmlGetNode('profile', label = old_label)
268        node['label'] = label
269
270
271    @Variables.undoLocal
272    def setFormat(self, label, fmt):
273        """
274        Public method.
275        """
276        self.isInList(label, self.getProfilesLabelsList())
277        node = self.node_prof.xmlGetNode('profile', label = label)
278        node.xmlRemoveChild('format')
279        node.xmlAddChild('format', name=fmt)
280
281
282    @Variables.undoLocal
283    def setVariable(self, label, lst):
284        """
285        Public method.
286        """
287        self.isInList(label, self.getProfilesLabelsList())
288        node = self.node_prof.xmlGetNode('profile', label = label)
289        OutputVolumicVariablesModel(self.case).setVariablesAtNode(node, lst, time_averages=True, get_components=True)
290
291    @Variables.noUndo
292    def getVariable(self, label):
293        """
294        Public method.
295        """
296        self.isInList(label, self.getProfilesLabelsList())
297        node = self.node_prof.xmlGetNode('profile', label = label)
298        return OutputVolumicVariablesModel(self.case).getVariablesAtNode(node, time_averages=True, get_components=False)
299
300
301    @Variables.undoLocal
302    def deleteProfile(self, label):
303        """
304        Public method.
305        Deletes profile named I{label}.
306        """
307        self.isInList(label, self.getProfilesLabelsList())
308        node = self.node_prof.xmlGetNode('profile', label=label)
309        if node:
310            node.xmlRemoveNode()
311
312
313    @Variables.noUndo
314    def getProfileData(self, label):
315        """
316        Public method. Only for the GUI.
317        Get profile named label and return list of variables or properties,
318        frequency and coordinates.
319        """
320        self.isInList(label, self.getProfilesLabelsList())
321        node = self.node_prof.xmlGetNode('profile', label = label)
322        choice = node.xmlGetString('output_type')
323
324        if not choice:
325            choice = self.__defaultValues()['choice']
326            self.setOutputType(label, choice)
327
328        if choice == "time_value":
329            freq = node.xmlGetDouble('output_frequency')
330        else:
331            freq = node.xmlGetInt('output_frequency')
332        if not freq:
333            freq = self.__defaultValues()['frequency']
334            self.setOutputFrequency(label, freq)
335
336        f_node = node.xmlGetChildNode('format')
337        if not f_node:
338            fmt = self.__defaultValues()['format']
339            self.setFormat(label, fmt)
340        else:
341            fmt = f_node['name']
342
343        formula = self.getFormula(label)
344        if not formula:
345            formula = self.__defaultValues()['formula']
346            self.setFormula(label, formula)
347
348        NbPoint = self.getNbPoint(label)
349        if not NbPoint:
350            NbPoint = self.__defaultValues()['points']
351            self.setNbPoint(label, NbPoint)
352
353        lst = OutputVolumicVariablesModel(self.case).getVariablesAtNode(node, time_averages=True, get_components=True)
354
355        return label, fmt, lst, choice, freq, formula, NbPoint
356
357
358#-------------------------------------------------------------------------------
359# TimeAveragesModel test case
360#-------------------------------------------------------------------------------
361
362
363class ProfilesTestCase(ModelTest):
364    """
365    Unittest.
366    """
367    def checkProfilesModelInstantiation(self):
368        """Check whether the ProfilesModel class could be instantiated"""
369        model = None
370        model = ProfilesModel(self.case)
371        assert model != None, 'Could not instantiate ProfilesModel'
372
373
374    def checkSetProfile(self):
375        """Check whether the ProfilesModel class could set one profile"""
376        mdl = ProfilesModel(self.case)
377        mdl.setProfile('prof1.dat', ['VelocitU', 'VelocitV', 'VelocitW'], 20, 0.1, 0.2, 0.3, 2.1, 2.2, 2.3)
378        doc = '''<profiles>
379                    <profile label="prof1.dat">
380                            <var_prop name="velocity" component="0"/>
381                            <var_prop name="velocity" component="1"/>
382                            <var_prop name="velocity" component="2"/>
383                            <output_frequency>20</output_frequency>
384                            <x1>0.1</x1>
385                            <y1>0.2</y1>
386                            <z1>0.3</z1>
387                            <x2>2.1</x2>
388                            <y2>2.2</y2>
389                            <z2>2.3</z2>
390                    </profile>
391                 </profiles>'''
392
393        assert mdl.node_prof == self.xmlNodeFromString(doc),\
394            'Could not set profiles in ProfilesModel'
395
396
397    def checkReplaceProfile(self):
398        """Check whether the ProfilesModel class could replace profiles"""
399        mdl = ProfilesModel(self.case)
400        mdl.setProfile('prof1', ['VelocitU', 'VelocitV', 'VelocitW'], 20, 0.1, 0.2, 0.3, 2.1, 2.2, 2.3)
401        mdl.replaceProfile('prof1', 'premier', ['VelocitU'], 30, 0.1, 0.2, 0.3, 2.0, 2.0, 2.0)
402        doc = '''<profiles>
403                    <profile label="premier">
404                            <var_prop name="velocity" component="0"/>
405                            <output_frequency>30</output_frequency>
406                            <x1>0.1</x1>
407                            <y1>0.2</y1>
408                            <z1>0.3</z1>
409                            <x2>2.0</x2>
410                            <y2>2.0</y2>
411                            <z2>2.0</z2>
412                    </profile>
413                 </profiles>'''
414
415        assert mdl.node_prof == self.xmlNodeFromString(doc),\
416            'Could not replace profiles in ProfilesModel'
417
418
419    def checkDeleteProfile(self):
420        """Check whether the ProfilesModel class could delete profiles"""
421        mdl = ProfilesModel(self.case)
422
423        mdl.setProfile('prof1.dat', ['VelocitU', 'VelocitV', 'VelocitW'], 20, 0.1, 0.2, 0.3, 2.1, 2.2, 2.3)
424        mdl.setProfile('prof2.dat', ['VelocitU'], 20, 0.9, 0.8, 0.7, 9.1, 9.2, 9.3)
425        mdl.deleteProfile('prof1')
426        doc = '''<profiles>
427                    <profile label="prof2.dat">
428                            <var_prop name="velocity" component="0"/>
429                            <output_frequency>20</output_frequency>
430                            <x1>0.9</x1>
431                            <y1>0.8</y1>
432                            <z1>0.7</z1>
433                            <x2>9.1</x2>
434                            <y2>9.2</y2>
435                            <z2>9.3</z2>
436                    </profile>
437                 </profiles>'''
438        assert mdl.node_prof == self.xmlNodeFromString(doc),\
439            'Could not delete profiles in ProfilesModel'
440
441
442    def checkGetVarProfile(self):
443        """Check whether the ProfilesModel class could get one profile"""
444        mdl = ProfilesModel(self.case)
445        mdl.setProfile('prof1.dat', ['VelocitU', 'VelocitV', 'VelocitW'], 20, 0.1, 0.2, 0.3, 2.1, 2.2, 2.3)
446        mdl.setProfile('prof2.dat', ['VelocitU'], 20, 0.9, 0.8, 0.7, 9.1, 9.2, 9.3)
447        prof = ('prof2.dat', ['VelocitU'], 20, 0.9, 0.8, 0.7, 9.1, 9.2, 9.3)
448
449        assert mdl.getProfileData('prof2') == prof,\
450            'Could not get values for profile named label in ProfilesModel'
451
452
453def suite():
454    testSuite = unittest.makeSuite(ProfilesTestCase, "check")
455    return testSuite
456
457
458def runTest():
459    print(__file__)
460    runner = unittest.TextTestRunner()
461    runner.run(suite())
462
463#-------------------------------------------------------------------------------
464# End
465#-------------------------------------------------------------------------------
466