PartMC  2.8.0
bin_grid.F90
Go to the documentation of this file.
1 ! Copyright (C) 2005-2016 Nicole Riemer and 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_bin_grid module.
7 
8 !> The bin_grid_t structure and associated subroutines.
10 
11  use pmc_constants
12  use pmc_util
13  use pmc_spec_file
14  use pmc_mpi
15  use pmc_netcdf
16 #ifdef PMC_USE_MPI
17  use mpi
18 #endif
19 
20  !> Invalid type of bin grid.
21  integer, parameter :: bin_grid_type_invalid = 0
22  !> Logarithmically spaced bin grid.
23  integer, parameter :: bin_grid_type_log = 1
24  !> Linearly spaced bin grid.
25  integer, parameter :: bin_grid_type_linear = 2
26 
27  !> 1D grid, either logarithmic or linear.
28  !!
29  !! The grid of bins is logarithmically spaced in volume, an
30  !! assumption that is quite heavily incorporated into the code. At
31  !! some point in the future it would be nice to relax this
32  !! assumption.
34  !> Type of grid spacing (BIN_GRID_TYPE_LOG, etc).
35  integer :: type
36  !> Bin centers.
37  real(kind=dp), allocatable :: centers(:)
38  !> Bin edges.
39  real(kind=dp), allocatable :: edges(:)
40  !> Bin widths.
41  real(kind=dp), allocatable :: widths(:)
42  end type bin_grid_t
43 
44 contains
45 
46 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
47 
48  !> Return the number of bins in the grid, or -1 if the bin grid is
49  !> not allocated.
50  elemental integer function bin_grid_size(bin_grid)
51 
52  !> Bin grid structure.
53  type(bin_grid_t), intent(in) :: bin_grid
54 
55  if (allocated(bin_grid%centers)) then
56  bin_grid_size = size(bin_grid%centers)
57  else
58  bin_grid_size = -1
59  end if
60 
61  end function bin_grid_size
62 
63 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
64 
65  !> Convert a concentration f(vol)d(vol) to f(ln(r))d(ln(r))
66  !> where vol = 4/3 pi r^3.
67  subroutine vol_to_lnr(r, f_vol, f_lnr)
68 
69  !> Radius (m).
70  real(kind=dp), intent(in) :: r
71  !> Concentration as a function of volume.
72  real(kind=dp), intent(in) :: f_vol
73  !> Concentration as a function of ln(r).
74  real(kind=dp), intent(out) :: f_lnr
75 
76  f_lnr = f_vol * 4d0 * const%pi * r**3
77 
78  end subroutine vol_to_lnr
79 
80 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
81 
82  !> Generates the bin grid given the range and number of bins.
83  subroutine bin_grid_make(bin_grid, type, n_bin, min, max)
84 
85  !> New bin grid.
86  type(bin_grid_t), intent(inout) :: bin_grid
87  !> Type of bin grid.
88  integer, intent(in) :: type
89  !> Number of bins.
90  integer, intent(in) :: n_bin
91  !> Minimum edge value.
92  real(kind=dp), intent(in) :: min
93  !> Minimum edge value.
94  real(kind=dp), intent(in) :: max
95 
96  real(kind=dp) :: c1, c2
97  integer :: i
98 
99  call assert_msg(538534122, n_bin >= 0, &
100  "bin_grid requires a non-negative n_bin, not: " &
101  // trim(integer_to_string(n_bin)))
102  if (n_bin > 0) then
103  if (type == bin_grid_type_log) then
104  call assert_msg(966541762, min > 0d0, &
105  "log bin_grid requires a positive min value, not: " &
106  // trim(real_to_string(min)))
107  end if
108  call assert_msg(711537859, min < max, &
109  "bin_grid requires min < max, not: " &
110  // trim(real_to_string(min)) // " and " &
111  // trim(real_to_string(max)))
112  end if
113  bin_grid%type = type
114  if (n_bin == 0) return
115  if (type == bin_grid_type_log) then
116  bin_grid%edges = logspace(min, max, n_bin + 1)
117  c1 = exp(interp_linear_disc(log(min), log(max), 2 * n_bin + 1, 2))
118  c2 = exp(interp_linear_disc(log(min), log(max), 2 * n_bin + 1, &
119  2 * n_bin))
120  bin_grid%centers = logspace(c1, c2, n_bin)
121  bin_grid%widths = [ ((log(max) - log(min)) / real(n_bin, kind=dp), &
122  i=1,n_bin) ]
123  elseif (bin_grid%type == bin_grid_type_linear) then
124  bin_grid%edges = linspace(min, max, n_bin + 1)
125  c1 = interp_linear_disc(min, max, 2 * n_bin + 1, 2)
126  c2 = interp_linear_disc(min, max, 2 * n_bin + 1, 2 * n_bin)
127  bin_grid%centers = linspace(c1, c2, n_bin)
128  bin_grid%widths = [ ((max - min) / real(n_bin, kind=dp), i=1,n_bin) ]
129  else
130  call die_msg(678302366, "unknown bin_grid type: " &
131  // trim(integer_to_string(bin_grid%type)))
132  end if
133 
134  end subroutine bin_grid_make
135 
136 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
137 
138  !> Find the bin number that contains a given value.
139  !!
140  !! If a particle is below the smallest bin then its bin number is
141  !! 0. If a particle is above the largest bin then its bin number is
142  !! <tt>bin_grid_size(bin_grid) + 1</tt>.
143  integer function bin_grid_find(bin_grid, val)
144 
145  !> Bin_grid.
146  type(bin_grid_t), intent(in) :: bin_grid
147  !> Value to locate bin for.
148  real(kind=dp), intent(in) :: val
149 
150  bin_grid_find = -1
151  if (bin_grid_size(bin_grid) <= 0) then
152  return
153  end if
154  if (bin_grid%type == bin_grid_type_log) then
155  bin_grid_find = logspace_find(bin_grid%edges(1), &
156  bin_grid%edges(bin_grid_size(bin_grid) + 1), &
157  bin_grid_size(bin_grid) + 1, val)
158  elseif (bin_grid%type == bin_grid_type_linear) then
159  bin_grid_find = linspace_find(bin_grid%edges(1), &
160  bin_grid%edges(bin_grid_size(bin_grid) + 1), &
161  bin_grid_size(bin_grid) + 1, val)
162  else
163  call die_msg(348908641, "unknown bin_grid type: " &
164  // trim(integer_to_string(bin_grid%type)))
165  end if
166 
167  end function bin_grid_find
168 
169 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
170 
171  !> Determines if a value is in a given bin.
172  !!
173  !! The value is contained in bin i if edge(i) <= val < edge(i+1).
174  !! If bin_i = 0, then we return true if val < edge(1). If bin_i =
175  !! bin_grid_size + 1, then we return true if val > edge(bin_grid_size+1).
176  !! If val = edge(bin_grid_size+1), then return true if i_bin = bin_grid_size.
177  logical function bin_grid_contains(bin_grid, i_bin, val)
178 
179  !> Bin grid.
180  type(bin_grid_t), intent(in) :: bin_grid
181  !> Bin to see if it contains the value.
182  integer, intent(in) :: i_bin
183  !> Data value.
184  real(kind=dp), intent(in) :: val
185 
186  call assert_msg(828875607, bin_grid_size(bin_grid) >= 0, "bin_grid not " &
187  // "created.")
188  call assert_msg(454111488, 0 <= i_bin .and. &
189  i_bin <= bin_grid_size(bin_grid) + 1, "i_bin not a valid bin in " &
190  // "bin_grid")
191 
192  bin_grid_contains = .false.
193 
194  if (i_bin == 0) then
195  if (val < bin_grid%edges(1)) then
196  bin_grid_contains = .true.
197  end if
198  return
199  end if
200 
201  if (i_bin == bin_grid_size(bin_grid) + 1) then
202  if (val > bin_grid%edges(bin_grid_size(bin_grid) + 1)) then
203  bin_grid_contains = .true.
204  end if
205  return
206  end if
207 
208  if (bin_grid%edges(i_bin) <= val .and. &
209  val < bin_grid%edges(i_bin + 1)) then
210  bin_grid_contains = .true.
211  return
212  end if
213 
214  if (i_bin == bin_grid_size(bin_grid) .and. &
215  val == bin_grid%edges(i_bin + 1)) then
216  bin_grid_contains = .true.
217  end if
218 
219  end function bin_grid_contains
220 
221 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
222 
223  !> Make a histogram with of the given weighted data, scaled by the
224  !> bin sizes.
225  function bin_grid_histogram_1d(x_bin_grid, x_data, weight_data)
226 
227  !> x-axis bin grid.
228  type(bin_grid_t), intent(in) :: x_bin_grid
229  !> Data values on the x-axis.
230  real(kind=dp), intent(in) :: x_data(:)
231  !> Data value weights.
232  real(kind=dp), intent(in) :: weight_data(size(x_data))
233 
234  !> Return histogram.
235  real(kind=dp) :: bin_grid_histogram_1d(bin_grid_size(x_bin_grid))
236 
237  integer :: i_data, x_bin
238 
240  do i_data = 1,size(x_data)
241  x_bin = bin_grid_find(x_bin_grid, x_data(i_data))
242  if ((x_bin >= 1) .and. (x_bin <= bin_grid_size(x_bin_grid))) then
244  + weight_data(i_data) / x_bin_grid%widths(x_bin)
245  end if
246  end do
247 
248  end function bin_grid_histogram_1d
249 
250 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
251 
252  !> Make a 2D histogram with of the given weighted data, scaled by
253  !> the bin sizes.
254  function bin_grid_histogram_2d(x_bin_grid, x_data, y_bin_grid, y_data, &
255  weight_data)
256 
257  !> x-axis bin grid.
258  type(bin_grid_t), intent(in) :: x_bin_grid
259  !> Data values on the x-axis.
260  real(kind=dp), intent(in) :: x_data(:)
261  !> y-axis bin grid.
262  type(bin_grid_t), intent(in) :: y_bin_grid
263  !> Data values on the y-axis.
264  real(kind=dp), intent(in) :: y_data(size(x_data))
265  !> Data value weights.
266  real(kind=dp), intent(in) :: weight_data(size(x_data))
267 
268  !> Return histogram.
269  real(kind=dp) :: bin_grid_histogram_2d(bin_grid_size(x_bin_grid), &
270  bin_grid_size(y_bin_grid))
271 
272  integer :: i_data, x_bin, y_bin
273 
275  do i_data = 1,size(x_data)
276  x_bin = bin_grid_find(x_bin_grid, x_data(i_data))
277  y_bin = bin_grid_find(y_bin_grid, y_data(i_data))
278  if ((x_bin >= 1) .and. (x_bin <= bin_grid_size(x_bin_grid)) &
279  .and. (y_bin >= 1) .and. (y_bin <= bin_grid_size(y_bin_grid))) then
280  bin_grid_histogram_2d(x_bin, y_bin) &
281  = bin_grid_histogram_2d(x_bin, y_bin) + weight_data(i_data) &
282  / x_bin_grid%widths(x_bin) / y_bin_grid%widths(y_bin)
283  end if
284  end do
285 
286  end function bin_grid_histogram_2d
287 
288 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
289 
290  !> Read the specification for a radius bin_grid from a spec file.
291  subroutine spec_file_read_radius_bin_grid(file, bin_grid)
292 
293  !> Spec file.
294  type(spec_file_t), intent(inout) :: file
295  !> Radius bin grid.
296  type(bin_grid_t), intent(inout) :: bin_grid
297 
298  integer :: n_bin
299  real(kind=dp) :: d_min, d_max
300 
301  !> \page input_format_diam_bin_grid Input File Format: Diameter Axis Bin Grid
302  !!
303  !! The diameter bin grid is logarithmic, consisting of
304  !! \f$n_{\rm bin}\f$ bins with centers \f$c_i\f$ (\f$i =
305  !! 1,\ldots,n_{\rm bin}\f$) and edges \f$e_i\f$ (\f$i =
306  !! 1,\ldots,(n_{\rm bin} + 1)\f$) such that \f$e_{i+1}/e_i\f$ is a
307  !! constant and \f$c_i/e_i = \sqrt{e_{i+1}/e_i}\f$. That is,
308  !! \f$\ln(e_i)\f$ are uniformly spaced and \f$\ln(c_i)\f$ are the
309  !! arithmetic centers.
310  !!
311  !! The diameter axis bin grid is specified by the parameters:
312  !! - \b n_bin (integer): The number of bins \f$n_{\rm bin}\f$.
313  !! - \b d_min (real, unit m): The left edge of the left-most bin,
314  !! \f$e_1\f$.
315  !! - \b d_max (real, unit m): The right edge of the right-most bin,
316  !! \f$e_{n_{\rm bin} + 1}\f$.
317  !!
318  !! See also:
319  !! - \ref spec_file_format --- the input file text format
320  !! - \ref output_format_diam_bin_grid --- the corresponding output format
321 
322  call spec_file_read_integer(file, 'n_bin', n_bin)
323  call spec_file_read_real(file, 'd_min', d_min)
324  call spec_file_read_real(file, 'd_max', d_max)
325  call bin_grid_make(bin_grid, bin_grid_type_log, n_bin, diam2rad(d_min), &
326  diam2rad(d_max))
327 
328  end subroutine spec_file_read_radius_bin_grid
329 
330 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
331 
332  !> Determines the number of bytes required to pack the given value.
333  integer function pmc_mpi_pack_size_bin_grid(val)
334 
335  !> Value to pack.
336  type(bin_grid_t), intent(in) :: val
337 
339  pmc_mpi_pack_size_integer(val%type) &
340  + pmc_mpi_pack_size_real_array(val%centers) &
341  + pmc_mpi_pack_size_real_array(val%edges) &
342  + pmc_mpi_pack_size_real_array(val%widths)
343 
344  end function pmc_mpi_pack_size_bin_grid
345 
346 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
347 
348  !> Packs the given value into the buffer, advancing position.
349  subroutine pmc_mpi_pack_bin_grid(buffer, position, val)
350 
351  !> Memory buffer.
352  character, intent(inout) :: buffer(:)
353  !> Current buffer position.
354  integer, intent(inout) :: position
355  !> Value to pack.
356  type(bin_grid_t), intent(in) :: val
357 
358 #ifdef PMC_USE_MPI
359  integer :: prev_position
360 
361  prev_position = position
362  call pmc_mpi_pack_integer(buffer, position, val%type)
363  call pmc_mpi_pack_real_array(buffer, position, val%centers)
364  call pmc_mpi_pack_real_array(buffer, position, val%edges)
365  call pmc_mpi_pack_real_array(buffer, position, val%widths)
366  call assert(385455586, &
367  position - prev_position <= pmc_mpi_pack_size_bin_grid(val))
368 #endif
369 
370  end subroutine pmc_mpi_pack_bin_grid
371 
372 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
373 
374  !> Unpacks the given value from the buffer, advancing position.
375  subroutine pmc_mpi_unpack_bin_grid(buffer, position, val)
376 
377  !> Memory buffer.
378  character, intent(inout) :: buffer(:)
379  !> Current buffer position.
380  integer, intent(inout) :: position
381  !> Value to pack.
382  type(bin_grid_t), intent(inout) :: val
383 
384 #ifdef PMC_USE_MPI
385  integer :: prev_position
386 
387  prev_position = position
388  call pmc_mpi_unpack_integer(buffer, position, val%type)
389  call pmc_mpi_unpack_real_array(buffer, position, val%centers)
390  call pmc_mpi_unpack_real_array(buffer, position, val%edges)
391  call pmc_mpi_unpack_real_array(buffer, position, val%widths)
392  call assert(741838730, &
393  position - prev_position <= pmc_mpi_pack_size_bin_grid(val))
394 #endif
395 
396  end subroutine pmc_mpi_unpack_bin_grid
397 
398 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
399 
400  !> Check whether all processors have the same value.
401  logical function pmc_mpi_allequal_bin_grid(val)
402 
403  !> Value to compare.
404  type(bin_grid_t), intent(inout) :: val
405 
406 #ifdef PMC_USE_MPI
407  logical :: same_bin_min, same_bin_max
408 
409  if (.not. pmc_mpi_allequal_integer(val%type)) then
410  pmc_mpi_allequal_bin_grid = .false.
411  return
412  end if
413 
414  if (.not. pmc_mpi_allequal_integer(bin_grid_size(val))) then
415  pmc_mpi_allequal_bin_grid = .false.
416  return
417  end if
418 
419  if (bin_grid_size(val) <= 0) then
421  return
422  end if
423 
424  same_bin_min = pmc_mpi_allequal_real(val%edges(1))
425  same_bin_max = pmc_mpi_allequal_real(val%edges(bin_grid_size(val)))
426  if (same_bin_min .and. same_bin_max) then
428  else
429  pmc_mpi_allequal_bin_grid = .false.
430  end if
431 #else
433 #endif
434 
435  end function pmc_mpi_allequal_bin_grid
436 
437 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
438 
439  !> Write a bin grid dimension to the given NetCDF file if it is
440  !> not already present and in any case return the associated dimid.
441  subroutine bin_grid_netcdf_dim(bin_grid, ncid, dim_name, unit, dimid, &
442  long_name, scale)
443 
444  !> Bin_grid structure.
445  type(bin_grid_t), intent(in) :: bin_grid
446  !> NetCDF file ID, in data mode.
447  integer, intent(in) :: ncid
448  !> Dimension name.
449  character(len=*), intent(in) :: dim_name
450  !> Units for the grid.
451  character(len=*), intent(in) :: unit
452  !> Dimid of the grid dimension.
453  integer, intent(out) :: dimid
454  !> Long dimension name to use.
455  character(len=*), intent(in), optional :: long_name
456  !> Factor to scale grid by before output.
457  real(kind=dp), intent(in), optional :: scale
458 
459  integer :: status, varid, dimid_edges, varid_edges, varid_widths, i
460  real(kind=dp) :: centers(size(bin_grid%centers))
461  real(kind=dp) :: edges(size(bin_grid%edges))
462  real(kind=dp) :: widths(size(bin_grid%widths))
463  character(len=(len_trim(dim_name)+10)) :: dim_name_edges
464  character(len=255) :: use_long_name
465 
466  status = nf90_inq_dimid(ncid, dim_name, dimid)
467  if (status == nf90_noerr) return
468  if (status /= nf90_ebaddim) call pmc_nc_check(status)
469 
470  ! dimension not defined, so define now define it
471 
472  dim_name_edges = trim(dim_name) // "_edges"
473  if (present(long_name)) then
474  call assert_msg(125084459, len_trim(long_name) <= len(use_long_name), &
475  "long_name is longer than " &
476  // trim(integer_to_string(len(use_long_name))))
477  use_long_name = trim(long_name)
478  else
479  call assert_msg(660927086, len_trim(dim_name) <= len(use_long_name), &
480  "dim_name is longer than " &
481  // trim(integer_to_string(len(use_long_name))))
482  use_long_name = trim(dim_name)
483  end if
484 
485  call pmc_nc_check(nf90_redef(ncid))
486  call pmc_nc_check(nf90_def_dim(ncid, dim_name, size(bin_grid%centers), &
487  dimid))
488  call pmc_nc_check(nf90_def_dim(ncid, dim_name_edges, &
489  size(bin_grid%edges), dimid_edges))
490  call pmc_nc_check(nf90_enddef(ncid))
491 
492  centers = bin_grid%centers
493  edges = bin_grid%edges
494  widths = bin_grid%widths
495  if (bin_grid%type == bin_grid_type_log) then
496  if (present(scale)) then
497  centers = centers * scale
498  edges = edges * scale
499  end if
500  call pmc_nc_write_real_1d(ncid, centers, dim_name, (/ dimid /), &
501  unit=unit, long_name=(trim(use_long_name) // " grid centers"), &
502  description=("logarithmically spaced centers of " &
503  // trim(use_long_name) // " grid, so that " // trim(dim_name) &
504  // "(i) is the geometric mean of " // trim(dim_name_edges) &
505  // "(i) and " // trim(dim_name_edges) // "(i + 1)"))
506  call pmc_nc_write_real_1d(ncid, edges, dim_name_edges, &
507  (/ dimid_edges /), unit=unit, &
508  long_name=(trim(use_long_name) // " grid edges"), &
509  description=("logarithmically spaced edges of " &
510  // trim(use_long_name) // " grid, with one more edge than center"))
511  call pmc_nc_write_real_1d(ncid, widths, trim(dim_name) // "_widths", &
512  (/ dimid /), unit="1", &
513  long_name=(trim(use_long_name) // " grid widths"), &
514  description=("base-e logarithmic widths of " &
515  // trim(use_long_name) // " grid, with " // trim(dim_name) &
516  // "_widths(i) = ln(" // trim(dim_name_edges) // "(i + 1) / " &
517  // trim(dim_name_edges) // "(i))"))
518  elseif (bin_grid%type == bin_grid_type_linear) then
519  if (present(scale)) then
520  centers = centers * scale
521  edges = edges * scale
522  widths = widths * scale
523  end if
524  call pmc_nc_write_real_1d(ncid, centers, dim_name, (/ dimid /), &
525  unit=unit, long_name=(trim(use_long_name) // " grid centers"), &
526  description=("linearly spaced centers of " // trim(use_long_name) &
527  // " grid, so that " // trim(dim_name) // "(i) is the mean of " &
528  // trim(dim_name_edges) // "(i) and " // trim(dim_name_edges) &
529  // "(i + 1)"))
530  call pmc_nc_write_real_1d(ncid, edges, dim_name_edges, &
531  (/ dimid_edges /), unit=unit, &
532  long_name=(trim(use_long_name) // " grid edges"), &
533  description=("linearly spaced edges of " &
534  // trim(use_long_name) // " grid, with one more edge than center"))
535  call pmc_nc_write_real_1d(ncid, widths, trim(dim_name) // "_widths", &
536  (/ dimid /), unit=unit, &
537  long_name=(trim(use_long_name) // " grid widths"), &
538  description=("widths of " // trim(use_long_name) &
539  // " grid, with " // trim(dim_name) // "_widths(i) = " &
540  // trim(dim_name_edges) // "(i + 1) - " // trim(dim_name_edges) &
541  // "(i)"))
542  else
543  call die_msg(942560572, "unknown bin_grid type: " &
544  // trim(integer_to_string(bin_grid%type)))
545  end if
546 
547  end subroutine bin_grid_netcdf_dim
548 
549 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
550 
551  !> Write a bin grid to the given NetCDF file.
552  subroutine bin_grid_output_netcdf(bin_grid, ncid, dim_name, unit, &
553  long_name, scale)
554 
555  !> Bin_grid structure.
556  type(bin_grid_t), intent(in) :: bin_grid
557  !> NetCDF file ID, in data mode.
558  integer, intent(in) :: ncid
559  !> Dimension name.
560  character(len=*), intent(in) :: dim_name
561  !> Units for the grid.
562  character(len=*), intent(in) :: unit
563  !> Long dimension name to use.
564  character(len=*), intent(in), optional :: long_name
565  !> Factor to scale grid by before output.
566  real(kind=dp), intent(in), optional :: scale
567 
568  integer :: dimid
569 
570  call bin_grid_netcdf_dim(bin_grid, ncid, dim_name, unit, dimid, &
571  long_name, scale)
572 
573  end subroutine bin_grid_output_netcdf
574 
575 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
576 
577  !> Read full state.
578  subroutine bin_grid_input_netcdf(bin_grid, ncid, dim_name, scale)
579 
580  !> bin_grid to read.
581  type(bin_grid_t), intent(inout) :: bin_grid
582  !> NetCDF file ID, in data mode.
583  integer, intent(in) :: ncid
584  !> Dimension name.
585  character(len=*), intent(in) :: dim_name
586  !> Factor to scale grid by after input.
587  real(kind=dp), intent(in), optional :: scale
588 
589  integer :: dimid, varid, n_bin, type
590  character(len=1000) :: name, description
591  real(kind=dp), allocatable :: edges(:)
592 
593  call pmc_nc_check(nf90_inq_dimid(ncid, dim_name, dimid))
594  call pmc_nc_check(nf90_inquire_dimension(ncid, dimid, name, n_bin))
595  call pmc_nc_check(nf90_inq_varid(ncid, dim_name, varid))
596  call pmc_nc_check(nf90_get_att(ncid, varid, "description", description))
597 
598  call pmc_nc_read_real_1d(ncid, edges, dim_name // "_edges")
599 
600  if (starts_with(description, "logarithmically")) then
601  type = bin_grid_type_log
602  elseif (starts_with(description, "linearly")) then
603  type = bin_grid_type_linear
604  else
605  call die_msg(792158584, "cannot identify grid type for NetCDF " &
606  // "dimension: " // trim(dim_name))
607  end if
608 
609  if (present(scale)) then
610  call bin_grid_make(bin_grid, type, n_bin, scale * edges(1), &
611  scale * edges(n_bin + 1))
612  else
613  call bin_grid_make(bin_grid, type, n_bin, edges(1), edges(n_bin + 1))
614  end if
615 
616  end subroutine bin_grid_input_netcdf
617 
618 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
619 
620 end module pmc_bin_grid
pmc_util::linspace_find
integer function linspace_find(min_x, max_x, n, x)
Find the position of a real number in a 1D linear array.
Definition: util.F90:533
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_mpi
Wrapper functions for MPI.
Definition: mpi.F90:13
pmc_util::starts_with
logical function starts_with(string, start_string)
Checks whether a string starts with a given other string.
Definition: util.F90:1894
pmc_spec_file::spec_file_read_integer
subroutine spec_file_read_integer(file, name, var)
Read an integer from a spec file that must have the given name.
Definition: spec_file.F90:541
pmc_bin_grid::vol_to_lnr
subroutine vol_to_lnr(r, f_vol, f_lnr)
Convert a concentration f(vol)d(vol) to f(ln(r))d(ln(r)) where vol = 4/3 pi r^3.
Definition: bin_grid.F90:68
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_util::die_msg
subroutine die_msg(code, error_msg)
Error immediately.
Definition: util.F90:135
pmc_bin_grid::bin_grid_histogram_2d
real(kind=dp) function, dimension(bin_grid_size(x_bin_grid), bin_grid_size(y_bin_grid)) bin_grid_histogram_2d(x_bin_grid, x_data, y_bin_grid, y_data, weight_data)
Make a 2D histogram with of the given weighted data, scaled by the bin sizes.
Definition: bin_grid.F90:256
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_mpi::pmc_mpi_allequal_integer
logical function pmc_mpi_allequal_integer(val)
Returns whether all processors have the same value.
Definition: mpi.F90:1904
pmc_constants::dp
integer, parameter dp
Kind of a double precision real number.
Definition: constants.F90:12
pmc_spec_file
Reading formatted text input.
Definition: spec_file.F90:43
pmc_bin_grid::bin_grid_size
elemental integer function bin_grid_size(bin_grid)
Return the number of bins in the grid, or -1 if the bin grid is not allocated.
Definition: bin_grid.F90:51
pmc_util::assert
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
Definition: util.F90:104
pmc_util::logspace
real(kind=dp) function, dimension(:), allocatable logspace(min_x, max_x, n)
Makes a logarithmically spaced array of length n from min to max.
Definition: util.F90:493
pmc_mpi::pmc_mpi_pack_size_real_array
integer function pmc_mpi_pack_size_real_array(val)
Determines the number of bytes required to pack the given value.
Definition: mpi.F90:527
pmc_bin_grid::pmc_mpi_allequal_bin_grid
logical function pmc_mpi_allequal_bin_grid(val)
Check whether all processors have the same value.
Definition: bin_grid.F90:402
pmc_util::interp_linear_disc
real(kind=dp) function interp_linear_disc(x_1, x_n, n, i)
Linear interpolation over discrete indices.
Definition: util.F90:664
pmc_spec_file::spec_file_t
An input file with extra data for printing messages.
Definition: spec_file.F90:59
pmc_util::linspace
real(kind=dp) function, dimension(:), allocatable linspace(min_x, max_x, n)
Makes a linearly spaced array from min to max.
Definition: util.F90:461
pmc_spec_file::spec_file_read_real
subroutine spec_file_read_real(file, name, var)
Read a real number from a spec file that must have the given name.
Definition: spec_file.F90:563
pmc_bin_grid::pmc_mpi_pack_size_bin_grid
integer function pmc_mpi_pack_size_bin_grid(val)
Determines the number of bytes required to pack the given value.
Definition: bin_grid.F90:334
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::real_to_string
character(len=pmc_util_convert_string_len) function real_to_string(val)
Convert a real to a string format.
Definition: util.F90:799
pmc_util::assert_msg
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition: util.F90:78
pmc_util::diam2rad
real(kind=dp) elemental function diam2rad(d)
Convert diameter (m) to radius (m).
Definition: util.F90:278
pmc_bin_grid::bin_grid_output_netcdf
subroutine bin_grid_output_netcdf(bin_grid, ncid, dim_name, unit, long_name, scale)
Write a bin grid to the given NetCDF file.
Definition: bin_grid.F90:554
pmc_bin_grid::pmc_mpi_pack_bin_grid
subroutine pmc_mpi_pack_bin_grid(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: bin_grid.F90:350
pmc_constants::const
type(const_t), save const
Fixed variable for accessing the constant's values.
Definition: constants.F90:75
pmc_bin_grid::bin_grid_input_netcdf
subroutine bin_grid_input_netcdf(bin_grid, ncid, dim_name, scale)
Read full state.
Definition: bin_grid.F90:579
pmc_bin_grid::bin_grid_type_linear
integer, parameter bin_grid_type_linear
Linearly spaced bin grid.
Definition: bin_grid.F90:25
pmc_util::logspace_find
integer function logspace_find(min_x, max_x, n, x)
Find the position of a real number in a 1D logarithmic array.
Definition: util.F90:567
pmc_mpi::pmc_mpi_unpack_integer
subroutine pmc_mpi_unpack_integer(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: mpi.F90:1139
pmc_constants
Physical constants.
Definition: constants.F90:9
pmc_bin_grid::bin_grid_netcdf_dim
subroutine bin_grid_netcdf_dim(bin_grid, ncid, dim_name, unit, dimid, long_name, scale)
Write a bin grid dimension to the given NetCDF file if it is not already present and in any case retu...
Definition: bin_grid.F90:443
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_mpi::pmc_mpi_allequal_real
logical function pmc_mpi_allequal_real(val)
Returns whether all processors have the same value.
Definition: mpi.F90:1928
pmc_bin_grid::pmc_mpi_unpack_bin_grid
subroutine pmc_mpi_unpack_bin_grid(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: bin_grid.F90:376
pmc_bin_grid::bin_grid_histogram_1d
real(kind=dp) function, dimension(bin_grid_size(x_bin_grid)) bin_grid_histogram_1d(x_bin_grid, x_data, weight_data)
Make a histogram with of the given weighted data, scaled by the bin sizes.
Definition: bin_grid.F90:226
pmc_mpi::pmc_mpi_pack_size_integer
integer function pmc_mpi_pack_size_integer(val)
Determines the number of bytes required to pack the given value.
Definition: mpi.F90:345
pmc_bin_grid
The bin_grid_t structure and associated subroutines.
Definition: bin_grid.F90:9
pmc_mpi::pmc_mpi_pack_integer
subroutine pmc_mpi_pack_integer(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: mpi.F90:711
pmc_mpi::pmc_mpi_pack_real_array
subroutine pmc_mpi_pack_real_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: mpi.F90:927
pmc_bin_grid::bin_grid_t
1D grid, either logarithmic or linear.
Definition: bin_grid.F90:33
pmc_mpi::pmc_mpi_unpack_real_array
subroutine pmc_mpi_unpack_real_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: mpi.F90:1356
pmc_bin_grid::bin_grid_contains
logical function bin_grid_contains(bin_grid, i_bin, val)
Determines if a value is in a given bin.
Definition: bin_grid.F90:178
pmc_bin_grid::bin_grid_type_log
integer, parameter bin_grid_type_log
Logarithmically spaced bin grid.
Definition: bin_grid.F90:23
pmc_bin_grid::bin_grid_make
subroutine bin_grid_make(bin_grid, type, n_bin, min, max)
Generates the bin grid given the range and number of bins.
Definition: bin_grid.F90:84
pmc_bin_grid::bin_grid_find
integer function bin_grid_find(bin_grid, val)
Find the bin number that contains a given value.
Definition: bin_grid.F90:144
pmc_bin_grid::bin_grid_type_invalid
integer, parameter bin_grid_type_invalid
Invalid type of bin grid.
Definition: bin_grid.F90:21