00001 #!/usr/bin/awk -We 00002 00003 # ======= 00004 # msh2inp 00005 # ======= 00006 # 00007 # :Version: 1.03 00008 # :Date: 2009-04-14 00009 # :Purpose: Convert gmsh msh files to UCD/inp format. 00010 # :Language: awk, tested with gawk, mawk, nawk. 00011 # :Author: Stefan Tibus 00012 # :Copyright: (C) 2009 Stefan Tibus 00013 # :License: GNU General Public License 00014 # 00015 # Changelog 00016 # ========= 00017 # 00018 # :2009-04-07 v1.00: First version. 00019 # :2009-04-07 v1.01: Renumber used cells and nodes by default, may be 00020 # disabled. *mawk* compatibility broken due to use of 00021 # ``asorti``. 00022 # :ToDo: Sort order is alphabetical, thus not only 00023 # the numbering, but actual order is changed, 00024 # even when writing out all elements. 00025 # :2009-04-07 v1.02: Creating the mapping in the scanning loops makes 00026 # ``asorti`` unnecessary, results in numerical order 00027 # and is compatible with *mawk* again. 00028 # :2009-04-14 v1.03: Added usage information. 00029 # 00030 # 00031 # Background Information 00032 # ====================== 00033 # 00034 # INP (UCD) file format: 00035 # 00036 # - http://people.sc.fsu.edu/~burkardt/html/ucd_format.html 00037 # 00038 # gmsh msh file format: 00039 # 00040 # - http://www.geuz.org/gmsh/doc/texinfo/gmsh_10.html#SEC55 00041 # - http://www.geuz.org/gmsh/doc/texinfo/gmsh-full.html#SEC55 00042 00043 function print_usage() { 00044 print "" 00045 print "msh2inp v1.03" 00046 print "© Stefan Tibus" 00047 print "" 00048 print "Convert gmsh msh files to UCD/inp format." 00049 print "" 00050 print "Usage:" 00051 print "msh2inp [options] <file> [<file> [...]]" 00052 print "cat <file> | msh2inp [options]" 00053 print "" 00054 print "Options:" 00055 print "--help Show usage information." 00056 print "--debug Provide some informational output on /dev/stderr." 00057 print "--renumber Renumber nodes and elements in output (default)." 00058 print "--norenumber Keep numbering as in input files." 00059 print "" 00060 print "Output filtering options:" 00061 print "(none) Output all element types as in input files." 00062 print "--pt Points." 00063 print "--line Lines." 00064 print "--tri Triangles." 00065 print "--quad Quadrangles." 00066 print "--tet Tetrahedra." 00067 print "--hex Hexahedra." 00068 print "--prism Prisms." 00069 print "--pyr Pyramids." 00070 print "" 00071 print "Note: gmsh saves physical mesh elements only by default. Remember to assign\n physical element numbers to all required element types." 00072 print "" 00073 } 00074 00075 BEGIN { 00076 # Simple option handling. 00077 inp_filter_output = 0 00078 DEBUG = 0 00079 inp_renumber = 1 00080 for (i = 1; i < ARGC; i++) { 00081 if (ARGV[i] == "--renumber") { 00082 inp_renumber = 1 00083 } else 00084 if (ARGV[i] == "--norenumber") { 00085 inp_renumber = 0 00086 } else 00087 if (ARGV[i] == "--debug") { 00088 DEBUG = 1 00089 } else 00090 if (ARGV[i] == "--line") { 00091 inp_filter_output = 1 00092 inp_output[1] = 1 00093 } else 00094 if (ARGV[i] == "--tri") { 00095 inp_filter_output = 1 00096 inp_output[2] = 1 00097 } else 00098 if (ARGV[i] == "--quad") { 00099 inp_filter_output = 1 00100 inp_output[3] = 1 00101 } else 00102 if (ARGV[i] == "--tet") { 00103 inp_filter_output = 1 00104 inp_output[4] = 1 00105 } else 00106 if (ARGV[i] == "--hex") { 00107 inp_filter_output = 1 00108 inp_output[5] = 1 00109 } else 00110 if (ARGV[i] == "--prism") { 00111 inp_filter_output = 1 00112 inp_output[6] = 1 00113 } else 00114 if (ARGV[i] == "--pyr") { 00115 inp_filter_output = 1 00116 inp_output[7] = 1 00117 } else 00118 if (ARGV[i] == "--pt") { 00119 inp_filter_output = 1 00120 inp_output[15] = 1 00121 } else 00122 if (ARGV[i] == "--help") { 00123 print_usage() 00124 error = -127 00125 exit error 00126 } else 00127 if (ARGV[i] ~ /^--./) { 00128 print "Unknown option \"" ARGV[i] "\"." > "/dev/stderr" 00129 print_usage() 00130 error = 1 00131 exit error 00132 } else 00133 # Stop option handling on first non-option. 00134 break 00135 # Delete handled option from argument list. 00136 delete ARGV[i] 00137 } 00138 00139 msh_read_part = 0 00140 00141 msh_part_meshformat = 1 00142 msh_part_nodes = 2 00143 msh_part_elements = 3 00144 msh_part_physicalnames = 4 00145 # msh_part_nodedata = 5 00146 # msh_part_elementdata = 6 00147 # msh_part_elementnodedata = 7 00148 msh_part_unknown = -1 00149 00150 # Element type conversions (first order elements only). 00151 msh_elementtype_inp[1] = "line" 00152 msh_elementtype_nodes[1] = 2 00153 msh_elementtype_inp[2] = "tri" 00154 msh_elementtype_nodes[2] = 3 00155 msh_elementtype_inp[3] = "quad" 00156 msh_elementtype_nodes[3] = 4 00157 msh_elementtype_inp[4] = "tet" 00158 msh_elementtype_nodes[4] = 4 00159 msh_elementtype_inp[5] = "hex" 00160 msh_elementtype_nodes[5] = 8 00161 msh_elementtype_inp[6] = "prism" 00162 msh_elementtype_nodes[6] = 6 00163 msh_elementtype_inp[7] = "pyr" 00164 msh_elementtype_nodes[7] = 5 00165 msh_elementtype_inp[15] = "pt" 00166 msh_elementtype_nodes[15] = 1 00167 # Node order seems to be equivalent. (gmsh, GiD, VTK) 00168 # Unsure about msh_PRISM = VTK_WEDGE. 00169 msh_elementtype_str[1] = "lines" 00170 msh_elementtype_str[2] = "triangles" 00171 msh_elementtype_str[3] = "quadrangles" 00172 msh_elementtype_str[4] = "tetrahedra" 00173 msh_elementtype_str[5] = "hexahedra" 00174 msh_elementtype_str[6] = "prisms" 00175 msh_elementtype_str[7] = "pyramids" 00176 msh_elementtype_str[15] = "points" 00177 } 00178 00179 (FNR == 1) { 00180 # Handle multiple files. 00181 if (NR > 1) { 00182 # New file, output current data. 00183 check_msh_finished() 00184 if (inp_filter_output) print_inp_filtered() 00185 else print_inp() 00186 } 00187 00188 # Reset. 00189 msh_count_meshformat = 0 00190 msh_version = 0 00191 msh_type = 0 00192 msh_datasize = 0 00193 msh_count_nodes = 0 00194 delete nodes 00195 delete nodeX 00196 delete nodeY 00197 delete nodeZ 00198 msh_count_elements = 0 00199 delete elements 00200 delete elementType 00201 msh_count_type[1] = 0 00202 msh_count_type[2] = 0 00203 msh_count_type[3] = 0 00204 msh_count_type[4] = 0 00205 msh_count_type[5] = 0 00206 msh_count_type[6] = 0 00207 msh_count_type[7] = 0 00208 msh_count_type[15] = 0 00209 delete elementNodes 00210 delete msh_node_usedtype 00211 delete elementTags 00212 delete elementPhysical 00213 delete elementGeometry 00214 delete elementPartition 00215 delete elementNode 00216 msh_count_physicalnames = 0 00217 delete physicalnames 00218 delete physicalnameName 00219 msh_part_NR = 0 00220 00221 # Filename handling. 00222 if (FILENAME == "-") { 00223 inpfile = "/dev/stdout" 00224 } else { 00225 inpfile = FILENAME 00226 if (inpfile ~ /\.msh$/) { 00227 sub(/\.msh$/, ".inp", inpfile) 00228 } else { 00229 inpfile = inpfile ".inp" 00230 } 00231 if (FILENAME == inpfile) { 00232 print "Filename " FILENAME " could not be handled." > "/dev/stderr" 00233 error = 1 00234 exit error 00235 } 00236 } 00237 if (DEBUG) { 00238 print "Reading from \"" FILENAME "\", output to \"" inpfile "\"." > "/dev/stderr" 00239 } 00240 } 00241 00242 # Detect whicht part of the file we are about to read. 00243 (msh_read_part == 0) { 00244 if ($0 == "$MeshFormat") { 00245 msh_read_part = msh_part_meshformat 00246 } else 00247 if ($0 == "$Nodes") { 00248 msh_read_part = msh_part_nodes 00249 } else 00250 if ($0 == "$Elements") { 00251 msh_read_part = msh_part_elements 00252 } else 00253 if ($0 == "$PhysicalNames") { 00254 msh_read_part = msh_part_physicalnames 00255 } else 00256 # if ($0 == "$NodeData") { 00257 # msh_read_part = msh_part_nodedata 00258 # } else 00259 # if ($0 == "$ElementData") { 00260 # msh_read_part = msh_part_elementdata 00261 # } else 00262 # if ($0 == "$ElementNodeData") { 00263 # msh_read_part = msh_part_elementnodedata 00264 # } else 00265 if ($0 ~ /^\$/) { 00266 msh_read_part = msh_part_unknown 00267 } 00268 00269 msh_part_end = $0 00270 sub(/^\$/, "$End", msh_part_end) 00271 00272 msh_part_NR = 0 00273 next 00274 } 00275 00276 # Read header. 00277 # version-number file-type data-size 00278 (msh_read_part == msh_part_meshformat) { 00279 if ($0 == msh_part_end) { 00280 msh_read_part = 0 00281 next 00282 } 00283 if (msh_count_meshformat == 0) { 00284 msh_version = $1 00285 msh_type = $2 00286 msh_datasize = $3 00287 msh_count_meshformat++ 00288 if (msh_version != 2) { 00289 print "Unknown file version on line " FNR "." > "/dev/stderr" 00290 error = 2 00291 exit error 00292 } 00293 if (msh_type != 0) { 00294 print "Unknown file type on line " FNR "." > "/dev/stderr" 00295 error = 3 00296 exit error 00297 } 00298 } else { 00299 print "Multiple format specifications found on line " FNR "." > "/dev/stderr" 00300 error = 4 00301 exit error 00302 } 00303 next 00304 } 00305 00306 # Read nodes. 00307 # number-of-nodes 00308 # node-number x-coord y-coord z-coord 00309 # ... 00310 (msh_read_part == msh_part_nodes) { 00311 if ($0 == msh_part_end) { 00312 if (msh_nodes_to_read > 0) { 00313 print "Node missing on line " FNR "." > "/dev/stderr" 00314 error = 5 00315 exit error 00316 } 00317 msh_read_part = 0 00318 next 00319 } 00320 msh_part_NR++ 00321 if (msh_part_NR == 1) { 00322 msh_nodes_to_read = $1 00323 if (DEBUG) { 00324 print "Reading " msh_nodes_to_read " nodes." > "/dev/stderr" 00325 } 00326 next 00327 } 00328 if (msh_nodes_to_read < 1) { 00329 print msh_part_end " missing in \"" FILENAME "\" on line " FNR "." > "/dev/stderr" 00330 error = 6 00331 exit error 00332 } 00333 msh_count_nodes++ 00334 nodes[msh_count_nodes] = $1 00335 nodeX[$1] = $2 00336 nodeY[$1] = $3 00337 nodeZ[$1] = $4 00338 msh_nodes_to_read-- 00339 next 00340 } 00341 00342 # Read elements. 00343 # number-of-elements 00344 # elm-number elm-type number-of-tags < tag > ... node-number-list 00345 # ... 00346 (msh_read_part == msh_part_elements) { 00347 if ($0 == msh_part_end) { 00348 if (msh_elements_to_read > 0) { 00349 print "Element missing on line " FNR "." > "/dev/stderr" 00350 error = 7 00351 exit error 00352 } 00353 msh_read_part = 0 00354 next 00355 } 00356 msh_part_NR++ 00357 if (msh_part_NR == 1) { 00358 msh_elements_to_read = $1 00359 if (DEBUG) { 00360 print "Reading " msh_elements_to_read " elements." > "/dev/stderr" 00361 } 00362 next 00363 } 00364 if (msh_elements_to_read < 1) { 00365 print msh_part_end " missing on line " FNR "." > "/dev/stderr" 00366 error = 8 00367 exit error 00368 } 00369 msh_count_elements++ 00370 elements[msh_count_elements] = $1 00371 elementType[$1] = $2 00372 msh_count_type[$2]++ 00373 elementNodes[$1] = msh_elementtype_nodes[$2] 00374 if (!elementNodes[$1]) { 00375 print "Unknown element type on line " FNR "." > "/dev/stderr" 00376 error = 9 00377 exit error 00378 } 00379 elementTags[$1] = $3 00380 if ($3 != 3) { 00381 print "Can handle 3 default tags only (line " FNR ")." > "/dev/stderr" 00382 error = 10 00383 exit error 00384 } 00385 elementPhysical[$1] = $4 00386 elementGeometry[$1] = $5 00387 elementPartition[$1] = $6 00388 j = 6 00389 for (i = 3; i <= $3; i++) { 00390 j = i + 3 00391 } 00392 for (i = 1; i <= elementNodes[$1]; i++) { 00393 k = i + j 00394 elementNode[$1,i] = $k 00395 msh_node_usedtype[$k,$2]++ 00396 } 00397 msh_elements_to_read-- 00398 next 00399 } 00400 00401 # Read physical names. 00402 # number-of-names 00403 # physical-number "physical-name" 00404 # ... 00405 (msh_read_part == msh_part_physicalnames) { 00406 if ($0 == msh_part_end) { 00407 if (msh_physicalnames_to_read > 0) { 00408 print "Physical name missing on line " FNR "." > "/dev/stderr" 00409 error = 11 00410 exit error 00411 } 00412 msh_read_part = 0 00413 next 00414 } 00415 msh_part_NR++ 00416 if (msh_part_NR == 1) { 00417 msh_physicalnames_to_read = $1 00418 print "Reading " msh_physicalnames_to_read " physical names." > "/dev/stderr" 00419 next 00420 } 00421 if (msh_physicalnames_to_read < 1) { 00422 print msh_part_end " missing on line " FNR "." > "/dev/stderr" 00423 error = 12 00424 exit error 00425 } 00426 msh_count_physicalnames++ 00427 physicalnames[msh_count_physicalnames] = $1 00428 physicalnameName[$1] = $2 00429 msh_physicalnames_to_read-- 00430 next 00431 } 00432 00433 # Skip unknown part. 00434 (msh_read_part == msh_part_unknown) { 00435 if ($0 == msh_part_end) { 00436 msh_read_part = 0 00437 next 00438 } 00439 next 00440 } 00441 00442 # Check if all parts have been read. 00443 function check_msh_finished( i, s) { 00444 if (msh_read_part != 0) { 00445 print msh_part_end " missing on line " FNR "." > "/dev/stderr" 00446 error = 13 00447 exit error 00448 } 00449 if (DEBUG) { 00450 print "Nodes: " msh_count_nodes > "/dev/stderr" 00451 print "Elements: " msh_count_elements > "/dev/stderr" 00452 print "Physical Names: " msh_count_physicalnames > "/dev/stderr" 00453 print "Points: " msh_count_type[15] > "/dev/stderr" 00454 print "Lines: " msh_count_type[1] > "/dev/stderr" 00455 print "Triangles: " msh_count_type[2] > "/dev/stderr" 00456 print "Quadrangles: " msh_count_type[3] > "/dev/stderr" 00457 print "Tetrahedra: " msh_count_type[4] > "/dev/stderr" 00458 print "Hexahedra: " msh_count_type[5] > "/dev/stderr" 00459 print "Prisms: " msh_count_type[6] > "/dev/stderr" 00460 print "Pyramids: " msh_count_type[7] > "/dev/stderr" 00461 } 00462 s = 0 00463 for (i in msh_count_type) { 00464 s += msh_count_type[i] 00465 } 00466 if (s != msh_count_elements) { 00467 print "Sum of element counts not equal to total element count in \"" FILENAME "\"." > "/dev/stderr" 00468 error = 14 00469 exit error 00470 } 00471 } 00472 00473 # Print inp output of current data. 00474 function print_inp( i,inode,icell,j) { 00475 if (DEBUG) { 00476 print "No output filtering." > "/dev/stderr" 00477 print "Output " msh_count_nodes " nodes and " msh_count_elements " cells." > "/dev/stderr" 00478 } 00479 # Header: nnodes, ncells, nnodedata, ncelldata, nmodeldata 00480 print msh_count_nodes, msh_count_elements, 0, 0, 0 > inpfile 00481 # Nodes: n, x, y, z 00482 for (i = 1; i <= msh_count_nodes; i++) { 00483 inode = nodes[i] 00484 print inode, nodeX[inode], nodeY[inode], nodeZ[inode] > inpfile 00485 } 00486 # Cells: n, material, type, nodes 00487 for (i = 1; i <= msh_count_elements; i++) { 00488 icell = elements[i] 00489 oldORS = ORS 00490 ORS = "" 00491 print icell, elementPhysical[icell], msh_elementtype_inp[elementType[icell]] > inpfile 00492 for (j = 1; j <= elementNodes[icell]; j++) { 00493 print "", elementNode[icell,j] > inpfile 00494 } 00495 ORS = oldORS 00496 print "" > inpfile 00497 } 00498 if (DEBUG) print "" > "/dev/stderr" 00499 } 00500 00501 # Print filtered inp output of current data. 00502 function print_inp_filtered( oldORS,t,ncells,i,icell,cell_used,cell_map,nnodes,inode,node_used,node_map,node_remap,j) { 00503 if (DEBUG) { 00504 oldORS = ORS 00505 ORS = "" 00506 print "Output filtering enabled: " > "/dev/stderr" 00507 for (t in inp_output) { 00508 if (inp_output[t]) print msh_elementtype_str[t] " " > "/dev/stderr" 00509 } 00510 ORS = oldORS 00511 print "" > "/dev/stderr" 00512 } 00513 00514 # Find filtered cells and create mapping. 00515 ncells = 0 00516 delete cell_used 00517 delete cell_map 00518 for (i = 1; i <= msh_count_elements; i++) { 00519 icell = elements[i] 00520 for (t in inp_output) { 00521 if (inp_output[t]) { 00522 if (elementType[icell] == t) { 00523 cell_used[icell]++ 00524 if (cell_used[icell] == 1) { 00525 ncells++ 00526 cell_map[ncells] = icell 00527 } 00528 } 00529 } 00530 } 00531 } 00532 if (DEBUG) { 00533 print ncells " cells found." > "/dev/stderr" 00534 } 00535 00536 # Find filtered nodes and create mapping. 00537 nnodes = 0 00538 delete node_used 00539 delete node_map 00540 for (i = 1; i <= msh_count_nodes; i++) { 00541 inode = nodes[i] 00542 for (t in inp_output) { 00543 if (inp_output[t]) { 00544 if (msh_node_usedtype[inode,t]) { 00545 node_used[inode]++ 00546 if (node_used[inode] == 1) { 00547 nnodes++ 00548 node_map[nnodes] = inode 00549 } 00550 } 00551 } 00552 } 00553 } 00554 if (DEBUG) { 00555 print nnodes " nodes found." > "/dev/stderr" 00556 print "Output " nnodes " nodes and " ncells " cells." > "/dev/stderr" 00557 if (inp_renumber) print "Renumbering used nodes and cells." > "/dev/stderr" 00558 } 00559 00560 delete node_remap 00561 if (inp_renumber) { 00562 # Header: nnodes, ncells, nnodedata, ncelldata, nmodeldata 00563 print nnodes, ncells, 0, 0, 0 > inpfile 00564 # Nodes: n, x, y, z 00565 for (i = 1; i <= nnodes; i++) { 00566 inode = node_map[i] 00567 node_remap[inode] = i 00568 print i, nodeX[inode], nodeY[inode], nodeZ[inode] > inpfile 00569 } 00570 # Cells: n, material, type, nodes 00571 for (i = 1; i <= ncells; i++) { 00572 icell = cell_map[i] 00573 oldORS = ORS 00574 ORS = "" 00575 print i, elementPhysical[icell], msh_elementtype_inp[elementType[icell]] > inpfile 00576 for (j = 1; j <= elementNodes[icell]; j++) { 00577 print "", node_remap[elementNode[icell,j]] > inpfile 00578 } 00579 ORS = oldORS 00580 print "" > inpfile 00581 } 00582 } else { 00583 # Header: nnodes, ncells, nnodedata, ncelldata, nmodeldata 00584 print nnodes, ncells, 0, 0, 0 > inpfile 00585 # Nodes: n, x, y, z 00586 for (i = 1; i <= msh_count_nodes; i++) { 00587 inode = nodes[i] 00588 if (node_used[inode]) { 00589 print inode, nodeX[inode], nodeY[inode], nodeZ[inode] > inpfile 00590 } 00591 } 00592 # Cells: n, material, type, nodes 00593 for (i = 1; i <= msh_count_elements; i++) { 00594 icell = elements[i] 00595 if (cell_used[icell]) { 00596 oldORS = ORS 00597 ORS = "" 00598 print icell, elementPhysical[icell], msh_elementtype_inp[elementType[icell]] > inpfile 00599 for (j = 1; j <= elementNodes[icell]; j++) { 00600 print "", elementNode[icell,j] > inpfile 00601 } 00602 ORS = oldORS 00603 print "" > inpfile 00604 } 00605 } 00606 } 00607 if (DEBUG) print "" > "/dev/stderr" 00608 } 00609 00610 END { 00611 if (error == -127) exit 0 00612 if (error) exit error 00613 00614 check_msh_finished() 00615 # Print inp. 00616 if (inpfile) { 00617 if (inp_filter_output) print_inp_filtered() 00618 else print_inp() 00619 } 00620 } 00621 00622 # vim:set sts=2 sw=2: