FileType_HDF5.f90 265 KB
Newer Older
1
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++!
2
3
4
5
6
7
!                          Futility Development Group                          !
!                             All rights reserved.                             !
!                                                                              !
! Futility is a jointly-maintained, open-source project between the University !
! of Michigan and Oak Ridge National Laboratory.  The copyright and license    !
! can be found in LICENSE.txt in the head directory of this repository.        !
8
9
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++!
!> @brief Utility module for I/O defines the HDF5 file type object.
10
!>
11
12
13
14
15
!> This type is an extension of the base file type implemented in FileType_Base.
!> It contains specific routines for interrogating an HDF5-format binary file
!> and for writing to and reading from records in an HDF5 file. Since the module
!> relies of the HDF5 library to be present, the entire module is disabled and
!> not compiled if the build system does not have HDF5 support enabled.
16
!>
17
!> There are actually two versions of the HDF library, a serial implementation
18
19
20
!> and a parallel implementation. The latter relies on MPI and has separate
!> subroutine calls, so there will need to be preprocessor directives switching
!> between the two depending on which library is present.
21
!>
22
23
24
25
!> It is important to note that the read and write routines are typed to use
!> fixed precision (for instance SSK and SDK instead of SRK). This is important
!> because we need to use the supported types of the HDF5 library and file
!> format.
26
27
!++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++!
MODULE FileType_HDF5
bkochuna's avatar
bkochuna committed
28
#include "Futility_DBC.h"
Graham, Aaron's avatar
Graham, Aaron committed
29
30
31
USE Futility_DBC
USE ISO_FORTRAN_ENV
USE ISO_C_BINDING
32
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
33
USE HDF5
34
#endif
Graham, Aaron's avatar
Graham, Aaron committed
35
36
37
38
39
40
41
USE IntrType
USE Strings
USE ExceptionHandler
USE IO_Strings
USE ParameterLists
USE ParallelEnv
USE FileType_Base
42

Graham, Aaron's avatar
Graham, Aaron committed
43
44
IMPLICIT NONE
PRIVATE
45

46
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
47
INTEGER,PRIVATE :: error
48
#endif
49

Graham, Aaron's avatar
Graham, Aaron committed
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
!> Name of the module
CHARACTER(LEN=*),PARAMETER :: modName='FileType_HDF5'

!> Set maximum string length
INTEGER(SIK),PARAMETER :: MAXSTRLEN=1024

!> This type extends the base file type, and adds support for writing to and
!List of Public Members
PUBLIC :: HDF5FileType
PUBLIC :: HDF5FilePtrArrayType
PUBLIC :: HDF5Open
PUBLIC :: HDF5Close
PUBLIC :: HDF5Quiet

!> reading from HDF5 binary files. As implemented, there are three modes for
!> accessing a file can be opened as: 'read' and 'write' and 'new'. Read mode
!> opens an already extant HDF5 file and allows the client code to interrogate
!> that file and extract data without permissions to alter the file. Write
!> mode opens an extant HDF5 file and allows the client code to alter its
!> contents. New mode overwrites any file by the same name and starts from
!> scratch.
TYPE,EXTENDS(BaseFileType) :: HDF5FileType
  !> Initialization status
  LOGICAL(SBK) :: isInit=.FALSE.
  !> Whether or not the file uses compression for writing
  LOGICAL(SBK) :: hasCompression=.FALSE.
  !> Option for gzip compression -1 (no filter) or [0-9].
  !> these options are defined by HDF5.
  !> https://support.hdfgroup.org/HDF5/doc/RM/RM_H5P.html#Property-SetDeflate
  INTEGER(SIK),PRIVATE :: zlibOpt=-1
  !> The 'new' status of a file
  LOGICAL(SBK),PRIVATE :: newstat=.FALSE.
  !> Full path to the file
  TYPE(StringType) :: fullname
  !> The unit number of the file
  INTEGER(SIK),PRIVATE :: unitno=-1
  !> Parallel environment for MPI I/O
  TYPE(MPI_EnvType),POINTER  :: pe => NULL()
  !> When .TRUE., file data can be overwritten
  LOGICAL(SBK),PRIVATE :: overwriteStat=.FALSE.
90

91
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
92
93
  !> File id assigned by the HDF5 library when file is opened
  INTEGER(HID_T) :: file_id=0
94
95
#endif

