45 character(len=AERO_NAME_LEN),
allocatable :: name(:)
48 integer,
allocatable :: mosaic_index(:)
50 real(kind=dp),
allocatable :: density(:)
52 integer,
allocatable :: num_ions(:)
54 real(kind=dp),
allocatable :: molec_weight(:)
56 real(kind=dp),
allocatable :: kappa(:)
58 character(len=AERO_SOURCE_NAME_LEN),
allocatable :: source_name(:)
74 real(kind=dp),
intent(in) :: v
89 real(kind=dp),
intent(in) :: v
104 real(kind=dp),
intent(in) :: r
119 real(kind=dp),
intent(in) :: d
137 real(kind=dp),
intent(in) :: v
140 aero_data%fractal, v)
156 real(kind=dp),
intent(in) :: v
158 real(kind=dp),
intent(in) :: temp
160 real(kind=dp),
intent(in) :: pressure
163 aero_data%fractal, v, temp, pressure)
172 mobility_rad, temp, pressure)
177 real(kind=dp),
intent(in) :: mobility_rad
179 real(kind=dp),
intent(in) :: temp
181 real(kind=dp),
intent(in) :: pressure
184 aero_data%fractal, mobility_rad, temp, pressure)
193 mobility_rad, temp, pressure)
198 real(kind=dp),
intent(in) :: mobility_rad
200 real(kind=dp),
intent(in) :: temp
202 real(kind=dp),
intent(in) :: pressure
206 mobility_rad, temp, pressure)
218 if (
allocated(aero_data%name))
then 234 if (
allocated(aero_data%source_name))
then 251 character(len=*),
intent(in) :: name
258 if (name == aero_data%name(i))
then 280 character(len=*),
intent(in) :: name
282 if (.not.
allocated(aero_data%source_name))
then 289 aero_data%source_name = [aero_data%source_name, &
317 integer,
parameter :: n_mosaic_spec = 19
318 character(AERO_NAME_LEN),
parameter,
dimension(n_mosaic_spec) :: &
319 mosaic_spec_name = [ &
320 "SO4 ",
"NO3 ",
"Cl ",
"NH4 ",
"MSA ",
"ARO1 ", &
321 "ARO2 ",
"ALK1 ",
"OLE1 ",
"API1 ",
"API2 ",
"LIM1 ", &
322 "LIM2 ",
"CO3 ",
"Na ",
"Ca ",
"OIN ",
"OC ", &
325 integer :: i_spec, i_mosaic_spec, i
327 aero_data%mosaic_index = 0
330 aero_data%name(i_spec))
338 subroutine spec_file_read_aero_data(file, aero_data)
345 integer :: n_species, species, i
346 character(len=SPEC_LINE_MAX_VAR_LEN),
allocatable :: species_name(:)
347 real(kind=dp),
allocatable :: species_data(:,:)
386 n_species =
size(species_data, 1)
387 if (.not. ((
size(species_data, 2) == 4) .or. (n_species == 0)))
then 388 call die_msg(428926381,
'each line in ' // trim(file%name) &
389 //
' should contain exactly 5 values')
401 aero_data%density(i) = species_data(i,1)
402 aero_data%num_ions(i) = nint(species_data(i,2))
403 aero_data%molec_weight(i) = species_data(i,3)
404 aero_data%kappa(i) = species_data(i,4)
406 (aero_data%num_ions(i) == 0) .or. (aero_data%kappa(i) == 0d0), &
407 "ions and kappa both non-zero for species " &
408 // trim(aero_data%name(i)) //
" in " // trim(file%name))
409 if (species_name(i) ==
"H2O")
then 410 aero_data%i_water = i
412 aero_data%density(i) == const%water_density, &
413 "input H2O density not equal to const%water_density (" &
417 aero_data%molec_weight(i) == const%water_molec_weight, &
418 "input H2O molec_weight not equal " &
419 //
"to const%water_molec_weight (" &
427 end subroutine spec_file_read_aero_data
437 character(len=*),
intent(in) :: name
441 integer,
allocatable :: species_list(:)
443 type(spec_line_t) :: line
449 do i = 1,
size(line%data)
453 'unknown species: ' // trim(line%data(i)))
455 species_list(i) = spec
487 character,
intent(inout) :: buffer(:)
489 integer,
intent(inout) :: position
494 integer :: prev_position
496 prev_position = position
518 character,
intent(inout) :: buffer(:)
520 integer,
intent(inout) :: position
525 integer :: prev_position
527 prev_position = position
554 integer,
intent(in) :: ncid
556 integer,
intent(out) :: dimid_aero_species
558 integer :: status, i_spec
559 integer :: varid_aero_species
561 character(len=(AERO_NAME_LEN * aero_data_n_spec(aero_data))) :: &
565 status = nf90_inq_dimid(ncid,
"aero_species", dimid_aero_species)
566 if (status == nf90_noerr)
return 574 aero_species_names =
"" 576 aero_species_names((len_trim(aero_species_names) + 1):) &
577 = trim(aero_data%name(i_spec))
579 aero_species_names((len_trim(aero_species_names) + 1):) =
"," 582 call pmc_nc_check(nf90_def_var(ncid,
"aero_species", nf90_int, &
583 dimid_aero_species, varid_aero_species))
584 call pmc_nc_check(nf90_put_att(ncid, varid_aero_species,
"names", &
586 call pmc_nc_check(nf90_put_att(ncid, varid_aero_species,
"description", &
587 "dummy dimension variable (no useful value) - read species names " &
588 //
"as comma-separated values from the 'names' attribute"))
593 aero_species_centers(i_spec) = i_spec
595 call pmc_nc_check(nf90_put_var(ncid, varid_aero_species, &
596 aero_species_centers))
611 integer,
intent(in) :: ncid
613 integer,
intent(out) :: dimid_aero_source
615 integer :: status, i_source
616 integer :: varid_aero_source
618 character(len=(AERO_SOURCE_NAME_LEN * aero_data_n_source(aero_data))) &
622 status = nf90_inq_dimid(ncid,
"aero_source", dimid_aero_source)
623 if (status == nf90_noerr)
return 631 aero_source_names =
"" 633 aero_source_names((len_trim(aero_source_names) + 1):) &
634 = trim(aero_data%source_name(i_source))
636 aero_source_names((len_trim(aero_source_names) + 1):) =
"," 639 call pmc_nc_check(nf90_def_var(ncid,
"aero_source", nf90_int, &
640 dimid_aero_source, varid_aero_source))
641 call pmc_nc_check(nf90_put_att(ncid, varid_aero_source,
"names", &
643 call pmc_nc_check(nf90_put_att(ncid, varid_aero_source,
"description", &
644 "dummy dimension variable (no useful value) - read source names " &
645 //
"as comma-separated values from the 'names' attribute"))
650 aero_source_centers(i_source) = i_source
652 call pmc_nc_check(nf90_put_var(ncid, varid_aero_source, &
653 aero_source_centers))
660 subroutine aero_data_output_netcdf(aero_data, ncid)
665 integer,
intent(in) :: ncid
667 integer :: dimid_aero_species, dimid_aero_source
703 "aero_mosaic_index", (/ dimid_aero_species /), &
704 long_name=
"MOSAIC indices of aerosol species")
706 "aero_density", (/ dimid_aero_species /), unit=
"kg/m^3", &
707 long_name=
"densities of aerosol species")
709 "aero_num_ions", (/ dimid_aero_species /), &
710 long_name=
"number of ions after dissociation of aerosol species")
712 "aero_molec_weight", (/ dimid_aero_species /), unit=
"kg/mol", &
713 long_name=
"molecular weights of aerosol species")
715 "aero_kappa", (/ dimid_aero_species /), unit=
"1", &
716 long_name=
"hygroscopicity parameters (kappas) of aerosol species")
717 call fractal_output_netcdf(aero_data%fractal, ncid)
719 end subroutine aero_data_output_netcdf
729 integer,
intent(in) :: ncid
731 integer,
parameter :: MAX_SPECIES = 1000
732 integer,
parameter :: MAX_SOURCES = 1000
734 character(len=1000) :: name
735 integer :: dimid_aero_species, n_spec, varid_aero_species, i_spec, i
736 integer :: dimid_aero_source, n_source, varid_aero_source, i_source
737 character(len=((AERO_NAME_LEN + 2) * MAX_SPECIES)) :: aero_species_names
738 character(len=((AERO_SOURCE_NAME_LEN + 2) * MAX_SPECIES)) &
741 call pmc_nc_check(nf90_inq_dimid(ncid,
"aero_species", &
744 dimid_aero_species, name, n_spec))
745 call assert(141013948, n_spec < max_species)
750 dimid_aero_source, name, n_source))
751 call assert(739238793, n_source < max_sources)
760 call pmc_nc_check(nf90_inq_varid(ncid,
"aero_species", &
762 call pmc_nc_check(nf90_get_att(ncid, varid_aero_species,
"names", &
768 do while ((aero_species_names(i:i) /=
" ") &
769 .and. (aero_species_names(i:i) /=
","))
772 call assert(852937292, i > 1)
773 aero_data%name(i_spec) = aero_species_names(1:(i-1))
774 aero_species_names = aero_species_names((i+1):)
776 call assert(729138192, aero_species_names ==
"")
780 call pmc_nc_check(nf90_get_att(ncid, varid_aero_source,
"names", &
786 do while ((aero_source_names(i:i) /=
" ") &
787 .and. (aero_source_names(i:i) /=
","))
790 call assert(840982478, i > 1)
791 aero_data%source_name(i_source) = aero_source_names(1:(i-1))
792 aero_source_names = aero_source_names((i+1):)
794 call assert(377166446, aero_source_names ==
"")
subroutine pmc_mpi_pack_integer_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
real(kind=dp) elemental function fractal_vol_to_num_of_monomers(fractal, v)
Convert mass-equivalent volume (m^3) to number of monomers in a fractal particle cluster...
type(fractal_t), intent(in) fractal
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
An input file with extra data for printing messages.
integer function pmc_mpi_pack_size_integer_array(val)
Determines the number of bytes required to pack the given value.
subroutine spec_file_read_species_list(file, name, aero_data, species_list)
Read a list of species from the given file with the given name.
Wrapper functions for NetCDF. These all take a NetCDF ncid in data mode and return with it again in d...
subroutine pmc_nc_read_real_1d(ncid, var, name, must_be_present)
Read a simple real array from a NetCDF file.
real(kind=dp) function aero_data_vol_to_mobility_rad(aero_data, v, temp, pressure)
Convert mass-equivalent volume (m^3) to mobility equivalent radius (m).
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 ...
real(kind=dp) elemental function aero_data_diam2vol(aero_data, d)
Convert geometric diameter (m) to mass-equivalent volume (m^3).
subroutine pmc_mpi_unpack_integer_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
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 ...
real(kind=dp) elemental function aero_data_rad2vol(aero_data, r)
Convert geometric radius (m) to mass-equivalent volume (m^3).
subroutine pmc_mpi_pack_string_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine aero_data_netcdf_dim_aero_species(aero_data, ncid, dimid_aero_species)
Write the aero species dimension to the given NetCDF file if it is not already present and in any cas...
integer function pmc_mpi_pack_size_real_array(val)
Determines the number of bytes required to pack the given value.
The fractal_t structure and associated subroutines.
subroutine aero_data_set_mosaic_map(aero_data)
Fills in aero_data%mosaic_index.
real(kind=dp) function aero_data_mobility_rad_to_vol(aero_data, mobility_rad, temp, pressure)
Convert mobility equivalent radius (m) to mass-equivalent volume (m^3).
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
real(kind=dp) elemental function fractal_rad2vol(fractal, r)
Convert geometric radius (m) to mass-equivalent volume (m^3).
integer function aero_data_source_by_name(aero_data, name)
Returns the number of the source in aero_data with the given name, or adds the source if it doesn't e...
subroutine pmc_mpi_pack_fractal(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine pmc_nc_check(status)
Check the status of a NetCDF function call.
subroutine warn_assert_msg(code, condition_ok, warning_msg)
Prints a warning message if condition_ok is false.
subroutine die_msg(code, error_msg)
Error immediately.
subroutine pmc_mpi_unpack_aero_data(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
real(kind=dp) elemental function aero_data_vol_to_num_of_monomers(aero_data, v)
Convert mass-equivalent volume (m^3) to number of monomers in a fractal particle cluster...
subroutine ensure_string_array_size(x, n)
Allocate or reallocate the given array to ensure it is of the given size, without preserving data...
subroutine aero_data_input_netcdf(aero_data, ncid)
Read full state.
subroutine spec_file_die_msg(code, file, msg)
Exit with an error message containing filename and line number.
subroutine pmc_mpi_pack_aero_data(buffer, position, val)
Packs the given value into the buffer, advancing position.
character(len=pmc_util_convert_string_len) function real_to_string(val)
Convert a real to a string format.
integer function pmc_mpi_pack_size_fractal(val)
Determines the number of bytes required to pack the given value.
The aero_data_t structure and associated subroutines.
real(kind=dp) elemental function fractal_vol2rad(fractal, v)
Convert mass-equivalent volume (m^3) to geometric radius (m).
real(kind=dp) elemental function diam2rad(d)
Convert diameter (m) to radius (m).
subroutine pmc_mpi_pack_integer(buffer, position, val)
Packs the given value into the buffer, advancing position.
integer, parameter aero_name_len
subroutine pmc_mpi_unpack_fractal(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Reading formatted text input.
subroutine pmc_mpi_unpack_string_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
integer function string_array_find(array, val)
Return the index of the first occurance of the given value in the array, or 0 if it is not present...
subroutine pmc_mpi_pack_real_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine pmc_mpi_unpack_real_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
real(kind=dp) function fractal_mobility_rad_to_vol(fractal, mobility_rad, temp, pressure)
Convert mobility equivalent radius (m) to mass-equivalent volume (m^3).
subroutine aero_data_netcdf_dim_aero_source(aero_data, ncid, dimid_aero_source)
Write the aero source dimension to the given NetCDF file if it is not already present and in any case...
subroutine spec_file_read_real_named_array(file, max_lines, names, vals)
Read an array of named lines with real data. All lines must have the same number of data elements...
real(kind=dp) elemental function aero_data_vol2rad(aero_data, v)
Convert mass-equivalent volume (m^3) to geometric radius (m).
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.
subroutine spec_file_check_line_name(file, line, name)
Check that the name of the line data is as given.
subroutine aero_data_set_water_index(aero_data)
Fills in aero_data%i_water.
integer function pmc_mpi_pack_size_integer(val)
Determines the number of bytes required to pack the given value.
real(kind=dp) elemental function aero_data_vol2diam(aero_data, v)
Convert mass-equivalent volume (m^3) to geometric diameter (m).
subroutine spec_file_read_line_no_eof(file, line)
Read a spec_line from the spec_file. This will always succeed or error out, so should only be called ...
subroutine pmc_mpi_unpack_integer(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
real(kind=dp) elemental function fractal_vol2diam(fractal, v)
Convert mass-equivalent volume (m^3) to geometric diameter (m).
integer function pmc_mpi_pack_size_aero_data(val)
Determines the number of bytes required to pack the given value.
elemental integer function aero_data_n_source(aero_data)
Return the number of aerosol sources, or -1 if uninitialized.
elemental integer function aero_data_n_spec(aero_data)
Return the number of aerosol species, or -1 if uninitialized.
subroutine pmc_nc_read_integer_1d(ncid, var, name, must_be_present)
Read a simple integer array from a NetCDF file.
Aerosol material properties and associated data.
integer, parameter aero_source_name_len
subroutine fractal_input_netcdf(fractal, ncid)
Read full state.
real(kind=dp) function fractal_mobility_rad_to_geometric_rad(fractal, mobility_rad, temp, pressure)
Convert mobility equivalent radius (m) to geometric radius (m^3).
Common utility subroutines.
Wrapper functions for MPI.
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.
real(kind=dp) function aero_data_mobility_rad_to_geometric_rad(aero_data, mobility_rad, temp, pressure)
Convert mobility equivalent radius (m) to geometric radius (m^3).
integer function aero_data_spec_by_name(aero_data, name)
Returns the number of the species in aero_data with the given name, or returns 0 if there is no such ...
integer function pmc_mpi_pack_size_string_array(val)
Determines the number of bytes required to pack the given value.
real(kind=dp) function fractal_vol_to_mobility_rad(fractal, v, temp, pressure)
Convert mass-equivalent volume (m^3) to mobility equivalent radius (m).