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