Graham, Aaron's avatar
Graham, Aaron committed
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
  CONTAINS
    !> @copybrief FileType_HDF5::init_HDF5FileType
    !> @copydetails FileType_HDF5::init_HDF5FileType
    PROCEDURE,PASS :: init => init_HDF5FileType
    !> @copybrief FileType_HDF5::clear_HDF5FileType
    !> @copydetails FileType_HDF5::clear_HDF5FileType
    PROCEDURE,PASS :: clear => clear_HDF5FileType
    !> @copybrief FileType_HDF5::setOverwriteStat_file
    !> @copydetails FileType_HDF5::setOverwriteStat_file
    PROCEDURE,PASS :: setOverwriteStat => setOverwriteStat_file
    !> @copybrief FileType_HDF5::open_HDF5FileType
    !> @copydetails FileType_HDF5::open_HDF5FileType
    PROCEDURE,PASS :: fopen => open_HDF5FileType
    !> @copybrief FileType_HDF5::close_HDF5FileType
    !> @copydetails FileType_HDF5::close_HDF5FileType
    PROCEDURE,PASS :: fclose => close_HDF5FileType
    !> @copybrief FileType_HDF5::delete_HDF5FileType
    !> @copydetails FileType_HDF5::delete_HDF5FileType
    PROCEDURE,PASS :: fdelete => delete_HDF5FileType
    !> @copybrief FileType_HDF5::getUnitNo_HFD5FileType
    !> @copydetails FileType_HDF5::getUnitNo_HDF5FileType
    PROCEDURE,PASS :: getUnitNo => getUnitNo_HDF5FileType
    !> @copybrief FileType_HDF5::isNew_HDF5FileType
    !> @copydetails FileType_HDF5::isNew_HDF5FileType
    PROCEDURE,PASS :: isNew => isNew_HDF5FileType
    !> @copybrief FileType_HDF5::setNewStat_HDF5FileType
    !> @copydetails FileType_HDF5::setNewStat_HDF5FileType
    PROCEDURE,PASS,PRIVATE :: setNewStat => setNewStat_HDF5FileType
    !> @copybrief FileType_HDF5::ls_HDF5FileType
    !> @copydetails FileType_HDF5::ls_HDF5FileType
    PROCEDURE,PASS :: ls => ls_HDF5FileType
    !> @copybrief FileType_HDF5::mkdir_HDF5FileType
    !> @copydetails FileType_HDF5::mkdir_HDF5FileType
    PROCEDURE,PASS :: mkdir => mkdir_HDF5FileType
    !> @copybrief FileType_HDF5::mkalldir_HDF5FileType
    !> @copydetails FileType_HDF5::mkalldir_HDF5FileType
    PROCEDURE,PASS :: mkalldir => mkalldir_HDF5FileType
    !> @copybrief FileType_HDF5::ngrp_HDF5FileType
    !> @copydetails FileType_HDF5::ngrp_HDF5FileType
    PROCEDURE,PASS :: ngrp => ngrp_HDF5FileType
    !> @copybrief FileType_HDF5::isgrp_HDF5FileType
    !> @copydetails FileType_HDF5::isgrp_HDF5FileType
    PROCEDURE,PASS :: isGroup => isgrp_HDF5FileType
    !> @copybrief FileType_HDF5::pathexists_HDF5FileType
    !> @copydetails FileType_HDF5::pathexists_HDF5FileType
    PROCEDURE,PASS :: pathExists => pathexists_HDF5FileType
    !> @copybrief FileType_HDF5::createHardLink_HDF5FileType
    !> @copydetails FileType_HDF5::createHardLink_HDF5FileType
    PROCEDURE,PASS :: createHardLink => createHardLink_HDF5FileType
    !> @copybrief FileType_HDF5::getChunkSize_HDF5FileType
    !> @copydetails FileType_HDF5::getChunkSize_HDF5FileType
    PROCEDURE,PASS :: getChunkSize => getChunkSize_HDF5FileType
    !> @copybrief FileType_HDF5::isCompressed_HDF5FileType
    !> @copydetails FileType_HDF5::isCompressed_HDF5FileType
    PROCEDURE,PASS :: isCompressed => isCompressed_HDF5FileType
    !> @copybrief FileType_HDF5::write_d0
    !> @copydoc FileType_HDF5::write_d0
    PROCEDURE,PASS,PRIVATE :: write_d0
    !> @copybrief FileType_HDF5::write_d1
    !> @copydoc FileType_HDF5::write_d1
    PROCEDURE,PASS,PRIVATE :: write_d1
    !> @copybrief FileType_HDF5::write_d2
    !> @copydoc FileType_HDF5::write_d2
    PROCEDURE,PASS,PRIVATE :: write_d2
    !> @copybrief FileType_HDF5::write_d3
    !> @copydoc FileType_HDF5::write_d3
    PROCEDURE,PASS,PRIVATE :: write_d3
    !> @copybrief FileType_HDF5::write_d4
    !> @copydoc FileType_HDF5::write_d4
    PROCEDURE,PASS,PRIVATE :: write_d4
    !> @copybrief FileType_HDF5::write_d5
    !> @copydoc FileType_HDF5::write_d5
    PROCEDURE,PASS,PRIVATE :: write_d5
    !> @copybrief FileType_HDF5::write_d6
    !> @copydoc FileType_HDF5::write_d6
    PROCEDURE,PASS,PRIVATE :: write_d6
    !> @copybrief FileType_HDF5::write_d7
    !> @copydoc FileType_HDF5::write_d7
    PROCEDURE,PASS,PRIVATE :: write_d7
    !> @copybrief FileType_HDF5::write_s0
    !> @copydoc FileType_HDF5::write_s0
    PROCEDURE,PASS,PRIVATE :: write_s0
    !> @copybrief FileType_HDF5::write_s1
    !> @copydoc FileType_HDF5::write_s1
    PROCEDURE,PASS,PRIVATE :: write_s1
    !> @copybrief FileType_HDF5::write_s2
    !> @copydoc FileType_HDF5::write_s2
    PROCEDURE,PASS,PRIVATE :: write_s2
    !> @copybrief FileType_HDF5::write_s3
    !> @copydoc FileType_HDF5::write_s3
    PROCEDURE,PASS,PRIVATE :: write_s3
    !> @copybrief FileType_HDF5::write_s4
    !> @copydoc FileType_HDF5::write_s4
    PROCEDURE,PASS,PRIVATE :: write_s4
    !> @copybrief FileType_HDF5::write_s5
    !> @copydoc FileType_HDF5::write_s5
    PROCEDURE,PASS,PRIVATE :: write_s5
    !> @copybrief FileType_HDF5::write_s6
    !> @copydoc FileType_HDF5::write_s6
    PROCEDURE,PASS,PRIVATE :: write_s6
    !> @copybrief FileType_HDF5::write_s7
    !> @copydoc FileType_HDF5::write_s7
    PROCEDURE,PASS,PRIVATE :: write_s7
    !> @copybrief FileType_HDF5::write_b0
    !> @copydoc FileType_HDF5::write_b0
    PROCEDURE,PASS,PRIVATE :: write_b0
    !> @copybrief FileType_HDF5::write_b1
    !> @copydoc FileType_HDF5::write_b1
    PROCEDURE,PASS,PRIVATE :: write_b1
    !> @copybrief FileType_HDF5::write_b2
    !> @copydoc FileType_HDF5::write_b2
    PROCEDURE,PASS,PRIVATE :: write_b2
    !> @copybrief FileType_HDF5::write_b3
    !> @copydoc FileType_HDF5::write_b3
    PROCEDURE,PASS,PRIVATE :: write_b3
    !> @copybrief FileType_HDF5::write_n0
    !> @copydoc FileType_HDF5::write_n0
    PROCEDURE,PASS,PRIVATE :: write_n0
    !> @copybrief FileType_HDF5::write_n1
    !> @copydoc FileType_HDF5::write_n1
    PROCEDURE,PASS,PRIVATE :: write_n1
    !> @copybrief FileType_HDF5::write_n2
    !> @copydoc FileType_HDF5::write_n2
    PROCEDURE,PASS,PRIVATE :: write_n2
    !> @copybrief FileType_HDF5::write_n3
    !> @copydoc FileType_HDF5::write_n3
    PROCEDURE,PASS,PRIVATE :: write_n3
    !> @copybrief FileType_HDF5::write_n4
    !> @copydoc FileType_HDF5::write_n4
    PROCEDURE,PASS,PRIVATE :: write_n4
    !> @copybrief FileType_HDF5::write_n5
    !> @copydoc FileType_HDF5::write_n5
    PROCEDURE,PASS,PRIVATE :: write_n5
    !> @copybrief FileType_HDF5::write_n6
    !> @copydoc FileType_HDF5::write_n6
    PROCEDURE,PASS,PRIVATE :: write_n6
    !> @copybrief FileType_HDF5::write_n7
    !> @copydoc FileType_HDF5::write_n7
    PROCEDURE,PASS,PRIVATE :: write_n7
    !> @copybrief FileType_HDF5::write_l0
    !> @copydoc FileType_HDF5::write_l0
    PROCEDURE,PASS,PRIVATE :: write_l0
    !> @copybrief FileType_HDF5::write_l1
    !> @copydoc FileType_HDF5::write_l1
    PROCEDURE,PASS,PRIVATE :: write_l1
    !> @copybrief FileType_HDF5::write_l2
    !> @copydoc FileType_HDF5::write_l2
    PROCEDURE,PASS,PRIVATE :: write_l2
    !> @copybrief FileType_HDF5::write_l3
    !> @copydoc FileType_HDF5::write_l3
    PROCEDURE,PASS,PRIVATE :: write_l3
    !> @copybrief FileType_HDF5::write_l4
    !> @copydoc FileType_HDF5::write_l4
    PROCEDURE,PASS,PRIVATE :: write_l4
    !> @copybrief FileType_HDF5::write_l5
    !> @copydoc FileType_HDF5::write_l5
    PROCEDURE,PASS,PRIVATE :: write_l5
    !> @copybrief FileType_HDF5::write_l6
    !> @copydoc FileType_HDF5::write_l6
    PROCEDURE,PASS,PRIVATE :: write_l6
    !> @copybrief FileType_HDF5::write_l7
    !> @copydoc FileType_HDF5::write_l7
    PROCEDURE,PASS,PRIVATE :: write_l7
    !> @copybrief FileType_HDF5::write_st0
    !> @copydoc FileType_HDF5::write_st0
    PROCEDURE,PASS,PRIVATE :: write_st0
    !> @copybrief FileType_HDF5::write_st1_helper
    !> @copydoc FileType_HDF5::write_st1_helper
    PROCEDURE,PASS,PRIVATE :: write_st1_helper
    !> @copybrief FileType_HDF5::write_st1
    !> @copydoc FileType_HDF5::write_st1
    PROCEDURE,PASS,PRIVATE :: write_st1
    !> @copybrief FileType_HDF5::write_st2_helper
    !> @copydoc FileType_HDF5::write_st2_helper
    PROCEDURE,PASS,PRIVATE :: write_st2_helper
    !> @copybrief FileType_HDF5::write_st2
    !> @copydoc FileType_HDF5::write_st2
    PROCEDURE,PASS,PRIVATE :: write_st2
    !> @copybrief FileType_HDF5::write_st3_helper
    !> @copydoc FileType_HDF5::write_st3_helper
    PROCEDURE,PASS,PRIVATE :: write_st3_helper
    !> @copybrief FileType_HDF5::write_st3
    !> @copydoc FileType_HDF5::write_st3
    PROCEDURE,PASS,PRIVATE :: write_st3
    !> @copybrief FileType_HDF5::write_c1
    !> @copydoc FileType_HDF5::write_c1
    PROCEDURE,PASS,PRIVATE :: write_c1
    !> @copybrief FileType_HDF5::write_pList
    !> @copydoc FileType_HDF5::write_pList
    PROCEDURE,PASS,PRIVATE :: write_pList
    !> Generic typebound interface for all @c write operations
    GENERIC :: fwrite => write_d0, write_d1, write_d2, write_d3, write_d4,   &
        write_d5, write_d6, write_d7, write_s0, write_s1, write_s2, write_s3, &
        write_s4, write_s5, write_s6, write_s7, write_b0, write_b1, write_b2, &
        write_b3, write_n0, write_n1, write_n2, write_n3, write_n4, write_n5, &
        write_n6, write_n7, write_st0, write_st1_helper, write_st1, write_st2_helper,  &
        write_st2, write_st3_helper, write_st3, write_l0, write_l1, write_l2, &
        write_l3, write_l4, write_l5, write_l6, write_l7,write_c1, write_pList
    !> @copybrief FileType_HDF5::read_d0
    !> @copydoc FileType_HDF5::read_d0
    PROCEDURE,PASS,PRIVATE :: read_d0
    !> @copybrief FileType_HDF5::read_d1
    !> @copydoc FileType_HDF5::read_d1
    PROCEDURE,PASS,PRIVATE :: read_d1
    !> @copybrief FileType_HDF5::read_d2
    !> @copydoc FileType_HDF5::read_d2
    PROCEDURE,PASS,PRIVATE :: read_d2
    !> @copybrief FileType_HDF5::read_d3
    !> @copydoc FileType_HDF5::read_d3
    PROCEDURE,PASS,PRIVATE :: read_d3
    !> @copybrief FileType_HDF5::read_d4
    !> @copydoc FileType_HDF5::read_d4
    PROCEDURE,PASS,PRIVATE :: read_d4
    !> @copybrief FileType_HDF5::read_d5
    !> @copydoc FileType_HDF5::read_d5
    PROCEDURE,PASS,PRIVATE :: read_d5
    !> @copybrief FileType_HDF5::read_d6
    !> @copydoc FileType_HDF5::read_d6
    PROCEDURE,PASS,PRIVATE :: read_d6
    !> @copybrief FileType_HDF5::read_d7
    !> @copydoc FileType_HDF5::read_d7
    PROCEDURE,PASS,PRIVATE :: read_d7
    !> @copybrief FileType_HDF5::read_dp4
    !> @copydoc FileType_HDF5::read_dp4
    PROCEDURE,PASS,PRIVATE :: read_dp4
    !> @copybrief FileType_HDF5::read_s0
    !> @copydoc FileType_HDF5::read_s0
    PROCEDURE,PASS,PRIVATE :: read_s0
    !> @copybrief FileType_HDF5::read_s1
    !> @copydoc FileType_HDF5::read_s1
    PROCEDURE,PASS,PRIVATE :: read_s1
    !> @copybrief FileType_HDF5::read_s2
    !> @copydoc FileType_HDF5::read_s2
    PROCEDURE,PASS,PRIVATE :: read_s2
    !> @copybrief FileType_HDF5::read_s3
    !> @copydoc FileType_HDF5::read_s3
    PROCEDURE,PASS,PRIVATE :: read_s3
    !> @copybrief FileType_HDF5::read_s4
    !> @copydoc FileType_HDF5::read_s4
    PROCEDURE,PASS,PRIVATE :: read_s4
    !> @copybrief FileType_HDF5::read_s5
    !> @copydoc FileType_HDF5::read_s5
    PROCEDURE,PASS,PRIVATE :: read_s5
    !> @copybrief FileType_HDF5::read_s6
    !> @copydoc FileType_HDF5::read_s6
    PROCEDURE,PASS,PRIVATE :: read_s6
    !> @copybrief FileType_HDF5::read_s7
    !> @copydoc FileType_HDF5::read_s7
    PROCEDURE,PASS,PRIVATE :: read_s7
    !> @copybrief FileType_HDF5::read_b0
    !> @copydoc FileType_HDF5::read_b0
    PROCEDURE,PASS,PRIVATE :: read_b0
    !> @copybrief FileType_HDF5::read_b1
    !> @copydoc FileType_HDF5::read_b1
    PROCEDURE,PASS,PRIVATE :: read_b1
    !> @copybrief FileType_HDF5::read_b2
    !> @copydoc FileType_HDF5::read_b2
    PROCEDURE,PASS,PRIVATE :: read_b2
    !> @copybrief FileType_HDF5::read_b3
    !> @copydoc FileType_HDF5::read_b3
    PROCEDURE,PASS,PRIVATE :: read_b3
    !> @copybrief FileType_HDF5::read_n0
    !> @copydoc FileType_HDF5::read_n0
    PROCEDURE,PASS,PRIVATE :: read_n0
    !> @copybrief FileType_HDF5::read_n1
    !> @copydoc FileType_HDF5::read_n1
    PROCEDURE,PASS,PRIVATE :: read_n1
    !> @copybrief FileType_HDF5::read_n2
    !> @copydoc FileType_HDF5::read_n2
    PROCEDURE,PASS,PRIVATE :: read_n2
    !> @copybrief FileType_HDF5::read_n3
    !> @copydoc FileType_HDF5::read_n3
    PROCEDURE,PASS,PRIVATE :: read_n3
    !> @copybrief FileType_HDF5::read_n4
    !> @copydoc FileType_HDF5::read_n4
    PROCEDURE,PASS,PRIVATE :: read_n4
    !> @copybrief FileType_HDF5::read_n5
    !> @copydoc FileType_HDF5::read_n5
    PROCEDURE,PASS,PRIVATE :: read_n5
    !> @copybrief FileType_HDF5::read_n6
    !> @copydoc FileType_HDF5::read_n6
    PROCEDURE,PASS,PRIVATE :: read_n6
    !> @copybrief FileType_HDF5::read_n7
    !> @copydoc FileType_HDF5::read_n7
    PROCEDURE,PASS,PRIVATE :: read_n7
    !> @copybrief FileType_HDF5::read_l0
    !> @copydoc FileType_HDF5::read_l0
    PROCEDURE,PASS,PRIVATE :: read_l0
    !> @copybrief FileType_HDF5::read_l1
    !> @copydoc FileType_HDF5::read_l1
    PROCEDURE,PASS,PRIVATE :: read_l1
    !> @copybrief FileType_HDF5::read_l2
    !> @copydoc FileType_HDF5::read_l2
    PROCEDURE,PASS,PRIVATE :: read_l2
    !> @copybrief FileType_HDF5::read_l3
    !> @copydoc FileType_HDF5::read_l3
    PROCEDURE,PASS,PRIVATE :: read_l3
    !> @copybrief FileType_HDF5::read_l4
    !> @copydoc FileType_HDF5::read_l4
    PROCEDURE,PASS,PRIVATE :: read_l4
    !> @copybrief FileType_HDF5::read_l5
    !> @copydoc FileType_HDF5::read_l5
    PROCEDURE,PASS,PRIVATE :: read_l5
    !> @copybrief FileType_HDF5::read_l6
    !> @copydoc FileType_HDF5::read_l6
    PROCEDURE,PASS,PRIVATE :: read_l6
    !> @copybrief FileType_HDF5::read_l7
    !> @copydoc FileType_HDF5::read_l7
    PROCEDURE,PASS,PRIVATE :: read_l7
    !> @copybrief FileType_HDF5::read_st0_helper
    !> @copydoc FileType_HDF5::read_st0_helper
    PROCEDURE,PASS,PRIVATE :: read_st0_helper
    !> @copybrief FileType_HDF5::read_st0
    !> @copydoc FileType_HDF5::read_st0
    PROCEDURE,PASS,PRIVATE :: read_st0
    !> @copybrief FileType_HDF5::read_st1_helper
    !> @copydoc FileType_HDF5::read_st1_helper
    PROCEDURE,PASS,PRIVATE :: read_st1_helper
    !> @copybrief FileType_HDF5::read_st1
    !> @copydoc FileType_HDF5::read_st1
    PROCEDURE,PASS,PRIVATE :: read_st1
    !> @copybrief FileType_HDF5::read_st2_helper
    !> @copydoc FileType_HDF5::read_st2_helper
    PROCEDURE,PASS,PRIVATE :: read_st2_helper
    !> @copybrief FileType_HDF5::read_st2
    !> @copydoc FileType_HDF5::read_st2
    PROCEDURE,PASS,PRIVATE :: read_st2
    !> @copybrief FileType_HDF5::read_st3_helper
    !> @copydoc FileType_HDF5::read_st3_helper
    PROCEDURE,PASS,PRIVATE :: read_st3_helper
    !> @copybrief FileType_HDF5::read_st3
    !> @copydoc FileType_HDF5::read_st3
    PROCEDURE,PASS,PRIVATE :: read_st3
    !> @copybrief FileType_HDF5::read_c1
    !> @copydoc FileType_HDF5::read_c1
    PROCEDURE,PASS,PRIVATE :: read_c1
    !> @copybrief FileType_HDF5::read_pList
    !> @copydoc FileType_HDF5::read_pList
    PROCEDURE,PASS,PRIVATE :: read_pList
    !> Generic typebound interface for all @c read operations
    GENERIC :: fread => read_d1, read_d2, read_d3, read_d4, read_d5, read_d6,&
