add xdmf wrapper generator for HDF5

Not recommended for large dataset due to potential memory leak currently plaguing Xdmf ilbrary.
This commit is contained in:
chen 2016-10-13 13:41:04 -04:00
parent ec59dfeec0
commit 8cdc7c0b10
1 changed files with 127 additions and 0 deletions

View File

@ -0,0 +1,127 @@
#!/usr/bin/env python2.7
# -*- coding: UTF-8 no BOM -*-
# ------------------------------------------------------------------- #
# NOTE: #
# 1. Current Xdmf rendering in Paraview has some memory issue where #
# large number of polyvertices will cause segmentation fault. By #
# default, paraview output a cell based xdmf description, which #
# is working for small and medium mesh (<10,000) points. Hence a #
# rectangular mesh is used as the de facto Geometry description #
# here. #
# 2. Due to the unstable state Xdmf, it is safer to use port data #
# to VTR rather than using xdmf as interpretive layer for data #
# visualization. #
# ------------------------------------------------------------------- #
import damask
import h5py
import xml.etree.cElementTree as ET
from xml.dom import minidom
from damask.h5table import lables_to_path
scriptName = os.path.splitext(os.path.basename(__file__))[0]
scriptID = ' '.join([scriptName,damask.version])
# ----- HELPER FUNCTIONS -----#
def addTopLvlCmt(xmlstr, topLevelCmt):
"""add top level comment to string from ET"""
# a quick hack to add the top level comment to XML file
# --> somehow Elementtree does not provide this functionality
# --> by default
strList = xmlstr.split("\n")
strList[0] += "\n"+topLevelCmt
return "\n".join(strList)
# --------------------------------------------------------------------
# MAIN
# --------------------------------------------------------------------
msg = 'generate Xdmf wrapper for HDF5 file.'
parser = OptionParser(option_class=damask.extendableOption,
usage='%prog options [file[s]]',
description = msg,
version = scriptID)
(options, filenames) = parser.parse_args()
h5f = filenames[0]
# ----- parse HDF5 file ----- #
h5f_dataDim = {}
h5f_dataPath = {}
h5f_dataType = {}
with h5py.File(h5f, 'a') as f:
labels = f.keys()
labels += f['/Constitutive'].keys()
labels += f['/Crystallite'].keys()
labels += ['Vx', 'Vy', "Vz"]
# remove group names as they do not contain real data
# TODO: use h5py/H5table API to detect dataset name to
# avoid necessary name space pruning.
labels.remove('Constitutive')
labels.remove('Crystallite')
labels.remove('Geometry')
# loop through remaining labels
for label in labels:
dataType, h5Path = lables_to_path(label)
h5f_dataType[label] = dataType
h5f_dataDim[label] = " ".join(map(str,f[h5Path].shape))
h5f_dataPath[label] = h5Paths
# ----- constructing xdmf elements ----- #
root = ET.Element("Xdmf", version='3.3')
root.set('xmlns:xi', "http://www.w3.org/2001/XInclude")
root.append(ET.Comment('Generated Xdmf wapper for DAMASH H5 output'))
# usually there should only be ONE domain
domain = ET.SubElement(root, 'Domain',
Name=h5f_base.split(".")[0])
# use global topology through reference
grid = ET.SubElement(domain, 'Grid', GridType="Uniform")
# geometry section
geometry = ET.SubElement(grid, 'Geometry', GeometryType="VXVYVZ")
for vector in ["Vz", "Vy", "Vx"]:
dataitem = ET.SubElement(geometry, "DataItem",
DataType="Float",
Dimensions=h5f_dataDim[vector],
Name=vector,
Format="HDF")
dataitem.text = h5f_base.split("/")[-1] + ":{}".format(h5f_dataPath[vector])
# topology section
# TODO: support for other format based on given option
meshDim = [h5f_dataDim["Vz"], h5f_dataDim["Vy"], h5f_dataDim["Vx"]]
topology = ET.SubElement(grid, 'Topology',
TopologyType="3DRectMesh",
Dimensions=" ".join(map(str, meshDim)))
# attributes section
# Question: how to properly handle data mapping for multiphase situations
labelsProcessed = ['Vx', 'Vy', 'Vz']
# walk through each attributes
for label in labels:
if label in labelsProcessed: continue
print "adding {}...".format(label)
attr = ET.SubElement(grid, 'Attribute',
Name=label,
Type="None",
Center="Cell")
dataitem = ET.SubElement(attr, 'DataItem',
Name=label,
Format='HDF',
Dimensions=h5f_dataDim[label])
dataitem.text = h5f_base + ":" + h5f_dataPath[label]
# update progress list
labelsProcessed.append(label)
# pretty print the xdmf(xml) file content
xmlstr = minidom.parseString(ET.tostring(root)).toprettyxml(indent="\t")
xmlstr = addTopLvlCmt(xmlstr, '<!DOCTYPE Xdmf SYSTEM "Xdmf.dtd" []>')
# write str to file through native python API
with open(h5f.replace(".h5", ".xmf"), 'w') as f:
f.write(xmlstr)