PartMC  2.6.1
aero_particle_array.F90
Go to the documentation of this file.
1 ! Copyright (C) 2005-2012 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_aero_particle_array module.
7 
8 !> The aero_particle_array_t structure and assoicated subroutines.
10 
12  use pmc_util
13  use pmc_spec_file
14  use pmc_mpi
15 #ifdef PMC_USE_MPI
16  use mpi
17 #endif
18 
19  !> 1-D array of particles, used by aero_state to store the
20  !> particles.
21  !!
22  !! To give a reasonable tradeoff between frequent re-allocs and
23  !! memory usage, the length of an aero_particle_array is generally a
24  !! bit longer than the number of particles stored in it. When the
25  !! array is full then a larger array is allocated with new extra
26  !! space. As a balance between memory usage and frequency of
27  !! re-allocs the length of the array is currently doubled when
28  !! necessary and halved when possible.
29  !!
30  !! The true allocated length of the aero_particle_array can be
31  !! obtained by size(aero_particle_array%%particle), while the number
32  !! of used particle slots in it is given by
33  !! aero_particle_array%%n_part. It must be that
34  !! aero_particle_array%%n_part is less than or equal to
35  !! size(aero_particle_array%%particle). In user code, the \c
36  !! aero_particle_array_n_part() getter function should be used.q
37  !!
38  !! For internal usage, if \c particle is not allocated then \c
39  !! n_part is invalid. If \c particle is allocated then \c n_part
40  !! must be valid.
42  !> Number of particles.
43  integer :: n_part
44  !> Particle array.
45  type(aero_particle_t), allocatable :: particle(:)
46  end type aero_particle_array_t
47 
48 contains
49 
50 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
51 
52  !> Return the current number of particles.
53  elemental integer function aero_particle_array_n_part(aero_particle_array)
54 
55  !> Aerosol particle array.
56  type(aero_particle_array_t), intent(in) :: aero_particle_array
57 
58  if (allocated(aero_particle_array%particle)) then
59  aero_particle_array_n_part = aero_particle_array%n_part
60  else
62  end if
63 
64  end function aero_particle_array_n_part
65 
66 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
67 
68  !> Resets an aero_particle_array to contain zero particles.
69  subroutine aero_particle_array_zero(aero_particle_array)
70 
71  !> Structure to reset.
72  type(aero_particle_array_t), intent(inout) :: aero_particle_array
73 
74  aero_particle_array%n_part = 0
75  if (allocated(aero_particle_array%particle)) then
76  deallocate(aero_particle_array%particle)
77  end if
78 
79  end subroutine aero_particle_array_zero
80 
81 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
82 
83  !> Changes the given aero_particle_array to exactly the given
84  !> new_length.
85  !!
86  !! This function should not be called directly, but rather use
87  !! aero_particle_array_enlarge() or aero_particle_array_shrink().
88  subroutine aero_particle_array_realloc(aero_particle_array, new_length)
89 
90  !> Array to reallocate.
91  type(aero_particle_array_t), intent(inout) :: aero_particle_array
92  !> New length of the array.
93  integer, intent(in) :: new_length
94 
95  integer :: i
96  type(aero_particle_t), allocatable :: new_particles(:)
97 
98  if (.not. allocated(aero_particle_array%particle)) then
99  allocate(aero_particle_array%particle(new_length))
100  aero_particle_array%n_part = 0
101  return
102  end if
103 
104  call assert(867444847, new_length >= aero_particle_array%n_part)
105  allocate(new_particles(new_length))
106  do i = 1,aero_particle_array%n_part
107  call aero_particle_shift(aero_particle_array%particle(i), &
108  new_particles(i))
109  end do
110  call move_alloc(new_particles, aero_particle_array%particle)
111 
112  end subroutine aero_particle_array_realloc
113 
114 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
115 
116  !> Possibly enlarges the given array, ensuring that it is at least of size n.
117  subroutine aero_particle_array_enlarge(aero_particle_array, n)
118 
119  !> Array to enlarge.
120  type(aero_particle_array_t), intent(inout) :: aero_particle_array
121  !> Minimum new size of array.
122  integer, intent(in) :: n
123 
124  if (.not. allocated(aero_particle_array%particle)) then
125  call aero_particle_array_realloc(aero_particle_array, pow2_above(n))
126  return
127  end if
128 
129  if (n <= size(aero_particle_array%particle)) return
130 
131  call aero_particle_array_realloc(aero_particle_array, pow2_above(n))
132 
133  end subroutine aero_particle_array_enlarge
134 
135 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
136 
137  !> Possibly shrinks the storage of the given array, ensuring that
138  !> it can still store the allocated particles.
139  subroutine aero_particle_array_shrink(aero_particle_array)
140 
141  !> Array to shrink.
142  type(aero_particle_array_t), intent(inout) :: aero_particle_array
143 
144  integer :: new_length
145 
146  if (.not. allocated(aero_particle_array%particle)) return
147 
148  new_length = pow2_above(aero_particle_array%n_part)
149  if (new_length < size(aero_particle_array%particle)) then
150  call aero_particle_array_realloc(aero_particle_array, new_length)
151  end if
152 
153  end subroutine aero_particle_array_shrink
154 
155 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
156 
157  !> Adds the given particle to the end of the array.
158  subroutine aero_particle_array_add_particle(aero_particle_array, &
159  aero_particle)
160 
161  !> Array to add to.
162  type(aero_particle_array_t), intent(inout) :: aero_particle_array
163  !> Particle to add.
164  type(aero_particle_t), intent(in) :: aero_particle
165 
166  integer :: n
167 
168  n = aero_particle_array_n_part(aero_particle_array) + 1
169  call aero_particle_array_enlarge(aero_particle_array, n)
170  aero_particle_array%particle(n) = aero_particle
171  aero_particle_array%n_part = n
172 
173  end subroutine aero_particle_array_add_particle
174 
175 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
176 
177  !> Removes the particle at the given index.
178  subroutine aero_particle_array_remove_particle(aero_particle_array, &
179  index)
180 
181  !> Array to remove from.
182  type(aero_particle_array_t), intent(inout) :: aero_particle_array
183  !> Index of particle to remove.
184  integer, intent(in) :: index
185 
186  call assert(883639923, allocated(aero_particle_array%particle))
187  call assert(992946227, index >= 1)
188  call assert(711246139, index <= aero_particle_array%n_part)
189  if (index < aero_particle_array%n_part) then
190  ! shift last particle into empty slot to preserve dense packing
191  call aero_particle_shift( &
192  aero_particle_array%particle(aero_particle_array%n_part), &
193  aero_particle_array%particle(index))
194  end if
195  aero_particle_array%n_part = aero_particle_array%n_part - 1
196  call aero_particle_array_shrink(aero_particle_array)
197 
199 
200 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
201 
202  !> Determines the number of bytes required to pack the given value.
203  integer function pmc_mpi_pack_size_apa(val)
204 
205  !> Value to pack.
206  type(aero_particle_array_t), intent(in) :: val
207 
208  integer :: i, total_size
209 
210  total_size = 0
211  total_size = total_size &
213  do i = 1,aero_particle_array_n_part(val)
214  total_size = total_size &
215  + pmc_mpi_pack_size_aero_particle(val%particle(i))
216  end do
217  pmc_mpi_pack_size_apa = total_size
218 
219  end function pmc_mpi_pack_size_apa
220 
221 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
222 
223  !> Packs the given value into the buffer, advancing position.
224  subroutine pmc_mpi_pack_aero_particle_array(buffer, position, val)
225 
226  !> Memory buffer.
227  character, intent(inout) :: buffer(:)
228  !> Current buffer position.
229  integer, intent(inout) :: position
230  !> Value to pack.
231  type(aero_particle_array_t), intent(in) :: val
232 
233 #ifdef PMC_USE_MPI
234  integer :: prev_position, i
235 
236  prev_position = position
237  call pmc_mpi_pack_integer(buffer, position, &
239  do i = 1,aero_particle_array_n_part(val)
240  call pmc_mpi_pack_aero_particle(buffer, position, val%particle(i))
241  end do
242  call assert(803856329, &
243  position - prev_position <= pmc_mpi_pack_size_apa(val))
244 #endif
245 
246  end subroutine pmc_mpi_pack_aero_particle_array
247 
248 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
249 
250  !> Unpacks the given value from the buffer, advancing position.
251  subroutine pmc_mpi_unpack_aero_particle_array(buffer, position, val)
252 
253  !> Memory buffer.
254  character, intent(inout) :: buffer(:)
255  !> Current buffer position.
256  integer, intent(inout) :: position
257  !> Value to pack.
258  type(aero_particle_array_t), intent(inout) :: val
259 
260 #ifdef PMC_USE_MPI
261  integer :: prev_position, i, n
262 
263  prev_position = position
264  call pmc_mpi_unpack_integer(buffer, position, n)
265  call aero_particle_array_realloc(val, n)
266  val%n_part = n
267  do i = 1,n
268  call pmc_mpi_unpack_aero_particle(buffer, position, val%particle(i))
269  end do
270  call assert(138783294, &
271  position - prev_position <= pmc_mpi_pack_size_apa(val))
272 #endif
273 
275 
276 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
277 
278  !> Check that the particle array data is consistent.
279  subroutine aero_particle_array_check(aero_particle_array, aero_data, &
280  continue_on_error)
281 
282  !> Aerosol particle array to check.
283  type(aero_particle_array_t), intent(in) :: aero_particle_array
284  !> Aerosol data.
285  type(aero_data_t), intent(in) :: aero_data
286  !> Whether to continue despite error.
287  logical, intent(in) :: continue_on_error
288 
289  integer :: i_part
290 
291  if (.not. allocated(aero_particle_array%particle)) return
292 
293  if (aero_particle_array%n_part < 0) then
294  write(0, *) 'ERROR aero_particle_array A:'
295  write(0, *) 'aero_particle_array%n_part', aero_particle_array%n_part
296  call assert(250011397, continue_on_error)
297  end if
298 
299  do i_part = 1,aero_particle_array%n_part
300  call aero_particle_check(aero_particle_array%particle(i_part), &
301  aero_data, continue_on_error)
302  end do
303 
304  end subroutine aero_particle_array_check
305 
306 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
307 
308 end module pmc_aero_particle_array
pmc_aero_particle::aero_particle_t
Single aerosol particle data structure.
Definition: aero_particle.F90:26
pmc_aero_particle_array::aero_particle_array_t
1-D array of particles, used by aero_state to store the particles.
Definition: aero_particle_array.F90:41
pmc_mpi
Wrapper functions for MPI.
Definition: mpi.F90:13
pmc_aero_particle_array::pmc_mpi_pack_aero_particle_array
subroutine pmc_mpi_pack_aero_particle_array(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: aero_particle_array.F90:225
pmc_aero_particle
The aero_particle_t structure and associated subroutines.
Definition: aero_particle.F90:9
pmc_aero_particle_array::aero_particle_array_enlarge
subroutine aero_particle_array_enlarge(aero_particle_array, n)
Possibly enlarges the given array, ensuring that it is at least of size n.
Definition: aero_particle_array.F90:118
pmc_aero_particle_array::pmc_mpi_pack_size_apa
integer function pmc_mpi_pack_size_apa(val)
Determines the number of bytes required to pack the given value.
Definition: aero_particle_array.F90:204
pmc_spec_file
Reading formatted text input.
Definition: spec_file.F90:43
pmc_util::pow2_above
integer function pow2_above(n)
Return the least power-of-2 that is at least equal to n.
Definition: util.F90:1642
pmc_util::assert
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
Definition: util.F90:103
pmc_aero_particle_array::aero_particle_array_add_particle
subroutine aero_particle_array_add_particle(aero_particle_array, aero_particle)
Adds the given particle to the end of the array.
Definition: aero_particle_array.F90:160
pmc_aero_particle::aero_particle_shift
subroutine aero_particle_shift(aero_particle_from, aero_particle_to)
Shift data from one aero_particle_t to another and free the first one.
Definition: aero_particle.F90:68
pmc_aero_particle_array::aero_particle_array_n_part
elemental integer function aero_particle_array_n_part(aero_particle_array)
Return the current number of particles.
Definition: aero_particle_array.F90:54
pmc_aero_particle_array::aero_particle_array_realloc
subroutine aero_particle_array_realloc(aero_particle_array, new_length)
Changes the given aero_particle_array to exactly the given new_length.
Definition: aero_particle_array.F90:89
pmc_aero_particle::pmc_mpi_unpack_aero_particle
subroutine pmc_mpi_unpack_aero_particle(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: aero_particle.F90:956
pmc_aero_data::aero_data_t
Aerosol material properties and associated data.
Definition: aero_data.F90:49
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:818
pmc_aero_particle::pmc_mpi_pack_size_aero_particle
integer function pmc_mpi_pack_size_aero_particle(val)
Determines the number of bytes required to pack the given value.
Definition: aero_particle.F90:894
pmc_aero_particle_array::aero_particle_array_shrink
subroutine aero_particle_array_shrink(aero_particle_array)
Possibly shrinks the storage of the given array, ensuring that it can still store the allocated parti...
Definition: aero_particle_array.F90:140
pmc_aero_particle::aero_particle_check
subroutine aero_particle_check(aero_particle, aero_data, continue_on_error)
Check that the particle data is consistent.
Definition: aero_particle.F90:993
pmc_util
Common utility subroutines.
Definition: util.F90:9
pmc_aero_particle_array::aero_particle_array_check
subroutine aero_particle_array_check(aero_particle_array, aero_data, continue_on_error)
Check that the particle array data is consistent.
Definition: aero_particle_array.F90:281
pmc_aero_particle_array::pmc_mpi_unpack_aero_particle_array
subroutine pmc_mpi_unpack_aero_particle_array(buffer, position, val)
Unpacks the given value from the buffer, advancing position.
Definition: aero_particle_array.F90:252
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_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:561
pmc_aero_particle_array
The aero_particle_array_t structure and assoicated subroutines.
Definition: aero_particle_array.F90:9
pmc_aero_particle_array::aero_particle_array_zero
subroutine aero_particle_array_zero(aero_particle_array)
Resets an aero_particle_array to contain zero particles.
Definition: aero_particle_array.F90:70
pmc_aero_particle::pmc_mpi_pack_aero_particle
subroutine pmc_mpi_pack_aero_particle(buffer, position, val)
Packs the given value into the buffer, advancing position.
Definition: aero_particle.F90:920
pmc_aero_particle_array::aero_particle_array_remove_particle
subroutine aero_particle_array_remove_particle(aero_particle_array, index)
Removes the particle at the given index.
Definition: aero_particle_array.F90:180