XDMF writer: share mesh between different functions (avoid ParaView oddities)

Issue #885 invalid
Nico Schlömer created an issue

Thanks to PR #338, FEniCS has support for Xdmf3 time series with multiple data sets.

So far, the data sets are stores as

<?xml version="1.0"?>
<!DOCTYPE Xdmf SYSTEM "Xdmf.dtd" []>
<Xdmf Version="3.0" xmlns:xi="http://www.w3.org/2001/XInclude">
  <Domain>
    <Grid Name="TimeSeries_u" GridType="Collection" CollectionType="Temporal">
      <Grid Name="mesh" GridType="Uniform">
        <Topology NumberOfElements="2121" TopologyType="Triangle" NodesPerElement="3">
          <DataItem Dimensions="2121 3" NumberType="UInt" Format="HDF">all.h5:/Mesh/0/mesh/topology</DataItem>
        </Topology>
        <Geometry GeometryType="XY">
          <DataItem Dimensions="1149 2" Format="HDF">all.h5:/Mesh/0/mesh/geometry</DataItem>
        </Geometry>
        <Time Value="0" />
        <Attribute Name="u" AttributeType="Vector" Center="Node">
          <DataItem Dimensions="1149 3" Format="HDF">all.h5:/VisualisationVector/0</DataItem>
        </Attribute>
      </Grid>
      <Grid>
        <xi:include xpointer="xpointer(//Grid[@Name=&quot;TimeSeries_u&quot;]/Grid[1]/*[self::Topology or self::Geometry])" />
        <Time Value="0.001" />
        <Attribute Name="u" AttributeType="Vector" Center="Node">
          <DataItem Dimensions="1149 3" Format="HDF">all.h5:/VisualisationVector/3</DataItem>
        </Attribute>
      </Grid>
     <!-- More time steps ... -->
    <Grid Name="TimeSeries_p" GridType="Collection" CollectionType="Temporal">
      <Grid Name="mesh" GridType="Uniform">
        <Topology NumberOfElements="2121" TopologyType="Triangle" NodesPerElement="3">
          <DataItem Dimensions="2121 3" NumberType="UInt" Format="HDF">all.h5:/Mesh/1/mesh/topology</DataItem>
        </Topology>
        <Geometry GeometryType="XY">
          <DataItem Dimensions="1149 2" Format="HDF">all.h5:/Mesh/1/mesh/geometry</DataItem>
        </Geometry>
        <Time Value="0" />
        <Attribute Name="p" AttributeType="Scalar" Center="Node">
          <DataItem Dimensions="1149 1" Format="HDF">all.h5:/VisualisationVector/1</DataItem>
        </Attribute>
      </Grid>
      <Grid>
        <xi:include xpointer="xpointer(//Grid[@Name=&quot;TimeSeries_p&quot;]/Grid[1]/*[self::Topology or self::Geometry])" />
        <Time Value="0.001" />
        <Attribute Name="p" AttributeType="Scalar" Center="Node">
          <DataItem Dimensions="1149 1" Format="HDF">all.h5:/VisualisationVector/4</DataItem>
        </Attribute>
      </Grid>
     <!-- ... -->
    </Grid>
  </Domain>
</Xdmf>

Every data set (here u and p has its own TimeSeries.

This has multiple disadvantages:

  • The mesh cannot be shared between u and p.
  • ParaView recognized the data sets as partial, leading to all sorts of funny errors (see, e.g., here).

In case the the data sets share the same mesh – which I assume is the dominant use case –, the data could be stored like

<?xml version="1.0"?>
<!DOCTYPE Xdmf SYSTEM "Xdmf.dtd" []>
<Xdmf Version="3.0" xmlns:xi="http://www.w3.org/2001/XInclude">
  <Domain>
    <Grid Name="TimeSeries_u" GridType="Collection" CollectionType="Temporal">
      <Grid Name="mesh" GridType="Uniform">
        <Topology NumberOfElements="2121" TopologyType="Triangle" NodesPerElement="3">
          <DataItem Dimensions="2121 3" NumberType="UInt" Format="HDF">all.h5:/Mesh/0/mesh/topology</DataItem>
        </Topology>
        <Geometry GeometryType="XY">
          <DataItem Dimensions="1149 2" Format="HDF">all.h5:/Mesh/0/mesh/geometry</DataItem>
        </Geometry>
        <Time Value="0" />
        <Attribute Name="u" AttributeType="Vector" Center="Node">
          <DataItem Dimensions="1149 3" Format="HDF">all.h5:/VisualisationVector/0</DataItem>
        </Attribute>
    <Attribute Name="p" AttributeType="Scalar" Center="Node">
          <DataItem Dimensions="1149 1" Format="HDF">all.h5:/VisualisationVector/1</DataItem>
        </Attribute>
      </Grid>
      <Grid>
        <xi:include xpointer="xpointer(//Grid[@Name=&quot;TimeSeries_u&quot;]/Grid[1]/*[self::Topology or self::Geometry])" />
        <Time Value="0.001" />
        <Attribute Name="u" AttributeType="Vector" Center="Node">
          <DataItem Dimensions="1149 3" Format="HDF">all.h5:/VisualisationVector/2</DataItem>
        </Attribute>
    <Attribute Name="p" AttributeType="Scalar" Center="Node">
          <DataItem Dimensions="1149 1" Format="HDF">all.h5:/VisualisationVector/3</DataItem>
        </Attribute>
      </Grid>
     <!-- More time steps ... -->
  </Domain>
</Xdmf>

Advantages:

  • (slightly) smaller files
  • better support for ParaView.

For implementing this, I see two possible interfaces:

  • Provide a parameter (like the exisitng 'rewrite_function_mesh') that tells the writer to share the mesh between all input functions
  • Add a write_all method with the signature write_all(list_of_functions, time).

The latter is perhaps cleaner in that it forces all functions to be present at all time steps.

Comments (1)

  1. Nico Schlömer reporter

    Okay, that was easier than expected. Looking at the code, one finds the parameter 'functions_share_mesh' that does exactly what's described.

  2. Log in to comment