@@ -4,7 +4,7 @@ Storing datafiles
44mpi4py-fft works with regular Numpy arrays. However, since arrays in parallel
55can become very large, and the arrays live on multiple processors, we require
66parallel IO capabilities that goes beyond Numpys regular methods.
7- In the :mod: `mpi4py_fft.utilities ` module there are two helper classes for dumping
7+ In the :mod: `mpi4py_fft.io ` module there are two helper classes for dumping
88dataarrays to either `HDF5 <https://www.hdf5.org >`_ or
99`NetCDF <https://www.unidata.ucar.edu/software/netcdf/ >`_ format:
1010
@@ -17,56 +17,74 @@ reads data in parallel. A simple example of usage is::
1717 from mpi4py import MPI
1818 import numpy as np
1919 from mpi4py_fft import PFFT, HDF5File, NCFile, newDistArray
20-
2120 N = (128, 256, 512)
2221 T = PFFT(MPI.COMM_WORLD, N)
2322 u = newDistArray(T, forward_output=False)
2423 v = newDistArray(T, forward_output=False, val=2)
25- u[:] = np.random.random(N )
26-
24+ u[:] = np.random.random(u.shape )
25+ # Store by first creating output files
2726 fields = {'u': [u], 'v': [v]}
28- f0 = HDF5File('h5test.h5', T )
29- f1 = NCFile('nctest.nc', T )
27+ f0 = HDF5File('h5test.h5', mode='w' )
28+ f1 = NCFile('nctest.nc', mode='w' )
3029 f0.write(0, fields)
3130 f1.write(0, fields)
3231 v[:] = 3
3332 f0.write(1, fields)
3433 f1.write(1, fields)
3534
36- Note that we are creating two datafiles ``h5test.h5 `` and ``nctest.nc ``,
35+ Note that we are here creating two datafiles ``h5test.h5 `` and ``nctest.nc ``,
3736for storing in HDF5 or NetCDF4 formats respectively. Normally, one would be
3837satisfied using only one format, so this is only for illustration. We store
39- the fields ``u `` and ``v `` using method ``write `` on two different occasions,
40- so the datafiles will contain two snapshots of each field ``u `` and ``v ``.
38+ the fields ``u `` and ``v `` on three different occasions,
39+ so the datafiles will contain three snapshots of each field ``u `` and ``v ``.
40+
41+ Also note that an alternative and perhaps simpler approach is to just use
42+ the ``write `` method of each distributed array::
43+
44+ u.write('h5test.h5', 'u', step=2)
45+ v.write('h5test.h5', 'v', step=2)
46+ u.write('nctest.nc', 'u', step=2)
47+ v.write('nctest.nc', 'v', step=2)
4148
42- The stored dataarrays can be retrieved later on::
49+ The two different approaches can be used on the same output files.
50+
51+ The stored dataarrays can also be retrieved later on::
4352
44- f0 = HDF5File('h5test.h5', T, mode='r')
45- f1 = NCFile('nctest.nc', T, mode='r')
4653 u0 = newDistArray(T, forward_output=False)
4754 u1 = newDistArray(T, forward_output=False)
48- f0.read(u0, 'u', 0)
49- f0.read(u1, 'u', 1)
50- f1.read(u0, 'u', 0)
51- f1.read(u1, 'u', 1)
55+ u0.read('h5test.h5', 'u', 0)
56+ u1.read('h5test.h5', 'u', 1)
57+ # or alternatively for netcdf
58+ #u0.read('nctest.nc', 'u', 0)
59+ #u1.read('nctest.nc', 'u', 1)
5260
5361Note that one does not have to use the same number of processors when
5462retrieving the data as when they were stored.
5563
5664It is also possible to store only parts of the, potentially large, arrays.
57- Any chosen slice may be stored, using a *global * view of the arrays::
65+ Any chosen slice may be stored, using a *global * view of the arrays. It is
66+ possible to store both complete fields and slices in one single call by
67+ using the following appraoch::
5868
59- f2 = HDF5File('variousfields.h5', T, mode='w')
69+ f2 = HDF5File('variousfields.h5', mode='w')
6070 fields = {'u': [u,
6171 (u, [slice(None), slice(None), 4]),
6272 (u, [5, 5, slice(None)])],
6373 'v': [v,
6474 (v, [slice(None), 6, slice(None)])]}
6575 f2.write(0, fields)
6676 f2.write(1, fields)
67- f2.write(2, fields)
6877
69- This will lead to an hdf5-file with groups::
78+ Alternatively, one can use the write method of each field with the ``global_slice ``
79+ keyword argument::
80+
81+ u.write('variousfields.h5', 'u', 2)
82+ u.write('variousfields.h5', 'u', 2, global_slice=[slice(None), slice(None), 4])
83+ u.write('variousfields.h5', 'u', 2, global_slice=[5, 5, slice(None)])
84+ v.write('variousfields.h5', 'v', 2)
85+ v.write('variousfields.h5', 'v', 2, global_slice=[slice(None), 6, slice(None)])
86+
87+ In the end this will lead to an hdf5-file with groups::
7088
7189 variousfields.h5/
7290 ├─ u/
@@ -80,41 +98,49 @@ This will lead to an hdf5-file with groups::
8098 | | ├─ 0
8199 | | ├─ 1
82100 | | └─ 2
83- | └─ 3D/
84- | ├─ 0
85- | ├─ 1
86- | └─ 2
87- ├─ v/
88- | ├─ 2D/
89- | | └─ slice_6_slice/
90- | | ├─ 0
91- | | ├─ 1
92- | | └─ 2
93- | └─ 3D/
94- | ├─ 0
95- | ├─ 1
96- | └─ 2
97- └─ mesh/
98- ├─ x0
99- ├─ x1
100- └─ x2
101-
102- Note that a mesh is stored along with all the data. This mesh can be given in
103- two different ways when creating the datafiles:
101+ | ├─ 3D/
102+ | | ├─ 0
103+ | | ├─ 1
104+ | | └─ 2
105+ | └─ mesh/
106+ | ├─ x0
107+ | ├─ x1
108+ | └─ x2
109+ └─ v/
110+ ├─ 2D/
111+ | └─ slice_6_slice/
112+ | ├─ 0
113+ | ├─ 1
114+ | └─ 2
115+ ├─ 3D/
116+ | ├─ 0
117+ | ├─ 1
118+ | └─ 2
119+ └─ mesh/
120+ ├─ x0
121+ ├─ x1
122+ └─ x2
123+
124+ Note that a mesh is stored along with each group of data. This mesh can be
125+ given in two different ways when creating the datafiles:
104126
105127 1) A sequence of 2-tuples, where each 2-tuple contains the (origin, length)
106128 of the domain along its dimension. For example, a uniform mesh that
107129 originates from the origin, with lengths :math: `\pi , 2 \pi , 3 \pi `, can be
108- given as::
130+ given when creating the output file as::
131+
132+ f0 = HDF5File('filename.h5', domain=((0, pi), (0, 2*np.pi), (0, 3*np.pi)))
133+
134+ or, using the write method of the distributed array:
109135
110- f0 = HDF5File ('filename.h5', T , domain=((0, pi), (0, 2*np.pi), (0, 3*np.pi)))
136+ u.write ('filename.h5', 'u', 0 , domain=((0, pi), (0, 2*np.pi), (0, 3*np.pi)))
111137
112138 2) A sequence of arrays giving the coordinates for each dimension. For example::
113139
114140 d = (np.arange(N[0], dtype=np.float)*1*np.pi/N[0],
115141 np.arange(N[1], dtype=np.float)*2*np.pi/N[1],
116142 np.arange(N[2], dtype=np.float)*2*np.pi/N[2])
117- f0 = HDF5File('filename.h5', T, domain=d)
143+ f0 = HDF5File('filename.h5', domain=d)
118144
119145With NetCDF4 the layout is somewhat different. For ``variousfields `` above,
120146if we were using :class: `.NCFile ` instead of :class: `.HDF5File `,
@@ -147,9 +173,9 @@ opened with `Visit <https://www.visitusers.org>`_.
147173
148174To view the HDF5-files we first need to generate some light-weight *xdmf *-files that can
149175be understood by both Paraview and Visit. To generate such files, simply throw the
150- module :mod: `.utilities .generate_xdmf ` on the HDF5-files::
176+ module :mod: `.io .generate_xdmf ` on the HDF5-files::
151177
152- from mpi4py_fft.utilities import generate_xdmf
178+ from mpi4py_fft.io import generate_xdmf
153179 generate_xdmf('variousfields.h5')
154180
155181This will create a number of xdmf-files, one for each group that contains 2D
0 commit comments