ULM files

Simple and efficient pythonic file-format

Stores ndarrays as binary data and Python’s built-in datatypes (bool, int, float, complex, str, dict, list, tuple, None) as json.

ase.io.ulm.open(filename, mode='r', index=None, tag=None)[source]

Open ulm-file.

filename: str


mode: str

Mode. Must be ‘r’ for reading, ‘w’ for writing to a new file (overwriting an existing one) or ‘a’ for appending to an existing file.

index: int

Index of item to read. Defaults to 0.

tag: str

Magic ID string.

Returns a Reader or a Writer object. May raise InvalidULMFileError.

exception ase.io.ulm.InvalidULMFileError[source]

File layout

When there is only a single item:

0: "- of Ulm" (magic prefix, ascii)
8: "                " (tag, ascii)
24: version (int64)
32: nitems (int64)
40: 48 (position of offsets, int64)
48: p0 (offset to json data, int64)
56: array1, array2, ... (8-byte aligned ndarrays)
p0: n (length of json data, int64)
p0+8: json data
p0+8+n: EOF



>>> import numpy as np
>>> import ase.io.ulm as ulm
>>> with ulm.open('x.ulm', 'w') as w:
...     w.write(a=np.ones(7), b=42, c='abc')
...     w.write(d=3.14)


>>> r = ulm.open('x.ulm')
>>> print(r.c)
>>> r.close()

To see what’s inside ‘x.ulm’ do this:

$ ase ulm x.ulm
x.ulm  (tag: "", 1 item)
item #0:
    a: <ndarray shape=(7,) dtype=float64>,
    b: 42,
    c: abc,
    d: 3.14}
class ase.io.ulm.Writer(fd, mode='w', tag='', data=None)[source]

Create writer object.

fd: str


mode: str

Mode. Must be ‘w’ for writing to a new file (overwriting an existing one) and ‘a’ for appending to an existing file.

tag: str

Magic ID string.

add_array(name, shape, dtype=<class 'float'>)[source]

Add ndarray object.

Set name, shape and dtype for array and fill in the data in chunks later with the fill() method.


Create child-writer object.


Close file.


Fill in ndarray chunks for array currently being written.


Write data dictionary.

Write bool, int, float, complex and str data, shapes and dtypes for ndarrays.

write(*args, **kwargs)[source]

Write data.


writer.write('n', 7)
writer.write(n=7, s='abc', a=np.zeros(3), abc=obj)

If obj is not one of the supported data types (bool, int, float, complex, tupl, list, dict, None or ndarray) then it must have a obj.write(childwriter) method.

class ase.io.ulm.Reader(fd, index=0, data=None, _little_endian=None)[source]

Create reader.


Read everything now and convert to dict.

get(attr, value=None)[source]

Get attr or value if no such attr.


Return special tag string.


Return list of keys.

More examples

In the following we append to the ulm-file from above and demonstrae how to write a big array in chunks:

>>> w = ulm.open('x.ulm', 'a')
>>> w.add_array('bigarray', (10, 1000), float)
>>> for i in range(10):
...     w.fill(np.ones(1000))
>>> w.close()

Now read first and second items:

>>> with ulm.open('x.ulm') as r:
...     print(r.keys())
dict_keys(['a', 'b', 'c', 'd'])
>>> with ulm.open('x.ulm', index=1) as r:
...     print(r.keys())

To get all the data, it is possible to iterate over the items in the file.

>>> for i, r in enumerate(ulm.Reader('x.ulm')):
...     for k in r.keys():
...         print(i, k)
0 a
0 b
0 c
0 d
1 bigarray
>>> r.close()

The different parts (items) of the file are numbered by the index argument:

>>> r = ulm.Reader('x.ulm')
>>> r[1].bigarray.shape
(10, 1000)
>>> r.close()


  1. Initial version.

  2. Added support for big endian machines. Json data may now have _little_endian=False item.

  3. Changed magic string from “AFFormat” to “- of Ulm”.