├── COPYING ├── Fortran ├── dpl2su2_2D.f ├── gmsh2su2_2D.f90 └── gmsh2su2_3D.f90 ├── Matlab ├── MergeSU2.m ├── ReadSU2.m ├── WriteSU2.m ├── angle2dcm.m ├── example_MergeMeshes.m ├── getElemTypeInfo.m ├── mesh_bipara_1.su2 ├── mesh_bipara_2.su2 ├── plotElem.m ├── plotFace.m └── plotMarkers.m ├── Python ├── 2DChannel.py ├── 3DChannel.py ├── Expandp3d.py ├── p3d2su2_3D.py ├── p3d2su2_CGrid.py └── p3d2su2_OGrid.py └── SU2_PER ├── COMPILE ├── README └── su2_periodic.f90 /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /Fortran/dpl2su2_2D.f: -------------------------------------------------------------------------------- 1 | PROGRAM dpl2su2 2 | 3 | C Code provided by Dr. Aldo Bonfiglioli 4 | C Associate professor of Fluid Flow Machinery 5 | C Scuola di Ingegneria 6 | C Universita' della Basilicata 7 | 8 | C 9 | C This routine reads a .dpl unstructured datafile 10 | C and creates a SU2 mesh file 11 | C 12 | C dplot is a: 13 | C write (*,*) 'STRUCTURED/UNSTRUCTURED CONTOUR PLOTTING PACKAGE' 14 | C write (*,*) ' -Written by DARREN DE ZEEUW ' 15 | C write (*,*) ' -Last Modified 02/93 ' 16 | C write (*,*) ' ' 17 | C 18 | C the dplot format is described in format 110-130 19 | C 20 | C Unstructured dplot file are created using the 21 | C Delaundo mesh generator 22 | C http://www.cerfacs.fr/~muller/delaundo.html 23 | C 24 | IMPLICIT NONE 25 | C 26 | INTEGER NELEMAX,NODEMAX,NFACMAX,NDIM,NOFVERT 27 | PARAMETER (NELEMAX=525000,NODEMAX=265000, 28 | & NFACMAX=5000,NDIM=2,NOFVERT=NDIM+1) 29 | C 30 | INTEGER nCells,nNodes,nCorners,nBoundaryFaces,NFAC,nBodies, 31 | + nBodyFaces,iBodyType 32 | INTEGER node1,node2,ntriangle 33 | INTEGER i,j,k,npo 34 | INTEGER NELEM,NPOIN,NBFAC,NHOLE 35 | C 36 | INTEGER Corner(3,NELEMAX) 37 | C 38 | DOUBLE PRECISION XY(2,NODEMAX) 39 | CHARACTER*80 filename,title 40 | C 41 | EQUIVALENCE (nCells,NELEM) 42 | EQUIVALENCE (nNodes,NPOIN) 43 | EQUIVALENCE (NFAC,NBFAC) 44 | C 45 | WRITE (6,*) 46 | WRITE (6,*) ' Give the input filename in dpl format :' 47 | WRITE (6,*) 48 | READ (5,'(A80)') filename 49 | C 50 | WRITE(6,150) 51 | 5 OPEN (1,FILE=filename,STATUS='OLD',FORM='formatted') 52 | OPEN(UNIT=12,FILE="MESH.su2") 53 | C 54 | C UNSTRUCTURED DATA FILE 55 | C 56 | READ (1,'(A80)') title 57 | WRITE (6,'(A80)') title 58 | c 59 | c..Needs "unstr" or "UNSTR" as first five characters 60 | c 61 | READ (1,*) nCells 62 | IF (nCells.GT.NELEMAX) THEN 63 | WRITE(6,*)'Actual nof cells ',nCells,' > Max allowed = ', 64 | & NELEMAX 65 | STOP 'Increase NELEMAX within dpl2su2' 66 | ENDIF 67 | DO 19 i = 1,nCells 68 | READ (1,*) nCorners, (Corner(j,i),j=1,nCorners) 69 | 19 CONTINUE 70 | WRITE (6,*) nCells,' Cells read !' 71 | WRITE(12,FMT=201)NDIM 72 | WRITE(12,FMT=202)NELEM 73 | do I= 1,NELEM 74 | WRITE(12,FMT=80)5,((Corner(j,I)-1),j=1,NOFVERT),I-1 75 | enddo 76 | WRITE (6,*) nCells,' Cells have been written !' 77 | C 78 | READ (1,*) nNodes 79 | IF (nNodes.GT.NODEMAX) THEN 80 | WRITE(6,*)'Actual nof nodes ',nNodes,' > Max allowed = ', 81 | & NODEMAX 82 | STOP 'Increase NODEMAX within dpl2su2' 83 | ENDIF 84 | READ (1,*) 85 | c 86 | c..read gridpoints 87 | c 88 | DO 21 i = 1,nNodes 89 | READ (1,*) XY(1,i),XY(2,i) 90 | 21 CONTINUE 91 | WRITE (6,*) nNodes,' Nodes read !' 92 | C 93 | WRITE(12,FMT=203) NPOIN 94 | do 125 I=1,NPOIN 95 | WRITE(12,FMT=*)(XY(j,I),j=1,NDIM),I-1 96 | 125 CONTINUE 97 | WRITE (6,*) nNodes,' Nodes written !' 98 | C 99 | READ (1,*) nBodies 100 | Write(6,*)nBodies,' have been found in the dpl file' 101 | WRITE(12,FMT=204)nBodies 102 | DO 25 j = 1,nBodies 103 | READ (1,*) nBodyFaces,iBodyType 104 | WRITE (6,*) 'There are ',nBodyFaces,' edges on bndry # ',j, 105 | &' type is ',iBodyType 106 | write(12,FMT=205)iBodyType 107 | write(12,FMT=206)nBodyFaces 108 | DO 25 i = 1,nBodyFaces 109 | READ (1,*) node1,node2,ntriangle 110 | write(12,FMT=95)3,node1-1,node2-1 111 | 25 CONTINUE 112 | c 113 | c REM: dplot files created by Delaundo have nBoundaryFaces=0 114 | c 115 | c 116 | READ (1,*) nBoundaryFaces 117 | IF (nBoundaryFaces.NE.0) THEN 118 | WRITE (*,*) ' nBoundaryFaces is NOT 0 but ... ', 119 | + nBoundaryFaces 120 | CALL EXIT(1) 121 | 122 | ENDIF 123 | CLOSE (1) 124 | C 125 | C 126 | WRITE(6,*) 127 | WRITE(6,*)'REMEMBER:' 128 | WRITE(6,*) 129 | WRITE(6,*)'Give a meaningful name to MARKER_TAG in the mesh file' 130 | WRITE(6,*)'It needs to have a corresponding boundary condition' 131 | WRITE(6,*)'in the configuration file!!!!' 132 | C 133 | C 134 | C 135 | 80 FORMAT(I1,1X,5(I6,1X)) 136 | 95 FORMAT(I1,1X,4(I6,1X)) 137 | 110 format (' '/ 138 | + 'UNSTRUCTURED DATA FILE '/ 139 | + ' write (1,"(a22)") "unstructured grid data" '/ 140 | + 'c..Needs "unstr" or "UNSTR" as first five characters '/ 141 | + ' write (1,*) nCells '/ 142 | + ' do i=1,nCells '/ 143 | + ' write (1,*) nCorners,(Corner(j,i),j=1,nCorners) '/ 144 | + ' end do ') 145 | 120 format (' write (1,*) nNodes '/ 146 | + ' write (1,*) U1(inf),U2(inf),U3(inf),U4(inf) '/ 147 | + 'c..Freestream state values '/ 148 | + ' do i=1,nNodes '/ 149 | + ' write (1,*) X(i),Y(i),U1(i),U2(i),U3(i),U4(i) '/ 150 | + ' end do ') 151 | 130 format (' write (1,*) nBodies '/ 152 | + ' do j=1,nBodies '/ 153 | + ' write (1,*) nBodyFaces(j) '/ 154 | + ' do i=1,nBodyFaces(j) '/ 155 | + ' write (1,*) node1(i),node2(i) '/ 156 | + ' end do '/ 157 | + ' end do '/ 158 | + 'c..Two nodes for face on body numbered as above '/ 159 | + ' write (1,*) nBoundaryFaces '/ 160 | + ' do i=1,nBoundaryFaces '/ 161 | + ' write (1,*) node1(i),node2(i) '/ 162 | + ' end do '/ 163 | + 'c..Two nodes for face on boundary numbered as above '/ 164 | + ' ') 165 | 111 FORMAT('.',$) 166 | 135 FORMAT(5X,'Writing the coordinates ... ') 167 | 145 FORMAT(5X,'Writing the variables ... ') 168 | 150 FORMAT(5X,'I am opening the Dplot file ... ',/) 169 | 175 FORMAT(' done !',/) 170 | 180 FORMAT(5X,'Su2 file WRITTEN',/) 171 | 201 FORMAT('NDIME= ',I1) 172 | 202 FORMAT('NELEM= ',I8) 173 | 203 FORMAT('NPOIN= ',I8) 174 | 204 FORMAT('NMARK= ',I8) 175 | 205 FORMAT('MARKER_TAG= ',I2) 176 | 206 FORMAT('MARKER_ELEMS= ',I8) 177 | END 178 | -------------------------------------------------------------------------------- /Fortran/gmsh2su2_2D.f90: -------------------------------------------------------------------------------- 1 | ! ==================== 2 | ! README Gmsh2SU2D ver 0.06 3 | ! ==================== 4 | ! 5 | ! Original version by Ceanwang@gmail.com, Jan 2012 6 | ! 7 | ! Adapted from gmsh2dolfyn.f90 developed by dolfyn team. 8 | ! For dolfyn, please visit http://www.dolfyn.net/index_en.html 9 | ! 10 | ! Support Gmsh 2.5.0 11 | ! 12 | ! Purpose 13 | ! ------- 14 | ! This Fortran95 program translates a mesh file from Gmsh (.msh) format 15 | ! to Su2 format. 16 | ! 17 | ! Input and Output 18 | ! ---------------- 19 | ! Input : A Gmsh .msh file (version 2.0, ascii format). 20 | ! Output: SU2 files. 21 | ! 22 | ! Running the Program 23 | !-------------------- 24 | ! First compile it using a Fortran95 compiler (eg g95 or gfortran). 25 | ! Run it from the command line. 26 | ! The program prompts for the name of the input file. 27 | ! 28 | ! Bug reports 29 | ! ----------- 30 | ! Please report bugs to ceanwang@gmail.com 31 | ! 32 | ! Important note about the Gmsh msh format and Physical Groups. 33 | ! ------------------------------------------------------------- 34 | ! In order to define boundary conditions, the Gmsh geometry-builder allows a 35 | ! group of faces to be assigned a common 'physical group' label. The mesh 36 | ! inherits this label, and the label is used in the .su2 file. 37 | ! 38 | ! When saving the mesh, the default is to save only mesh elements with a 39 | ! physical group label. This means that some mesh elements will be missing, 40 | ! unless every mesh element belongs to a physical group. 41 | ! 42 | ! For example in the adapted gmsh tutorial t2.geo enter: 43 | ! 44 | ! Physical Volume ("Fluid") = {119,120}; 45 | ! Physical Surface("Inlet") = {111}; 46 | ! Physical Surface("Outlet") = {132}; 47 | ! 48 | ! Mesh 3D and save it as t2.msh 49 | ! 50 | !======================================================================== 51 | ! ver 0.06 Fixed rectangle element output 52 | ! Fixed MARKER_FAR output 53 | !======================================================================== 54 | !======================================================================== 55 | SUBROUTINE UPPERCASE(STR) 56 | 57 | IMPLICIT NONE 58 | 59 | CHARACTER(LEN=*), INTENT(IN OUT) :: STR 60 | INTEGER :: I, DEL 61 | 62 | DEL = IACHAR('a') - IACHAR('A') 63 | 64 | DO I = 1, LEN_TRIM(STR) 65 | IF (LGE(STR(I:I),'a') .AND. LLE(STR(I:I),'z')) THEN 66 | STR(I:I) = ACHAR(IACHAR(STR(I:I)) - DEL) 67 | END IF 68 | END DO 69 | 70 | RETURN 71 | 72 | END SUBROUTINE UPPERCASE 73 | 74 | integer function lens(string) 75 | 76 | character(len=*) string 77 | 78 | do i=len(string),0,-1 79 | if( string(i:i) .ne. ' ') goto 10 80 | end do 81 | i = 0 82 | 10 continue 83 | 84 | lens = i 85 | 86 | end function lens 87 | !====================================================================== 88 | subroutine openfile(iunit,casename,extension,reqform,status,idebug) 89 | 90 | character(len=*) casename 91 | character(len=*) extension 92 | character(len=*) reqform 93 | character(len=*) status 94 | character(len=48) filename 95 | character(len=11) form 96 | 97 | logical exists 98 | 99 | filename = casename(1:lens(casename))//extension(1:lens(extension)) 100 | length = lens(filename) 101 | 102 | if( idebug > 2 )write(*,*) 'Opening ',filename(1:length) 103 | 104 | if( status(1:3) == 'OLD' )then 105 | inquire(file=filename(1:length),exist=exists,form=form) 106 | if( .not. exists )then 107 | write(*,*) '*** Error: File ',filename(1:length),' does not exist' 108 | stop 109 | endif 110 | endif 111 | 112 | open(iunit,file=filename(1:length),form=reqform,status=status) 113 | 114 | if( idebug >= 2 ) write(*,*) 'File ',filename(1:length),' opened' 115 | 116 | end subroutine openfile 117 | !============================================================================== 118 | program gmsh2SU2 119 | 120 | implicit none 121 | 122 | integer, parameter :: IOinp = 13, IOcel = 14 ! I/O file numbers 123 | integer, parameter :: IOdbg = 63, IOcfg = 12 124 | integer, parameter :: IOgmsh= 24 !Gmsh mesh file 125 | 126 | integer :: NFluid = 0 127 | integer :: Nfarfield = 0 128 | integer :: Ninlet = 0 129 | integer :: Noutlet = 0 130 | integer :: Nsurface = 0 131 | integer :: isur = 0 132 | 133 | integer :: debug = 0 134 | 135 | integer, parameter :: version = 0530 136 | 137 | character(len=128) :: line 138 | 139 | integer, parameter :: MaxNames = 100 140 | integer, parameter :: MaxNperBnd = 500 141 | integer, parameter :: MaxNodes = 90000 142 | 143 | character(len=64), dimension(MaxNames) :: Names 144 | character(len=64), dimension(MaxNames) :: Regions 145 | integer, dimension(MaxNames) :: ICTID = -1 146 | integer, dimension(MaxNames) :: Partition= 1 147 | 148 | logical, dimension(MaxNames) :: Fluid = .false. 149 | logical, dimension(MaxNames) :: Boundary = .false. 150 | 151 | character(len=64) :: casename = 'su2' 152 | character(len=72) :: c_input1, c_input2, c_input3 153 | 154 | integer i, j, k, ie, icel, ibnd, iloop,ii 155 | integer tbnd(maxnames) 156 | integer nbnd 157 | ! 158 | ! nodes/vertices 159 | ! 160 | integer n_nodes,inode 161 | real node(MaxNodes,3) 162 | integer mytags(MaxNames) 163 | integer tv0(MaxNperBnd,MaxNames) 164 | integer tv1(MaxNperBnd,MaxNames) 165 | integer tv2(MaxNperBnd,MaxNames) 166 | integer tv3(MaxNperBnd,MaxNames) 167 | integer tv4(MaxNperBnd,MaxNames) 168 | 169 | ! 170 | ! there are 19 gmsh element types: \ 171 | ! 172 | ! 1 : 2-node line 173 | ! 2 : 3-node triangle (face) 174 | ! 3 : 4-node quadrangle (face) 175 | ! 4 : 4-node tetrahedron 176 | ! 5 : 8-node hexahedron (eg cube) 177 | ! 6 : 6-node triangular-prism 178 | ! 7 : 5-node pyramid 179 | ! 180 | ! 8-14: 'second-order' elements. Ref Gmsh manual. 181 | ! 15 : 1-node point 182 | ! 16-19: more second-order FEM elements 183 | ! 184 | ! the nodes/vertices for each element are read into the 185 | ! v array. 186 | ! 187 | ! each element can have several tags. 188 | ! the first tag gives the physical_group number. 189 | ! all elements on the same boundary have the same physical_group number. 190 | ! 191 | integer, parameter :: element_type(19) = & 192 | (/ 2,3,4,4,8,6,5,3,6,9,10,27,18,14,1,8,20,15,13 /) 193 | 194 | integer :: n_elements, ielement, ielement_type, n_tags, n_names, lens 195 | integer :: tags(64), v(27) 196 | integer :: bmarknew,bmarkold 197 | integer :: i3, i4q, i4, i5, i6, i8 198 | integer :: i2 199 | integer :: ivs = 0 200 | 201 | 202 | 203 | if( size(v) /= maxval(element_type) )then 204 | stop'bug: error in dimensions of array v' 205 | endif 206 | 207 | ! 208 | ! read the gmsh filename, then open the .msh file 209 | ! 210 | write(*,*) 'Gmsh2SU2: Converts a Gmsh mesh file to SU2 format.' 211 | write(*,*) '(Input must be in Gmsh version 2.0 ascii format.' 212 | write(*,*) ' Output is in SU2 format.)' 213 | write(*,*) ' ' 214 | write(*,*) 'Input Gmsh filename, excluding the .msh suffix' 215 | read(*,'(A)') casename 216 | 217 | write(*,*) 'Opening the Gmsh file' 218 | call openfile(IOgmsh,casename,'.msh','FORMATTED','OLD',debug) 219 | 220 | ! 221 | ! read the Gmsh file header 222 | ! 223 | write(*,*)'Reading MeshFormat' 224 | read(IOgmsh,*) c_input1 225 | call check_input_character(c_input1,'$MeshFormat') 226 | 227 | read(IOgmsh,*) c_input1,c_input2,c_input3 228 | if( c_input1 == '2.2' )then 229 | ivs = 22 230 | else if( c_input1 == '2.1' )then 231 | ivs = 21 232 | else if( c_input1 == '2' )then 233 | ivs = 20 234 | else 235 | write(*,*) '*** WARNING: unknown Gmsh version' 236 | write(*,*) '*** Unexpected results might happen' 237 | ivs = 21 238 | endif 239 | 240 | if( ivs == 20 )then 241 | call check_input_character(c_input1,'2') 242 | else if( ivs == 21 )then 243 | call check_input_character(c_input1,'2.1') 244 | else if( ivs == 22 )then 245 | call check_input_character(c_input1,'2.2') 246 | else 247 | write(*,*) '*** Version found ',c_input1 248 | endif 249 | 250 | call check_input_character(c_input2,'0') 251 | call check_input_character(c_input3,'8') 252 | 253 | write(*,*) 'MeshFormat: ', c_input1(1:lens(c_input1)),' ', & 254 | c_input2(1:lens(c_input2)),' ', & 255 | c_input3(1:lens(c_input3)) 256 | 257 | read(IOgmsh,*) c_input1 258 | call check_input_character(c_input1,'$EndMeshFormat') 259 | 260 | ! 261 | ! read the Gmsh PhysicalNames 262 | ! 263 | write(*,*)'' 264 | write(*,*)'Reading PhysicalNames' 265 | read(IOgmsh,*) c_input1 266 | call check_input_character(c_input1,'$PhysicalNames') 267 | 268 | read(IOgmsh,*) n_names 269 | if( n_names <= 0 )then 270 | write(*,*) 'error: number of names must be a positive number' 271 | stop 272 | endif 273 | 274 | if( ivs == 20 )then 275 | do i=1,n_names 276 | !read(IOgmsh,*) k,j,c_input1 277 | read(IOgmsh,*) j,c_input1 278 | write(*,*) 'Name ',j,'-> ', c_input1 279 | Names(j) = c_input1 280 | end do 281 | else if( ivs == 21 )then 282 | do i=1,n_names 283 | read(IOgmsh,*) k,j,c_input1 284 | write(*,*) 'Name ',j,'-> ', c_input1 285 | Names(j) = c_input1 286 | end do 287 | else 288 | do i=1,n_names 289 | read(IOgmsh,*) k,j,c_input1 290 | write(*,*) 'Name ',j,'-> ', c_input1 291 | Names(j) = c_input1 292 | end do 293 | endif 294 | 295 | do i=1,n_names 296 | CALL UPPERCASE(Names(i)) 297 | enddo 298 | 299 | read(IOgmsh,*) c_input1 300 | call check_input_character(c_input1,'$EndPhysicalNames') 301 | ! 302 | ! read the nodes from the .msh file and write them 303 | ! to the .vrt file. 304 | ! 305 | write(*,*)'Reading Nodes' 306 | read(IOgmsh,*) c_input1 307 | call check_input_character(c_input1,'$Nodes') 308 | !nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn 309 | read(IOgmsh,*) n_nodes 310 | if( n_nodes <= 0 )then 311 | write(*,*) 'error: number of nodes must be a positive number' 312 | stop 313 | endif 314 | 315 | if( n_nodes > MaxNodes )then 316 | write(*,*) 'error: The Gmsh file contains ',n_nodes,' nodes.' 317 | write(*,*) 'Gmsh2Su2 is hard-wired for a maximum of ',MaxNodes,& 318 | 'nodes. The dimension of this array needs to be increased.' 319 | stop 320 | endif 321 | 322 | ! 323 | ! open the su2 .vrt.su2 file 324 | ! 325 | !write(*,*) 'Creating the su2 .vrt.su2 file' 326 | !call openfile(IOvrt,casename,'.vrt.su2','FORMATTED','UNKNOWN',debug) 327 | 328 | nodes: do iloop=1,n_nodes 329 | read(IOgmsh,*) inode,(node(iloop,i), i=1,3) 330 | !write(IOvrt,'(3g16.9,6x,i9)') (node(iloop,i),i=1,3),inode-1 331 | enddo nodes 332 | 333 | write(*,*) 'Nodes written ',n_nodes 334 | ! 335 | ! close the su2 .vrt.su2 file 336 | ! 337 | !close(IOvrt) 338 | 339 | read(IOgmsh,*) c_input1 340 | call check_input_character(c_input1,'$EndNodes') 341 | !eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 342 | ! 343 | ! read the elements from the .msh file and write them 344 | ! to the .cel and .bnd files. 345 | ! 346 | read(IOgmsh,*) c_input1 347 | call check_input_character(c_input1,'$Elements') 348 | 349 | read(IOgmsh,*) n_elements 350 | if( n_elements <= 0 )then 351 | write(*,*) 'error: number of elements must be a positive number' 352 | stop 353 | endif 354 | 355 | write(*,*) 'Total Gmsh elements to be read in:',n_elements 356 | ! 357 | ! open the su2 .cel files 358 | ! 359 | write(*,*) '' 360 | write(*,*) 'Creating the .su2 files' 361 | call openfile(IOcel,casename,'.su2','FORMATTED','UNKNOWN',debug) 362 | write(IOcel,101) 2 363 | 101 format('NDIME= ',i1) 364 | 365 | 366 | ! 367 | ! note in Gmsh fluid cells and boudaries can be mixed 368 | ! we just keep track on them both 369 | ! remind default region is not assigned 370 | ! 371 | icel = 0 372 | ibnd = 0 373 | nbnd=0 374 | tbnd(nbnd)=0 375 | 376 | i2 = 0 377 | i3 = 0 378 | i4q = 0 379 | i4 = 0 380 | i5 = 0 381 | i6 = 0 382 | i8 = 0 383 | 384 | bmarkOld=0 385 | do ie=1,n_elements 386 | 387 | read(IOgmsh,*) ielement, ielement_type, n_tags 388 | if( ivs <= 21 )then 389 | if( n_tags /= 3 ) write(*,*) 'tag error n_tags /= 3:',ielement,n_tags 390 | else 391 | if( n_tags /= 2 ) write(*,*) 'tag error n_tags /= 2:',ielement,n_tags 392 | endif 393 | call check_element_type(ielement_type,element_type) 394 | call check_n_tags(n_tags,tags) 395 | backspace(IOgmsh) 396 | 397 | ! 398 | ! we need to circumvent backspace but 399 | ! advance='no' requires fixed format 400 | ! just keep it for now. 401 | ! 402 | 403 | ! 404 | ! now we know what to to expect to find on the line 405 | ! 406 | !write (*,*) element_type(ielement_type) 407 | read(IOgmsh,*) ielement, ielement_type, & 408 | n_tags, (tags(i),i=1,n_tags),& 409 | (v(i),i=1,element_type(ielement_type)) 410 | 411 | do ii=1,element_type(ielement_type) 412 | v(ii)=v(ii)-1 413 | end do 414 | 415 | bmarkNew=tags(1) 416 | if( 2 <= ielement_type .and. ielement_type <= 3 )then 417 | if (icel==0) then 418 | write(IOcel,121) n_elements-ibnd 419 | 121 format('NELEM= ',i10) 420 | endif 421 | icel = icel + 1 422 | 423 | if( .not. Fluid(tags(1)) ) Fluid(tags(1)) = .true. 424 | if( Boundary(tags(1)) )then 425 | write(*,*) 'Inconsistent data: Physical names ids overlap 1' 426 | endif 427 | 428 | 1 format(i8,8(1x,i8),2(1x,i4)) 429 | select case(ielement_type) 430 | 431 | case(2) ! 3-node tri 432 | 433 | write(IOcel,*) 5, v(1),v(2),v(3),icel-1 434 | i3 = i3 + 1 435 | 436 | case(3) ! 4-node quad 437 | 438 | write(IOcel,*) 9,v(1),v(2),v(3),v(4),icel-1 439 | i4q = i4q + 1 440 | 441 | case default 442 | 443 | write(*,*)'internal error 1' 444 | 445 | end select 446 | 447 | elseif( ielement_type == 1 )then 448 | 449 | if (bmarkNew/=bmarkOld) then 450 | bmarkOld=bmarkNew 451 | nbnd=nbnd+1 452 | tbnd(nbnd)=0 453 | endif 454 | 455 | ibnd = ibnd + 1 456 | tbnd(nbnd) = tbnd(nbnd) + 1 457 | 458 | if( .not. Boundary(tags(1)) ) Boundary(tags(1)) = .true. 459 | if( Fluid(tags(1)) )then 460 | write(*,*) 'Inconsistent data: Physical names ids overlap 2' 461 | endif 462 | 463 | !write(IObnd,*) 3, v(1),v(2) 464 | mytags(nbnd)=tags(1) 465 | tv0(tbnd(nbnd),nbnd)=3 466 | tv1(tbnd(nbnd),nbnd)=v(1) 467 | tv2(tbnd(nbnd),nbnd)=v(2) 468 | i2 = i2 + 1 469 | 470 | else 471 | 472 | write(*,*)'internal error 3' 473 | 474 | endif 475 | 476 | end do 477 | 478 | read(IOgmsh,*) c_input1 479 | call check_input_character(c_input1,'$EndElements') 480 | !------------------------------------------------------------ 481 | ! write out points 482 | !------------------------------------------------------------ 483 | write(IOcel,91) n_nodes 484 | 91 format('NPOIN= ',i10) 485 | 486 | do iloop=1,n_nodes 487 | write(IOcel,'(3g16.9,6x,i9)') (node(iloop,i),i=1,2),iloop-1 488 | enddo 489 | !------------------------------------------------------------ 490 | ! write out markers 491 | !------------------------------------------------------------ 492 | write(IOcel,111) n_names-1 493 | 111 format('NMARK= ',i10) 494 | do j=1,n_names-1 495 | write(IOcel,141) mytags(j) 496 | write(IOcel,151) tbnd(j) 497 | do i=1,tbnd(j) 498 | if (tv0(i,j)==3) then 499 | write(IOcel,*) tv0(i,j),tv1(i,j),tv2(i,j) 500 | endif 501 | enddo 502 | end do 503 | 141 format('MARKER_TAG= ',i3) 504 | 151 format('MARKER_ELEMS= ', i10) 505 | close(IOcel) 506 | 507 | 508 | if( i3 > 0 ) write(*,*) 'Triangle boundaries: ',i3 509 | if( i4q > 0 ) write(*,*) 'Quad boundaries: ',i4q 510 | if( i4 > 0 ) write(*,*) 'Tetrahedral cells: ',i4 511 | if( i5 > 0 ) write(*,*) 'Pyramid cells: ',i5 512 | if( i6 > 0 ) write(*,*) 'Prism cells: ',i6 513 | if( i8 > 0 ) write(*,*) 'Hexahedral cells: ',i8 514 | 515 | write(*,*) 'Done su2 file.' 516 | 517 | !------------------------------------------------------------ 518 | ! finally write out the boundary names 519 | !------------------------------------------------------------ 520 | do i=1,n_Names 521 | if (Names(i)=='INLET') then 522 | Ninlet=Ninlet+1 523 | endif 524 | if (Names(i)=='OUTLET') then 525 | Noutlet=Noutlet+1 526 | endif 527 | if (Names(i)=='FARFIELD') then 528 | Nfarfield=Nfarfield+1 529 | endif 530 | if (Names(i)=='FLUID') then 531 | Nfluid=Nfluid+1 532 | endif 533 | enddo 534 | Nsurface=N_names-Ninlet-Noutlet-Nfarfield-1 535 | !------------------------------------------------------------------------------------ 536 | ! Write out the .inp file 537 | !------------------------------------------------------------------------------------ 538 | write(*,*) '' 539 | write(*,*) 'Writing the .inp file' 540 | call openfile(IOinp,casename,'_inp.txt','FORMATTED','UNKNOWN',debug) 541 | 542 | write(IOinp,'('''')') 543 | write(IOinp,'(''% -------------------- BOUNDARY CONDITION DEFINITION --------------------------%'')') 544 | write(IOinp,'(''%'')') 545 | write(IOinp,'(''% Euler wall boundary marker(s) (NONE = no marker)'')') 546 | !write(IOinp,'(''MARKER_EULER='')') !( 3,4,5,6,7,8,9,10 ) 547 | if (N_names>0) then 548 | write(IOinp,'( "MARKER_EULER=(" )',ADVANCE = "NO") 549 | do i=1,N_names 550 | if (Names(i) .ne. 'INLET' .and. Names(i) .ne. 'OUTLET' .and. Names(i) .ne. 'FLUID'.and. Names(i) .ne. 'FARFIELD') then 551 | write(IOinp,'( i4 )',ADVANCE = "NO") i 552 | isur=isur+1 553 | if (isur0) then 568 | do i=1,MaxNames 569 | if (Names(i)=='FARFIELD') then 570 | write(IOinp,'( "MARKER_FAR=(",i4,")" )') i 571 | endif 572 | end do 573 | write(*,*) Nfarfield,'Farfield.' 574 | else 575 | write(IOinp,'(''MARKER_FAR= NONE'')') 576 | write(*,*) 'No farfield.' 577 | endif 578 | write(IOinp,'(''%'')') 579 | 580 | write(IOinp,'(''% Inlet boundary marker(s) (NONE = no marker) '')') 581 | write(IOinp,'(''% Format: ( inlet marker, total temperature, total pressure, flow_direction_x, '')') 582 | write(IOinp,'(''% flow_direction_y, flow_direction_z, ... ) where flow_direction is'')') 583 | write(IOinp,'(''% a unit vector.'')') 584 | if (Ninlet>0) then 585 | do i=1,MaxNames 586 | if (Names(i)=='INLET') then 587 | write(IOinp,'( "MARKER_INLET=(",i4,",288.6, 102010.0, 1.0, 0.0, 0.0)" )') i 588 | endif 589 | end do 590 | write(*,*) Ninlet,'Inlet.' 591 | else 592 | write(IOinp,'(''MARKER_INLET= NONE'')') 593 | write(*,*) 'No inlet.' 594 | endif 595 | write(IOinp,'(''%'')') 596 | !1001 format(1x,'MARKER_INLET=(',i10,'288.6, 102010.0, 1.0, 0.0, 0.0)') 597 | 598 | write(IOinp,'(''% Outlet boundary marker(s) (NONE = no marker)'')') 599 | write(IOinp,'(''% Format: ( outlet marker, back pressure (static), ... )'')') 600 | if (Noutlet>0) then 601 | do i=1,MaxNames 602 | if (Names(i)=='OUTLET') then 603 | write(IOinp,'( "MARKER_OUTLET=(",i4,",101300.0)" )') i 604 | endif 605 | end do 606 | write(*,*) Noutlet,'Outlet.' 607 | else 608 | write(IOinp,'(''MARKER_OUTLET= NONE'')') 609 | write(*,*) 'No outlet.' 610 | endif 611 | write(IOinp,'(''%'')') 612 | 613 | write(IOinp,'(''% Marker(s) of the surface to be plotted or designed'')') 614 | write(IOinp,'( ''MARKER_PLOTTING=(4,5)'' )') ! ( 5,4 ) 615 | write(IOinp,'(''%'')') 616 | 617 | write(IOinp,'(''% Marker(s) of the surface where the functional (Cd, Cl, etc.) will be evaluated'')') 618 | write(IOinp,'( ''MARKER_MONITORING=(4,5)'' )') ! ( 5, 4 ) 619 | write(IOinp,'('''')') 620 | 621 | if (Nfluid>0) then 622 | write(*,*) Nfluid,'Fluid.' 623 | else 624 | write(*,*) 'Error: No fluid. One 2D physical surface must be FLUID.' 625 | endif 626 | write(IOinp,'(''%'')') 627 | 628 | !do i=1,MaxNames 629 | ! if( Boundary(i) )then 630 | ! if( i <= 9 )then 631 | ! write(IOinp,'(''rname,'',i1,'','',A64)') i,Names(i) 632 | ! elseif( i <= 99 )then 633 | ! write(IOinp,'(''rname,'',i2,'','',A64)') i,Names(i) 634 | ! elseif( i <= 999 )then 635 | ! write(IOinp,'(''rname,'',i3,'','',A64)') i,Names(i) 636 | ! elseif( i <= 9999 )then 637 | ! write(IOinp,'(''rname,'',i4,'','',A64)') i,Names(i) 638 | ! elseif( i <= 99999 )then 639 | ! write(IOinp,'(''rname,'',i5,'','',A64)') i,Names(i) 640 | ! else 641 | ! write(IOinp,'(''rname,'',i6,'','',A64)') i,Names(i) 642 | ! endif 643 | ! endif 644 | ! end do 645 | 646 | close(IOinp) 647 | write(*,*) 'Done .inp file' 648 | 649 | write(*,*) '' 650 | write(*,*) 'Done gmsh2su2' 651 | 652 | 653 | 654 | contains 655 | !------------------------------------------------------------------------------------ 656 | ! 657 | !------------------------------------------------------------------------------------ 658 | subroutine check_input_character(c1,c2) 659 | 660 | implicit none 661 | 662 | character (len=*) :: c1, c2 663 | 664 | if( c1(1:len(c2)) /= c2 )then 665 | write(*,*) 'error reading Gmsh input file: ',& 666 | 'the following two characters should be the ',& 667 | 'same but differ ',c1(1:len(c2)),c2 668 | stop 669 | endif 670 | 671 | end subroutine 672 | !------------------------------------------------------------------------------------ 673 | ! 674 | !------------------------------------------------------------------------------------ 675 | subroutine check_element_type(ielement_type,element_type) 676 | 677 | implicit none 678 | integer ielement_type 679 | integer element_type(:) 680 | 681 | if( ielement_type < 0 )then 682 | write(*,*) 'error reading Gmsh file: element type must be positive' 683 | write(*,*) 'element type = ',ielement_type 684 | stop 685 | endif 686 | 687 | if( ielement_type > size(element_type) )then 688 | write(*,*) 'error reading Gmsh file: unrecognised element type' 689 | write(*,*) 'element type ',ielement_type 690 | write(*,*) 'max recognised element type ',size(element_type) 691 | stop 692 | endif 693 | 694 | end subroutine 695 | !------------------------------------------------------------------------------------ 696 | ! 697 | !------------------------------------------------------------------------------------ 698 | subroutine check_n_tags(ntags,itags) 699 | 700 | implicit none 701 | 702 | integer ntags 703 | integer itags(:) 704 | 705 | if( ntags > size(itags) )then 706 | write(*,*) 'error: The Gmsh file contains ',ntags,' tags per element' 707 | write(*,*) 'Gmsh2Su2 is hard-wired for a maximum of ',size(itags),& 708 | 'tags. The dimension of this array needs to be increased.' 709 | stop 710 | endif 711 | 712 | end subroutine 713 | end 714 | 715 | -------------------------------------------------------------------------------- /Fortran/gmsh2su2_3D.f90: -------------------------------------------------------------------------------- 1 | ! ==================== 2 | ! README Gmsh2SU3D ver 0.02 3 | ! ==================== 4 | ! 5 | ! Original version by Ceanwang@gmail.com, Jan 2012 6 | ! 7 | ! Adapted from gmsh2dolfyn.f90 developed by dolfyn team. 8 | ! For dolfyn, please visit http://www.dolfyn.net/index_en.html 9 | ! 10 | ! Support Gmsh 2.5.0 11 | ! 12 | ! Purpose 13 | ! ------- 14 | ! This Fortran95 program translates a mesh file from Gmsh (.msh) format 15 | ! to Su2 format. 16 | ! 17 | ! Input and Output 18 | ! ---------------- 19 | ! Input : A Gmsh .msh file (version 2.0, ascii format). 20 | ! Output: SU2 files. 21 | ! 22 | ! Running the Program 23 | !-------------------- 24 | ! First compile it using a Fortran95 compiler (eg g95 or gfortran). 25 | ! Run it from the command line. 26 | ! The program prompts for the name of the input file. 27 | ! 28 | ! Bug reports 29 | ! ----------- 30 | ! Please report bugs to ceanwang@gmail.com 31 | ! 32 | ! Important note about the Gmsh msh format and Physical Groups. 33 | ! ------------------------------------------------------------- 34 | ! In order to define boundary conditions, the Gmsh geometry-builder allows a 35 | ! group of faces to be assigned a common 'physical group' label. The mesh 36 | ! inherits this label, and the label is used in the .su2 file. 37 | ! 38 | ! When saving the mesh, the default is to save only mesh elements with a 39 | ! physical group label. This means that some mesh elements will be missing, 40 | ! unless every mesh element belongs to a physical group. 41 | ! 42 | ! For example in the adapted gmsh tutorial t2.geo enter: 43 | ! 44 | ! Physical Volume ("Fluid") = {119,120}; 45 | ! Physical Surface("Inlet") = {111}; 46 | ! Physical Surface("Outlet") = {132}; 47 | ! 48 | ! Mesh 3D and save it as t2.msh 49 | ! 50 | !======================================================================== 51 | !======================================================================== 52 | !======================================================================== 53 | SUBROUTINE UPPERCASE(STR) 54 | 55 | IMPLICIT NONE 56 | 57 | CHARACTER(LEN=*), INTENT(IN OUT) :: STR 58 | INTEGER :: I, DEL 59 | 60 | DEL = IACHAR('a') - IACHAR('A') 61 | 62 | DO I = 1, LEN_TRIM(STR) 63 | IF (LGE(STR(I:I),'a') .AND. LLE(STR(I:I),'z')) THEN 64 | STR(I:I) = ACHAR(IACHAR(STR(I:I)) - DEL) 65 | END IF 66 | END DO 67 | 68 | RETURN 69 | 70 | END SUBROUTINE UPPERCASE 71 | 72 | integer function lens(string) 73 | 74 | character(len=*) string 75 | 76 | do i=len(string),0,-1 77 | if( string(i:i) .ne. ' ') goto 10 78 | end do 79 | i = 0 80 | 10 continue 81 | 82 | lens = i 83 | 84 | end function lens 85 | !====================================================================== 86 | subroutine openfile(iunit,casename,extension,reqform,status,idebug) 87 | 88 | character(len=*) casename 89 | character(len=*) extension 90 | character(len=*) reqform 91 | character(len=*) status 92 | character(len=48) filename 93 | character(len=11) form 94 | 95 | logical exists 96 | 97 | filename = casename(1:lens(casename))//extension(1:lens(extension)) 98 | length = lens(filename) 99 | 100 | if( idebug > 2 )write(*,*) 'Opening ',filename(1:length) 101 | 102 | if( status(1:3) == 'OLD' )then 103 | inquire(file=filename(1:length),exist=exists,form=form) 104 | if( .not. exists )then 105 | write(*,*) '*** Error: File ',filename(1:length),' does not exist' 106 | stop 107 | endif 108 | endif 109 | 110 | open(iunit,file=filename(1:length),form=reqform,status=status) 111 | 112 | if( idebug >= 2 ) write(*,*) 'File ',filename(1:length),' opened' 113 | 114 | end subroutine openfile 115 | !============================================================================== 116 | program gmsh2SU2 117 | 118 | implicit none 119 | 120 | integer, parameter :: IOinp = 13, IOcel = 14 ! I/O file numbers 121 | integer, parameter :: IOdbg = 63, IOcfg = 12 122 | integer, parameter :: IOgmsh= 24 !Gmsh mesh file 123 | 124 | integer :: Ninlet = 0 125 | integer :: Noutlet = 0 126 | integer :: Nsurface = 0 127 | integer :: isur = 0 128 | 129 | integer :: debug = 0 130 | 131 | integer, parameter :: version = 0530 132 | 133 | character(len=128) :: line 134 | 135 | integer, parameter :: MaxNames = 100 136 | integer, parameter :: MaxNperBnd = 500 137 | integer, parameter :: MaxNodes = 90000 138 | 139 | character(len=64), dimension(MaxNames) :: Names 140 | character(len=64), dimension(MaxNames) :: Regions 141 | integer, dimension(MaxNames) :: ICTID = -1 142 | integer, dimension(MaxNames) :: Partition= 1 143 | 144 | logical, dimension(MaxNames) :: Fluid = .false. 145 | logical, dimension(MaxNames) :: Boundary = .false. 146 | 147 | character(len=64) :: casename = 'su2' 148 | character(len=72) :: c_input1, c_input2, c_input3 149 | 150 | integer i, j, k, ie, icel, ibnd, iloop,ii 151 | integer tbnd(maxnames) 152 | integer nbnd 153 | ! 154 | ! nodes/vertices 155 | ! 156 | integer n_nodes,inode 157 | real node(MaxNodes,3) 158 | integer mytags(MaxNames) 159 | integer tv0(MaxNperBnd,MaxNames) 160 | integer tv1(MaxNperBnd,MaxNames) 161 | integer tv2(MaxNperBnd,MaxNames) 162 | integer tv3(MaxNperBnd,MaxNames) 163 | integer tv4(MaxNperBnd,MaxNames) 164 | 165 | ! 166 | ! there are 19 gmsh element types: \ 167 | ! 168 | ! 1 : 2-node line 169 | ! 2 : 3-node triangle (face) 170 | ! 3 : 4-node quadrangle (face) 171 | ! 4 : 4-node tetrahedron 172 | ! 5 : 8-node hexahedron (eg cube) 173 | ! 6 : 6-node triangular-prism 174 | ! 7 : 5-node pyramid 175 | ! 176 | ! 8-14: 'second-order' elements. Ref Gmsh manual. 177 | ! 15 : 1-node point 178 | ! 16-19: more second-order FEM elements 179 | ! 180 | ! the nodes/vertices for each element are read into the 181 | ! v array. 182 | ! 183 | ! each element can have several tags. 184 | ! the first tag gives the physical_group number. 185 | ! all elements on the same boundary have the same physical_group number. 186 | ! 187 | integer, parameter :: element_type(19) = & 188 | (/ 2,3,4,4,8,6,5,3,6,9,10,27,18,14,1,8,20,15,13 /) 189 | 190 | integer :: n_elements, ielement, ielement_type, n_tags, n_names, lens 191 | integer :: tags(64), v(27) 192 | integer :: bmarknew,bmarkold 193 | integer :: i3, i4q, i4, i5, i6, i8 194 | integer :: i2 195 | integer :: ivs = 0 196 | 197 | 198 | 199 | if( size(v) /= maxval(element_type) )then 200 | stop'bug: error in dimensions of array v' 201 | endif 202 | 203 | ! 204 | ! read the gmsh filename, then open the .msh file 205 | ! 206 | write(*,*) 'Gmsh2SU2: Converts a Gmsh mesh file to SU2 format.' 207 | write(*,*) '(Input must be in Gmsh version 2.0 ascii format.' 208 | write(*,*) ' Output is in SU2 format.)' 209 | write(*,*) ' ' 210 | write(*,*) 'Input Gmsh filename, excluding the .msh suffix' 211 | read(*,'(A)') casename 212 | 213 | write(*,*) 'Opening the Gmsh file' 214 | call openfile(IOgmsh,casename,'.msh','FORMATTED','OLD',debug) 215 | 216 | ! 217 | ! read the Gmsh file header 218 | ! 219 | write(*,*)'Reading MeshFormat' 220 | read(IOgmsh,*) c_input1 221 | call check_input_character(c_input1,'$MeshFormat') 222 | 223 | read(IOgmsh,*) c_input1,c_input2,c_input3 224 | if( c_input1 == '2.2' )then 225 | ivs = 22 226 | else if( c_input1 == '2.1' )then 227 | ivs = 21 228 | else if( c_input1 == '2' )then 229 | ivs = 20 230 | else 231 | write(*,*) '*** WARNING: unknown Gmsh version' 232 | write(*,*) '*** Unexpected results might happen' 233 | ivs = 21 234 | endif 235 | 236 | if( ivs == 20 )then 237 | call check_input_character(c_input1,'2') 238 | else if( ivs == 21 )then 239 | call check_input_character(c_input1,'2.1') 240 | else if( ivs == 22 )then 241 | call check_input_character(c_input1,'2.2') 242 | else 243 | write(*,*) '*** Version found ',c_input1 244 | endif 245 | 246 | call check_input_character(c_input2,'0') 247 | call check_input_character(c_input3,'8') 248 | 249 | write(*,*) 'MeshFormat: ', c_input1(1:lens(c_input1)),' ', & 250 | c_input2(1:lens(c_input2)),' ', & 251 | c_input3(1:lens(c_input3)) 252 | 253 | read(IOgmsh,*) c_input1 254 | call check_input_character(c_input1,'$EndMeshFormat') 255 | 256 | ! 257 | ! read the Gmsh PhysicalNames 258 | ! 259 | write(*,*)'Reading PhysicalNames' 260 | read(IOgmsh,*) c_input1 261 | call check_input_character(c_input1,'$PhysicalNames') 262 | 263 | read(IOgmsh,*) n_names 264 | if( n_names <= 0 )then 265 | write(*,*) 'error: number of names must be a positive number' 266 | stop 267 | endif 268 | 269 | if( ivs == 20 )then 270 | do i=1,n_names 271 | !read(IOgmsh,*) k,j,c_input1 272 | read(IOgmsh,*) j,c_input1 273 | write(*,*) 'Name ',j,'-> ', c_input1 274 | Names(j) = c_input1 275 | end do 276 | else if( ivs == 21 )then 277 | do i=1,n_names 278 | read(IOgmsh,*) k,j,c_input1 279 | write(*,*) 'Name ',j,'-> ', c_input1 280 | Names(j) = c_input1 281 | end do 282 | else 283 | do i=1,n_names 284 | read(IOgmsh,*) k,j,c_input1 285 | write(*,*) 'Name ',j,'-> ', c_input1 286 | Names(j) = c_input1 287 | end do 288 | endif 289 | 290 | 291 | do i=1,n_names 292 | CALL UPPERCASE(Names(i)) 293 | enddo 294 | 295 | read(IOgmsh,*) c_input1 296 | call check_input_character(c_input1,'$EndPhysicalNames') 297 | ! 298 | ! read the nodes from the .msh file and write them 299 | ! to the .vrt file. 300 | ! 301 | write(*,*)'Reading Nodes' 302 | read(IOgmsh,*) c_input1 303 | call check_input_character(c_input1,'$Nodes') 304 | !nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn 305 | read(IOgmsh,*) n_nodes 306 | if( n_nodes <= 0 )then 307 | write(*,*) 'error: number of nodes must be a positive number' 308 | stop 309 | endif 310 | 311 | if( n_nodes > MaxNodes )then 312 | write(*,*) 'error: The Gmsh file contains ',n_nodes,' nodes.' 313 | write(*,*) 'Gmsh2Su2 is hard-wired for a maximum of ',MaxNodes,& 314 | 'nodes. The dimension of this array needs to be increased.' 315 | stop 316 | endif 317 | 318 | ! 319 | ! open the su2 .vrt.su2 file 320 | ! 321 | !write(*,*) 'Creating the su2 .vrt.su2 file' 322 | !call openfile(IOvrt,casename,'.vrt.su2','FORMATTED','UNKNOWN',debug) 323 | 324 | nodes: do iloop=1,n_nodes 325 | read(IOgmsh,*) inode,(node(iloop,i), i=1,3) 326 | !write(IOvrt,'(3g16.9,6x,i9)') (node(iloop,i),i=1,3),inode-1 327 | enddo nodes 328 | 329 | write(*,*) 'Nodes written ',n_nodes 330 | ! 331 | ! close the su2 .vrt.su2 file 332 | ! 333 | !close(IOvrt) 334 | 335 | read(IOgmsh,*) c_input1 336 | call check_input_character(c_input1,'$EndNodes') 337 | !eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 338 | ! 339 | ! read the elements from the .msh file and write them 340 | ! to the .cel and .bnd files. 341 | ! 342 | read(IOgmsh,*) c_input1 343 | call check_input_character(c_input1,'$Elements') 344 | 345 | read(IOgmsh,*) n_elements 346 | if( n_elements <= 0 )then 347 | write(*,*) 'error: number of elements must be a positive number' 348 | stop 349 | endif 350 | 351 | write(*,*) 'Total Gmsh elements to be read in:',n_elements 352 | ! 353 | ! open the su2 .cel files 354 | ! 355 | write(*,*) 'Creating the .su2 files' 356 | call openfile(IOcel,casename,'.su2','FORMATTED','UNKNOWN',debug) 357 | write(IOcel,101) 3 358 | 101 format('NDIME= ',i1) 359 | 360 | 361 | ! 362 | ! note in Gmsh fluid cells and boudaries can be mixed 363 | ! we just keep track on them both 364 | ! remind default region is not assigned 365 | ! 366 | icel = 0 367 | ibnd = 0 368 | nbnd=0 369 | tbnd(nbnd)=0 370 | 371 | i2 = 0 372 | i3 = 0 373 | i4q = 0 374 | i4 = 0 375 | i5 = 0 376 | i6 = 0 377 | i8 = 0 378 | 379 | bmarkOld=0 380 | do ie=1,n_elements 381 | 382 | read(IOgmsh,*) ielement, ielement_type, n_tags 383 | if( ivs <= 21 )then 384 | if( n_tags /= 3 ) write(*,*) 'tag error n_tags /= 3:',ielement,n_tags 385 | else 386 | if( n_tags /= 2 ) write(*,*) 'tag error n_tags /= 2:',ielement,n_tags 387 | endif 388 | call check_element_type(ielement_type,element_type) 389 | call check_n_tags(n_tags,tags) 390 | backspace(IOgmsh) 391 | 392 | ! 393 | ! we need to circumvent backspace but 394 | ! advance='no' requires fixed format 395 | ! just keep it for now. 396 | ! 397 | 398 | ! 399 | ! now we know what to to expect to find on the line 400 | ! 401 | read(IOgmsh,*) ielement, ielement_type, & 402 | n_tags, (tags(i),i=1,n_tags),& 403 | (v(i),i=1,element_type(ielement_type)) 404 | 405 | do ii=1,element_type(ielement_type) 406 | v(ii)=v(ii)-1 407 | end do 408 | 409 | bmarkNew=tags(1) 410 | if( 4 <= ielement_type .and. ielement_type <= 7 )then 411 | if (icel==0) then 412 | write(IOcel,121) n_elements-ibnd 413 | 121 format('NELEM= ',i10) 414 | endif 415 | icel = icel + 1 416 | 417 | if( .not. Fluid(tags(1)) ) Fluid(tags(1)) = .true. 418 | if( Boundary(tags(1)) )then 419 | write(*,*) 'Inconsistent data: Physical names ids overlap 1' 420 | endif 421 | 422 | 1 format(i8,8(1x,i8),2(1x,i4)) 423 | select case(ielement_type) 424 | 425 | case(4) ! 4-node tet 426 | 427 | write(IOcel,*) 10,v(1),v(2),v(3),v(4),icel-1 428 | i4 = i4 + 1 429 | 430 | case(5) ! 8-node hex 431 | 432 | write(IOcel,*) 12,v(1),v(2),v(3),v(4), v(5),v(6),v(7),v(8),icel-1 433 | !tags(1),tags(3) 434 | i8 = i8 + 1 435 | 436 | case(6) ! 6-node prism or wedge 437 | 438 | write(IOcel,*) 13,v(1),v(2),v(3), v(4),v(5),v(6),icel-1 439 | i6 = i6 + 1 440 | 441 | case(7) ! 5-node pyramid 442 | 443 | write(IOcel,*) 14,v(1),v(2),v(3),v(4), v(5),icel-1 444 | i5 = i5 + 1 445 | 446 | case default 447 | 448 | write(*,*)'internal error 1' 449 | 450 | end select 451 | 452 | elseif( ielement_type == 2 .or. ielement_type == 3 )then 453 | 454 | if (bmarkNew/=bmarkOld) then 455 | bmarkOld=bmarkNew 456 | nbnd=nbnd+1 457 | tbnd(nbnd)=0 458 | endif 459 | 460 | ibnd = ibnd + 1 461 | tbnd(nbnd) = tbnd(nbnd) + 1 462 | 463 | 464 | if( .not. Boundary(tags(1)) ) Boundary(tags(1)) = .true. 465 | if( Fluid(tags(1)) )then 466 | write(*,*) 'Inconsistent data: Physical names ids overlap 2' 467 | endif 468 | 469 | select case(ielement_type) 470 | 471 | case(2) ! 3-node tri 472 | 473 | !write(IObnd,*) 5, v(1),v(2),v(3) 474 | mytags(nbnd)=tags(1) 475 | tv0(tbnd(nbnd),nbnd)=5 476 | tv1(tbnd(nbnd),nbnd)=v(1) 477 | tv2(tbnd(nbnd),nbnd)=v(2) 478 | tv3(tbnd(nbnd),nbnd)=v(3) 479 | i3 = i3 + 1 480 | 481 | case(3) ! 4-node quad 482 | 483 | !write(IObnd,1) 8, v(1),v(2),v(3),v(4) 484 | mytags(nbnd)=tags(1) 485 | tv0(tbnd(nbnd),nbnd)=8 486 | tv1(tbnd(nbnd),nbnd)=v(1) 487 | tv2(tbnd(nbnd),nbnd)=v(2) 488 | tv3(tbnd(nbnd),nbnd)=v(3) 489 | tv4(tbnd(nbnd),nbnd)=v(4) 490 | i4q = i4q + 1 491 | 492 | case default 493 | 494 | write(*,*)'internal error 2' 495 | 496 | end select 497 | 498 | elseif( ielement_type == 1 )then 499 | ! 2- nodes line 500 | 501 | !write(IObnd,*) 3, v(1),v(2) 502 | mytags(nbnd)=tags(1) 503 | tv0(tbnd(nbnd),nbnd)=3 504 | tv1(tbnd(nbnd),nbnd)=v(1) 505 | tv2(tbnd(nbnd),nbnd)=v(2) 506 | i2 = i2 + 1 507 | 508 | else 509 | 510 | write(*,*)'internal error 3' 511 | 512 | endif 513 | 514 | end do 515 | 516 | read(IOgmsh,*) c_input1 517 | call check_input_character(c_input1,'$EndElements') 518 | !------------------------------------------------------------ 519 | ! write out points 520 | !------------------------------------------------------------ 521 | write(IOcel,91) n_nodes 522 | 91 format('NPOIN= ',i10) 523 | 524 | do iloop=1,n_nodes 525 | write(IOcel,'(3g16.9,6x,i9)') (node(iloop,i),i=1,3),iloop-1 526 | enddo 527 | 528 | write(IOcel,111) n_names-1 529 | 111 format('NMARK= ',i10) 530 | do j=1,n_names-1 531 | write(IOcel,141) mytags(j) 532 | write(IOcel,151) tbnd(j) 533 | do i=1,tbnd(j) 534 | if (tv0(i,j)==5) then 535 | write(IOcel,*) tv0(i,j), tv1(i,j),tv2(i,j),tv3(i,j) 536 | endif 537 | 201 format(1x, i10,3f15.6) 538 | if (tv0(i,j)==8) then 539 | write(IOcel,*) tv0(i,j), tv1(i,j),tv2(i,j),tv3(i,j),tv4(i,j) 540 | endif 541 | 211 format(1x, i10,4f15.6) 542 | 543 | enddo 544 | end do 545 | 141 format('MARKER_TAG= ',i3) 546 | 151 format('MARKER_ELEMS= ', i10) 547 | close(IOcel) 548 | 549 | 550 | if( i3 > 0 ) write(*,*) 'Triangle boundaries: ',i3 551 | if( i4q > 0 ) write(*,*) 'Quad boundaries: ',i4q 552 | if( i4 > 0 ) write(*,*) 'Tetrahedral cells: ',i4 553 | if( i5 > 0 ) write(*,*) 'Pyramid cells: ',i5 554 | if( i6 > 0 ) write(*,*) 'Prism cells: ',i6 555 | if( i8 > 0 ) write(*,*) 'Hexahedral cells: ',i8 556 | 557 | !------------------------------------------------------------ 558 | ! finally write out the boundary names 559 | !------------------------------------------------------------ 560 | do i=1,n_Names 561 | if (Names(i)=='INLET') then 562 | Ninlet=Ninlet+1 563 | endif 564 | if (Names(i)=='OUTLET') then 565 | Noutlet=Noutlet+1 566 | endif 567 | enddo 568 | Nsurface=N_names-Ninlet-Noutlet-1 569 | 570 | write(*,*) 'Writing the .inp file' 571 | call openfile(IOinp,casename,'_inp.txt','FORMATTED','UNKNOWN',debug) 572 | 573 | write(IOinp,'('''')') 574 | write(IOinp,'(''% -------------------- BOUNDARY CONDITION DEFINITION --------------------------%'')') 575 | write(IOinp,'(''%'')') 576 | write(IOinp,'(''% Euler wall boundary marker(s) (NONE = no marker)'')') 577 | !write(IOinp,'(''MARKER_EULER='')') !( 3,4,5,6,7,8,9,10 ) 578 | if (N_names>0) then 579 | write(IOinp,'( "MARKER_EULER=(" )',ADVANCE = "NO") 580 | do i=1,N_names 581 | if (Names(i) .ne. 'INLET' .and. Names(i) .ne. 'OUTLET' .and. Names(i) .ne. 'FLUID') then 582 | write(IOinp,'( i4 )',ADVANCE = "NO") i 583 | isur=isur+1 584 | if (isur0) then 600 | do i=1,MaxNames 601 | if (Names(i)=='INLET') then 602 | write(IOinp,'( "MARKER_INLET=(",i4,",288.6, 102010.0, 1.0, 0.0, 0.0)" )') i 603 | endif 604 | end do 605 | else 606 | write(IOinp,'(''MARKER_INLET= NONE'')') 607 | endif 608 | write(IOinp,'(''%'')') 609 | !1001 format(1x,'MARKER_INLET=(',i10,'288.6, 102010.0, 1.0, 0.0, 0.0)') 610 | 611 | write(IOinp,'(''% Outlet boundary marker(s) (NONE = no marker)'')') 612 | write(IOinp,'(''% Format: ( outlet marker, back pressure (static), ... )'')') 613 | if (Noutlet>0) then 614 | do i=1,MaxNames 615 | if (Names(i)=='OUTLET') then 616 | write(IOinp,'( "MARKER_OUTLET=(",i4,",101300.0)" )') i 617 | endif 618 | end do 619 | else 620 | write(IOinp,'(''MARKER_OUTLET= NONE'')') 621 | endif 622 | write(IOinp,'(''%'')') 623 | 624 | write(IOinp,'(''% Marker(s) of the surface to be plotted or designed'')') 625 | write(IOinp,'( ''MARKER_PLOTTING=(4,5)'' )') ! ( 5,4 ) 626 | write(IOinp,'(''%'')') 627 | 628 | write(IOinp,'(''% Marker(s) of the surface where the functional (Cd, Cl, etc.) will be evaluated'')') 629 | write(IOinp,'( ''MARKER_MONITORING=(4,5)'' )') ! ( 5, 4 ) 630 | write(IOinp,'('''')') 631 | 632 | !do i=1,MaxNames 633 | ! if( Boundary(i) )then 634 | ! if( i <= 9 )then 635 | ! write(IOinp,'(''rname,'',i1,'','',A64)') i,Names(i) 636 | ! elseif( i <= 99 )then 637 | ! write(IOinp,'(''rname,'',i2,'','',A64)') i,Names(i) 638 | ! elseif( i <= 999 )then 639 | ! write(IOinp,'(''rname,'',i3,'','',A64)') i,Names(i) 640 | ! elseif( i <= 9999 )then 641 | ! write(IOinp,'(''rname,'',i4,'','',A64)') i,Names(i) 642 | ! elseif( i <= 99999 )then 643 | ! write(IOinp,'(''rname,'',i5,'','',A64)') i,Names(i) 644 | ! else 645 | ! write(IOinp,'(''rname,'',i6,'','',A64)') i,Names(i) 646 | ! endif 647 | ! endif 648 | ! end do 649 | 650 | close(IOinp) 651 | 652 | write(*,*) 'Done gmsh2su2' 653 | 654 | contains 655 | !------------------------------------------------------------------------------------ 656 | subroutine check_input_character(c1,c2) 657 | 658 | implicit none 659 | 660 | character (len=*) :: c1, c2 661 | 662 | if( c1(1:len(c2)) /= c2 )then 663 | write(*,*) 'error reading Gmsh input file: ',& 664 | 'the following two characters should be the ',& 665 | 'same but differ ',c1(1:len(c2)),c2 666 | stop 667 | endif 668 | 669 | end subroutine 670 | subroutine check_element_type(ielement_type,element_type) 671 | 672 | implicit none 673 | integer ielement_type 674 | integer element_type(:) 675 | 676 | if( ielement_type < 0 )then 677 | write(*,*) 'error reading Gmsh file: element type must be positive' 678 | write(*,*) 'element type = ',ielement_type 679 | stop 680 | endif 681 | 682 | if( ielement_type > size(element_type) )then 683 | write(*,*) 'error reading Gmsh file: unrecognised element type' 684 | write(*,*) 'element type ',ielement_type 685 | write(*,*) 'max recognised element type ',size(element_type) 686 | stop 687 | endif 688 | 689 | end subroutine 690 | subroutine check_n_tags(ntags,itags) 691 | 692 | implicit none 693 | 694 | integer ntags 695 | integer itags(:) 696 | 697 | if( ntags > size(itags) )then 698 | write(*,*) 'error: The Gmsh file contains ',ntags,' tags per element' 699 | write(*,*) 'Gmsh2Su2 is hard-wired for a maximum of ',size(itags),& 700 | 'tags. The dimension of this array needs to be increased.' 701 | stop 702 | endif 703 | 704 | end subroutine 705 | end 706 | 707 | -------------------------------------------------------------------------------- /Matlab/MergeSU2.m: -------------------------------------------------------------------------------- 1 | function meshout = MergeSU2(mesh1,mesh2) 2 | % meshout = MergeSU2(mesh1,mesh2) 3 | % concatenates mesh2 information below mesh1 4 | 5 | %% SETUP 6 | 7 | assert( mesh1.dim == mesh2.dim , 'mesh dimension mismatch' ); 8 | 9 | meshout = mesh1; 10 | 11 | 12 | %% POINTS 13 | 14 | mesh2.poin(:,end) = mesh2.poin(:,end) + mesh1.npoin; 15 | 16 | meshout.poin = [ meshout.poin ; mesh2.poin ]; 17 | meshout.npoin = size( meshout.poin, 1 ); 18 | 19 | 20 | %% ELEMENTS 21 | 22 | for ielem = 1:mesh2.nelem 23 | elem_leng = getElemTypeInfo( mesh2.elem(ielem,1) ); 24 | elem_range = 2:(1+elem_leng); 25 | mesh2.elem( ielem, elem_range ) = mesh1.npoin + mesh2.elem( ielem, elem_range ); 26 | mesh2.elem( ielem, elem_leng+2 ) = mesh1.nelem + mesh2.elem( ielem, elem_leng+2 ); 27 | end 28 | 29 | meshout.elem = [ meshout.elem ; mesh2.elem ]; 30 | meshout.nelem = size( meshout.elem, 1 ); 31 | 32 | 33 | %% MARKERS 34 | 35 | mesh1_marklist = { mesh1.mark(:).tag }; 36 | 37 | for imark = 1:mesh2.nmark; 38 | 39 | % Elements 40 | for ielem = 1:mesh2.mark(imark).nelem 41 | elem_leng = getElemTypeInfo( mesh2.mark(imark).elem(ielem,1) ); 42 | elem_range = 2:(1+elem_leng); 43 | mesh2.mark(imark).elem( ielem, elem_range ) = mesh1.npoin + mesh2.mark(imark).elem( ielem, elem_range ); 44 | end 45 | 46 | jmark = find( strcmp( mesh2.mark(imark).tag, mesh1_marklist ) ); 47 | njmark = length(jmark); 48 | 49 | % Existing Marker 50 | if njmark == 1 51 | 52 | meshout.mark(jmark).elem = [ meshout.mark(jmark).elem ; mesh2.mark(imark).elem ]; 53 | meshout.mark(jmark).nelem = size( meshout.mark(jmark).elem, 1 ); 54 | 55 | % New Marker 56 | elseif njmark == 0 57 | 58 | jmark = length(meshout.mark)+1; 59 | 60 | meshout.mark(jmark).tag = mesh2.mark(imark).tag; 61 | meshout.mark(jmark).elem = mesh2.mark(imark).elem; 62 | meshout.mark(jmark).nelem = size( meshout.mark(jmark).elem, 1 ); 63 | 64 | else 65 | error('duplicate markers?') 66 | 67 | end 68 | 69 | end 70 | 71 | meshout.nmark = length(meshout.mark); 72 | 73 | 74 | %% DONE 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Matlab/ReadSU2.m: -------------------------------------------------------------------------------- 1 | function meshout = ReadSU2(meshname) 2 | % meshout = ReadSU2(meshname) 3 | % reads meshname.su2 into struct meshout 4 | % 5 | % meshout = 6 | % dim: mesh dimension 7 | % npoin: number of points 8 | % poin: point array [x y (z) ip] 9 | % nelem: number of elements 10 | % elem: element array [ type p1 p2 ... pn ielem ] 11 | % nmark: number of markers 12 | % mark: marker struct array 13 | % meshout.mark(imark) = 14 | % tag: marker tag 15 | % nelem: number of marker elements 16 | % elem: element array [ type p1 p2 ... pn ] 17 | % 18 | % note: element array is right-padded with zeros to 19 | % accomodate multiple element types. use getElemTypeInfo() 20 | % to get how many points are in an element. 21 | % 22 | 23 | %% Open File 24 | 25 | fprintf('Read %s \n',meshname); 26 | fid = fopen(meshname,'r'); 27 | 28 | % make sure file opened 29 | if fid == -1 30 | error('file open error') 31 | end 32 | 33 | %% Setup 34 | 35 | % initialize data 36 | meshout.dim = 0; 37 | meshout.npoin = 0; 38 | meshout.poin = [0]; 39 | meshout.nelem = 0; 40 | meshout.elem = [0]; 41 | meshout.nmark = 0; 42 | meshout.mark(1).tag = ''; 43 | meshout.mark(1).nelem = 0; 44 | meshout.mark(1).elem = [0]; 45 | 46 | % marker index 47 | imarkr = 1; 48 | 49 | 50 | %% Read 51 | 52 | % scan file until end of file 53 | while ~feof(fid) 54 | 55 | % look for mesh keywords 56 | % read one line 57 | C = textscan(fid,'%s %s',1,'CommentStyle','%'); 58 | 59 | % check for end of file 60 | if feof(fid) 61 | break 62 | end 63 | 64 | % tokenize line 65 | key = C{1}{1}; 66 | val = C{2}{1}; 67 | 68 | % check if val is a double or a string 69 | temp = str2double(val); 70 | if ~isnan(temp) 71 | val = temp; 72 | end 73 | 74 | % handle the keyword 75 | switch key 76 | 77 | % dimension number 78 | case 'NDIME=' 79 | % save to data struct 80 | meshout.dim=val; 81 | 82 | % elements 83 | case 'NELEM=' 84 | % save to data struct 85 | meshout.nelem = val; 86 | 87 | % read next lines for element data 88 | % builds a potentially oversized matrix 89 | E = textscan(fid, '%u64 %u64 %u64 %u64 %u64 %u64 %u64 %u64 %u64 %u64', ... 90 | meshout.nelem, ... 91 | 'CollectOutput',true,'CommentStyle','%' ); 92 | E = E{1}; 93 | 94 | % save to data struct 95 | meshout.elem = E; 96 | 97 | % points 98 | case 'NPOIN=' 99 | % save to data struct 100 | meshout.npoin = val; 101 | 102 | % read next lines for point data 103 | E = textscan(fid, '%f64 %f64 %f64 %f64 %f64', ... 104 | meshout.npoin , ... 105 | 'CollectOutput',true,'CommentStyle','%' ); 106 | E = E{1}; 107 | 108 | % save to data struct 109 | meshout.poin = E(:,1:(meshout.dim+1)); 110 | 111 | % number of markers 112 | case 'NMARK=' 113 | % save to data struct 114 | meshout.nmark = val; 115 | 116 | % a marker 117 | case 'MARKER_TAG=' 118 | % save name to data.mark struct 119 | meshout.mark(imarkr).tag=val; 120 | 121 | % read next line to get marker nelems 122 | C = textscan(fid,'%s %s',1,'CommentStyle','%'); 123 | % tokenize line 124 | key = C{1}{1}; 125 | val = C{2}{1}; 126 | 127 | if ~strcmp(key,'MARKER_ELEMS=') 128 | error('marker specification error') 129 | end 130 | 131 | % save number of elements to data.mark struct 132 | meshout.mark(imarkr).nelem = str2double(val); 133 | 134 | % read next lines to get marker elements 135 | E = textscan(fid, '%u64 %u64 %u64 %u64 %u64 %u64 %u64 %u64 %u64 %u64', ... 136 | meshout.mark(imarkr).nelem, ... 137 | 'CollectOutput',true,'CommentStyle','%' ); 138 | E = E{1}; 139 | 140 | % save elements to data.mark struct 141 | meshout.mark(imarkr).elem = E; 142 | 143 | % increment marker index 144 | imarkr = imarkr+1; 145 | 146 | end % switch key 147 | 148 | 149 | 150 | end % while read file line 151 | 152 | 153 | %% Done 154 | 155 | % close 156 | fclose(fid); 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /Matlab/WriteSU2.m: -------------------------------------------------------------------------------- 1 | function WriteSU2(meshout,meshname) 2 | % WriteSU2(meshout,meshname) 3 | % writes meshname.su2 from struct meshout 4 | % for some reason it will only write single precision 5 | % 6 | % meshout = 7 | % dim: mesh dimension 8 | % npoin: number of points 9 | % poin: point array [x y (z) ip] 10 | % nelem: number of elements 11 | % elem: element array [ type p1 p2 ... pn ielem ] 12 | % nmark: number of markers 13 | % mark: marker struct array 14 | % meshout.mark(imark) = 15 | % tag: marker tag 16 | % nelem: number of marker elements 17 | % elem: element array [ type p1 p2 ... pn ] 18 | % 19 | % note: element array is right-padded with zeros to 20 | % accomodate multiple element types. use getElemTypeInfo() 21 | % to get how many points are in an element. 22 | % 23 | 24 | %% Open File 25 | 26 | fprintf('Write %s \n',meshname); 27 | fid = fopen(meshname,'w'); 28 | 29 | 30 | %% Dimension 31 | 32 | fprintf(fid,'%% \n%% Problem dimension \n%% \n'); 33 | fprintf(fid,'NDIME= %i\n%',meshout.dim); 34 | 35 | 36 | %% Elements 37 | 38 | fprintf(fid,'%% \n%% Inner element connectivity \n%% \n'); 39 | fprintf(fid,'NELEM= %i\n%',meshout.nelem); 40 | % fprintf(fid,'%-2i %5i %5i %5i %5i \n',data.elem'); 41 | for i = 1:meshout.nelem 42 | this_elem = meshout.elem(i,:); 43 | elem_type = this_elem(1); 44 | elem_leng = getElemTypeInfo(elem_type); 45 | elem_range = 1:(2+elem_leng); 46 | printElement( fid, this_elem(elem_range) ); 47 | end 48 | 49 | 50 | %% Nodes 51 | 52 | fprintf(fid,'%% \n%% Node coordinates \n%% \n'); 53 | fprintf(fid,'NPOIN= %i\n%',meshout.npoin); 54 | if meshout.dim == 2 55 | fprintf(fid,'%#28.16g %#28.18g %i \n',meshout.poin'); 56 | else 57 | fprintf(fid,'%#28.18g %#28.18g %#28.18g %i \n',meshout.poin'); 58 | end 59 | 60 | 61 | %% Markers 62 | 63 | fprintf(fid,'%%\n%% Boundary elements \n%% \n'); 64 | fprintf(fid,'NMARK= %i\n%',meshout.nmark); 65 | 66 | nM = meshout.nmark; 67 | for i = 1:nM 68 | fprintf(fid,'MARKER_TAG= %s\n',meshout.mark(i).tag); 69 | fprintf(fid,'MARKER_ELEMS= %i\n',meshout.mark(i).nelem); 70 | for j = 1:meshout.mark(i).nelem 71 | this_elem = meshout.mark(i).elem(j,:); 72 | elem_type = this_elem(1); 73 | elem_leng = getElemTypeInfo(elem_type); 74 | elem_range = 1:(1+elem_leng); 75 | printElement( fid, this_elem(elem_range) ); 76 | end 77 | end 78 | 79 | fclose all; 80 | 81 | 82 | %% Helper Function 83 | function printElement(fid,elem) 84 | fprintf(fid,'%-2i ',elem(1)); 85 | fprintf(fid,'%5i ',elem(2:end)); 86 | fprintf(fid,'\n'); 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Matlab/angle2dcm.m: -------------------------------------------------------------------------------- 1 | function [dcm] = angle2dcm(r,seq) 2 | % dcm = angle2dcm(r1,r2,r3,seq) 3 | % builds euler angle rotation matrix 4 | % 5 | % r = [r1 r2 r3] 6 | % seq = 'ZYX' (default) 7 | % 'ZXZ' 8 | % dcm = direction cosine matrix 9 | 10 | if nargin == 1 11 | seq = 'ZYX'; 12 | end 13 | 14 | switch seq 15 | case 'ZYX' 16 | dcm = Tx(r(3))*Ty(r(2))*Tz(r(1)); 17 | case 'ZXZ' 18 | dcm = Tz(r(3))*Tx(r(2))*Tz(r(1)); 19 | end 20 | 21 | function A = Tx(a) 22 | A = [1 0 0;0 cosd(a) sind(a);0 -sind(a) cosd(a)]; 23 | 24 | function A = Ty(a) 25 | A = [cosd(a) 0 -sind(a);0 1 0;sind(a) 0 cosd(a)]; 26 | 27 | function A = Tz(a) 28 | A = [cosd(a) sind(a) 0;-sind(a) cosd(a) 0;0 0 1]; -------------------------------------------------------------------------------- /Matlab/example_MergeMeshes.m: -------------------------------------------------------------------------------- 1 | % MergeMeshes.m 2 | % merges two SU2 meshes 3 | % beware of large meshes!! 4 | % 5 | 6 | %% SETUP 7 | 8 | meshname1 = 'mesh_bipara_1.su2'; 9 | meshname2 = 'mesh_bipara_2.su2'; 10 | meshnameout = 'mesh_bipara_merged.su2'; 11 | 12 | 13 | %% READ 14 | 15 | mesh1 = ReadSU2(meshname1); 16 | mesh2 = ReadSU2(meshname2); 17 | 18 | figure(1); clf; hold on; 19 | plotMarkers(mesh1,{mesh1.mark(:).tag},'b-'); 20 | plotMarkers(mesh2,{mesh2.mark(:).tag},'r-'); 21 | 22 | 23 | %% MERGE 24 | 25 | meshout = MergeSU2(mesh1,mesh2); 26 | 27 | figure(2); clf; hold on; 28 | plotMarkers(meshout,'k-'); 29 | 30 | 31 | %% WRITE 32 | 33 | WriteSU2(meshout,'mesh_bipara_merged.su2'); 34 | 35 | 36 | %% DONE 37 | 38 | 39 | -------------------------------------------------------------------------------- /Matlab/getElemTypeInfo.m: -------------------------------------------------------------------------------- 1 | function [elem_leng,elem_type] = getElemTypeInfo(elem_type) 2 | % get vtk element type data 3 | % input - 4 | % elem_type = name or vtk type number 5 | % output - 6 | % elem_leng = number of nodes in element 7 | % elem_type = vtk type number 8 | 9 | 10 | if isnumeric(elem_type) 11 | switch elem_type 12 | case 3 13 | elem_leng = 2; 14 | case 5 15 | elem_leng = 3; 16 | case 9 17 | elem_leng = 4; 18 | case 10 19 | elem_leng = 4; 20 | case 12 21 | elem_leng = 8; 22 | case 13 23 | elem_leng = 6; 24 | case 14 25 | elem_leng = 5; 26 | end 27 | 28 | else 29 | switch elem_type 30 | case 'line' 31 | elem_type = 3; 32 | elem_leng = 2; 33 | case 'triangle' 34 | elem_type = 5; 35 | elem_leng = 3; 36 | case 'rectangle' 37 | elem_type = 9; 38 | elem_leng = 4; 39 | case 'tetrahedral' 40 | elem_type = 10; 41 | elem_leng = 4; 42 | case 'hexahedral' 43 | elem_type = 12; 44 | elem_leng = 8; 45 | case 'wedge' 46 | elem_type = 13; 47 | elem_leng = 6; 48 | case 'pyramid' 49 | elem_type = 14; 50 | elem_leng = 5; 51 | end 52 | end -------------------------------------------------------------------------------- /Matlab/plotElem.m: -------------------------------------------------------------------------------- 1 | function plotElem(poin,elem,plotstyle) 2 | % plotElem(poin,elem,plotstyle) 3 | % plots points of the element array 4 | % 5 | % poin: 3d point locations 6 | % elem: element connectivity 7 | % plotstyle: element plot style 8 | % i.e. 'b' plots a blue patch 9 | % 'b-' plots a blue line 10 | % 11 | 12 | %% SETUP 13 | 14 | % element type plot list 15 | etype_list = [3 5 9]; % line, triangle, rectangle 16 | 17 | 18 | %% ELEMENTS 19 | 20 | for elem_type = etype_list 21 | 22 | % find element rows of this type 23 | i_plotelem = elem(:,1) == elem_type; 24 | 25 | if any(i_plotelem) 26 | 27 | % pull how many points 28 | elem_leng = getElemTypeInfo(elem_type); 29 | elem_range = 2:(1+elem_leng); 30 | 31 | % pull plotable element array 32 | this_elem = elem(i_plotelem,elem_range); 33 | this_elem = this_elem + 1; 34 | 35 | % plot elements 36 | plotFace(this_elem,poin,plotstyle) 37 | 38 | end 39 | 40 | end 41 | 42 | 43 | %% DONE 44 | 45 | 46 | -------------------------------------------------------------------------------- /Matlab/plotFace.m: -------------------------------------------------------------------------------- 1 | function plotFace(varargin) 2 | % plotFace(FP,P,s) 3 | % plotFace(F,FP,P,s) 4 | % 5 | % P: 3d point coordinates 6 | % FP: face-to-point connectivity (aka elem) 7 | % F: face indeces to plot (within FP), optional 8 | % s: plot style 9 | % example: 'b' plots a blue patch 10 | % 'b-' plots a blue line 11 | % 12 | 13 | %% SETUP 14 | 15 | switch nargin 16 | case 3 17 | s = varargin{3}; 18 | P = varargin{2}; 19 | FP = varargin{1}; 20 | F = (1:size(FP,1))'; 21 | case 4 22 | s = varargin{4}; 23 | P = varargin{3}; 24 | FP = varargin{2}; 25 | F = varargin{1}; 26 | end 27 | 28 | [nF,nFP] = size(FP); 29 | 30 | 31 | %% COORDS 32 | 33 | X = zeros(nF,nFP+1); 34 | Y = zeros(nF,nFP+1); 35 | Z = zeros(nF,nFP+1); 36 | 37 | lFP = [1:nFP 1]; 38 | for iFP = 1:nFP+1; 39 | X(:,iFP) = P(FP(F,lFP(iFP)),1); 40 | Y(:,iFP) = P(FP(F,lFP(iFP)),2); 41 | Z(:,iFP) = P(FP(F,lFP(iFP)),3); 42 | end 43 | 44 | 45 | %% PLOT 46 | 47 | % plot style 48 | if length(s) == 1 49 | patch(X',Y',Z',s) 50 | else 51 | plot3(X',Y',Z',s,'LineWidth',1) 52 | end 53 | 54 | 55 | %% DONE 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Matlab/plotMarkers.m: -------------------------------------------------------------------------------- 1 | function plotMarkers(varargin) 2 | % plotMarkers(meshdata,plotstyle) 3 | % plotMarkers(meshdata,marklist,plotstyle) 4 | % 5 | % plots markers from the meshdata 6 | % 7 | % meshdata: mesh data struct 8 | % marklist: cell array of marker names, optional 9 | % plotstyle: element plot style 10 | % i.e.: 'b' plots a blue patch 11 | % 'b-' plots a blue line 12 | % 13 | 14 | %% SETUP 15 | 16 | switch nargin 17 | case 2 18 | meshdata = varargin{1}; 19 | marklist = {meshdata.mark(:).tag}; 20 | plotstyle = varargin{2}; 21 | case 3 22 | meshdata = varargin{1}; 23 | marklist = varargin{2}; 24 | plotstyle = varargin{3}; 25 | end 26 | 27 | % number of markers 28 | nmark = meshdata.nmark; 29 | 30 | % dimension 31 | dim = meshdata.dim; 32 | 33 | % point array 34 | poin = meshdata.poin(:,1:dim); 35 | if dim == 2 36 | poin(:,3) = 0; 37 | end 38 | 39 | 40 | %% MARKERS 41 | 42 | % plot nodes for each marker 43 | for imark = 1:nmark 44 | 45 | % pull marker tag 46 | this_tag = meshdata.mark(imark).tag; 47 | 48 | % check if this tag exists 49 | if any(strcmp(this_tag,marklist)) 50 | 51 | % pull elements and plot 52 | this_elem = meshdata.mark(imark).elem; 53 | plotElem(poin,this_elem,plotstyle); 54 | 55 | end 56 | 57 | end 58 | 59 | 60 | %% DONE 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Python/2DChannel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## \file 2DChannel.py 4 | # \brief Python script for creating grid for freesurface channels. 5 | # \author F. Palacios 6 | # \version 3.2.8 "eagle" 7 | # 8 | # SU2 Lead Developers: Dr. Francisco Palacios (fpalacios@stanford.edu). 9 | # Dr. Thomas D. Economon (economon@stanford.edu). 10 | # 11 | # SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. 12 | # Prof. Piero Colonna's group at Delft University of Technology. 13 | # Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. 14 | # Prof. Alberto Guardone's group at Polytechnic University of Milan. 15 | # Prof. Rafael Palacios' group at Imperial College London. 16 | # 17 | # Copyright (C) 2012-2015 SU2, the open-source CFD code. 18 | # 19 | # SU2 is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public 21 | # License as published by the Free Software Foundation; either 22 | # version 2.1 of the License, or (at your option) any later version. 23 | # 24 | # SU2 is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | # Lesser General Public License for more details. 28 | # 29 | # You should have received a copy of the GNU Lesser General Public 30 | # License along with SU2. If not, see . 31 | 32 | from optparse import OptionParser 33 | 34 | parser=OptionParser() 35 | parser.add_option("-f", "--file", dest="filename", default="Channel.su2", 36 | help="write mesh to FILE", metavar="FILE") 37 | parser.add_option("-n", "--nNode", dest="nNode", default=125, 38 | help="use this NNODE in x direction", metavar="NNODE") 39 | parser.add_option("-m", "--mNode", dest="mNode", default=100, 40 | help="use this MNODE in y direction", metavar="MNODE") 41 | parser.add_option("-x", "--xLength", dest="xLength", default=7.0, 42 | help="use this XLENGTH", metavar="XLENGTH") 43 | parser.add_option("--offsetx", dest="offsetx", default=1.0, 44 | help="use this OFFSETX", metavar="OFFSETX") 45 | parser.add_option("--xAdapt", dest="xAdapt", default="True", 46 | help="Adapt the grid XADAPT", metavar="XADAPT") 47 | parser.add_option("-y", "--yLength", dest="yLength", default=1.0, 48 | help="use this YLENGTH", metavar="YLENGTH") 49 | parser.add_option("--offsety", dest="offsety", default=0.5, 50 | help="use this OFFSETY", metavar="OFFSETY") 51 | parser.add_option("--yAdapt", dest="yAdapt", default="True", 52 | help="Adapt the grid YADAPT", metavar="YADAPT") 53 | (options, args)=parser.parse_args() 54 | 55 | nNode = int(options.nNode) 56 | mNode = int(options.mNode) 57 | xLength = float(options.xLength) 58 | yLength = float(options.yLength) 59 | xAdapt = options.xAdapt 60 | yAdapt = options.yAdapt 61 | 62 | Mesh_File = open(options.filename,"w") 63 | 64 | Mesh_File.write( "%\n" ) 65 | Mesh_File.write( "% Problem dimension\n" ) 66 | Mesh_File.write( "%\n" ) 67 | Mesh_File.write( "NDIME=2\n" ) 68 | Mesh_File.write( "%\n" ) 69 | Mesh_File.write( "% Inner elements\n" ) 70 | Mesh_File.write( "%\n" ) 71 | Mesh_File.write( "NELEM=%s\n" % ((nNode-1)*(mNode-1))) 72 | 73 | 74 | iElem = 0 75 | for jNode in range(mNode-1): 76 | for iNode in range(nNode-1): 77 | iPoint = jNode*nNode + iNode 78 | jPoint = jNode*nNode + iNode + 1 79 | kPoint = (jNode + 1)*nNode + iNode 80 | mPoint = (jNode + 1)*nNode + (iNode + 1) 81 | Mesh_File.write( "9 \t %s \t %s \t %s \t %s \t %s\n" % (iPoint, jPoint, mPoint, kPoint, iElem) ) 82 | iElem = iElem + 1 83 | 84 | nPoint = (nNode)*(mNode) 85 | Mesh_File.write( "%\n" ) 86 | Mesh_File.write( "NPOIN=%s\n" % ((nNode)*(mNode)) ) 87 | iPoint = 0 88 | 89 | for jNode in range(mNode): 90 | for iNode in range(nNode): 91 | xCoord = float(iNode)/float(nNode-1) 92 | yCoord = float(jNode)/float(mNode-1) 93 | 94 | if xAdapt == "True": 95 | 96 | x0 = 0.0; x1 = 0.12; x2 = 0.30; x3 = 1.0; 97 | fp3 = 10.0; fp0 = fp3; fpp2 = 0.0; fpp1 = -fpp2; 98 | if (xCoord >= x0) and (xCoord < x1): 99 | incr = x1-x0; incr2 = x1*x1-x0*x0; incr3 = x1*x1*x1-x0*x0*x0 100 | d = ((1.0 - fp0) - fpp1*incr)/ (3.0*incr2-6.0*x1*incr); c = (fpp1/2.0) -3.0*d*x1 101 | b = 1.0 - 2.0*c*x1 - 3.0*d*x1*x1; a = x1 - b*x1-c*x1*x1-d*x1*x1*x1 102 | x = a + b*xCoord + c*xCoord*xCoord + d*xCoord*xCoord*xCoord 103 | if (xCoord >= x1) and (xCoord <= x2): 104 | x = xCoord 105 | if (xCoord > x2) and (xCoord <= x3): 106 | incr = x2-x3; incr2 = x2*x2-x3*x3; incr3 = x2*x2*x2-x3*x3*x3 107 | d = ((1.0 - fp3) - fpp2*incr)/ (3.0*incr2-6.0*x2*incr); c = (fpp2/2.0) - 3.0*d*x2 108 | b = 1.0 - 2.0*c*x2 - 3.0*d*x2*x2; a = x2 - b*x2-c*x2*x2-d*x2*x2*x2 109 | x = a + b*xCoord + c*xCoord*xCoord + d*xCoord*xCoord*xCoord 110 | 111 | incr = x1-x0; incr2 = x1*x1-x0*x0; incr3 = x1*x1*x1-x0*x0*x0 112 | d = ((1.0 - fp0) - fpp1*incr)/ (3.0*incr2-6.0*x1*incr); c = (fpp1/2.0) -3.0*d*x1 113 | b = 1.0 - 2.0*c*x1 - 3.0*d*x1*x1; a = x1 - b*x1-c*x1*x1-d*x1*x1*x1 114 | x_min = a + b*x0 + c*x0*x0 + d*x0*x0*x0 115 | incr = x2-x3; incr2 = x2*x2-x3*x3; incr3 = x2*x2*x2-x3*x3*x3 116 | d = ((1.0 - fp3) - fpp2*incr)/ (3.0*incr2-6.0*x2*incr); c = (fpp2/2.0) - 3.0*d*x2 117 | b = 1.0 - 2.0*c*x2 - 3.0*d*x2*x2; a = x2 - b*x2-c*x2*x2-d*x2*x2*x2 118 | x_max = a + b*x3 + c*x3*x3 + d*x3*x3*x3 119 | 120 | xCoord_new = xLength*((x-x_min)/(x_max-x_min)) - float(options.offsetx) 121 | 122 | else: 123 | 124 | xCoord_new = xLength*xCoord - float(options.offsetx) 125 | 126 | if yAdapt == "True": 127 | 128 | y0 = 0.0; y1 = 0.000001; y2 = 0.001; y3 = 1.0; 129 | fp3 = 10.0; fp0 = fp3; fpp2 = 0.0; fpp1 = -fpp2; 130 | if (yCoord >= y0) and (yCoord < y1): 131 | incr = y1-y0; incr2 = y1*y1-y0*y0; incr3 = y1*y1*y1-y0*y0*y0 132 | d = ((1.0 - fp0) - fpp1*incr)/ (3.0*incr2-6.0*y1*incr); c = (fpp1/2.0) -3.0*d*y1 133 | b = 1.0 - 2.0*c*y1 - 3.0*d*y1*y1; a = y1 - b*y1-c*y1*y1-d*y1*y1*y1 134 | y = a + b*yCoord + c*yCoord*yCoord + d*yCoord*yCoord*yCoord 135 | if (yCoord >= y1) and (yCoord <= y2): 136 | y = yCoord 137 | if (yCoord > y2) and (yCoord <= y3): 138 | incr = y2-y3; incr2 = y2*y2-y3*y3; incr3 = y2*y2*y2-y3*y3*y3 139 | d = ((1.0 - fp3) - fpp2*incr)/ (3.0*incr2-6.0*y2*incr); c = (fpp2/2.0) - 3.0*d*y2 140 | b = 1.0 - 2.0*c*y2 - 3.0*d*y2*y2; a = y2 - b*y2-c*y2*y2-d*y2*y2*y2 141 | y = a + b*yCoord + c*yCoord*yCoord + d*yCoord*yCoord*yCoord 142 | 143 | incr = y1-y0; incr2 = y1*y1-y0*y0; incr3 = y1*y1*y1-y0*y0*y0 144 | d = ((1.0 - fp0) - fpp1*incr)/ (3.0*incr2-6.0*y1*incr); c = (fpp1/2.0) -3.0*d*y1 145 | b = 1.0 - 2.0*c*y1 - 3.0*d*y1*y1; a = y1 - b*y1-c*y1*y1-d*y1*y1*y1 146 | y_min = a + b*y0 + c*y0*y0 + d*y0*y0*y0 147 | 148 | incr = y2-y3; incr2 = y2*y2-y3*y3; incr3 = y2*y2*y2-y3*y3*y3 149 | d = ((1.0 - fp3) - fpp2*incr)/ (3.0*incr2-6.0*y2*incr); c = (fpp2/2.0) - 3.0*d*y2 150 | b = 1.0 - 2.0*c*y2 - 3.0*d*y2*y2; a = y2 - b*y2-c*y2*y2-d*y2*y2*y2 151 | y_max = a + b*y3 + c*y3*y3 + d*y3*y3*y3 152 | 153 | yCoord_new = yLength*((y-y_min)/(y_max-y_min)) - float(options.offsety) 154 | 155 | else: 156 | 157 | yCoord_new = yLength*yCoord - float(options.offsety) 158 | 159 | Mesh_File.write( "%15.14f \t %15.14f \t %s\n" % (xCoord_new, yCoord_new, iPoint) ) 160 | iPoint = iPoint + 1 161 | 162 | Mesh_File.write( "%\n" ) 163 | Mesh_File.write( "% Boundary elements\n" ) 164 | Mesh_File.write( "%\n" ) 165 | Mesh_File.write( "NMARK=4\n" ) 166 | Mesh_File.write( "MARKER_TAG= lower\n" ) 167 | Mesh_File.write( "MARKER_ELEMS=%s\n" % (nNode-1)) 168 | for iNode in range(nNode-1): 169 | Mesh_File.write( "3 \t %s \t %s\n" % (iNode, iNode + 1) ) 170 | 171 | Mesh_File.write( "MARKER_TAG= outlet\n" ) 172 | Mesh_File.write( "MARKER_ELEMS=%s\n" % (mNode-1)) 173 | for jNode in range(mNode-1): 174 | Mesh_File.write( "3 \t %s \t %s\n" % (jNode*nNode + (nNode - 1), (jNode + 1)*nNode + (nNode - 1) ) ) 175 | Mesh_File.write( "MARKER_TAG= upper\n" ) 176 | Mesh_File.write( "MARKER_ELEMS=%s\n" % (nNode-1)) 177 | for iNode in range(nNode-1): 178 | Mesh_File.write( "3 \t %s \t %s\n" % ((nNode*mNode - 1) - iNode, (nNode*mNode - 1) - (iNode + 1)) ) 179 | Mesh_File.write( "MARKER_TAG= inlet\n" ) 180 | Mesh_File.write( "MARKER_ELEMS=%s\n" % (mNode-1)) 181 | for jNode in range(mNode-2, -1, -1): 182 | Mesh_File.write( "3 \t %s \t %s\n" % ((jNode + 1)*nNode, jNode*nNode ) ) 183 | 184 | Mesh_File.close() 185 | -------------------------------------------------------------------------------- /Python/3DChannel.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## \file 3DChannel.py 4 | # \brief Python script for box meshing 5 | # \author F. Palacios 6 | # \version 3.2.8 "eagle" 7 | # 8 | # SU2 Lead Developers: Dr. Francisco Palacios (fpalacios@stanford.edu). 9 | # Dr. Thomas D. Economon (economon@stanford.edu). 10 | # 11 | # SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. 12 | # Prof. Piero Colonna's group at Delft University of Technology. 13 | # Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. 14 | # Prof. Alberto Guardone's group at Polytechnic University of Milan. 15 | # Prof. Rafael Palacios' group at Imperial College London. 16 | # 17 | # Copyright (C) 2012-2015 SU2, the open-source CFD code. 18 | # 19 | # SU2 is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public 21 | # License as published by the Free Software Foundation; either 22 | # version 2.1 of the License, or (at your option) any later version. 23 | # 24 | # SU2 is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | # Lesser General Public License for more details. 28 | # 29 | # You should have received a copy of the GNU Lesser General Public 30 | # License along with SU2. If not, see . 31 | 32 | from optparse import OptionParser 33 | 34 | parser=OptionParser() 35 | parser.add_option("-f", "--file", dest="filename", default="channel.su2", 36 | help="write mesh to FILE", metavar="FILE") 37 | parser.add_option("-n", "--nNode", dest="nNode", default=5, 38 | help="use this NNODE in x direction", metavar="NNODE") 39 | parser.add_option("-m", "--mNode", dest="mNode", default=5, 40 | help="use this MNODE in y direction", metavar="MNODE") 41 | parser.add_option("-l", "--lNode", dest="lNode", default=5, 42 | help="use this LNODE in z direction", metavar="LNODE") 43 | parser.add_option("-x", "--xLength", dest="xLength", default=1.0, 44 | help="use this XLENGTH", metavar="XLENGTH") 45 | parser.add_option("-y", "--yLength", dest="yLength", default=1.0, 46 | help="use this YLENGTH", metavar="YLENGTH") 47 | parser.add_option("-z", "--zLength", dest="zLength", default=1.0, 48 | help="use this ZLENGTH", metavar="ZLENGTH") 49 | (options, args)=parser.parse_args() 50 | 51 | KindElem = 12 52 | KindBound = 9 53 | nNode = int(options.nNode) 54 | mNode = int(options.mNode) 55 | lNode = int(options.lNode) 56 | xLength = float(options.xLength) 57 | yLength = float(options.yLength) 58 | zLength = float(options.zLength) 59 | 60 | Mesh_File = open(options.filename,"w") 61 | 62 | Mesh_File.write( "%\n" ) 63 | Mesh_File.write( "% Problem dimension\n" ) 64 | Mesh_File.write( "%\n" ) 65 | Mesh_File.write( "NDIME=3\n" ) 66 | Mesh_File.write( "%\n" ) 67 | Mesh_File.write( "% Inner elements\n" ) 68 | Mesh_File.write( "%\n" ) 69 | Mesh_File.write( "NELEM=%s\n" % ((lNode-1)*(nNode-1)*(mNode-1))) 70 | 71 | 72 | iElem = 0 73 | for kNode in range(lNode-1): 74 | for jNode in range(mNode-1): 75 | for iNode in range(nNode-1): 76 | Point0 = kNode*mNode*nNode + jNode*nNode + iNode 77 | Point1 = kNode*mNode*nNode + jNode*nNode + iNode + 1 78 | Point2 = kNode*mNode*nNode + (jNode+1)*nNode + (iNode+1) 79 | Point3 = kNode*mNode*nNode + (jNode+1)*nNode + iNode 80 | Point4 = (kNode+1)*mNode*nNode + jNode*nNode + iNode 81 | Point5 = (kNode+1)*mNode*nNode + jNode*nNode + iNode + 1 82 | Point6 = (kNode+1)*mNode*nNode + (jNode + 1)*nNode + (iNode + 1) 83 | Point7 = (kNode+1)*mNode*nNode + (jNode + 1)*nNode + iNode 84 | Mesh_File.write( "%s \t %s \t %s \t %s \t %s \t %s \t %s \t %s \t %s \t %s\n" % (KindElem, Point0, Point1, Point2, Point3, Point4, Point5, Point6, Point7, iElem) ) 85 | iElem = iElem + 1 86 | 87 | nPoint = (nNode)*(mNode)*(lNode) 88 | Mesh_File.write( "%\n" ) 89 | Mesh_File.write( "NPOIN=%s\n" % ((nNode)*(mNode)*(lNode))) 90 | iPoint = 0 91 | for kNode in range(lNode): 92 | for jNode in range(mNode): 93 | for iNode in range(nNode): 94 | Mesh_File.write( "%15.14f \t %15.14f \t %15.14f \t %s\n" % (xLength*float(iNode)/float(nNode-1), zLength*float(kNode)/float(lNode-1), yLength*float(jNode)/float(mNode-1), iPoint) ) 95 | iPoint = iPoint + 1 96 | 97 | Mesh_File.write( "%\n" ) 98 | Mesh_File.write( "% Boundary elements\n" ) 99 | Mesh_File.write( "%\n" ) 100 | Mesh_File.write( "NMARK=6\n" ) 101 | 102 | Mesh_File.write( "MARKER_TAG= left\n" ) 103 | elem = (nNode-1)*(mNode-1); 104 | Mesh_File.write( "MARKER_ELEMS=%s\n" % elem) 105 | for jNode in range(mNode-1): 106 | for iNode in range(nNode-1): 107 | Mesh_File.write( "%s \t %s \t %s \t %s \t %s\n" % (KindBound, jNode*nNode + iNode, jNode*nNode + (iNode+1), (jNode + 1)*nNode + (iNode + 1), (jNode + 1)*nNode + iNode) ) 108 | 109 | Mesh_File.write( "MARKER_TAG= right\n" ) 110 | elem = (nNode-1)*(mNode-1) 111 | Mesh_File.write( "MARKER_ELEMS=%s\n" % elem ) 112 | for jNode in range(mNode-1): 113 | for iNode in range(nNode-1): 114 | Mesh_File.write( "%s \t %s \t %s \t %s \t %s\n" % (KindBound, nNode*mNode*(lNode - 1) + jNode*nNode + iNode, nNode*mNode*(lNode - 1) + jNode*nNode + iNode + 1, nNode*mNode*(lNode - 1) + (jNode + 1)*nNode + (iNode + 1), nNode*mNode*(lNode - 1) + (jNode + 1)*nNode + iNode) ) 115 | 116 | Mesh_File.write( "MARKER_TAG= lower\n" ) 117 | elem = (nNode-1)*(lNode-1) 118 | Mesh_File.write( "MARKER_ELEMS=%s\n" % elem ) 119 | for iNode in range(nNode-1): 120 | for kNode in range(lNode-1): 121 | Mesh_File.write( "%s \t %s \t %s \t %s \t %s\n" % (KindBound, iNode + kNode*nNode*mNode, iNode + (kNode+1)*nNode*mNode, iNode + 1 + (kNode+1)*nNode*mNode, iNode + 1 + kNode*nNode*mNode) ) 122 | 123 | Mesh_File.write( "MARKER_TAG= upper\n" ) 124 | elem = (nNode-1)*(lNode-1) 125 | Mesh_File.write( "MARKER_ELEMS=%s\n" % elem ) 126 | for iNode in range(nNode-1): 127 | for kNode in range(lNode-1): 128 | Mesh_File.write( "%s \t %s \t %s \t %s \t %s\n" % (KindBound, (nNode*mNode - 1) - iNode + kNode*nNode*mNode, (nNode*mNode - 1) - iNode + (kNode+1)*nNode*mNode, (nNode*mNode - 1) - (iNode + 1) + (kNode+1)*nNode*mNode, (nNode*mNode - 1) - (iNode + 1) + kNode*nNode*mNode) ) 129 | 130 | Mesh_File.write( "MARKER_TAG= outlet\n" ) 131 | elem = (mNode-1)*(lNode-1) 132 | Mesh_File.write( "MARKER_ELEMS=%s\n" % elem ) 133 | for jNode in range(mNode-1): 134 | for kNode in range(lNode-1): 135 | Mesh_File.write( "%s \t %s \t %s \t %s \t %s\n" % (KindBound, jNode*nNode + (nNode - 1) + kNode*nNode*mNode, (jNode + 1)*nNode + (nNode - 1) + kNode*nNode*mNode, (jNode + 1)*nNode + (nNode - 1)+ (kNode+1)*nNode*mNode, jNode*nNode + (nNode - 1)+ (kNode+1)*nNode*mNode ) ) 136 | 137 | Mesh_File.write( "MARKER_TAG= inlet\n" ) 138 | elem = (mNode-1)*(lNode-1) 139 | Mesh_File.write( "MARKER_ELEMS=%s\n" % elem ) 140 | for jNode in range(mNode-2, -1, -1): 141 | for kNode in range(lNode-1): 142 | Mesh_File.write( "%s \t %s \t %s \t %s \t %s\n" % (KindBound, (jNode + 1)*nNode + kNode*nNode*mNode, jNode*nNode + kNode*nNode*mNode, jNode*nNode+ (kNode+1)*nNode*mNode, (jNode + 1)*nNode+ (kNode+1)*nNode*mNode ) ) 143 | 144 | Mesh_File.write( "FFD_NBOX=1\n") 145 | Mesh_File.write( "FFD_NLEVEL=1\n") 146 | Mesh_File.write( "FFD_TAG=0\n") 147 | Mesh_File.write( "FFD_LEVEL=0\n") 148 | Mesh_File.write( "FFD_DEGREE_I=6\n") 149 | Mesh_File.write( "FFD_DEGREE_J=6\n") 150 | Mesh_File.write( "FFD_DEGREE_K=1\n") 151 | Mesh_File.write( "FFD_PARENTS=0\n") 152 | Mesh_File.write( "FFD_CHILDREN=0\n") 153 | Mesh_File.write( "FFD_CORNER_POINTS=8\n") 154 | Mesh_File.write( "4.0 0 -0.1\n") 155 | Mesh_File.write( "6.0 0 -0.1\n") 156 | Mesh_File.write( "6.0 2.0 -0.1\n") 157 | Mesh_File.write( "4.0 2.0 -0.1\n") 158 | Mesh_File.write( "4.0 0 0.1\n") 159 | Mesh_File.write( "6.0 0 0.1\n") 160 | Mesh_File.write( "6.0 2.0 0.1\n") 161 | Mesh_File.write( "4.0 2.0 0.1\n") 162 | Mesh_File.write( "FFD_CONTROL_POINTS=0\n") 163 | Mesh_File.write( "FFD_SURFACE_POINTS=0\n") 164 | 165 | 166 | 167 | Mesh_File.close() 168 | -------------------------------------------------------------------------------- /Python/Expandp3d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## \file Expandp3d.py 4 | # \brief Python script for converting from plot3D to SU2 5 | # \author _________ 6 | # \version 3.2.8 "eagle" 7 | # 8 | # SU2 Lead Developers: Dr. Francisco Palacios (fpalacios@stanford.edu). 9 | # Dr. Thomas D. Economon (economon@stanford.edu). 10 | # 11 | # SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. 12 | # Prof. Piero Colonna's group at Delft University of Technology. 13 | # Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. 14 | # Prof. Alberto Guardone's group at Polytechnic University of Milan. 15 | # Prof. Rafael Palacios' group at Imperial College London. 16 | # 17 | # Copyright (C) 2012-2015 SU2, the open-source CFD code. 18 | # 19 | # SU2 is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public 21 | # License as published by the Free Software Foundation; either 22 | # version 2.1 of the License, or (at your option) any later version. 23 | # 24 | # SU2 is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | # Lesser General Public License for more details. 28 | # 29 | # You should have received a copy of the GNU Lesser General Public 30 | # License along with SU2. If not, see . 31 | 32 | from optparse import OptionParser 33 | import string 34 | 35 | parser=OptionParser() 36 | parser.add_option("-f", "--file", dest="filename", default="default.p3d", 37 | help="write mesh to FILE", metavar="FILE") 38 | (options, args)=parser.parse_args() 39 | 40 | # Read the input file 41 | p3d_File = open(options.filename,"r") 42 | 43 | # Read the body 44 | body = p3d_File.read().replace("\n"," ").replace("\t"," ").split() 45 | 46 | # Write the body 47 | filename = options.filename.rsplit( ".", 1 )[ 0 ] + ".Expp3d" 48 | 49 | 50 | Expp3d_File = open(filename,"w") 51 | 52 | for x in range(0, len(body)): 53 | 54 | if len(body[x].rsplit("*")) == 2: 55 | mult = int(body[x].rsplit("*")[0]) 56 | for y in range(0, mult): 57 | Expp3d_File.write("%s " % body[x].rsplit("*")[1]) 58 | 59 | else: 60 | Expp3d_File.write("%s " % body[x]) 61 | 62 | 63 | Expp3d_File.close() 64 | p3d_File.close() -------------------------------------------------------------------------------- /Python/p3d2su2_3D.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## \file p3d2su2_3D.py 4 | # \brief Python script for converting from plot3D to SU2 5 | # \author F. Palacios 6 | # \version 3.2.8 "eagle" 7 | # 8 | # SU2 Lead Developers: Dr. Francisco Palacios (fpalacios@stanford.edu). 9 | # Dr. Thomas D. Economon (economon@stanford.edu). 10 | # 11 | # SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. 12 | # Prof. Piero Colonna's group at Delft University of Technology. 13 | # Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. 14 | # Prof. Alberto Guardone's group at Polytechnic University of Milan. 15 | # Prof. Rafael Palacios' group at Imperial College London. 16 | # 17 | # Copyright (C) 2012-2015 SU2, the open-source CFD code. 18 | # 19 | # SU2 is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public 21 | # License as published by the Free Software Foundation; either 22 | # version 2.1 of the License, or (at your option) any later version. 23 | # 24 | # SU2 is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | # Lesser General Public License for more details. 28 | # 29 | # You should have received a copy of the GNU Lesser General Public 30 | # License along with SU2. If not, see . 31 | 32 | from optparse import OptionParser 33 | import string 34 | 35 | parser=OptionParser() 36 | parser.add_option("-f", "--file", dest="filename", default="default.p3d", 37 | help="write mesh to FILE", metavar="FILE") 38 | (options, args)=parser.parse_args() 39 | 40 | # Read the input file 41 | p3d_File = open(options.filename,"r") 42 | 43 | # Read the header 44 | header = p3d_File.readline().replace("\n"," ").replace("\t"," ").split() 45 | nNode = int(header[0].strip()) 46 | mNode = int(header[1].strip()) 47 | lNode = int(header[2].strip()) 48 | 49 | # Read the body 50 | body = p3d_File.read().replace("\n"," ").replace("\t"," ").split() 51 | 52 | p3d_File.close() 53 | 54 | # Write the .su2 file 55 | filename = options.filename.rsplit( ".", 1 )[ 0 ] + ".su2" 56 | su2_File = open(filename,"w") 57 | 58 | # Write the header 59 | su2_File.write( "NDIME=3\n" ) 60 | su2_File.write( "NELEM=%s\n" % ((lNode-1)*(nNode-1)*(mNode-1))) 61 | 62 | # Write the connectivity 63 | iElem = 0 64 | for kNode in range(lNode-1): 65 | for jNode in range(mNode-1): 66 | for iNode in range(nNode-1): 67 | Point0 = kNode*mNode*nNode + jNode*nNode + iNode 68 | Point1 = kNode*mNode*nNode + jNode*nNode + iNode + 1 69 | Point2 = kNode*mNode*nNode + (jNode+1)*nNode + (iNode+1) 70 | Point3 = kNode*mNode*nNode + (jNode+1)*nNode + iNode 71 | Point4 = (kNode+1)*mNode*nNode + jNode*nNode + iNode 72 | Point5 = (kNode+1)*mNode*nNode + jNode*nNode + iNode + 1 73 | Point6 = (kNode+1)*mNode*nNode + (jNode + 1)*nNode + (iNode + 1) 74 | Point7 = (kNode+1)*mNode*nNode + (jNode + 1)*nNode + iNode 75 | su2_File.write( "12 \t %s \t %s \t %s \t %s \t %s \t %s \t %s \t %s \t %s\n" % (Point0, Point1, Point2, Point3, Point4, Point5, Point6, Point7, iElem) ) 76 | iElem = iElem + 1 77 | 78 | # Write the coordinates 79 | nPoint = (nNode)*(mNode)*(lNode) 80 | su2_File.write( "NPOIN=%s\n" % ((nNode)*(mNode)*(lNode))) 81 | iPoint = 0 82 | for kNode in range(lNode): 83 | for jNode in range(mNode): 84 | for iNode in range(nNode): 85 | XCoord = body[kNode*(mNode*nNode) + jNode*nNode + iNode] 86 | YCoord = body[(nNode*mNode*lNode) + kNode*(mNode*nNode) + jNode*nNode + iNode] 87 | ZCoord = body[2*(nNode*mNode*lNode) + kNode*(mNode*nNode) + jNode*nNode + iNode] 88 | su2_File.write( "%s \t %s \t %s \t %s\n" % (XCoord, YCoord, ZCoord, iPoint) ) 89 | iPoint = iPoint + 1 90 | 91 | # Write the boundaries 92 | su2_File.write( "NMARK=6\n" ) 93 | 94 | su2_File.write( "MARKER_TAG= Xplane_0\n" ) 95 | elem = (mNode-1)*(lNode-1) 96 | su2_File.write( "MARKER_ELEMS=%s\n" % elem ) 97 | for jNode in range(mNode-1): 98 | for kNode in range(lNode-1): 99 | su2_File.write( "9 \t %s \t %s \t %s \t %s\n" % (jNode*nNode + (nNode - 1) + kNode*nNode*mNode, (jNode + 1)*nNode + (nNode - 1) + kNode*nNode*mNode, (jNode + 1)*nNode + (nNode - 1)+ (kNode+1)*nNode*mNode, jNode*nNode + (nNode - 1)+ (kNode+1)*nNode*mNode ) ) 100 | 101 | su2_File.write( "MARKER_TAG= Xplane_1\n" ) 102 | elem = (mNode-1)*(lNode-1) 103 | su2_File.write( "MARKER_ELEMS=%s\n" % elem ) 104 | for jNode in range(mNode-2, -1, -1): 105 | for kNode in range(lNode-1): 106 | su2_File.write( "9 \t %s \t %s \t %s \t %s\n" % ((jNode + 1)*nNode + kNode*nNode*mNode, jNode*nNode + kNode*nNode*mNode, jNode*nNode+ (kNode+1)*nNode*mNode, (jNode + 1)*nNode+ (kNode+1)*nNode*mNode ) ) 107 | 108 | su2_File.write( "MARKER_TAG= Yplane_0\n" ) 109 | elem = (nNode-1)*(lNode-1) 110 | su2_File.write( "MARKER_ELEMS=%s\n" % elem ) 111 | for iNode in range(nNode-1): 112 | for kNode in range(lNode-1): 113 | su2_File.write( "9 \t %s \t %s \t %s \t %s\n" % (iNode + kNode*nNode*mNode, iNode + (kNode+1)*nNode*mNode, iNode + 1 + (kNode+1)*nNode*mNode, iNode + 1 + kNode*nNode*mNode) ) 114 | 115 | su2_File.write( "MARKER_TAG= Yplane_1\n" ) 116 | elem = (nNode-1)*(lNode-1) 117 | su2_File.write( "MARKER_ELEMS=%s\n" % elem ) 118 | for iNode in range(nNode-1): 119 | for kNode in range(lNode-1): 120 | su2_File.write( "9 \t %s \t %s \t %s \t %s\n" % ((nNode*mNode - 1) - iNode + kNode*nNode*mNode, (nNode*mNode - 1) - iNode + (kNode+1)*nNode*mNode, (nNode*mNode - 1) - (iNode + 1) + (kNode+1)*nNode*mNode, (nNode*mNode - 1) - (iNode + 1) + kNode*nNode*mNode) ) 121 | 122 | su2_File.write( "MARKER_TAG= Zplane_0\n" ) 123 | elem = (nNode-1)*(mNode-1); 124 | su2_File.write( "MARKER_ELEMS=%s\n" % elem) 125 | for jNode in range(mNode-1): 126 | for iNode in range(nNode-1): 127 | su2_File.write( "9 \t %s \t %s \t %s \t %s\n" % (jNode*nNode + iNode, jNode*nNode + (iNode+1), (jNode + 1)*nNode + (iNode + 1), (jNode + 1)*nNode + iNode) ) 128 | 129 | su2_File.write( "MARKER_TAG= Zplane_1\n" ) 130 | elem = (nNode-1)*(mNode-1) 131 | su2_File.write( "MARKER_ELEMS=%s\n" % elem ) 132 | for jNode in range(mNode-1): 133 | for iNode in range(nNode-1): 134 | su2_File.write( "9 \t %s \t %s \t %s \t %s\n" % (nNode*mNode*(lNode - 1) + jNode*nNode + iNode, nNode*mNode*(lNode - 1) + jNode*nNode + iNode + 1, nNode*mNode*(lNode - 1) + (jNode + 1)*nNode + (iNode + 1), nNode*mNode*(lNode - 1) + (jNode + 1)*nNode + iNode) ) 135 | 136 | su2_File.close() -------------------------------------------------------------------------------- /Python/p3d2su2_CGrid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## \file p3d2su2_CGrid.py 4 | # \brief Python script for converting C-Grids from plot3D to SU2 5 | # \author F. Palacios 6 | # \version 3.2.8 "eagle" 7 | # 8 | # SU2 Lead Developers: Dr. Francisco Palacios (fpalacios@stanford.edu). 9 | # Dr. Thomas D. Economon (economon@stanford.edu). 10 | # 11 | # SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. 12 | # Prof. Piero Colonna's group at Delft University of Technology. 13 | # Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. 14 | # Prof. Alberto Guardone's group at Polytechnic University of Milan. 15 | # Prof. Rafael Palacios' group at Imperial College London. 16 | # 17 | # Copyright (C) 2012-2015 SU2, the open-source CFD code. 18 | # 19 | # SU2 is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public 21 | # License as published by the Free Software Foundation; either 22 | # version 2.1 of the License, or (at your option) any later version. 23 | # 24 | # SU2 is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | # Lesser General Public License for more details. 28 | # 29 | # You should have received a copy of the GNU Lesser General Public 30 | # License along with SU2. If not, see . 31 | 32 | from optparse import OptionParser 33 | import string 34 | 35 | parser=OptionParser() 36 | parser.add_option("-f", "--file", dest="filename", default="default.p2d", 37 | help="write mesh to FILE", metavar="FILE") 38 | (options, args)=parser.parse_args() 39 | 40 | # Read the input file 41 | p2d_File = open(options.filename,"r") 42 | 43 | # Read the header 44 | header = p2d_File.readline() 45 | header = p2d_File.readline().replace("\n"," ").replace("\t"," ").split() 46 | nNode = int(header[0].strip()) 47 | mNode = int(header[1].strip()) 48 | 49 | # Read the body 50 | body = p2d_File.read().replace("\n"," ").replace("\t"," ").split() 51 | 52 | p2d_File.close() 53 | 54 | # Write the .su2 file 55 | filename = options.filename.rsplit( ".", 1 )[ 0 ] + ".su2" 56 | su2_File = open(filename,"w") 57 | 58 | # Write the header 59 | su2_File.write( "NDIME=2\n" ) 60 | su2_File.write( "NELEM=%s\n" % ((mNode-1)*(nNode-1))) 61 | 62 | #Extra points to remove to adjust the conectivity 63 | points_airfoil = (mNode-1)*2 64 | points_remove = ((nNode+1)-points_airfoil)/2 65 | FirstPoint = points_remove + points_airfoil - 1 # minus 1 because C++ uses 0 66 | LastPoint = FirstPoint + points_remove - 1 67 | 68 | # Write the connectivity 69 | iElem = 0 70 | for jNode in range(mNode-1): 71 | for iNode in range(nNode-1): 72 | Point0 = jNode*nNode + iNode 73 | Point1 = jNode*nNode + iNode + 1 74 | Point2 = (jNode+1)*nNode + (iNode+1) 75 | Point3 = (jNode+1)*nNode + iNode 76 | 77 | if Point0 >= FirstPoint and Point0 <= LastPoint : 78 | Point0 = nNode - Point0 - 1 79 | if Point0 > LastPoint : 80 | Point0 = Point0 - points_remove 81 | 82 | 83 | if Point1 >= FirstPoint and Point1 <= LastPoint : 84 | Point1 = nNode - Point1 - 1 85 | if Point1 > LastPoint : 86 | Point1 = Point1 - points_remove 87 | 88 | Point2 = Point2 - points_remove 89 | 90 | Point3 = Point3 - points_remove 91 | 92 | su2_File.write( "9 \t %s \t %s \t %s \t %s \t %s\n" % (Point0, Point1, Point2, Point3, iElem) ) 93 | iElem = iElem + 1 94 | 95 | # Write the coordinates 96 | nPoint = (nNode)*(mNode) 97 | su2_File.write( "NPOIN=%s\n" % ((nNode)*(mNode) - points_remove)) 98 | iPoint = 0 99 | for jNode in range(mNode): 100 | for iNode in range(nNode): 101 | XCoord = body[jNode*nNode + iNode] 102 | YCoord = body[(nNode*mNode) + jNode*nNode + iNode] 103 | 104 | if iPoint < FirstPoint or iPoint > LastPoint : 105 | su2_File.write( "%s \t %s \t %s\n" % (XCoord, YCoord, iPoint) ) 106 | 107 | iPoint = iPoint + 1 108 | 109 | # Write the boundaries 110 | su2_File.write( "NMARK=2\n" ) 111 | 112 | su2_File.write( "MARKER_TAG= airfoil\n" ) 113 | points = (mNode-1)*2 114 | elems = points 115 | FirstPoint = ( (nNode+1)-points )/2 116 | su2_File.write( "MARKER_ELEMS=%s\n" % elems ) 117 | for iNode in range(points-1): 118 | su2_File.write( "3 \t %s \t %s\n" % (FirstPoint + iNode -1 , FirstPoint + iNode + 1 - 1) ) # minus 1 because C++ uses 0 119 | 120 | su2_File.write( "3 \t %s \t %s\n" % (FirstPoint + points -1 -1, FirstPoint -1 ) ) # minus 1 because C++ uses 0 121 | 122 | 123 | su2_File.write( "MARKER_TAG= farfield\n" ) 124 | TotalElem = (nNode-1) + (mNode-1) + (mNode-1) 125 | su2_File.write( "MARKER_ELEMS=%s\n" % TotalElem) 126 | 127 | points_airfoil = (mNode-1)*2 128 | elems = (nNode-1) 129 | FirstPoint = nNode*(points_airfoil/2) + 1 # minus 1 because C++ uses 0 130 | for iNode in range(elems): 131 | su2_File.write( "3 \t %s \t %s\n" % (FirstPoint + iNode - 1 - points_remove, FirstPoint + iNode + 1 - 1 - points_remove) ) 132 | 133 | elems = (mNode-1) 134 | for jNode in range(elems): 135 | if jNode == 0 : 136 | su2_File.write( "3 \t 0 \t %s\n" % ((jNode*nNode + 1) + nNode - 1 - points_remove) ) 137 | else : 138 | su2_File.write( "3 \t %s \t %s\n" % ((jNode*nNode + 1) - 1 - points_remove, (jNode*nNode + 1) + nNode - 1 - points_remove) ) 139 | 140 | elems = (mNode-1) 141 | for jNode in range(elems): 142 | if jNode == 0 : 143 | su2_File.write( "3 \t 0 \t %s\n" % ( (jNode + 1)*nNode + nNode - 1 - points_remove) ) 144 | else : 145 | su2_File.write( "3 \t %s \t %s\n" % (jNode*nNode + nNode - 1 - points_remove, (jNode + 1)*nNode + nNode - 1 - points_remove) ) 146 | 147 | 148 | su2_File.close() -------------------------------------------------------------------------------- /Python/p3d2su2_OGrid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ## \file p3d2su2_OGrid.py 4 | # \brief Python script for converting O-Grids from plot3D to SU2 5 | # \author F. Palacios 6 | # \version 3.2.8 "eagle" 7 | # 8 | # SU2 Lead Developers: Dr. Francisco Palacios (fpalacios@stanford.edu). 9 | # Dr. Thomas D. Economon (economon@stanford.edu). 10 | # 11 | # SU2 Developers: Prof. Juan J. Alonso's group at Stanford University. 12 | # Prof. Piero Colonna's group at Delft University of Technology. 13 | # Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. 14 | # Prof. Alberto Guardone's group at Polytechnic University of Milan. 15 | # Prof. Rafael Palacios' group at Imperial College London. 16 | # 17 | # Copyright (C) 2012-2015 SU2, the open-source CFD code. 18 | # 19 | # SU2 is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public 21 | # License as published by the Free Software Foundation; either 22 | # version 2.1 of the License, or (at your option) any later version. 23 | # 24 | # SU2 is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | # Lesser General Public License for more details. 28 | # 29 | # You should have received a copy of the GNU Lesser General Public 30 | # License along with SU2. If not, see . 31 | 32 | from optparse import OptionParser 33 | import string 34 | 35 | parser=OptionParser() 36 | parser.add_option("-f", "--file", dest="filename", default="default.p2d", 37 | help="write mesh to FILE", metavar="FILE") 38 | (options, args)=parser.parse_args() 39 | 40 | # Read the input file 41 | p2d_File = open(options.filename,"r") 42 | 43 | # Read the header 44 | header = p2d_File.readline() 45 | header = p2d_File.readline().replace("\n"," ").replace("\t"," ").split() 46 | nNode = int(header[0].strip()) 47 | mNode = int(header[1].strip()) 48 | 49 | # Read the body 50 | body = p2d_File.read().replace("\n"," ").replace("\t"," ").split() 51 | 52 | p2d_File.close() 53 | 54 | # Write the .su2 file 55 | filename = options.filename.rsplit( ".", 1 )[ 0 ] + ".su2" 56 | su2_File = open(filename,"w") 57 | 58 | # Write the header 59 | su2_File.write( "NDIME=2\n" ) 60 | su2_File.write( "NELEM=%s\n" % ((mNode-1)*(nNode-1))) 61 | 62 | # Write the connectivity 63 | iElem = 0 64 | for jNode in range(mNode-1): 65 | for iNode in range(nNode-1): 66 | 67 | Point0 = iNode + (jNode*(nNode-1)) 68 | Point1 = (iNode+1) + (jNode*(nNode-1)) 69 | Point2 = (iNode+1) + (jNode+1)*(nNode-1) 70 | Point3 = iNode + (jNode+1)*(nNode-1) 71 | 72 | if iNode == nNode-2: 73 | Point1 = jNode*(nNode-1) 74 | Point2 = (jNode+1)*(nNode-1) 75 | 76 | su2_File.write( "9 \t %s \t %s \t %s \t %s \t %s\n" % (Point0, Point1, Point2, Point3, iElem) ) 77 | iElem = iElem + 1 78 | 79 | # Write the coordinates 80 | nPoint = (nNode)*(mNode) 81 | su2_File.write( "NPOIN=%s\n" % ((nNode-1)*(mNode))) 82 | iPoint = 0 83 | for jNode in range(mNode): 84 | for iNode in range(nNode): 85 | XCoord = body[jNode*nNode + iNode] 86 | YCoord = body[(nNode*mNode) + jNode*nNode + iNode] 87 | 88 | if iNode != (nNode-1) : 89 | su2_File.write( "%s \t %s \t %s\n" % (XCoord, YCoord, iPoint) ) 90 | iPoint = iPoint + 1 91 | 92 | # Write the boundaries 93 | su2_File.write( "NMARK=2\n" ) 94 | 95 | su2_File.write( "MARKER_TAG= airfoil\n" ) 96 | points = (nNode-1) 97 | FirstPoint = 1 98 | su2_File.write( "MARKER_ELEMS=%s\n" % points ) 99 | for iNode in range(points-1): 100 | su2_File.write( "3 \t %s \t %s\n" % (FirstPoint + iNode -1 , FirstPoint + iNode + 1 - 1) ) # minus 1 because C++ uses 0 101 | su2_File.write( "3 \t %s \t %s\n" % (FirstPoint + points -1 -1, FirstPoint -1 ) ) # minus 1 because C++ uses 0 102 | 103 | 104 | su2_File.write( "MARKER_TAG= farfield\n" ) 105 | points = (nNode-1) 106 | elems = points 107 | FirstPoint = 1+(nNode-1)*(mNode-1) 108 | su2_File.write( "MARKER_ELEMS=%s\n" % points ) 109 | for iNode in range(points-1): 110 | su2_File.write( "3 \t %s \t %s\n" % (FirstPoint + iNode -1 , FirstPoint + iNode + 1 - 1) ) # minus 1 because C++ uses 0 111 | su2_File.write( "3 \t %s \t %s\n" % (FirstPoint + points -1 -1, FirstPoint -1 ) ) # minus 1 because C++ uses 0 112 | 113 | su2_File.close() -------------------------------------------------------------------------------- /SU2_PER/COMPILE: -------------------------------------------------------------------------------- 1 | gfortran -O3 -o SU2_PER su2_periodic.f90 2 | -------------------------------------------------------------------------------- /SU2_PER/README: -------------------------------------------------------------------------------- 1 | The SU2_PER is a fortran serial executable that generates periodic mesh for SU2. 2 | The code was developed by Antonio Ghidoni from the University of Brescia. 3 | 4 | TO COMPILE 5 | run the compiling script "./COMPILE" available in the folder. 6 | 7 | 8 | TO RUN 9 | run the program followed by a "<" sign and the SU2 config file "./SU2_PER < su2config.cfg". 10 | The SU2_PER program uses the same config options of the SU2_MSH binary. 11 | 12 | 13 | LIMITATIONS 14 | 15 | 1) It can only be run in serial 16 | 2) To avoid that the program occupies too much memory SU2_PER is limited to mesh containing 17 | less than 1E+05 periodic nodes and less than 8E+06 nodes in total. However, 18 | if bigger meshes must be converted, this limit can be adjusted by modifying line 35 of 19 | the su2_periodic.f90 file. 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SU2_PER/su2_periodic.f90: -------------------------------------------------------------------------------- 1 | program su2_periodic 2 | 3 | !-----------------------------------------------------------------------------! 4 | ! Algorith to create periodic data structure (SU2 format) ! 5 | !-----------------------------------------------------------------------------! 6 | ! Author: Prof. Antonio Ghidoni ! 7 | ! email: antonio.ghidoni@unibs.it ! 8 | ! University of Brescia, Department of Mechanical and Industrial Engineering ! 9 | !-----------------------------------------------------------------------------! 10 | 11 | implicit none 12 | 13 | character(30) :: rmesh, wmesh 14 | integer(4), allocatable :: ne(:), np(:), nmark(:), nb(:,:) 15 | integer(4), allocatable :: neg(:), npg(:), nmarkg(:), nbg(:,:) 16 | integer(4) :: nf, nd, nperio, id2np(15) 17 | 18 | ! Grid arrays 19 | real(8), allocatable :: xp(:,:,:) 20 | real(8), allocatable :: xpg(:,:,:) 21 | integer(4), allocatable :: s2p(:,:,:), topo(:,:), b2p(:,:,:,:), npp2(:), & 22 | bp2bp(:,:,:), bperio(:,:), npp1(:), p2p(:,:), p3p4(:,:) 23 | character(20), allocatable :: cbc(:,:) 24 | 25 | ! Temporary grid arrays 26 | integer(4), allocatable :: s2ptmp(:,:,:), b2ptmp(:,:,:,:), po2pn(:) 27 | real(8), allocatable :: xptmp(:,:,:) 28 | 29 | ! Periodic bcs 30 | character(20) :: perio(2,20) 31 | integer(4) :: dperio(20) 32 | real(8) :: lperio(9,20), ax_perio(3,20), lnper(20) 33 | logical :: axial 34 | 35 | integer(4), parameter :: mtb = 20, mb = 100000, me = 8000000, mp = 8000000, & 36 | md = 3 37 | 38 | real(8), parameter :: tol0 = 1.e-8 39 | 40 | real(8) :: scaling 41 | 42 | id2np = 0 43 | ! 2D 44 | id2np(3) = 2 45 | id2np(5) = 3 46 | id2np(9) = 4 47 | ! 3D 48 | id2np(10) = 4 49 | id2np(12) = 8 50 | id2np(13) = 6 51 | id2np(14) = 5 52 | 53 | write(*,*) 54 | write(*,*)'====================================================' 55 | write(*,*)'READING cfg file' 56 | write(*,*) 57 | call read_cfg 58 | write(*,*)'====================================================' 59 | 60 | write(*,*) 61 | write(*,*)'====================================================' 62 | write(*,*)'READING mesh file: ',rmesh 63 | write(*,*) 64 | call read_mesh 65 | call write_tec 66 | write(*,*)'====================================================' 67 | 68 | write(*,*) 69 | write(*,*)'====================================================' 70 | write(*,*)'BUILD periodic data structure' 71 | write(*,*) 72 | call build_perio 73 | write(*,*)'====================================================' 74 | 75 | write(*,*) 76 | write(*,*)'====================================================' 77 | write(*,*)'WRITING mesh file: ',wmesh 78 | call write_mesh 79 | call write_tec_perio 80 | write(*,*)'====================================================' 81 | 82 | contains 83 | 84 | subroutine read_cfg 85 | 86 | character(200) :: str200 87 | integer(4) :: i, l, idf, m(12), mm 88 | logical :: rmsh, wmsh 89 | 90 | 91 | scaling = 1.0 92 | nperio = 0 93 | rmsh = .false. 94 | wmsh = .false. 95 | do l = 1, 10000 96 | do i = 1, 200 97 | str200(i:i) = ' ' 98 | enddo 99 | 100 | read (*,'(a200)',end=9) str200 101 | 102 | if ( str200(1:16) == 'MARKER_PERIODIC=' ) then 103 | nperio = nperio +1 104 | mm = 0 105 | m = 0 106 | do i = 1, 200 107 | if ( str200(i:i) == '(' ) then 108 | mm = mm +1 109 | m(mm) = i+1 110 | elseif ( str200(i:i) == ',' ) then 111 | mm = mm +1 112 | m(mm) = i-1 113 | elseif ( str200(i:i) == ')' ) then 114 | mm = mm +1 115 | m(mm) = i-1 116 | endif 117 | enddo 118 | read (str200(m(1):m(2)),*)perio(1,nperio) 119 | read (str200(m(2)+2:m(3)),*) perio(2,nperio) 120 | read (str200(m(3)+2:m(4)),*)lperio(1,nperio) 121 | read (str200(m(4)+2:m(5)),*)lperio(2,nperio) 122 | read (str200(m(5)+2:m(6)),*)lperio(3,nperio) 123 | read (str200(m(6)+2:m(7)),*)lperio(4,nperio) 124 | read (str200(m(7)+2:m(8)),*)lperio(5,nperio) 125 | read (str200(m(8)+2:m(9)),*)lperio(6,nperio) 126 | read (str200(m(9)+2:m(10)),*)lperio(7,nperio) 127 | read (str200(m(10)+2:m(11)),*)lperio(8,nperio) 128 | read (str200(m(11)+2:m(12)),*)lperio(9,nperio) 129 | 130 | write(*,*)'Periodic condition:',nperio 131 | write(*,'(3a25)')'FLAG=',perio(1,nperio), perio(2,nperio) 132 | write(*,*)'Rotation_center_(x,y,z)' 133 | write(*,'(3f15.8)')lperio(1:3,nperio) 134 | write(*,*)'Rotation_angle_(x,y,z)-axis' 135 | write(*,'(3f15.8)')lperio(4:6,nperio) 136 | write(*,*)'Translation_(x,y,z)' 137 | write(*,'(3f15.8)')lperio(7:9,nperio) 138 | elseif ( str200(1:14) == 'MESH_FILENAME=' ) then 139 | read (str200(15:34),*)rmesh 140 | rmsh = .true. 141 | elseif ( str200(1:18) == 'MESH_OUT_FILENAME=' ) then 142 | read (str200(19:38),*)wmesh 143 | wmsh = .true. 144 | elseif ( str200(1:16) == 'MSH_PERIO_SCALE=' ) then 145 | read (str200(17:38),*)scaling 146 | wmsh = .true. 147 | endif 148 | enddo 149 | 150 | 9 continue 151 | 152 | if ( .not. rmsh ) then 153 | write(*,*)'ERROR! INPUT mesh file not specified!' 154 | stop 155 | endif 156 | if ( .not. wmsh ) then 157 | write(*,*)'WARNING! OUTPUT mesh file not specified!' 158 | write(*,*)'Default name will be used: mesh_out.su2' 159 | wmesh = 'mesh_out.su2' 160 | stop 161 | endif 162 | 163 | if ( lperio(4,1) == 0. .and. lperio(5,1) == 0. .and. lperio(6,1) == 0. ) then 164 | axial = .true. 165 | else 166 | axial = .false. 167 | endif 168 | 169 | do i = 1, nperio 170 | if ( lperio(4,i) /= 0. ) then 171 | dperio(i) = 1 172 | lnper(i) = lperio(4,i)*acos(-1.0)/180. 173 | ax_perio(1,i) = 1. 174 | ax_perio(2,i) = 0. 175 | ax_perio(3,i) = 0. 176 | elseif ( lperio(5,i) /= 0. ) then 177 | dperio(i) = 2 178 | lnper(i) = lperio(5,i)*acos(-1.0)/180. 179 | ax_perio(1,i) = 0. 180 | ax_perio(2,i) = 1. 181 | ax_perio(3,i) = 0. 182 | elseif ( lperio(6,i) /= 0. ) then 183 | dperio(i) = 3 184 | lnper(i) = lperio(6,i)*acos(-1.0)/180. 185 | ax_perio(1,i) = 0. 186 | ax_perio(2,i) = 0. 187 | ax_perio(3,i) = 1. 188 | endif 189 | enddo 190 | 191 | end subroutine read_cfg 192 | 193 | subroutine read_mesh 194 | 195 | integer(4) :: iunit, i, j, k, io, last, m, npri, npyr, ntet, nhex, ntri, nqua 196 | character(6) :: c6, control 197 | character(200) :: str200 198 | real(8) :: ct(3,4) 199 | 200 | 201 | iunit = 15 202 | open(unit=iunit,file=rmesh,form="formatted") 203 | 204 | ! nf: number of zones 205 | control = 'NZONE=' 206 | call tstlin2(iunit,control,io) 207 | if ( io == 0 ) then 208 | read(iunit,'(a6,i5)') c6, nf 209 | else 210 | nf = 1 211 | endif 212 | 213 | 214 | allocate (ne(nf), np(nf), nmark(nf)) 215 | 216 | allocate (xp(md,mp,nf)) 217 | allocate (p2p(mp,nf)) 218 | allocate (p3p4(mp,nf)) 219 | allocate (s2p(8,me,nf)) 220 | allocate (topo(me,nf)) 221 | 222 | allocate (nb(mtb,nf)) 223 | allocate (b2p(5,mb,mtb,nf)) 224 | allocate (cbc(mtb,nf)) 225 | 226 | allocate (xptmp(md,mp,nf)) 227 | allocate (s2ptmp(8,me,nf)) 228 | allocate (b2ptmp(5,mb,mtb,nf)) 229 | allocate ( po2pn(mp) ) 230 | 231 | do i = 1, nf 232 | 233 | rewind(iunit) 234 | control = 'NDIME=' 235 | call tstlin2(iunit,control,io) 236 | if ( io == 0 ) then 237 | read(iunit,'(a6,i5)') c6, nd 238 | else 239 | write(*,*)'Error! Cannot read mesh dimension' 240 | stop 241 | endif 242 | 243 | ! ne(:): number of elements for each zone 244 | rewind(iunit) 245 | control = 'NELEM=' 246 | call tstlin2(iunit,control,io) 247 | if ( io == 0 ) then 248 | read(iunit,'(a6,i15)') c6, ne(i) 249 | else 250 | write(*,*)'Error! Cannot read mesh elements' 251 | stop 252 | endif 253 | 254 | ! topo(:,:): element ID 255 | ! s2p(:,:,:): connectivity of each element 256 | do j = 1, ne(i) 257 | read(iunit,*)topo(j,i), s2ptmp(1:id2np(topo(j,i)),j,i) 258 | enddo 259 | 260 | ! np(:): number of points for each zone 261 | rewind(iunit) 262 | control = 'NPOIN=' 263 | call tstlin2(iunit,control,io) 264 | if ( io == 0 ) then 265 | read(iunit,'(a6,i15)') c6, np(i) 266 | else 267 | write(*,*)'Error! Cannot read points coordinates' 268 | stop 269 | endif 270 | 271 | ! xp(:,:,:): points coordinates for each zone 272 | do j = 1, np(i) 273 | read(iunit,*)xptmp(1:nd,j,i) 274 | enddo 275 | p2p(:,i) = -1 276 | p3p4(:,i) = -1 277 | 278 | rewind(iunit) 279 | control = 'NMARK=' 280 | call tstlin2(iunit,control,io) 281 | 282 | ! nmark(:): number of bcs for each zone 283 | if ( io == 0 ) then 284 | read(iunit,'(a6,i15)') c6, nmark(i) 285 | else 286 | write(*,*)'Error! Cannot read number of bcs' 287 | stop 288 | endif 289 | 290 | ! cbc(:,:): ID of the bcs for each zone 291 | ! nb(:,:): number of boundary elements for each bcs 292 | ! b2p(:,:,:,:): connectivity of every boundary element for each bcs 293 | do j = 1, nmark(i) 294 | read (iunit,'(a200)') str200 295 | read (str200(12:31),*)cbc(j,i) 296 | read (iunit,'(a200)') str200 297 | read (str200(14:28),*)nb(j,i) 298 | do k = 1, nb(j,i) 299 | read(iunit,*)b2ptmp(1,k,j,i), b2ptmp(2:id2np(b2ptmp(1,k,j,i))+1,k,j,i) 300 | enddo 301 | enddo 302 | enddo 303 | 304 | close(iunit) 305 | 306 | ! Change numbering 307 | 308 | do i = 1, nf 309 | 310 | po2pn = -1 311 | 312 | do j = 1, nmark(i) 313 | if ( cbc(j,i) == perio(1,i) ) then 314 | last = np(i)-1 315 | do k = 1, nb(j,i) 316 | do m = 2, id2np(b2ptmp(1,k,j,i))+1 317 | if ( po2pn(b2ptmp(m,k,j,i)+1) == -1 ) then 318 | po2pn(b2ptmp(m,k,j,i)+1) = last 319 | last = last -1 320 | endif 321 | enddo 322 | enddo 323 | endif 324 | enddo 325 | 326 | last = 0 327 | do j = 1, ne(i) 328 | do k = 1, id2np(topo(j,i)) 329 | if ( po2pn(s2ptmp(k,j,i)+1) == -1 ) then 330 | po2pn(s2ptmp(k,j,i)+1) = last 331 | last = last +1 332 | endif 333 | enddo 334 | enddo 335 | 336 | do j = 1, ne(i) 337 | do k = 1, id2np(topo(j,i)) 338 | s2p(k,j,i) = po2pn(s2ptmp(k,j,i)+1) 339 | xp(:,s2p(k,j,i)+1,i) = xptmp(:,s2ptmp(k,j,i)+1,i) 340 | enddo 341 | enddo 342 | 343 | do j = 1, nmark(i) 344 | do k = 1, nb(j,i) 345 | b2p(1,k,j,i) = b2ptmp(1,k,j,i) 346 | do m = 2, id2np(b2ptmp(1,k,j,i))+1 347 | b2p(m,k,j,i) = po2pn(b2ptmp(m,k,j,i)+1) 348 | enddo 349 | enddo 350 | enddo 351 | 352 | npri = 0 353 | ntet = 0 354 | nhex = 0 355 | npyr = 0 356 | ntri = 0 357 | nqua = 0 358 | do j = 1, ne(i) 359 | if ( topo(j,i) == 5 ) ntri = ntri +1 360 | if ( topo(j,i) == 9 ) nqua = nqua +1 361 | if ( topo(j,i) == 10 ) ntet = ntet +1 362 | if ( topo(j,i) == 12 ) nhex = nhex +1 363 | if ( topo(j,i) == 13 ) npri = npri +1 364 | if ( topo(j,i) == 14 ) npyr = npyr +1 365 | enddo 366 | 367 | 368 | write(*,*)'Domain=',i 369 | if ( nd == 2 ) then 370 | write(*,'(a12,i15)')'Triangles=', ntri 371 | write(*,'(a12,i15)')'Quads=', nqua 372 | else 373 | write(*,'(a12,i15)')'Tetrahedra=', ntet 374 | write(*,'(a12,i15)')'Prysm=', npri 375 | write(*,'(a12,i15)')'Pyramid=', npyr 376 | write(*,'(a12,i15)')'Hexahedra=', nhex 377 | endif 378 | write(*,*) 379 | write(*,*)'Boundary conditions' 380 | do j = 1, nmark(i) 381 | write(*,*)cbc(j,i),'=',nb(j,i) 382 | enddo 383 | enddo 384 | 385 | 386 | end subroutine read_mesh 387 | 388 | subroutine build_perio 389 | 390 | integer(4) :: i, j, k, ii, iii, e1, e2, m, n, kkk, w, npri, ntet, nhex, npyr, ntri, nqua 391 | integer(4) :: jj, jjj, kk, coun 392 | logical :: found, exist 393 | real(8) :: xa(3), xb(3), r1, r2, dx(3), da, db, dc, alp1, alp2, & 394 | delta, delteta, oo(3), xap(3), tol 395 | 396 | 397 | allocate( bperio(2,nf) ) 398 | bperio = 0 399 | 400 | ! bperio(:,:): numbering of two periodic bc for every zone 401 | do j = 1, nf 402 | do k = 1, nmark(j) 403 | if ( cbc(k,j) == perio(1,j) ) then 404 | bperio(1,j) = k 405 | elseif ( cbc(k,j) == perio(2,j) ) then 406 | bperio(2,j) = k 407 | endif 408 | enddo 409 | enddo 410 | 411 | allocate( bp2bp(4,mb+1,nf) ) 412 | allocate( npp1(nf) ) 413 | 414 | bp2bp = 0 415 | npp1 = 0 416 | 417 | ! bp2bp(1,:,:): list of points associated to side e1 418 | ! npp1(:): number of periodic points on the edge e1 419 | do j = 1, nf 420 | e1 = bperio(1,j) 421 | 422 | do i = 1, nb(e1,j) 423 | do k = 2, id2np(b2p(1,i,e1,j))+1 424 | found = .false. 425 | do ii = 1, npp1(j) 426 | if ( bp2bp(1,ii,j) == b2p(k,i,e1,j) ) then 427 | found = .true. 428 | exit 429 | endif 430 | enddo 431 | if ( .not. found ) then 432 | npp1(j) = npp1(j) +1 433 | bp2bp(1,npp1(j),j) = b2p(k,i,e1,j) 434 | endif 435 | enddo 436 | enddo 437 | 438 | ! do i = 1, npp1(j) 439 | ! write(555,*)xp(1:nd,bp2bp(1,i,j)+1,j) 440 | ! enddo 441 | enddo 442 | 443 | ! bp2bp(2,:,:): list of points associated to side e2 444 | ! p2p(:,:): for each periodic point of e1, the number of the corresponding point 445 | ! on e2 is given 446 | 447 | xa = 0. 448 | xb = 0. 449 | 450 | 451 | do j = 1, nf 452 | 453 | tol = tol0 454 | 455 | m = 0 456 | n = 0 457 | do kkk = 1, 3 458 | if ( dperio(j) == kkk ) cycle 459 | if ( m == 0 ) then 460 | m = kkk 461 | else 462 | n = kkk 463 | endif 464 | enddo 465 | 466 | e1 = bperio(1,j) 467 | e2 = bperio(2,j) 468 | 469 | do i = 1, npp1(j) 470 | xa(1:nd) = xp(:,bp2bp(1,i,j)+1,j) 471 | 472 | if ( axial ) then 473 | xap = xa +lperio(7:9,j) 474 | else 475 | oo = lperio(1:nd,j) 476 | oo(dperio(j)) = xa(dperio(j)) 477 | dx = xa -oo 478 | r1 = sqrt(dx(1)**2 +dx(2)**2 +dx(3)**2) 479 | alp1 = atan2(dx(n),dx(m)) 480 | 481 | xap(1:nd) = xa 482 | xap(m) = lperio(m,j) +r1*cos(alp1 +lnper(j)) 483 | xap(n) = lperio(n,j) +r1*sin(alp1 +lnper(j)) 484 | endif 485 | 486 | 100 found = .false. 487 | do k = 1, nb(e2,j) 488 | do ii = 2, id2np(b2p(1,k,e2,j))+1 489 | xb(1:nd) = xp(:,b2p(ii,k,e2,j)+1,j) 490 | 491 | da = sqrt((xap(1)-xb(1))**2+(xap(2)-xb(2))**2+(xap(3)-xb(3))**2) 492 | 493 | if ( da < tol ) then 494 | write(*,*)i, da 495 | bp2bp(2,i,j) = b2p(ii,k,e2,j) 496 | p2p(bp2bp(1,i,j)+1,j) = bp2bp(2,i,j) 497 | found = .true. 498 | exit 499 | endif 500 | enddo 501 | if ( found ) exit 502 | enddo 503 | if ( .not. found .and. tol <= 1.e-3) then 504 | tol = tol*10. 505 | goto 100 506 | elseif ( .not. found) then 507 | write(*,*)'ERROR! Cannot find periodic point' 508 | stop 509 | endif 510 | enddo 511 | ! do i = 1, npp1(j) 512 | ! write(777,*)xp(1:nd,bp2bp(2,i,j)+1,j) 513 | ! enddo 514 | enddo 515 | 516 | allocate ( neg(nf), npg(nf), nmarkg(nf), nbg(mtb,nf) ) 517 | allocate( npp2(nf) ) 518 | allocate (xpg(md,mp,nf)) 519 | 520 | npp2 = 0 521 | 522 | xpg = 0.0 523 | do i = 1, nf 524 | do j = 1, np(i) 525 | xpg(:,j,i) = xp(:,j,i) 526 | enddo 527 | enddo 528 | 529 | ! nmarkg(:): number of bcs for each zone with halos 530 | do i = 1, nf 531 | nmarkg(i) = nmark(i) +2 532 | enddo 533 | 534 | do i = 1, nf 535 | do j = nmark(i)+1, nmarkg(i) 536 | cbc(j,i)="SEND_RECEIVE" 537 | enddo 538 | enddo 539 | 540 | ! neg(:): number of elements for each zone (with halos) 541 | ! npg(:): number of points for each zone (with halos) 542 | ! bp2bp(3,:,:): list of points (inside domain) for the elements sharing the side e1 543 | ! bp2bp(4,:,:): list of points for the elements sharing the side e1 544 | do i = 1, nf 545 | neg(i) = ne(i) 546 | npg(i) = np(i) 547 | do j = 1, ne(i) 548 | found = .false. 549 | do ii = 1, id2np(topo(j,i)) 550 | if ( p2p(s2p(ii,j,i)+1,i) >= 0 ) then 551 | neg(i) = neg(i) +1 552 | topo(neg(i),i) = topo(j,i) 553 | found = .true. 554 | exit 555 | endif 556 | enddo 557 | if ( found ) then 558 | do ii = 1, id2np(topo(j,i)) 559 | if ( p2p(s2p(ii,j,i)+1,i) >= 0 ) then 560 | s2p(ii,neg(i),i) = p2p(s2p(ii,j,i)+1,i) 561 | else 562 | exist = .false. 563 | do iii = 1, npp2(i) 564 | if ( bp2bp(3,iii,i) == s2p(ii,j,i) ) then 565 | exist = .true. 566 | exit 567 | endif 568 | enddo 569 | if ( .not. exist ) then 570 | npp2(i) = npp2(i) +1 571 | npg(i) = npg(i) +1 572 | s2p(ii,neg(i),i) = npg(i) -1 573 | bp2bp(3,npp2(i),i) = s2p(ii,j,i) 574 | bp2bp(4,npp2(i),i) = s2p(ii,neg(i),i) 575 | if ( axial ) then 576 | xpg(1:nd,npg(i),i) = xp(1:nd,s2p(ii,j,i)+1,i) +lperio(7:7+nd-1,i) 577 | else 578 | m = 0 579 | n = 0 580 | do kkk = 1, 3 581 | if ( dperio(i) == kkk ) cycle 582 | if ( m == 0 ) then 583 | m = kkk 584 | else 585 | n = kkk 586 | endif 587 | enddo 588 | 589 | oo = lperio(1:nd,i) 590 | oo(dperio(i)) = xp(dperio(i),s2p(ii,j,i)+1,i) 591 | dx = xp(1:nd,s2p(ii,j,i)+1,i) -oo 592 | r1 = sqrt(dx(1)**2 +dx(2)**2 +dx(3)**2) 593 | alp1 = atan2(dx(n),dx(m)) 594 | 595 | xpg(1:nd,npg(i),i) = xp(1:nd,s2p(ii,j,i)+1,i) 596 | xpg(m,npg(i),i) = lperio(m,i) +r1*cos(alp1 +lnper(i)) 597 | xpg(n,npg(i),i) = lperio(n,i) +r1*sin(alp1 +lnper(i)) 598 | endif 599 | else 600 | s2p(ii,neg(i),i) = bp2bp(4,iii,i) 601 | endif 602 | endif 603 | enddo 604 | endif 605 | enddo 606 | npri = 0 607 | ntet = 0 608 | nhex = 0 609 | npyr = 0 610 | ntri = 0 611 | nqua = 0 612 | do j = 1, neg(i) 613 | if ( topo(j,i) == 5 ) ntri = ntri +1 614 | if ( topo(j,i) == 9 ) nqua = nqua +1 615 | if ( topo(j,i) == 10 ) ntet = ntet +1 616 | if ( topo(j,i) == 12 ) nhex = nhex +1 617 | if ( topo(j,i) == 13 ) npri = npri +1 618 | if ( topo(j,i) == 14 ) npyr = npyr +1 619 | enddo 620 | 621 | 622 | write(*,*)'Domain=',i 623 | if ( nd == 2 ) then 624 | write(*,'(a12,i15)')'Triangles=', ntri 625 | write(*,'(a12,i15)')'Quads=', nqua 626 | else 627 | write(*,'(a12,i15)')'Tetrahedra=', ntet 628 | write(*,'(a12,i15)')'Prysm=', npri 629 | write(*,'(a12,i15)')'Pyramid=', npyr 630 | write(*,'(a12,i15)')'Hexahedra=', nhex 631 | endif 632 | enddo 633 | 634 | do i = 1, nf 635 | do j = 1, npp2(i) 636 | p3p4(bp2bp(3,j,i)+1,i) = bp2bp(4,j,i) 637 | ! write(888,*)xpg(1:nd,bp2bp(3,j,i)+1,i) 638 | ! write(999,*)xpg(1:nd,bp2bp(4,j,i)+1,i) 639 | enddo 640 | enddo 641 | 642 | nbg = nb 643 | do i = 1, nf 644 | do j = 1, nmark(i) 645 | if ( j == bperio(1,i) .or. j == bperio(2,i) ) cycle 646 | ! 647 | !Bisogna verififcare quali boundary intersecano il periodico 648 | ! do w = 1, nwall 649 | ! if ( cbc(j,i) == cwall(w,i) ) goto 100 650 | ! enddo 651 | 652 | do k = 1, nb(j,i) 653 | iii = 0 654 | jjj = 0 655 | do ii = 2, id2np(b2p(1,k,j,i))+1 656 | if ( p2p(b2p(ii,k,j,i)+1,i) >= 0 ) jjj = jjj +1 657 | if ( p3p4(b2p(ii,k,j,i)+1,i) >= 0 ) iii = iii +1 658 | enddo 659 | if ( (iii+jjj) == id2np(b2p(1,k,j,i)) .and. jjj > 0) then 660 | nbg(j,i) = nbg(j,i) +1 661 | do ii = 2, id2np(b2p(1,k,j,i))+1 662 | if ( p2p(b2p(ii,k,j,i)+1,i) >= 0 ) then 663 | b2p(ii,nbg(j,i),j,i) = p2p(b2p(ii,k,j,i)+1,i) 664 | elseif ( p3p4(b2p(ii,k,j,i)+1,i) >= 0 ) then 665 | b2p(ii,nbg(j,i),j,i) = p3p4(b2p(ii,k,j,i)+1,i) 666 | endif 667 | enddo 668 | b2p(1,nbg(j,i),j,i) = b2p(1,k,j,i) 669 | endif 670 | enddo 671 | ! 100 continue 672 | enddo 673 | write(*,*) 674 | write(*,*)'Boundary conditions' 675 | do j = 1, nmark(i) 676 | write(*,*)cbc(j,i),'=',nbg(j,i) 677 | enddo 678 | 679 | 680 | !!!! do j = 1, nmark(i) 681 | !!!! do jj = 1, nbg(j,i) 682 | !!!! do k = 1, neg(i) 683 | !!!! coun = 0 684 | !!!! found = .false. 685 | !!!! do jjj = 2, id2np(b2p(1,jj,j,i))+1 686 | !!!! do kk = 1, id2np(topo(k,i)) 687 | !!!! if ( b2p(jjj,jj,j,i) == s2p(kk,k,i) ) coun = coun +1 688 | !!!! enddo 689 | !!!! if ( coun == id2np(b2p(1,jj,j,i)) ) then 690 | !!!! found = .true. 691 | !!!! exit 692 | !!!! endif 693 | !!!! enddo 694 | !!!! if ( found ) exit 695 | !!!! enddo 696 | !!!! if ( .not. found ) then 697 | !!!! write(*,*)'ERROR! Face without corresponding element' 698 | !!!! write(*,*)b2p(1:id2np(b2p(1,jj,j,i))+1,jj,j,i) 699 | !!!! write(*,*)xpg(1:nd,b2p(2,jj,j,i),i) 700 | !!!! write(*,*)xpg(1:nd,b2p(3,jj,j,i),i) 701 | !!!! write(*,*)xpg(1:nd,b2p(4,jj,j,i),i) 702 | !!!! stop 703 | !!!! endif 704 | !!!! enddo 705 | !!!! enddo 706 | enddo 707 | 708 | end subroutine build_perio 709 | 710 | subroutine write_tec 711 | 712 | integer(4) :: i, j, idf 713 | 714 | 715 | idf = 10 716 | open(unit=idf,file='periodic_original.dat') 717 | 718 | if ( nd == 2 ) then 719 | do i = 1, nf 720 | write (idf,*) 'VARIABLES = "X", "Y"' 721 | write (idf,*) 'ZONE N=',np(i),', E=',ne(i),', F=FEPOINT, ET=QUADRILATERAL' 722 | do j = 1, np(i) 723 | write (idf,'(2f20.10)') xp(1:nd,j,i) 724 | enddo 725 | write(idf,*) 726 | do j = 1, ne(i) 727 | if ( topo(j,i) == 5 ) then 728 | write (idf,'(4i15)') s2p(1:3,j,i)+1, s2p(1,j,i)+1 729 | else 730 | write (idf,'(4i15)') s2p(1:4,j,i)+1 731 | endif 732 | enddo 733 | enddo 734 | else 735 | do i = 1, nf 736 | write (idf,*) 'VARIABLES = "X", "Y", "Z"' 737 | write (idf,*) 'ZONE N=',np(i),', E=',ne(i),', & 738 | F=FEPOINT, ET=BRICK' 739 | do j = 1, np(i) 740 | write (idf,'(2f20.10)') xp(:,j,i) 741 | enddo 742 | write(idf,*) 743 | do j = 1, ne(i) 744 | if ( topo(j,i) == 10 ) then 745 | ! TET 746 | write (idf,'(8i10)') s2p(1:3,j,i)+1, s2p(3,j,i)+1, s2p(4,j,i)+1, s2p(4,j,i)+1, s2p(4,j,i)+1, s2p(4,j,i)+1 747 | elseif ( topo(j,i) == 12 ) then 748 | ! HEX 749 | write (idf,'(8i10)') s2p(1:8,j,i)+1 750 | elseif ( topo(j,i) == 13 ) then 751 | ! PRISM 752 | write (idf,'(8i10)') s2p(1:3,j,i)+1, s2p(3,j,i)+1, s2p(4:6,j,i)+1, s2p(6,j,i)+1 753 | elseif ( topo(j,i) == 14 ) then 754 | ! PYRAMID 755 | write (idf,'(8i10)') s2p(1:4,j,i)+1, s2p(5,j,i)+1, s2p(5,j,i)+1, s2p(5,j,i)+1, s2p(5,j,i)+1 756 | endif 757 | enddo 758 | enddo 759 | endif 760 | 761 | close(idf) 762 | 763 | end subroutine write_tec 764 | 765 | subroutine write_tec_perio 766 | 767 | integer(4) :: i, j, idf 768 | 769 | 770 | idf = 10 771 | open(unit=idf,file='periodic_halo.dat') 772 | 773 | if ( nd == 2 ) then 774 | do i = 1, nf 775 | write (idf,*) 'VARIABLES = "X", "Y"' 776 | write (idf,*) 'ZONE N=',npg(i),', E=',neg(i),', F=FEPOINT, ET=QUADRILATERAL' 777 | do j = 1, npg(i) 778 | write (idf,'(2f20.10)') xpg(1:nd,j,i) 779 | enddo 780 | write(idf,*) 781 | do j = 1, neg(i) 782 | if ( topo(j,i) == 5 ) then 783 | write (idf,'(4i15)') s2p(1:3,j,i)+1, s2p(1,j,i)+1 784 | else 785 | write (idf,'(4i15)') s2p(1:4,j,i)+1 786 | endif 787 | enddo 788 | enddo 789 | else 790 | do i = 1, nf 791 | write (idf,*) 'VARIABLES = "X", "Y", "Z"' 792 | write (idf,*) 'ZONE NODES=',npg(i),', ELEMENTS=',neg(i),', & 793 | DATAPACKING=POINT, ZONETYPE=FEBRICK' 794 | do j = 1, npg(i) 795 | write (idf,'(3f20.10)') xpg(:,j,i) 796 | enddo 797 | write(idf,*) 798 | do j = 1, neg(i) 799 | if ( topo(j,i) == 10 ) then 800 | ! TET 801 | write (idf,'(8i15)') s2p(1:3,j,i)+1, s2p(3,j,i)+1, s2p(4,j,i)+1, s2p(4,j,i)+1, s2p(4,j,i)+1, s2p(4,j,i)+1 802 | elseif ( topo(j,i) == 12 ) then 803 | ! HEX 804 | write (idf,'(8i15)') s2p(1:8,j,i)+1 805 | elseif ( topo(j,i) == 13 ) then 806 | ! PRISM 807 | write (idf,'(8i15)') s2p(1:2,j,i)+1, s2p(2,j,i)+1,s2p(3,j,i)+1, s2p(4:5,j,i)+1, s2p(5,j,i)+1,s2p(6,j,i)+1 808 | elseif ( topo(j,i) == 14 ) then 809 | ! PYRAMID 810 | write (idf,'(8i15)') s2p(1:4,j,i)+1, s2p(5,j,i)+1, s2p(5,j,i)+1, s2p(5,j,i)+1, s2p(5,j,i)+1 811 | endif 812 | enddo 813 | enddo 814 | endif 815 | 816 | close(idf) 817 | 818 | end subroutine write_tec_perio 819 | 820 | subroutine write_mesh 821 | 822 | integer(4) :: idf, if, i, j, ip, iel 823 | character(2) :: sz 824 | 825 | write(*,*)'Scaling=',scaling 826 | idf = 25 827 | open(unit=idf,file=wmesh,form="formatted") 828 | 829 | write(idf,'(a6,i3)') 'NZONE=', nf 830 | 831 | do if = 1, nf 832 | 833 | write(idf,*) 834 | write(idf,'(a6,i3)') 'IZONE=', if 835 | 836 | write(idf,*) '%' 837 | write(idf,*) '% Problem dimension' 838 | write(idf,*) '%' 839 | write(idf,'(a6,i3)') 'NDIME=', nd 840 | 841 | write(idf,*) '%' 842 | write(idf,*) '% Inner element connectivity' 843 | write(idf,*) '%' 844 | 845 | write(idf,'(a6,i10)') 'NELEM=', neg(if) 846 | 847 | ! Write the interior element connectivity... 848 | 849 | iel = 0 850 | do i = 1, neg(if) 851 | sz = int2ch2( id2np(topo(i,if)) ) 852 | write (idf,'(1i3,'//sz//'i10,i10)') topo(i,if), ( s2p(j,i,if), j=1,id2np(topo(i,if)) ), iel 853 | iel = iel +1 854 | enddo 855 | 856 | write(idf,*) '%' 857 | write(idf,*) '% Node coordinates' 858 | write(idf,*) '%' 859 | write(idf,'(a6,2i10)') 'NPOIN=', npg(if), npg(if)-npp1(if)-npp2(if) 860 | 861 | do ip = 1, npg(if) 862 | sz = int2ch2( nd ) 863 | write (idf,'('//sz//'f25.15,i10)') scaling*xpg(1:nd,ip,if), ip-1 864 | enddo 865 | 866 | write(idf,'(a6,i3)') 'NMARK=', nmarkg(if) 867 | 868 | do j = 1, nmark(if) 869 | write(idf,'(a11,a10)') 'MARKER_TAG=', cbc(j,if) 870 | write(idf,'(a13,i10)') 'MARKER_ELEMS=', nbg(j,if) 871 | do i = 1, nbg(j,if) 872 | sz = int2ch2( id2np(b2p(1,i,j,if))) 873 | write(idf,'(1i3,'//sz//'i10)') b2p(1,i,j,if), b2p(2:id2np(b2p(1,i,j,if))+1,i,j,if) 874 | enddo 875 | enddo 876 | 877 | j = nmark(if)+1 878 | write(idf,'(a11,a20)') 'MARKER_TAG=', cbc(j,if) 879 | write(idf,'(a13,i10)') 'MARKER_ELEMS=', npp1(if) +npp2(if) 880 | write(idf,'(a10)') 'SEND_TO= 1' 881 | do i = 1, npp1(if) 882 | write(idf,*)1, bp2bp(2,i,if), 1 883 | enddo 884 | do i = 1, npp2(if) 885 | write(idf,*)1, bp2bp(3,i,if), 2 886 | enddo 887 | 888 | j = nmarkg(if) 889 | write(idf,'(a11,a20)') 'MARKER_TAG=', cbc(j,if) 890 | write(idf,'(a13,i10)') 'MARKER_ELEMS=', npp1(if) +npp2(if) 891 | write(idf,'(a10)') 'SEND_TO=-1' 892 | do i = 1, npp1(if) 893 | write(idf,*)1, bp2bp(1,i,if), 1 894 | enddo 895 | do i = 1, npp2(if) 896 | write(idf,*)1, bp2bp(4,i,if), 2 897 | enddo 898 | 899 | write(idf,'(a12)') 'NPERIODIC= 3' 900 | write(idf,'(a15,i4)') 'PERIODIC_INDEX=',0 901 | write(idf,'(3f15.9)') lperio(1:3,if) 902 | write(idf,'(3f15.9)') lperio(1:3,if) 903 | write(idf,'(3f15.9)') lperio(1:3,if) 904 | write(idf,'(a15,i4)') 'PERIODIC_INDEX=',1 905 | write(idf,'(3f15.9)') lperio(1:3,if) 906 | write(idf,'(3f15.9)') lperio(4:6,if)*acos(-1.0)/180. 907 | write(idf,'(3f15.9)') scaling*lperio(7:9,if) 908 | write(idf,'(a15,i4)') 'PERIODIC_INDEX=',2 909 | write(idf,'(3f15.9)')-lperio(1:3,if) 910 | write(idf,'(3f15.9)')-lperio(4:6,if)*acos(-1.0)/180. 911 | write(idf,'(3f15.9)')-scaling*lperio(7:9,if) 912 | 913 | enddo 914 | 915 | close(idf) 916 | 917 | end subroutine write_mesh 918 | 919 | subroutine tstlin2 ( iunit, string, io ) 920 | 921 | integer(4) :: iunit, io 922 | character(6) :: string 923 | 924 | character(80) :: text 925 | 926 | 2002 read(iunit,'(A80)',IOSTAT=io)text 927 | 928 | if ( io == 0 ) then 929 | if ( text(1:6) /= string ) goto 2002 930 | 931 | backspace (iunit) 932 | endif 933 | 934 | end subroutine tstlin2 935 | 936 | function int2ch2 ( n ) result ( c2 ) 937 | 938 | integer(4), intent(in) :: n 939 | character(2) :: c2 940 | 941 | integer(4) :: m, n0, n1 942 | 943 | 944 | m = n 945 | n1 = m/10 946 | n0 = m -10*n1 947 | 948 | m = ichar('0') 949 | c2 = char(m+n1)//char(m+n0) 950 | 951 | end function int2ch2 952 | 953 | function voltet( ct ) result ( vol ) 954 | 955 | ! tetrahedron volume 956 | 957 | real(8) :: ct(3,4), v(3,4), vol 958 | 959 | integer(4) :: j, i 960 | 961 | 962 | do j=2,4 963 | do i=1,3 964 | v(i,j) = ct(i,j) - ct(i,1) 965 | enddo 966 | enddo 967 | 968 | vol = v(1,4)*(v(2,2)*v(3,3)-v(3,2)*v(2,3))+ & 969 | v(2,4)*(v(3,2)*v(1,3)-v(1,2)*v(3,3))+ & 970 | v(3,4)*(v(1,2)*v(2,3)-v(2,2)*v(1,3)) 971 | vol =(1./6.)*vol 972 | 973 | end function voltet 974 | 975 | end program su2_periodic 976 | --------------------------------------------------------------------------------