437
438
439
440
441
        read_d7, read_s1, read_s2, read_s3, read_s4, read_s5, read_s6, read_s7,&
        read_l1, read_l2, read_l3, read_l4, read_l5, read_l6, read_l7, read_b1,&
        read_b2, read_b3, read_st0_helper,read_st0, read_d0, read_s0, read_l0, &
        read_b0, read_st1, read_st1_helper,read_st2, read_st2_helper, read_st3,&
        read_st3_helper, read_n0, read_n1, read_n2, read_n3, read_n4, read_n5, &
442
        read_n6, read_n7, read_c1, read_pList
Graham, Aaron's avatar
Graham, Aaron committed
443
444
445
    !> Generic typebound interface for pointer-based read operations
    GENERIC :: freadp => read_dp4
    !> @copybrief FileType_HDF5::write_attribute_st0
Graham, Aaron's avatar
Graham, Aaron committed
446
    !> @copydoc FileType_HDF5_write_attribute_st0
Graham, Aaron's avatar
Graham, Aaron committed
447
448
    PROCEDURE,PASS,PRIVATE :: write_attribute_st0
    !> @copybrief FileType_HDF5::write_attribute_c0
Graham, Aaron's avatar
Graham, Aaron committed
449
    !> @copydoc FileType_HDF5_write_attribute_c0
Graham, Aaron's avatar
Graham, Aaron committed
450
451
    PROCEDURE,PASS,PRIVATE :: write_attribute_c0
    !> @copybrief FileType_HDF5::write_attribute_i0
Graham, Aaron's avatar
Graham, Aaron committed
452
    !> @copydoc FileType_HDF5_write_attribute_i0
Graham, Aaron's avatar
Graham, Aaron committed
453
454
    PROCEDURE,PASS,PRIVATE :: write_attribute_i0
    !> @copybrief FileType_HDF5::write_attribute_d0
Graham, Aaron's avatar
Graham, Aaron committed
455
    !> @copydoc FileType_HDF5_write_attribute_d0
Graham, Aaron's avatar
Graham, Aaron committed
456
    PROCEDURE,PASS,PRIVATE :: write_attribute_d0
457
458
459
    !> @copybrief FileType_HDF5::write_attribute_b0
    !> @copydoc FileType_HDF5_write_attribute_b0
    PROCEDURE,PASS,PRIVATE :: write_attribute_b0
Graham, Aaron's avatar
Graham, Aaron committed
460
461
    !> Generic typebound interface for all @c attribute writes
    GENERIC ::  write_attribute => write_attribute_st0, write_attribute_c0,&
462
        write_attribute_i0, write_attribute_d0,write_attribute_b0
Graham, Aaron's avatar
Graham, Aaron committed
463
    !> @copybrief FileType_HDF5::read_str_attribure_help
Graham, Aaron's avatar
Graham, Aaron committed
464
    !> @copydoc FileType_HDF5_read_str_attribure_help
Graham, Aaron's avatar
Graham, Aaron committed
465
466
    PROCEDURE,PASS,PRIVATE :: read_attribute_st0
    !> @copybrief FileType_HDF5::read_attribute_c0
