PartMC  2.3.0
extract_aero_size.F90
Go to the documentation of this file.
1 ! Copyright (C) 2009-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 extract_aero_size program.
7 
8 !> Read NetCDF output files and write out the aerosol number or mass
9 !> size distributions in text format.
11 
12  use pmc_aero_state
14  use pmc_output
15  use pmc_mpi
16  use getopt_m
17 
18  integer, parameter :: dist_type_none = 0
19  integer, parameter :: dist_type_num = 1
20  integer, parameter :: dist_type_mass = 2
21 
22  character(len=PMC_MAX_FILENAME_LEN) :: in_prefix, out_filename
23  character(len=PMC_MAX_FILENAME_LEN), allocatable :: filename_list(:)
24  character(len=1000) :: tmp_str
25  type(bin_grid_t) :: diam_grid
26  type(aero_data_t) :: aero_data
27  type(aero_state_t) :: aero_state
28  integer :: index, i_repeat, i_part, i_spec, out_unit
29  integer :: i_file, n_file, i_bin, n_bin, dist_type
30  real(kind=dp) :: time, del_t
31  type(aero_particle_t), pointer :: aero_particle
32  real(kind=dp) :: d_min, d_max, diam, volume
33  character(len=PMC_UUID_LEN) :: uuid, run_uuid
34  real(kind=dp), allocatable :: diameters(:), num_concs(:), masses(:), hist(:)
35  real(kind=dp), allocatable :: aero_dist(:,:)
36  type(option_s) :: opts(7)
37 
38  call pmc_mpi_init()
39 
40  opts(1) = option_s("help", .false., 'h')
41  opts(2) = option_s("num", .false., 'n')
42  opts(3) = option_s("mass", .false., 'm')
43  opts(4) = option_s("dmin", .true., 'N')
44  opts(5) = option_s("dmax", .true., 'X')
45  opts(6) = option_s("nbin", .true., 'b')
46  opts(7) = option_s("output", .true., 'o')
47 
48  dist_type = dist_type_none
49  d_min = 1d-10
50  d_max = 1d-3
51  n_bin = 100
52  out_filename = ""
53 
54  do
55  select case(getopt("hnmN:X:b:o:", opts))
56  case(char(0))
57  exit
58  case('h')
59  call print_help()
60  stop
61  case('n')
62  if (dist_type /= dist_type_none) then
63  call print_help()
64  call die_msg(525113814, 'multiple distribution types selected')
65  end if
66  dist_type = dist_type_num
67  case('m')
68  if (dist_type /= dist_type_none) then
69  call print_help()
70  call die_msg(155494931, 'multiple distribution types selected')
71  end if
72  dist_type = dist_type_mass
73  case('N')
74  d_min = string_to_real(optarg)
75  case('X')
76  d_max = string_to_real(optarg)
77  case('b')
78  n_bin = string_to_integer(optarg)
79  case('o')
80  out_filename = optarg
81  case( '?' )
82  call print_help()
83  call die_msg(956456220, 'unknown option: ' // trim(optopt))
84  case default
85  call print_help()
86  call die_msg(203991511, 'unhandled option: ' // trim(optopt))
87  end select
88  end do
89 
90  if (optind /= command_argument_count()) then
91  call print_help()
92  call die_msg(533171694, 'expected exactly one non-option prefix argument')
93  end if
94 
95  call get_command_argument(optind, in_prefix)
96 
97  if (dist_type == dist_type_none) then
98  call print_help()
99  call die_msg(540839314, 'must select distribution type (--num or --mass)')
100  end if
101 
102  if (out_filename == "") then
103  if (dist_type == dist_type_num) then
104  out_filename = trim(in_prefix) // "_aero_size_num.txt"
105  elseif (dist_type == dist_type_mass) then
106  out_filename = trim(in_prefix) // "_aero_size_mass.txt"
107  else
108  call die(545030852)
109  end if
110  end if
111 
112  call bin_grid_allocate(diam_grid)
113  call aero_data_allocate(aero_data)
114  call aero_state_allocate(aero_state)
115 
116  allocate(filename_list(0))
117  call input_filename_list(in_prefix, filename_list)
118  n_file = size(filename_list)
119  call assert_msg(554271458, n_file > 0, &
120  "no NetCDF files found with prefix: " // trim(in_prefix))
121 
122  call bin_grid_make(diam_grid, bin_grid_type_log, n_bin, d_min, d_max)
123  allocate(aero_dist(n_bin, n_file))
124 
125  do i_file = 1,n_file
126  call input_state(filename_list(i_file), index, time, del_t, i_repeat, &
127  uuid, aero_data=aero_data, aero_state=aero_state)
128 
129  if (i_file == 1) then
130  run_uuid = uuid
131  else
132  call assert_msg(657993562, uuid == run_uuid, &
133  "UUID mismatch between " // trim(filename_list(1)) // " and " &
134  // trim(filename_list(i_file)))
135  end if
136 
137  diameters = aero_state_diameters(aero_state)
138  num_concs = aero_state_num_concs(aero_state)
139  if (dist_type == dist_type_num) then
140  hist = bin_grid_histogram_1d(diam_grid, diameters, num_concs)
141  elseif (dist_type == dist_type_mass) then
142  masses = aero_state_masses(aero_state, aero_data)
143  hist = bin_grid_histogram_1d(diam_grid, diameters, num_concs * masses)
144  else
145  call die(123323238)
146  end if
147  aero_dist(:, i_file) = hist
148  end do
149 
150  write(*,'(a)') "Output file: " // trim(out_filename)
151  write(*,'(a)') " Each row of output is one size bin."
152  write(*,'(a)') " The columns of output are:"
153  write(*,'(a)') " column 1: bin center diameter (m)"
154  if (dist_type == dist_type_num) then
155  write(*,'(a)') " column j+1: number concentration at time(j) (#/m^3)"
156  elseif (dist_type == dist_type_mass) then
157  write(*,'(a)') " column j+1: mass concentration at time(j) (kg/m^3)"
158  end if
159  write(*,'(a)') " Diameter bins have logarithmic width:"
160  write(*,'(a,e20.10)') " log_width = ln(diam(i+1)) - ln(diam(i)) =", &
161  diam_grid%widths(1)
162 
163  call open_file_write(out_filename, out_unit)
164  do i_bin = 1,n_bin
165  write(out_unit, '(e30.15e3)', advance='no') diam_grid%centers(i_bin)
166  do i_file = 1,n_file
167  write(out_unit, '(e30.15e3)', advance='no') aero_dist(i_bin, i_file)
168  end do
169  write(out_unit, '(a)') ''
170  end do
171  call close_file(out_unit)
172 
173  deallocate(filename_list)
174  deallocate(aero_dist)
175  call bin_grid_allocate(diam_grid)
176  call aero_data_deallocate(aero_data)
177  call aero_state_deallocate(aero_state)
178 
179  call pmc_mpi_finalize()
180 
181 contains
182 
183  subroutine print_help()
184 
185  write(*,'(a)') 'Usage: extract_aero_size [options] <netcdf_prefix>'
186  write(*,'(a)') ''
187  write(*,'(a)') 'options are:'
188  write(*,'(a)') ' -h, --help Print this help message.'
189  write(*,'(a)') ' -n, --num Output number distribution.'
190  write(*,'(a)') ' -m, --mass Output mass distribution.'
191  write(*,'(a)') ' -N, --dmin <D> Minimum diameter (m).'
192  write(*,'(a)') ' -X, --dmax <D> Maximum diameter (m).'
193  write(*,'(a)') ' -b, --nbin <N> Number of size bins.'
194  write(*,'(a)') ' -o, --out <file> Output filename.'
195  write(*,'(a)') ''
196  write(*,'(a)') 'Examples:'
197  write(*,'(a)') ' extract_aero_size --num data_0001'
198  write(*,'(a)') &
199  ' extract_aero_size --mass --dmin 1e-8 --dmax 1e-4 data_0001'
200  write(*,'(a)') ''
201 
202  end subroutine print_help
203 
204 end program extract_aero_size
subroutine input_state(filename, index, time, del_t, i_repeat, uuid, aero_data, aero_state, gas_data, gas_state, env_state)
Read the current state.
Definition: output.F90:509
subroutine die_msg(code, error_msg)
Error immediately.
Definition: util.F90:133
character function getopt(optstring, longopts)
Definition: getopt.F90:131
subroutine input_filename_list(prefix, filename_list)
Find all NetCDF (.nc) filenames that match the given prefix.
Definition: output.F90:580
real(kind=dp) function, dimension(x_bin_grid%n_bin) 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:223
subroutine close_file(unit)
Close a file and de-assign the unit.
Definition: util.F90:225
The aero_particle_t structure and associated subroutines.
subroutine aero_state_allocate(aero_state)
Allocates aerosol arrays.
Definition: aero_state.F90:83
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:136
real(kind=dp) function, dimension(aero_state%apa%n_part) aero_state_diameters(aero_state)
Returns the diameters of all particles.
Definition: aero_state.F90:976
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
Definition: util.F90:76
real(kind=dp) function, dimension(aero_state%apa%n_part) aero_state_masses(aero_state, aero_data, include, exclude)
Returns the masses of all particles.
subroutine pmc_mpi_finalize()
Shut down MPI.
Definition: mpi.F90:88
subroutine pmc_mpi_init()
Initialize MPI.
Definition: mpi.F90:55
program extract_aero_size
Read NetCDF output files and write out the aerosol number or mass size distributions in text format...
subroutine bin_grid_allocate(bin_grid)
Allocates a bin_grid.
Definition: bin_grid.F90:51
integer function string_to_integer(string)
Convert a string to an integer.
Definition: util.F90:665
subroutine aero_data_deallocate(aero_data)
Frees all storage.
Definition: aero_data.F90:116
The aero_state_t structure and assocated subroutines.
Definition: aero_state.F90:9
Wrapper functions for MPI.
Definition: mpi.F90:13
The current collection of aerosol particles.
Definition: aero_state.F90:63
Single aerosol particle data structure.
1D grid, either logarithmic or linear.
Definition: bin_grid.F90:33
subroutine aero_state_deallocate(aero_state)
Deallocates a previously allocated aerosol.
Definition: aero_state.F90:100
subroutine die(code)
Error immediately.
Definition: util.F90:121
subroutine print_help()
real(kind=dp) function, dimension(aero_state%apa%n_part) aero_state_num_concs(aero_state)
Returns the number concentrations of all particles.
subroutine aero_data_allocate(aero_data)
Allocate storage for aero_data.
Definition: aero_data.F90:69
Aerosol material properties and associated data.
Definition: aero_data.F90:40
real(kind=dp) function string_to_real(string)
Convert a string to a real.
Write data in NetCDF format.
Definition: output.F90:68
subroutine open_file_write(filename, unit)
Open a file for writing with an automatically assigned unit and test that it succeeds. The file should be closed with close_file().
Definition: util.F90:205