Xdmf3 Python API: Difference between revisions
(Created page with "Image:XdmfLogo1.gif __TOC__ ==XDMF API== While use of the XDMF API is not necessary to produce or consume valid XDMF datasets, there are many convenience features that ...") |
No edit summary |
||
Line 48: | Line 48: | ||
y = [1, 2, 3, ..] | y = [1, 2, 3, ..] | ||
z = [1, 2, 3, ..] | z = [1, 2, 3, ..] | ||
dims = UInt32Vector() | dims = UInt32Vector() | ||
dims.push_back(10) | dims.push_back(10) | ||
dims.push_back(20) | dims.push_back(20) | ||
dims.push_back(30) | dims.push_back(30) | ||
total = 10 * 20 * 30 | total = 10 * 20 * 30 | ||
xyz = XdmfArray.New() | xyz = XdmfArray.New() | ||
xyz.initialize(XdmfArrayType.Float64(), dims); // KDim, JDim, IDim | xyz.initialize(XdmfArrayType.Float64(), dims); // KDim, JDim, IDim | ||
xyz.insertAsFloat64(0, x, 0, total, 3, 1); // insert<nowiki><T></nowiki>(unsigned int index, T <nowiki>*</nowiki>Values, | xyz.insertAsFloat64(0, x, 0, total, 3, 1); // insert<nowiki><T></nowiki>(unsigned int index, T <nowiki>*</nowiki>Values, | ||
Line 84: | Line 80: | ||
from Xdmf import <nowiki>*</nowiki> | from Xdmf import <nowiki>*</nowiki> | ||
Geometry = "-1.75 -1.25 0 -1.25 -1.25 0 -0.75 | Geometry = "-1.75 -1.25 0 -1.25 -1.25 0 -0.75 | ||
Connectivity = "3 2 5 1 . | Connectivity = "3 2 5 1 . | ||
Values = "100 200 300 .. | Values = "100 200 300 .. | ||
heavywriter = XdmfHDF5Writer.New(<nowiki>"example.h5"</nowiki>) | heavywriter = XdmfHDF5Writer.New(<nowiki>"example.h5"</nowiki>) | ||
# Geometry | # Geometry | ||
GeometryArray = XdmfArray() | GeometryArray = XdmfArray() | ||
GeometryArray.insertAsFloat64(0, Geometry) | GeometryArray.insertAsFloat64(0, Geometry) | ||
GeometryArray.accept(heavywriter) | GeometryArray.accept(heavywriter) | ||
# Connectivity | |||
# | |||
ConnectivityArray = XdmfArray() | ConnectivityArray = XdmfArray() | ||
ConnectivityArray.insertAsFloat64(0, Connectivity) | ConnectivityArray.insertAsFloat64(0, Connectivity) | ||
ConnectivityArray.accept(heavywriter) | ConnectivityArray.accept(heavywriter) | ||
# Values | # Values | ||
ValueArray = XdmfArray() | ValueArray = XdmfArray() | ||
Line 152: | Line 143: | ||
reader = XdmfReader.New() | reader = XdmfReader.New() | ||
domain = reader.read(<nowiki>"Points.xmf"</nowiki>) | domain = reader.read(<nowiki>"Points.xmf"</nowiki>) | ||
grid = domain.getUnstructuredGrid(0) | grid = domain.getUnstructuredGrid(0) | ||
topology = grid.getTopology() | topology = grid.getTopology() | ||
print "Values = ", topology.getValuesString() | print "Values = ", topology.getValuesString() | ||
geometry = grid.getGeometry() | geometry = grid.getGeometry() | ||
print "Geo Type = ", geo.getType().getName(), " # Points = ", geometry.getNumberOfPoints() | print "Geo Type = ", geo.getType().getName(), " # Points = ", geometry.getNumberOfPoints() | ||
Line 173: | Line 161: | ||
root.insert(i) # XdmfDomain is the root of the tree | root.insert(i) # XdmfDomain is the root of the tree | ||
# insert adds the information we just created as a leaf | # insert adds the information we just created as a leaf | ||
# Dimensions | # Dimensions | ||
dimensions = XdmfArray.New() | dimensions = XdmfArray.New() |
Revision as of 11:55, 7 November 2014
XDMF API
While use of the XDMF API is not necessary to produce or consume valid XDMF datasets, there are many convenience features that make it attractive.
All XDMF Objects are derived from XdmfItem.
XdmfDomain
To understand access to XDMF data, understanding of the XdmfDOM is critical. XDMF uses the libxml2 library to parse and generate XML documents. The Domain is an in-memory tree structure that represents the XML file. Nodes of the tree are added, deleted, queried and serialized.
A Domain can be created inside the code via the New function:
domain = XdmfDomain.New()
A reader can be used to produce a domain from an existing file:
reader = XdmfReader.New() domain = reader.read("MyXMLFile.xmf")
Once the XML has been parsed into the Domain, the tree can be navigated and modified. The domain is the root of the Xdmf tree and by accessing its children via XdmfDomain::getUnstructuredGrid(unsigned int) and similar functions.
ungrid = domain.getUnstructuredGrid(0)
The same grid can also be fetched by name.
ungrid = domain.getUnstructuredGrid("Unstructured Grid")
Once you have the child object, that child has its own functions that can be used to modify or retrieve attributes or children.
originalName = ungrid.getName() ungrid.setName("New Name")
When finished building and modifying the XdmfTree it can then be written out to file with an XdmfWriter visitor.
writer = XdmfWriter.New("outfile.xmf") domain.accept(writer)
XdmfArray
The XdmfArray class is a self describing data structure. It contains descriptions for its internal number type, precision, and shape (rank and dimensions). Many XDMF classes require an XdmfArray as input to methods. The following C++ example demonstrates creating an interlaced XYZ array from three separate variables:
x = [1, 2, 3, ..] y = [1, 2, 3, ..] z = [1, 2, 3, ..] dims = UInt32Vector() dims.push_back(10) dims.push_back(20) dims.push_back(30) total = 10 * 20 * 30 xyz = XdmfArray.New() xyz.initialize(XdmfArrayType.Float64(), dims); // KDim, JDim, IDim xyz.insertAsFloat64(0, x, 0, total, 3, 1); // insert<T>(unsigned int index, T *Values, // unsigned int NumberOfValues, unsigned int ArrayStride=1, // unsigned int ValuesStride=1) xyz.insertAsFloat64(1, y, 0, total, 3, 1); xyz.insertAsFloat64(2, z, 0, total, 3, 1);
XdmfTime
When modifying the Xdmf Tree, XdmfTime objects can be added to grids in order to specify timestamps.
time = XdmfTime.New(5.0) ungrid.setTime(time)
XdmfHDF
In XDMF, Light data is stored in XML while the Heavy data is typically stored in an HDF5 file. Passing an XdmfHDF5Writer to an array will write its contents to the specified hdf5 file. A controller object is created to handle the data description and allows the array to read the data back in if needed. The default write mode creates a new hdf5 dataspace for each written array. HDF5 write modes include:
- Default
- Overwrite
- Append
- Hyperslab
from Xdmf import * Geometry = "-1.75 -1.25 0 -1.25 -1.25 0 -0.75 Connectivity = "3 2 5 1 . Values = "100 200 300 .. heavywriter = XdmfHDF5Writer.New("example.h5") # Geometry GeometryArray = XdmfArray() GeometryArray.insertAsFloat64(0, Geometry) GeometryArray.accept(heavywriter) # Connectivity ConnectivityArray = XdmfArray() ConnectivityArray.insertAsFloat64(0, Connectivity) ConnectivityArray.accept(heavywriter) # Values ValueArray = XdmfArray() ValueArray.insertAsFloat64(0, Values) ValueArray.accept(heavywriter)
When reading, if reading from an XML file where the arrays have the hdf5 data sets specified, controllers will automatically be created for all arrays with a heavy data description. To access the data in heavy data XdmfArray::read() must be called. If it is required to link heavy data manually a heavy data controller can be created manually and added to an array.
newPath = "File path to hdf5 file goes here" newSetPath = "path to the set goes here" readType = XdmfArrayType.Int32() #Xdmf provides wrappers for C++ types #in this case std::vector<unsigned int> readStarts = UInt32Vector() #Three dimensions, all starting at index 0 readStarts.push_back(0) readStarts.push_back(0) readStarts.push_back(0) readStrides = UInt32Vector() #Three dimensions, no skipping between index readStrides.push_back(1) readStrides.push_back(1) readStrides.push_back(1) readCounts = UInt32Vector() #Three dimensions, reading 10 values from each readCounts.push_back(10) readCounts.push_back(10) readCounts.push_back(10) readDataSize = UInt32Vector() #three dimensins, each with 20 maximum values readDataSize.push_back(20) readDataSize.push_back(20) readDataSize.push_back(20) controller = XdmfHDF5Controller.New( newPath, newSetPath, readType, readStarts, readStrides, readCounts, readDataSize) array.insert(controller) array.read()
Reading XDMF
Putting all of this together, assume Points.xmf is a valid XDMF XML file with a single Grid. Here is a Python example to read and print values.
reader = XdmfReader.New() domain = reader.read("Points.xmf") grid = domain.getUnstructuredGrid(0) topology = grid.getTopology() print "Values = ", topology.getValuesString() geometry = grid.getGeometry() print "Geo Type = ", geo.getType().getName(), " # Points = ", geometry.getNumberOfPoints() print "Points = ", geometry.getValuesString()
Writing XDMF
Using the insert() and set() methods, an XDMF dataset can be generated programmatically as well. An object tree mirroring the XML is built as Xdmf objects are attached to each other. Since this is handled via shared pointers the objects are not duplicated if there are multiple instances of that object in the tree and the user does not have to worry about memory cleanup.
root = XdmfDomain.New() # Information i = XdmfInformation.New() # Arbitrary Name=Value Facility i.setName("Time") i.setValue("0.0123") root.insert(i) # XdmfDomain is the root of the tree # insert adds the information we just created as a leaf # Dimensions dimensions = XdmfArray.New() dimensions.pushBackAsUInt32(10) dimensions.pushBackAsUInt32(20) dimensions.pushBackAsUInt32(30) # Origin origin = XdmfArray.New() origin.pushBackAsUInt32(1) origin.pushBackAsUInt32(2) origin.pushBackAsUInt32(3) # Brick Size brick = XdmfArray.New() brick.pushBackAsUInt32(1) brick.pushBackAsUInt32(2) brick.pushBackAsUInt32(3) # Grid g = XdmfRegularGrid.New(brick, dimensions, origin) g.setName("Structured Grid") root.Insert(g) # Attribute attr = XdmfAttribute.New() attr.setName("Pressure") attr.setAttributeCenter(XdmfAttributeCenter::Cell()); attr.setAttributeType(XdmfAttributeType::Scalar()); attr.initializeAsFloat64(10 * 20 * 30) pressureVals = {0, 1, 2, 3, 4, 5, ...} attr.insert(0, pressureVals) # The heavy data set name is determined by the writer if not set g.insert(attr) # Generate a writer writer = XdmfWriter.New("output.xmf") domain.accept(writer)