Graham, Aaron's avatar
Graham, Aaron committed
467
    !> @copydoc FileType_HDF5_read_attribute_c0
Graham, Aaron's avatar
Graham, Aaron committed
468
469
    PROCEDURE,PASS,PRIVATE :: read_attribute_c0
    !> @copybrief FileType_HDF5::read_attribute_i0
Graham, Aaron's avatar
Graham, Aaron committed
470
    !> @copydoc FileType_HDF5_read_attribute_i0
Graham, Aaron's avatar
Graham, Aaron committed
471
472
    PROCEDURE,PASS,PRIVATE :: read_attribute_i0
    !> @copybrief FileType_HDF5::read_attribute_d0
Graham, Aaron's avatar
Graham, Aaron committed
473
    !> @copydoc FileType_HDF5_read_attribute_d0
Graham, Aaron's avatar
Graham, Aaron committed
474
    PROCEDURE,PASS,PRIVATE :: read_attribute_d0
475
476
477
    !> @copybrief FileType_HDF5::read_attribute_b0
    !> @copydoc FileType_HDF5_read_attribute_b0
    PROCEDURE,PASS,PRIVATE :: read_attribute_b0
Graham, Aaron's avatar
Graham, Aaron committed
478
479
    !> Generic typebound interface for all @c attribute writes
    GENERIC :: read_attribute => read_attribute_st0, read_attribute_c0,&
480
        read_attribute_i0, read_attribute_d0,read_attribute_b0
Graham, Aaron's avatar
Graham, Aaron committed
481
482
483
484
485
486
    !> @copybrief FileType_HDF5::getDataShape
    !> @copydoc FileType_HDF5::getDataShape
    PROCEDURE,PASS :: getDataShape
    !> @copybrief FileType_HDF5::getDataType
    !> @copydoc FileType_HDF5::getDataType
    PROCEDURE,PASS :: getDataType
Graham, Aaron's avatar
Graham, Aaron committed
487
ENDTYPE
488

Graham, Aaron's avatar
Graham, Aaron committed
489
490
491
!> @brief Type that is a container so as to have an array of pointers to HDF5 files
TYPE :: HDF5FilePtrArrayType
  !> @brief Pointer to a HDF5 file type
492
  CLASS(HDF5FileType),POINTER :: h5 => NULL()
Graham, Aaron's avatar
Graham, Aaron committed
493
ENDTYPE HDF5FilePtrArrayType
494

495
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
496
497
498
499
!> Variable for keeping track of the number of hdf5 files initialized
!> This variable will be used in logic to call the h5close_f(error)
!> which closes the interface.
INTEGER(SIK),SAVE :: nhdf5fileinuse=0
500
#endif
Graham, Aaron's avatar
Graham, Aaron committed
501
502
503
!> Variable to make sure that the hdf5 interface was opened, and thus
!> can then be closed.
LOGICAL(SBK),SAVE :: libh5Open=.FALSE.
504
505
!
!===============================================================================
Graham, Aaron's avatar
Graham, Aaron committed
506
CONTAINS
507
!
508
!-------------------------------------------------------------------------------
Graham, Aaron's avatar
Graham, Aaron committed
509
510
511
SUBROUTINE HDF5Open()
  INTEGER(SIK) :: herr
  herr=-1
512
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
513
  IF(.NOT.libh5Open) CALL H5open_f(herr)
514
#endif
Graham, Aaron's avatar
Graham, Aaron committed
515
516
  IF(herr == 0) libh5Open=.TRUE.
ENDSUBROUTINE HDF5Open
517
518
!
!-------------------------------------------------------------------------------
Graham, Aaron's avatar
Graham, Aaron committed
519
520
521
SUBROUTINE HDF5Close()
  INTEGER(SIK) :: herr
  herr=-1
522
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
523
  IF(libh5Open) CALL H5close_f(herr)
524
#endif
Graham, Aaron's avatar
Graham, Aaron committed
525
526
  IF(herr == 0) libh5Open=.FALSE.
ENDSUBROUTINE HDF5Close
527
!
528
!-------------------------------------------------------------------------------
529
530
!> @brief   Enable/disable HDF5 exception writing
!> @param   quiet Set to .TRUE. to disable HDF5 exceptions from being printed
Graham, Aaron's avatar
Graham, Aaron committed
531
532
SUBROUTINE HDF5Quiet(quiet)
  LOGICAL,INTENT(IN) :: quiet
533
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
534
535
536
537
538
  IF(quiet) THEN
     CALL h5eset_auto_f(0, error)
  ELSE
     CALL h5eset_auto_f(1, error)
  ENDIF
539
#endif
Graham, Aaron's avatar
Graham, Aaron committed
540
ENDSUBROUTINE
541
542
543

!
!-------------------------------------------------------------------------------
544
!> @brief Initializes an HDF5 file object.
545
!> @param thisHDF5File the object to be initialized
546
!> @param filename the relative path to the file on the filesystem
547
548
!> @param mode the access mode. Can be 'READ', 'WRITE', 'OVERWRITE', or 'NEW'.
!>        Status 'READ', 'WRITE', and 'OVERWRITE' all require the file to
549
550
551
552
553
554
555
556
557
558
!>        exist.
!>        'WRITE' gives write access but will fail if the user tries to overwrite
!>        data existing in the file, whereas 'OVERWRITE' will allow the user to
!>        overwrite existing data in the file.
!>        'NEW' will create the file, overwriting any existing files with the
!>        same name.  File will be given 'WRITE' status.  Use setOverwriteStat
!>        to change the status to 'OVERWRITE'.
!>        Note that when overwriting datasets, new datasets must be the same
!>        type and shape as the existing one being overwritten; otherwise
!>        an exception will be thrown.
559
560
!> @param zlibOpt numeric option for GZIP compression [0-9] uses compression, -1
!>        is no compression
561
562
563
564
!>
!> This routine initializes an HDF5 file object by setting the objects
!> attributes, initializing the HDF5 library interface and calling the @c open
!> routine.
565
!>
Graham, Aaron's avatar
Graham, Aaron committed
566
567
568
569
570
SUBROUTINE init_HDF5FileType(thisHDF5File,filename,mode,zlibOpt)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: filename
  CHARACTER(LEN=*),INTENT(IN) :: mode
  INTEGER(SIK),INTENT(IN),OPTIONAL :: zlibOpt
571
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
572
573
574
575
  CHARACTER(LEN=*),PARAMETER :: myName='init_HDF5FileType'
  TYPE(StringType) :: fpath,fname,fext,mode_in
  INTEGER(SIK) :: unitno
  LOGICAL(SBK) :: ostat,exists
Graham, Aaron's avatar
Graham, Aaron committed
576
577
578

  REQUIRE(.NOT.thisHDF5File%isInit)

Graham, Aaron's avatar
Graham, Aaron committed
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  CALL getFileParts(filename,fpath,fname,fext,thisHDF5File%e)
  CALL thisHDF5File%setFilePath(CHAR(fpath))
  CALL thisHDF5File%setFileName(CHAR(fname))
  CALL thisHDF5File%setFileExt(CHAR(fext))

  IF(PRESENT(zlibOpt)) THEN
    IF(zlibOpt >= 0) THEN
      thisHDF5File%hasCompression=.TRUE.
      thisHDF5File%zlibOpt=zlibOpt
    ENDIF
  ENDIF

  ! Store the access mode
  mode_in=mode
  mode_in = mode_in%upper()
  SELECTCASE(TRIM(mode_in))
  CASE('READ')
    INQUIRE(FILE=filename,EXIST=exists)
    IF(exists) THEN
      CALL thisHDF5File%setWriteStat(.FALSE.)
      CALL thisHDF5File%setReadStat(.TRUE.)
    ELSE
      CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
          ' - HDF5 file '//filename//' is being opened with '// &
          'mode READ but does not exist.')
    ENDIF
  CASE('WRITE')
    INQUIRE(FILE=filename,EXIST=exists)
    IF(exists) THEN
      CALL thisHDF5File%setWriteStat(.TRUE.)
      CALL thisHDF5File%setReadStat(.TRUE.)
    ELSE
      CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
          ' - HDF5 file '//filename//' is being opened with '// &
          'mode WRITE but does not exist.')
    ENDIF
  CASE('OVERWRITE')
    INQUIRE(FILE=filename,EXIST=exists)
    IF(exists) THEN
      CALL thisHDF5File%setWriteStat(.TRUE.)
      CALL thisHDF5File%setOverwriteStat(.TRUE.)
      CALL thisHDF5File%setReadStat(.TRUE.)
    ELSE
      CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
          ' - HDF5 file '//filename//' is being opened with '// &
          'mode OVERWRITE but does not exist.')
    ENDIF
  CASE('NEW')
    CALL thisHDF5File%setWriteStat(.TRUE.)
    CALL thisHDF5File%setNewStat(.TRUE.)
    CALL thisHDF5File%setReadStat(.TRUE.)
  CASE DEFAULT
    CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
        ' - Unrecognized access mode.')
  ENDSELECT

  thisHDF5File%fullname=filename

  ! Initialize the HDF5 interface. This needs be done before any other calls
  ! to the HF5 interface can be made.
  CALL HDF5Open()

  ! Assign arbitrary UNIT number to file.  Used only for deleting file.
  unitno=99
  INQUIRE(UNIT=unitno,OPENED=ostat)
  DO WHILE(thisHDF5File%unitno == -1)
    IF(ostat) THEN
      unitno=unitno-1_SIK
