PartMC  2.8.0
netcdf.F90
Go to the documentation of this file.
1 ! Copyright (C) 2007-2010, 2012 Matthew West
2 ! Licensed under the GNU General Public License version 2 or (at your
3 ! option) any later version. See the file COPYING for details.
4 
5 !> \file
6 !> The pmc_netcdf module.
7 
8 !> Wrapper functions for NetCDF. These all take a NetCDF \c ncid in
9 !> data mode and return with it again in data mode. Shifting to define
10 !> mode is handled internally within each subroutine.
11 module pmc_netcdf
12 
13  use netcdf
14  use pmc_util
15  use pmc_rand
16 
17 contains
18 
19 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
20 
21  !> Check the status of a NetCDF function call.
22  subroutine pmc_nc_check(status)
23 
24  !> Status return value.
25  integer, intent(in) :: status
26 
27  if (status /= nf90_noerr) then
28  call die_msg(291021908, nf90_strerror(status))
29  end if
30 
31  end subroutine pmc_nc_check
32 
33 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
34 
35  !> Check the status of a NetCDF function call and prints the given
36  !> error message on failure.
37  subroutine pmc_nc_check_msg(status, error_msg)
38 
39  !> Status return value.
40  integer, intent(in) :: status
41  !> Error message in case of failure.
42  character(len=*), intent(in) :: error_msg
43 
44  if (status /= nf90_noerr) then
45  call die_msg(701841139, trim(error_msg) &
46  // " : " // trim(nf90_strerror(status)))
47  end if
48 
49  end subroutine pmc_nc_check_msg
50 
51 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
52 
53  !> Open a NetCDF file for reading.
54  subroutine pmc_nc_open_read(filename, ncid)
55 
56  !> Filename of NetCDF file to open.
57  character(len=*), intent(in) :: filename
58  !> NetCDF file ID, in data mode.
59  integer, intent(out) :: ncid
60 
61  call pmc_nc_check_msg(nf90_open(filename, nf90_nowrite, ncid), &
62  "opening " // trim(filename) // " for reading")
63 
64  end subroutine pmc_nc_open_read
65 
66 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
67 
68  !> Open a NetCDF file for writing.
69  subroutine pmc_nc_open_write(filename, ncid)
70 
71  !> Filename of NetCDF file to open.
72  character(len=*), intent(in) :: filename
73  !> NetCDF file ID, in data mode, returns in data mode.
74  integer, intent(out) :: ncid
75 
76  call pmc_nc_check_msg(nf90_create(filename, nf90_netcdf4, ncid), &
77  "opening " // trim(filename) // " for writing")
78 
79  call pmc_nc_check(nf90_enddef(ncid))
80 
81  end subroutine pmc_nc_open_write
82 
83 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
84 
85  !> Close a NetCDF file.
86  subroutine pmc_nc_close(ncid)
87 
88  !> NetCDF file ID, in data mode.
89  integer, intent(in) :: ncid
90 
91  call pmc_nc_check_msg(nf90_close(ncid), "closing NetCDF file")
92 
93  end subroutine pmc_nc_close
94 
95 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
96 
97  !> Write basic information to a NetCDF file.
98  subroutine pmc_nc_write_info(ncid, uuid, source, write_rank, write_n_proc)
99 
100  !> NetCDF file ID, in data mode.
101  integer, intent(in) :: ncid
102  !> UUID for this data set.
103  character(len=PMC_UUID_LEN), intent(in) :: uuid
104  !> Source name for this data.
105  character(len=*), intent(in) :: source
106  !> Rank to write into file.
107  integer, intent(in), optional :: write_rank
108  !> Number of processes to write into file.
109  integer, intent(in), optional :: write_n_proc
110 
111  character(len=(len_trim(source) + 100)) :: history
112  integer :: use_rank, use_n_proc
113 
114  call pmc_nc_check(nf90_redef(ncid))
115  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "title", &
116  trim(source) // " output file"))
117  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "source", source))
118  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "UUID", uuid))
119  call iso8601_date_and_time(history)
120  history((len_trim(history)+1):) = (" created by " // trim(source))
121  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "history", history))
122  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "Conventions", "CF-1.4"))
123  call pmc_nc_check(nf90_enddef(ncid))
124 
125  if (present(write_rank)) then
126  use_rank = write_rank
127  else
128  use_rank = pmc_mpi_rank()
129  end if
130  if (present(write_n_proc)) then
131  use_n_proc = write_n_proc
132  else
133  use_n_proc = pmc_mpi_size()
134  end if
135 
136 #ifdef PMC_USE_MPI
137  call pmc_nc_write_integer(ncid, use_rank + 1, "process", &
138  description="the process number (starting from 1) " &
139  // "that output this data file")
140  call pmc_nc_write_integer(ncid, use_n_proc, "total_processes", &
141  description="total number of processes")
142 #endif
143 
144  end subroutine pmc_nc_write_info
145 
146 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
147 
148  !> Read a single real from a NetCDF file.
149  subroutine pmc_nc_read_real(ncid, var, name, must_be_present)
150 
151  !> NetCDF file ID, in data mode.
152  integer, intent(in) :: ncid
153  !> Data to write.
154  real(kind=dp), intent(out) :: var
155  !> Variable name in NetCDF file.
156  character(len=*), intent(in) :: name
157  !> Whether the variable must be present in the NetCDF file
158  !> (default .true.).
159  logical, optional, intent(in) :: must_be_present
160 
161  integer :: varid, status
162  logical :: use_must_be_present
163 
164  if (present(must_be_present)) then
165  use_must_be_present = must_be_present
166  else
167  use_must_be_present = .true.
168  end if
169  status = nf90_inq_varid(ncid, name, varid)
170  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
171  ! variable was not present, but that's ok
172  var = 0d0
173  return
174  end if
175  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
176  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
177  "getting variable " // trim(name))
178 
179  end subroutine pmc_nc_read_real
180 
181 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
182 
183  !> Read a single integer from a NetCDF file.
184  subroutine pmc_nc_read_integer(ncid, var, name, must_be_present)
185 
186  !> NetCDF file ID, in data mode.
187  integer, intent(in) :: ncid
188  !> Data to write.
189  integer, intent(out) :: var
190  !> Variable name in NetCDF file.
191  character(len=*), intent(in) :: name
192  !> Whether the variable must be present in the NetCDF file
193  !> (default .true.).
194  logical, optional, intent(in) :: must_be_present
195 
196  integer :: varid, status
197  logical :: use_must_be_present
198 
199  if (present(must_be_present)) then
200  use_must_be_present = must_be_present
201  else
202  use_must_be_present = .true.
203  end if
204  status = nf90_inq_varid(ncid, name, varid)
205  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
206  ! variable was not present, but that's ok
207  var = 0
208  return
209  end if
210  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
211  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
212  "getting variable " // trim(name))
213 
214  end subroutine pmc_nc_read_integer
215 
216 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
217 
218  !> Read a single 64 bit integer from a NetCDF file.
219  subroutine pmc_nc_read_integer64(ncid, var, name, must_be_present)
220 
221  !> NetCDF file ID, in data mode.
222  integer, intent(in) :: ncid
223  !> Data to write.
224  integer(kind=8), intent(out) :: var
225  !> Variable name in NetCDF file.
226  character(len=*), intent(in) :: name
227  !> Whether the variable must be present in the NetCDF file
228  !> (default .true.).
229  logical, optional, intent(in) :: must_be_present
230 
231  integer :: varid, status
232  logical :: use_must_be_present
233 
234  if (present(must_be_present)) then
235  use_must_be_present = must_be_present
236  else
237  use_must_be_present = .true.
238  end if
239  status = nf90_inq_varid(ncid, name, varid)
240  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
241  ! variable was not present, but that's ok
242  var = 0
243  return
244  end if
245  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
246  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
247  "getting variable " // trim(name))
248 
249  end subroutine pmc_nc_read_integer64
250 
251 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
252 
253  !> Read a simple real array from a NetCDF file.
254  subroutine pmc_nc_read_real_1d(ncid, var, name, must_be_present)
255 
256  !> NetCDF file ID, in data mode.
257  integer, intent(in) :: ncid
258  !> Data to read.
259  real(kind=dp), intent(inout), allocatable :: var(:)
260  !> Variable name in NetCDF file.
261  character(len=*), intent(in) :: name
262  !> Whether the variable must be present in the NetCDF file
263  !> (default .true.).
264  logical, optional, intent(in) :: must_be_present
265 
266  integer :: varid, status, dimids(1), size1
267  logical :: use_must_be_present
268 
269  if (present(must_be_present)) then
270  use_must_be_present = must_be_present
271  else
272  use_must_be_present = .true.
273  end if
274  status = nf90_inq_varid(ncid, name, varid)
275  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
276  ! variable was not present, but that's ok, set it to empty
277  var = [real(kind=dp)::]
278  return
279  end if
280  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
281  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
282  "determining size of variable " // trim(name))
283  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
284  "determining size of dimension number " &
285  // trim(integer_to_string(dimids(1))))
286  call ensure_real_array_size(var, size1)
287  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
288  "getting variable " // trim(name))
289 
290  end subroutine pmc_nc_read_real_1d
291 
292 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
293 
294  !> Read a simple integer array from a NetCDF file.
295  subroutine pmc_nc_read_integer_1d(ncid, var, name, must_be_present)
296 
297  !> NetCDF file ID, in data mode.
298  integer, intent(in) :: ncid
299  !> Data to read.
300  integer, intent(inout), allocatable :: var(:)
301  !> Variable name in NetCDF file.
302  character(len=*), intent(in) :: name
303  !> Whether the variable must be present in the NetCDF file
304  !> (default .true.).
305  logical, optional, intent(in) :: must_be_present
306 
307  integer :: varid, status, dimids(1), size1
308  logical :: use_must_be_present
309 
310  if (present(must_be_present)) then
311  use_must_be_present = must_be_present
312  else
313  use_must_be_present = .true.
314  end if
315  status = nf90_inq_varid(ncid, name, varid)
316  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
317  ! variable was not present, but that's ok
318  var = [integer::]
319  return
320  end if
321  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
322  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
323  "determining size of variable " // trim(name))
324  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
325  "determining size of dimension number " &
326  // trim(integer_to_string(dimids(1))))
327  call ensure_integer_array_size(var, size1)
328  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
329  "getting variable " // trim(name))
330 
331  end subroutine pmc_nc_read_integer_1d
332 
333 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
334 
335  !> Read a 64 bit integer array from a NetCDF file.
336  subroutine pmc_nc_read_integer64_1d(ncid, var, name, must_be_present)
337 
338  !> NetCDF file ID, in data mode.
339  integer, intent(in) :: ncid
340  !> Data to read.
341  integer(kind=8), intent(inout), allocatable :: var(:)
342  !> Variable name in NetCDF file.
343  character(len=*), intent(in) :: name
344  !> Whether the variable must be present in the NetCDF file
345  !> (default .true.).
346  logical, optional, intent(in) :: must_be_present
347 
348  integer :: varid, status, dimids(1), size1
349  logical :: use_must_be_present
350 
351  if (present(must_be_present)) then
352  use_must_be_present = must_be_present
353  else
354  use_must_be_present = .true.
355  end if
356  status = nf90_inq_varid(ncid, name, varid)
357  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
358  ! variable was not present, but that's ok
359  var = [integer::]
360  return
361  end if
362  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
363  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
364  "determining size of variable " // trim(name))
365  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
366  "determining size of dimension number " &
367  // trim(integer_to_string(dimids(1))))
368  call ensure_integer64_array_size(var, size1)
369  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
370  "getting variable " // trim(name))
371 
372  end subroutine pmc_nc_read_integer64_1d
373 
374 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
375 
376  !> Read a simple real 2D array from a NetCDF file.
377  subroutine pmc_nc_read_real_2d(ncid, var, name, must_be_present)
378 
379  !> NetCDF file ID, in data mode.
380  integer, intent(in) :: ncid
381  !> Data to read.
382  real(kind=dp), intent(inout), allocatable :: var(:,:)
383  !> Variable name in NetCDF file.
384  character(len=*), intent(in) :: name
385  !> Whether the variable must be present in the NetCDF file
386  !> (default .true.).
387  logical, optional, intent(in) :: must_be_present
388 
389  integer :: varid, status, dimids(2), size1, size2
390  logical :: use_must_be_present
391 
392  if (present(must_be_present)) then
393  use_must_be_present = must_be_present
394  else
395  use_must_be_present = .true.
396  end if
397  status = nf90_inq_varid(ncid, name, varid)
398  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
399  ! variable was not present, but that's ok
400  var = reshape([real(kind=dp)::], [0, 0])
401  return
402  end if
403  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
404  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
405  "determining size of variable " // trim(name))
406  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
407  "determining size of dimension number " &
408  // trim(integer_to_string(dimids(1))))
409  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(2), len=size2), &
410  "determining size of dimension number " &
411  // trim(integer_to_string(dimids(2))))
412  call ensure_real_array_2d_size(var, size1, size2)
413  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
414  "getting variable " // trim(name))
415 
416  end subroutine pmc_nc_read_real_2d
417 
418 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
419 
420  !> Read a simple integer 2D array from a NetCDF file.
421  subroutine pmc_nc_read_integer_2d(ncid, var, name, must_be_present)
422 
423  !> NetCDF file ID, in data mode.
424  integer, intent(in) :: ncid
425  !> Data to read.
426  integer, intent(inout), allocatable :: var(:,:)
427  !> Variable name in NetCDF file.
428  character(len=*), intent(in) :: name
429  !> Whether the variable must be present in the NetCDF file
430  !> (default .true.).
431  logical, optional, intent(in) :: must_be_present
432 
433  integer :: varid, status, dimids(2), size1, size2
434  logical :: use_must_be_present
435 
436  if (present(must_be_present)) then
437  use_must_be_present = must_be_present
438  else
439  use_must_be_present = .true.
440  end if
441  status = nf90_inq_varid(ncid, name, varid)
442  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
443  ! variable was not present, but that's ok
444  var = reshape([integer::], [0, 0])
445  return
446  end if
447  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
448  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
449  "determining size of variable " // trim(name))
450  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
451  "determining size of dimension number " &
452  // trim(integer_to_string(dimids(1))))
453  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(2), len=size2), &
454  "determining size of dimension number " &
455  // trim(integer_to_string(dimids(2))))
456  call ensure_integer_array_2d_size(var, size1, size2)
457  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
458  "getting variable " // trim(name))
459 
460  end subroutine pmc_nc_read_integer_2d
461 
462 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
463 
464  !> Read a simple integer 3D array from a NetCDF file.
465  subroutine pmc_nc_read_integer_3d(ncid, var, name, must_be_present)
466 
467  !> NetCDF file ID, in data mode.
468  integer, intent(in) :: ncid
469  !> Data to read.
470  integer, intent(inout), allocatable :: var(:,:,:)
471  !> Variable name in NetCDF file.
472  character(len=*), intent(in) :: name
473  !> Whether the variable must be present in the NetCDF file
474  !> (default .true.).
475  logical, optional, intent(in) :: must_be_present
476 
477  integer :: varid, status, dimids(3), size1, size2, size3
478  logical :: use_must_be_present
479 
480  if (present(must_be_present)) then
481  use_must_be_present = must_be_present
482  else
483  use_must_be_present = .true.
484  end if
485  status = nf90_inq_varid(ncid, name, varid)
486  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
487  ! variable was not present, but that's ok
488  var = reshape([integer::], [0, 0, 0])
489  return
490  end if
491  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
492  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
493  "determining size of variable " // trim(name))
494  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
495  "determining size of dimension number " &
496  // trim(integer_to_string(dimids(1))))
497  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(2), len=size2), &
498  "determining size of dimension number " &
499  // trim(integer_to_string(dimids(2))))
500  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(3), len=size3), &
501  "determining size of dimension number " &
502  // trim(integer_to_string(dimids(3))))
503  call ensure_integer_array_3d_size(var, size1, size2, size3)
504  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
505  "getting variable " // trim(name))
506 
507  end subroutine pmc_nc_read_integer_3d
508 
509 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
510 
511  !> Read a simple real 3D array from a NetCDF file.
512  subroutine pmc_nc_read_real_3d(ncid, var, name, must_be_present)
513 
514  !> NetCDF file ID, in data mode.
515  integer, intent(in) :: ncid
516  !> Data to read.
517  real(kind=dp), allocatable, intent(out) :: var(:,:,:)
518  !> Variable name in NetCDF file.
519  character(len=*), intent(in) :: name
520  !> Whether the variable must be present in the NetCDF file
521  !> (default .true.).
522  logical, optional, intent(in) :: must_be_present
523 
524  integer :: varid, status
525  logical :: use_must_be_present
526  integer :: dimids(3)
527  integer :: size1, size2, size3
528 
529  if (present(must_be_present)) then
530  use_must_be_present = must_be_present
531  else
532  use_must_be_present = .true.
533  end if
534  status = nf90_inq_varid(ncid, name, varid)
535  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
536  ! variable was not present, but that's ok
537  var = reshape([real(kind=dp)::], [0, 0, 0])
538  return
539  end if
540  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
541  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
542  "determining size of variable " // trim(name))
543  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
544  "determining size of dimension number " &
545  // trim(integer_to_string(dimids(1))))
546  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(2), len=size2), &
547  "determining size of dimension number " &
548  // trim(integer_to_string(dimids(2))))
549  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(3), len=size3), &
550  "determining size of dimension number " &
551  // trim(integer_to_string(dimids(3))))
552  call ensure_real_array_3d_size(var, size1, size2, size3)
553  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
554  "getting variable " // trim(name))
555 
556  end subroutine pmc_nc_read_real_3d
557 
558 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
559 
560  !> Read a simple real 4D array from a NetCDF file.
561  subroutine pmc_nc_read_real_4d(ncid, var, name, must_be_present)
562 
563  !> NetCDF file ID, in data mode.
564  integer, intent(in) :: ncid
565  !> Data to read.
566  real(kind=dp), allocatable, intent(out) :: var(:,:,:,:)
567  !> Variable name in NetCDF file.
568  character(len=*), intent(in) :: name
569  !> Whether the variable must be present in the NetCDF file
570  !> (default .true.).
571  logical, optional, intent(in) :: must_be_present
572 
573  integer :: varid, status
574  logical :: use_must_be_present
575  integer :: dimids(4)
576  integer :: size1, size2, size3, size4
577 
578  if (present(must_be_present)) then
579  use_must_be_present = must_be_present
580  else
581  use_must_be_present = .true.
582  end if
583  status = nf90_inq_varid(ncid, name, varid)
584  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
585  ! variable was not present, but that's ok
586  var = reshape([real(kind=dp)::], [0, 0, 0, 0])
587  return
588  end if
589  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
590  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
591  "determining size of variable " // trim(name))
592  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
593  "determining size of dimension number " &
594  // trim(integer_to_string(dimids(1))))
595  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(2), len=size2), &
596  "determining size of dimension number " &
597  // trim(integer_to_string(dimids(2))))
598  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(3), len=size3), &
599  "determining size of dimension number " &
600  // trim(integer_to_string(dimids(3))))
601  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(4), len=size4), &
602  "determining size of dimension number " &
603  // trim(integer_to_string(dimids(4))))
604  call ensure_real_array_4d_size(var, size1, size2, size3, size4)
605  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
606  "getting variable " // trim(name))
607 
608  end subroutine pmc_nc_read_real_4d
609 
610 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
611 
612  !> Read a simple integer 4D array from a NetCDF file.
613  subroutine pmc_nc_read_integer_4d(ncid, var, name, must_be_present)
614 
615  !> NetCDF file ID, in data mode.
616  integer, intent(in) :: ncid
617  !> Data to read.
618  integer, allocatable, intent(out) :: var(:,:,:,:)
619  !> Variable name in NetCDF file.
620  character(len=*), intent(in) :: name
621  !> Whether the variable must be present in the NetCDF file
622  !> (default .true.).
623  logical, optional, intent(in) :: must_be_present
624 
625  integer :: varid, status
626  logical :: use_must_be_present
627  integer :: dimids(4)
628  integer :: size1, size2, size3, size4
629 
630  if (present(must_be_present)) then
631  use_must_be_present = must_be_present
632  else
633  use_must_be_present = .true.
634  end if
635  status = nf90_inq_varid(ncid, name, varid)
636  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
637  ! variable was not present, but that's ok
638  var = reshape([integer::], [0, 0, 0, 0])
639  return
640  end if
641  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
642  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
643  "determining size of variable " // trim(name))
644  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
645  "determining size of dimension number " &
646  // trim(integer_to_string(dimids(1))))
647  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(2), len=size2), &
648  "determining size of dimension number " &
649  // trim(integer_to_string(dimids(2))))
650  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(3), len=size3), &
651  "determining size of dimension number " &
652  // trim(integer_to_string(dimids(3))))
653  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(4), len=size4), &
654  "determining size of dimension number " &
655  // trim(integer_to_string(dimids(4))))
656  call ensure_integer_array_4d_size(var, size1, size2, size3, size4)
657  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
658  "getting variable " // trim(name))
659 
660  end subroutine pmc_nc_read_integer_4d
661 
662 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
663 
664  !> Write attributes for a variable to a NetCDF file.
665  subroutine pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
666  description)
667 
668  !> NetCDF file ID, in define mode.
669  integer, intent(in) :: ncid
670  !> Variable ID to write attributes for.
671  integer, intent(in) :: varid
672  !> Unit of variable.
673  character(len=*), optional, intent(in) :: unit
674  !> Long name of variable.
675  character(len=*), optional, intent(in) :: long_name
676  !> Standard name of variable.
677  character(len=*), optional, intent(in) :: standard_name
678  !> Description of variable.
679  character(len=*), optional, intent(in) :: description
680 
681  if (present(unit)) then
682  call pmc_nc_check(nf90_put_att(ncid, varid, "unit", unit))
683  end if
684  if (present(long_name)) then
685  call pmc_nc_check(nf90_put_att(ncid, varid, "long_name", long_name))
686  end if
687  if (present(standard_name)) then
688  call pmc_nc_check(nf90_put_att(ncid, varid, "standard_name", &
689  standard_name))
690  end if
691  if (present(description)) then
692  call pmc_nc_check(nf90_put_att(ncid, varid, "description", &
693  description))
694  end if
695 
696  end subroutine pmc_nc_write_atts
697 
698 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
699 
700  !> Write a single real to a NetCDF file.
701  subroutine pmc_nc_write_real(ncid, var, name, unit, long_name, &
702  standard_name, description)
703 
704  !> NetCDF file ID, in data mode.
705  integer, intent(in) :: ncid
706  !> Data to write.
707  real(kind=dp), intent(in) :: var
708  !> Variable name in NetCDF file.
709  character(len=*), intent(in) :: name
710  !> Unit of variable.
711  character(len=*), optional, intent(in) :: unit
712  !> Long name of variable.
713  character(len=*), optional, intent(in) :: long_name
714  !> Standard name of variable.
715  character(len=*), optional, intent(in) :: standard_name
716  !> Description of variable.
717  character(len=*), optional, intent(in) :: description
718 
719  integer :: varid, dimids(0)
720 
721  call pmc_nc_check(nf90_redef(ncid))
722  call pmc_nc_check(nf90_def_var(ncid, name, nf90_double, dimids, varid))
723  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
724  description)
725  call pmc_nc_check(nf90_enddef(ncid))
726 
727  call pmc_nc_check(nf90_put_var(ncid, varid, var))
728 
729  end subroutine pmc_nc_write_real
730 
731 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
732 
733  !> Write a single integer to a NetCDF file.
734  subroutine pmc_nc_write_integer(ncid, var, name, unit, long_name, &
735  standard_name, description)
736 
737  !> NetCDF file ID, in data mode.
738  integer, intent(in) :: ncid
739  !> Data to write.
740  integer, intent(in) :: var
741  !> Variable name in NetCDF file.
742  character(len=*), intent(in) :: name
743  !> Unit of variable.
744  character(len=*), optional, intent(in) :: unit
745  !> Long name of variable.
746  character(len=*), optional, intent(in) :: long_name
747  !> Standard name of variable.
748  character(len=*), optional, intent(in) :: standard_name
749  !> Description of variable.
750  character(len=*), optional, intent(in) :: description
751 
752  integer :: varid, dimids(0)
753 
754  call pmc_nc_check(nf90_redef(ncid))
755  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int, dimids, varid))
756  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
757  description)
758  call pmc_nc_check(nf90_enddef(ncid))
759 
760  call pmc_nc_check(nf90_put_var(ncid, varid, var))
761 
762  end subroutine pmc_nc_write_integer
763 
764 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
765 
766  !> Write a single 64 bit integer to a NetCDF file.
767  subroutine pmc_nc_write_integer64(ncid, var, name, unit, long_name, &
768  standard_name, description)
769 
770  !> NetCDF file ID, in data mode.
771  integer, intent(in) :: ncid
772  !> Data to write.
773  integer(kind=8), intent(in) :: var
774  !> Variable name in NetCDF file.
775  character(len=*), intent(in) :: name
776  !> Unit of variable.
777  character(len=*), optional, intent(in) :: unit
778  !> Long name of variable.
779  character(len=*), optional, intent(in) :: long_name
780  !> Standard name of variable.
781  character(len=*), optional, intent(in) :: standard_name
782  !> Description of variable.
783  character(len=*), optional, intent(in) :: description
784 
785  integer :: varid, dimids(0)
786 
787  call pmc_nc_check(nf90_redef(ncid))
788  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int64, dimids, varid))
789  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
790  description)
791  call pmc_nc_check(nf90_enddef(ncid))
792 
793  call pmc_nc_check(nf90_put_var(ncid, varid, var))
794 
795  end subroutine pmc_nc_write_integer64
796 
797 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
798 
799  !> Create a dimension if necessary, or check its size if it already
800  !> exists. In any case return the \c dimid.
801  subroutine pmc_nc_ensure_dim(ncid, dim_name, dimid, dim_size, array_dim)
802 
803  !> NetCDF file ID, in data mode.
804  integer, intent(in) :: ncid
805  !> NetCDF dimension name for the variable.
806  character(len=*), intent(in) :: dim_name
807  !> NetCDF dimension ID.
808  integer, intent(out) :: dimid
809  !> Size of dimension.
810  integer, intent(in) :: dim_size
811  !> Dimension within data array that this NetCDF dim corresponds to.
812  integer, intent(in) :: array_dim
813 
814  integer :: status, check_dim_size
815  character(len=NF90_MAX_NAME) :: check_name
816 
817  status = nf90_inq_dimid(ncid, dim_name, dimid)
818  if (status == nf90_noerr) then
819  call pmc_nc_check(nf90_inquire_dimension(ncid, dimid, check_name, &
820  check_dim_size))
821  call assert_msg(657263912, check_dim_size == dim_size, &
822  "dim " // trim(integer_to_string(array_dim)) // " size " &
823  // trim(integer_to_string(dim_size)) &
824  // " of data array does not match size " &
825  // trim(integer_to_string(dim_size)) // " of '" &
826  // trim(dim_name) // "' dim")
827  else
828  ! could not determine dimid
829  if (status /= nf90_ebaddim) then
830  ! the problem was not a missing dimension
831  call pmc_nc_check(status)
832  end if
833  ! the problem was a missing dimension, so make it
834  call pmc_nc_check(nf90_redef(ncid))
835  call pmc_nc_check(nf90_def_dim(ncid, dim_name, dim_size, dimid))
836  call pmc_nc_check(nf90_enddef(ncid))
837  end if
838 
839  end subroutine pmc_nc_ensure_dim
840 
841 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
842 
843  !> Write a simple real array to a NetCDF file.
844  subroutine pmc_nc_write_real_1d(ncid, var, name, dimids, dim_name, unit, &
845  long_name, standard_name, description)
846 
847  !> NetCDF file ID, in data mode.
848  integer, intent(in) :: ncid
849  !> Data to write.
850  real(kind=dp), intent(in) :: var(:)
851  !> Variable name in NetCDF file.
852  character(len=*), intent(in) :: name
853  !> NetCDF dimension IDs of the variable (either this or dim_name
854  !> must be present).
855  integer, optional, intent(in) :: dimids(1)
856  !> NetCDF dimension name for the variable (either this or dimids
857  !> must be present).
858  character(len=*), optional, intent(in) :: dim_name
859  !> Unit of variable.
860  character(len=*), optional, intent(in) :: unit
861  !> Long name of variable.
862  character(len=*), optional, intent(in) :: long_name
863  !> Standard name of variable.
864  character(len=*), optional, intent(in) :: standard_name
865  !> Description of variable.
866  character(len=*), optional, intent(in) :: description
867 
868  integer :: varid, start(1), count(1), use_dimids(1)
869 
870  if (present(dimids)) then
871  use_dimids = dimids
872  elseif (present(dim_name)) then
873  call pmc_nc_ensure_dim(ncid, dim_name, use_dimids(1), size(var), 1)
874  else
875  call die_msg(891890123, "either dimids or dim_name must be present")
876  end if
877  call pmc_nc_check(nf90_redef(ncid))
878  call pmc_nc_check(nf90_def_var(ncid, name, nf90_double, use_dimids, varid))
879  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
880  description)
881  call pmc_nc_check(nf90_enddef(ncid))
882 
883  start = (/ 1 /)
884  count = (/ size(var, 1) /)
885  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
886  start = start, count = count))
887 
888  end subroutine pmc_nc_write_real_1d
889 
890 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
891 
892  !> Write a simple integer array to a NetCDF file.
893  subroutine pmc_nc_write_integer_1d(ncid, var, name, dimids, dim_name, unit, &
894  long_name, standard_name, description)
895 
896  !> NetCDF file ID, in data mode.
897  integer, intent(in) :: ncid
898  !> Data to write.
899  integer, intent(in) :: var(:)
900  !> Variable name in NetCDF file.
901  character(len=*), intent(in) :: name
902  !> NetCDF dimension IDs of the variable (either this or dim_name
903  !> must be present).
904  integer, optional, intent(in) :: dimids(1)
905  !> NetCDF dimension name for the variable (either this or dimids
906  !> must be present).
907  character(len=*), optional, intent(in) :: dim_name
908  !> Unit of variable.
909  character(len=*), optional, intent(in) :: unit
910  !> Long name of variable.
911  character(len=*), optional, intent(in) :: long_name
912  !> Standard name of variable.
913  character(len=*), optional, intent(in) :: standard_name
914  !> Description of variable.
915  character(len=*), optional, intent(in) :: description
916 
917  integer :: varid, start(1), count(1), use_dimids(1)
918 
919  if (present(dimids)) then
920  use_dimids = dimids
921  elseif (present(dim_name)) then
922  call pmc_nc_ensure_dim(ncid, dim_name, use_dimids(1), size(var), 1)
923  else
924  call die_msg(464170526, "either dimids or dim_name must be present")
925  end if
926  call pmc_nc_check(nf90_redef(ncid))
927  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int, use_dimids, varid))
928  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
929  description)
930  call pmc_nc_check(nf90_enddef(ncid))
931 
932  start = (/ 1 /)
933  count = (/ size(var, 1) /)
934  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
935  start = start, count = count))
936 
937  end subroutine pmc_nc_write_integer_1d
938 
939 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
940 
941  !> Write a 64 bit integer array to a NetCDF file.
942  subroutine pmc_nc_write_integer64_1d(ncid, var, name, dimids, dim_name, &
943  unit, long_name, standard_name, description)
944 
945  !> NetCDF file ID, in data mode.
946  integer, intent(in) :: ncid
947  !> Data to write.
948  integer(kind=8), intent(in) :: var(:)
949  !> Variable name in NetCDF file.
950  character(len=*), intent(in) :: name
951  !> NetCDF dimension IDs of the variable (either this or dim_name
952  !> must be present).
953  integer, optional, intent(in) :: dimids(1)
954  !> NetCDF dimension name for the variable (either this or dimids
955  !> must be present).
956  character(len=*), optional, intent(in) :: dim_name
957  !> Unit of variable.
958  character(len=*), optional, intent(in) :: unit
959  !> Long name of variable.
960  character(len=*), optional, intent(in) :: long_name
961  !> Standard name of variable.
962  character(len=*), optional, intent(in) :: standard_name
963  !> Description of variable.
964  character(len=*), optional, intent(in) :: description
965 
966  integer :: varid, start(1), count(1), use_dimids(1)
967 
968  if (present(dimids)) then
969  use_dimids = dimids
970  elseif (present(dim_name)) then
971  call pmc_nc_ensure_dim(ncid, dim_name, use_dimids(1), size(var), 1)
972  else
973  call die_msg(895894487, "either dimids or dim_name must be present")
974  end if
975  call pmc_nc_check(nf90_redef(ncid))
976  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int64, use_dimids, varid))
977  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
978  description)
979  call pmc_nc_check(nf90_enddef(ncid))
980 
981  start = (/ 1 /)
982  count = (/ size(var, 1) /)
983  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
984  start = start, count = count))
985 
986  end subroutine pmc_nc_write_integer64_1d
987 
988 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
989 
990  !> Write a simple real 2D array to a NetCDF file.
991  subroutine pmc_nc_write_real_2d(ncid, var, name, dimids, dim_name_1, &
992  dim_name_2, unit, long_name, standard_name, description)
993 
994  !> NetCDF file ID, in data mode.
995  integer, intent(in) :: ncid
996  !> Data to write.
997  real(kind=dp), intent(in) :: var(:,:)
998  !> Variable name in NetCDF file.
999  character(len=*), intent(in) :: name
1000  !> NetCDF dimension IDs of the variable (either \c dimids or both
1001  !> \c dim_name_1 and \c dim_name_2 must be present).
1002  integer, optional, intent(in) :: dimids(2)
1003  !> First NetCDF dimension name for the variable (either \c dimids
1004  !> or both \c dim_name_1 and \c dim_name 2 must be present).
1005  character(len=*), optional, intent(in) :: dim_name_1
1006  !> Second NetCDF dimension name for the variable (either \c dimids
1007  !> or both \c dim_name_1 and \c dim_name 2 must be present).
1008  character(len=*), optional, intent(in) :: dim_name_2
1009  !> Unit of variable.
1010  character(len=*), optional, intent(in) :: unit
1011  !> Long name of variable.
1012  character(len=*), optional, intent(in) :: long_name
1013  !> Standard name of variable.
1014  character(len=*), optional, intent(in) :: standard_name
1015  !> Description of variable.
1016  character(len=*), optional, intent(in) :: description
1017 
1018  integer :: varid, start(2), count(2), use_dimids(2)
1019 
1020  if (present(dimids)) then
1021  use_dimids = dimids
1022  elseif (present(dim_name_1) .and. present(dim_name_2)) then
1023  call pmc_nc_ensure_dim(ncid, dim_name_1, use_dimids(1), size(var, 1), 1)
1024  call pmc_nc_ensure_dim(ncid, dim_name_2, use_dimids(2), size(var, 2), 2)
1025  else
1026  call die_msg(959111259, &
1027  "either dimids or both dim_name_1 and dim_name_2 must be present")
1028  end if
1029  call pmc_nc_check(nf90_redef(ncid))
1030  call pmc_nc_check(nf90_def_var(ncid, name, nf90_double, use_dimids, varid))
1031  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
1032  description)
1033  call pmc_nc_check(nf90_enddef(ncid))
1034 
1035  start = (/ 1, 1 /)
1036  count = (/ size(var, 1), size(var, 2) /)
1037  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
1038  start = start, count = count))
1039 
1040  end subroutine pmc_nc_write_real_2d
1041 
1042 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1043 
1044  !> Write a simple integer 2D array to a NetCDF file.
1045  subroutine pmc_nc_write_integer_2d(ncid, var, name, dimids, dim_name_1, &
1046  dim_name_2, unit, long_name, standard_name, description)
1047 
1048  !> NetCDF file ID, in data mode.
1049  integer, intent(in) :: ncid
1050  !> Data to write.
1051  integer, intent(in) :: var(:,:)
1052  !> Variable name in NetCDF file.
1053  character(len=*), intent(in) :: name
1054  !> NetCDF dimension IDs of the variable (either \c dimids or both
1055  !> \c dim_name_1 and \c dim_name_2 must be present).
1056  integer, optional, intent(in) :: dimids(2)
1057  !> First NetCDF dimension name for the variable (either \c dimids
1058  !> or both \c dim_name_1 and \c dim_name 2 must be present).
1059  character(len=*), optional, intent(in) :: dim_name_1
1060  !> Second NetCDF dimension name for the variable (either \c dimids
1061  !> or both \c dim_name_1 and \c dim_name 2 must be present).
1062  character(len=*), optional, intent(in) :: dim_name_2
1063  !> Unit of variable.
1064  character(len=*), optional, intent(in) :: unit
1065  !> Long name of variable.
1066  character(len=*), optional, intent(in) :: long_name
1067  !> Standard name of variable.
1068  character(len=*), optional, intent(in) :: standard_name
1069  !> Description of variable.
1070  character(len=*), optional, intent(in) :: description
1071 
1072  integer :: varid, start(2), count(2), use_dimids(2)
1073 
1074  if (present(dimids)) then
1075  use_dimids = dimids
1076  elseif (present(dim_name_1) .and. present(dim_name_2)) then
1077  call pmc_nc_ensure_dim(ncid, dim_name_1, use_dimids(1), size(var, 1), 1)
1078  call pmc_nc_ensure_dim(ncid, dim_name_2, use_dimids(2), size(var, 2), 2)
1079  else
1080  call die_msg(669381383, &
1081  "either dimids or both dim_name_1 and dim_name_2 must be present")
1082  end if
1083  call pmc_nc_check(nf90_redef(ncid))
1084  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int, use_dimids, varid))
1085  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
1086  description)
1087  call pmc_nc_check(nf90_enddef(ncid))
1088 
1089  start = (/ 1, 1 /)
1090  count = (/ size(var, 1), size(var, 2) /)
1091  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
1092  start = start, count = count))
1093 
1094  end subroutine pmc_nc_write_integer_2d
1095 
1096 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1097 
1098  !> Write a simple integer 3D array to a NetCDF file.
1099  subroutine pmc_nc_write_integer_3d(ncid, var, name, dimids, dim_name_1, &
1100  dim_name_2, dim_name_3, unit, long_name, standard_name, description)
1101 
1102  !> NetCDF file ID, in data mode.
1103  integer, intent(in) :: ncid
1104  !> Data to write.
1105  integer, intent(in) :: var(:,:,:)
1106  !> Variable name in NetCDF file.
1107  character(len=*), intent(in) :: name
1108  !> NetCDF dimension IDs of the variable (either \c dimids or both
1109  !> \c dim_name_1 and \c dim_name_2 must be present).
1110  integer, optional, intent(in) :: dimids(3)
1111  !> First NetCDF dimension name for the variable (either \c dimids
1112  !> or all \c dim_name_* must be present).
1113  character(len=*), optional, intent(in) :: dim_name_1
1114  !> Second NetCDF dimension name for the variable (either \c dimids
1115  !> or all \c dim_name_* must be present).
1116  character(len=*), optional, intent(in) :: dim_name_2
1117  !> Third NetCDF dimension name for the variable (either \c dimids
1118  !> or all \c dim_name_* must be present).
1119  character(len=*), optional, intent(in) :: dim_name_3
1120  !> Unit of variable.
1121  character(len=*), optional, intent(in) :: unit
1122  !> Long name of variable.
1123  character(len=*), optional, intent(in) :: long_name
1124  !> Standard name of variable.
1125  character(len=*), optional, intent(in) :: standard_name
1126  !> Description of variable.
1127  character(len=*), optional, intent(in) :: description
1128 
1129  integer :: varid, start(3), count(3), use_dimids(3)
1130 
1131  if (present(dimids)) then
1132  use_dimids = dimids
1133  elseif (present(dim_name_1) .and. present(dim_name_2) .and. &
1134  present(dim_name_3)) then
1135  call pmc_nc_ensure_dim(ncid, dim_name_1, use_dimids(1), size(var, 1), 1)
1136  call pmc_nc_ensure_dim(ncid, dim_name_2, use_dimids(2), size(var, 2), 2)
1137  call pmc_nc_ensure_dim(ncid, dim_name_3, use_dimids(3), size(var, 3), 3)
1138  else
1139  call die_msg(113962002, &
1140  "either dimids or dim_name_1, dim_name_2 and dim_name_3" &
1141  // "must be present")
1142  end if
1143  call pmc_nc_check(nf90_redef(ncid))
1144  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int, use_dimids, varid))
1145  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
1146  description)
1147  call pmc_nc_check(nf90_enddef(ncid))
1148 
1149  start = (/ 1, 1, 1 /)
1150  count = (/ size(var, 1), size(var, 2) , size(var, 3)/)
1151  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
1152  start = start, count = count))
1153 
1154  end subroutine pmc_nc_write_integer_3d
1155 
1156 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1157 
1158  !> Write a simple real 3D array to a NetCDF file.
1159  subroutine pmc_nc_write_real_3d(ncid, var, name, dimids, dim_name_1, &
1160  dim_name_2, dim_name_3, unit, long_name, standard_name, description)
1161 
1162  !> NetCDF file ID, in data mode.
1163  integer, intent(in) :: ncid
1164  !> Data to write.
1165  real(kind=dp), intent(in) :: var(:,:,:)
1166  !> Variable name in NetCDF file.
1167  character(len=*), intent(in) :: name
1168  !> NetCDF dimension IDs of the variable (either \c dimids or both
1169  !> \c dim_name_1 \c dim_name_2 and \c dim_name_3 must be present).
1170  integer, optional, intent(in) :: dimids(3)
1171  !> First NetCDF dimension name for the variable (either \c dimids
1172  !> or all dimension names must be present).
1173  character(len=*), optional, intent(in) :: dim_name_1
1174  !> Second NetCDF dimension name for the variable (either \c dimids
1175  !> or all dimension names must be present).
1176  character(len=*), optional, intent(in) :: dim_name_2
1177  !> Third NetCDF dimension name for the variable (either \c dimids
1178  !> or all dimension names must be present).
1179  character(len=*), optional, intent(in) :: dim_name_3
1180  !> Unit of variable.
1181  character(len=*), optional, intent(in) :: unit
1182  !> Long name of variable.
1183  character(len=*), optional, intent(in) :: long_name
1184  !> Standard name of variable.
1185  character(len=*), optional, intent(in) :: standard_name
1186  !> Description of variable.
1187  character(len=*), optional, intent(in) :: description
1188 
1189  integer :: varid, start(3), count(3), use_dimids(3)
1190 
1191  if (present(dimids)) then
1192  use_dimids = dimids
1193  elseif (present(dim_name_1) .and. present(dim_name_2) .and. &
1194  present(dim_name_3) ) then
1195  call pmc_nc_ensure_dim(ncid, dim_name_1, use_dimids(1), size(var, 1), 1)
1196  call pmc_nc_ensure_dim(ncid, dim_name_2, use_dimids(2), size(var, 2), 2)
1197  call pmc_nc_ensure_dim(ncid, dim_name_3, use_dimids(3), size(var, 3), 3)
1198  else
1199  call die_msg(503513757, "either dimids or dim_name_1, dim_name_2 and " &
1200  // "dim_name_3 must be present")
1201  end if
1202  call pmc_nc_check(nf90_redef(ncid))
1203  call pmc_nc_check(nf90_def_var(ncid, name, nf90_double, use_dimids, varid))
1204  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
1205  description)
1206  call pmc_nc_check(nf90_enddef(ncid))
1207 
1208  start = (/ 1, 1, 1 /)
1209  count = (/ size(var, 1), size(var, 2), size(var, 3) /)
1210  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
1211  start = start, count = count))
1212 
1213  end subroutine pmc_nc_write_real_3d
1214 
1215 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1216 
1217  !> Write a simple real 4D array to a NetCDF file.
1218  subroutine pmc_nc_write_real_4d(ncid, var, name, dimids, dim_name_1, &
1219  dim_name_2, dim_name_3, dim_name_4, unit, long_name, standard_name, &
1220  description)
1221 
1222  !> NetCDF file ID, in data mode.
1223  integer, intent(in) :: ncid
1224  !> Data to write.
1225  real(kind=dp), intent(in) :: var(:,:,:,:)
1226  !> Variable name in NetCDF file.
1227  character(len=*), intent(in) :: name
1228  !> NetCDF dimension IDs of the variable (either \c dimids or both
1229  !> \c dim_name_1 \c dim_name_2 and \c dim_name_3 must be present).
1230  integer, optional, intent(in) :: dimids(4)
1231  !> First NetCDF dimension name for the variable (either \c dimids
1232  !> or all dimension names must be present).
1233  character(len=*), optional, intent(in) :: dim_name_1
1234  !> Second NetCDF dimension name for the variable (either \c dimids
1235  !> or all dimension names must be present).
1236  character(len=*), optional, intent(in) :: dim_name_2
1237  !> Third NetCDF dimension name for the variable (either \c dimids
1238  !> or all dimension names must be present).
1239  character(len=*), optional, intent(in) :: dim_name_3
1240  !> Fourth NetCDF dimension name for the variable (either \c dimids
1241  !> or all dimension names must be present).
1242  character(len=*), optional, intent(in) :: dim_name_4
1243  !> Unit of variable.
1244  character(len=*), optional, intent(in) :: unit
1245  !> Long name of variable.
1246  character(len=*), optional, intent(in) :: long_name
1247  !> Standard name of variable.
1248  character(len=*), optional, intent(in) :: standard_name
1249  !> Description of variable.
1250  character(len=*), optional, intent(in) :: description
1251 
1252  integer :: varid, start(4), count(4), use_dimids(4)
1253 
1254  if (present(dimids)) then
1255  use_dimids = dimids
1256  elseif (present(dim_name_1) .and. present(dim_name_2) .and. &
1257  present(dim_name_3) .and. present(dim_name_4)) then
1258  call pmc_nc_ensure_dim(ncid, dim_name_1, use_dimids(1), size(var, 1), 1)
1259  call pmc_nc_ensure_dim(ncid, dim_name_2, use_dimids(2), size(var, 2), 2)
1260  call pmc_nc_ensure_dim(ncid, dim_name_3, use_dimids(3), size(var, 3), 3)
1261  call pmc_nc_ensure_dim(ncid, dim_name_4, use_dimids(4), size(var, 4), 4)
1262  else
1263  call die_msg(464532814, "either dimids or dim_name_1, dim_name_2 " &
1264  // "dim_name_3 and dim_name_4 must be present")
1265  end if
1266  call pmc_nc_check(nf90_redef(ncid))
1267  call pmc_nc_check(nf90_def_var(ncid, name, nf90_double, use_dimids, varid))
1268  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
1269  description)
1270  call pmc_nc_check(nf90_enddef(ncid))
1271 
1272  start = (/ 1, 1, 1, 1 /)
1273  count = (/ size(var, 1), size(var, 2), size(var, 3), size(var, 4) /)
1274  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
1275  start = start, count = count))
1276 
1277  end subroutine pmc_nc_write_real_4d
1278 
1279 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1280 
1281 end module pmc_netcdf
pmc_util::ensure_real_array_3d_size
subroutine ensure_real_array_3d_size(x, n1, n2, n3, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1132
pmc_netcdf::pmc_nc_read_integer_1d
subroutine pmc_nc_read_integer_1d(ncid, var, name, must_be_present)
Read a simple integer array from a NetCDF file.
Definition: netcdf.F90:296
pmc_netcdf::pmc_nc_write_integer
subroutine pmc_nc_write_integer(ncid, var, name, unit, long_name, standard_name, description)
Write a single integer to a NetCDF file.
Definition: netcdf.F90:736
pmc_mpi::pmc_mpi_size
integer function pmc_mpi_size()
Returns the total number of processes.
Definition: mpi.F90:134
pmc_netcdf::pmc_nc_write_real_1d
subroutine pmc_nc_write_real_1d(ncid, var, name, dimids, dim_name, unit, long_name, standard_name, description)
Write a simple real array to a NetCDF file.
Definition: netcdf.F90:846
pmc_netcdf::pmc_nc_write_integer64_1d
subroutine pmc_nc_write_integer64_1d(ncid, var, name, dimids, dim_name, unit, long_name, standard_name, description)
Write a 64 bit integer array to a NetCDF file.
Definition: netcdf.F90:944
pmc_util::ensure_integer_array_4d_size
subroutine ensure_integer_array_4d_size(x, n1, n2, n3, n4, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1418
pmc_netcdf::pmc_nc_write_real_2d
subroutine pmc_nc_write_real_2d(ncid, var, name, dimids, dim_name_1, dim_name_2, unit, long_name, standard_name, description)
Write a simple real 2D array to a NetCDF file.
Definition: netcdf.F90:993
pmc_netcdf::pmc_nc_read_real_1d
subroutine pmc_nc_read_real_1d(ncid, var, name, must_be_present)
Read a simple real array from a NetCDF file.
Definition: netcdf.F90:255
pmc_netcdf::pmc_nc_write_integer_1d
subroutine pmc_nc_write_integer_1d(ncid, var, name, dimids, dim_name, unit, long_name, standard_name, description)
Write a simple integer array to a NetCDF file.
Definition: netcdf.F90:895
pmc_util::die_msg
subroutine die_msg(code, error_msg)
Error immediately.
Definition: util.F90:135
pmc_mpi::pmc_mpi_rank
integer function pmc_mpi_rank()
Returns the rank of the current process.
Definition: mpi.F90:117
pmc_netcdf
Wrapper functions for NetCDF. These all take a NetCDF ncid in data mode and return with it again in d...
Definition: netcdf.F90:11
pmc_util::ensure_real_array_4d_size
subroutine ensure_real_array_4d_size(x, n1, n2, n3, n4, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1178
pmc_constants::dp
integer, parameter dp
Kind of a double precision real number.
Definition: constants.F90:12
pmc_util::ensure_real_array_size
subroutine ensure_real_array_size(x, n, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1058
pmc_netcdf::pmc_nc_write_real_4d
subroutine pmc_nc_write_real_4d(ncid, var, name, dimids, dim_name_1, dim_name_2, dim_name_3, dim_name_4, unit, long_name, standard_name, description)
Write a simple real 4D array to a NetCDF file.
Definition: netcdf.F90:1221
pmc_netcdf::pmc_nc_write_integer64
subroutine pmc_nc_write_integer64(ncid, var, name, unit, long_name, standard_name, description)
Write a single 64 bit integer to a NetCDF file.
Definition: netcdf.F90:769
pmc_netcdf::pmc_nc_write_integer_2d
subroutine pmc_nc_write_integer_2d(ncid, var, name, dimids, dim_name_1, dim_name_2, unit, long_name, standard_name, description)
Write a simple integer 2D array to a NetCDF file.
Definition: netcdf.F90:1047
pmc_netcdf::pmc_nc_read_integer
subroutine pmc_nc_read_integer(ncid, var, name, must_be_present)
Read a single integer from a NetCDF file.
Definition: netcdf.F90:185
pmc_netcdf::pmc_nc_read_integer64_1d
subroutine pmc_nc_read_integer64_1d(ncid, var, name, must_be_present)
Read a 64 bit integer array from a NetCDF file.
Definition: netcdf.F90:337
pmc_netcdf::pmc_nc_ensure_dim
subroutine pmc_nc_ensure_dim(ncid, dim_name, dimid, dim_size, array_dim)
Create a dimension if necessary, or check its size if it already exists. In any case return the dimid...
Definition: netcdf.F90:802
pmc_netcdf::pmc_nc_open_read
subroutine pmc_nc_open_read(filename, ncid)
Open a NetCDF file for reading.
Definition: netcdf.F90:55
pmc_netcdf::pmc_nc_read_integer_4d
subroutine pmc_nc_read_integer_4d(ncid, var, name, must_be_present)
Read a simple integer 4D array from a NetCDF file.
Definition: netcdf.F90:614
pmc_netcdf::pmc_nc_write_atts
subroutine pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, description)
Write attributes for a variable to a NetCDF file.
Definition: netcdf.F90:667
pmc_netcdf::pmc_nc_write_info
subroutine pmc_nc_write_info(ncid, uuid, source, write_rank, write_n_proc)
Write basic information to a NetCDF file.
Definition: netcdf.F90:99
pmc_netcdf::pmc_nc_open_write
subroutine pmc_nc_open_write(filename, ncid)
Open a NetCDF file for writing.
Definition: netcdf.F90:70
pmc_netcdf::pmc_nc_read_integer_3d
subroutine pmc_nc_read_integer_3d(ncid, var, name, must_be_present)
Read a simple integer 3D array from a NetCDF file.
Definition: netcdf.F90:466
pmc_util::ensure_real_array_2d_size
subroutine ensure_real_array_2d_size(x, n1, n2, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1092
pmc_util::integer_to_string
character(len=pmc_util_convert_string_len) function integer_to_string(val)
Convert an integer to a string format.
Definition: util.F90:767
pmc_util::assert_msg
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition: util.F90:78
pmc_netcdf::pmc_nc_check_msg
subroutine pmc_nc_check_msg(status, error_msg)
Check the status of a NetCDF function call and prints the given error message on failure.
Definition: netcdf.F90:38
pmc_util::ensure_integer_array_3d_size
subroutine ensure_integer_array_3d_size(x, n1, n2, n3, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1372
pmc_netcdf::pmc_nc_write_real
subroutine pmc_nc_write_real(ncid, var, name, unit, long_name, standard_name, description)
Write a single real to a NetCDF file.
Definition: netcdf.F90:703
pmc_netcdf::pmc_nc_write_real_3d
subroutine pmc_nc_write_real_3d(ncid, var, name, dimids, dim_name_1, dim_name_2, dim_name_3, unit, long_name, standard_name, description)
Write a simple real 3D array to a NetCDF file.
Definition: netcdf.F90:1161
pmc_rand
Random number generators.
Definition: rand.F90:9
pmc_util::ensure_integer_array_2d_size
subroutine ensure_integer_array_2d_size(x, n1, n2, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1332
pmc_netcdf::pmc_nc_read_real_4d
subroutine pmc_nc_read_real_4d(ncid, var, name, must_be_present)
Read a simple real 4D array from a NetCDF file.
Definition: netcdf.F90:562
pmc_netcdf::pmc_nc_close
subroutine pmc_nc_close(ncid)
Close a NetCDF file.
Definition: netcdf.F90:87
pmc_netcdf::pmc_nc_check
subroutine pmc_nc_check(status)
Check the status of a NetCDF function call.
Definition: netcdf.F90:23
pmc_util
Common utility subroutines.
Definition: util.F90:9
pmc_util::ensure_integer64_array_size
subroutine ensure_integer64_array_size(x, n, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1264
pmc_netcdf::pmc_nc_read_real_3d
subroutine pmc_nc_read_real_3d(ncid, var, name, must_be_present)
Read a simple real 3D array from a NetCDF file.
Definition: netcdf.F90:513
pmc_netcdf::pmc_nc_read_real
subroutine pmc_nc_read_real(ncid, var, name, must_be_present)
Read a single real from a NetCDF file.
Definition: netcdf.F90:150
pmc_util::iso8601_date_and_time
subroutine iso8601_date_and_time(date_time)
Current date and time in ISO 8601 format.
Definition: util.F90:1528
pmc_netcdf::pmc_nc_read_real_2d
subroutine pmc_nc_read_real_2d(ncid, var, name, must_be_present)
Read a simple real 2D array from a NetCDF file.
Definition: netcdf.F90:378
pmc_netcdf::pmc_nc_write_integer_3d
subroutine pmc_nc_write_integer_3d(ncid, var, name, dimids, dim_name_1, dim_name_2, dim_name_3, unit, long_name, standard_name, description)
Write a simple integer 3D array to a NetCDF file.
Definition: netcdf.F90:1101
pmc_netcdf::pmc_nc_read_integer_2d
subroutine pmc_nc_read_integer_2d(ncid, var, name, must_be_present)
Read a simple integer 2D array from a NetCDF file.
Definition: netcdf.F90:422
pmc_netcdf::pmc_nc_read_integer64
subroutine pmc_nc_read_integer64(ncid, var, name, must_be_present)
Read a single 64 bit integer from a NetCDF file.
Definition: netcdf.F90:220
pmc_util::ensure_integer_array_size
subroutine ensure_integer_array_size(x, n, only_grow)
Allocate or reallocate the given array to ensure it is of the given size, preserving any data and/or ...
Definition: util.F90:1230