msh2inp.awk

Go to the documentation of this file.
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:

magpar - Parallel Finite Element Micromagnetics Package
Copyright (C) 2002-2010 Werner Scholz