647
      INQUIRE(UNIT=unitno,OPENED=ostat)
Graham, Aaron's avatar
Graham, Aaron committed
648
649
650
651
652
653
    ELSE
      thisHDF5File%unitno=unitno
    ENDIF
  ENDDO
  thisHDF5File%isinit=.TRUE.
  nhdf5fileinuse=nhdf5fileinuse+1
654
#else
Graham, Aaron's avatar
Graham, Aaron committed
655
656
657
  ! We dont have HDF5, so we can't initialize
  CALL thisHDF5File%e%raiseWarning('The HDF5 library is not present in '// &
      'this build')
658
#endif
Graham, Aaron's avatar
Graham, Aaron committed
659
ENDSUBROUTINE init_HDF5FileType
660
661
!
!-------------------------------------------------------------------------------
662
!> @brief Destructs an HDF5 file object.
663
!> @param thisHDF5File the HDF5 object to be destroyed
Dan Jabaay's avatar
Dan Jabaay committed
664
!> @param ldel logical on whether or not to delete or close the file.
665
666
!>
!> This routine releases resources used for interacting with the HSF5 file. It
Dan Jabaay's avatar
Dan Jabaay committed
667
668
!> closes or deletes the file and the HDF5 library interface. The structure
!> was taken from the Fortran file.
669
!>
Graham, Aaron's avatar
Graham, Aaron committed
670
671
672
SUBROUTINE clear_HDF5FileType(thisHDF5File,ldel)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  LOGICAL(SBK),INTENT(IN),OPTIONAL :: ldel
673
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
674
  LOGICAL(SBK) :: bool
675
#endif
Graham, Aaron's avatar
Graham, Aaron committed
676
  IF(thisHDF5File%isinit) THEN
677
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
678
679
680
681
682
683
684
685
686
687
688
689
690
    !Logical to close or delete the file.
    bool=.FALSE.
    IF(PRESENT(ldel)) bool=ldel
    IF(bool) THEN
      CALL thisHDF5File%fdelete()
    ELSE
      CALL thisHDF5File%fclose()
    ENDIF

    ! Close the HDF5 interface. This can only be done once all calls to the
    ! HDF5 library are complete.
    nhdf5fileinuse=nhdf5fileinuse-1
    IF(libh5Open .AND. (nhdf5fileinuse == 0)) CALL HDF5Close()
691
#endif
Graham, Aaron's avatar
Graham, Aaron committed
692
693
694
695
696
697
698
699
700
701
    thisHDF5File%isinit=.FALSE.
    thisHDF5File%newstat=.FALSE.
    thisHDF5File%hasCompression=.FALSE.
    thisHDF5File%zlibOpt=-1
    thisHDF5File%fullname=''
    thisHDF5File%unitno=-1
    thisHDF5File%overwriteStat = .FALSE.
    CALL clear_base_file(thisHDF5File)
  ENDIF
ENDSUBROUTINE clear_HDF5FileType
702
703
!
!-------------------------------------------------------------------------------
704
705
706
!> @brief Sets the value for the status of whether or not the file will
!> be overwritable.
!>
Graham, Aaron's avatar
Graham, Aaron committed
707
708
709
710
711
SUBROUTINE setOverwriteStat_file(file,bool)
  CLASS(HDF5FileType),INTENT(INOUT) :: file
  LOGICAL(SBK),INTENT(IN) :: bool
  file%overwriteStat=bool
ENDSUBROUTINE setOverwriteStat_file
712
713
714

!
!-------------------------------------------------------------------------------
715
716
717
718
719
720
!> @brief Open an HDF5 file
!> @param file the HDF5FileType object to open
!>
!> This routine implements the abstract @c fopen routine in the base file type.
!> It uses the HDF5 library interface that was initialized in @c init to open
!> the file.
721
!>
Graham, Aaron's avatar
Graham, Aaron committed
722
723
SUBROUTINE open_HDF5FileType(file)
  CLASS(HDF5FileType),INTENT(INOUT) :: file
724
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
725
726
727
728
  CHARACTER(LEN=*),PARAMETER :: myName='open_HDF5FileType'
  INTEGER :: acc
  INTEGER(HID_T) :: plist_id

Graham, Aaron's avatar
Graham, Aaron committed
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
  REQUIRE(file%isinit)

  CALL h5pcreate_f(H5P_FILE_ACCESS_F,plist_id,error)
  CALL h5pset_fclose_degree_f(plist_id,H5F_CLOSE_SEMI_F,error)

  IF (error /= 0) CALL file%e%raiseError(modName//'::'//myName// &
      ' - Unable to create property list for open operation.')

  ! Decide what access type to use
  IF(file%isNew()) THEN
    acc=H5F_ACC_TRUNC_F
    CALL h5fcreate_f(CHAR(file%fullname),acc,file%file_id,error, &
        access_prp=plist_id)
    ! If the file is NEW, change the mode to WRITE after
    ! Creating it so we don't keep truncating it repeatedly.
    CALL file%setNewStat(.FALSE.)
  ELSEIF(file%isWrite()) THEN
    acc=H5F_ACC_RDWR_F
    CALL h5fopen_f(CHAR(file%fullname),acc,file%file_id,error, &
        access_prp=plist_id)
  ELSEIF(file%isRead()) THEN
    acc=H5F_ACC_RDONLY_F
    CALL h5fopen_f(CHAR(file%fullname),acc,file%file_id,error, &
        access_prp=plist_id)
  ELSE
    CALL file%e%raiseError(modName//'::'//myName// &
        ' - Unrecognized access mode! The file is not'// &
        ' set as either new, read, or write!')
  ENDIF
Graham, Aaron's avatar
Graham, Aaron committed
758

Graham, Aaron's avatar
Graham, Aaron committed
759
760
761
762
763
764
  CALL h5pclose_f(plist_id,error)
  IF(error /= 0) THEN
    CALL file%e%raiseError(modName//'::'//myName// &
        ' - Unable to destroy property list.')
  ELSE
    CALL file%setOpenStat(.TRUE.)
Graham, Aaron's avatar
Graham, Aaron committed
765
  ENDIF
Graham, Aaron's avatar
Graham, Aaron committed
766

767
#endif
Graham, Aaron's avatar
Graham, Aaron committed
768
ENDSUBROUTINE open_HDF5FileType
769
770
!
!-------------------------------------------------------------------------------
771
772
773
774
!> @brief Closes access to an HDF5 file
!> @param file the HDF5FileType object to close
!>
!> This routine implements the abstract @c fclose routine in the base file type.
775
!>
Graham, Aaron's avatar
Graham, Aaron committed
776
777
SUBROUTINE close_HDF5FileType(file)
  CLASS(HDF5FileType),INTENT(INOUT) :: file
778
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
779
780
  CHARACTER(LEN=*),PARAMETER :: myName='close_HDF5FileType'
  LOGICAL(SBK) :: lastStopOnError
Graham, Aaron's avatar
Graham, Aaron committed
781
782
783

  REQUIRE(file%isinit)

Graham, Aaron's avatar
Graham, Aaron committed
784
785
  lastStopOnError=file%e%isStopOnError()
  CALL file%e%setStopOnError(.FALSE.)
Graham, Aaron's avatar
Graham, Aaron committed
786
787
788
789
790
791
792
793
794
795

  !Check open status.
  IF(file%isopen()) THEN
    CALL h5fclose_f(file%file_id,error)
    file%file_id=0
    IF(error /= 0) THEN
      CALL file%e%raiseError(modName//'::'//myName// &
          ' - Unable to close HDF5 file.')
    ELSE
      CALL file%setOpenStat(.FALSE.)
Graham, Aaron's avatar
Graham, Aaron committed
796
797
    ENDIF
  ENDIF
Graham, Aaron's avatar
Graham, Aaron committed
798

Graham, Aaron's avatar
Graham, Aaron committed
799
  CALL file%e%setStopOnError(lastStopOnError)
Graham, Aaron's avatar
Graham, Aaron committed
800

801
#endif
Graham, Aaron's avatar
Graham, Aaron committed
802
ENDSUBROUTINE close_HDF5FileType
803
804
!
!-------------------------------------------------------------------------------
805
806
807
808
809
810
!> @brief delete and HDF5 file
!>
!> @param file the HDF5FileType object to delet
!>
!> This routine implements the abstract @c fdelete routine in the base file
!> type.
Dan Jabaay's avatar
Dan Jabaay committed
811
812
!> Mimicking FileType_Fortran logical structure.  We do not clear the file
!> after it is deleted.
813
!>
Graham, Aaron's avatar
Graham, Aaron committed
814
815
SUBROUTINE delete_HDF5FileType(file)
  CLASS(HDF5FileType),INTENT(INOUT) :: file
816
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
817
818
819
  CHARACTER(LEN=*),PARAMETER :: myName='delete_HDF5FileType'
  CHARACTER(LEN=EXCEPTION_MAX_MESG_LENGTH) :: emesg

