meshio icon indicating copy to clipboard operation
meshio copied to clipboard

Cannot parse XDMF time series

Open blechta opened this issue 6 years ago • 3 comments

The following XDMF is understood by Paraview 5.6 but is not understood by meshio, which raises AssertionError: Unknown section 'Grid'.

It contains two <Grid>s inside of <Grid CollectionType="Temporal" GridType="Collection" Name="TimeSeries">.

<?xml version="1.0" encoding="utf-8"?>
<Xdmf xmlns:xi="http://www.w3.org/2001/XInclude" Version="3.0">
   <Domain>
      <Grid CollectionType="Temporal" GridType="Collection" Name="TimeSeries">
         <Grid GridType="Uniform" Name="grid0">
            <Time Value="0"/>
            <Attribute AttributeType="Vector" Center="Other" ElementCell="triangle" ElementDegree="1"
                       ElementFamily="DG"
                       ItemType="FiniteElementFunction"
                       Name="u">
               <DataItem Dimensions="2 6" Format="XML" Name="celldofs" NumberType="UInt">0 1 2 3 4 5
6 7 8 9 10 11
</DataItem>
               <DataItem Dimensions="12 1" Format="XML" NumberType="Float">0
0
0
-0
-0
-0
-0
-0
-0
-0
-0
-0
</DataItem>
            </Attribute>
            <Topology NodesPerElement="3" NumberOfElements="2" TopologyType="Triangle">
               <DataItem Dimensions="2 3" Format="XML" NumberType="UInt">0 1 2
1 2 3
</DataItem>
            </Topology>
            <Geometry GeometryType="XY">
               <DataItem Dimensions="4 2" Format="XML">0 0
1 0
0 1
1 1
</DataItem>
            </Geometry>
         </Grid>
         <Grid GridType="Uniform" Name="grid1">
            <Time Value="0.001"/>
            <Attribute AttributeType="Vector" Center="Other" ElementCell="triangle" ElementDegree="1"
                       ElementFamily="DG"
                       ItemType="FiniteElementFunction"
                       Name="u">
               <DataItem Dimensions="2 6" Format="XML" Name="celldofs" NumberType="UInt">0 1 2 3 4 5
6 7 8 9 10 11
</DataItem>
               <DataItem Dimensions="12 1" Format="XML" NumberType="Float">0
0
0
-0
-0
-0
-0
-0
-0
-0
-0
-0
</DataItem>
            </Attribute>
            <xi:include xpointer="xpointer(//Grid[@Name=&#34;TimeSeries&#34;]/Grid[@Name=&#34;grid0&#34;]/*[self::Topology or self::Geometry])"/>
         </Grid>
      </Grid>
   </Domain>
</Xdmf>

blechta avatar Oct 01 '19 15:10 blechta

Ok, I guess I am talking about unsupported feature: finite element functions. Feel free to close.

blechta avatar Oct 01 '19 15:10 blechta

It's okay to leave it open, meshio should support this. This is a time series, so you'll have to tackle it in the main readme,

import meshio

reader = meshio.XdmfTimeSeriesReader("a.xdmf")
points, cells = reader.read_points_cells()
for k in range(reader.num_steps):
    t, point_data, cell_data = reader.read_data(k)

However, this doesn't work yet. It chokes on GridType="Collection". I'll have a look one of these days.

nschloe avatar Oct 01 '19 16:10 nschloe

To solve my problem (I have XDMF XML files which Paraview chockes on error: xmlSAX2Characters: huge text node: out of memory), I wrote this XDMF XML to binary converter. The idea is it does not need to be able to completely understand XDMF, it merely replaces DataItem nodes. Meshio was invaluable in developing this :wink: Feel free to reuse any portion of the following with MIT if useful.

from lxml import etree
import numpy

from meshio.common import write_xml
from meshio.xdmf_io.common import xdmf_to_numpy_type


def xdmf_xml_to_binary(infilename, outfilename):
    """Convert XDMF with XML data items into binary data items"""

    outfilebase, ext = outfilename.rsplit(sep='.', maxsplit=1)
    assert ext.lower() == 'xdmf'

    parser = etree.XMLParser(remove_comments=True, huge_tree=True)
    tree = etree.parse(infilename, parser)

    # Loop over heavy data nodes
    for i, e in enumerate(tree.getroot().iter('DataItem')):

        # Extract shape
        dims = [int(d) for d in e.get("Dimensions").split()]

        # Extract dtype
        dtype = e.get('NumberType', 'Float')  # XDMF default
        precision = e.get('Precision', '4')   # XDMF default
        dtype = xdmf_to_numpy_type[(dtype, precision)]

        # Convert XML text to numpy array
        assert e.get('Format') == 'XML'
        data = numpy.array(e.text.split(), dtype=dtype).reshape(dims)

        # Dump array to binary file
        bin_filename = "{}{}.bin".format(outfilebase, i)
        with open(bin_filename, "wb") as f:
            data.tofile(f)

        # Make XML point to binary file
        e.text = bin_filename
        e.set('Format', 'Binary')

    write_xml(outfilename, tree.getroot())


if __name__ == '__main__':
    import sys
    xdmf_xml_to_binary(sys.argv[1], sys.argv[2])

blechta avatar Oct 01 '19 18:10 blechta