├── LICENSE ├── README.md ├── Simulations └── airFoil2DInit │ ├── 0.orig │ ├── T │ ├── U │ ├── alphat │ ├── k │ ├── nuTilda │ ├── nut │ ├── omega │ └── p │ ├── constant │ ├── thermophysicalProperties │ ├── transportProperties │ └── turbulenceProperties │ └── system │ ├── blockMeshDict.orig │ ├── controlDict.orig │ ├── decomposeParDict │ ├── fvOptions │ ├── fvSchemes │ └── fvSolution ├── dataset_generator.py ├── main.py ├── mesh_scheme.pdf ├── metrics.py ├── naca_generator.py ├── params.yaml └── simulation_generator.py /LICENSE: -------------------------------------------------------------------------------- 1 | ## ODC Open Database License (ODbL) 2 | 3 | ### Preamble 4 | 5 | The Open Database License (ODbL) is a license agreement intended to 6 | allow users to freely share, modify, and use this Database while 7 | maintaining this same freedom for others. Many databases are covered by 8 | copyright, and therefore this document licenses these rights. Some 9 | jurisdictions, mainly in the European Union, have specific rights that 10 | cover databases, and so the ODbL addresses these rights, too. Finally, 11 | the ODbL is also an agreement in contract for users of this Database to 12 | act in certain ways in return for accessing this Database. 13 | 14 | Databases can contain a wide variety of types of content (images, 15 | audiovisual material, and sounds all in the same database, for example), 16 | and so the ODbL only governs the rights over the Database, and not the 17 | contents of the Database individually. Licensors should use the ODbL 18 | together with another license for the contents, if the contents have a 19 | single set of rights that uniformly covers all of the contents. If the 20 | contents have multiple sets of different rights, Licensors should 21 | describe what rights govern what contents together in the individual 22 | record or in some other way that clarifies what rights apply. 23 | 24 | Sometimes the contents of a database, or the database itself, can be 25 | covered by other rights not addressed here (such as private contracts, 26 | trade mark over the name, or privacy rights / data protection rights 27 | over information in the contents), and so you are advised that you may 28 | have to consult other documents or clear other rights before doing 29 | activities not covered by this License. 30 | 31 | ------ 32 | 33 | The Licensor (as defined below) 34 | 35 | and 36 | 37 | You (as defined below) 38 | 39 | agree as follows: 40 | 41 | ### 1.0 Definitions of Capitalised Words 42 | 43 | "Collective Database" – Means this Database in unmodified form as part 44 | of a collection of independent databases in themselves that together are 45 | assembled into a collective whole. A work that constitutes a Collective 46 | Database will not be considered a Derivative Database. 47 | 48 | "Convey" – As a verb, means Using the Database, a Derivative Database, 49 | or the Database as part of a Collective Database in any way that enables 50 | a Person to make or receive copies of the Database or a Derivative 51 | Database. Conveying does not include interaction with a user through a 52 | computer network, or creating and Using a Produced Work, where no 53 | transfer of a copy of the Database or a Derivative Database occurs. 54 | "Contents" – The contents of this Database, which includes the 55 | information, independent works, or other material collected into the 56 | Database. For example, the contents of the Database could be factual 57 | data or works such as images, audiovisual material, text, or sounds. 58 | 59 | "Database" – A collection of material (the Contents) arranged in a 60 | systematic or methodical way and individually accessible by electronic 61 | or other means offered under the terms of this License. 62 | 63 | "Database Directive" – Means Directive 96/9/EC of the European 64 | Parliament and of the Council of 11 March 1996 on the legal protection 65 | of databases, as amended or succeeded. 66 | 67 | "Database Right" – Means rights resulting from the Chapter III ("sui 68 | generis") rights in the Database Directive (as amended and as transposed 69 | by member states), which includes the Extraction and Re-utilisation of 70 | the whole or a Substantial part of the Contents, as well as any similar 71 | rights available in the relevant jurisdiction under Section 10.4. 72 | 73 | "Derivative Database" – Means a database based upon the Database, and 74 | includes any translation, adaptation, arrangement, modification, or any 75 | other alteration of the Database or of a Substantial part of the 76 | Contents. This includes, but is not limited to, Extracting or 77 | Re-utilising the whole or a Substantial part of the Contents in a new 78 | Database. 79 | 80 | "Extraction" – Means the permanent or temporary transfer of all or a 81 | Substantial part of the Contents to another medium by any means or in 82 | any form. 83 | 84 | "License" – Means this license agreement and is both a license of rights 85 | such as copyright and Database Rights and an agreement in contract. 86 | 87 | "Licensor" – Means the Person that offers the Database under the terms 88 | of this License. 89 | 90 | "Person" – Means a natural or legal person or a body of persons 91 | corporate or incorporate. 92 | 93 | "Produced Work" – a work (such as an image, audiovisual material, text, 94 | or sounds) resulting from using the whole or a Substantial part of the 95 | Contents (via a search or other query) from this Database, a Derivative 96 | Database, or this Database as part of a Collective Database. 97 | 98 | "Publicly" – means to Persons other than You or under Your control by 99 | either more than 50% ownership or by the power to direct their 100 | activities (such as contracting with an independent consultant). 101 | 102 | "Re-utilisation" – means any form of making available to the public all 103 | or a Substantial part of the Contents by the distribution of copies, by 104 | renting, by online or other forms of transmission. 105 | 106 | "Substantial" – Means substantial in terms of quantity or quality or a 107 | combination of both. The repeated and systematic Extraction or 108 | Re-utilisation of insubstantial parts of the Contents may amount to the 109 | Extraction or Re-utilisation of a Substantial part of the Contents. 110 | 111 | "Use" – As a verb, means doing any act that is restricted by copyright 112 | or Database Rights whether in the original medium or any other; and 113 | includes without limitation distributing, copying, publicly performing, 114 | publicly displaying, and preparing derivative works of the Database, as 115 | well as modifying the Database as may be technically necessary to use it 116 | in a different mode or format. 117 | 118 | "You" – Means a Person exercising rights under this License who has not 119 | previously violated the terms of this License with respect to the 120 | Database, or who has received express permission from the Licensor to 121 | exercise rights under this License despite a previous violation. 122 | 123 | Words in the singular include the plural and vice versa. 124 | 125 | ### 2.0 What this License covers 126 | 127 | 2.1. Legal effect of this document. This License is: 128 | 129 | a. A license of applicable copyright and neighbouring rights; 130 | 131 | b. A license of the Database Right; and 132 | 133 | c. An agreement in contract between You and the Licensor. 134 | 135 | 2.2 Legal rights covered. This License covers the legal rights in the 136 | Database, including: 137 | 138 | a. Copyright. Any copyright or neighbouring rights in the Database. 139 | The copyright licensed includes any individual elements of the 140 | Database, but does not cover the copyright over the Contents 141 | independent of this Database. See Section 2.4 for details. Copyright 142 | law varies between jurisdictions, but is likely to cover: the Database 143 | model or schema, which is the structure, arrangement, and organisation 144 | of the Database, and can also include the Database tables and table 145 | indexes; the data entry and output sheets; and the Field names of 146 | Contents stored in the Database; 147 | 148 | b. Database Rights. Database Rights only extend to the Extraction and 149 | Re-utilisation of the whole or a Substantial part of the Contents. 150 | Database Rights can apply even when there is no copyright over the 151 | Database. Database Rights can also apply when the Contents are removed 152 | from the Database and are selected and arranged in a way that would 153 | not infringe any applicable copyright; and 154 | 155 | c. Contract. This is an agreement between You and the Licensor for 156 | access to the Database. In return you agree to certain conditions of 157 | use on this access as outlined in this License. 158 | 159 | 2.3 Rights not covered. 160 | 161 | a. This License does not apply to computer programs used in the making 162 | or operation of the Database; 163 | 164 | b. This License does not cover any patents over the Contents or the 165 | Database; and 166 | 167 | c. This License does not cover any trademarks associated with the 168 | Database. 169 | 170 | 2.4 Relationship to Contents in the Database. The individual items of 171 | the Contents contained in this Database may be covered by other rights, 172 | including copyright, patent, data protection, privacy, or personality 173 | rights, and this License does not cover any rights (other than Database 174 | Rights or in contract) in individual Contents contained in the Database. 175 | For example, if used on a Database of images (the Contents), this 176 | License would not apply to copyright over individual images, which could 177 | have their own separate licenses, or one single license covering all of 178 | the rights over the images. 179 | 180 | ### 3.0 Rights granted 181 | 182 | 3.1 Subject to the terms and conditions of this License, the Licensor 183 | grants to You a worldwide, royalty-free, non-exclusive, terminable (but 184 | only under Section 9) license to Use the Database for the duration of 185 | any applicable copyright and Database Rights. These rights explicitly 186 | include commercial use, and do not exclude any field of endeavour. To 187 | the extent possible in the relevant jurisdiction, these rights may be 188 | exercised in all media and formats whether now known or created in the 189 | future. 190 | 191 | The rights granted cover, for example: 192 | 193 | a. Extraction and Re-utilisation of the whole or a Substantial part of 194 | the Contents; 195 | 196 | b. Creation of Derivative Databases; 197 | 198 | c. Creation of Collective Databases; 199 | 200 | d. Creation of temporary or permanent reproductions by any means and 201 | in any form, in whole or in part, including of any Derivative 202 | Databases or as a part of Collective Databases; and 203 | 204 | e. Distribution, communication, display, lending, making available, or 205 | performance to the public by any means and in any form, in whole or in 206 | part, including of any Derivative Database or as a part of Collective 207 | Databases. 208 | 209 | 3.2 Compulsory license schemes. For the avoidance of doubt: 210 | 211 | a. Non-waivable compulsory license schemes. In those jurisdictions in 212 | which the right to collect royalties through any statutory or 213 | compulsory licensing scheme cannot be waived, the Licensor reserves 214 | the exclusive right to collect such royalties for any exercise by You 215 | of the rights granted under this License; 216 | 217 | b. Waivable compulsory license schemes. In those jurisdictions in 218 | which the right to collect royalties through any statutory or 219 | compulsory licensing scheme can be waived, the Licensor waives the 220 | exclusive right to collect such royalties for any exercise by You of 221 | the rights granted under this License; and, 222 | 223 | c. Voluntary license schemes. The Licensor waives the right to collect 224 | royalties, whether individually or, in the event that the Licensor is 225 | a member of a collecting society that administers voluntary licensing 226 | schemes, via that society, from any exercise by You of the rights 227 | granted under this License. 228 | 229 | 3.3 The right to release the Database under different terms, or to stop 230 | distributing or making available the Database, is reserved. Note that 231 | this Database may be multiple-licensed, and so You may have the choice 232 | of using alternative licenses for this Database. Subject to Section 233 | 10.4, all other rights not expressly granted by Licensor are reserved. 234 | 235 | ### 4.0 Conditions of Use 236 | 237 | 4.1 The rights granted in Section 3 above are expressly made subject to 238 | Your complying with the following conditions of use. These are important 239 | conditions of this License, and if You fail to follow them, You will be 240 | in material breach of its terms. 241 | 242 | 4.2 Notices. If You Publicly Convey this Database, any Derivative 243 | Database, or the Database as part of a Collective Database, then You 244 | must: 245 | 246 | a. Do so only under the terms of this License or another license 247 | permitted under Section 4.4; 248 | 249 | b. Include a copy of this License (or, as applicable, a license 250 | permitted under Section 4.4) or its Uniform Resource Identifier (URI) 251 | with the Database or Derivative Database, including both in the 252 | Database or Derivative Database and in any relevant documentation; and 253 | 254 | c. Keep intact any copyright or Database Right notices and notices 255 | that refer to this License. 256 | 257 | d. If it is not possible to put the required notices in a particular 258 | file due to its structure, then You must include the notices in a 259 | location (such as a relevant directory) where users would be likely to 260 | look for it. 261 | 262 | 4.3 Notice for using output (Contents). Creating and Using a Produced 263 | Work does not require the notice in Section 4.2. However, if you 264 | Publicly Use a Produced Work, You must include a notice associated with 265 | the Produced Work reasonably calculated to make any Person that uses, 266 | views, accesses, interacts with, or is otherwise exposed to the Produced 267 | Work aware that Content was obtained from the Database, Derivative 268 | Database, or the Database as part of a Collective Database, and that it 269 | is available under this License. 270 | 271 | a. Example notice. The following text will satisfy notice under 272 | Section 4.3: 273 | 274 | Contains information from DATABASE NAME, which is made available 275 | here under the Open Database License (ODbL). 276 | 277 | DATABASE NAME should be replaced with the name of the Database and a 278 | hyperlink to the URI of the Database. "Open Database License" should 279 | contain a hyperlink to the URI of the text of this License. If 280 | hyperlinks are not possible, You should include the plain text of the 281 | required URI's with the above notice. 282 | 283 | 4.4 Share alike. 284 | 285 | a. Any Derivative Database that You Publicly Use must be only under 286 | the terms of: 287 | 288 | i. This License; 289 | 290 | ii. A later version of this License similar in spirit to this 291 | License; or 292 | 293 | iii. A compatible license. 294 | 295 | If You license the Derivative Database under one of the licenses 296 | mentioned in (iii), You must comply with the terms of that license. 297 | 298 | b. For the avoidance of doubt, Extraction or Re-utilisation of the 299 | whole or a Substantial part of the Contents into a new database is a 300 | Derivative Database and must comply with Section 4.4. 301 | 302 | c. Derivative Databases and Produced Works. A Derivative Database is 303 | Publicly Used and so must comply with Section 4.4. if a Produced Work 304 | created from the Derivative Database is Publicly Used. 305 | 306 | d. Share Alike and additional Contents. For the avoidance of doubt, 307 | You must not add Contents to Derivative Databases under Section 4.4 a 308 | that are incompatible with the rights granted under this License. 309 | 310 | e. Compatible licenses. Licensors may authorise a proxy to determine 311 | compatible licenses under Section 4.4 a iii. If they do so, the 312 | authorised proxy's public statement of acceptance of a compatible 313 | license grants You permission to use the compatible license. 314 | 315 | 316 | 4.5 Limits of Share Alike. The requirements of Section 4.4 do not apply 317 | in the following: 318 | 319 | a. For the avoidance of doubt, You are not required to license 320 | Collective Databases under this License if You incorporate this 321 | Database or a Derivative Database in the collection, but this License 322 | still applies to this Database or a Derivative Database as a part of 323 | the Collective Database; 324 | 325 | b. Using this Database, a Derivative Database, or this Database as 326 | part of a Collective Database to create a Produced Work does not 327 | create a Derivative Database for purposes of Section 4.4; and 328 | 329 | c. Use of a Derivative Database internally within an organisation is 330 | not to the public and therefore does not fall under the requirements 331 | of Section 4.4. 332 | 333 | 4.6 Access to Derivative Databases. If You Publicly Use a Derivative 334 | Database or a Produced Work from a Derivative Database, You must also 335 | offer to recipients of the Derivative Database or Produced Work a copy 336 | in a machine readable form of: 337 | 338 | a. The entire Derivative Database; or 339 | 340 | b. A file containing all of the alterations made to the Database or 341 | the method of making the alterations to the Database (such as an 342 | algorithm), including any additional Contents, that make up all the 343 | differences between the Database and the Derivative Database. 344 | 345 | The Derivative Database (under a.) or alteration file (under b.) must be 346 | available at no more than a reasonable production cost for physical 347 | distributions and free of charge if distributed over the internet. 348 | 349 | 4.7 Technological measures and additional terms 350 | 351 | a. This License does not allow You to impose (except subject to 352 | Section 4.7 b.) any terms or any technological measures on the 353 | Database, a Derivative Database, or the whole or a Substantial part of 354 | the Contents that alter or restrict the terms of this License, or any 355 | rights granted under it, or have the effect or intent of restricting 356 | the ability of any person to exercise those rights. 357 | 358 | b. Parallel distribution. You may impose terms or technological 359 | measures on the Database, a Derivative Database, or the whole or a 360 | Substantial part of the Contents (a "Restricted Database") in 361 | contravention of Section 4.74 a. only if You also make a copy of the 362 | Database or a Derivative Database available to the recipient of the 363 | Restricted Database: 364 | 365 | i. That is available without additional fee; 366 | 367 | ii. That is available in a medium that does not alter or restrict 368 | the terms of this License, or any rights granted under it, or have 369 | the effect or intent of restricting the ability of any person to 370 | exercise those rights (an "Unrestricted Database"); and 371 | 372 | iii. The Unrestricted Database is at least as accessible to the 373 | recipient as a practical matter as the Restricted Database. 374 | 375 | c. For the avoidance of doubt, You may place this Database or a 376 | Derivative Database in an authenticated environment, behind a 377 | password, or within a similar access control scheme provided that You 378 | do not alter or restrict the terms of this License or any rights 379 | granted under it or have the effect or intent of restricting the 380 | ability of any person to exercise those rights. 381 | 382 | 4.8 Licensing of others. You may not sublicense the Database. Each time 383 | You communicate the Database, the whole or Substantial part of the 384 | Contents, or any Derivative Database to anyone else in any way, the 385 | Licensor offers to the recipient a license to the Database on the same 386 | terms and conditions as this License. You are not responsible for 387 | enforcing compliance by third parties with this License, but You may 388 | enforce any rights that You have over a Derivative Database. You are 389 | solely responsible for any modifications of a Derivative Database made 390 | by You or another Person at Your direction. You may not impose any 391 | further restrictions on the exercise of the rights granted or affirmed 392 | under this License. 393 | 394 | ### 5.0 Moral rights 395 | 396 | 5.1 Moral rights. This section covers moral rights, including any rights 397 | to be identified as the author of the Database or to object to treatment 398 | that would otherwise prejudice the author's honour and reputation, or 399 | any other derogatory treatment: 400 | 401 | a. For jurisdictions allowing waiver of moral rights, Licensor waives 402 | all moral rights that Licensor may have in the Database to the fullest 403 | extent possible by the law of the relevant jurisdiction under Section 404 | 10.4; 405 | 406 | b. If waiver of moral rights under Section 5.1 a in the relevant 407 | jurisdiction is not possible, Licensor agrees not to assert any moral 408 | rights over the Database and waives all claims in moral rights to the 409 | fullest extent possible by the law of the relevant jurisdiction under 410 | Section 10.4; and 411 | 412 | c. For jurisdictions not allowing waiver or an agreement not to assert 413 | moral rights under Section 5.1 a and b, the author may retain their 414 | moral rights over certain aspects of the Database. 415 | 416 | Please note that some jurisdictions do not allow for the waiver of moral 417 | rights, and so moral rights may still subsist over the Database in some 418 | jurisdictions. 419 | 420 | ### 6.0 Fair dealing, Database exceptions, and other rights not affected 421 | 422 | 6.1 This License does not affect any rights that You or anyone else may 423 | independently have under any applicable law to make any use of this 424 | Database, including without limitation: 425 | 426 | a. Exceptions to the Database Right including: Extraction of Contents 427 | from non-electronic Databases for private purposes, Extraction for 428 | purposes of illustration for teaching or scientific research, and 429 | Extraction or Re-utilisation for public security or an administrative 430 | or judicial procedure. 431 | 432 | b. Fair dealing, fair use, or any other legally recognised limitation 433 | or exception to infringement of copyright or other applicable laws. 434 | 435 | 6.2 This License does not affect any rights of lawful users to Extract 436 | and Re-utilise insubstantial parts of the Contents, evaluated 437 | quantitatively or qualitatively, for any purposes whatsoever, including 438 | creating a Derivative Database (subject to other rights over the 439 | Contents, see Section 2.4). The repeated and systematic Extraction or 440 | Re-utilisation of insubstantial parts of the Contents may however amount 441 | to the Extraction or Re-utilisation of a Substantial part of the 442 | Contents. 443 | 444 | ### 7.0 Warranties and Disclaimer 445 | 446 | 7.1 The Database is licensed by the Licensor "as is" and without any 447 | warranty of any kind, either express, implied, or arising by statute, 448 | custom, course of dealing, or trade usage. Licensor specifically 449 | disclaims any and all implied warranties or conditions of title, 450 | non-infringement, accuracy or completeness, the presence or absence of 451 | errors, fitness for a particular purpose, merchantability, or otherwise. 452 | Some jurisdictions do not allow the exclusion of implied warranties, so 453 | this exclusion may not apply to You. 454 | 455 | ### 8.0 Limitation of liability 456 | 457 | 8.1 Subject to any liability that may not be excluded or limited by law, 458 | the Licensor is not liable for, and expressly excludes, all liability 459 | for loss or damage however and whenever caused to anyone by any use 460 | under this License, whether by You or by anyone else, and whether caused 461 | by any fault on the part of the Licensor or not. This exclusion of 462 | liability includes, but is not limited to, any special, incidental, 463 | consequential, punitive, or exemplary damages such as loss of revenue, 464 | data, anticipated profits, and lost business. This exclusion applies 465 | even if the Licensor has been advised of the possibility of such 466 | damages. 467 | 468 | 8.2 If liability may not be excluded by law, it is limited to actual and 469 | direct financial loss to the extent it is caused by proved negligence on 470 | the part of the Licensor. 471 | 472 | ### 9.0 Termination of Your rights under this License 473 | 474 | 9.1 Any breach by You of the terms and conditions of this License 475 | automatically terminates this License with immediate effect and without 476 | notice to You. For the avoidance of doubt, Persons who have received the 477 | Database, the whole or a Substantial part of the Contents, Derivative 478 | Databases, or the Database as part of a Collective Database from You 479 | under this License will not have their licenses terminated provided 480 | their use is in full compliance with this License or a license granted 481 | under Section 4.8 of this License. Sections 1, 2, 7, 8, 9 and 10 will 482 | survive any termination of this License. 483 | 484 | 9.2 If You are not in breach of the terms of this License, the Licensor 485 | will not terminate Your rights under it. 486 | 487 | 9.3 Unless terminated under Section 9.1, this License is granted to You 488 | for the duration of applicable rights in the Database. 489 | 490 | 9.4 Reinstatement of rights. If you cease any breach of the terms and 491 | conditions of this License, then your full rights under this License 492 | will be reinstated: 493 | 494 | a. Provisionally and subject to permanent termination until the 60th 495 | day after cessation of breach; 496 | 497 | b. Permanently on the 60th day after cessation of breach unless 498 | otherwise reasonably notified by the Licensor; or 499 | 500 | c. Permanently if reasonably notified by the Licensor of the 501 | violation, this is the first time You have received notice of 502 | violation of this License from the Licensor, and You cure the 503 | violation prior to 30 days after your receipt of the notice. 504 | 505 | Persons subject to permanent termination of rights are not eligible to 506 | be a recipient and receive a license under Section 4.8. 507 | 508 | 9.5 Notwithstanding the above, Licensor reserves the right to release 509 | the Database under different license terms or to stop distributing or 510 | making available the Database. Releasing the Database under different 511 | license terms or stopping the distribution of the Database will not 512 | withdraw this License (or any other license that has been, or is 513 | required to be, granted under the terms of this License), and this 514 | License will continue in full force and effect unless terminated as 515 | stated above. 516 | 517 | ### 10.0 General 518 | 519 | 10.1 If any provision of this License is held to be invalid or 520 | unenforceable, that must not affect the validity or enforceability of 521 | the remainder of the terms and conditions of this License and each 522 | remaining provision of this License shall be valid and enforced to the 523 | fullest extent permitted by law. 524 | 525 | 10.2 This License is the entire agreement between the parties with 526 | respect to the rights granted here over the Database. It replaces any 527 | earlier understandings, agreements or representations with respect to 528 | the Database. 529 | 530 | 10.3 If You are in breach of the terms of this License, You will not be 531 | entitled to rely on the terms of this License or to complain of any 532 | breach by the Licensor. 533 | 534 | 10.4 Choice of law. This License takes effect in and will be governed by 535 | the laws of the relevant jurisdiction in which the License terms are 536 | sought to be enforced. If the standard suite of rights granted under 537 | applicable copyright law and Database Rights in the relevant 538 | jurisdiction includes additional rights not granted under this License, 539 | these additional rights are granted in this License in order to meet the 540 | terms of this License. 541 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## NACA_simulation 2 | In this repository, you will find different python scripts to run incompressible or compressible Reynolds-Averaged-Simulations over NACA airfoils. 3 | 4 | ## Requirements 5 | - OpenFOAM v2112 (You can install it by following those [instructions](https://develop.openfoam.com/Development/openfoam/-/wikis/precompiled/debian) for Ubuntu, do not forget to update your .bashrc file to automatically run OpenFOAM when launching a terminal) 6 | - Python 3.9.12 7 | - NumPy 1.23.1 8 | - PyYAML 6.0 9 | - Seaborn 0.11.2 10 | 11 | ## Simulation 12 | To launch a simulation, enter your parameters in the ```params.yaml``` file and run: 13 | ``` 14 | python main.py -i 0 -g 1 -v 1 -f 1 15 | ``` 16 | 17 | ## Usage 18 | ``` 19 | usage: main.py [-h] [-i INIT] [-g GRADIENT] [-v VTK] [-f FIGURE] 20 | 21 | optional arguments: 22 | -h, --help show this help message and exit 23 | -i INIT, --init INIT Only generate the mesh (default: 0) 24 | -g GRADIENT, --gradient GRADIENT 25 | Compute the term of the RANS equations as a post-processing (default: 0) 26 | -v VTK, --vtk VTK Generate the VTK files from the simulation (default: 1) 27 | -f FIGURE, --figure FIGURE 28 | Save an image of the airfoil in the simulation folder (default: 1) 29 | ``` 30 | 31 | ## Dataset 32 | Those scripts have been used to generate the AirfRANS dataset proposed at the NeurIPS 2022 Datasets and Benchmarks Track conference. In particular, the script ```dataset_generator.py``` run multiple simulations by sampling Reynolds number and Angle of Attack as explained in the associated paper. 33 | 34 | This script can be re-used to run multiple new random simulations. 35 | 36 | ## Mesh parameters 37 | The mesh is generated with the blockMesh utility available in the OpenFOAM suite. The block definition is given in the following ![scheme](https://github.com/Extrality/NACA_simulation/blob/main/mesh_scheme.pdf?raw=true). 38 | Some of the parameters contained in the ```params.yaml``` file are for the mesh generation. Parameters are defined as: 39 | - ```L```: Size of the domain in meters 40 | - ```y_h```: Heigth of the first cell of the boundary layer 41 | - ```y_hd```: Heigth of the furthest first cell of the trail (at vertex 1 in the scheme) 42 | - ```x_h```: Width of the smallest cell at the leading edge (at vertex 8 in the scheme) 43 | - ```y_exp```: Expansion ratio in the y-direction 44 | - ```x_exp```: Expansion ratio in the x-direction on the airfoil (edge between vertices 8 and 11) 45 | - ```x_expd```: Expansion ratio in the x-direction behind the airfoil (edge between vertices 1 and 10) 46 | 47 | ## Citation 48 | The original paper accepted at the 36th Conference on Neural Information Processing Systems (NeurIPS 2022) Track on Datasets and Benchmarks can be found [here](https://openreview.net/forum?id=Zp8YmiQ_bDC) and the preprint [here](https://arxiv.org/abs/2212.07564). **Disclaimer: An important update correcting an inconsistency in the Machine Learning experiments proposed in the main part of the NeurIPS version of the paper has been done. Please refer to the [ArXiv version](https://arxiv.org/abs/2212.07564) for the up to date version.** 49 | 50 | Please cite this paper if you use this dataset in your own work. 51 | ``` 52 | @inproceedings{ 53 | bonnet2022airfrans, 54 | title={Airf{RANS}: High Fidelity Computational Fluid Dynamics Dataset for Approximating Reynolds-Averaged Navier{\textendash}Stokes Solutions}, 55 | author={Florent Bonnet and Jocelyn Ahmed Mazari and Paola Cinnella and Patrick Gallinari}, 56 | booktitle={Thirty-sixth Conference on Neural Information Processing Systems Datasets and Benchmarks Track}, 57 | year={2022}, 58 | url={https://arxiv.org/abs/2212.07564} 59 | } 60 | ``` 61 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/0.orig/T: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object T; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 0 0 1 0 0 0]; 18 | 19 | field 298.15; 20 | 21 | internalField uniform $field; 22 | 23 | boundaryField 24 | { 25 | aerofoil 26 | { 27 | type zeroGradient; 28 | } 29 | 30 | freestream 31 | { 32 | type freestream; 33 | freestreamValue uniform $field; 34 | } 35 | 36 | frontAndBack 37 | { 38 | type empty; 39 | } 40 | } 41 | 42 | 43 | // ************************************************************************* // 44 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/0.orig/U: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volVectorField; 13 | object U; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 1 -1 0 0 0 0]; 18 | 19 | field (50 0 0); 20 | 21 | internalField uniform $field; 22 | 23 | boundaryField 24 | { 25 | aerofoil 26 | { 27 | type noSlip; 28 | } 29 | 30 | freestream 31 | { 32 | type freestreamVelocity; 33 | freestreamValue uniform $field; 34 | } 35 | 36 | frontAndBack 37 | { 38 | type empty; 39 | } 40 | } 41 | 42 | 43 | // ************************************************************************* // 44 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/0.orig/alphat: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object alphat; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [1 -1 -1 0 0 0 0]; 18 | 19 | field 1.569984e-5; // rho*nu_t/Pr_t, rho = 1.184, nu_t = 1.56e-5, Pr_t = 0.85 20 | 21 | internalField uniform $field; 22 | 23 | boundaryField 24 | { 25 | aerofoil 26 | { 27 | type compressible::alphatWallFunction; 28 | Prt 0.85; 29 | value uniform 0; 30 | } 31 | 32 | freestream 33 | { 34 | type calculated; 35 | value uniform $field; 36 | } 37 | 38 | frontAndBack 39 | { 40 | type empty; 41 | } 42 | } 43 | 44 | 45 | // ************************************************************************* // 46 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/0.orig/k: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object k; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 2 -2 0 0 0 0]; 18 | 19 | field 0; // 0.001*Uinf^2/Re_L, Re_L : Reynolds number computed with L the size of the computational domain and Uinf 20 | 21 | internalField uniform $field; 22 | 23 | boundaryField 24 | { 25 | aerofoil 26 | { 27 | type fixedValue; 28 | value uniform 0; 29 | } 30 | 31 | freestream 32 | { 33 | type freestream; 34 | freestreamValue uniform $field; 35 | } 36 | 37 | frontAndBack 38 | { 39 | type empty; 40 | } 41 | } 42 | 43 | 44 | // ************************************************************************* // 45 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/0.orig/nuTilda: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object nuTilda; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 2 -1 0 0 0 0]; 18 | 19 | field 6.24e-5; 20 | 21 | internalField uniform $field; 22 | 23 | boundaryField 24 | { 25 | aerofoil 26 | { 27 | type fixedValue; 28 | value uniform 0; 29 | } 30 | 31 | freestream 32 | { 33 | type freestream; 34 | freestreamValue uniform $field; 35 | } 36 | 37 | frontAndBack 38 | { 39 | type empty; 40 | } 41 | } 42 | 43 | 44 | // ************************************************************************* // 45 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/0.orig/nut: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object nut; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 2 -1 0 0 0 0]; 18 | 19 | field 1.56e-5; 20 | 21 | internalField uniform $field; 22 | 23 | boundaryField 24 | { 25 | aerofoil 26 | { 27 | type nutLowReWallFunction; 28 | value uniform 0; 29 | } 30 | 31 | freestream 32 | { 33 | type freestream; 34 | freestreamValue uniform $field; 35 | } 36 | 37 | frontAndBack 38 | { 39 | type empty; 40 | } 41 | } 42 | 43 | 44 | // ************************************************************************* // 45 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/0.orig/omega: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object omega; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dimensions [0 0 -1 0 0 0 0]; 18 | 19 | field 0; // 5*Uinf/L, L: size of the computational domain 20 | 21 | internalField uniform $field; 22 | 23 | boundaryField 24 | { 25 | aerofoil 26 | { 27 | type omegaWallFunction; 28 | value uniform 0; // 6*nu/(0.075*y_1^2), y_1 : height of the first wall cell 29 | } 30 | 31 | freestream 32 | { 33 | type freestream; 34 | freestreamValue uniform $field; 35 | } 36 | 37 | frontAndBack 38 | { 39 | type empty; 40 | } 41 | } 42 | 43 | // ************************************************************************* // 44 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/0.orig/p: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class volScalarField; 13 | object p; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | field 0; 18 | 19 | dimensions [0 2 -2 0 0 0 0]; 20 | 21 | internalField uniform $field; 22 | 23 | boundaryField 24 | { 25 | aerofoil 26 | { 27 | type zeroGradient; 28 | } 29 | 30 | freestream 31 | { 32 | type freestreamPressure; 33 | freestreamValue uniform $field; 34 | } 35 | 36 | frontAndBack 37 | { 38 | type empty; 39 | } 40 | } 41 | 42 | 43 | // ************************************************************************* // 44 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/constant/thermophysicalProperties: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object thermophysicalProperties; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | dpdt no; 18 | 19 | thermoType 20 | { 21 | type hePsiThermo; 22 | mixture pureMixture; 23 | transport sutherland; 24 | thermo hConst; 25 | equationOfState perfectGas; 26 | specie specie; 27 | energy sensibleInternalEnergy; 28 | } 29 | 30 | mixture // air 31 | { 32 | specie 33 | { 34 | molWeight 28.965338; 35 | } 36 | thermodynamics 37 | { 38 | Cp 1005; 39 | Hf 0; 40 | } 41 | transport 42 | { 43 | As 1.457e-6; 44 | Ts 110.4; 45 | } 46 | } 47 | 48 | // ************************************************************************* // 49 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/constant/transportProperties: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object transportProperties; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | transportModel Newtonian; 18 | 19 | nu 1.56e-5; 20 | 21 | 22 | // ************************************************************************* // 23 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/constant/turbulenceProperties: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object turbulenceProperties; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | simulationType RAS; 18 | 19 | RAS 20 | { 21 | RASModel SpalartAllmaras; 22 | 23 | turbulence on; 24 | 25 | printCoeffs on; 26 | } 27 | 28 | 29 | // ************************************************************************* // 30 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/system/blockMeshDict.orig: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object blockMeshDict; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | checkBlockFaceOrientation false; 18 | 19 | scale 1; 20 | 21 | domain 22 | { 23 | // Boundary of the domain 24 | xMin -200; 25 | xMax -$xMin; 26 | yMin $xMin; 27 | yMax -$xMin; 28 | xMid 33; 29 | xAngle 34.556; 30 | 31 | // Number of cells in each direction 32 | yCells 330; 33 | xUUCells 101; 34 | xDUCells 101; 35 | xUMCells 189; 36 | xDMCells 189; 37 | xDCells 134; 38 | 39 | // Grading 40 | yGrading 9360076.409; 41 | yUGrading 53889.885; 42 | yDGrading 79041.521; 43 | xUUGrading 77.867; 44 | xDUGrading 77.867; 45 | xUMAeroGrading 15.235; 46 | xDMAeroGrading 15.235; 47 | xMGrading 1; 48 | xDTrailGrading 6.648e-5; 49 | xUDGrading 4.260e-2; 50 | xDDGrading 4.260e-2; 51 | leadUGrading 7.230e-4; 52 | leadDGrading 7.230e-4; 53 | 54 | // Origin of the arcs 55 | xOrigin -550.128; 56 | yOrigin 190.741; 57 | } 58 | 59 | aerofoil 60 | { 61 | xLead 0; 62 | yLead 0; 63 | xTrail 1; 64 | yTrail 0; 65 | xUpper 0.247395; 66 | yUpper 0; 67 | xLower 0; 68 | yLower 0; 69 | } 70 | 71 | vertices 72 | ( 73 | ($domain.xMax $domain.yMin 0) 74 | ($domain.xMax $domain.xAngle 0) 75 | ($domain.xMax $domain.yMax 0) 76 | ($domain.xMid $domain.yMax 0) 77 | ($aerofoil.xUpper $domain.yMax 0) 78 | ($domain.xMin $aerofoil.yLead 0) 79 | ($aerofoil.xUpper $domain.yMin 0) 80 | ($domain.xMid $domain.yMin 0) 81 | ($aerofoil.xLead $aerofoil.yLead 0) 82 | ($aerofoil.xLower $aerofoil.yLower 0) 83 | ($aerofoil.xTrail $aerofoil.yTrail 0) 84 | ($aerofoil.xUpper $aerofoil.yUpper 0) 85 | 86 | ($domain.xMax $domain.yMin 1) 87 | ($domain.xMax $domain.xAngle 1) 88 | ($domain.xMax $domain.yMax 1) 89 | ($domain.xMid $domain.yMax 1) 90 | ($aerofoil.xUpper $domain.yMax 1) 91 | ($domain.xMin $aerofoil.yLead 1) 92 | ($aerofoil.xUpper $domain.yMin 1) 93 | ($domain.xMid $domain.yMin 1) 94 | ($aerofoil.xLead $aerofoil.yLead 1) 95 | ($aerofoil.xLower $aerofoil.yLower 1) 96 | ($aerofoil.xTrail $aerofoil.yTrail 1) 97 | ($aerofoil.xUpper $aerofoil.yUpper 1) 98 | ); 99 | 100 | blocks 101 | ( 102 | hex (1 10 7 0 13 22 19 12) 103 | ($domain.xDCells $domain.yCells 1) 104 | edgeGrading 105 | ( 106 | $domain.xDTrailGrading $domain.xDDGrading $domain.xDDGrading $domain.xDTrailGrading 107 | $domain.yDGrading $domain.yGrading $domain.yGrading $domain.yDGrading 108 | 1 1 1 1 109 | ) 110 | 111 | hex (13 22 15 14 1 10 3 2) 112 | ($domain.xDCells $domain.yCells 1) 113 | edgeGrading 114 | ( 115 | $domain.xDTrailGrading $domain.xUDGrading $domain.xUDGrading $domain.xDTrailGrading 116 | $domain.yUGrading $domain.yGrading $domain.yGrading $domain.yUGrading 117 | 1 1 1 1 118 | ) 119 | 120 | hex (22 23 16 15 10 11 4 3) 121 | ($domain.xUMCells $domain.yCells 1) 122 | edgeGrading 123 | ( 124 | $domain.xUMAeroGrading $domain.xMGrading $domain.xMGrading $domain.xUMAeroGrading 125 | $domain.yGrading $domain.yGrading $domain.yGrading $domain.yGrading 126 | 1 1 1 1 127 | ) 128 | 129 | hex (10 9 6 7 22 21 18 19) 130 | ($domain.xDMCells $domain.yCells 1) 131 | edgeGrading 132 | ( 133 | $domain.xDMAeroGrading $domain.xMGrading $domain.xMGrading $domain.xDMAeroGrading 134 | $domain.yGrading $domain.yGrading $domain.yGrading $domain.yGrading 135 | 1 1 1 1 136 | ) 137 | 138 | hex (23 20 17 16 11 8 5 4) 139 | ($domain.xUUCells $domain.yCells 1) 140 | edgeGrading 141 | ( 142 | $domain.leadUGrading $domain.xUUGrading $domain.xUUGrading $domain.leadUGrading 143 | $domain.yGrading $domain.yGrading $domain.yGrading $domain.yGrading 144 | 1 1 1 1 145 | ) 146 | 147 | hex (9 8 5 6 21 20 17 18) 148 | ($domain.xDUCells $domain.yCells 1) 149 | edgeGrading 150 | ( 151 | $domain.leadDGrading $domain.xDUGrading $domain.xDUGrading $domain.leadDGrading 152 | $domain.yGrading $domain.yGrading $domain.yGrading $domain.yGrading 153 | 1 1 1 1 154 | ) 155 | ); 156 | 157 | edges 158 | ( 159 | arc 4 5 origin ($aerofoil.xUpper 0 0) 160 | arc 16 17 origin ($aerofoil.xUpper 0 1) 161 | 162 | arc 5 6 origin ($aerofoil.xUpper 0 0) 163 | arc 17 18 origin ($aerofoil.xUpper 0 1) 164 | 165 | arc 10 3 origin ($domain.xOrigin $domain.yOrigin 0) 166 | arc 22 15 origin ($domain.xOrigin $domain.yOrigin 1) 167 | 168 | arc 7 10 origin ($domain.xOrigin -$domain.yOrigin 0) 169 | arc 19 22 origin ($domain.xOrigin -$domain.yOrigin 1) 170 | ); 171 | 172 | boundary 173 | ( 174 | aerofoil 175 | { 176 | type wall; 177 | faces 178 | ( 179 | (8 11 23 20) 180 | (8 20 21 9) 181 | (9 21 22 10) 182 | (11 10 22 23) 183 | ); 184 | } 185 | 186 | freestream 187 | { 188 | type patch; 189 | faces 190 | ( 191 | // inlet 192 | (4 5 17 16) 193 | (5 6 18 17) 194 | 195 | // outlet 196 | (2 1 13 14) 197 | (1 0 12 13) 198 | 199 | // top 200 | (3 4 16 15) 201 | (2 3 15 14) 202 | 203 | // bottom 204 | (6 7 19 18) 205 | (7 0 12 19) 206 | ); 207 | } 208 | 209 | frontAndBack 210 | { 211 | type empty; 212 | faces 213 | ( 214 | (1 10 3 2) 215 | (3 10 11 4) 216 | (4 11 8 5) 217 | (5 8 9 6) 218 | (6 9 10 7) 219 | (0 7 10 1) 220 | 221 | (13 14 15 22) 222 | (15 16 23 22) 223 | (16 17 20 23) 224 | (17 18 21 20) 225 | (18 19 22 21) 226 | (12 13 22 19) 227 | ); 228 | } 229 | ); 230 | 231 | // ************************************************************************* // 232 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/system/controlDict.orig: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object controlDict; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | Uinf 50; 17 | 18 | application simpleFoam; 19 | 20 | startFrom startTime; 21 | 22 | startTime 0; 23 | 24 | stopAt endTime; 25 | 26 | endTime 10000; 27 | 28 | deltaT 1; 29 | 30 | writeControl timeStep; 31 | 32 | writeInterval $endTime; 33 | 34 | purgeWrite 0; 35 | 36 | writeFormat ascii; 37 | 38 | writePrecision 6; 39 | 40 | writeCompression on; 41 | 42 | timeFormat general; 43 | 44 | timePrecision 6; 45 | 46 | runTimeModifiable true; 47 | 48 | functions 49 | { 50 | forces_object 51 | { 52 | type forces; 53 | libs ("libforces.so"); 54 | 55 | enabled true; 56 | 57 | writeControl timeStep; 58 | writeInterval $endTime; 59 | 60 | patches ("aerofoil"); 61 | 62 | p p; 63 | U U; 64 | rho rhoInf; 65 | 66 | //// Density only for incompressible flows 67 | rhoInf 1.184; 68 | 69 | //// Centre of rotation 70 | CofR (0 0 0); 71 | } 72 | 73 | forceCoeffs1 74 | { 75 | // Mandatory entries 76 | type forceCoeffs; 77 | libs ("libforces.so"); 78 | patches ("aerofoil"); 79 | 80 | 81 | // Optional entries 82 | 83 | // Field names 84 | p p; 85 | U U; 86 | rho rhoInf; 87 | 88 | ////Density only for incompressible flows 89 | rhoInf 1.184; 90 | 91 | // Reference pressure [Pa] 92 | pRef 0; 93 | 94 | // Include porosity effects? 95 | porosity no; 96 | 97 | // Store and write volume field representations of forces and moments 98 | writeFields yes; 99 | writeControl timeStep; 100 | writeInterval $endTime; 101 | 102 | // Centre of rotation for moment calculations 103 | CofR (0 0 0); 104 | 105 | // Lift direction 106 | liftDir (0 1 0); 107 | 108 | // Drag direction 109 | dragDir (1 0 0); 110 | 111 | // Pitch axis 112 | pitchAxis (0 0 1); 113 | 114 | // Freestream velocity magnitude [m/s] 115 | magUInf $Uinf; 116 | 117 | // Reference length [m] 118 | lRef 1; 119 | 120 | // Reference area [m2] 121 | Aref 1; 122 | 123 | // Spatial data binning 124 | // - extents given by the bounds of the input geometry 125 | /*binData 126 | { 127 | nBin 20; 128 | direction (1 0 0); 129 | cumulative yes; 130 | }*/ 131 | } 132 | 133 | momErr 134 | { 135 | type momentumError; 136 | libs (fieldFunctionObjects); 137 | executeControl writeTime; 138 | writeControl writeTime; 139 | } 140 | 141 | contErr 142 | { 143 | type div; 144 | libs (fieldFunctionObjects); 145 | field phi; 146 | executeControl writeTime; 147 | writeControl writeTime; 148 | } 149 | 150 | 151 | turbulenceFields1 152 | { 153 | type turbulenceFields; 154 | libs (fieldFunctionObjects); 155 | fields 156 | ( 157 | R 158 | I 159 | L 160 | k 161 | epsilon 162 | omega 163 | nut 164 | nuEff 165 | devReff 166 | ); 167 | 168 | executeControl writeTime; 169 | writeControl writeTime; 170 | } 171 | 172 | yplus 173 | { 174 | type yPlus; 175 | libs (fieldFunctionObjects); 176 | 177 | enabled true; 178 | executeControl writeTime; 179 | writeControl writeTime; 180 | } 181 | 182 | wallshearstress 183 | { 184 | type wallShearStress; 185 | libs (fieldFunctionObjects); 186 | 187 | executeControl writeTime; 188 | writeControl writeTime; 189 | } 190 | 191 | mach 192 | { 193 | type MachNo; 194 | libs (fieldFunctionObjects); 195 | 196 | executeControl writeTime; 197 | writeControl writeTime; 198 | } 199 | } 200 | 201 | 202 | // ************************************************************************* // 203 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/system/decomposeParDict: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object decomposeParDict; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | numberOfSubdomains 16; 18 | 19 | method scotch; 20 | 21 | // ************************************************************************* // 22 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/system/fvOptions: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object fvOptions; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | limitT 18 | { 19 | type limitTemperature; 20 | min 200; 21 | max 400; 22 | selectionMode all; 23 | } 24 | 25 | 26 | //************************************************************************** // 27 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/system/fvSchemes: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object fvSchemes; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | ddtSchemes 18 | { 19 | default steadyState; 20 | } 21 | 22 | gradSchemes 23 | { 24 | default Gauss linear; 25 | 26 | // Spalart-Allmaras 27 | grad(nuTilda) cellLimited Gauss linear 1; 28 | 29 | // k-omega SST 30 | grad(k) cellLimited Gauss linear 1; 31 | grad(omega) cellLimited Gauss linear 1; 32 | 33 | // Compressible 34 | grad(e) cellLimited Gauss linear 1; 35 | grad(K) cellLimited Gauss linear 1; 36 | grad(Ekp) cellLimited Gauss linear 1; 37 | } 38 | 39 | divSchemes 40 | { 41 | default Gauss linear; 42 | 43 | div(phi,U) bounded Gauss linearUpwind grad(U); 44 | 45 | // Spalart-Allmaras 46 | div(phi,nuTilda) bounded Gauss linearUpwind grad(nuTilda); 47 | 48 | // k-omega SST 49 | div(phi,k) bounded Gauss linearUpwind grad(k); 50 | div(phi,omega) bounded Gauss linearUpwind grad(omega); 51 | 52 | // Incompressible 53 | div((nuEff*dev2(T(grad(U))))) Gauss linear; 54 | 55 | // Compressible 56 | div(phi,e) bounded Gauss linearUpwind grad(e); 57 | div(phi,K) bounded Gauss linearUpwind grad(K); 58 | div(phi,Ekp) bounded Gauss linearUpwind grad(Ekp); 59 | div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear; 60 | } 61 | 62 | laplacianSchemes 63 | { 64 | default Gauss linear limited 1; 65 | } 66 | 67 | interpolationSchemes 68 | { 69 | default linear; 70 | } 71 | 72 | snGradSchemes 73 | { 74 | default limited 1; 75 | } 76 | 77 | wallDist 78 | { 79 | method meshWave; 80 | correctWalls true; 81 | } 82 | 83 | 84 | // ************************************************************************* // 85 | -------------------------------------------------------------------------------- /Simulations/airFoil2DInit/system/fvSolution: -------------------------------------------------------------------------------- 1 | /*--------------------------------*- C++ -*----------------------------------*\ 2 | | ========= | | 3 | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | 4 | | \\ / O peration | Version: v2112 | 5 | | \\ / A nd | Website: www.openfoam.com | 6 | | \\/ M anipulation | | 7 | \*---------------------------------------------------------------------------*/ 8 | FoamFile 9 | { 10 | version 2.0; 11 | format ascii; 12 | class dictionary; 13 | object fvSolution; 14 | } 15 | // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // 16 | 17 | solvers 18 | { 19 | p 20 | { 21 | solver PCG; 22 | preconditioner DIC; 23 | tolerance 1e-06; 24 | relTol 0; 25 | minIter 10; 26 | maxIter 300; 27 | } 28 | 29 | "(U|nuTilda|k|omega|e|rho)" 30 | { 31 | solver PBiCGStab; 32 | preconditioner DILU; 33 | tolerance 1e-08; 34 | relTol 0; 35 | minIter 3; 36 | maxIter 50; 37 | } 38 | } 39 | 40 | SIMPLE 41 | { 42 | consistent yes; 43 | nNonOrthogonalCorrectors 3; 44 | 45 | residualControl 46 | { 47 | p 0; 48 | U 0; 49 | nuTilda 0; 50 | k 0; 51 | omega 0; 52 | h 0; 53 | } 54 | } 55 | 56 | relaxationFactors 57 | { 58 | fields 59 | { 60 | p 1; 61 | rho 0.01; 62 | } 63 | equations 64 | { 65 | h 0.9; 66 | U 0.9; 67 | nuTilda 0.9; 68 | k 0.9; 69 | omega 0.9; 70 | } 71 | } 72 | 73 | 74 | // ************************************************************************* // 75 | -------------------------------------------------------------------------------- /dataset_generator.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import numpy as np 3 | import metrics 4 | from simulation_generator import simulation 5 | 6 | # Global path where the airFoil2DInit folder is and where the simulations are gonna be done. 7 | glob_path = 'Simulations/' 8 | 9 | with open('params.yaml', 'r') as f: # hyperparameters of the model 10 | params = yaml.safe_load(f) 11 | 12 | # Properties of air at 1.01325hPa 13 | NU = -3.400747e-6 + 3.452139e-8*params['temperature'] + 1.00881778e-10*params['temperature']**2 - 1.363528e-14*params['temperature']**3 14 | 15 | n = 5 # Size of the dataset is 2n 16 | Reynolds = np.random.uniform(2, 6, 2*n)*1e6 17 | AoA = np.random.uniform(-5, 15, 2*n) 18 | 19 | # 4-digits 20 | M = np.random.uniform(0, 7, n) 21 | P_4 = np.random.uniform(0, 7, n) 22 | P_4[P_4 < 1.5] = 0 23 | XX_4 = np.random.uniform(5, 20, n) 24 | 25 | # 5-digits 26 | L = np.random.uniform(0, 4, n) 27 | P_5 = np.random.uniform(3, 8, n) 28 | Q = np.random.randint(2, size = n) 29 | XX_5 = np.random.uniform(5, 20, n) 30 | 31 | design_space = [] 32 | for i in range(len(M)): 33 | design_space.append([Reynolds[i], AoA[i], M[i], P_4[i], XX_4[i]]) 34 | for i in range(len(L)): 35 | design_space.append([Reynolds[i + len(M)], AoA[i + len(M)], L[i], P_5[i], Q[i], XX_5[i]]) 36 | 37 | index = np.arange(len(Reynolds)) 38 | np.random.shuffle(index) 39 | design_space_shuffle = [] 40 | for i in range(len(design_space)): 41 | design_space_shuffle.append(design_space[index[i]]) 42 | 43 | for sim in design_space_shuffle: 44 | params['Uinf'] = np.round(sim[0]*NU, 3) 45 | params['aoa'] = np.round(sim[1], 3) # Angle of attack. (< 15) 46 | params['digits'] = tuple(np.round(sim[2:], 3)) # 4 or 5-digits for the naca airfoil. 47 | if np.abs(params['aoa']) <= 10: 48 | params['n_iter'] = 20000 49 | else: 50 | params['n_iter'] = 40000 51 | 52 | init_path = glob_path + 'airFoil2DInit/' # OpenFoam initial case path (don't forget the '/' at the end of the path) 53 | 54 | digits = '' 55 | for digit in params['digits']: 56 | digits = digits + '_' + str(digit) 57 | path = glob_path + 'airFoil2D_' + params['turbulence'] + '_' + str(params['Uinf']) + '_' + str(params['aoa']) + digits + '/' 58 | 59 | simulation(init_path, path, params, figure = True, compute_grad = True, VTK = True) 60 | res = metrics.plot_residuals(path, params) 61 | coef = metrics.plot_coef_convergence(path, params) 62 | with open(glob_path + 'manifest', 'a') as manifest: 63 | manifest.write('airFoil2D_' + params['turbulence'] + '_' + str(params['Uinf']) + '_' + str(params['aoa']) + digits + '\n') -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import yaml, argparse 2 | import numpy as np 3 | import metrics 4 | from simulation_generator import simulation 5 | 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument('-i', '--init', help = 'Only generate the mesh (default: 0)', default = 0, type = int) 8 | parser.add_argument('-g', '--gradient', help = 'Compute the term of the RANS equations as a post-processing (default: 0)', default = 0, type = int) 9 | parser.add_argument('-v', '--vtk', help = 'Generate the VTK files from the simulation (default: 1)', default = 1, type = int) 10 | parser.add_argument('-f', '--figure', help = 'Save an image of the airfoil in the simulation folder (default: 1)', default = 1, type = int) 11 | args = parser.parse_args() 12 | 13 | # Global path where the airFoil2DInit folder is and where the simulations are gonna be done. 14 | glob_path = 'Simulations/' 15 | 16 | with open('params.yaml', 'r') as f: # hyperparameters of the model 17 | params = yaml.safe_load(f) 18 | 19 | # Properties of air at 1.01325hPa 20 | NU = -3.400747e-6 + 3.452139e-8*params['temperature'] + 1.00881778e-10*params['temperature']**2 - 1.363528e-14*params['temperature']**3 21 | 22 | params['Uinf'] = np.round(params['reynolds']*NU, 3) 23 | params['aoa'] = np.round(params['aoa'], 3) # Angle of attack. (< 15) 24 | params['digits'] = tuple(np.round(params['digits'], 3)) # 4 or 5-digits for the naca airfoil. 25 | 26 | init_path = glob_path + 'airFoil2DInit/' # OpenFoam initial case path (don't forget the '/' at the end of the path) 27 | 28 | digits = '' 29 | for digit in params['digits']: 30 | digits = digits + '_' + str(digit) 31 | path = glob_path + 'airFoil2D_' + params['turbulence'] + '_' + str(params['Uinf']) + '_' + str(params['aoa']) + digits + '/' 32 | 33 | simulation(init_path, path, params, just_init = bool(args.init), figure = bool(args.figure), compute_grad = bool(args.gradient), VTK = bool(args.vtk)) 34 | res = metrics.plot_residuals(path, params) 35 | coef = metrics.plot_coef_convergence(path, params) -------------------------------------------------------------------------------- /mesh_scheme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Extrality/NACA_simulation/2dbf00c5ecbb8d6cef720db1e72c1fe40307eeab/mesh_scheme.pdf -------------------------------------------------------------------------------- /metrics.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import yaml 3 | import matplotlib.pyplot as plt 4 | import seaborn as sns 5 | 6 | sns.set() 7 | 8 | with open('params.yaml', 'r') as f: # hyperparameters of the model 9 | params = yaml.safe_load(f) 10 | 11 | # Properties of air at 1.01325hPa 12 | MOL = 28.965338 # Molar weight in g/mol 13 | P_ref = 1.01325e5 14 | RHO = P_ref*MOL*1e-3/(8.3144621*params['temperature']) 15 | NU = -3.400747e-6 + 3.452139e-8*params['temperature'] + 1.00881778e-10*params['temperature']**2 - 1.363528e-14*params['temperature']**3 16 | C = 20.05*np.sqrt(params['temperature']) 17 | 18 | def surface_coefficients(airfoil, params, sorted = True): 19 | qInf = 0.5*params['Uinf']**2 20 | # if params['compressible']: # OpenFOAM case path (don't forget the '/' at the end of the path) 21 | # fold = 'airFoil2D_rho_' + params['turbulence'] + '_' + str(params['digits']) + '_' + str(params['aoa']) + '_' + str(params['Uinf']) + '_' + str(params['n_iter']) + '/' 22 | # else: 23 | # fold = 'airFoil2D_' + params['turbulence'] + '_' + str(params['digits']) + '_' + str(params['aoa']) + '_' + str(params['Uinf']) + '_' + str(params['n_iter']) + '/' 24 | # aerofoil = pv.read(path + 'VTK/' + fold + 'boundary/aerofoil.vtp').cell_centers() 25 | aerofoil = airfoil.cell_centers() 26 | 27 | if sorted: 28 | jump = np.argwhere(np.abs(aerofoil.points[:-1, 0] - aerofoil.points[1:, 0]) > 5e-2) + 1 29 | n_extrado = len(aerofoil.points) - jump[2, 0] + jump[0, 0] 30 | points = np.vstack([ 31 | aerofoil.points[jump[2, 0]:, 0], aerofoil.points[:jump[0, 0], 0], 32 | aerofoil.points[jump[0, 0]:jump[1, 0], 0][::-1], aerofoil.points[jump[1, 0]:jump[2, 0], 0][::-1] 33 | ]) 34 | pressure = np.vstack([ 35 | aerofoil.cell_data['p'][jump[2, 0]:], aerofoil.cell_data['p'][:jump[0, 0]], 36 | aerofoil.cell_data['p'][jump[0, 0]:jump[1, 0]][::-1], aerofoil.cell_data['p'][jump[1, 0]:jump[2, 0]][::-1] 37 | ]) 38 | 39 | wss = np.vstack([ 40 | aerofoil.cell_data['wallShearStress'][jump[2, 0]:, :2], aerofoil.cell_data['wallShearStress'][:jump[0, 0], :2], 41 | aerofoil.cell_data['wallShearStress'][jump[0, 0]:jump[1, 0], :2][::-1], aerofoil.cell_data['wallShearStress'][jump[1, 0]:jump[2, 0], :2][::-1] 42 | ]) 43 | wss = np.linalg.norm(wss, axis = 1) 44 | else: 45 | points = aerofoil.points[:, 0] 46 | pressure = aerofoil.cell_data['p'] 47 | wss = np.linalg.norm(aerofoil.cell_data['wallShearStress'][:, :2], axis = 1) 48 | 49 | if params['compressible']: 50 | c_p = np.vstack([points, (pressure - P_ref)/qInf/RHO]).T 51 | else: 52 | c_p = np.vstack([points, pressure/qInf]).T 53 | c_l = np.vstack([points, wss/qInf/RHO]).T 54 | 55 | if sorted: 56 | results = (c_p, c_l, n_extrado) 57 | else: 58 | results = (c_p, c_l) 59 | return results 60 | 61 | def compare_surface_coefs(coefs1, coefs2, extrado = True, path = None): 62 | ycp1, ycp2, c_p1, c_p2 = coefs1[0][:, 0], coefs2[0][:, 0], coefs1[0][:, 1], coefs2[0][:, 1] 63 | ycl1, ycl2, c_f1, c_f2 = coefs1[1][:, 0], coefs2[1][:, 0], coefs1[1][:, 1], coefs2[1][:, 1] 64 | 65 | fig, ax = plt.subplots(2, figsize = (20, 10)) 66 | if extrado: 67 | n_extrado1, n_extrado2 = coefs1[2], coefs2[2] 68 | ax[0].scatter(ycp1[:n_extrado1], c_p1[:n_extrado1], label = 'Extrado 1') 69 | ax[0].scatter(ycp1[:n_extrado1], c_p1[:n_extrado1], color = 'r', marker = 'x', label = 'Intrado 1') 70 | ax[0].scatter(ycp2[:n_extrado2], c_p2[:n_extrado2], color = 'y', label = 'Extrado 2') 71 | ax[0].scatter(ycp2[:n_extrado2], c_p2[:n_extrado2], color = 'r', marker = 'x', label = 'Intrado 2') 72 | 73 | ax[1].scatter(ycl1[:n_extrado1], c_f1[:n_extrado1], label = 'Extrado 1') 74 | ax[1].scatter(ycl1[:n_extrado1], c_f1[:n_extrado1], color = 'r', marker = 'x', label = 'Intrado 1') 75 | ax[1].scatter(ycl2[:n_extrado2], c_f2[:n_extrado2], color = 'y', label = 'Extrado 2') 76 | ax[1].scatter(ycl2[:n_extrado2], c_f2[:n_extrado2], color = 'g', marker = 'x', label = 'Intrado 2') 77 | 78 | else: 79 | ax[0].scatter(ycp1, c_p1, label = 'Experiment 1') 80 | ax[0].scatter(ycp2, c_p2, color = 'y', label = 'Experiment 2') 81 | 82 | ax[1].scatter(ycl1, c_f1, label = 'Experiment 1') 83 | ax[1].scatter(ycl2, c_f2, color = 'y', label = 'Experiment 2') 84 | 85 | ax[0].invert_yaxis() 86 | ax[0].set_xlabel('x/c') 87 | ax[1].set_xlabel('x/c') 88 | ax[0].set_ylabel(r'$C_p$') 89 | ax[1].set_ylabel(r'$C_f$') 90 | ax[0].set_title('Pressure coefficient') 91 | ax[1].set_title('Skin friction coefficient') 92 | ax[0].legend(loc = 'best') 93 | ax[1].legend(loc = 'best') 94 | 95 | if path != None: 96 | fig.savefig(path + 'surface_coefs.png', bbox_inches = 'tight', dpi = 150) 97 | 98 | def boundary_layer(airfoil, internal, x, params, y = .1, resolution = int(1e4), rotation = True): 99 | u_inf = params['Uinf'] 100 | # if params['compressible']: # OpenFOAM case path (don't forget the '/' at the end of the path) 101 | # fold = 'airFoil2D_rho_' + params['turbulence'] + '_' + str(params['digits']) + '_' + str(params['aoa']) + '_' + str(params['Uinf']) + '_' + str(params['n_iter']) + '/' 102 | # else: 103 | # fold = 'airFoil2D_' + params['turbulence'] + '_' + str(params['digits']) + '_' + str(params['aoa']) + '_' + str(params['Uinf']) + '_' + str(params['n_iter']) + '/' 104 | # aerofoil = pv.read(path + 'VTK/' + fold + 'boundary/aerofoil.vtp') 105 | aerofoil = airfoil.compute_normals(point_normals = False, inplace = True, flip_normals = True).cell_centers() 106 | 107 | jump = np.argwhere(np.abs(aerofoil.points[:-1, 0] - aerofoil.points[1:, 0]) > 5e-2) + 1 108 | n_extrado = len(aerofoil.points) - jump[2, 0] + jump[0, 0] 109 | points = np.vstack([ 110 | aerofoil.points[jump[2, 0]:], aerofoil.points[:jump[0, 0]], 111 | aerofoil.points[jump[0, 0]:jump[1, 0]][::-1], aerofoil.points[jump[1, 0]:jump[2, 0]][::-1] 112 | ]) 113 | normals = np.vstack([ 114 | aerofoil.cell_data['Normals'][jump[2, 0]:], aerofoil.cell_data['Normals'][:jump[0, 0]], 115 | aerofoil.cell_data['Normals'][jump[0, 0]:jump[1, 0]][::-1], aerofoil.cell_data['Normals'][jump[1, 0]:jump[2, 0]][::-1] 116 | ]) 117 | 118 | arg = np.argmin(np.abs(points[:n_extrado, 0] - x)) 119 | a, b = points[arg], points[arg] + y*normals[arg] 120 | 121 | # internal = pv.read(path + 'VTK/' + fold + 'internal.vtu') 122 | bl = internal.sample_over_line(a, b, resolution = resolution) 123 | 124 | if rotation: 125 | rot = np.array([[0, 1, 0], [-1, 0, 0], [0, 0, 1]]) 126 | u = (bl.point_data['U']*(rot@normals[arg])).sum(axis = 1) 127 | v = (bl.point_data['U']*normals[arg]).sum(axis = 1) 128 | else: 129 | u = bl.point_data['U'][:, 0] 130 | v = bl.point_data['U'][:, 1] 131 | 132 | nut = bl.point_data['nut'] 133 | yc = bl.points[:, 1] - a[1] 134 | 135 | return yc, u/u_inf, v/u_inf, nut/NU 136 | 137 | def compare_boundary_layer(coefs1, coefs2, ylim = .1, path = None): 138 | yc1, u1, v1, nut1 = coefs1 139 | yc2, u2, v2, nut2 = coefs2 140 | 141 | fig, ax = plt.subplots(1, 3, figsize = (30, 10)) 142 | ax[0].scatter(u1, yc1, label = 'Experiment 1') 143 | ax[0].scatter(u2, yc2, label = 'Experiment 2', color = 'r', marker = 'x') 144 | ax[0].set_xlabel(r'$u/U_\infty$') 145 | ax[0].set_ylabel(r'$(y-y_0)/c$') 146 | # ax[0].set_xlim([-0.2, 1.4]) 147 | ax[0].set_ylim([0, ylim]) 148 | ax[0].legend(loc = 'best') 149 | 150 | ax[1].scatter(v1, yc1, label = 'Experiment 1') 151 | ax[1].scatter(v2, yc2, label = 'Experiment 2', color = 'r', marker = 'x') 152 | ax[1].set_xlabel(r'$v/U_\infty$') 153 | ax[1].set_ylabel(r'$(y-y_0)/c$') 154 | # ax[1].set_xlim([-0.2, 0.2]) 155 | ax[1].set_ylim([0, ylim]) 156 | ax[1].legend(loc = 'best') 157 | 158 | ax[2].scatter(nut1, yc1, label = 'Experience 1') 159 | ax[2].scatter(nut2, yc2, label = 'Experience 2', color = 'r', marker = 'x') 160 | ax[2].set_ylim([0, ylim]) 161 | ax[2].set_xlabel(r'$\nu_t/\nu$') 162 | ax[2].set_ylabel(r'$(y-y_0)/c$') 163 | ax[2].legend(loc = 'best') 164 | 165 | if path != None: 166 | fig.savefig(path + 'boundary_layer.png', bbox_inches = 'tight', dpi = 150) 167 | 168 | def plot_residuals(path, params): 169 | datas = dict() 170 | if params['turbulence'] == 'SA': 171 | fields = ['Ux', 'Uy', 'p', 'nuTilda'] 172 | elif params['turbulence'] == 'SST': 173 | fields = ['Ux', 'Uy', 'p', 'k', 'omega'] 174 | for field in fields: 175 | data = np.loadtxt(path + 'logs/' + field +'_0')[:, 1] 176 | datas[field] = data 177 | 178 | if params['turbulence'] == 'SA': 179 | fig, ax = plt.subplots(2, 2, figsize = (20, 20)) 180 | ax[1, 1].plot(datas['nuTilda']) 181 | ax[1, 1].set_yscale('log') 182 | ax[1, 1].set_title('nuTilda residual') 183 | ax[1, 1].set_xlabel('Number of iterations') 184 | 185 | elif params['turbulence'] == 'SST': 186 | fig, ax = plt.subplots(3, 2, figsize = (30, 20)) 187 | ax[1, 1].plot(datas['k']) 188 | ax[1, 1].set_yscale('log') 189 | ax[1, 1].set_title('k residual') 190 | ax[1, 1].set_xlabel('Number of iterations') 191 | 192 | ax[2, 0].plot(datas['omega']) 193 | ax[2, 0].set_yscale('log') 194 | ax[2, 0].set_title('omega residual') 195 | ax[2, 0].set_xlabel('Number of iterations'); 196 | 197 | ax[0, 0].plot(datas['Ux']) 198 | ax[0, 0].set_yscale('log') 199 | ax[0, 0].set_title('Ux residual') 200 | 201 | ax[0, 1].plot(datas['Uy']) 202 | ax[0, 1].set_yscale('log') 203 | ax[0, 1].set_title('Uy residual') 204 | 205 | ax[1, 0].plot(datas['p']) 206 | ax[1, 0].set_yscale('log') 207 | ax[1, 0].set_title('p residual') 208 | ax[1, 0].set_xlabel('Number of iterations'); 209 | 210 | fig.savefig(path + 'residuals.png', bbox_inches = 'tight', dpi = 150) 211 | 212 | return datas 213 | 214 | def plot_coef_convergence(path, params): 215 | datas = dict() 216 | datas['c_d'] = np.loadtxt(path + 'postProcessing/forceCoeffs1/0/coefficient.dat')[:, 1] 217 | datas['c_l'] = np.loadtxt(path + 'postProcessing/forceCoeffs1/0/coefficient.dat')[:, 3] 218 | c_d, c_l = datas['c_d'][-1], datas['c_l'][-1] 219 | 220 | fig, ax = plt.subplots(2, figsize = (30, 15)) 221 | ax[0].plot(datas['c_d']) 222 | ax[0].set_ylim([.5*c_d, 1.5*c_d]) 223 | ax[0].set_title('Drag coefficient') 224 | ax[0].set_xlabel('Number of iterations') 225 | ax[0].set_ylabel(r'$C_D$') 226 | 227 | ax[1].plot(datas['c_l']) 228 | ax[1].set_title('Lift coefficient') 229 | ax[1].set_ylim([.5*c_l, 1.5*c_l]) 230 | ax[1].set_ylabel(r'$C_L$') 231 | ax[1].set_xlabel('Number of iterations'); 232 | 233 | print('Drag coefficient: {0:.5}, lift coefficient: {1:.5}'.format(c_d, c_l)) 234 | 235 | fig.savefig(path + 'coef_convergence.png', bbox_inches = 'tight', dpi = 150) 236 | 237 | return datas, c_d, c_l -------------------------------------------------------------------------------- /naca_generator.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def thickness_dist(t, x, CTE = True): 4 | if CTE: 5 | a = -0.1036 6 | else: 7 | a = -0.1015 8 | return 5*t*(0.2969*np.sqrt(x) - 0.1260*x - 0.3516*x**2 + 0.2843*x**3 + a*x**4) 9 | 10 | def camber_line(params, x): 11 | assert np.all(np.logical_and(x >= 0, x <= 1)), 'Found x > 1 or x < 0' 12 | y_c = np.zeros_like(x) 13 | dy_c = np.zeros_like(x) 14 | 15 | if len(params) == 2: 16 | m = params[0]/100 17 | p = params[1]/10 18 | 19 | if p == 0: 20 | dy_c = -2*m*x 21 | return y_c, dy_c 22 | elif p == 1: 23 | dy_c = 2*m*(1 - x) 24 | return y_c, dy_c 25 | 26 | mask1 = np.logical_and(x >= 0, x < p) 27 | mask2 = np.logical_and(x >= p, x <= 1) 28 | y_c[mask1] = (m/p**2)*(2*p*x[mask1] - x[mask1]**2) 29 | dy_c[mask1] = (2*m/p**2)*(p - x[mask1]) 30 | y_c[mask2] = (m/(1 - p)**2)*((1 - 2*p) + 2*p*x[mask2] - x[mask2]**2) 31 | dy_c[mask2] = (2*m/(1 - p)**2)*(p - x[mask2]) 32 | 33 | elif len(params) == 3: 34 | l, p, q = params 35 | c_l, x_f = 3/20*l, p/20 36 | 37 | f = lambda x: x*(1 - np.sqrt(x/3)) - x_f 38 | df = lambda x: 1 - 3*np.sqrt(x/3)/2 39 | old_m = 0.5 40 | cond = True 41 | while cond: 42 | new_m = np.max([old_m - f(old_m)/df(old_m), 0]) 43 | cond = (np.abs(old_m - new_m) > 1e-15) 44 | old_m = new_m 45 | m = old_m 46 | r = (3*m - 7*m**2 + 8*m**3 - 4*m**4)/np.sqrt(m*(1 - m)) - 3/2*(1 - 2*m)*(np.pi/2 - np.arcsin(1 - 2*m)) 47 | k_1 = c_l/r 48 | 49 | mask1 = np.logical_and(x >= 0, x <= m) 50 | mask2 = np.logical_and(x > m, x <= 1) 51 | if q == 0: 52 | y_c[mask1] = k_1*((x[mask1]**3 - 3*m*x[mask1]**2 + m**2*(3 - m)*x[mask1])) 53 | dy_c[mask1] = k_1*(3*x[mask1]**2 - 6*m*x[mask1] + m**2*(3 - m)) 54 | y_c[mask2] = k_1*m**3*(1 - x[mask2]) 55 | dy_c[mask2] = -k_1*m**3*np.ones_like(dy_c[mask2]) 56 | 57 | elif q == 1: 58 | k = (3*(m - x_f)**2 - m**3)/(1 - m)**3 59 | y_c[mask1] = k_1*((x[mask1] - m)**3 - k*(1 - m)**3*x[mask1] - m**3*x[mask1] + m**3) 60 | dy_c[mask1] = k_1*(3*(x[mask1] - m)**2 - k*(1 - m)**3 - m**3) 61 | y_c[mask2] = k_1*(k*(x[mask2] - m)**3 - k*(1 - m)**3*x[mask2] - m**3*x[mask2] + m**3) 62 | dy_c[mask2] = k_1*(3*k*(x[mask2] - m)**2 - k*(1 - m)**3 - m**3) 63 | 64 | else: 65 | raise ValueError('Q must be 0 for normal camber or 1 for reflex camber.') 66 | 67 | else: 68 | raise ValueError('The first input must be a tuple of the 2 or 3 digits that represent the camber line.') 69 | 70 | return y_c, dy_c 71 | 72 | def naca_generator(params, nb_samples = 400, scale = 1, origin = (0, 0), cosine_spacing = True, verbose = True, CTE = True): 73 | if len(params) == 3: 74 | params_c = params[:2] 75 | t = params[2]/100 76 | if verbose: 77 | print(f'Generating naca M = {params_c[0]}, P = {params_c[1]}, XX = {t*100}') 78 | elif len(params) == 4: 79 | params_c = params[:3] 80 | t = params[3]/100 81 | if verbose: 82 | print(f'Generating naca L = {params_c[0]}, P = {params_c[1]}, Q = {params_c[2]}, XX = {t*100}') 83 | else: 84 | raise ValueError('The first argument must be a tuple of the 4 or 5 digits of the airfoil.') 85 | 86 | if cosine_spacing: 87 | beta = np.pi*np.linspace(1, 0, nb_samples + 1, endpoint = True) 88 | x = (1 - np.cos(beta))/2 89 | else: 90 | x = np.linspace(1, 0, nb_samples + 1, endpoint = True) 91 | 92 | y_c, dy_c = camber_line(params_c, x) 93 | y_t = thickness_dist(t, x, CTE) 94 | theta = np.arctan(dy_c) 95 | x_u = x - y_t*np.sin(theta) 96 | x_l = x + y_t*np.sin(theta) 97 | y_u = y_c + y_t*np.cos(theta) 98 | y_l = y_c - y_t*np.cos(theta) 99 | x = np.concatenate([x_u, x_l[:-1][::-1]], axis=0) 100 | y = np.concatenate([y_u, y_l[:-1][::-1]], axis=0) 101 | pos = np.stack([ 102 | x*scale + origin[0], 103 | y*scale + origin[1] 104 | ], axis=-1 105 | ) 106 | pos[0], pos[-1] = np.array([1, 0]), np.array([1, 0]) 107 | return pos -------------------------------------------------------------------------------- /params.yaml: -------------------------------------------------------------------------------- 1 | L: 200 # Size of the domain 2 | y_h: 2.e-6 # Heigth of the first cell of the boundary layer. 3 | y_hd: 1.e-4 # Heigth of the furthest first cell of the trail. 4 | x_h: 1.e-5 # Width of the smallest cell at the leading edge. 5 | y_exp: 1.075 # Expansion ratio in the y-direction. (< 1.2) 6 | x_exp: 1.025 # Expansion ratio in the x-direction on the airfoil. (< 1.2) 7 | x_expd: 1.075 # Expansion ratio in the x-direction behind the airfoil. (< 1.2) 8 | turbulence: 'SST' # Turbulence model, choose between 'SST' for k-omega SST and 'SA' for Spalart-Allmaras. 9 | compressible: False # If you run compressible simulation, be careful that compressible simulation are less stable and could not converge without finetuning. 10 | n_proc: 16 # Number of physical CPU cores used for the simulation. 11 | reynolds: 3.e+6 # Reynolds number of the simulation. 12 | temperature: 298.15 # Temperature of air for the simulation in Kelvin. 13 | aoa: 0 # Angle of attack of the simulation. 14 | digits: [0, 0, 12] # 4 or 5-digits of the airfoil. The last two digits are given together as it is the thickness of the airfoil, e.g. [0, 0, 12] or [2, 4, 1, 12]. 15 | n_iter: 20000 # Number of iterations for the simulation (it can be raised to 40000 for high angle of attack (> 10) simulations). -------------------------------------------------------------------------------- /simulation_generator.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os, shutil, glob 3 | import yaml 4 | import subprocess 5 | import matplotlib.pyplot as plt 6 | import seaborn as sns 7 | from naca_generator import naca_generator 8 | 9 | sns.set() 10 | 11 | with open('params.yaml', 'r') as f: # hyperparameters of the model 12 | params = yaml.safe_load(f) 13 | 14 | # Properties of air at 1.01325hPa 15 | MOL = 28.965338 # Molar weight in g/mol 16 | P_ref = 1.01325e5 17 | RHO = P_ref*MOL*1e-3/(8.3144621*params['temperature']) 18 | NU = -3.400747e-6 + 3.452139e-8*params['temperature'] + 1.00881778e-10*params['temperature']**2 - 1.363528e-14*params['temperature']**3 19 | C = 20.05*np.sqrt(params['temperature']) 20 | C_P = 1.0575e3 - 4.4890e-1*params['temperature'] + 1.1407e-3*params['temperature']**2 - 7.9999e-7*params['temperature']**3 + 1.9327e-10*params['temperature']**4 21 | 22 | def angle_to_origin(a, b, alpha): 23 | c = b - a 24 | # Compute the middle point on the segment [a, b] 25 | mid = (a + b)/2 26 | 27 | # Compute the distance between a and b 28 | d1 = np.linalg.norm(c) 29 | 30 | # Compute the distance between the middle point and the center of the circle 31 | d = d1/(2*np.tan(alpha/2)) 32 | 33 | # Compute the angle between (b - mid) and the x-axis 34 | theta = np.arctan(c[1]/c[0]) 35 | 36 | # Rotate the center of the circle 37 | center = np.array([0, d]) 38 | rot = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) 39 | center = rot@center + mid 40 | 41 | return center 42 | 43 | def coef_grading(a, b, c, type = 'L, h, e'): 44 | if type == 'L, h, e': 45 | L, h, expansion = a, b, c 46 | N = int(np.log(1 - (1 - expansion)*L/h)/np.log(expansion)) 47 | delta = expansion**(N - 1) 48 | H = h*delta 49 | results = (N, H, delta) 50 | 51 | elif type == 'L, h, delta': 52 | L, h, delta = a, b, c 53 | expansion = 1 + h*(delta - 1)/(L - h*delta) 54 | N = int(np.log(1 - (1 - expansion)*L/h)/np.log(expansion)) 55 | H = h*delta 56 | results = (N, H, expansion) 57 | 58 | elif type == 'L, N, e': 59 | L, N, expansion = a, b, c 60 | delta = expansion**(N - 1) 61 | if expansion < 1: 62 | H = L*(1 - expansion)/(1 - expansion**N) 63 | h = L*(1 - 1/expansion)/(1 - (1/expansion)**N) 64 | else: 65 | H = L*(1 - 1/expansion)/(1 - (1/expansion)**N) 66 | h = L*(1 - expansion)/(1 - expansion**N) 67 | results = (H, h, delta) 68 | 69 | elif type == 'L, N, h': 70 | L, N, h = a, b, c 71 | f = lambda x: (h*(x**N) - L*x + L - h) 72 | df = lambda x: (h*N*(x**(N - 1)) - L) 73 | if (N*h > L): 74 | old_expansion = 0.5 75 | else: 76 | old_expansion = 2 77 | cond = True 78 | 79 | while cond: 80 | new_expansion = old_expansion - f(old_expansion)/df(old_expansion) 81 | cond = (np.abs(new_expansion - old_expansion) > 1e-15) 82 | old_expansion = new_expansion 83 | 84 | expansion = old_expansion 85 | delta = expansion**(N - 1) 86 | H = h*delta 87 | results = (H, expansion, delta) 88 | 89 | return results 90 | 91 | def dict_grading(L, y_h, y_hd, x_h, y_exp, x_exp, x_expd, aoa, geometry): 92 | arg_upper = geometry[:, 1].argmax() 93 | arg_lead = geometry[:, 0].argmin() 94 | x_upper = geometry[arg_upper, 0] 95 | y_upper = geometry[arg_upper, 1] 96 | x_lead = geometry[arg_lead, 0] 97 | y_lead = geometry[arg_lead, 1] 98 | y_lower = geometry[np.abs(geometry[:, 0] - x_upper) < 1e-2, 1].min() 99 | arg_lower = np.where(geometry[:, 1] - y_lower == 0)[0][0] 100 | x_lower = geometry[arg_lower, 0] 101 | 102 | d_ULead = np.sqrt(((geometry[arg_upper:arg_lead] - geometry[arg_upper + 1: arg_lead + 1])**2).sum(axis = 1)).sum() 103 | d_DLead = np.sqrt(((geometry[arg_lead:arg_lower] - geometry[arg_lead + 1:arg_lower + 1])**2).sum(axis = 1)).sum() 104 | 105 | d_UTrail = np.sqrt(((geometry[:arg_upper] - geometry[1:arg_upper + 1])**2).sum(axis = 1)).sum() 106 | d_DTrail = np.sqrt(((geometry[arg_lower:-1] - geometry[arg_lower + 1:])**2).sum(axis = 1)).sum() 107 | 108 | alpha = np.pi*20/180 109 | x_mid = L/6 110 | a, b = np.array([1, 0]), np.array([x_mid, L]) 111 | center = angle_to_origin(a, b, alpha) 112 | 113 | x_angle = (L - 1)*np.sin(aoa*np.pi/180) 114 | 115 | # yGrading 116 | N_y, _, delta_y = coef_grading(L, y_h, y_exp) 117 | L_U, L_D = L - x_angle, L + x_angle 118 | _, _, delta_yu = coef_grading(L_U, N_y, y_hd, type = 'L, N, h') 119 | _, _, delta_yd = coef_grading(L_D, N_y, y_hd, type = 'L, N, h') 120 | 121 | # leadGrading 122 | N_Ulead, H_Ulead, delta_Ulead = coef_grading(d_ULead, x_h, x_exp) 123 | delta_Ulead = 1/delta_Ulead 124 | N_Dlead, H_Dlead, delta_Dlead = coef_grading(d_DLead, x_h, x_exp) 125 | delta_Dlead = 1/delta_Dlead 126 | 127 | # xMAeroGrading 128 | expansion = 1.001*(1 - H_Ulead/d_UTrail) 129 | N_UM, h_UM_aero, delta_UM_aero = coef_grading(d_UTrail, H_Ulead, expansion) 130 | delta_UM_aero = 1/delta_UM_aero 131 | 132 | delta_DM_aero = H_Dlead/h_UM_aero 133 | N_DM, _, _ = coef_grading(d_DTrail, h_UM_aero, delta_DM_aero, type = 'L, h, delta') 134 | 135 | # expansion = 1.001*(1 - H_Dlead/d_DTrail) 136 | # N_DM, h_DM_aero, delta_DM_aero = coef_grading(d_DTrail, H_Dlead, expansion) 137 | # delta_DM_aero = 1/delta_DM_aero 138 | 139 | # xUGrading 140 | L_U = np.pi/2*L 141 | h_UU = (x_mid - x_upper)/N_UM 142 | _, _, delta_UU = coef_grading(L_U, N_Ulead, h_UU, type = 'L, N, h') 143 | 144 | h_DU = (x_mid - x_upper)/N_DM 145 | _, _, delta_DU = coef_grading(L_U, N_Dlead, h_DU, type = 'L, N, h') 146 | 147 | # xMGrading 148 | delta_M = 1 149 | h_UM = delta_M*h_UU 150 | h_DM = delta_M*h_DU 151 | 152 | # xDTrailGrading 153 | N_D, _, delta_D_trail = coef_grading(L - 1, h_UM_aero, x_expd) 154 | delta_D_trail = 1/delta_D_trail 155 | 156 | # N_DD, _, delta_DD_trail = coef_grading(L - 1, h_UM_aero, x_expd) 157 | # delta_DD_trail = 1/delta_DD_trail 158 | 159 | # xDGrading 160 | _, _, delta_UD = coef_grading(L - x_mid, N_D, h_UM, type = 'L, N, h') 161 | delta_UD = 1/delta_UD 162 | 163 | _, _, delta_DD = coef_grading(L - x_mid, N_D, h_DM, type = 'L, N, h') 164 | delta_DD = 1/delta_DD 165 | 166 | results = dict() 167 | results['xMin'] = -L 168 | results['xMid'] = x_mid 169 | results['xAngle'] = x_angle 170 | 171 | results['yCells'] = N_y 172 | results['xUUCells'] = N_Ulead 173 | results['xDUCells'] = N_Dlead 174 | results['xUMCells'] = N_UM 175 | results['xDMCells'] = N_DM 176 | results['xDCells'] = N_D 177 | # results['xDDCells'] = N_DD 178 | 179 | results['yGrading'] = delta_y 180 | results['yUGrading'] = delta_yu 181 | results['yDGrading'] = delta_yd 182 | results['xUUGrading'] = delta_UU 183 | results['xDUGrading'] = delta_DU 184 | results['xUMAeroGrading'] = delta_UM_aero 185 | results['xDMAeroGrading'] = delta_DM_aero 186 | results['xMGrading'] = delta_M 187 | results['xDTrailGrading'] = delta_D_trail 188 | # results['xDDTrailGrading'] = delta_DD_trail 189 | results['xUDGrading'] = delta_UD 190 | results['xDDGrading'] = delta_DD 191 | results['leadUGrading'] = delta_Ulead 192 | results['leadDGrading'] = delta_Dlead 193 | 194 | results['xOrigin'] = center[0] 195 | results['yOrigin'] = center[1] 196 | 197 | results['argUpper'] = arg_upper 198 | results['argLead'] = arg_lead 199 | results['argLower'] = arg_lower 200 | results['xLead'] = x_lead 201 | results['yLead'] = y_lead 202 | results['xUpper'] = x_upper 203 | results['yUpper'] = y_upper 204 | results['xLower'] = x_lower 205 | results['yLower'] = y_lower 206 | 207 | return results 208 | 209 | def blockMeshDict_generator(path, geometry, params): 210 | with open(path + 'system/blockMeshDict.orig', 'r') as file: 211 | line_list = file.read().splitlines() 212 | 213 | # Domain boundaries 214 | line_list[23] = '\txMin\t' + str(params['xMin']) + ';' 215 | line_list[27] = '\txMid\t' + str(params['xMid']) + ';' 216 | line_list[28] = '\txAngle\t' + str(params['xAngle']) + ';' 217 | 218 | # Cells number 219 | line_list[31] = '\tyCells\t' + str(params['yCells']) + ';' 220 | line_list[32] = '\txUUCells\t' + str(params['xUUCells']) + ';' 221 | line_list[33] = '\txDUCells\t' + str(params['xDUCells']) + ';' 222 | line_list[34] = '\txUMCells\t' + str(params['xUMCells']) + ';' 223 | line_list[35] = '\txDMCells\t' + str(params['xDMCells']) + ';' 224 | line_list[36] = '\txDCells\t' + str(params['xDCells']) + ';' 225 | 226 | # Grading 227 | line_list[39] = '\tyGrading\t' + str(params['yGrading']) + ';' 228 | line_list[40] = '\tyUGrading\t' + str(params['yUGrading']) + ';' 229 | line_list[41] = '\tyDGrading\t' + str(params['yDGrading']) + ';' 230 | line_list[42] = '\txUUGrading\t' + str(params['xUUGrading']) + ';' 231 | line_list[43] = '\txDUGrading\t' + str(params['xDUGrading']) + ';' 232 | line_list[44] = '\txUMAeroGrading\t' + str(params['xUMAeroGrading']) + ';' 233 | line_list[45] = '\txDMAeroGrading\t' + str(params['xDMAeroGrading']) + ';' 234 | line_list[47] = '\txDTrailGrading\t' + str(params['xDTrailGrading']) + ';' 235 | line_list[48] = '\txUDGrading\t' + str(params['xUDGrading']) + ';' 236 | line_list[49] = '\txDDGrading\t' + str(params['xDDGrading']) + ';' 237 | line_list[50] = '\tleadUGrading\t' + str(params['leadUGrading']) + ';' 238 | line_list[51] = '\tleadDGrading\t' + str(params['leadDGrading']) + ';' 239 | 240 | # Mid-arc 241 | line_list[54] = '\txOrigin\t' + str(params['xOrigin']) + ';' 242 | line_list[55] = '\tyOrigin\t' + str(params['yOrigin']) + ';' 243 | 244 | # Aerofoil 245 | line_list[60] = '\txLead\t' + str(params['xLead']) + ';' 246 | line_list[61] = '\tyLead\t' + str(params['yLead']) + ';' 247 | line_list[64] = '\txUpper\t' + str(params['xUpper']) + ';' 248 | line_list[65] = '\tyUpper\t' + str(params['yUpper']) + ';' 249 | line_list[66] = '\txLower\t' + str(params['xLower']) + ';' 250 | line_list[67] = '\tyLower\t' + str(params['yLower']) + ';' 251 | 252 | end = line_list[169:] 253 | line_list = line_list[:169] 254 | 255 | line_list.extend(['', '\tspline 10 11', '\t(']) 256 | for pt in geometry[:params['argUpper'] + 1]: 257 | line_list.append('\t\t(' + str(pt[0]) + ' ' + str(pt[1]) + ' 0)') 258 | 259 | line_list.extend(['\t)', '', '\tspline 22 23', '\t(']) 260 | for pt in geometry[:params['argUpper'] + 1]: 261 | line_list.append('\t\t(' + str(pt[0]) + ' ' + str(pt[1]) + ' 1)') 262 | 263 | line_list.extend(['\t)', '', '\tspline 11 8', '\t(']) 264 | for pt in geometry[params['argUpper']:params['argLead'] + 1]: 265 | line_list.append('\t\t(' + str(pt[0]) + ' ' + str(pt[1]) + ' 0)') 266 | 267 | line_list.extend(['\t)', '', '\tspline 23 20', '\t(']) 268 | for pt in geometry[params['argUpper']:params['argLead'] + 1]: 269 | line_list.append('\t\t(' + str(pt[0]) + ' ' + str(pt[1]) + ' 1)') 270 | 271 | line_list.extend(['\t)', '', '\tspline 8 9', '\t(']) 272 | for pt in geometry[params['argLead']:params['argLower'] + 1]: 273 | line_list.append('\t\t(' + str(pt[0]) + ' ' + str(pt[1]) + ' 0)') 274 | 275 | line_list.extend(['\t)', '', '\tspline 20 21', '\t(']) 276 | for pt in geometry[params['argLead']:params['argLower'] + 1]: 277 | line_list.append('\t\t(' + str(pt[0]) + ' ' + str(pt[1]) + ' 1)') 278 | 279 | line_list.extend(['\t)', '', '\tspline 9 10', '\t(']) 280 | for pt in geometry[params['argLower']:]: 281 | line_list.append('\t\t(' + str(pt[0]) + ' ' + str(pt[1]) + ' 0)') 282 | 283 | line_list.extend(['\t)', '', '\tspline 21 22', '\t(']) 284 | for pt in geometry[params['argLower']:]: 285 | line_list.append('\t\t(' + str(pt[0]) + ' ' + str(pt[1]) + ' 1)') 286 | line_list.append('\t)') 287 | 288 | line_list.extend(end) 289 | 290 | with open(path + 'system/blockMeshDict', 'w') as file: 291 | for line in line_list: 292 | file.write(line + '\n') 293 | 294 | def system_generator(path, u_inf, aoa, n_proc, n_iter = 10000, compressible = False): 295 | a = np.array([np.cos(aoa*np.pi/180), np.sin(aoa*np.pi/180)]) 296 | 297 | with open(path + 'system/controlDict.orig', 'r') as file: 298 | line_list = file.read().splitlines() 299 | 300 | line_list[15] = 'Uinf\t' + str(u_inf) + ';' 301 | line_list[25] = 'endTime\t' + str(n_iter) + ';' 302 | line_list[66] = '\t rhoInf\t' + str(RHO) + ';' 303 | line_list[88] = '\t rhoInf\t' + str(RHO) + ';' 304 | line_list[105] = '\t liftDir\t (' + str(-a[1]) + ' ' + str(a[0]) + ' 0);' 305 | line_list[108] = '\t dragDir\t (' + str(a[0]) + ' ' + str(a[1]) + ' 0);' 306 | 307 | if compressible: 308 | line_list[17] = 'application rhoSimpleFoam;' # Change solver 309 | line_list[63] = ' rho\trho;' # Add density for integral forces computation 310 | line_list[85] = ' rho\trho;' # Add density for force coeffs computation 311 | line_list[91] = '\t pRef ' + str(P_ref) + ';' # Absolute pressure for compressible simulation 312 | line_list[162] = ' mut' 313 | line_list[163] = ' muEff' 314 | line_list[164] = ' devRhoReff' 315 | 316 | file = open(path + 'system/fvSolution', 'r') 317 | line_list_fv = file.read().splitlines() 318 | 319 | # Come nack to SIMPLE algorithm for stability 320 | line_list_fv[41] = ' consistent no;' 321 | line_list_fv[59] = ' p 0.5;' 322 | line_list_fv[64] = ' e 0.7;' 323 | line_list_fv[65] = ' U 0.7;' 324 | line_list_fv[66] = ' nuTilda 0.7;' 325 | line_list_fv[67] = ' k 0.7;' 326 | line_list_fv[68] = ' omega 0.7;' 327 | 328 | with open(path + 'system/fvSolution', 'w') as file: 329 | for line in line_list_fv: 330 | file.write(line + '\n') 331 | else: 332 | os.remove(path + 'system/fvOptions') 333 | 334 | with open(path + 'system/controlDict', 'w') as file: 335 | for line in line_list: 336 | file.write(line + '\n') 337 | 338 | with open(path + 'system/decomposeParDict', 'r') as file: 339 | line_list = file.read().splitlines() 340 | 341 | line_list[16] = 'numberOfSubdomains ' + str(n_proc) + ';' 342 | 343 | with open(path + 'system/decomposeParDict', 'w') as file: 344 | for line in line_list: 345 | file.write(line + '\n') 346 | 347 | def init_generator(path, u_inf, aoa, L, turbulence, y_1 = None, compressible = False): 348 | a = np.array([u_inf*np.cos(aoa*np.pi/180), u_inf*np.sin(aoa*np.pi/180)]) 349 | shutil.copytree(path + '0.orig/', path + '0') 350 | 351 | with open(path + '0/U', 'r') as file: 352 | line_list = file.read().splitlines() 353 | 354 | line_list[18] = 'field\t\t(' + str(a[0]) + ' ' + str(a[1]) + ' 0);' 355 | 356 | with open(path + '0/U', 'w') as file: 357 | for line in line_list: 358 | file.write(line + '\n') 359 | 360 | with open(path + 'constant/transportProperties', 'r') as file: 361 | line_list = file.read().splitlines() 362 | line_list[18] = 'nu\t\t' + str(NU) + ';' 363 | with open(path + 'constant/transportProperties', 'w') as file: 364 | for line in line_list: 365 | file.write(line +'\n') 366 | 367 | if turbulence == 'SA': 368 | nut = NU 369 | nutilda = 4*NU 370 | 371 | with open(path + 'constant/turbulenceProperties', 'r') as file: 372 | line_list_turb = file.read().splitlines() 373 | 374 | line_list_turb[20] = '\tRASModel\tSpalartAllmaras;' 375 | 376 | with open(path + '0/nut', 'r') as file: 377 | line_list = file.read().splitlines() 378 | line_list[18] = 'field\t\t' + str(nut) + ';' 379 | with open(path + '0/nut', 'w') as file: 380 | for line in line_list: 381 | file.write(line +'\n') 382 | 383 | with open(path + '0/nuTilda', 'r') as file: 384 | line_list = file.read().splitlines() 385 | line_list[18] = 'field\t\t' + str(nutilda) + ';' 386 | with open(path + '0/nuTilda', 'w') as file: 387 | for line in line_list: 388 | file.write(line +'\n') 389 | 390 | os.remove(path + '0/k') 391 | os.remove(path + '0/omega') 392 | 393 | elif turbulence == 'SST': 394 | if isinstance(y_1, float): 395 | nut = NU 396 | Re_L = u_inf*L/NU 397 | k = 1e-3*u_inf**2/Re_L 398 | omega = 5*u_inf/L 399 | omega_wall = 6*NU/0.075/y_1**2 400 | 401 | with open(path + 'constant/turbulenceProperties', 'r') as file: 402 | line_list_turb = file.read().splitlines() 403 | 404 | line_list_turb[20] = '\tRASModel\tkOmegaSST;' 405 | 406 | with open(path + '0/nut', 'r') as file: 407 | line_list = file.read().splitlines() 408 | line_list[18] = 'field\t\t' + str(nut) + ';' 409 | with open(path + '0/nut', 'w') as file: 410 | for line in line_list: 411 | file.write(line +'\n') 412 | 413 | with open(path + '0/k', 'r') as file: 414 | line_list = file.read().splitlines() 415 | line_list[18] = 'field\t\t' + str(k) + ';' 416 | with open(path + '0/k', 'w') as file: 417 | for line in line_list: 418 | file.write(line +'\n') 419 | 420 | with open(path + '0/omega', 'r') as file: 421 | line_list = file.read().splitlines() 422 | line_list[18] = 'field\t\t' + str(omega) + ';' 423 | line_list[27] = '\t\tvalue\t\tuniform ' + str(omega_wall) + ';' 424 | with open(path + '0/omega', 'w') as file: 425 | for line in line_list: 426 | file.write(line +'\n') 427 | 428 | os.remove(path + '0/nuTilda') 429 | 430 | else: 431 | raise ValueError('The height of the first aerofoil cell "y_1" must be given as a float number.') 432 | 433 | with open(path + 'constant/turbulenceProperties', 'w') as file: 434 | for line in line_list_turb: 435 | file.write(line +'\n') 436 | 437 | if compressible: 438 | alphat = RHO*NU/0.85 439 | temp = params['temperature'] 440 | 441 | with open(path + 'constant/thermophysicalProperties', 'r') as file: 442 | line_list = file.read().splitlines() 443 | line_list[37] = '\tCp\t' + str(C_P) + ';' 444 | with open(path + 'constant/thermophysicalProperties', 'w') as file: 445 | for line in line_list: 446 | file.write(line +'\n') 447 | 448 | with open(path + '0/p', 'r') as file: 449 | line_list_comp = file.read().splitlines() 450 | 451 | line_list_comp[16] = 'field ' + str(P_ref) + ';' 452 | line_list_comp[18] = 'dimensions [1 -1 -2 0 0 0 0];' # Change the dimension to the real pressure dimension. 453 | with open(path + '0/p', 'w') as file: 454 | for line in line_list_comp: 455 | file.write(line + '\n') 456 | 457 | with open(path + '0/alphat', 'r') as file: 458 | line_list = file.read().splitlines() 459 | line_list[18] = 'field\t\t' + str(alphat) + ';' 460 | with open(path + '0/alphat', 'w') as file: 461 | for line in line_list: 462 | file.write(line +'\n') 463 | 464 | with open(path + '0/T', 'r') as file: 465 | line_list = file.read().splitlines() 466 | line_list[18] = 'field\t\t' + str(temp) + ';' 467 | with open(path + '0/T', 'w') as file: 468 | for line in line_list: 469 | file.write(line +'\n') 470 | 471 | os.remove(path + 'constant/transportProperties') 472 | 473 | else: 474 | os.remove(path + 'constant/thermophysicalProperties') 475 | os.remove(path + '0/alphat') 476 | os.remove(path + '0/T') 477 | 478 | def simulation(init_path, path, params, just_init = False, figure = False, compute_grad = False, VTK = False): 479 | ''' 480 | Run a Reynolds-Averaged-Simulation over airfoils on OpenFOAM v2112. 481 | 482 | Args: 483 | init_path (string): Path where the initial conditions and simulation dictionnaries are given. 484 | path (string): Path where the simulation is going to be saved. 485 | params (dict): Parameters of the simulation. 486 | just_init (bool, optional): If ``True``, only do the mesh generation without the simulation. Default: ``False`` 487 | figure (bool, optional): If ``True``, save an image of the airfoil in the simulation folder. Default: ``False`` 488 | compute_grad (bool, optional): If ``True``, compute the different terms of the RANS equations as a post-processing. Default: ``False`` 489 | VTK (bool, optional): If ``True``, generate VTK files from the simulation. Default: ``False`` 490 | ''' 491 | Re, Ma = params['Uinf']/NU, params['Uinf']/C 492 | print('Reynolds number: {0:.3}\ 493 | \nMach number: {1:.3}\ 494 | \nUinf: {2:.3}\ 495 | \nAoA: {3:.3}\ 496 | \nTemperature: {4:.3}\ 497 | \nNACA:'.format(Re, Ma, float(params['Uinf']), float(params['aoa']), float(params['temperature'])), str(params['digits']), 498 | '\nTurbulence model: ' + params['turbulence'] + '\nCompressible: ' + str(params['compressible']) + '\n') 499 | 500 | if os.path.exists(path): 501 | shutil.rmtree(path) 502 | shutil.copytree(init_path, path) 503 | 504 | print('Generating NACA airfoil.') 505 | geometry = naca_generator(params['digits'], nb_samples = 2000, scale = 1, origin = (0, 0), cosine_spacing = True, verbose = False, CTE = True) 506 | if figure: 507 | fig, ax = plt.subplots(figsize = (15, 15*params['digits'][-1]/100)) 508 | ax.scatter(geometry[:, 0], geometry[:, 1]) 509 | ax.set_title('NACA ' + str(params['digits'])) 510 | ax.set_xlabel('x/c') 511 | ax.set_ylabel('y/c') 512 | fig.savefig(path + 'naca_' + str(params['digits']) + '.png', bbox_inches = 'tight', dpi = 150); 513 | 514 | print('Generating simulation dictionnaries.') 515 | coef_grad = dict_grading(params['L'], params['y_h'], params['y_hd'], params['x_h'], params['y_exp'], params['x_exp'], params['x_expd'], params['aoa'], geometry) 516 | blockMeshDict_generator(path, geometry, coef_grad) 517 | system_generator(path, params['Uinf'], params['aoa'], params['n_proc'], n_iter = params['n_iter'], compressible = params['compressible']) 518 | init_generator(path, params['Uinf'], params['aoa'], 2*params['L'], params['turbulence'], params['y_h'], params['compressible']) 519 | 520 | wd = os.getcwd() 521 | os.chdir(path) 522 | print('Generating mesh.') 523 | subprocess.run('blockMesh > log.blockMesh', shell = True) 524 | 525 | print('Checking mesh.') 526 | subprocess.run('checkMesh > log.checkMesh', shell = True) 527 | open(params['turbulence'] + '_' + str(params['Uinf']) + '_' + str(params['aoa']) + '_' + str(params['digits']) + '.foam', 'w') 528 | if just_init: 529 | print('\nInitialization done!') 530 | 531 | else: 532 | print('Simulation running.') 533 | if params['compressible']: 534 | if params['n_proc'] == 1: 535 | subprocess.run('rhoSimpleFoam > log.rhoSimpleFoam', shell = True) 536 | else: 537 | subprocess.run('decomposePar > log.decomposePar', shell = True) 538 | # subprocess.run('mpirun -np ' + str(params['n_proc']) + ' renumberMesh -parallel -overwrite > log.renumberMesh', shell = True) 539 | subprocess.run('mpirun -np ' + str(params['n_proc']) + ' rhoSimpleFoam -parallel > log.rhoSimpleFoam', shell = True) 540 | subprocess.run('foamLog log.rhoSimpleFoam > log.foamLog', shell = True) 541 | else: 542 | if params['n_proc'] == 1: 543 | subprocess.run('simpleFoam > log.simpleFoam', shell = True) 544 | else: 545 | subprocess.run('decomposePar > log.decomposePar', shell = True) 546 | # subprocess.run('mpirun -np ' + str(params['n_proc']) + ' renumberMesh -parallel -overwrite > log.renumberMesh', shell = True) 547 | subprocess.run('mpirun -np ' + str(params['n_proc']) + ' simpleFoam -parallel > log.simpleFoam', shell = True) 548 | subprocess.run('foamLog log.simpleFoam > log.foamLog', shell = True) 549 | subprocess.run('reconstructPar > log.reconstructPar', shell = True) 550 | for path_dir in glob.glob('processor*'): 551 | shutil.rmtree(path_dir) 552 | if compute_grad: 553 | print('Computing gradient.') 554 | subprocess.run('postProcess -func "components(U)" > log', shell = True) 555 | subprocess.run('postProcess -func "grad(Ux)" > log', shell = True) 556 | subprocess.run('postProcess -func "grad(Uy)" > log', shell = True) 557 | subprocess.run('postProcess -func "div(grad(Ux))" > log', shell = True) 558 | subprocess.run('postProcess -func "div(grad(Uy))" > log', shell = True) 559 | subprocess.run('postProcess -func "grad(p)" > log', shell = True) 560 | os.remove('log') 561 | for file in ['Ux.gz', 'Uy.gz', 'Uz.gz']: 562 | os.remove(str(params['n_iter']) + '/' + file) 563 | if VTK: 564 | print('Generating VTK.') 565 | if params['compressible']: 566 | subprocess.run("foamToVTK -noZero -fields '(p U T rho nut wallShearStress Ma)' > log.foamToVTK", shell = True) 567 | else: 568 | subprocess.run("foamToVTK -noZero -fields '(p U nut wallShearStress)' > log.foamToVTK", shell = True) 569 | print('\nSimulation done!') 570 | 571 | os.chdir(wd) --------------------------------------------------------------------------------