Graham, Aaron's avatar
Graham, Aaron committed
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
  REQUIRE(file%isInit)

  !So, HDF5 is special in that the unitno assigned isn't used in the
  !fopen() operation.  So, regardless of the %isOpen() status, it needs
  !to be opened.
  OPEN(UNIT=file%unitno,FILE=TRIM(file%getFilePath())// &
      TRIM(file%getFileName())//TRIM(file%getFileExt()), &
      IOSTAT=error)
  IF(error /= 0) THEN
    WRITE(emesg,'(a,i4,a,i4)') 'Error deleting file (UNIT=', &
        file%unitno,') IOSTAT=',error
    CALL file%e%raiseError(modName//'::'//myName//' - '//emesg)
  ENDIF
  CLOSE(UNIT=file%unitno,STATUS='DELETE',IOSTAT=error)
  IF(error /= 0) THEN
    WRITE(emesg,'(a,i4,a,i4)') 'Error deleting file (UNIT=', &
        file%unitno,') IOSTAT=',error
    CALL file%e%raiseError(modName//'::'//myName//' - '//emesg)
  ELSE
    CALL file%setOpenStat(.FALSE.)
Graham, Aaron's avatar
Graham, Aaron committed
840
  ENDIF
Aaron Graham's avatar
Aaron Graham committed
841
#else
Graham, Aaron's avatar
Graham, Aaron committed
842
843
844
  ! We dont have HDF5, so we can't initialize
  CALL file%e%raiseWarning('The HDF5 library is not present in '// &
      'this build')
845
#endif
Graham, Aaron's avatar
Graham, Aaron committed
846
ENDSUBROUTINE delete_HDF5FileType
847
848
!
!-------------------------------------------------------------------------------
Dan Jabaay's avatar
Dan Jabaay committed
849
850
851
852
!> @brief gets the unit number used by the HDF5 file
!> @param file the HDF5 file type object
!> @returns val the value of the unit number
!>
Graham, Aaron's avatar
Graham, Aaron committed
853
854
855
856
857
PURE FUNCTION getUnitNo_HDF5FileType(file) RESULT(val)
  CLASS(HDF5FileType),INTENT(IN) :: file
  INTEGER(SIK) :: val
  val=file%unitno
ENDFUNCTION getUnitNo_HDF5FileType
Dan Jabaay's avatar
Dan Jabaay committed
858
859
860
861
862
863
!
!-------------------------------------------------------------------------------
!> @brief Returns whether or not the HDF5 file is new.
!> @param file the HDF5 file type object
!> @returns bool TRUE/FALSE if the file is new
!>
Graham, Aaron's avatar
Graham, Aaron committed
864
865
866
867
868
PURE FUNCTION isNew_HDF5FileType(file) RESULT(bool)
  CLASS(HDF5FileType),INTENT(IN) :: file
  LOGICAL(SBK) :: bool
  bool=file%newstat
ENDFUNCTION isNew_HDF5FileType
Dan Jabaay's avatar
Dan Jabaay committed
869
870
871
872
873
874
!
!-------------------------------------------------------------------------------
!> @brief Sets whether or not the HDF5 file is new.
!> @param file the HDF5 file type object
!> @returns bool TRUE/FALSE to set the file to new or not, respectively.
!>
Graham, Aaron's avatar
Graham, Aaron committed
875
876
877
878
879
PURE SUBROUTINE setNewStat_HDF5FileType(file,bool)
  CLASS(HDF5FileType),INTENT(INOUT) :: file
  LOGICAL(SBK),INTENT(IN) :: bool
  file%newstat=bool
ENDSUBROUTINE setNewStat_HDF5FileType
Dan Jabaay's avatar
Dan Jabaay committed
880
881
!
!-------------------------------------------------------------------------------
882
!> @brief List the contents of a group
883
!> @param thisHDF5File the HDF5FileType object to operate on
884
885
886
887
888
889
890
891
892
!> @param path the absolute path to the group of interest (group heirarchy
!> represented with '->')
!> @param objs the list of objects to be returned. See below.
!>
!> This routine is useful for discovering the contents of an HDF5 file. A path
!> to a group in the file is provided in the subroutine call and the names of
!> its constituents is stored in the objs list. If objs is passed in, it will be
!> deallocated and reallocated to the proper size to store the names of all of
!> the objects in the group.
893
!>
Graham, Aaron's avatar
Graham, Aaron committed
894
895
896
897
SUBROUTINE ls_HDF5FileType(thisHDF5File,path,objs)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: path
  TYPE(StringType),ALLOCATABLE,INTENT(INOUT) :: objs(:)
898
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
899
900
901
902
903
904
905
  CHARACTER(LEN=*),PARAMETER :: myName='ls_HDF5FileType'
  CHARACTER(LEN=1024) :: tmpchar
  TYPE(StringType) :: path2
  INTEGER(HSIZE_T) :: i
  INTEGER(HID_T) :: grp_id
  INTEGER :: store_type,nlinks,max_corder

Graham, Aaron's avatar
Graham, Aaron committed
906
  REQUIRE(thisHDF5File%isinit)
Graham, Aaron's avatar
Graham, Aaron committed
907

Graham, Aaron's avatar
Graham, Aaron committed
908
909
910
911
912
913
914
915
916
917
  IF(.NOT.thisHDF5File%isOpen()) CALL thisHDF5File%fopen()
  IF(ALLOCATED(objs)) THEN
    !objs=''
    DEALLOCATE(objs)
  ENDIF
  IF(isgrp_HDF5FileType(thisHDF5File,path)) THEN
    path2=convertPath(path)
    CALL h5gopen_f(thisHDF5File%file_id,CHAR(path2),grp_id,error)
    IF(error /= 0) CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
        ' - Unable to open file.')
Graham, Aaron's avatar
Graham, Aaron committed
918

Graham, Aaron's avatar
Graham, Aaron committed
919
920
921
    CALL h5gget_info_f(grp_id,store_type,nlinks,max_corder,error)
    IF(error /= 0) CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
        ' - Unable to get group information.')
Graham, Aaron's avatar
Graham, Aaron committed
922

Graham, Aaron's avatar
Graham, Aaron committed
923
    ALLOCATE(objs(nlinks))
924

Graham, Aaron's avatar
Graham, Aaron committed
925
926
927
928
    DO i=0,nlinks-1
      CALL h5lget_name_by_idx_f(thisHDF5File%file_id,CHAR(path2), &
          H5_INDEX_NAME_F,H5_ITER_INC_F,i,tmpchar,error)
      objs(i+1)=TRIM(tmpchar)
Graham, Aaron's avatar
Graham, Aaron committed
929
      IF(error /= 0) CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
Graham, Aaron's avatar
Graham, Aaron committed
930
931
932
933
934
935
          ' - Unable to get object name.')
    ENDDO

    CALL h5gclose_f(grp_id, error)
    IF(error /= 0) CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
        ' - Unable to close group.')
Graham, Aaron's avatar
Graham, Aaron committed
936
  ENDIF
937
#endif
Graham, Aaron's avatar
Graham, Aaron committed
938
ENDSUBROUTINE ls_HDF5FileType
939
940
!
!-------------------------------------------------------------------------------
941
!> @brief Creates a new group in the HDF file.
942
!> @param thisHDF5File the HDF5FileType object to operate on
943
944
945
946
!> @param path the path to the group to be created
!>
!> This routine is used to create a new group in an HDF5 file. It can only be
!> called if the file has write access.
947
!>
948
RECURSIVE SUBROUTINE mkdir_HDF5FileType(thisHDF5File,path)
Graham, Aaron's avatar
Graham, Aaron committed
949
950
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: path
951
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
952
  CHARACTER(LEN=*),PARAMETER :: myNAme='mkdir_HDF5FileType'
953
  TYPE(StringType) :: path2,path3
Graham, Aaron's avatar
Graham, Aaron committed
954
955
  INTEGER(HID_T) :: group_id
  LOGICAL :: dset_exists
956
  INTEGER(SIK) :: lastslash
Graham, Aaron's avatar
Graham, Aaron committed
957

Graham, Aaron's avatar
Graham, Aaron committed
958
959
  REQUIRE(thisHDF5File%isinit)
  REQUIRE(thisHDF5File%isWrite())
Graham, Aaron's avatar
Graham, Aaron committed
960

Graham, Aaron's avatar
Graham, Aaron committed
961
962
963
964
965
966
967
968
969
  IF(.NOT.thisHDF5File%isOpen()) CALL thisHDF5File%fopen()
  ! Convert the path to use slashes
  path2=convertPath(path)

  lastslash=INDEX(path2,'/',.TRUE.)
  IF(lastslash > 1) THEN
    path3=path2%substr(1,lastslash-1)
    IF(.NOT.thisHDF5File%pathExists(CHAR(path3))) THEN
      CALL thisHDF5File%mkdir(CHAR(path3))
970
    ENDIF
Graham, Aaron's avatar
Graham, Aaron committed
971
972
973
974
  ENDIF
  CALL h5lexists_f(thisHDF5File%file_id,CHAR(path2),dset_exists,error)
  IF(error /= 0) CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
      ' - invalid group path: '//path)
Graham, Aaron's avatar
Graham, Aaron committed
975

Graham, Aaron's avatar
Graham, Aaron committed
976
977
978
979
  IF(thisHDF5File%overwriteStat .AND. dset_exists) THEN
    ! If group exists, do nothing, but only if overwrites are allowed
    CONTINUE
  ELSE
Graham, Aaron's avatar
Graham, Aaron committed
980

Graham, Aaron's avatar
Graham, Aaron committed
981
982
    ! Create the group
    CALL h5gcreate_f(thisHDF5File%file_id,CHAR(path2),group_id,error)
Graham, Aaron's avatar
Graham, Aaron committed
983

