19 integer,
parameter :: AERO_NAME_LEN = 15
20 integer,
parameter :: AERO_SOURCE_NAME_LEN = 100
48 character(len=AERO_NAME_LEN),
pointer :: name(:)
51 integer,
pointer :: mosaic_index(:)
53 real(kind=dp),
pointer :: density(:)
55 integer,
pointer :: num_ions(:)
57 real(kind=dp),
pointer :: molec_weight(:)
59 real(kind=dp),
pointer :: kappa(:)
61 character(len=AERO_SOURCE_NAME_LEN),
pointer :: source_name(:)
75 aero_data%n_source = 0
76 allocate(aero_data%name(0))
77 allocate(aero_data%mosaic_index(0))
78 allocate(aero_data%density(0))
79 allocate(aero_data%num_ions(0))
80 allocate(aero_data%molec_weight(0))
81 allocate(aero_data%kappa(0))
82 allocate(aero_data%source_name(0))
96 integer,
intent(in) :: n_spec
98 integer,
intent(in) :: n_source
100 aero_data%n_spec = n_spec
101 aero_data%n_source = n_source
102 allocate(aero_data%name(n_spec))
103 allocate(aero_data%mosaic_index(n_spec))
104 allocate(aero_data%density(n_spec))
105 allocate(aero_data%num_ions(n_spec))
106 allocate(aero_data%molec_weight(n_spec))
107 allocate(aero_data%kappa(n_spec))
108 allocate(aero_data%source_name(n_source))
109 aero_data%i_water = 0
121 deallocate(aero_data%name)
122 deallocate(aero_data%mosaic_index)
123 deallocate(aero_data%density)
124 deallocate(aero_data%num_ions)
125 deallocate(aero_data%molec_weight)
126 deallocate(aero_data%kappa)
127 deallocate(aero_data%source_name)
143 aero_data_from%n_source)
145 aero_data_to%i_water = aero_data_from%i_water
146 aero_data_to%name = aero_data_from%name
147 aero_data_to%mosaic_index = aero_data_from%mosaic_index
148 aero_data_to%density = aero_data_from%density
149 aero_data_to%num_ions = aero_data_from%num_ions
150 aero_data_to%molec_weight = aero_data_from%molec_weight
151 aero_data_to%kappa = aero_data_from%kappa
152 aero_data_to%source_name = aero_data_from%source_name
165 character(len=*),
intent(in) :: name
171 do i = 1,aero_data%n_spec
172 if (name == aero_data%name(i))
then
194 character(len=*),
intent(in) :: name
198 character(len=AERO_SOURCE_NAME_LEN),
pointer :: new_source_name(:)
201 do i = 1,aero_data%n_source
202 if (name == aero_data%source_name(i))
then
210 allocate(new_source_name(aero_data%n_source + 1))
211 do i = 1,aero_data%n_source
212 new_source_name(i) = aero_data%source_name(i)
214 new_source_name(i) = name(1:aero_source_name_len)
215 deallocate(aero_data%source_name)
216 aero_data%source_name => new_source_name
217 aero_data%n_source = aero_data%n_source + 1
233 do i = 1,aero_data%n_spec
234 if (aero_data%name(i) ==
"H2O")
then
235 aero_data%i_water = i
249 integer,
parameter :: n_mosaic_spec = 19
250 character(AERO_NAME_LEN),
parameter,
dimension(n_mosaic_spec) :: &
251 mosaic_spec_name = [ &
252 "SO4 ",
"NO3 ",
"Cl ",
"NH4 ",
"MSA ",
"ARO1 ", &
253 "ARO2 ",
"ALK1 ",
"OLE1 ",
"API1 ",
"API2 ",
"LIM1 ", &
254 "LIM2 ",
"CO3 ",
"Na ",
"Ca ",
"OIN ",
"OC ", &
257 integer :: i_spec, i_mosaic_spec, i
259 aero_data%mosaic_index = 0
260 do i_spec = 1,aero_data%n_spec
262 do i = 1,n_mosaic_spec
263 if (aero_data%name(i_spec) == mosaic_spec_name(i))
then
267 if (i_mosaic_spec > 0)
then
268 aero_data%mosaic_index(i_spec) = i_mosaic_spec
277 subroutine spec_file_read_aero_data(file, aero_data)
284 integer :: n_species, species, i
285 character(len=SPEC_LINE_MAX_VAR_LEN),
pointer :: species_name(:)
286 real(kind=dp),
pointer :: species_data(:,:)
322 allocate(species_name(0))
323 allocate(species_data(0,0))
327 n_species =
size(species_data, 1)
328 if (.not. ((
size(species_data, 2) == 4) .or. (n_species == 0)))
then
329 call
die_msg(428926381,
'each line in ' // trim(file%name) &
330 //
' should contain exactly 5 values')
337 aero_data%name(i) = species_name(i)(1:aero_name_len)
338 aero_data%density(i) = species_data(i,1)
339 aero_data%num_ions(i) = nint(species_data(i,2))
340 aero_data%molec_weight(i) = species_data(i,3)
341 aero_data%kappa(i) = species_data(i,4)
343 (aero_data%num_ions(i) == 0) .or. (aero_data%kappa(i) == 0d0), &
344 "ions and kappa both non-zero for species " &
345 // trim(aero_data%name(i)) //
" in " // trim(file%name))
346 if (species_name(i) ==
"H2O")
then
347 aero_data%i_water = i
349 aero_data%density(i) == const%water_density, &
350 "input H2O density not equal to const%water_density (" &
354 aero_data%molec_weight(i) == const%water_molec_weight, &
355 "input H2O molec_weight not equal " &
356 //
"to const%water_molec_weight (" &
361 deallocate(species_name)
362 deallocate(species_data)
366 end subroutine spec_file_read_aero_data
376 character(len=*),
intent(in) :: name
380 integer,
pointer :: species_list(:)
382 type(spec_line_t
) :: line
387 allocate(species_list(
size(line%data)))
388 do i = 1,
size(line%data)
392 'unknown species: ' // trim(line%data(i)))
394 species_list(i) = spec
428 character,
intent(inout) :: buffer(:)
430 integer,
intent(inout) :: position
435 integer :: prev_position
437 prev_position = position
460 character,
intent(inout) :: buffer(:)
462 integer,
intent(inout) :: position
467 integer :: prev_position
469 prev_position = position
497 integer,
intent(in) :: ncid
499 integer,
intent(out) :: dimid_aero_species
501 integer :: status, i_spec
502 integer :: varid_aero_species
503 integer :: aero_species_centers(aero_data%n_spec)
504 character(len=(AERO_NAME_LEN * aero_data%n_spec)) :: aero_species_names
507 status = nf90_inq_dimid(ncid,
"aero_species", dimid_aero_species)
508 if (status == nf90_noerr)
return
515 aero_data%n_spec, dimid_aero_species))
516 aero_species_names =
""
517 do i_spec = 1,aero_data%n_spec
518 aero_species_names((len_trim(aero_species_names) + 1):) &
519 = trim(aero_data%name(i_spec))
520 if (i_spec < aero_data%n_spec)
then
521 aero_species_names((len_trim(aero_species_names) + 1):) =
","
524 call
pmc_nc_check(nf90_def_var(ncid,
"aero_species", nf90_int, &
525 dimid_aero_species, varid_aero_species))
526 call
pmc_nc_check(nf90_put_att(ncid, varid_aero_species,
"names", &
528 call
pmc_nc_check(nf90_put_att(ncid, varid_aero_species,
"description", &
529 "dummy dimension variable (no useful value) - read species names " &
530 //
"as comma-separated values from the 'names' attribute"))
534 do i_spec = 1,aero_data%n_spec
535 aero_species_centers(i_spec) = i_spec
537 call
pmc_nc_check(nf90_put_var(ncid, varid_aero_species, &
538 aero_species_centers))
553 integer,
intent(in) :: ncid
555 integer,
intent(out) :: dimid_aero_source
557 integer :: status, i_source
558 integer :: varid_aero_source
559 integer :: aero_source_centers(aero_data%n_source)
560 character(len=(AERO_SOURCE_NAME_LEN * aero_data%n_source)) &
564 status = nf90_inq_dimid(ncid,
"aero_source", dimid_aero_source)
565 if (status == nf90_noerr)
return
572 aero_data%n_source, dimid_aero_source))
573 aero_source_names =
""
574 do i_source = 1,aero_data%n_source
575 aero_source_names((len_trim(aero_source_names) + 1):) &
576 = trim(aero_data%source_name(i_source))
577 if (i_source < aero_data%n_source)
then
578 aero_source_names((len_trim(aero_source_names) + 1):) =
","
581 call
pmc_nc_check(nf90_def_var(ncid,
"aero_source", nf90_int, &
582 dimid_aero_source, varid_aero_source))
583 call
pmc_nc_check(nf90_put_att(ncid, varid_aero_source,
"names", &
585 call
pmc_nc_check(nf90_put_att(ncid, varid_aero_source,
"description", &
586 "dummy dimension variable (no useful value) - read source names " &
587 //
"as comma-separated values from the 'names' attribute"))
591 do i_source = 1,aero_data%n_source
592 aero_source_centers(i_source) = i_source
594 call
pmc_nc_check(nf90_put_var(ncid, varid_aero_source, &
595 aero_source_centers))
602 subroutine aero_data_output_netcdf(aero_data, ncid)
607 integer,
intent(in) :: ncid
609 integer :: dimid_aero_species, dimid_aero_source
644 "aero_mosaic_index", (/ dimid_aero_species /), &
645 long_name=
"MOSAIC indices of aerosol species")
647 "aero_density", (/ dimid_aero_species /), unit=
"kg/m^3", &
648 long_name=
"densities of aerosol species")
650 "aero_num_ions", (/ dimid_aero_species /), &
651 long_name=
"number of ions after dissociation of aerosol species")
653 "aero_molec_weight", (/ dimid_aero_species /), unit=
"kg/mol", &
654 long_name=
"molecular weights of aerosol species")
656 "aero_kappa", (/ dimid_aero_species /), unit=
"1", &
657 long_name=
"hygroscopicity parameters (kappas) of aerosol species")
659 end subroutine aero_data_output_netcdf
669 integer,
intent(in) :: ncid
671 character(len=1000) :: name
672 integer :: dimid_aero_species, n_spec, varid_aero_species, i_spec, i
673 integer :: dimid_aero_source, n_source, varid_aero_source, i_source
674 character(len=((AERO_NAME_LEN + 2) * 1000)) :: aero_species_names
675 character(len=((AERO_SOURCE_NAME_LEN + 2) * 1000)) :: aero_source_names
677 call
pmc_nc_check(nf90_inq_dimid(ncid,
"aero_species", &
680 dimid_aero_species, name, n_spec))
681 call
assert(141013948, n_spec < 1000)
686 dimid_aero_source, name, n_source))
687 call
assert(739238793, n_source < 1000)
703 call
pmc_nc_check(nf90_inq_varid(ncid,
"aero_species", &
705 call
pmc_nc_check(nf90_get_att(ncid, varid_aero_species,
"names", &
708 do i_spec = 1,aero_data%n_spec
710 do while ((aero_species_names(i:i) /=
" ") &
711 .and. (aero_species_names(i:i) /=
","))
714 call
assert(852937292, i > 1)
715 aero_data%name(i_spec) = aero_species_names(1:(i-1))
716 aero_species_names = aero_species_names((i+1):)
718 call
assert(729138192, aero_species_names ==
"")
722 call
pmc_nc_check(nf90_get_att(ncid, varid_aero_source,
"names", &
725 do i_source = 1,aero_data%n_source
727 do while ((aero_source_names(i:i) /=
" ") &
728 .and. (aero_source_names(i:i) /=
","))
731 call
assert(840982478, i > 1)
732 aero_data%source_name(i_source) = aero_source_names(1:(i-1))
733 aero_source_names = aero_source_names((i+1):)
735 call
assert(377166446, aero_source_names ==
"")
subroutine aero_data_set_mosaic_map(aero_data)
Fills in aero_data%mosaic_index.
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.
integer function pmc_mpi_pack_size_real_array(val)
Determines the number of bytes required to pack the given value.
An input file with extra data for printing messages.
subroutine spec_file_check_line_name(file, line, name)
Check that the name of the line data is as given.
The aero_data_t structure and associated subroutines.
integer function pmc_mpi_pack_size_integer(val)
Determines the number of bytes required to pack the given value.
subroutine die_msg(code, error_msg)
Error immediately.
subroutine aero_data_set_water_index(aero_data)
Fills in aero_data%i_water.
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_aero_data(buffer, position, val)
Packs the given value into the buffer, advancing position.
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_aero_data(val)
Determines the number of bytes required to pack the given value.
subroutine pmc_nc_check(status)
Check the status of a NetCDF function call.
subroutine aero_data_allocate_size(aero_data, n_spec, n_source)
Allocate storage for aero_data parameters given the number of species.
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
subroutine pmc_mpi_pack_string_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine pmc_nc_read_integer_1d(ncid, var, name, must_be_present)
Read a simple integer array from a NetCDF file.
subroutine pmc_mpi_unpack_aero_data(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
subroutine pmc_mpi_pack_integer(buffer, position, val)
Packs the given value into the buffer, advancing position.
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.
subroutine warn_assert_msg(code, condition_ok, warning_msg)
Prints a warning message if condition_ok is false.
subroutine aero_data_deallocate(aero_data)
Frees all storage.
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...
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...
Common utility subroutines.
subroutine pmc_mpi_unpack_real_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
subroutine pmc_nc_read_real_1d(ncid, var, name, must_be_present)
Read a simple real array from a NetCDF file.
subroutine pmc_mpi_unpack_integer(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Wrapper functions for MPI.
subroutine pmc_mpi_unpack_integer_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
integer function pmc_mpi_pack_size_string_array(val)
Determines the number of bytes required to pack the given value.
Reading formatted text input.
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 spec_file_die_msg(code, file, msg)
Exit with an error message containing filename and line number.
subroutine aero_data_copy(aero_data_from, aero_data_to)
Copy structure.
subroutine pmc_mpi_unpack_string_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
subroutine aero_data_input_netcdf(aero_data, ncid)
Read full state.
integer function pmc_mpi_pack_size_integer_array(val)
Determines the number of bytes required to pack the given value.
subroutine pmc_mpi_pack_real_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine spec_line_deallocate(spec_line)
Frees all storage.
subroutine aero_data_allocate(aero_data)
Allocate storage for aero_data.
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 ...
character(len=pmc_util_convert_string_len) function real_to_string(val)
Convert a real to a string format.
Aerosol material properties and associated data.
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
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 pmc_mpi_pack_integer_array(buffer, position, val)
Packs the given value into the buffer, advancing position.