PB3D [2.47]
Ideal linear high-n MHD stability in 3-D
Loading...
Searching...
No Matches
HDF5_utilities.f90
Go to the documentation of this file.
1!------------------------------------------------------------------------------!
2!> Utilities pertaining to HDF5 and XDMF
3!!
4!! \see See hdf5_ops for notes on HDF5 and XDMF.
5!------------------------------------------------------------------------------!
7#include <PB3D_macros.h>
9 use messages
10 use str_utilities, only: i2str, r2str, r2strt
11 use hdf5_vars
12 use hdf5
13
14 implicit none
15 private
17#if ldebug
20#endif
21
22#if ldebug
23 ! global variables
24 logical :: debug_set_1d_vars = .false. !< set to true to debug set_1D_vars \ldebug
25#endif
26
27contains
28 !> Sets up the chunk property list and/or the 1D hyperslabs that correspond
29 !! to a local subset of \c lim_tot given by the limits \c lim_loc.
30 !!
31 !! An example for the hyperslab is given in 3 dimensions with size n =
32 !! 5,3,3:
33 !! - for dim = 1, limits: 2..4
34 !! - for dim = 2, limits: 3..3
35 !! - for dim = 3, limits: 2..3.
36 !!
37 !! The 1D equivalent can be represented as
38 !! ```
39 !! [.....][.....][.....] | [.....][.....][.....] | [.....][.....][.....]
40 !! ```
41 !! Now, dimension 1 will only allow for the following elements
42 !! (given by <tt>-</tt>):
43 !! ```
44 !! [.---.][.---.][.---.] | [.---.][.---.][.---.] | [.---.][.---.][.---.]
45 !! ```
46 !! dimension 2 will only allow for the following elements:
47 !! ```
48 !! [.....][.....][-----] | [.....][.....][-----] | [.....][.....][-----]
49 !! ```
50 !! dimension 3 will only allow for the following elements:
51 !! ```
52 !! [.....][.....][.....] | [-----][-----][-----] | [-----][-----][-----]
53 !! ```
54 !! so that the total is given by:
55 !! ```
56 !! [.....][.....][.....] | [.....][.....][.....] | [.....][.....][.---.]
57 !! ```
58 !!
59 !! In practice, it is easiest to work with a full selection, where for every
60 !! dimension the ranges that do not correspond to the range of that
61 !! dimension are taken away. Clearly, if a dimension has the full range,
62 !! nothing will be taken out:
63 !! - \c block_i = \f$n_1 n_2 \cdots n_{i-1} (b_i-a_{i+1}) \f$ ,
64 !! - \c stride_i = \f$n_1 n_2 \cdots n_{i-1} (B_i-A_{i+1}) \f$ ,
65 !! - \c offset_i = \f$n_1 n_2 \cdots n_{i-1} (a_i-A_i) \f$ ,
66 !! - \c count_i = \f$n_{i+1} n_{i+2} \cdots n_N \f$ ,
67 !!
68 !! where \f$a_i\f$ and \f$b_i\f$ represent the local limits of dimension
69 !! \f$i\f$, \f$A_i\f$ and \f$B_i\f$ the total ones and the number of
70 !! dimensions is \f$N\f$, as can be verified.
71 !!
72 !! The chunk property list for creation can be set up so that its size is
73 !! equal to the largest dimensions of full range, or an integer part of that
74 !! if it exceeds 4GB. Since the variables don't need to be used more than
75 !! once, either \c nbytes or \c nslots could be set to 0 in an access
76 !! property list, but this is currently not done.
77 !!
78 !! \return ierr
79 integer function set_1d_vars(lim_tot,lim_loc,space_id,c_plist_id) &
80 &result(ierr)
81#if ldebug
82 use num_vars, only: rank
83#endif
84
85 character(*), parameter :: rout_name = 'set_1D_vars'
86
87 ! input / output
88 integer, intent(in) :: lim_tot(:,:) !< total limits
89 integer, intent(in) :: lim_loc(:,:) !< local limits
90 integer(HID_T), intent(in), optional :: space_id !< dataspace identifier
91 integer(HID_T), intent(inout), optional :: c_plist_id !< chunk creation property list identifier
92
93 ! local variables
94 integer :: id, kd ! counters
95 integer :: n_dims ! nr. of dimensions
96 integer :: n_prod(2) ! n_prod(1) = n_1*n_2*..*n_(i-1), n_prod(2) = n_prod(1)*n_i
97 integer :: div_dim ! first divided dimension
98 integer :: chunk_size ! size of chunk
99 integer(HSIZE_T) :: block(1) ! block size in memory
100 integer(HSIZE_T) :: stride(1) ! stride in memory
101 integer(HSIZE_T) :: count(1) ! nr. of repetitions of block in memory
102 integer(HSIZE_T) :: offset(1) ! offset in memory
103 integer(HSIZE_T) :: chunk_dims(1) ! chunk dimensions
104 real(dp) :: max_chunk_size ! maximum 4 GB (from manual)
105 real(dp) :: min_chunk_size ! minimum 10 MB (from experience)
106 character(len=max_str_ln) :: err_msg ! error message
107#if ldebug
108 integer :: istat ! status
109#endif
110
111 ! initialize ierr
112 ierr = 0
113
114 ! set n_dims
115 n_dims = size(lim_tot,1)
116
117#if ldebug
118 if (size(lim_loc,1).ne.n_dims) then
119 ierr = 1
120 err_msg = 'lim_tot and lim_loc are not compatible'
121 chckerr(err_msg)
122 end if
123 if (size(lim_tot,2).ne.2 .or. size(lim_loc,2).ne.2) then
124 ierr = 1
125 err_msg = 'lim_tot and_lim_loc need to contain 2 columns'
126 chckerr(err_msg)
127 end if
128 do id = 1,n_dims
129 if (lim_tot(id,1).gt.lim_loc(id,1) .or. &
130 &lim_tot(id,2).lt.lim_loc(id,2)) then
131 write(*,*) rank, 'lim_tot = ', lim_tot
132 write(*,*) rank, 'lim_loc = ', lim_loc
133 ierr = 1
134 err_msg = 'Total limits must comprise local ones'
135 chckerr(err_msg)
136 end if
137 end do
138
139 if (debug_set_1d_vars) then
140 write(*,*,iostat=istat) rank, 'in set_1D_vars:'
141 write(*,*,iostat=istat) rank, 'lim_tot_lo = ', lim_tot(:,1)
142 write(*,*,iostat=istat) rank, 'lim_tot_hi = ', lim_tot(:,2)
143 write(*,*,iostat=istat) rank, 'lim_loc_lo = ', lim_loc(:,1)
144 write(*,*,iostat=istat) rank, 'lim_loc_hi = ', lim_loc(:,2)
145 end if
146#endif
147
148 ! initialize divided dimension
149 div_dim = n_dims+1
150
151 ! set hyperslab to be everything if requested
152 if (present(space_id)) then
153 call h5sselect_all_f(space_id,ierr)
154 chckerr('Failed to select hyperslab')
155 end if
156
157 ! loop over dimensions to possibly restrict hyperslab and set div_dim
158 do id = 1,n_dims
159 ! only restrict hyperslab if local range differ from total one
160 if (lim_loc(id,1).gt.lim_tot(id,1) .or. &
161 &lim_loc(id,2).lt.lim_tot(id,2)) then
162 ! set divided dimension if first time
163 if (div_dim.eq.n_dims+1) div_dim = id
164
165 ! calculations if hyperslab restriction requested
166 if (present(space_id)) then
167 ! set auxiliary variables
168 n_prod(1) = product(lim_tot(1:id-1,2)-lim_tot(1:id-1,1)+1)
169 n_prod(2) = n_prod(1)*(lim_tot(id,2)-lim_tot(id,1)+1)
170
171#if ldebug
172 if (debug_set_1d_vars) then
173 write(*,*,iostat=istat) rank, 'dimension', id, 'of', &
174 &n_dims
175 write(*,*,iostat=istat) rank, 'n_prod = ', n_prod
176 end if
177#endif
178
179 block = (lim_loc(id,2)-lim_loc(id,1)+1) * n_prod(1)
180 stride = n_prod(2)
181 offset = (lim_loc(id,1)-lim_tot(id,1)) * n_prod(1)
182 count = 1
183 do kd = id+1,n_dims
184 count = count*(lim_tot(kd,2)-lim_tot(kd,1)+1)
185 end do
186
187#if ldebug
188 if (debug_set_1d_vars) then
189 write(*,*,iostat=istat) rank, 'block, offset, stride, &
190 &count = ', block, offset, stride, count
191 end if
192#endif
193
194 call h5sselect_hyperslab_f(space_id,h5s_select_and_f,&
195 &offset,count,ierr,stride=stride,block=block)
196 chckerr('Failed to select hyperslab')
197 end if
198#if ldebug
199 if (debug_set_1d_vars) then
200 write(*,*,iostat=istat) rank, 'total range DIFFERS from &
201 &local'
202 end if
203 else
204 if (debug_set_1d_vars) then
205 write(*,*,iostat=istat) rank, 'total range EQUAL to local'
206 end if
207#endif
208 end if
209 end do
210
211 ! set chunk property list if requested
212 max_chunk_size = 4.e9_dp / sizeof(1._dp) ! maximum 4 GB (from manual)
213 min_chunk_size = min(10.e6_dp/sizeof(1._dp),&
214 &product(lim_tot(:,2)-lim_tot(:,1)+1._dp)) ! maximum 10 MB (from experience), or limit to total variable size
215 if (present(c_plist_id)) then
216 ! set up variables
217 chunk_size = 1
218 id = 1
219 do while (chunk_size.le.min_chunk_size .and. id.le.size(lim_tot,1))
220 chunk_size = chunk_size * (lim_tot(id,2)-lim_tot(id,1)+1)
221 id = id + 1
222 end do
223#if ldebug
224 if (debug_set_1d_vars) then
225 write(*,*,iostat=istat) rank, 'suggested chunk size', chunk_size
226 end if
227#endif
228 chunk_size = chunk_size / (1 + floor(chunk_size/max_chunk_size)) ! limit to max chunk size
229#if ldebug
230 if (debug_set_1d_vars) then
231 write(*,*,iostat=istat) rank, 'def. chunk size', chunk_size
232 end if
233#endif
234
235 ! set creation property list if provided
236 if (present(c_plist_id)) then
237 chunk_dims = chunk_size
238 call h5pcreate_f(h5p_dataset_create_f,c_plist_id,ierr)
239 chckerr('Failed to create property list')
240 call h5pset_chunk_f(c_plist_id,1,chunk_dims,ierr) ! one dimension for 1D chunk
241 chckerr('Failed to create chunk')
242 end if
243 end if
244 end function set_1d_vars
245
246 !> Probe HDF5 file for group existence.
247 !!
248 !! \return ierr
249 integer function probe_hdf5_group(HDF5_name,group_name,group_exists) &
250 &result(ierr)
251 use mpi_vars, only: hdf5_lock
253
254 character(*), parameter :: rout_name = 'probe_HDF5_group'
255
256 ! input / output
257 character(len=*), intent(in) :: hdf5_name !< name of HDF5 file
258 character(len=*), intent(in) :: group_name !< name of group to probe for
259 logical, intent(inout) :: group_exists !< whether group exists
260
261 ! local variables
262 integer :: istat ! status
263 integer(HID_T) :: hdf5_i ! file identifier
264 integer(HID_T) :: group_id ! group identifier
265
266 ! initialize ierr
267 ierr = 0
268
269 ! initialize FORTRAN predefined datatypes
270 call h5open_f(ierr)
271 chckerr('Failed to initialize HDF5')
272
273 ! wait for file access in a non-blocking way
274 ierr = lock_req_acc(hdf5_lock,blocking=.false.)
275 chckerr('')
276
277 ! open the file
278 call h5fopen_f(hdf5_name,h5f_acc_rdonly_f,hdf5_i,ierr)
279 chckerr('Failed to open file. Does it exist?')
280
281 ! disable error messages
282 call h5eset_auto_f(0,ierr)
283 chckerr('Failed to disable error printing')
284
285 ! try to open group
286 call h5gopen_f(hdf5_i,group_name,group_id,istat)
287 group_exists = istat.eq.0
288
289 ! reenable error messages
290 call h5eset_auto_f(1,ierr)
291 chckerr('Failed to enable error printing')
292
293 ! close group
294 if (group_exists) then
295 call h5gclose_f(group_id,ierr)
296 chckerr('Failed to close head group')
297 end if
298
299 ! close the HDF5 file
300 call h5fclose_f(hdf5_i,ierr)
301 chckerr('failed to close HDF5 file')
302
303 ! return lock
305 chckerr('')
306
307 ! close FORTRAN interfaces and HDF5 library.
308 call h5close_f(ierr)
309 chckerr('Failed to close FORTRAN HDF5 interface')
310 end function probe_hdf5_group
311
312#if ldebug
313 !> Lists all variables in a HDF5 group.
314 !!
315 !! \ldebug
316 !!
317 !! \return ierr
318 integer function list_all_vars_in_group(group_id) result(ierr)
319 character(*), parameter :: rout_name = 'list_all_vars_in_group'
320
321 ! input / output
322 integer(HID_T), intent(in) :: group_id !< group identifier
323
324 ! local variables
325 integer :: storage_type ! type of storage used in HDF5 file
326 integer :: nr_lnks ! number of links in group
327 integer :: max_corder ! current maximum creation order value for group
328 integer(HSIZE_T) :: id ! counter
329 integer :: id_loc ! local id
330 integer(SIZE_T) :: name_len ! length of name of group
331 character(len=max_str_ln) :: var_name ! name of variable
332
333 ! get number of objects in group
334 call h5gget_info_f(group_id,storage_type,nr_lnks,max_corder,&
335 &ierr)
336 chckerr('Failed to get group info')
337
338 ! user output
339 call writo('The group has '//trim(i2str(nr_lnks))//' elements')
340
341 ! loop over all elements
342 do id = 1,nr_lnks
343 ! get variable name
344 call h5lget_name_by_idx_f(group_id,'.',h5_index_name_f,&
345 &h5_iter_native_f,id-1,var_name,ierr,size=name_len)
346 chckerr('Failed to get name')
347
348 ! user output
349 id_loc = int(id,1)
350 call writo('Element '//trim(i2str(id_loc))//'/'//&
351 &trim(i2str(nr_lnks))//': '//trim(var_name))
352 end do
353 end function list_all_vars_in_group
354#endif
355end module hdf5_utilities
Utilities pertaining to HDF5 and XDMF.
integer function, public set_1d_vars(lim_tot, lim_loc, space_id, c_plist_id)
Sets up the chunk property list and/or the 1D hyperslabs that correspond to a local subset of lim_tot...
integer function, public list_all_vars_in_group(group_id)
Lists all variables in a HDF5 group.
integer function, public probe_hdf5_group(hdf5_name, group_name, group_exists)
Probe HDF5 file for group existence.
logical, public debug_set_1d_vars
set to true to debug set_1D_vars
Variables pertaining to HDF5 and XDMF.
Definition HDF5_vars.f90:4
Numerical utilities related to giving output.
Definition messages.f90:4
subroutine, public writo(input_str, persistent, error, warning, alert)
Write output to file identified by output_i.
Definition messages.f90:275
Numerical utilities related to MPI.
integer function, public lock_req_acc(lock, blocking)
Request access to lock of a BL (blocking) or optionally a NB (non-blocking) type.
integer function, public lock_return_acc(lock)
Returns access to a lock.
Variables pertaining to MPI.
Definition MPI_vars.f90:4
type(lock_type), public hdf5_lock
HDF5 lock.
Definition MPI_vars.f90:76
Numerical variables used by most other modules.
Definition num_vars.f90:4
integer, parameter, public dp
double precision
Definition num_vars.f90:46
character(len=7), public script_dir
directory where to save scripts for plots
Definition num_vars.f90:154
integer, parameter, public max_str_ln
maximum length of strings
Definition num_vars.f90:50
character(len=5), public plot_dir
directory where to save plots
Definition num_vars.f90:153
integer, public rank
MPI rank.
Definition num_vars.f90:68
character(len=4), public data_dir
directory where to save data for plots
Definition num_vars.f90:155
Operations on strings.
elemental character(len=max_str_ln) function, public i2str(k)
Convert an integer to string.
elemental character(len=max_str_ln) function, public r2str(k)
Convert a real (double) to string.
elemental character(len=max_str_ln) function, public r2strt(k)
Convert a real (double) to string.