Graham, Aaron's avatar
Graham, Aaron committed
984
985
986
987
988
989
990
991
    IF(error == 0) THEN
      ! Close the group
      CALL h5gclose_f(group_id,error)
      IF(error /= 0) CALL thisHDF5File%e%raiseDebug(modName//'::'// &
          myName//' - Failed to close HDF group')
    ELSE
      CALL thisHDF5File%e%raiseDebug(modName//'::'//myName// &
          ' - Failed to create HDF5 group.')
Graham, Aaron's avatar
Graham, Aaron committed
992
993
    ENDIF
  ENDIF
994
#endif
Graham, Aaron's avatar
Graham, Aaron committed
995
ENDSUBROUTINE mkdir_HDF5FileType
996
997
!
!-------------------------------------------------------------------------------
998
999
1000
1001
1002
1003
1004
!> @brief Creates a new group in the HDF file.
!> @param thisHDF5File the HDF5FileType object to operate on
!> @param path the path to the group to be created
!>
!> This routine is used to create a new group in an HDF5 file. It can only be
!> called if the file has write access.
!>
Graham, Aaron's avatar
Graham, Aaron committed
1005
1006
1007
SUBROUTINE mkalldir_HDF5FileType(thisHDF5File,path)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: path
1008
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
1009
1010
1011
1012
1013
1014
  CHARACTER(LEN=*),PARAMETER :: myNAme='mkalldir_HDF5FileType'
  INTEGER(SIK) :: i,nslash
  INTEGER(SIK),ALLOCATABLE :: slashloc(:)
  TYPE(StringType) :: path2,tmppath
  INTEGER(HID_T) :: group_id

Graham, Aaron's avatar
Graham, Aaron committed
1015
1016
  REQUIRE(thisHDF5File%isinit)
  REQUIRE(thisHDF5File%isWrite())
Graham, Aaron's avatar
Graham, Aaron committed
1017

Graham, Aaron's avatar
Graham, Aaron committed
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
  IF(.NOT.thisHDF5File%isOpen()) CALL thisHDF5File%fopen()
  error=0
  ! Convert the path to use slashes
  path2=convertPath(TRIM(path))
  CALL strfind(TRIM(CHAR(path2)),FSLASH,slashloc)
  nslash=SIZE(slashloc)
  DO i=1,nslash-1
    tmppath = path2%substr(1,slashloc(i+1)-1)
    IF(.NOT.pathexists_HDF5FileType(thisHDF5File,TRIM(CHAR(tmppath)))) THEN
      CALL h5gcreate_f(thisHDF5File%file_id,TRIM(CHAR(tmppath)),group_id,error)
Graham, Aaron's avatar
Graham, Aaron committed
1028
1029
      CALL h5gclose_f(group_id,error)
    ENDIF
Graham, Aaron's avatar
Graham, Aaron committed
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
  ENDDO
  DEALLOCATE(slashloc)
  ! Create the group
  IF(.NOT.pathexists_HDF5FileType(thisHDF5File,TRIM(CHAR(path2)))) &
      CALL h5gcreate_f(thisHDF5File%file_id,TRIM(CHAR(path2)),group_id,error)

  IF(error == 0) THEN
    ! Close the group
    CALL h5gclose_f(group_id,error)
    IF(error /= 0) CALL thisHDF5File%e%raiseDebug(modName//'::'// &
        myName//' - Failed to close HDF group')
  ELSE
    CALL thisHDF5File%e%raiseDebug(modName//'::'//myName// &
        ' - Failed to create HDF5 group.')
Graham, Aaron's avatar
Graham, Aaron committed
1044
  ENDIF
1045
#endif
Graham, Aaron's avatar
Graham, Aaron committed
1046
ENDSUBROUTINE mkalldir_HDF5FileType
1047
1048
!
!-------------------------------------------------------------------------------
1049
!> @brief Returns the number of objects in a group
1050
!> @param thisHDF5File the HDF5FileType object to interrogate
1051
1052
1053
!> @param path the group in the file to interrogate
!>
!> This function returns how many objects are in the group @c path.
1054
!>
Graham, Aaron's avatar
Graham, Aaron committed
1055
1056
1057
1058
FUNCTION ngrp_HDF5FileType(thisHDF5File,path) RESULT(ngrp)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: path
  INTEGER(SIK) :: ngrp
1059
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
1060
1061
1062
1063
1064
  CHARACTER(LEN=*),PARAMETER :: myName='ngrp_HDF5FileType'
  TYPE(StringType) :: path2
  INTEGER(HID_T) :: grp_id
  INTEGER :: store_type,nlinks,max_corder

Graham, Aaron's avatar
Graham, Aaron committed
1065
  REQUIRE(thisHDF5File%isinit)
Graham, Aaron's avatar
Graham, Aaron committed
1066

Graham, Aaron's avatar
Graham, Aaron committed
1067
1068
  IF(.NOT.thisHDF5File%isOpen()) CALL thisHDF5File%fopen()
  path2=convertPath(path)
Graham, Aaron's avatar
Graham, Aaron committed
1069

Graham, Aaron's avatar
Graham, Aaron committed
1070
1071
1072
  CALL h5gopen_f(thisHDF5File%file_id,CHAR(path2),grp_id,error)
  IF(error /= 0) CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
      ' - Could not open group in HDF5 file.')
Graham, Aaron's avatar
Graham, Aaron committed
1073

Graham, Aaron's avatar
Graham, Aaron committed
1074
1075
1076
  CALL h5gget_info_f(grp_id, store_type,nlinks,max_corder,error)
  IF(error /= 0) CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
      ' - Could not get group info in HDF5 file.')
Graham, Aaron's avatar
Graham, Aaron committed
1077

