Afivo 0.3
All Classes Namespaces Functions Variables Pages
m_npy.f90
1module m_npy
2 use iso_fortran_env
3
4 implicit none
5 private
6
7 ! Suffix for temporary .npy files
8 character(len=*), parameter :: npy_suffix = '.npy'
9
10 interface save_npy
11 module procedure write_int64_vec, write_int64_mtx, &
12 write_int32_vec, write_int32_mtx, write_int32_3d, &
13 write_int16_vec, write_int16_mtx, &
14 write_int8_vec, write_int8_mtx, write_int8_3d, &
15 write_dbl_vec, write_dbl_mtx, &
16 write_sng_vec, write_sng_mtx, &
17 write_cmplx_sgn_vec, write_cmplx_sgn_mtx, &
18 write_cmplx_dbl_vec, write_cmplx_dbl_mtx, &
19 write_sng_3dt, write_dbl_3dt, &
20 write_sng_4dt, write_dbl_4dt, &
21 write_dbl_5dt, &
22 write_cmplx_dbl_3dt, &
23 write_cmplx_dbl_4dt, &
24 write_cmplx_dbl_5dt, &
25 write_cmplx_dbl_6dt
26 end interface save_npy
27
28 public :: save_npy
29 public :: remove_file
30 public :: add_to_zip
31
32contains
33
34 subroutine run_sys(cmd, stat)
35 character(len=*), intent(in) :: cmd
36 integer(int32), intent(out) :: stat
37
38 call execute_command_line(cmd, wait=.true., exitstat=stat)
39 end subroutine run_sys
40
41 ! Add npy file to a zip file and remove it
42 subroutine add_to_zip(zipfile, filename, keep_file, custom_name)
43 character(len=*), intent(in) :: zipfile ! Name of zip file
44 character(len=*), intent(in) :: filename ! Name of file to add
45 logical, intent(in) :: keep_file ! Whether to keep 'filename'
46 character(len=*), intent(in), optional :: custom_name ! Custom name
47 integer(int32) :: stat
48
49 ! Be quiet while zipping
50 character(len=*), parameter :: zip_command = "zip -q0"
51
52 call run_sys(zip_command//" "//trim(zipfile)//" "//&
53 trim(filename), stat)
54 if (stat /= 0) then
55 print *, zip_command//" "//trim(zipfile)//" "// trim(filename)
56 error stop "add_to_zip: Can't execute zip command"
57 endif
58
59 if (present(custom_name)) then
60 call run_sys('printf "@ '//trim(filename)//'\n@='//&
61 trim(custom_name)//'\n" | zipnote -w '//trim(zipfile), stat)
62 if (stat /= 0) then
63 error stop "add_to_zip: Failed to rename to custom_name"
64 endif
65 end if
66
67 if (.not. keep_file) then
68 call remove_file(filename)
69 end if
70 end subroutine add_to_zip
71
72 subroutine remove_file(filename)
73 character(len=*), intent(in) :: filename
74 integer :: p_un, stat
75
76 open(newunit=p_un, iostat=stat, file=filename, status='old')
77 if (stat == 0) close(p_un, status='delete')
78 end subroutine remove_file
79
80 function dict_str(var_type, var_shape) result(str)
81 character(len=*), intent(in) :: var_type
82 integer(int32), intent(in) :: var_shape(:)
83 character(len=:), allocatable :: str
84 character(len=1024) :: buffer
85 integer(int32) :: total_size, my_size
86
87 ! https://numpy.org/devdocs/reference/generated/numpy.lib.format.html
88
89 ! The first 6 bytes are a magic string: exactly \x93NUMPY.
90
91 ! The next 1 byte is an unsigned byte: the major version number of the file
92 ! format, e.g. \x01.
93
94 ! The next 1 byte is an unsigned byte: the minor version number of the file
95 ! format, e.g. \x00. Note: the version of the file format is not tied to the
96 ! version of the numpy package.
97
98 ! The next 2 bytes form a little-endian unsigned short int: the length of
99 ! the header data HEADER_LEN.
100
101 ! The next HEADER_LEN bytes form the header data describing the array’s
102 ! format. It is an ASCII string which contains a Python literal expression
103 ! of a dictionary. It is terminated by a newline (\n) and padded with spaces
104 ! (\x20) to make the total of len(magic string) + 2 + len(length) +
105 ! HEADER_LEN be evenly divisible by 64 for alignment purposes.
106
107 buffer = "{'descr': '"//var_type// &
108 "', 'fortran_order': True, 'shape': ("// &
109 shape_str(var_shape)//"), }"
110
111 ! len(magic string) + 2 + len(length) + ending newline =
112 ! 6 + 2 + 4 + 1 = 13 bytes
113 total_size = len_trim(buffer) + 13
114
115 ! ensure total_size is divisible by 16 bytes
116 total_size = ((total_size + 15)/16) * 16
117
118 ! Size of dict_str includes the ending newline (so -12 instead of -13)
119 my_size = total_size - 12
120
121 ! End with newline
122 buffer(my_size:my_size) = achar(10)
123 str = buffer(1:my_size)
124 end function dict_str
125
126 function shape_str(var_shape) result(fin_str)
127 integer(int32), intent(in) :: var_shape(:)
128 character(len=:), allocatable :: str, small_str, fin_str
129 integer(int32) :: i, length, start, halt
130
131 length = 14*size(var_shape)
132 allocate (character(length) :: str)
133 allocate (character(14) :: small_str)
134 str = " "
135
136 do i = 1, size(var_shape)
137 start = (i - 1)*length + 1
138 halt = i*length + 1
139 write (small_str, "(I13,A)") var_shape(i), ","
140 str = trim(str)//adjustl(small_str)
141 enddo
142
143 fin_str = trim(str)
144 end function shape_str
145
146 subroutine write_header(p_un, var_type, var_shape)
147 integer(int32), intent(in) :: p_un
148 character(len=*), intent(in) :: var_type
149 integer(int32), intent(in) :: var_shape(:)
150 integer(int32) :: header_len
151
152 ! Magic number hex x93 is 147 (unsigned), signed this is -109
153 integer(int8), parameter :: magic_num = int(-109, int8)
154 character(len=*), parameter :: magic_str = "NUMPY"
155 integer(int8), parameter :: major = 2_int8 ! major *.npy version
156 integer(int8), parameter :: minor = 0_int8 ! minor *.npy version
157
158 header_len = len(dict_str(var_type, var_shape))
159 write (p_un) magic_num, magic_str, major, minor
160 write (p_un) header_len
161 write (p_un) dict_str(var_type, var_shape)
162 end subroutine write_header
163
164 subroutine write_cmplx_sgn_mtx(filename, mtx)
165 character(len=*), intent(in) :: filename
166 complex(4), intent(in) :: mtx(:, :)
167 character(len=*), parameter :: var_type = "<c8"
168 integer(int32) :: p_un
169 open (newunit=p_un, file=filename, form="unformatted", access="stream")
170 call write_header(p_un, var_type, shape(mtx))
171 write (p_un) mtx
172 close (unit=p_un)
173 end subroutine write_cmplx_sgn_mtx
174
175 subroutine write_cmplx_sgn_vec(filename, vec)
176 character(len=*), intent(in) :: filename
177 complex(4), intent(in) :: vec(:)
178 character(len=*), parameter :: var_type = "<c8"
179 integer(int32) :: p_un
180 open (newunit=p_un, file=filename, form="unformatted", access="stream")
181 call write_header(p_un, var_type, shape(vec))
182 write (p_un) vec
183 close (unit=p_un)
184 end subroutine write_cmplx_sgn_vec
185
186 subroutine write_cmplx_dbl_6dt(filename, tensor)
187 character(len=*), intent(in) :: filename
188 complex(8), intent(in) :: tensor(:, :, :, :, :, :)
189 character(len=*), parameter :: var_type = "<c16"
190 integer(int32) :: p_un
191 open (newunit=p_un, file=filename, form="unformatted", access="stream")
192 call write_header(p_un, var_type, shape(tensor))
193 write (p_un) tensor
194 close (unit=p_un)
195 end subroutine write_cmplx_dbl_6dt
196
197 subroutine write_cmplx_dbl_5dt(filename, tensor)
198 character(len=*), intent(in) :: filename
199 complex(8), intent(in) :: tensor(:, :, :, :, :)
200 character(len=*), parameter :: var_type = "<c16"
201 integer(int32) :: p_un
202 open (newunit=p_un, file=filename, form="unformatted", access="stream")
203 call write_header(p_un, var_type, shape(tensor))
204 write (p_un) tensor
205 close (unit=p_un)
206 end subroutine write_cmplx_dbl_5dt
207
208 subroutine write_cmplx_dbl_4dt(filename, tensor)
209 character(len=*), intent(in) :: filename
210 complex(8), intent(in) :: tensor(:, :, :, :)
211 character(len=*), parameter :: var_type = "<c16"
212 integer(int32) :: p_un
213 open (newunit=p_un, file=filename, form="unformatted", access="stream")
214 call write_header(p_un, var_type, shape(tensor))
215 write (p_un) tensor
216 close (unit=p_un)
217 end subroutine write_cmplx_dbl_4dt
218
219 subroutine write_cmplx_dbl_3dt(filename, tensor)
220 character(len=*), intent(in) :: filename
221 complex(8), intent(in) :: tensor(:, :, :)
222 character(len=*), parameter :: var_type = "<c16"
223 integer(int32) :: p_un
224 open (newunit=p_un, file=filename, form="unformatted", access="stream")
225 call write_header(p_un, var_type, shape(tensor))
226 write (p_un) tensor
227 close (unit=p_un)
228 end subroutine write_cmplx_dbl_3dt
229
230 subroutine write_cmplx_dbl_mtx(filename, mtx)
231 character(len=*), intent(in) :: filename
232 complex(8), intent(in) :: mtx(:, :)
233 character(len=*), parameter :: var_type = "<c16"
234 integer(int32) :: p_un
235 open (newunit=p_un, file=filename, form="unformatted", access="stream")
236 call write_header(p_un, var_type, shape(mtx))
237 write (p_un) mtx
238 close (unit=p_un)
239 end subroutine write_cmplx_dbl_mtx
240
241 subroutine write_cmplx_dbl_vec(filename, vec)
242 character(len=*), intent(in) :: filename
243 complex(8), intent(in) :: vec(:)
244 character(len=*), parameter :: var_type = "<c16"
245 integer(int32) :: p_un
246 open (newunit=p_un, file=filename, form="unformatted", access="stream")
247 call write_header(p_un, var_type, shape(vec))
248 write (p_un) vec
249 close (unit=p_un)
250 end subroutine write_cmplx_dbl_vec
251
252 subroutine write_sng_3dt(filename, tensor)
253 character(len=*), intent(in) :: filename
254 real(real32), intent(in) :: tensor(:, :, :)
255 character(len=*), parameter :: var_type = "<f4"
256 integer(int32) :: p_un
257 open (newunit=p_un, file=filename, form="unformatted", access="stream")
258 call write_header(p_un, var_type, shape(tensor))
259 write (p_un) tensor
260 close (unit=p_un)
261 end subroutine write_sng_3dt
262
263 subroutine write_sng_4dt(filename, tensor)
264 character(len=*), intent(in) :: filename
265 real(real32), intent(in) :: tensor(:, :, :, :)
266 character(len=*), parameter :: var_type = "<f4"
267 integer(int32) :: p_un
268 open (newunit=p_un, file=filename, form="unformatted", access="stream")
269 call write_header(p_un, var_type, shape(tensor))
270 write (p_un) tensor
271 close (unit=p_un)
272 end subroutine write_sng_4dt
273
274 subroutine write_sng_mtx(filename, mtx)
275 character(len=*), intent(in) :: filename
276 real(real32), intent(in) :: mtx(:, :)
277 character(len=*), parameter :: var_type = "<f4"
278 integer(int32) :: p_un
279 open (newunit=p_un, file=filename, form="unformatted", access="stream")
280 call write_header(p_un, var_type, shape(mtx))
281 write (p_un) mtx
282 close (unit=p_un)
283 end subroutine write_sng_mtx
284
285 subroutine write_sng_vec(filename, vec)
286 character(len=*), intent(in) :: filename
287 real(real32), intent(in) :: vec(:)
288 character(len=*), parameter :: var_type = "<f4"
289 integer(int32) :: p_un
290 open (newunit=p_un, file=filename, form="unformatted", access="stream")
291 call write_header(p_un, var_type, shape(vec))
292 write (p_un) vec
293 close (unit=p_un)
294 end subroutine write_sng_vec
295
296 subroutine write_dbl_3dt(filename, tensor)
297 character(len=*), intent(in) :: filename
298 real(real64), intent(in) :: tensor(:, :, :)
299 character(len=*), parameter :: var_type = "<f8"
300 integer(int32) :: p_un
301 open (newunit=p_un, file=filename, form="unformatted", access="stream")
302 call write_header(p_un, var_type, shape(tensor))
303 write (p_un) tensor
304 close (unit=p_un)
305 end subroutine write_dbl_3dt
306
307 subroutine write_dbl_4dt(filename, tensor4)
308 character(len=*), intent(in) :: filename
309 real(real64), intent(in) :: tensor4(:, :, :, :)
310 character(len=*), parameter :: var_type = "<f8"
311 integer(int32) :: p_un
312 open (newunit=p_un, file=filename, form="unformatted", access="stream")
313 call write_header(p_un, var_type, shape(tensor4))
314 write (p_un) tensor4
315 close (unit=p_un)
316 end subroutine write_dbl_4dt
317
318 subroutine write_dbl_5dt(filename, tensor5)
319 character(len=*), intent(in) :: filename
320 real(real64), intent(in) :: tensor5(:, :, :, :, :)
321 character(len=*), parameter :: var_type = "<f8"
322 integer(int32) :: p_un
323 open (newunit=p_un, file=filename, form="unformatted", access="stream")
324 call write_header(p_un, var_type, shape(tensor5))
325 write (p_un) tensor5
326 close (unit=p_un)
327 end subroutine write_dbl_5dt
328
329 subroutine write_dbl_mtx(filename, mtx)
330 character(len=*), intent(in) :: filename
331 real(real64), intent(in) :: mtx(:, :)
332 character(len=*), parameter :: var_type = "<f8"
333 integer(int32) :: p_un
334 open (newunit=p_un, file=filename, form="unformatted", access="stream")
335 call write_header(p_un, var_type, shape(mtx))
336 write (p_un) mtx
337 close (unit=p_un)
338 end subroutine write_dbl_mtx
339
340 subroutine write_dbl_vec(filename, vec)
341 character(len=*), intent(in) :: filename
342 real(real64), intent(in) :: vec(:)
343 character(len=*), parameter :: var_type = "<f8"
344 integer(int32) :: p_un
345 open (newunit=p_un, file=filename, form="unformatted", access="stream")
346 call write_header(p_un, var_type, shape(vec))
347 write (p_un) vec
348 close (unit=p_un)
349 end subroutine write_dbl_vec
350
351 subroutine write_int64_mtx(filename, mtx)
352 character(len=*), intent(in) :: filename
353 integer(int64), intent(in) :: mtx(:, :)
354 character(len=*), parameter :: var_type = "<i8"
355 integer(int32) :: p_un
356 open (newunit=p_un, file=filename, form="unformatted", access="stream")
357 call write_header(p_un, var_type, shape(mtx))
358 write (p_un) mtx
359 close (unit=p_un)
360 end subroutine write_int64_mtx
361
362 subroutine write_int64_vec(filename, vec)
363 character(len=*), intent(in) :: filename
364 integer(int64), intent(in) :: vec(:)
365 character(len=*), parameter :: var_type = "<i8"
366 integer(int32) :: p_un
367 open (newunit=p_un, file=filename, form="unformatted", access="stream")
368 call write_header(p_un, var_type, shape(vec))
369 write (p_un) vec
370 close (unit=p_un)
371 end subroutine write_int64_vec
372
373 subroutine write_int32_mtx(filename, mtx)
374 character(len=*), intent(in) :: filename
375 integer(int32), intent(in) :: mtx(:, :)
376 character(len=*), parameter :: var_type = "<i4"
377 integer(int32) :: p_un
378 open (newunit=p_un, file=filename, form="unformatted", access="stream")
379 call write_header(p_un, var_type, shape(mtx))
380 write (p_un) mtx
381 close (unit=p_un)
382 end subroutine write_int32_mtx
383
384 subroutine write_int32_3d(filename, mtx)
385 character(len=*), intent(in) :: filename
386 integer(int32), intent(in) :: mtx(:,:,:)
387 character(len=*), parameter :: var_type = "<i4"
388 integer(int32) :: p_un
389 open (newunit=p_un, file=filename, form="unformatted", access="stream")
390 call write_header(p_un, var_type, shape(mtx))
391 write (p_un) mtx
392 close (unit=p_un)
393 end subroutine write_int32_3d
394
395 subroutine write_int32_vec(filename, vec)
396 character(len=*), intent(in) :: filename
397 integer(int32), intent(in) :: vec(:)
398 character(len=*), parameter :: var_type = "<i4"
399 integer(int32) :: p_un
400 open (newunit=p_un, file=filename, form="unformatted", access="stream")
401 call write_header(p_un, var_type, shape(vec))
402 write (p_un) vec
403 close (unit=p_un)
404 end subroutine write_int32_vec
405
406 subroutine write_int16_mtx(filename, mtx)
407 character(len=*), intent(in) :: filename
408 integer(int16), intent(in) :: mtx(:, :)
409 character(len=*), parameter :: var_type = "<i2"
410 integer(int32) :: p_un
411 open (newunit=p_un, file=filename, form="unformatted", access="stream")
412 call write_header(p_un, var_type, shape(mtx))
413 write (p_un) mtx
414 close (unit=p_un)
415 end subroutine write_int16_mtx
416
417 subroutine write_int16_vec(filename, vec)
418 character(len=*), intent(in) :: filename
419 integer(int16), intent(in) :: vec(:)
420 character(len=*), parameter :: var_type = "<i2"
421 integer(int32) :: p_un
422 open (newunit=p_un, file=filename, form="unformatted", access="stream")
423 call write_header(p_un, var_type, shape(vec))
424 write (p_un) vec
425 close (unit=p_un)
426 end subroutine write_int16_vec
427
428 subroutine write_int8_mtx(filename, mtx)
429 character(len=*), intent(in) :: filename
430 integer(int8), intent(in) :: mtx(:, :)
431 character(len=*), parameter :: var_type = "<i1"
432 integer(int32) :: p_un
433 open (newunit=p_un, file=filename, form="unformatted", access="stream")
434 call write_header(p_un, var_type, shape(mtx))
435 write (p_un) mtx
436 close (unit=p_un)
437 end subroutine write_int8_mtx
438
439 subroutine write_int8_3d(filename, mtx)
440 character(len=*), intent(in) :: filename
441 integer(int8), intent(in) :: mtx(:,:,:)
442 character(len=*), parameter :: var_type = "<i1"
443 integer(int32) :: p_un
444 open (newunit=p_un, file=filename, form="unformatted", access="stream")
445 call write_header(p_un, var_type, shape(mtx))
446 write (p_un) mtx
447 close (unit=p_un)
448 end subroutine write_int8_3d
449
450 subroutine write_int8_vec(filename, vec)
451 character(len=*), intent(in) :: filename
452 integer(int8), intent(in) :: vec(:)
453 character(len=*), parameter :: var_type = "<i1"
454 integer(int32) :: p_un
455 open (newunit=p_un, file=filename, form="unformatted", access="stream")
456 call write_header(p_un, var_type, shape(vec))
457 write (p_un) vec
458 close (unit=p_un)
459 end subroutine write_int8_vec
460
461end module m_npy
Definition: m_npy.f90:1