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 lagrangian two phase flow modelling management. 27 28This module contains the following classes and function: 29- LagrangianBoundariesModel 30- LagrangianBoundariesTestCase 31""" 32 33 34#------------------------------------------------------------------------------- 35# Library modules import 36#------------------------------------------------------------------------------- 37 38 39import sys, unittest, logging 40 41 42#------------------------------------------------------------------------------- 43# Application modules import 44#------------------------------------------------------------------------------- 45 46 47from code_saturne.model.Common import * 48from code_saturne.model.XMLvariables import Model, Variables 49from code_saturne.model.LagrangianModel import LagrangianModel 50from code_saturne.model.CoalCombustionModel import CoalCombustionModel 51 52 53#------------------------------------------------------------------------------- 54# log config 55#------------------------------------------------------------------------------- 56 57 58logging.basicConfig() 59log = logging.getLogger("LagrangianBoundariesModel") 60log.setLevel(GuiParam.DEBUG) 61 62 63#------------------------------------------------------------------------------- 64# lagrangian model class 65#------------------------------------------------------------------------------- 66 67 68class LagrangianBoundariesModel(Model): 69 """ 70 Manage the input/output markups in the xml doc about Lagrangian module. 71 """ 72 def __init__(self, case): 73 """ 74 Constructor. 75 """ 76 self.case = case 77 self.node_boundaries = self.case.root().xmlInitNode('boundary_conditions') 78 self.default = self.defaultParticlesBoundaryValues() 79 80 81 def defaultParticlesBoundaryValues(self): 82 """ 83 Return a dictionnary which contains default values. 84 """ 85 default = {} 86 default['particles'] = "inlet" 87 default['n_is'] = 0 88 default['number'] = 10 89 default['frequency'] = 1 90 default['statistical_groups'] = 0. 91 default['statistical_weight_choice'] = "prescribed" 92 default['statistical_weight'] = 1.0 93 default['mass_flow_rate'] = 0. 94 default['density'] = 1000. 95 default['velocity_choice'] = "fluid" 96 default['velocity_norm'] = 0. 97 default['velocity_value'] = 0. 98 default['temperature_choice'] = "fluid" 99 default['temperature'] = 20. 100 default['specific_heat'] = 1400. 101 default['emissivity'] = 0.9 102 default['diameter'] = 1.0e-5 103 default['diameter_standard_deviation'] = 0. 104 default['fouling_index'] = 1. 105 default['coal_number'] = 1 106 default['coal_temperature'] = 800. 107 return default 108 109 def getFoulingStatus(self): 110 """ 111 Return fouling status 112 """ 113 return LagrangianModel(self.case).getCoalFouling() 114 115 116 @Variables.undoGlobal 117 def setBoundaryChoice(self, nature, labelbc, value): 118 """ 119 Update value for the boundary condition. Here we defined the xml nodes 120 'self.node_boundary' and 'self.node_particles' used in many functions. 121 """ 122 if nature == "inlet": 123 self.isInList(value, ["inlet", "bounce", "outlet"]) 124 elif nature == "outlet": 125 self.isInList(value, ["outlet"]) 126 elif nature == "free_inlet_outlet": 127 self.isInList(value, ["inlet", "outlet"]) 128 elif nature == "imposed__outlet": 129 self.isInList(value, ["outlet"]) 130 elif nature == "symmetry": 131 self.isInList(value, ["part_symmetry", "bounce"]) 132 elif nature == "wall": 133 l = [ "inlet", "bounce", "deposit1", "deposit2"] 134 if LagrangianModel(self.case).getCoalFouling() == "on": 135 l.append("fouling") 136 self.isInList(value, l) 137 self.node_boundary = self.node_boundaries.xmlInitChildNode(nature, label=labelbc, field_id='none') 138 self.node_particles = self.node_boundary.xmlInitChildNode('particles', 'choice') 139 self.node_particles['choice'] = value 140 self.setCurrentBoundaryNode(nature, labelbc) 141 142 143 @Variables.noUndo 144 def getBoundaryChoice(self, nature, labelbc): 145 """ 146 Return value for the boundary condition. 147 """ 148 default = { "wall" : "deposit1", "inlet" : "inlet", 149 "outlet" : "outlet", "free_inlet_outlet" : "outlet", 150 "imposed_p_outlet" : "outlet", 151 "symmetry" : "part_symmetry"} 152 self.setCurrentBoundaryNode(nature, labelbc) 153 if self.node_particles: 154 val = self.node_particles['choice'] 155 if val == None or val == "": 156 val = default[nature] 157 self.setBoundaryChoice(nature, labelbc, val) 158 return val 159 160 161 @Variables.undoLocal 162 def setCurrentBoundaryNode(self, nature, labelbc): 163 """ 164 Update the current boundary node. 165 """ 166 self.node_boundary = self.node_boundaries.xmlInitChildNode(nature, label=labelbc, field_id='none') 167 self.node_particles = self.node_boundary.xmlInitChildNode('particles', 'choice') 168 169 170 def newSetNode(self): 171 """ 172 Add a new 'set' node with child nodes. 173 """ 174 node_set = self.node_particles.xmlAddChild('class') 175 node_set.xmlSetData('number', self.default['number']) 176 node_set.xmlSetData('frequency', self.default['frequency']) 177 node_set.xmlSetData('statistical_groups', self.default['statistical_groups']) 178 node_set.xmlSetData('mass_flow_rate', self.default['mass_flow_rate']) 179 if CoalCombustionModel(self.case).getCoalCombustionModel("only") == 'off': 180 node_set.xmlSetData('density', self.default['density']) 181 node_set.xmlInitChildNode('temperature', 182 choice=self.default['temperature_choice']) 183 node_set.xmlSetData('temperature', 184 self.default['temperature']) 185 186 node_set.xmlInitChildNode('statistical_weight', 187 choice=self.default['statistical_weight_choice']) 188 node_set.xmlSetData('statistical_weight', 189 self.default['statistical_weight']) 190 191 node_set.xmlInitChildNode('velocity', 192 choice=self.default['velocity_choice']) 193 194 node_set.xmlInitChildNode('diameter') 195 node_set.xmlSetData('diameter', self.default['diameter']) 196 node_set.xmlSetData('diameter_standard_deviation', 197 self.default['diameter_standard_deviation']) 198 node_set.xmlSetData('fouling_index', self.default['fouling_index']) 199 200 201 @Variables.undoGlobal 202 def setNumberOfSetsValue(self, value): 203 """ 204 Update the number of sets. Create or delete nodes if necessary. 205 """ 206 self.isInt(value) 207 self.isGreaterOrEqual(value, 0) 208 node_list = self.node_particles.xmlGetChildNodeList('class') 209 nnodes = len(node_list) 210 if value > nnodes: 211 for i in range(value-nnodes): 212 self.newSetNode() 213 else: 214 for i in range(nnodes - value): 215 node_to_delete = node_list.pop() 216 node_to_delete.xmlRemoveNode() 217 # redefine self.node_set 218 219 220 @Variables.noUndo 221 def getNumberOfSetsValue(self): 222 """ 223 Return the number of injection sets. 224 """ 225 node_list = self.node_particles.xmlGetChildNodeList('class') 226 value = len(node_list) 227 if value == None: 228 value = self.defaultParticlesBoundaryValues()['n_is'] 229 self.setNumberOfSetsValue(value) 230 return value 231 232 233 @Variables.undoLocal 234 def setCurrentSetNode(self, iset): 235 """ 236 Update the current set node. 237 """ 238 choice = self.node_particles['choice'] 239 self.isInList(choice, ["inlet"]) 240 self.isInt(iset) 241 self.node_set = None 242 nodes_list = self.node_particles.xmlGetChildNodeList('class') 243 if nodes_list: 244 nnodes = len(nodes_list) 245 self.isLowerOrEqual(iset, nnodes) 246 self.node_set = nodes_list[iset-1] 247 248 249 @Variables.undoLocal 250 def setNumberOfParticulesInSetValue(self, label, iset, value): 251 """ 252 Update the number of particles in a set. 253 """ 254 self.isInt(value) 255 self.isGreaterOrEqual(value, 0) 256 self.node_set.xmlSetData('number', value) 257 258 259 @Variables.noUndo 260 def getNumberOfParticulesInSetValue(self, label, iset): 261 """ 262 Return the number of particles in a set. 263 """ 264 value = self.node_set.xmlGetInt('number') 265 if value == None: 266 value = self.defaultParticlesBoundaryValues()['number'] 267 self.setNumberOfParticulesInZoneValue(label, iset,value) 268 return value 269 270 271 @Variables.undoLocal 272 def setInjectionFrequencyValue(self, label, iset, value): 273 """ 274 Update the injection frequency. 275 """ 276 self.isInt(value) 277 self.isGreaterOrEqual(value, 0) 278 self.node_set.xmlSetData('frequency', value) 279 280 281 @Variables.noUndo 282 def getInjectionFrequencyValue(self, label, iset): 283 """ 284 Return the injection frequency. 285 """ 286 value = self.node_set.xmlGetInt('frequency') 287 if value == None: 288 value = self.defaultParticlesBoundaryValues()['frequency'] 289 self.setInjectionFrequencyValue(label, iset, value) 290 return value 291 292 293 @Variables.undoLocal 294 def setParticleGroupNumberValue(self, label, iset, value): 295 """ 296 Update the group number of the particle. 297 """ 298 self.isInt(value) 299 self.isGreaterOrEqual(value, 0) 300 self.node_set.xmlSetData('statistical_groups', value) 301 302 303 @Variables.noUndo 304 def getParticleGroupNumberValue(self, label, iset): 305 """ 306 Return the group number of the particle. 307 """ 308 value = self.node_set.xmlGetInt('statistical_groups') 309 if value == None: 310 value = self.defaultParticlesBoundaryValues()['statistical_groups'] 311 self.setParticleGroupNumberValue(label, iset, value) 312 return value 313 314 315 @Variables.undoLocal 316 def setMassFlowRateValue(self, label, iset, value): 317 """ 318 Update the mass flow rate value. 319 """ 320 self.isFloat(value) 321 self.isGreaterOrEqual(value, 0) 322 self.node_set.xmlSetData('mass_flow_rate', value) 323 324 325 @Variables.noUndo 326 def getMassFlowRateValue(self, label, iset): 327 """ 328 Return the mass flow rate value. 329 """ 330 value = self.node_set.xmlGetDouble('mass_flow_rate') 331 if value == None: 332 value = self.defaultParticlesBoundaryValues()['mass_flow_rate'] 333 self.setMassFlowRateValue(label, iset, value) 334 return value 335 336 337 @Variables.undoLocal 338 def setStatisticalWeightChoice(self, label, iset, value): 339 """ 340 Update the condition on statistical weight. 341 """ 342 self.isInList(value, ["rate", "prescribed"]) 343 node = self.node_set.xmlInitChildNode('statistical_weight', 'choice') 344 node['choice'] = value 345 346 347 @Variables.noUndo 348 def getStatisticalWeightChoice(self, label, iset): 349 """ 350 Return the condition on statistical weight. 351 """ 352 val = None 353 node = self.node_set.xmlGetChildNode('statistical_weight', 'choice') 354 if node: 355 val = node['choice'] 356 if val == None or val == "": 357 val = self.defaultParticlesBoundaryValues()['statistical_weight_choice'] 358 return val 359 360 361 @Variables.undoLocal 362 def setStatisticalWeightValue(self, label, iset, value): 363 """ 364 Update the statistical weight value. 365 """ 366 self.isFloat(value) 367 self.isGreater(value, 0) 368 self.node_set.xmlSetData('statistical_weight', value) 369 370 371 @Variables.noUndo 372 def getStatisticalWeightValue(self, label, iset): 373 """ 374 Return the statistical weight value. 375 """ 376 value = self.node_set.xmlGetDouble('statistical_weight') 377 if value == None: 378 value = self.defaultParticlesBoundaryValues()['statistical_weight'] 379 self.setStatisticalWeightValue(label, iset, value) 380 return value 381 382 383 @Variables.undoLocal 384 def setDensityValue(self, label, iset, value): 385 """ 386 Update the density value. 387 """ 388 self.isFloat(value) 389 self.isGreaterOrEqual(value, 0) 390 self.node_set.xmlSetData('density', value) 391 392 393 @Variables.noUndo 394 def getDensityValue(self, label, iset): 395 """ 396 Return the density value. 397 """ 398 value = self.node_set.xmlGetDouble('density') 399 if value == None: 400 value = self.defaultParticlesBoundaryValues()['density'] 401 self.setDensityValue(label, iset, value) 402 return value 403 404 @Variables.undoLocal 405 def setFoulingIndexValue(self, label, iset, value): 406 """ 407 Update the fouling index value. 408 """ 409 self.isFloat(value) 410 self.isGreaterOrEqual(value, 0) 411 self.node_set.xmlSetData('fouling_index', value) 412 413 414 @Variables.noUndo 415 def getFoulingIndexValue(self, label, iset): 416 """ 417 Return the fouling index value. 418 """ 419 value = self.node_set.xmlGetDouble('fouling_index') 420 if value == None: 421 value = self.defaultParticlesBoundaryValues()['fouling_index'] 422 self.setFoulingIndexValue(label, iset, value) 423 return value 424 425 426 @Variables.undoLocal 427 def setVelocityChoice(self, label, iset, choice): 428 """ 429 Update the condition on velocity. 430 """ 431 self.isInList(choice, ["fluid", "components", "norm"]) 432 node_velocity = self.node_set.xmlInitChildNode('velocity', 'choice') 433 node_velocity['choice'] = choice 434 if choice in ["fluid", "norm"]: 435 node_velocity.xmlRemoveChild('velocity_x') 436 node_velocity.xmlRemoveChild('velocity_y') 437 node_velocity.xmlRemoveChild('velocity_z') 438 elif choice in ["fluid", "components"]: 439 node_velocity.xmlRemoveChild('norm') 440 441 442 @Variables.noUndo 443 def getVelocityChoice(self, label, iset): 444 """ 445 Return the condition on velocity. 446 """ 447 node = self.node_set.xmlInitChildNode('velocity', 'choice') 448 if node: 449 val = node['choice'] 450 if val == None: 451 val = self.defaultParticlesBoundaryValues()['velocity_choice'] 452 self.setVelocityChoice(val) 453 return val 454 455 456 @Variables.undoLocal 457 def setVelocityNormValue(self, label, iset, value): 458 """ 459 Update the velocity norm. 460 """ 461 self.isFloat(value) 462 self.isGreaterOrEqual(value, 0.) 463 node_velocity = self.node_set.xmlInitChildNode('velocity', choice="norm") 464 choice = node_velocity['choice'] 465 self.isInList(choice, ["norm"]) 466 node_velocity.xmlSetData('norm', value) 467 468 469 @Variables.noUndo 470 def getVelocityNormValue(self, label, iset): 471 """ 472 Return the velocity norm. 473 """ 474 node_velocity = self.node_set.xmlInitChildNode('velocity', choice="norm") 475 value = node_velocity.xmlGetDouble('norm') 476 if value == None: 477 value = self.defaultParticlesBoundaryValues()['velocity_norm'] 478 self.setVelocityNormValue(label, iset, value) 479 return value 480 481 482 @Variables.undoLocal 483 def setVelocityDirectionValue(self, label, iset, idir, value): 484 """ 485 Update the velocity value in the given direction. 486 """ 487 self.isFloat(value) 488 self.isGreaterOrEqual(value, 0.) 489 node_velocity = self.node_set.xmlInitChildNode('velocity', choice="components") 490 choice = node_velocity['choice'] 491 self.isInList(choice, ["components"]) 492 node_velocity.xmlSetData('velocity_' + idir, value) 493 494 495 @Variables.noUndo 496 def getVelocityDirectionValue(self, label, iset, idir): 497 """ 498 Return the velocity value in the given direction. 499 """ 500 node_velocity = self.node_set.xmlInitChildNode('velocity', choice="components") 501 value = self.node_set.xmlGetDouble('velocity_' + idir) 502 if value == None: 503 value = self.defaultParticlesBoundaryValues()['velocity_value'] 504 self.setVelocityDirectionValue(label, iset, idir, value) 505 return value 506 507 508 @Variables.undoLocal 509 def setTemperatureChoice(self, label, iset, value): 510 """ 511 Update the condition on temperature. 512 """ 513 self.isInList(value, ["prescribed", "fluid"]) 514 node = self.node_set.xmlInitChildNode('temperature', 'choice') 515 node['choice'] = value 516 517 518 @Variables.noUndo 519 def getTemperatureChoice(self, label, iset): 520 """ 521 Return the condition on temperature. 522 """ 523 val = None 524 node = self.node_set.xmlGetChildNode('temperature', 'choice') 525 if node: 526 val = node['choice'] 527 if val == None: 528 val = self.defaultParticlesBoundaryValues()['temperature_choice'] 529 return val 530 531 532 @Variables.undoLocal 533 def setTemperatureValue(self, label, iset, value): 534 """ 535 Update the temperature value. 536 """ 537 self.isFloat(value) 538 self.isGreaterOrEqual(value, 0) 539 self.node_set.xmlSetData('temperature', value) 540 541 542 @Variables.noUndo 543 def getTemperatureValue(self, label, iset): 544 """ 545 Return the temperature value. 546 """ 547 value = self.node_set.xmlGetDouble('temperature') 548 if value == None: 549 value = self.defaultParticlesBoundaryValues()['temperature'] 550 self.setTemperatureValue(label, iset, value) 551 return value 552 553 554 @Variables.undoLocal 555 def setSpecificHeatValue(self, label, iset, value): 556 """ 557 Update the specific heat value. 558 """ 559 self.isFloat(value) 560 self.isGreaterOrEqual(value, 0) 561 self.node_set.xmlSetData('specific_heat', value) 562 563 564 @Variables.noUndo 565 def getSpecificHeatValue(self, label, iset): 566 """ 567 Return the specific heat value. 568 """ 569 value = self.node_set.xmlGetDouble('specific_heat') 570 if value == None: 571 value = self.defaultParticlesBoundaryValues()['specific_heat'] 572 self.setSpecificHeatValue(label, iset, value) 573 return value 574 575 576 @Variables.undoLocal 577 def setEmissivityValue(self, label, iset, value): 578 """ 579 Update the emissivity value. 580 """ 581 self.isFloat(value) 582 self.isGreaterOrEqual(value, 0) 583 self.node_set.xmlSetData('emissivity', value) 584 585 586 @Variables.noUndo 587 def getEmissivityValue(self, label, iset): 588 """ 589 Return the emissivity value. 590 """ 591 value = self.node_set.xmlGetDouble('emissivity') 592 if value == None: 593 value = self.defaultParticlesBoundaryValues()['emissivity'] 594 self.setEmissivityValue(label, iset, value) 595 return value 596 597 598 @Variables.undoLocal 599 def setDiameterValue(self, label, iset, value): 600 """ 601 Update the particle diameter value. 602 """ 603 self.isFloat(value) 604 self.isGreaterOrEqual(value, 0) 605 self.node_set.xmlSetData('diameter', value) 606 607 608 @Variables.noUndo 609 def getDiameterValue(self, label, iset): 610 """ 611 Return the particle diameter value. 612 """ 613 value = self.node_set.xmlGetDouble('diameter') 614 if value == None: 615 value = self.defaultParticlesBoundaryValues()['diameter'] 616 self.setDiameterValue(label, iset, value) 617 return value 618 619 620 @Variables.undoLocal 621 def setDiameterVarianceValue(self, label, iset, value): 622 """ 623 Update the particle diameter variance value. 624 """ 625 self.isFloat(value) 626 self.isGreaterOrEqual(value, 0) 627 self.node_set.xmlSetData('diameter_standard_deviation', value) 628 629 630 @Variables.noUndo 631 def getDiameterVarianceValue(self, label, iset): 632 """ 633 Return the particle diameter variance value. 634 """ 635 value = self.node_set.xmlGetDouble('diameter_standard_deviation') 636 if value == None: 637 value = self.defaultParticlesBoundaryValues()['diameter_standard_deviation'] 638 self.setDiameterVarianceValue(label, iset, value) 639 return value 640 641 642 @Variables.undoLocal 643 def setCoalNumberValue(self, label, iset, value): 644 """ 645 Update the coal number of the particle. 646 """ 647 self.isInt(value) 648 self.isGreaterOrEqual(value, 0) 649 self.node_set.xmlSetData('coal_number', value) 650 651 652 @Variables.noUndo 653 def getCoalNumberValue(self, label, iset): 654 """ 655 Return the coal number of the particle. 656 """ 657 value = self.node_set.xmlGetInt('coal_number') 658 if value == None: 659 value = self.defaultParticlesBoundaryValues()['coal_number'] 660 self.setCoalNumberValue(label, iset, value) 661 return value 662 663 664 @Variables.undoLocal 665 def setCoalTemperatureValue(self, label, iset, value): 666 """ 667 Update the coal temperature. 668 """ 669 self.isFloat(value) 670 self.isGreaterOrEqual(value, 0) 671 self.node_set.xmlSetData('coal_temperature', value) 672 673 674 @Variables.noUndo 675 def getCoalTemperatureValue(self, label, iset): 676 """ 677 Return the coal temperature. 678 """ 679 value = self.node_set.xmlGetDouble('coal_temperature') 680 if value == None: 681 value = self.defaultParticlesBoundaryValues()['coal_temperature'] 682 self.setCoalTemperatureValue(label, iset, value) 683 return value 684 685 686#------------------------------------------------------------------------------- 687# LagrangianBoundaries test case 688#------------------------------------------------------------------------------- 689 690 691class LagrangianBoundariesTestCase(unittest.TestCase): 692 """ 693 """ 694 def setUp(self): 695 """ 696 This method is executed before all "check" methods. 697 """ 698 from code_saturne.model.XMLengine import Case 699 from code_saturne.model.XMLinitialize import XMLinit 700 self.case = Case() 701 XMLinit(self.case).initialize() 702 703 704 def tearDown(self): 705 """ 706 This method is executed after all "check" methods. 707 """ 708 del self.case 709 710 711 def checkLagrangianBoundariesInstantiation(self): 712 """ 713 Check whether the LagrangianBoundariesModel class could be instantiated 714 """ 715 model = None 716 model = LagrangianBoundariesModel(self.case) 717 718 assert model != None, 'Could not instantiate LagrangianBoundariesModel' 719 720 721 def checkLagrangianBoundariesDefaultValues(self): 722 """ 723 Check the default values 724 """ 725 model = LagrangianBoundariesModel(self.case) 726 doc = """""" 727 728 assert model.node_output == self.xmlNodeFromString(doc),\ 729 'Could not get default values for model' 730 731 732def suite(): 733 testSuite = unittest.makeSuite(LagrangianBoundariesTestCase, "check") 734 return testSuite 735 736 737def runTest(): 738 print("LagrangianBoundariesTestCase TODO*********.") 739 runner = unittest.TextTestRunner() 740 runner.run(suite()) 741 742 743#------------------------------------------------------------------------------- 744# End 745#------------------------------------------------------------------------------- 746