Graham, Aaron's avatar
Graham, Aaron committed
1078
1079
1080
1081
  ! Close the group
  CALL h5gclose_f(grp_id,error)
  IF(error /= 0) CALL thisHDF5File%e%raiseDebug(modName//'::'// &
      myName//' - Failed to close HDF group')
Graham, Aaron's avatar
Graham, Aaron committed
1082

Graham, Aaron's avatar
Graham, Aaron committed
1083
  ngrp=nlinks
1084
#else
Graham, Aaron's avatar
Graham, Aaron committed
1085
  ngrp=0
1086
#endif
Graham, Aaron's avatar
Graham, Aaron committed
1087
ENDFUNCTION ngrp_HDF5FileType
1088
1089
!
!-------------------------------------------------------------------------------
1090
!> @brief Returns whether the group is a group type in the file or not.
1091
!> @param thisHDF5File the HDF5FileType object to interrogate
1092
1093
!> @param path the group in the file to check if it is a group
!> @param bool the logical result of whether the specified group is a group.
1094
1095
!>
!> This function returns a logical corresponding to whether the group specified
1096
!> by @c path is a group or not.
1097
!>
Graham, Aaron's avatar
Graham, Aaron committed
1098
1099
1100
1101
FUNCTION isgrp_HDF5FileType(thisHDF5File,path) RESULT(bool)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: path
  LOGICAL(SBK) :: bool
1102
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
1103
1104
1105
1106
1107
  CHARACTER(LEN=*),PARAMETER :: myName='isgrp_HDF5FileType'
  TYPE(StringType) :: path2
  INTEGER(HID_T) :: obj_id
  INTEGER(SIK) :: type

Graham, Aaron's avatar
Graham, Aaron committed
1108
1109
  REQUIRE(thisHDF5File%isinit)

Graham, Aaron's avatar
Graham, Aaron committed
1110
1111
  ! Make sure the object is initialized, and opened
  bool=.FALSE.
Graham, Aaron's avatar
Graham, Aaron committed
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
  IF(.NOT.thisHDF5File%isOpen()) CALL thisHDF5File%fopen()
  bool=thisHDF5File%pathExists(path)
  IF(bool) THEN
    path2=convertPath(path)
    !Need to get the object ID from the path...
    CALL h5oopen_f(thisHDF5File%file_id,CHAR(path2),obj_id,error)
    IF(error == -1) THEN
      bool=.FALSE.
    ELSE
      CALL h5iget_type_f(obj_id,type,error)
      bool=(type == H5I_GROUP_F)
Graham, Aaron's avatar
Graham, Aaron committed
1123
    ENDIF
Graham, Aaron's avatar
Graham, Aaron committed
1124
1125
1126
1127
    ! Close the object
    CALL h5oclose_f(obj_id,error)
    IF(error /= 0) CALL thisHDF5File%e%raiseDebug(modName//'::'// &
        myName//' - Failed to close HDF object!')
Graham, Aaron's avatar
Graham, Aaron committed
1128
  ENDIF
1129
#else
Graham, Aaron's avatar
Graham, Aaron committed
1130
  bool=.FALSE.
1131
#endif
Graham, Aaron's avatar
Graham, Aaron committed
1132
ENDFUNCTION isgrp_HDF5FileType
1133
1134
1135
1136
1137
1138
1139
1140
!
!-------------------------------------------------------------------------------
!> @brief Returns whether the path exists in the file or not.
!> @param thisHDF5File the HDF5FileType object to interrogate
!> @param path the path in the file to check if it exists
!> @param bool the logical result of whether the specified path exists.
!>
!> This function returns a logical corresponding to whether the specified
1141
!> @c path exists or not.
1142
!>
Graham, Aaron's avatar
Graham, Aaron committed
1143
1144
1145
1146
FUNCTION pathexists_HDF5FileType(thisHDF5File,path) RESULT(bool)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: path
  LOGICAL(SBK) :: bool
1147
#ifdef FUTILITY_HAVE_HDF5
1148
1149
1150
  INTEGER :: iseg
  TYPE(StringType) :: strpath,path2
  TYPE(StringType),ALLOCATABLE :: segments(:)
Graham, Aaron's avatar
Graham, Aaron committed
1151

Graham, Aaron's avatar
Graham, Aaron committed
1152
1153
  REQUIRE(thisHDF5File%isinit)

Graham, Aaron's avatar
Graham, Aaron committed
1154
1155
  ! Make sure the object is initialized, and opened
  bool=.FALSE.
Graham, Aaron's avatar
Graham, Aaron committed
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
  IF(.NOT.thisHDF5File%isOpen()) CALL thisHDF5File%fopen()
  strpath=convertPath(path)
  segments=strpath%split('/')
  bool=.TRUE.
  path2=''
  DO iseg=2,SIZE(segments)
    path2=path2//'/'//segments(iseg)
    CALL h5lexists_f(thisHDF5File%file_id,CHAR(path2),bool,error)
    IF(.NOT.bool) EXIT
  ENDDO !iseg
1166
#else
Graham, Aaron's avatar
Graham, Aaron committed
1167
  bool=.FALSE.
1168
#endif
Graham, Aaron's avatar
Graham, Aaron committed
1169
ENDFUNCTION pathexists_HDF5FileType
1170
1171
!
!-------------------------------------------------------------------------------
1172
1173
!> @brief   Returns whether an HDF5 File or data set has compression
!> @param   thisHDF5File the HDF5FileType object to interrogate
Brendan Kochunas's avatar
Brendan Kochunas committed
1174
!> @param   path (optional) the path to a dataset in the file, which must exist
1175
1176
!> @returns bool the logical result of whether the specified object has
!>          compression.
Brendan Kochunas's avatar
Brendan Kochunas committed
1177
1178
1179
1180
1181
1182
1183
1184
!>
!> If the path is present, then whether or not the dataset is compressed is
!> returned.
!>
!> If the path is ommitted then the value of the hasCompression attribute is
!> returned.
!>
!> If a non-existent path is passed, a DBC error is thrown.
1185
!>
Graham, Aaron's avatar
Graham, Aaron committed
1186
1187
1188
1189
FUNCTION isCompressed_HDF5FileType(thisHDF5File,path) RESULT(bool)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: path
  LOGICAL(SBK) :: bool
1190
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
  INTEGER(SIZE_T),PARAMETER :: namelen=180
  CHARACTER(LEN=namelen) :: filter_name
  INTEGER(SIK) :: i,nfilters,filter_id,flags,cd_values(1)
  INTEGER(HID_T) :: dset_id,dcpl
  INTEGER(SIZE_T) :: nelmts
  TYPE(StringType) :: path2

  bool=.FALSE.

  ! Make sure the object is initialized, and opened
  REQUIRE(thisHDF5File%isinit)
  REQUIRE(thisHDF5File%isOpen())

  IF(PRESENT(path)) THEN
    REQUIRE(pathexists_HDF5FileType(thisHDF5File,path))
    path2=convertPath(path)
    nelmts=1

    !Get the data set ID
    CALL h5dopen_f(thisHDF5File%file_id,TRIM(path2),dset_id,error)

    !Get the data set creation property list
    CALL h5dget_create_plist_f(dset_id,dcpl,error)

    !Get the number of filters on the data set, and loop over
    !them to find a compression filter
    CALL h5pget_nfilters_f(dcpl,nfilters,error)
    DO i=0,nfilters-1
      CALL h5pget_filter_f(dcpl,i,flags,nelmts,cd_values, &
          namelen,filter_name,filter_id,error)
      bool=ANY(filter_id == (/H5Z_FILTER_DEFLATE_F, &
          H5Z_FILTER_SZIP_F,H5Z_FILTER_NBIT_F,H5Z_FILTER_NBIT_F/))
      IF(bool) EXIT
    ENDDO
  ELSE
    bool=thisHDF5File%hasCompression
  ENDIF
1228
#else
Graham, Aaron's avatar
Graham, Aaron committed
1229
  bool=.FALSE.
1230
#endif
Graham, Aaron's avatar
Graham, Aaron committed
1231
ENDFUNCTION isCompressed_HDF5FileType
1232
1233
1234
1235
1236
!
!-------------------------------------------------------------------------------
!> @brief   Returns the chunk size of a dataset
!> @param   thisHDF5File the HDF5FileType object to interrogate
!> @param   path the path to a dataset in the file
Brendan Kochunas's avatar
Brendan Kochunas committed
1237
!> @param   cdims allocatable array containing chunk sizes for each dimension
1238
1239
1240
1241
1242
!>          of dataset.
!>
!> If a dataset does not have chunking or does not exist, then cdims is
!> returned unallocated.
!>
Graham, Aaron's avatar
Graham, Aaron committed
1243
1244
1245
1246
SUBROUTINE getChunkSize_HDF5FileType(thisHDF5File,path,cdims)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: path
  INTEGER(SLK),ALLOCATABLE,INTENT(OUT) :: cdims(:)
1247
1248

#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
  INTEGER(SIK) :: ndims,layout
  INTEGER(HID_T) :: dset_id,dspace_id,dcpl
  INTEGER(HSIZE_T),ALLOCATABLE :: cdimsH5(:)
  TYPE(StringType) :: path2

  ! Make sure the object is initialized, and opened
  REQUIRE(thisHDF5File%isinit)
  REQUIRE(thisHDF5File%isOpen())
  IF(pathexists_HDF5FileType(thisHDF5File,path)) THEN
    path2=convertPath(path)

    !Get the data set ID, associated data space, and rank
    CALL h5dopen_f(thisHDF5File%file_id,TRIM(path2),dset_id,error)
    CALL h5dget_space_f(dset_id,dspace_id,error)
    CALL h5sget_simple_extent_ndims_f(dspace_id,ndims,error)

    !Get the data set creation property list
    CALL h5dget_create_plist_f(dset_id,dcpl,error)

    !Get the data space layout and chunk size
    CALL h5pget_layout_f(dcpl,layout,error)
    IF(layout == H5D_CHUNKED_F) THEN
      ALLOCATE(cdims(ndims)); cdims=-1
      ALLOCATE(cdimsH5(ndims)); cdimsH5=-1
      CALL h5pget_chunk_f(dcpl,ndims,cdimsH5,error)
      cdims=cdimsH5
    ENDIF
  ENDIF
1277
#endif
Graham, Aaron's avatar
Graham, Aaron committed
1278
ENDSUBROUTINE getChunkSize_HDF5FileType
1279
1280
!
!-------------------------------------------------------------------------------
Graham, Aaron's avatar
Graham, Aaron committed
1281
!> @brief Creates a hard link between 2 datasets
1282
1283
!> @param thisHDF5File the HDF5FileType object to interrogate
!> @param source_path the path in the file to create a link to
Graham, Aaron's avatar
Graham, Aaron committed
1284
!> @param link_path the path of the link
1285
1286
!>
!>
Graham, Aaron's avatar
Graham, Aaron committed
1287
1288
1289
1290
SUBROUTINE createHardLink_HDF5FileType(thisHDF5File,source_path,link_path)
  CLASS(HDF5FileType),INTENT(INOUT) :: thisHDF5File
  CHARACTER(LEN=*),INTENT(IN) :: source_path
  CHARACTER(LEN=*),INTENT(IN) :: link_path
1291
#ifdef FUTILITY_HAVE_HDF5
Graham, Aaron's avatar
Graham, Aaron committed
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
  CHARACTER(LEN=*),PARAMETER :: myName='createHardLink_HDF5FileType'
  INTEGER(HID_T) :: src_obj_id
  TYPE(StringType) :: spath,lpath

  INTERFACE
    FUNCTION H5Oclose(object_id) RESULT(herr_t) BIND(C,NAME="H5Oclose")
      USE ISO_C_BINDING
      USE HDF5
      INTEGER(HID_T),VALUE :: object_id
      INTEGER :: herr_t
    ENDFUNCTION H5Oclose
  ENDINTERFACE


  IF(pathexists_HDF5FileType(thisHDF5File,source_path)) THEN
    IF(.NOT.pathexists_HDF5FileType(thisHDF5File,link_path)) THEN
      spath=convertPath(source_path)
      lpath=convertPath(link_path)

      !Get the source object ID
      CALL H5Oopen_f(thisHDF5File%file_id,CHAR(spath),src_obj_id,error)

      !Create the link target object ID
      CALL H5Lcreate_hard_f(src_obj_id,CHAR(spath),thisHDF5File%file_id, &
          CHAR(lpath),error)

      !Close the source object
      !CALL H5Oclose_f(src_obj_id,error)
      error=H5Oclose(src_obj_id)
    ELSE
      CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
          ' - Location of new link already exists!')
    ENDIF
  ELSE
    CALL thisHDF5File%e%raiseError(modName//'::'//myName// &
        ' - Target of new link must exist in file!')
  ENDIF
1329
#endif
Graham, Aaron's avatar
Graham, Aaron committed
1330
ENDSUBROUTINE createHardLink_HDF5FileType
1331
1332
!
!-------------------------------------------------------------------------------
Aaron Graham's avatar
Aaron Graham committed
1333
!> @brief Write a double to a dataset
1334
1335
1336
1337
1338
!> @param thisHDF5File the HDF5FileType object to write to
!> @param dsetname dataset name and path to write to
!> @param vals data to write to dataset
!> @param gdims_in shape of data to write with
!>
1339
!> This routine writes a double @c vals to a dataset of name and path @c
1340
!> dsetname using the shape @c gdims_in, if present.