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