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:
parent
ec59dfeec0
commit
8cdc7c0b10
|
@ -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)
|
Loading…
Reference in New Issue