PartMC  2.6.1
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_clobber, ncid), &
77  "opening " // trim(filename) // " for writing")
78  call pmc_nc_check(nf90_enddef(ncid))
79 
80  end subroutine pmc_nc_open_write
81 
82 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
83 
84  !> Close a NetCDF file.
85  subroutine pmc_nc_close(ncid)
86 
87  !> NetCDF file ID, in data mode.
88  integer, intent(in) :: ncid
89 
90  call pmc_nc_check_msg(nf90_close(ncid), "closing NetCDF file")
91 
92  end subroutine pmc_nc_close
93 
94 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
95 
96  !> Write basic information to a NetCDF file.
97  subroutine pmc_nc_write_info(ncid, uuid, source, write_rank, write_n_proc)
98 
99  !> NetCDF file ID, in data mode.
100  integer, intent(in) :: ncid
101  !> UUID for this data set.
102  character(len=PMC_UUID_LEN), intent(in) :: uuid
103  !> Source name for this data.
104  character(len=*), intent(in) :: source
105  !> Rank to write into file.
106  integer, intent(in), optional :: write_rank
107  !> Number of processes to write into file.
108  integer, intent(in), optional :: write_n_proc
109 
110  character(len=(len_trim(source) + 100)) :: history
111  integer :: use_rank, use_n_proc
112 
113  call pmc_nc_check(nf90_redef(ncid))
114  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "title", &
115  trim(source) // " output file"))
116  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "source", source))
117  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "UUID", uuid))
118  call iso8601_date_and_time(history)
119  history((len_trim(history)+1):) = (" created by " // trim(source))
120  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "history", history))
121  call pmc_nc_check(nf90_put_att(ncid, nf90_global, "Conventions", "CF-1.4"))
122  call pmc_nc_check(nf90_enddef(ncid))
123 
124  if (present(write_rank)) then
125  use_rank = write_rank
126  else
127  use_rank = pmc_mpi_rank()
128  end if
129  if (present(write_n_proc)) then
130  use_n_proc = write_n_proc
131  else
132  use_n_proc = pmc_mpi_size()
133  end if
134 
135 #ifdef PMC_USE_MPI
136  call pmc_nc_write_integer(ncid, use_rank + 1, "process", &
137  description="the process number (starting from 1) " &
138  // "that output this data file")
139  call pmc_nc_write_integer(ncid, use_n_proc, "total_processes", &
140  description="total number of processes")
141 #endif
142 
143  end subroutine pmc_nc_write_info
144 
145 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
146 
147  !> Read a single real from a NetCDF file.
148  subroutine pmc_nc_read_real(ncid, var, name, must_be_present)
149 
150  !> NetCDF file ID, in data mode.
151  integer, intent(in) :: ncid
152  !> Data to write.
153  real(kind=dp), intent(out) :: var
154  !> Variable name in NetCDF file.
155  character(len=*), intent(in) :: name
156  !> Whether the variable must be present in the NetCDF file
157  !> (default .true.).
158  logical, optional, intent(in) :: must_be_present
159 
160  integer :: varid, status
161  logical :: use_must_be_present
162 
163  if (present(must_be_present)) then
164  use_must_be_present = must_be_present
165  else
166  use_must_be_present = .true.
167  end if
168  status = nf90_inq_varid(ncid, name, varid)
169  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
170  ! variable was not present, but that's ok
171  var = 0d0
172  return
173  end if
174  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
175  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
176  "getting variable " // trim(name))
177 
178  end subroutine pmc_nc_read_real
179 
180 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
181 
182  !> Read a single integer from a NetCDF file.
183  subroutine pmc_nc_read_integer(ncid, var, name, must_be_present)
184 
185  !> NetCDF file ID, in data mode.
186  integer, intent(in) :: ncid
187  !> Data to write.
188  integer, intent(out) :: var
189  !> Variable name in NetCDF file.
190  character(len=*), intent(in) :: name
191  !> Whether the variable must be present in the NetCDF file
192  !> (default .true.).
193  logical, optional, intent(in) :: must_be_present
194 
195  integer :: varid, status
196  logical :: use_must_be_present
197 
198  if (present(must_be_present)) then
199  use_must_be_present = must_be_present
200  else
201  use_must_be_present = .true.
202  end if
203  status = nf90_inq_varid(ncid, name, varid)
204  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
205  ! variable was not present, but that's ok
206  var = 0
207  return
208  end if
209  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
210  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
211  "getting variable " // trim(name))
212 
213  end subroutine pmc_nc_read_integer
214 
215 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
216 
217  !> Read a simple real array from a NetCDF file.
218  subroutine pmc_nc_read_real_1d(ncid, var, name, must_be_present)
219 
220  !> NetCDF file ID, in data mode.
221  integer, intent(in) :: ncid
222  !> Data to read.
223  real(kind=dp), intent(inout), allocatable :: var(:)
224  !> Variable name in NetCDF file.
225  character(len=*), intent(in) :: name
226  !> Whether the variable must be present in the NetCDF file
227  !> (default .true.).
228  logical, optional, intent(in) :: must_be_present
229 
230  integer :: varid, status, dimids(1), size1
231  logical :: use_must_be_present
232 
233  if (present(must_be_present)) then
234  use_must_be_present = must_be_present
235  else
236  use_must_be_present = .true.
237  end if
238  status = nf90_inq_varid(ncid, name, varid)
239  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
240  ! variable was not present, but that's ok, set it to empty
241  var = [real(kind=dp)::]
242  return
243  end if
244  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
245  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
246  "determining size of variable " // trim(name))
247  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
248  "determining size of dimension number " &
249  // trim(integer_to_string(dimids(1))))
250  call ensure_real_array_size(var, size1)
251  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
252  "getting variable " // trim(name))
253 
254  end subroutine pmc_nc_read_real_1d
255 
256 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
257 
258  !> Read a simple integer array from a NetCDF file.
259  subroutine pmc_nc_read_integer_1d(ncid, var, name, must_be_present)
260 
261  !> NetCDF file ID, in data mode.
262  integer, intent(in) :: ncid
263  !> Data to read.
264  integer, intent(inout), allocatable :: var(:)
265  !> Variable name in NetCDF file.
266  character(len=*), intent(in) :: name
267  !> Whether the variable must be present in the NetCDF file
268  !> (default .true.).
269  logical, optional, intent(in) :: must_be_present
270 
271  integer :: varid, status, dimids(1), size1
272  logical :: use_must_be_present
273 
274  if (present(must_be_present)) then
275  use_must_be_present = must_be_present
276  else
277  use_must_be_present = .true.
278  end if
279  status = nf90_inq_varid(ncid, name, varid)
280  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
281  ! variable was not present, but that's ok
282  var = [integer::]
283  return
284  end if
285  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
286  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
287  "determining size of variable " // trim(name))
288  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
289  "determining size of dimension number " &
290  // trim(integer_to_string(dimids(1))))
291  call ensure_integer_array_size(var, size1)
292  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
293  "getting variable " // trim(name))
294 
295  end subroutine pmc_nc_read_integer_1d
296 
297 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
298 
299  !> Read a simple real 2D array from a NetCDF file.
300  subroutine pmc_nc_read_real_2d(ncid, var, name, must_be_present)
301 
302  !> NetCDF file ID, in data mode.
303  integer, intent(in) :: ncid
304  !> Data to read.
305  real(kind=dp), intent(inout), allocatable :: var(:,:)
306  !> Variable name in NetCDF file.
307  character(len=*), intent(in) :: name
308  !> Whether the variable must be present in the NetCDF file
309  !> (default .true.).
310  logical, optional, intent(in) :: must_be_present
311 
312  integer :: varid, status, dimids(2), size1, size2
313  logical :: use_must_be_present
314 
315  if (present(must_be_present)) then
316  use_must_be_present = must_be_present
317  else
318  use_must_be_present = .true.
319  end if
320  status = nf90_inq_varid(ncid, name, varid)
321  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
322  ! variable was not present, but that's ok
323  var = reshape([real(kind=dp)::], [0, 0])
324  return
325  end if
326  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
327  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
328  "determining size of variable " // trim(name))
329  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
330  "determining size of dimension number " &
331  // trim(integer_to_string(dimids(1))))
332  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(2), len=size2), &
333  "determining size of dimension number " &
334  // trim(integer_to_string(dimids(2))))
335  call ensure_real_array_2d_size(var, size1, size2)
336  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
337  "getting variable " // trim(name))
338 
339  end subroutine pmc_nc_read_real_2d
340 
341 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
342 
343  !> Read a simple integer 2D array from a NetCDF file.
344  subroutine pmc_nc_read_integer_2d(ncid, var, name, must_be_present)
345 
346  !> NetCDF file ID, in data mode.
347  integer, intent(in) :: ncid
348  !> Data to read.
349  integer, intent(inout), allocatable :: var(:,:)
350  !> Variable name in NetCDF file.
351  character(len=*), intent(in) :: name
352  !> Whether the variable must be present in the NetCDF file
353  !> (default .true.).
354  logical, optional, intent(in) :: must_be_present
355 
356  integer :: varid, status, dimids(2), size1, size2
357  logical :: use_must_be_present
358 
359  if (present(must_be_present)) then
360  use_must_be_present = must_be_present
361  else
362  use_must_be_present = .true.
363  end if
364  status = nf90_inq_varid(ncid, name, varid)
365  if ((.not. use_must_be_present) .and. (status == nf90_enotvar)) then
366  ! variable was not present, but that's ok
367  var = reshape([integer::], [0, 0])
368  return
369  end if
370  call pmc_nc_check_msg(status, "inquiring variable " // trim(name))
371  call pmc_nc_check_msg(nf90_inquire_variable(ncid, varid, dimids=dimids), &
372  "determining size of variable " // trim(name))
373  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(1), len=size1), &
374  "determining size of dimension number " &
375  // trim(integer_to_string(dimids(1))))
376  call pmc_nc_check_msg(nf90_inquire_dimension(ncid, dimids(2), len=size2), &
377  "determining size of dimension number " &
378  // trim(integer_to_string(dimids(2))))
379  call ensure_integer_array_2d_size(var, size1, size2)
380  call pmc_nc_check_msg(nf90_get_var(ncid, varid, var), &
381  "getting variable " // trim(name))
382 
383  end subroutine pmc_nc_read_integer_2d
384 
385 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
386 
387  !> Write attributes for a variable to a NetCDF file.
388  subroutine pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
389  description)
390 
391  !> NetCDF file ID, in define mode.
392  integer, intent(in) :: ncid
393  !> Variable ID to write attributes for.
394  integer, intent(in) :: varid
395  !> Unit of variable.
396  character(len=*), optional, intent(in) :: unit
397  !> Long name of variable.
398  character(len=*), optional, intent(in) :: long_name
399  !> Standard name of variable.
400  character(len=*), optional, intent(in) :: standard_name
401  !> Description of variable.
402  character(len=*), optional, intent(in) :: description
403 
404  if (present(unit)) then
405  call pmc_nc_check(nf90_put_att(ncid, varid, "unit", unit))
406  end if
407  if (present(long_name)) then
408  call pmc_nc_check(nf90_put_att(ncid, varid, "long_name", long_name))
409  end if
410  if (present(standard_name)) then
411  call pmc_nc_check(nf90_put_att(ncid, varid, "standard_name", &
412  standard_name))
413  end if
414  if (present(description)) then
415  call pmc_nc_check(nf90_put_att(ncid, varid, "description", &
416  description))
417  end if
418 
419  end subroutine pmc_nc_write_atts
420 
421 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
422 
423  !> Write a single real to a NetCDF file.
424  subroutine pmc_nc_write_real(ncid, var, name, unit, long_name, &
425  standard_name, description)
426 
427  !> NetCDF file ID, in data mode.
428  integer, intent(in) :: ncid
429  !> Data to write.
430  real(kind=dp), intent(in) :: var
431  !> Variable name in NetCDF file.
432  character(len=*), intent(in) :: name
433  !> Unit of variable.
434  character(len=*), optional, intent(in) :: unit
435  !> Long name of variable.
436  character(len=*), optional, intent(in) :: long_name
437  !> Standard name of variable.
438  character(len=*), optional, intent(in) :: standard_name
439  !> Description of variable.
440  character(len=*), optional, intent(in) :: description
441 
442  integer :: varid, dimids(0)
443 
444  call pmc_nc_check(nf90_redef(ncid))
445  call pmc_nc_check(nf90_def_var(ncid, name, nf90_double, dimids, varid))
446  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
447  description)
448  call pmc_nc_check(nf90_enddef(ncid))
449 
450  call pmc_nc_check(nf90_put_var(ncid, varid, var))
451 
452  end subroutine pmc_nc_write_real
453 
454 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
455 
456  !> Write a single integer to a NetCDF file.
457  subroutine pmc_nc_write_integer(ncid, var, name, unit, long_name, &
458  standard_name, description)
459 
460  !> NetCDF file ID, in data mode.
461  integer, intent(in) :: ncid
462  !> Data to write.
463  integer, intent(in) :: var
464  !> Variable name in NetCDF file.
465  character(len=*), intent(in) :: name
466  !> Unit of variable.
467  character(len=*), optional, intent(in) :: unit
468  !> Long name of variable.
469  character(len=*), optional, intent(in) :: long_name
470  !> Standard name of variable.
471  character(len=*), optional, intent(in) :: standard_name
472  !> Description of variable.
473  character(len=*), optional, intent(in) :: description
474 
475  integer :: varid, dimids(0)
476 
477  call pmc_nc_check(nf90_redef(ncid))
478  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int, dimids, varid))
479  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
480  description)
481  call pmc_nc_check(nf90_enddef(ncid))
482 
483  call pmc_nc_check(nf90_put_var(ncid, varid, var))
484 
485  end subroutine pmc_nc_write_integer
486 
487 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
488 
489  !> Create a dimension if necessary, or check its size if it already
490  !> exists. In any case return the \c dimid.
491  subroutine pmc_nc_ensure_dim(ncid, dim_name, dimid, dim_size, array_dim)
492 
493  !> NetCDF file ID, in data mode.
494  integer, intent(in) :: ncid
495  !> NetCDF dimension name for the variable.
496  character(len=*), intent(in) :: dim_name
497  !> NetCDF dimension ID.
498  integer, intent(out) :: dimid
499  !> Size of dimension.
500  integer, intent(in) :: dim_size
501  !> Dimension within data array that this NetCDF dim corresponds to.
502  integer, intent(in) :: array_dim
503 
504  integer :: status, check_dim_size
505  character(len=NF90_MAX_NAME) :: check_name
506 
507  status = nf90_inq_dimid(ncid, dim_name, dimid)
508  if (status == nf90_noerr) then
509  call pmc_nc_check(nf90_inquire_dimension(ncid, dimid, check_name, &
510  check_dim_size))
511  call assert_msg(657263912, check_dim_size == dim_size, &
512  "dim " // trim(integer_to_string(array_dim)) // " size " &
513  // trim(integer_to_string(dim_size)) &
514  // " of data array does not match size " &
515  // trim(integer_to_string(dim_size)) // " of '" &
516  // trim(dim_name) // "' dim")
517  else
518  ! could not determine dimid
519  if (status /= nf90_ebaddim) then
520  ! the problem was not a missing dimension
521  call pmc_nc_check(status)
522  end if
523  ! the problem was a missing dimension, so make it
524  call pmc_nc_check(nf90_redef(ncid))
525  call pmc_nc_check(nf90_def_dim(ncid, dim_name, dim_size, dimid))
526  call pmc_nc_check(nf90_enddef(ncid))
527  end if
528 
529  end subroutine pmc_nc_ensure_dim
530 
531 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
532 
533  !> Write a simple real array to a NetCDF file.
534  subroutine pmc_nc_write_real_1d(ncid, var, name, dimids, dim_name, unit, &
535  long_name, standard_name, description)
536 
537  !> NetCDF file ID, in data mode.
538  integer, intent(in) :: ncid
539  !> Data to write.
540  real(kind=dp), intent(in) :: var(:)
541  !> Variable name in NetCDF file.
542  character(len=*), intent(in) :: name
543  !> NetCDF dimension IDs of the variable (either this or dim_name
544  !> must be present).
545  integer, optional, intent(in) :: dimids(1)
546  !> NetCDF dimension name for the variable (either this or dimids
547  !> must be present).
548  character(len=*), optional, intent(in) :: dim_name
549  !> Unit of variable.
550  character(len=*), optional, intent(in) :: unit
551  !> Long name of variable.
552  character(len=*), optional, intent(in) :: long_name
553  !> Standard name of variable.
554  character(len=*), optional, intent(in) :: standard_name
555  !> Description of variable.
556  character(len=*), optional, intent(in) :: description
557 
558  integer :: varid, start(1), count(1), use_dimids(1)
559 
560  if (present(dimids)) then
561  use_dimids = dimids
562  elseif (present(dim_name)) then
563  call pmc_nc_ensure_dim(ncid, dim_name, use_dimids(1), size(var), 1)
564  else
565  call die_msg(891890123, "either dimids or dim_name must be present")
566  end if
567  call pmc_nc_check(nf90_redef(ncid))
568  call pmc_nc_check(nf90_def_var(ncid, name, nf90_double, use_dimids, varid))
569  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
570  description)
571  call pmc_nc_check(nf90_enddef(ncid))
572 
573  start = (/ 1 /)
574  count = (/ size(var, 1) /)
575  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
576  start = start, count = count))
577 
578  end subroutine pmc_nc_write_real_1d
579 
580 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
581 
582  !> Write a simple integer array to a NetCDF file.
583  subroutine pmc_nc_write_integer_1d(ncid, var, name, dimids, dim_name, unit, &
584  long_name, standard_name, description)
585 
586  !> NetCDF file ID, in data mode.
587  integer, intent(in) :: ncid
588  !> Data to write.
589  integer, intent(in) :: var(:)
590  !> Variable name in NetCDF file.
591  character(len=*), intent(in) :: name
592  !> NetCDF dimension IDs of the variable (either this or dim_name
593  !> must be present).
594  integer, optional, intent(in) :: dimids(1)
595  !> NetCDF dimension name for the variable (either this or dimids
596  !> must be present).
597  character(len=*), optional, intent(in) :: dim_name
598  !> Unit of variable.
599  character(len=*), optional, intent(in) :: unit
600  !> Long name of variable.
601  character(len=*), optional, intent(in) :: long_name
602  !> Standard name of variable.
603  character(len=*), optional, intent(in) :: standard_name
604  !> Description of variable.
605  character(len=*), optional, intent(in) :: description
606 
607  integer :: varid, start(1), count(1), use_dimids(1)
608 
609  if (present(dimids)) then
610  use_dimids = dimids
611  elseif (present(dim_name)) then
612  call pmc_nc_ensure_dim(ncid, dim_name, use_dimids(1), size(var), 1)
613  else
614  call die_msg(464170526, "either dimids or dim_name must be present")
615  end if
616  call pmc_nc_check(nf90_redef(ncid))
617  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int, use_dimids, varid))
618  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
619  description)
620  call pmc_nc_check(nf90_enddef(ncid))
621 
622  start = (/ 1 /)
623  count = (/ size(var, 1) /)
624  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
625  start = start, count = count))
626 
627  end subroutine pmc_nc_write_integer_1d
628 
629 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
630 
631  !> Write a simple real 2D array to a NetCDF file.
632  subroutine pmc_nc_write_real_2d(ncid, var, name, dimids, dim_name_1, &
633  dim_name_2, unit, long_name, standard_name, description)
634 
635  !> NetCDF file ID, in data mode.
636  integer, intent(in) :: ncid
637  !> Data to write.
638  real(kind=dp), intent(in) :: var(:,:)
639  !> Variable name in NetCDF file.
640  character(len=*), intent(in) :: name
641  !> NetCDF dimension IDs of the variable (either \c dimids or both
642  !> \c dim_name_1 and \c dim_name_2 must be present).
643  integer, optional, intent(in) :: dimids(2)
644  !> First NetCDF dimension name for the variable (either \c dimids
645  !> or both \c dim_name_1 and \c dim_name 2 must be present).
646  character(len=*), optional, intent(in) :: dim_name_1
647  !> Second NetCDF dimension name for the variable (either \c dimids
648  !> or both \c dim_name_1 and \c dim_name 2 must be present).
649  character(len=*), optional, intent(in) :: dim_name_2
650  !> Unit of variable.
651  character(len=*), optional, intent(in) :: unit
652  !> Long name of variable.
653  character(len=*), optional, intent(in) :: long_name
654  !> Standard name of variable.
655  character(len=*), optional, intent(in) :: standard_name
656  !> Description of variable.
657  character(len=*), optional, intent(in) :: description
658 
659  integer :: varid, start(2), count(2), use_dimids(2)
660 
661  if (present(dimids)) then
662  use_dimids = dimids
663  elseif (present(dim_name_1) .and. present(dim_name_2)) then
664  call pmc_nc_ensure_dim(ncid, dim_name_1, use_dimids(1), size(var, 1), 1)
665  call pmc_nc_ensure_dim(ncid, dim_name_2, use_dimids(2), size(var, 2), 2)
666  else
667  call die_msg(959111259, &
668  "either dimids or both dim_name_1 and dim_name_2 must be present")
669  end if
670  call pmc_nc_check(nf90_redef(ncid))
671  call pmc_nc_check(nf90_def_var(ncid, name, nf90_double, use_dimids, varid))
672  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
673  description)
674  call pmc_nc_check(nf90_enddef(ncid))
675 
676  start = (/ 1, 1 /)
677  count = (/ size(var, 1), size(var, 2) /)
678  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
679  start = start, count = count))
680 
681  end subroutine pmc_nc_write_real_2d
682 
683 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
684 
685  !> Write a simple integer 2D array to a NetCDF file.
686  subroutine pmc_nc_write_integer_2d(ncid, var, name, dimids, dim_name_1, &
687  dim_name_2, unit, long_name, standard_name, description)
688 
689  !> NetCDF file ID, in data mode.
690  integer, intent(in) :: ncid
691  !> Data to write.
692  integer, intent(in) :: var(:,:)
693  !> Variable name in NetCDF file.
694  character(len=*), intent(in) :: name
695  !> NetCDF dimension IDs of the variable (either \c dimids or both
696  !> \c dim_name_1 and \c dim_name_2 must be present).
697  integer, optional, intent(in) :: dimids(2)
698  !> First NetCDF dimension name for the variable (either \c dimids
699  !> or both \c dim_name_1 and \c dim_name 2 must be present).
700  character(len=*), optional, intent(in) :: dim_name_1
701  !> Second NetCDF dimension name for the variable (either \c dimids
702  !> or both \c dim_name_1 and \c dim_name 2 must be present).
703  character(len=*), optional, intent(in) :: dim_name_2
704  !> Unit of variable.
705  character(len=*), optional, intent(in) :: unit
706  !> Long name of variable.
707  character(len=*), optional, intent(in) :: long_name
708  !> Standard name of variable.
709  character(len=*), optional, intent(in) :: standard_name
710  !> Description of variable.
711  character(len=*), optional, intent(in) :: description
712 
713  integer :: varid, start(2), count(2), use_dimids(2)
714 
715  if (present(dimids)) then
716  use_dimids = dimids
717  elseif (present(dim_name_1) .and. present(dim_name_2)) then
718  call pmc_nc_ensure_dim(ncid, dim_name_1, use_dimids(1), size(var, 1), 1)
719  call pmc_nc_ensure_dim(ncid, dim_name_2, use_dimids(2), size(var, 2), 2)
720  else
721  call die_msg(669381383, &
722  "either dimids or both dim_name_1 and dim_name_2 must be present")
723  end if
724  call pmc_nc_check(nf90_redef(ncid))
725  call pmc_nc_check(nf90_def_var(ncid, name, nf90_int, use_dimids, varid))
726  call pmc_nc_write_atts(ncid, varid, unit, long_name, standard_name, &
727  description)
728  call pmc_nc_check(nf90_enddef(ncid))
729 
730  start = (/ 1, 1 /)
731  count = (/ size(var, 1), size(var, 2) /)
732  call pmc_nc_check(nf90_put_var(ncid, varid, var, &
733  start = start, count = count))
734 
735  end subroutine pmc_nc_write_integer_2d
736 
737 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
738 
739 end module pmc_netcdf
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:260
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:459
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:536
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:634
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:219
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:585
pmc_util::die_msg
subroutine die_msg(code, error_msg)
Error immediately.
Definition: util.F90:134
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_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:1041
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:688
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:184
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:492
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_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:390
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:98
pmc_netcdf::pmc_nc_open_write
subroutine pmc_nc_open_write(filename, ncid)
Open a NetCDF file for writing.
Definition: netcdf.F90:70
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:1075
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:766
pmc_util::assert_msg
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition: util.F90:77
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_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:426
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:1149
pmc_netcdf::pmc_nc_close
subroutine pmc_nc_close(ncid)
Close a NetCDF file.
Definition: netcdf.F90:86
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_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:149
pmc_util::iso8601_date_and_time
subroutine iso8601_date_and_time(date_time)
Current date and time in ISO 8601 format.
Definition: util.F90:1247
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:301
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:345
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:1115