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 # :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:

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