54 logical :: coag_kernel_bounds_valid
56 real(kind=dp),
allocatable,
dimension(:,:) :: coag_kernel_min
58 real(kind=dp),
allocatable,
dimension(:,:) :: coag_kernel_max
60 logical :: removal_rate_bounds_valid
62 real(kind=dp),
allocatable,
dimension(:) :: removal_rate_max
66 real(kind=dp),
parameter :: AERO_SORTED_BINS_PER_DECADE = 10d0
68 real(kind=dp),
parameter :: AERO_SORTED_BIN_OVER_FACTOR = 10d0
70 real(kind=dp),
parameter :: AERO_SORTED_BIN_SAFETY_FACTOR = 3d0
85 aero_sorted%coag_kernel_bounds_valid = .false.
86 allocate(aero_sorted%coag_kernel_min(0, 0))
87 allocate(aero_sorted%coag_kernel_max(0, 0))
88 aero_sorted%removal_rate_bounds_valid = .false.
89 allocate(aero_sorted%removal_rate_max(0))
101 integer,
intent(in) :: n_bin
103 integer,
intent(in) :: n_group
105 integer,
intent(in) :: n_class
110 aero_sorted%coag_kernel_bounds_valid = .false.
111 allocate(aero_sorted%coag_kernel_min(n_bin, n_bin))
112 allocate(aero_sorted%coag_kernel_max(n_bin, n_bin))
113 aero_sorted%removal_rate_bounds_valid = .false.
114 allocate(aero_sorted%removal_rate_max(n_bin))
129 aero_sorted%coag_kernel_bounds_valid = .false.
130 deallocate(aero_sorted%coag_kernel_min)
131 deallocate(aero_sorted%coag_kernel_max)
132 aero_sorted%removal_rate_bounds_valid = .false.
133 deallocate(aero_sorted%removal_rate_max)
147 aero_sorted%coag_kernel_bounds_valid = .false.
148 aero_sorted%coag_kernel_min = 0d0
149 aero_sorted%coag_kernel_max = 0d0
150 aero_sorted%removal_rate_bounds_valid = .false.
151 aero_sorted%removal_rate_max = 0d0
201 integer,
intent(in) :: n_group
203 integer,
intent(in) :: n_class
223 integer :: i_part, i_bin
227 do i_part = aero_particle_array%n_part,1,-1
229 aero_particle_array%particle(i_part))
230 if ((i_bin < 1) .or. (i_bin > aero_sorted%bin_grid%n_bin))
then
231 call
warn_msg(954800836,
"particle ID " &
233 aero_particle_array%particle(i_part)%id)) &
234 //
" outside of bin_grid, discarding")
252 integer :: i_part, i_bin, i_group, i_class
257 do i_part = 1,aero_particle_array%n_part
259 aero_particle_array%particle(i_part))
260 i_group = aero_particle_array%particle(i_part)%weight_group
261 i_class = aero_particle_array%particle(i_part)%weight_class
272 valid_sort, n_group, n_class, bin_grid, all_procs_same)
279 logical,
intent(in) :: valid_sort
281 integer,
optional,
intent(in) :: n_group
283 integer,
optional,
intent(in) :: n_class
285 type(bin_grid_t),
optional,
intent(in) :: bin_grid
287 logical,
optional,
intent(in) :: all_procs_same
289 integer :: i_bin, i_bin_min, i_bin_max, i_part, n_bin, use_n_group
290 integer :: use_n_class
291 real(kind=dp) :: r, r_min, r_max, grid_r_min, grid_r_max
292 real(kind=dp) :: local_r_min, local_r_max
293 logical :: need_new_bin_grid
296 if (present(n_group))
then
297 call
assert(267881270, present(n_class))
298 use_n_group = n_group
299 use_n_class = n_class
301 call
assert(352582858, valid_sort)
306 if (present(bin_grid))
then
314 need_new_bin_grid = .false.
323 do i_bin = 1,aero_sorted%bin_grid%n_bin
324 if (sum(aero_sorted%size_class%inverse(i_bin, :)%n_entry) > 0)
then
325 if (i_bin_min == 0)
then
332 if (i_bin_min == 0)
then
334 call
assert(333430891, i_bin_max == 0)
335 if (aero_sorted%bin_grid%n_bin > 0)
then
337 r_min = aero_sorted%bin_grid%edges(aero_sorted%bin_grid%n_bin + 1)
338 r_max = aero_sorted%bin_grid%edges(1)
341 r_min = aero_sorted%bin_grid%edges(i_bin_min)
342 r_max = aero_sorted%bin_grid%edges(i_bin_max + 1)
346 do i_part = 1,aero_particle_array%n_part
348 if (i_part == 1)
then
352 r_min = min(r_min, r)
353 r_max = max(r_max, r)
358 if (present(all_procs_same))
then
359 if (all_procs_same)
then
364 if (r_min == 0d0)
then
373 need_new_bin_grid = .true.
379 if (r_max == 0d0)
then
380 if (valid_sort)
return
382 call
bin_grid_make(new_bin_grid, bin_grid_type_log, n_bin=0, min=0d0, &
390 if (aero_sorted%bin_grid%n_bin < 1)
then
391 need_new_bin_grid = .true.
393 grid_r_min = aero_sorted%bin_grid%edges(1)
394 grid_r_max = aero_sorted%bin_grid%edges(aero_sorted%bin_grid%n_bin + 1)
399 if ((r_min / grid_r_min < aero_sorted_bin_safety_factor) &
400 .or. (grid_r_max / r_max < aero_sorted_bin_safety_factor))
then
401 need_new_bin_grid = .true.
405 if (need_new_bin_grid)
then
406 grid_r_min = r_min / aero_sorted_bin_over_factor
407 grid_r_max = r_max * aero_sorted_bin_over_factor
408 n_bin = ceiling((log10(grid_r_max) - log10(grid_r_min)) &
409 * aero_sorted_bins_per_decade)
411 call
bin_grid_make(new_bin_grid, bin_grid_type_log, n_bin, grid_r_min, &
418 if (.not. valid_sort)
then
445 aero_particle, allow_resort)
454 logical,
optional,
intent(in) :: allow_resort
456 integer :: i_bin, i_group, i_class, n_bin, n_group, n_class
459 i_group = aero_particle%weight_group
460 i_class = aero_particle%weight_class
462 n_bin = aero_sorted%bin_grid%n_bin
465 call
assert(417177855, (i_group >= 1) .and. (i_group <= n_group))
466 call
assert(233133947, (i_class >= 1) .and. (i_class <= n_class))
471 if ((i_bin < 1) .or. (i_bin > n_bin))
then
474 if (present(allow_resort))
then
475 if (.not. allow_resort)
then
479 call
die_msg(134572570,
"particle outside of bin_grid: " &
480 //
"try reducing the timestep del_t")
484 valid_sort=.false., n_group=n_group, n_class=n_class)
505 integer,
intent(in) :: i_part
518 new_group, new_class)
523 integer,
intent(in) :: i_part
525 integer,
intent(in) :: new_bin
527 integer,
intent(in) :: new_group
529 integer,
intent(in) :: new_class
542 n_group, n_class, continue_on_error)
549 integer,
optional,
intent(in) :: n_group
551 integer,
optional,
intent(in) :: n_class
553 logical,
intent(in) :: continue_on_error
555 integer :: i_part, i_bin
558 n_domain=aero_particle_array%n_part, &
559 n_range_1=aero_sorted%bin_grid%n_bin, n_range_2=n_class, &
560 continue_on_error=continue_on_error)
561 do i_part = 1,aero_particle_array%n_part
563 aero_particle_array%particle(i_part))
564 if ((i_bin /= aero_sorted%size_class%forward1%entry(i_part)) &
565 .or. (i_bin /= aero_sorted%size_class%forward1%entry(i_part)))
then
566 write(0,*)
'ERROR aero_sorted A: ',
"size_class"
567 write(0,*)
'i_part', i_part
568 write(0,*)
'i_bin', i_bin
569 write(0,*)
'aero_sorted%size_class%forward1%entry(i_part)', &
570 aero_sorted%size_class%forward1%entry(i_part)
571 write(0,*)
'aero_sorted%size_class%forward2%entry(i_part)', &
572 aero_sorted%size_class%forward2%entry(i_part)
573 call
assert(565030916, continue_on_error)
578 n_domain=aero_particle_array%n_part, &
579 n_range_1=n_group, n_range_2=n_class, &
580 continue_on_error=continue_on_error)
581 do i_part = 1,aero_particle_array%n_part
582 if ((aero_particle_array%particle(i_part)%weight_group &
583 /= aero_sorted%group_class%forward1%entry(i_part)) &
584 .or. (aero_particle_array%particle(i_part)%weight_class &
585 /= aero_sorted%group_class%forward2%entry(i_part)))
then
586 write(0,*)
'ERROR aero_sorted B: ',
"group_class"
587 write(0,*)
'i_part', i_part
588 write(0,*)
'aero_particle_array%particle(i_part)%weight_group', &
589 aero_particle_array%particle(i_part)%weight_group
590 write(0,*)
'aero_particle_array%particle(i_part)%weight_class', &
591 aero_particle_array%particle(i_part)%weight_class
592 write(0,*)
'aero_sorted%group_class%forward1%entry(i_part)', &
593 aero_sorted%group_class%forward1%entry(i_part)
594 write(0,*)
'aero_sorted%group_class%forward2%entry(i_part)', &
595 aero_sorted%group_class%forward2%entry(i_part)
596 call
assert(803595412, continue_on_error)
610 integer :: total_size
614 total_size = total_size &
616 total_size = total_size &
631 character,
intent(inout) :: buffer(:)
633 integer,
intent(inout) :: position
638 integer :: prev_position
640 prev_position = position
659 character,
intent(inout) :: buffer(:)
661 integer,
intent(inout) :: position
666 integer :: prev_position, n_bin, n_group, n_class
668 prev_position = position
The aero_sorted_t structure and assocated subroutines.
elemental subroutine integer_rmap2_allocate(integer_rmap2)
Allocates an empty structure.
integer function pmc_mpi_pack_size_integer_rmap2(val)
Determines the number of bytes required to pack the given value.
subroutine pmc_mpi_pack_integer_rmap2(buffer, position, val)
Packs the given value into the buffer, advancing position.
elemental subroutine integer_rmap2_allocate_size(integer_rmap2, n_range_1, n_range_2)
Allocates a structure with the given size.
elemental subroutine integer_rmap2_deallocate(integer_rmap2)
Deallocates a previously allocated structure.
subroutine aero_sorted_add_particle(aero_sorted, aero_particle_array, aero_particle, allow_resort)
Add a new particle to both an aero_sorted and the corresponding aero_particle_array.
integer function pmc_mpi_pack_size_integer(val)
Determines the number of bytes required to pack the given value.
subroutine integer_rmap2_append(integer_rmap2, i_range_1, i_range_2)
Set the map value of the next free domain value to (i_range_1, i_range_2.
subroutine die_msg(code, error_msg)
Error immediately.
1-D arrays of particles, used by aero_state to build a ragged array.
subroutine integer_rmap2_check(integer_rmap2, name, n_domain, n_range_1, n_range_2, continue_on_error)
Check that the data is consistent.
subroutine pmc_mpi_allreduce_min_real(val, val_min)
Computes the minimum of val across all processes, storing the result in val_min on all processes...
subroutine pmc_mpi_unpack_integer_rmap2(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
subroutine aero_sorted_allocate_size(aero_sorted, n_bin, n_group, n_class)
Allocate a strcture with the given size.
The aero_particle_t structure and associated subroutines.
The integer_varray_t structure and assocated subroutines.
subroutine bin_grid_make(bin_grid, type, n_bin, min, max)
Generates the bin grid given the range and number of bins.
subroutine integer_rmap2_change(integer_rmap2, i_domain, i_range_1, i_range_2)
Change the map value of i_domain to (i_range_1, i_range_2).
integer function bin_grid_find(bin_grid, val)
Find the bin number that contains a given value.
integer function pmc_mpi_pack_size_aero_sorted(val)
Determines the number of bytes required to pack the given value.
elemental real(kind=dp) function aero_particle_radius(aero_particle)
Total radius of the particle (m).
subroutine aero_sorted_remake_if_needed(aero_sorted, aero_particle_array, valid_sort, n_group, n_class, bin_grid, all_procs_same)
Remake a sorting if particles are getting too close to the edges.
subroutine pmc_mpi_unpack_aero_sorted(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
The aero_particle_array_t structure and assoicated subroutines.
subroutine bin_grid_allocate(bin_grid)
Allocates a bin_grid.
subroutine pmc_mpi_pack_integer(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine aero_sorted_check(aero_sorted, aero_particle_array, n_group, n_class, continue_on_error)
Check sorting.
subroutine aero_particle_array_add_particle(aero_particle_array, aero_particle)
Adds the given particle to the end of the array.
integer function aero_sorted_n_bin(aero_sorted)
Returns the number of size bins.
integer function pmc_mpi_pack_size_bin_grid(val)
Determines the number of bytes required to pack the given value.
subroutine pmc_mpi_unpack_integer(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
logical function pmc_mpi_allequal_bin_grid(val)
Check whether all processors have the same value.
subroutine aero_sorted_sort_particles(aero_sorted, aero_particle_array)
Sort the particles.
A map , together with its multi-valued inverse.
Wrapper functions for MPI.
elemental subroutine integer_rmap2_zero(integer_rmap2)
Resets an integer_rmap2 to have zero particles per bin.
integer function aero_sorted_n_class(aero_sorted)
Returns the number of weight classes.
subroutine aero_sorted_move_particle(aero_sorted, i_part, new_bin, new_group, new_class)
Move a particle to a different bin and group.
subroutine aero_sorted_discard_outside_grid(aero_sorted, aero_particle_array)
Discard particles that don't fit the bin grid.
subroutine pmc_mpi_pack_aero_sorted(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine aero_sorted_set_bin_grid(aero_sorted, bin_grid, n_group, n_class)
Do a sorting of a set of aerosol particles.
subroutine pmc_mpi_allreduce_max_real(val, val_max)
Computes the maximum of val across all processes, storing the result in val_max on all processes...
character(len=pmc_util_convert_string_len) function integer_to_string(val)
Convert an integer to a string format.
subroutine aero_sorted_zero(aero_sorted)
Resets an aero_sorted to have zero particles per bin.
Single aerosol particle data structure.
1D grid, either logarithmic or linear.
The bin_grid_t structure and associated subroutines.
integer function aero_sorted_n_group(aero_sorted)
Returns the number of weight groups.
subroutine warn_msg(code, warning_msg, already_warned)
Prints a warning message.
The integer_rmap_t structure and assocated subroutines.
Sorting of particles into bins.
subroutine aero_particle_array_remove_particle(aero_particle_array, index)
Removes the particle at the given index.
The integer_rmap2_t structure and assocated subroutines.
subroutine integer_rmap2_remove(integer_rmap2, i_domain)
Replace the map at the given i_domain with the map value of the last entry, and delete the last entry...
subroutine pmc_mpi_unpack_bin_grid(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
subroutine bin_grid_copy(bin_grid_from, bin_grid_to)
Copies a bin grid.
subroutine aero_sorted_allocate(aero_sorted)
Allocate an empty structure.
subroutine pmc_mpi_pack_bin_grid(buffer, position, val)
Packs the given value into the buffer, advancing position.
subroutine bin_grid_deallocate(bin_grid)
Frees all memory.
integer function aero_sorted_particle_in_bin(aero_sorted, aero_particle)
Find the bin number that contains a given particle.
subroutine aero_sorted_deallocate(aero_sorted)
Deallocates a previously allocated structure.
subroutine aero_sorted_remove_particle(aero_sorted, aero_particle_array, i_part)
Remove a particle from both an aero_sorted and the corresponding aero_particle_array.