@@ -4,7 +4,7 @@ Storing datafiles
4
4
mpi4py-fft works with regular Numpy arrays. However, since arrays in parallel
5
5
can become very large, and the arrays live on multiple processors, we require
6
6
parallel 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
8
8
dataarrays to either `HDF5 <https://www.hdf5.org >`_ or
9
9
`NetCDF <https://www.unidata.ucar.edu/software/netcdf/ >`_ format:
10
10
@@ -17,56 +17,74 @@ reads data in parallel. A simple example of usage is::
17
17
from mpi4py import MPI
18
18
import numpy as np
19
19
from mpi4py_fft import PFFT, HDF5File, NCFile, newDistArray
20
-
21
20
N = (128, 256, 512)
22
21
T = PFFT(MPI.COMM_WORLD, N)
23
22
u = newDistArray(T, forward_output=False)
24
23
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
27
26
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' )
30
29
f0.write(0, fields)
31
30
f1.write(0, fields)
32
31
v[:] = 3
33
32
f0.write(1, fields)
34
33
f1.write(1, fields)
35
34
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 ``,
37
36
for storing in HDF5 or NetCDF4 formats respectively. Normally, one would be
38
37
satisfied 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)
41
48
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::
43
52
44
- f0 = HDF5File('h5test.h5', T, mode='r')
45
- f1 = NCFile('nctest.nc', T, mode='r')
46
53
u0 = newDistArray(T, forward_output=False)
47
54
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)
52
60
53
61
Note that one does not have to use the same number of processors when
54
62
retrieving the data as when they were stored.
55
63
56
64
It 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::
58
68
59
- f2 = HDF5File('variousfields.h5', T, mode='w')
69
+ f2 = HDF5File('variousfields.h5', mode='w')
60
70
fields = {'u': [u,
61
71
(u, [slice(None), slice(None), 4]),
62
72
(u, [5, 5, slice(None)])],
63
73
'v': [v,
64
74
(v, [slice(None), 6, slice(None)])]}
65
75
f2.write(0, fields)
66
76
f2.write(1, fields)
67
- f2.write(2, fields)
68
77
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::
70
88
71
89
variousfields.h5/
72
90
├─ u/
@@ -80,41 +98,49 @@ This will lead to an hdf5-file with groups::
80
98
| | ├─ 0
81
99
| | ├─ 1
82
100
| | └─ 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:
104
126
105
127
1) A sequence of 2-tuples, where each 2-tuple contains the (origin, length)
106
128
of the domain along its dimension. For example, a uniform mesh that
107
129
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:
109
135
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)))
111
137
112
138
2) A sequence of arrays giving the coordinates for each dimension. For example::
113
139
114
140
d = (np.arange(N[0], dtype=np.float)*1*np.pi/N[0],
115
141
np.arange(N[1], dtype=np.float)*2*np.pi/N[1],
116
142
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)
118
144
119
145
With NetCDF4 the layout is somewhat different. For ``variousfields `` above,
120
146
if we were using :class: `.NCFile ` instead of :class: `.HDF5File `,
@@ -147,9 +173,9 @@ opened with `Visit <https://www.visitusers.org>`_.
147
173
148
174
To view the HDF5-files we first need to generate some light-weight *xdmf *-files that can
149
175
be 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::
151
177
152
- from mpi4py_fft.utilities import generate_xdmf
178
+ from mpi4py_fft.io import generate_xdmf
153
179
generate_xdmf('variousfields.h5')
154
180
155
181
This will create a number of xdmf-files, one for each group that contains 2D
0 commit comments